Ported Balance Threshold Filter to new contract directory structure

This commit is contained in:
Greg Hysen
2018-12-11 14:47:52 -08:00
parent 8799f9bb90
commit 4417c76b13
11 changed files with 52 additions and 41 deletions

View File

@@ -18,5 +18,5 @@
}
}
},
"contracts": ["DutchAuction", "Forwarder"]
"contracts": ["BalanceThresholdFilter", "DutchAuction", "Forwarder"]
}

View File

@@ -0,0 +1,44 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity 0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
import "./interfaces/IThresholdAsset.sol";
import "./MixinBalanceThresholdFilterCore.sol";
contract BalanceThresholdFilter is MixinBalanceThresholdFilterCore {
/// @dev Constructs BalanceThresholdFilter.
/// @param exchange Address of 0x exchange.
/// @param thresholdAsset The asset that must be held by makers/takers.
/// @param thresholdBalance The minimum balance of `thresholdAsset` that must be held by makers/takers.
constructor(
address exchange,
address thresholdAsset,
uint256 thresholdBalance
)
public
{
EXCHANGE = IExchange(exchange);
THRESHOLD_ASSET = IThresholdAsset(thresholdAsset);
THRESHOLD_BALANCE = thresholdBalance;
}
}

View File

@@ -0,0 +1,319 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity 0.4.24;
pragma experimental ABIEncoderV2;
import "./mixins/MBalanceThresholdFilterCore.sol";
contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore {
/// @dev Executes an Exchange transaction iff the maker and taker meet
/// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR
/// the exchange function is a cancellation.
/// Supported Exchange functions:
/// - batchFillOrders
/// - batchFillOrdersNoThrow
/// - batchFillOrKillOrders
/// - fillOrder
/// - fillOrderNoThrow
/// - fillOrKillOrder
/// - marketBuyOrders
/// - marketBuyOrdersNoThrow
/// - marketSellOrders
/// - marketSellOrdersNoThrow
/// - matchOrders
/// - cancelOrder
/// - batchCancelOrders
/// - cancelOrdersUpTo
/// Trying to call any other exchange function will throw.
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
/// @param signerAddress Address of transaction signer.
/// @param signedExchangeTransaction AbiV2 encoded calldata.
/// @param signature Proof of signer transaction by signer.
function executeTransaction(
uint256 salt,
address signerAddress,
bytes signedExchangeTransaction,
bytes signature
)
external
{
// Validate addresses.
validateBalanceThresholdsOrRevert();
// All addresses are valid. Execute fillOrder.
EXCHANGE.executeTransaction(
salt,
signerAddress,
signedExchangeTransaction,
signature
);
}
/// @dev Validates addresses meet the balance threshold specified by `BALANCE_THRESHOLD`
/// for the asset `THRESHOLD_ASSET`. If one address does not meet the thresold
/// then this function will revert. Which addresses are validated depends on
/// which Exchange function is to be called (defined by `signedExchangeTransaction` above).
/// No parameters are taken as this function reads arguments directly from calldata, to save gas.
/// If all addresses are valid then this function emits a ValidatedAddresses event, listing all
/// of the addresses whose balance thresholds it checked.
function validateBalanceThresholdsOrRevert()
internal
{
// Addresses that are validated below.
address[] memory validatedAddresses;
///// Do not add variables after this point. /////
///// The assembly block may overwrite their values. /////
// Validate addresses
assembly {
/// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
/// which is accessed through `signedExchangeTransaction`.
/// @param offset - Offset into the Exchange calldata.
/// @return value - Corresponding 32 byte value stored at `offset`.
function exchangeCalldataload(offset) -> value {
// Pointer to exchange transaction
// 0x04 for calldata selector
// 0x40 to access `signedExchangeTransaction`, which is the third parameter
let exchangeTxPtr := calldataload(0x44)
// Offset into Exchange calldata
// We compute this by adding 0x24 to the `exchangeTxPtr` computed above.
// 0x04 for calldata selector
// 0x20 for length field of `signedExchangeTransaction`
let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset))
value := calldataload(exchangeCalldataOffset)
}
/// @dev Convenience function that skips the 4 byte selector when loading
/// from the embedded Exchange calldata.
/// @param offset - Offset into the Exchange calldata (minus the 4 byte selector)
/// @return value - Corresponding 32 byte value stored at `offset` + 4.
function loadExchangeData(offset) -> value {
value := exchangeCalldataload(add(offset, 0x4))
}
/// @dev A running list is maintained of addresses to validate.
/// This function records an address in this array.
/// @param addressToValidate - Address to record for validation.
function recordAddressToValidate(addressToValidate) {
// Compute `addressesToValidate` memory offset
let addressesToValidate_ := mload(0x40)
let nAddressesToValidate_ := mload(addressesToValidate_)
// Increment length
nAddressesToValidate_ := add(mload(addressesToValidate_), 0x01)
mstore(addressesToValidate_, nAddressesToValidate_)
// Append address to validate
let offset := mul(nAddressesToValidate_, 0x20)
mstore(add(addressesToValidate_, offset), addressToValidate)
}
/// @dev Extracts the maker address from an order stored in the Exchange calldata
/// (which is embedded in `signedExchangeTransaction`), and records it in
/// the running list of addresses to validate.
/// @param orderParamIndex - Index of the order in the Exchange function's signature
function recordMakerAddressFromOrder(orderParamIndex) {
let orderPtr := loadExchangeData(mul(orderParamIndex, 0x20))
let makerAddress := loadExchangeData(orderPtr)
recordAddressToValidate(makerAddress)
}
/// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
/// (which is embedded in `signedExchangeTransaction`), and records them in
/// the running list of addresses to validate.
/// @param orderArrayParamIndex - Index of the order array in the Exchange function's signature
function recordMakerAddressesFromOrderArray(orderArrayParamIndex) {
let orderArrayPtr := loadExchangeData(mul(orderArrayParamIndex, 0x20))
let orderArrayLength := loadExchangeData(orderArrayPtr)
let orderArrayElementPtr := add(orderArrayPtr, 0x20)
let orderArrayElementEndPtr := add(orderArrayElementPtr, mul(orderArrayLength, 0x20))
for {let orderPtrOffset := orderArrayElementPtr} lt(orderPtrOffset, orderArrayElementEndPtr) {orderPtrOffset := add(orderPtrOffset, 0x20)} {
let orderPtr := loadExchangeData(orderPtrOffset)
let makerAddress := loadExchangeData(add(orderPtr, orderArrayElementPtr))
recordAddressToValidate(makerAddress)
}
}
/// @dev Records address of signer in the running list of addresses to validate.
/// @note: We cannot access `signerAddress` directly from within the asm function,
/// so it is loaded from the calldata.
function recordSignerAddress() {
// Load the signer address from calldata
// 0x04 for selector
// 0x20 to access `signerAddress`, which is the second parameter.
let signerAddress_ := calldataload(0x24)
recordAddressToValidate(signerAddress_)
}
/// @dev Records addresses to be validated when Exchange transaction is a batch fill variant.
/// This is one of: batchFillOrders, batchFillOrKillOrders, batchFillNoThrow
/// Reference signature<T>: <batchFillVariant>(Order[],uint256[],bytes[])
function recordAddressesForBatchFillVariant() {
// Record maker addresses from order array (parameter index 0)
// The signer is the taker for these orders and must also be validated.
recordMakerAddressesFromOrderArray(0)
recordSignerAddress()
}
/// @dev Records addresses to be validated when Exchange transaction is a fill order variant.
/// This is one of: fillOrder, fillOrKillOrder, fillOrderNoThrow
/// Reference signature<T>: <fillOrderVariant>(Order,uint256,bytes)
function recordAddressesForFillOrderVariant() {
// Record maker address from the order (param index 0)
// The signer is the taker for this order and must also be validated.
recordMakerAddressFromOrder(0)
recordSignerAddress()
}
/// @dev Records addresses to be validated when Exchange transaction is a market fill variant.
/// This is one of: marketBuyOrders, marketBuyOrdersNoThrow, marketSellOrders, marketSellOrdersNoThrow
/// Reference signature<T>: <marketFillInvariant>(Order[],uint256,bytes[])
function recordAddressesForMarketFillVariant() {
// Record maker addresses from order array (parameter index 0)
// The signer is the taker for these orders and must also be validated.
recordMakerAddressesFromOrderArray(0)
recordSignerAddress()
}
/// @dev Records addresses to be validated when Exchange transaction is matchOrders.
/// Reference signature: matchOrders(Order,Order)
function recordAddressesForMatchOrders() {
// Record maker address from both orders (param indices 0 & 1).
// The signer is the taker and must also be validated.
recordMakerAddressFromOrder(0)
recordMakerAddressFromOrder(1)
recordSignerAddress()
}
///// Record Addresses to Validate /////
// Addresses needing validation depends on which Exchange function is being called.
// Step 1/2 Read the exchange function selector.
let exchangeFunctionSelector := and(
exchangeCalldataload(0x0),
0xffffffff00000000000000000000000000000000000000000000000000000000
)
// Step 2/2 Extract addresses to validate based on this selector.
// See ../../utils/ExchangeSelectors/ExchangeSelectors.sol for selectors
switch exchangeFunctionSelector
case 0x297bb70b00000000000000000000000000000000000000000000000000000000 { recordAddressesForBatchFillVariant() } // batchFillOrders
case 0x50dde19000000000000000000000000000000000000000000000000000000000 { recordAddressesForBatchFillVariant() } // batchFillOrdersNoThrow
case 0x4d0ae54600000000000000000000000000000000000000000000000000000000 { recordAddressesForBatchFillVariant() } // batchFillOrKillOrders
case 0xb4be83d500000000000000000000000000000000000000000000000000000000 { recordAddressesForFillOrderVariant() } // fillOrder
case 0x3e228bae00000000000000000000000000000000000000000000000000000000 { recordAddressesForFillOrderVariant() } // fillOrderNoThrow
case 0x64a3bc1500000000000000000000000000000000000000000000000000000000 { recordAddressesForFillOrderVariant() } // fillOrKillOrder
case 0xe5fa431b00000000000000000000000000000000000000000000000000000000 { recordAddressesForMarketFillVariant() } // marketBuyOrders
case 0xa3e2038000000000000000000000000000000000000000000000000000000000 { recordAddressesForMarketFillVariant() } // marketBuyOrdersNoThrow
case 0x7e1d980800000000000000000000000000000000000000000000000000000000 { recordAddressesForMarketFillVariant() } // marketSellOrders
case 0xdd1c7d1800000000000000000000000000000000000000000000000000000000 { recordAddressesForMarketFillVariant() } // marketSellOrdersNoThrow
case 0x3c28d86100000000000000000000000000000000000000000000000000000000 { recordAddressesForMatchOrders() } // matchOrders
case 0xd46b02c300000000000000000000000000000000000000000000000000000000 {} // cancelOrder
case 0x4ac1478200000000000000000000000000000000000000000000000000000000 {} // batchCancelOrders
case 0x4f9559b100000000000000000000000000000000000000000000000000000000 {} // cancelOrdersUpTo
default {
// Revert with `Error("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR")`
mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x00000024494e56414c49445f4f525f424c4f434b45445f45584348414e47455f)
mstore(0x60, 0x53454c4543544f52000000000000000000000000000000000000000000000000)
mstore(0x80, 0x00000000)
// Revert length calculation:
// 4 -- error selector
// 32 -- offset to string
// 32 -- string length field
// 64 -- strlen(INVALID_OR_BLOCKED_EXCHANGE_SELECTOR) rounded up to nearest 32-byte word.
revert(0, 132)
}
///// Validate Recorded Addresses /////
// Load from memory the addresses to validate
let addressesToValidate := mload(0x40)
let addressesToValidateLength := mload(addressesToValidate)
let addressesToValidateElementPtr := add(addressesToValidate, 0x20)
let addressesToValidateElementEndPtr := add(addressesToValidateElementPtr, mul(addressesToValidateLength, 0x20))
// Set free memory pointer to after `addressesToValidate` array.
// This is to avoid corruption when making calls in the loop below.
let freeMemPtr := addressesToValidateElementEndPtr
mstore(0x40, freeMemPtr)
// Validate addresses
let thresholdAssetAddress := sload(THRESHOLD_ASSET_slot)
let thresholdBalance := sload(THRESHOLD_BALANCE_slot)
for {let addressToValidate := addressesToValidateElementPtr} lt(addressToValidate, addressesToValidateElementEndPtr) {addressToValidate := add(addressToValidate, 0x20)} {
// Construct calldata for `THRESHOLD_ASSET.balanceOf`
mstore(freeMemPtr, 0x70a0823100000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemPtr, 0x04), mload(addressToValidate))
// call `THRESHOLD_ASSET.balanceOf`
let success := call(
gas, // forward all gas
thresholdAssetAddress, // call address of asset proxy
0, // don't send any ETH
freeMemPtr, // pointer to start of input
0x24, // length of input (one padded address)
freeMemPtr, // write output to next free memory offset
0x20 // reserve space for return balance (0x20 bytes)
)
if eq(success, 0) {
// @TODO Revert with `Error("BALANCE_QUERY_FAILED")`
mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000001442414c414e43455f51554552595f4641494c45440000000000000000)
mstore(0x60, 0x00000000)
// Revert length calculation:
// 4 -- error selector
// 32 -- offset to string
// 32 -- string length field
// 32 -- strlen(BALANCE_QUERY_FAILED) rounded up to nearest 32-byte word.
revert(0, 100)
}
// Revert if balance not held
let addressBalance := mload(freeMemPtr)
if lt(addressBalance, thresholdBalance) {
// Revert with `Error("AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD")`
mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(0x20, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(0x40, 0x0000003441545f4c454153545f4f4e455f414444524553535f444f45535f4e4f)
mstore(0x60, 0x545f4d4545545f42414c414e43455f5448524553484f4c440000000000000000)
mstore(0x80, 0x00000000)
// Revert length calculation:
// 4 -- error selector
// 32 -- offset to string
// 32 -- string length field
// 64 -- strlen(AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD) rounded up to nearest 32-byte word.
revert(0, 132)
}
}
// Record validated addresses
validatedAddresses := addressesToValidate
}
///// If we hit this point then all addresses are valid /////
emit ValidatedAddresses(validatedAddresses);
}
}

