Refactoring balance threshold filter

This commit is contained in:
Greg Hysen
2018-12-13 14:26:11 -08:00
parent f3a2e3b6f3
commit dea6f35b04
8 changed files with 481 additions and 74 deletions

View File

@@ -17,7 +17,6 @@
*/
pragma solidity 0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
import "./interfaces/IThresholdAsset.sol";

View File

@@ -62,8 +62,19 @@ contract MixinBalanceThresholdFilterCore is
)
external
{
// Validate addresses.
validateBalanceThresholdsOrRevert(signerAddress);
// Get accounts whose balances must be validated
address[] memory addressesToValidate = getAddressesToValidate(signerAddress);
// Validate account balances
uint256 balanceThreshold = BALANCE_THRESHOLD;
IThresholdAsset thresholdAsset = THRESHOLD_ASSET;
for(uint256 i = 0; i < addressesToValidate.length; ++i) {
uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]);
if (addressBalance < balanceThreshold) {
revert("AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD");
}
}
emit ValidatedAddresses(addressesToValidate);
// All addresses are valid. Execute fillOrder.
EXCHANGE.executeTransaction(
@@ -74,20 +85,15 @@ contract MixinBalanceThresholdFilterCore is
);
}
/// @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(address signerAddress)
internal
/// @dev Constructs an array of addresses to be validated.
/// Addresses depend on which Exchange function is to be called
/// (defined by `signedExchangeTransaction` above).
/// @param signerAddress Address of transaction signer.
/// @return addressesToValidate Array of addresses to validate.
function getAddressesToValidate(address signerAddress)
internal pure
returns (address[] memory addressesToValidate)
{
// Extract addresses to validate from Exchange calldata
address[] memory addressesToValidate = new address[](0);
bytes4 exchangeFunctionSelector = bytes4(exchangeCalldataload(0));
if(
exchangeFunctionSelector == batchFillOrdersSelector ||
@@ -99,21 +105,21 @@ contract MixinBalanceThresholdFilterCore is
exchangeFunctionSelector == marketSellOrdersNoThrowSelector
) {
addressesToValidate = loadMakerAddressesFromOrderArray(0);
recordAddressToValidate(signerAddress, addressesToValidate);
addressesToValidate = addressesToValidate.append(signerAddress);
} else if(
exchangeFunctionSelector == fillOrderSelector ||
exchangeFunctionSelector == fillOrderNoThrowSelector ||
exchangeFunctionSelector == fillOrKillOrderSelector
) {
address makerAddress = loadMakerAddressFromOrder(0);
recordAddressToValidate(makerAddress, addressesToValidate);
recordAddressToValidate(signerAddress, addressesToValidate);
addressesToValidate = addressesToValidate.append(makerAddress);
addressesToValidate = addressesToValidate.append(signerAddress);
} else if(exchangeFunctionSelector == matchOrdersSelector) {
address leftOrderAddress = loadMakerAddressFromOrder(0);
recordAddressToValidate(leftOrderAddress, addressesToValidate);
address rightOrderAddress = loadMakerAddressFromOrder(1);
recordAddressToValidate(rightOrderAddress, addressesToValidate);
recordAddressToValidate(signerAddress, addressesToValidate);
address leftMakerAddress = loadMakerAddressFromOrder(0);
addressesToValidate = addressesToValidate.append(leftMakerAddress);
address rightMakerAddress = loadMakerAddressFromOrder(1);
addressesToValidate = addressesToValidate.append(rightMakerAddress);
addressesToValidate = addressesToValidate.append(signerAddress);
} else if(
exchangeFunctionSelector != cancelOrderSelector &&
exchangeFunctionSelector != batchCancelOrdersSelector &&
@@ -121,16 +127,5 @@ contract MixinBalanceThresholdFilterCore is
) {
revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
}
// Validate account balances
uint256 balanceThreshold = BALANCE_THRESHOLD;
IThresholdAsset thresholdAsset = THRESHOLD_ASSET;
for(uint i = 0; i < addressesToValidate.length; ++i) {
uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]);
if (addressBalance < balanceThreshold) {
revert("AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD");
}
}
emit ValidatedAddresses(addressesToValidate);
}
}