View File

@@ -0,0 +1,30 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity 0.4.24;
contract IThresholdAsset {
/// @param _owner The address from which the balance will be retrieved
/// @return Balance of owner
function balanceOf(address _owner)
external
view
returns (uint256);
}

View File

@@ -0,0 +1,81 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity 0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
import "../interfaces/IThresholdAsset.sol";
contract MBalanceThresholdFilterCore {
// Points to 0x exchange contract
IExchange internal EXCHANGE;
// The asset that must be held by makers/takers
IThresholdAsset internal THRESHOLD_ASSET;
// The minimum balance of `THRESHOLD_ASSET` that must be held by makers/takers
uint256 internal THRESHOLD_BALANCE;
// Addresses that hold at least `THRESHOLD_BALANCE` of `THRESHOLD_ASSET`
event ValidatedAddresses (
address[] addresses
);
/// @dev Executes an Exchange transaction iff the maker and taker meet
/// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR
/// the exchange function is a cancellation.
/// Supported Exchange functions:
/// - batchFillOrders
/// - batchFillOrdersNoThrow
/// - batchFillOrKillOrders
/// - fillOrder
/// - fillOrderNoThrow
/// - fillOrKillOrder
/// - marketBuyOrders
/// - marketBuyOrdersNoThrow
/// - marketSellOrders
/// - marketSellOrdersNoThrow
/// - matchOrders
/// - cancelOrder
/// - batchCancelOrders
/// - cancelOrdersUpTo
/// Trying to call any other exchange function will throw.
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
/// @param signerAddress Address of transaction signer.
/// @param signedExchangeTransaction AbiV2 encoded calldata.
/// @param signature Proof of signer transaction by signer.
function executeTransaction(
uint256 salt,
address signerAddress,
bytes signedExchangeTransaction,
bytes signature
)
external;
/// @dev Validates addresses meet the balance threshold specified by `BALANCE_THRESHOLD`
/// for the asset `THRESHOLD_ASSET`. If one address does not meet the thresold
/// then this function will revert. Which addresses are validated depends on
/// which Exchange function is to be called (defined by `signedExchangeTransaction` above).
/// No parameters are taken as this function reads arguments directly from calldata, to save gas.
/// If all addresses are valid then this function emits a ValidatedAddresses event, listing all
/// of the addresses whose balance thresholds it checked.
function validateBalanceThresholdsOrRevert() internal;
}