View File

@@ -0,0 +1,102 @@
/*
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/LICENSE2.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;
import "./mixins/MExchangeCalldata.sol";
import "@0x/contracts-libs/contracts/libs/LibAddressArray.sol";
contract MixinExchangeCalldata is
MExchangeCalldata
{
using LibAddressArray for address[];
/// @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(uint256 offset)
internal pure
returns (bytes32 value)
{
assembly {
// 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(uint256 offset)
internal pure
returns (bytes32 value)
{
value = exchangeCalldataload(offset + 4);
}
/// @dev Extracts the maker address from an order stored in the Exchange calldata
/// (which is embedded in `signedExchangeTransaction`).
/// @param orderParamIndex Index of the order in the Exchange function's signature.
/// @return makerAddress The extracted maker address.
function loadMakerAddressFromOrder(uint256 orderParamIndex)
internal pure
returns (address makerAddress)
{
uint256 orderOffsetInBytes = orderParamIndex * 32;
uint256 orderPtr = uint256(loadExchangeData(orderOffsetInBytes));
makerAddress = address(loadExchangeData(orderPtr));
return 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
/// @return makerAddresses The extracted maker addresses.
function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
internal pure
returns (address[] makerAddresses)
{
uint256 orderArrayOffsetInBytes = orderArrayParamIndex * 32;
uint256 orderArrayPtr = uint256(loadExchangeData(orderArrayOffsetInBytes));
uint256 orderArrayLength = uint256(loadExchangeData(orderArrayPtr));
uint256 orderArrayLengthInBytes = orderArrayLength * 32;
uint256 orderArrayElementPtr = orderArrayPtr + 32;
uint256 orderArrayElementEndPtr = orderArrayElementPtr + orderArrayLengthInBytes;
for(uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 32) {
uint256 orderPtr = uint256(loadExchangeData(orderPtrOffset));
address makerAddress = address(loadExchangeData(orderPtr + orderArrayElementPtr));
makerAddresses = makerAddresses.append(makerAddress);
}
return makerAddresses;
}
}

View File

@@ -0,0 +1,56 @@
/*
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 IBalanceThresholdFilterCore {
/// @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;
}

View File

@@ -20,9 +20,12 @@ pragma solidity 0.4.24;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
import "../interfaces/IThresholdAsset.sol";
import "../interfaces/IBalanceThresholdFilterCore.sol";
contract MBalanceThresholdFilterCore {
contract MBalanceThresholdFilterCore is
IBalanceThresholdFilterCore
{
// Points to 0x exchange contract
// solhint-disable var-name-mixedcase
@@ -40,43 +43,12 @@ contract MBalanceThresholdFilterCore {
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.
/// @dev Constructs an array of addresses to be validated.
/// Addresses depend on which Exchange function is to be called
/// (defined by `signedExchangeTransaction` above).
/// @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(address signerAddress) internal;
/// @return addressesToValidate Array of addresses to validate.
function getAddressesToValidate(address signerAddress)
internal pure
returns (address[] memory addressesToValidate);
}

View File

@@ -0,0 +1,57 @@
/*
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/LICENSE2.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 MExchangeCalldata {
/// @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(uint256 offset)
internal pure
returns (bytes32 value);
/// @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(uint256 offset)
internal pure
returns (bytes32 value);
/// @dev Extracts the maker address from an order stored in the Exchange calldata
/// (which is embedded in `signedExchangeTransaction`).
/// @param orderParamIndex Index of the order in the Exchange function's signature.
/// @return makerAddress The extracted maker address.
function loadMakerAddressFromOrder(uint256 orderParamIndex)
internal pure
returns (address 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
/// @return makerAddresses The extracted maker addresses.
function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
internal pure
returns (address[] makerAddresses);
}

View File

@@ -0,0 +1,75 @@
/*
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;
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
library LibAddressArray {
/// @dev Append a new address to an array of addresses.
/// The `addressArray` may need to be reallocated to make space
/// for the new address. Because of this we return the resulting
/// memory location of `addressArray`.
/// @param addressToAppend Address to append.
/// @return Array of addresses: [... addressArray, addressToAppend]
function append(address[] memory addressArray, address addressToAppend)
internal pure
returns (address[])
{
// Get stats on address array and free memory
uint256 freeMemPtr = 0;
uint256 addressArrayBeginPtr = 0;
uint256 addressArrayEndPtr = 0;
uint256 addressArrayLength = addressArray.length;
uint256 addressArrayMemSizeInBytes = 32 + (32 * addressArrayLength);
assembly {
freeMemPtr := mload(0x40)
addressArrayBeginPtr := addressArray
addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes)
}
// If free memory begins at the end of `addressArray`
// then we can append `addressToAppend` directly.
// Otherwise, we must copy the array to free memory
// before appending new values to it.
if (freeMemPtr != addressArrayEndPtr) {
LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes);
assembly {
addressArray := freeMemPtr
addressArrayBeginPtr := addressArray
}
}
// Append `addressToAppend`
addressArrayLength += 1;
addressArrayMemSizeInBytes += 32;
addressArrayEndPtr = addressArrayBeginPtr + addressArrayMemSizeInBytes;
freeMemPtr = addressArrayEndPtr;
assembly {
// Store new array length
mstore(addressArray, addressArrayLength)
// Update `freeMemPtr`
mstore(0x40, freeMemPtr)
}
addressArray[addressArrayLength - 1] = addressToAppend;
return addressArray;
}
}

View File

@@ -0,0 +1,151 @@
/*
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 LibExchangeSelectors {
// allowedValidators
bytes4 constant allowedValidatorsSelector = 0x7b8e3514;
bytes4 constant allowedValidatorsSelectorGenerator = bytes4(keccak256('allowedValidators(address,address)'));
// assetProxies
bytes4 constant assetProxiesSelector = 0x3fd3c997;
bytes4 constant assetProxiesSelectorGenerator = bytes4(keccak256('assetProxies(bytes4)'));
// batchCancelOrders
bytes4 constant batchCancelOrdersSelector = 0x4ac14782;
bytes4 constant batchCancelOrdersSelectorGenerator = bytes4(keccak256('batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])'));
// batchFillOrKillOrders
bytes4 constant batchFillOrKillOrdersSelector = 0x4d0ae546;
bytes4 constant batchFillOrKillOrdersSelectorGenerator = bytes4(keccak256('batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
// batchFillOrders
bytes4 constant batchFillOrdersSelector = 0x297bb70b;
bytes4 constant batchFillOrdersSelectorGenerator = bytes4(keccak256('batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
// batchFillOrdersNoThrow
bytes4 constant batchFillOrdersNoThrowSelector = 0x50dde190;
bytes4 constant batchFillOrdersNoThrowSelectorGenerator = bytes4(keccak256('batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])'));
// cancelOrder
bytes4 constant cancelOrderSelector = 0xd46b02c3;
bytes4 constant cancelOrderSelectorGenerator = bytes4(keccak256('cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))'));
// cancelOrdersUpTo
bytes4 constant cancelOrdersUpToSelector = 0x4f9559b1;
bytes4 constant cancelOrdersUpToSelectorGenerator = bytes4(keccak256('cancelOrdersUpTo(uint256)'));
// cancelled
bytes4 constant cancelledSelector = 0x2ac12622;
bytes4 constant cancelledSelectorGenerator = bytes4(keccak256('cancelled(bytes32)'));
// currentContextAddress
bytes4 constant currentContextAddressSelector = 0xeea086ba;
bytes4 constant currentContextAddressSelectorGenerator = bytes4(keccak256('currentContextAddress()'));
// executeTransaction
bytes4 constant executeTransactionSelector = 0xbfc8bfce;
bytes4 constant executeTransactionSelectorGenerator = bytes4(keccak256('executeTransaction(uint256,address,bytes,bytes)'));
// fillOrKillOrder
bytes4 constant fillOrKillOrderSelector = 0x64a3bc15;
bytes4 constant fillOrKillOrderSelectorGenerator = bytes4(keccak256('fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
// fillOrder
bytes4 constant fillOrderSelector = 0xb4be83d5;
bytes4 constant fillOrderSelectorGenerator = bytes4(keccak256('fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
// fillOrderNoThrow
bytes4 constant fillOrderNoThrowSelector = 0x3e228bae;
bytes4 constant fillOrderNoThrowSelectorGenerator = bytes4(keccak256('fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)'));
// filled
bytes4 constant filledSelector = 0x288cdc91;
bytes4 constant filledSelectorGenerator = bytes4(keccak256('filled(bytes32)'));
// getAssetProxy
bytes4 constant getAssetProxySelector = 0x60704108;
bytes4 constant getAssetProxySelectorGenerator = bytes4(keccak256('getAssetProxy(bytes4)'));
// getOrderInfo
bytes4 constant getOrderInfoSelector = 0xc75e0a81;
bytes4 constant getOrderInfoSelectorGenerator = bytes4(keccak256('getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))'));
// getOrdersInfo
bytes4 constant getOrdersInfoSelector = 0x7e9d74dc;
bytes4 constant getOrdersInfoSelectorGenerator = bytes4(keccak256('getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])'));
// isValidSignature
bytes4 constant isValidSignatureSelector = 0x93634702;
bytes4 constant isValidSignatureSelectorGenerator = bytes4(keccak256('isValidSignature(bytes32,address,bytes)'));
// marketBuyOrders
bytes4 constant marketBuyOrdersSelector = 0xe5fa431b;
bytes4 constant marketBuyOrdersSelectorGenerator = bytes4(keccak256('marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
// marketBuyOrdersNoThrow
bytes4 constant marketBuyOrdersNoThrowSelector = 0xa3e20380;
bytes4 constant marketBuyOrdersNoThrowSelectorGenerator = bytes4(keccak256('marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
// marketSellOrders
bytes4 constant marketSellOrdersSelector = 0x7e1d9808;
bytes4 constant marketSellOrdersSelectorGenerator = bytes4(keccak256('marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
// marketSellOrdersNoThrow
bytes4 constant marketSellOrdersNoThrowSelector = 0xdd1c7d18;
bytes4 constant marketSellOrdersNoThrowSelectorGenerator = bytes4(keccak256('marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])'));
// matchOrders
bytes4 constant matchOrdersSelector = 0x3c28d861;
bytes4 constant matchOrdersSelectorGenerator = bytes4(keccak256('matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)'));
// orderEpoch
bytes4 constant orderEpochSelector = 0xd9bfa73e;
bytes4 constant orderEpochSelectorGenerator = bytes4(keccak256('orderEpoch(address,address)'));
// owner
bytes4 constant ownerSelector = 0x8da5cb5b;
bytes4 constant ownerSelectorGenerator = bytes4(keccak256('owner()'));
// preSign
bytes4 constant preSignSelector = 0x3683ef8e;
bytes4 constant preSignSelectorGenerator = bytes4(keccak256('preSign(bytes32,address,bytes)'));
// preSigned
bytes4 constant preSignedSelector = 0x82c174d0;
bytes4 constant preSignedSelectorGenerator = bytes4(keccak256('preSigned(bytes32,address)'));
// registerAssetProxy
bytes4 constant registerAssetProxySelector = 0xc585bb93;
bytes4 constant registerAssetProxySelectorGenerator = bytes4(keccak256('registerAssetProxy(address)'));
// setSignatureValidatorApproval
bytes4 constant setSignatureValidatorApprovalSelector = 0x77fcce68;
bytes4 constant setSignatureValidatorApprovalSelectorGenerator = bytes4(keccak256('setSignatureValidatorApproval(address,bool)'));
// transactions
bytes4 constant transactionsSelector = 0x642f2eaf;
bytes4 constant transactionsSelectorGenerator = bytes4(keccak256('transactions(bytes32)'));
// transferOwnership
bytes4 constant transferOwnershipSelector = 0xf2fde38b;
bytes4 constant transferOwnershipSelectorGenerator = bytes4(keccak256('transferOwnership(address)'));
}