View File

@@ -31,7 +31,7 @@
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
},
"config": {
"abis": "generated-artifacts/@(DutchAuction|Forwarder).json"
"abis": "generated-artifacts/@(BalanceThresholdFilter|DutchAuction|Forwarder).json"
},
"repository": {
"type": "git",

View File

@@ -1,9 +1,11 @@
import { ContractArtifact } from 'ethereum-types';
import * as BalanceThresholdFilter from '../../generated-artifacts/BalanceThresholdFilter.json';
import * as DutchAuction from '../../generated-artifacts/DutchAuction.json';
import * as Forwarder from '../../generated-artifacts/Forwarder.json';
export const artifacts = {
BalanceThresholdFilter: BalanceThresholdFilter as ContractArtifact,
DutchAuction: DutchAuction as ContractArtifact,
Forwarder: Forwarder as ContractArtifact,
};

View File

@@ -1,2 +1,3 @@
export * from '../../generated-wrappers/balance_threshold_filter';
export * from '../../generated-wrappers/dutch_auction';
export * from '../../generated-wrappers/forwarder';

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,246 @@
import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { ExchangeContract } from '@0x/contracts-protocol';
import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter';
import { formatters, LogDecoder, orderUtils, OrderInfo, TransactionFactory } from '@0x/contracts-test-utils';
import { artifacts } from '../../src/artifacts';
import {artifacts as protocolArtifacts} from '@0x/contracts-protocol';
import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
export class BalanceThresholdWrapper {
private readonly _balanceThresholdFilter: BalanceThresholdFilterContract;
private readonly _signerTransactionFactory: TransactionFactory;
private readonly _exchange: ExchangeContract;
private readonly _web3Wrapper: Web3Wrapper;
private readonly _logDecoder: LogDecoder;
constructor(balanceThresholdFilter: BalanceThresholdFilterContract, exchangeContract: ExchangeContract, signerTransactionFactory: TransactionFactory, provider: Provider) {
this._balanceThresholdFilter = balanceThresholdFilter;
this._exchange = exchangeContract;
this._signerTransactionFactory = signerTransactionFactory;
this._web3Wrapper = new Web3Wrapper(provider);
this._logDecoder = new LogDecoder(this._web3Wrapper, {... artifacts, ... tokensArtifacts, ... protocolArtifacts} );
}
public async fillOrderAsync(
signedOrder: SignedOrder,
from: string,
opts: { takerAssetFillAmount?: BigNumber } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
const data = this._exchange.fillOrder.getABIEncodedTransactionData(
params.order,
params.takerAssetFillAmount,
params.signature,
);
const txReceipt = this._executeTransaction(data, from);
return txReceipt;
}
public async fillOrKillOrderAsync(
signedOrder: SignedOrder,
from: string,
opts: { takerAssetFillAmount?: BigNumber } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
const data = this._exchange.fillOrKillOrder.getABIEncodedTransactionData(
params.order,
params.takerAssetFillAmount,
params.signature,
);
const txReceipt = this._executeTransaction(data, from);
return txReceipt;
}
public async fillOrderNoThrowAsync(
signedOrder: SignedOrder,
from: string,
opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
const data = this._exchange.fillOrderNoThrow.getABIEncodedTransactionData(
params.order,
params.takerAssetFillAmount,
params.signature,
);
const txReceipt = this._executeTransaction(data, from, opts.gas);
return txReceipt;
}
public async batchFillOrdersAsync(
orders: SignedOrder[],
from: string,
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
const data = this._exchange.batchFillOrders.getABIEncodedTransactionData(
params.orders,
params.takerAssetFillAmounts,
params.signatures,
);
const txReceipt = this._executeTransaction(data, from);
return txReceipt;
}
public async batchFillOrKillOrdersAsync(
orders: SignedOrder[],
from: string,
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
params.orders,
params.takerAssetFillAmounts,
params.signatures,
);
const txReceipt = this._executeTransaction(data, from);
return txReceipt;
}
public async batchFillOrdersNoThrowAsync(
orders: SignedOrder[],
from: string,
opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
params.orders,
params.takerAssetFillAmounts,
params.signatures,
);
const txReceipt = this._executeTransaction(data, from, opts.gas);
return txReceipt;
}
public async marketSellOrdersAsync(
orders: SignedOrder[],
from: string,
opts: { takerAssetFillAmount: BigNumber },
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
const data = this._exchange.marketSellOrders.getABIEncodedTransactionData(
params.orders,
params.takerAssetFillAmount,
params.signatures,
);
const txReceipt = this._executeTransaction(data, from);
return txReceipt;
}
public async marketSellOrdersNoThrowAsync(
orders: SignedOrder[],
from: string,
opts: { takerAssetFillAmount: BigNumber; gas?: number },
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
const data = this._exchange.marketSellOrdersNoThrow.getABIEncodedTransactionData(
params.orders,
params.takerAssetFillAmount,
params.signatures,
);
const txReceipt = this._executeTransaction(data, from, opts.gas);
return txReceipt;
}
public async marketBuyOrdersAsync(
orders: SignedOrder[],
from: string,
opts: { makerAssetFillAmount: BigNumber },
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
const data = this._exchange.marketBuyOrders.getABIEncodedTransactionData(
params.orders,
params.makerAssetFillAmount,
params.signatures,
);
const txReceipt = this._executeTransaction(data, from);
return txReceipt;
}
public async marketBuyOrdersNoThrowAsync(
orders: SignedOrder[],
from: string,
opts: { makerAssetFillAmount: BigNumber; gas?: number },
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
const data = this._exchange.marketBuyOrdersNoThrow.getABIEncodedTransactionData(
params.orders,
params.makerAssetFillAmount,
params.signatures,
);
const txReceipt = this._executeTransaction(data, from, opts.gas);
return txReceipt;
}
public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
const params = orderUtils.createCancel(signedOrder);
const data = this._exchange.cancelOrder.getABIEncodedTransactionData(params.order);
const txReceipt = this._executeTransaction(data, from);
return txReceipt;
}
public async batchCancelOrdersAsync(
orders: SignedOrder[],
from: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createBatchCancel(orders);
const data = this._exchange.batchCancelOrders.getABIEncodedTransactionData(params.orders);
const txReceipt = this._executeTransaction(data, from);
return txReceipt;
}
public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
const data = this._exchange.cancelOrdersUpTo.getABIEncodedTransactionData(salt);
const txReceipt = this._executeTransaction(data, from);
return txReceipt;
}
public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
const filledAmount = await this._exchange.filled.callAsync(orderHashHex);
return filledAmount;
}
public async isCancelledAsync(orderHashHex: string): Promise<boolean> {
const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex);
return isCancelled;
}
public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> {
const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress);
return orderEpoch;
}
public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> {
const orderInfo = (await this._exchange.getOrderInfo.callAsync(signedOrder)) as OrderInfo;
return orderInfo;
}
public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise<OrderInfo[]> {
const ordersInfo = (await this._exchange.getOrdersInfo.callAsync(signedOrders)) as OrderInfo[];
return ordersInfo;
}
public async matchOrdersAsync(
signedOrderLeft: SignedOrder,
signedOrderRight: SignedOrder,
from: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
const data = await this._exchange.matchOrders.getABIEncodedTransactionData(
params.left,
params.right,
params.leftSignature,
params.rightSignature
);
const txReceipt = this._executeTransaction(data, from);
return txReceipt;
}
public getBalanceThresholdAddress(): string {
return this._balanceThresholdFilter.address;
}
public getExchangeAddress(): string {
return this._exchange.address;
}
// Exchange functions
//abiEncodeFillOrder
//getFillOrderResultsAsync
//
private async _executeTransaction(abiEncodedExchangeTxData: string, from: string, gas?: number): Promise<TransactionReceiptWithDecodedLogs> {
const signedExchangeTx = this._signerTransactionFactory.newSignedTransaction(abiEncodedExchangeTxData);
const txOpts = _.isUndefined(gas) ? {from} : {from, gas};
const txHash = await this._balanceThresholdFilter.executeTransaction.sendTransactionAsync(
signedExchangeTx.salt,
signedExchangeTx.signerAddress,
signedExchangeTx.data,
signedExchangeTx.signature,
txOpts,
);
const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return txReceipt;
}
}

View File

@@ -6,6 +6,6 @@
"resolveJsonModule": true
},
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": ["./generated-artifacts/DutchAuction.json", "./generated-artifacts/Forwarder.json"],
"files": ["./generated-artifacts/BalanceThresholdFilter.json", "./generated-artifacts/DutchAuction.json", "./generated-artifacts/Forwarder.json"],
"exclude": ["./deploy/solc/solc_bin"]
}