From f91781a0605f46ee1a40bf979d22ff510f48d464 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 13 Dec 2018 13:52:20 -0800 Subject: Less Assembly. More Solidity. Less Efficiency. More Readability. --- .../BalanceThresholdFilter.sol | 10 +- .../MixinBalanceThresholdFilterCore.sol | 404 ++++++++------------- .../mixins/MBalanceThresholdFilterCore.sol | 7 +- .../utils/ExchangeSelectors/ExchangeSelectors.sol | 151 ++++++++ 4 files changed, 306 insertions(+), 266 deletions(-) create mode 100644 contracts/utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol (limited to 'contracts') diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol b/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol index a68f6805d..ea248793f 100644 --- a/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol +++ b/contracts/extensions/contracts/BalanceThresholdFilter/BalanceThresholdFilter.sol @@ -24,21 +24,23 @@ import "./interfaces/IThresholdAsset.sol"; import "./MixinBalanceThresholdFilterCore.sol"; -contract BalanceThresholdFilter is MixinBalanceThresholdFilterCore { +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. + /// @param balanceThreshold The minimum balance of `thresholdAsset` that must be held by makers/takers. constructor( address exchange, address thresholdAsset, - uint256 thresholdBalance + uint256 balanceThreshold ) public { EXCHANGE = IExchange(exchange); THRESHOLD_ASSET = IThresholdAsset(thresholdAsset); - THRESHOLD_BALANCE = thresholdBalance; + BALANCE_THRESHOLD = balanceThreshold; } } diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol index 51dbae8f3..e78f9ced8 100644 --- a/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol +++ b/contracts/extensions/contracts/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol @@ -6,7 +6,7 @@ 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 + 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, @@ -17,31 +17,36 @@ */ pragma solidity 0.4.24; -pragma experimental ABIEncoderV2; import "./mixins/MBalanceThresholdFilterCore.sol"; +import "@0x/contracts-utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol"; +import "@0x/contracts-libs/contracts/libs/LibOrder.sol"; -contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore { +contract MixinBalanceThresholdFilterCore is + MBalanceThresholdFilterCore, + LibOrder, + ExchangeSelectors +{ /// @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 + /// 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. @@ -56,7 +61,7 @@ contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore { external { // Validate addresses. - validateBalanceThresholdsOrRevert(); + validateBalanceThresholdsOrRevert(signerAddress); // All addresses are valid. Execute fillOrder. EXCHANGE.executeTransaction( @@ -67,6 +72,83 @@ contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore { ); } + /// @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 + 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 + returns (bytes32 value) + { + value = exchangeCalldataload(offset + 4); + } + + /// @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(address addressToValidate, address[] memory addressList) + internal + { + uint256 newAddressListLength = addressList.length + 1; + assembly { + // Store new array length + mstore(addressList, newAddressListLength) + mstore(0x40, add(addressList, add(0x20, mul(0x20, newAddressListLength)))) + } + addressList[newAddressListLength - 1] = 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 loadMakerAddressFromOrder(uint8 orderParamIndex) internal returns (address makerAddress) { + uint256 orderPtr = uint256(loadExchangeData(orderParamIndex * 0x20)); + makerAddress = address(loadExchangeData(orderPtr)); + } + + /// @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 loadMakerAddressesFromOrderArray(uint8 orderArrayParamIndex) + internal + returns (address[] makerAddresses) + { + uint256 orderArrayPtr = uint256(loadExchangeData(orderArrayParamIndex * 0x20)); + uint256 orderArrayLength = uint256(loadExchangeData(orderArrayPtr)); + uint256 orderArrayElementPtr = orderArrayPtr + 0x20; + uint256 orderArrayElementEndPtr = orderArrayElementPtr + (orderArrayLength * 0x20); + for(uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 0x20) { + uint256 orderPtr = uint256(loadExchangeData(orderPtrOffset)); + address makerAddress = address(loadExchangeData(orderPtr + orderArrayElementPtr)); + recordAddressToValidate(makerAddress, makerAddresses); + } + } + /// @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 @@ -74,250 +156,56 @@ contract MixinBalanceThresholdFilterCore is MBalanceThresholdFilterCore { /// 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() + function validateBalanceThresholdsOrRevert(address signerAddress) 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: (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: (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: (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 - // solhint-disable no-empty-blocks - 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) - } - // solhint-enable no-empty-blocks - - ///// 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) - // solhint-disable max-line-length - for {let addressToValidate := addressesToValidateElementPtr} lt(addressToValidate, addressesToValidateElementEndPtr) {addressToValidate := add(addressToValidate, 0x20)} { - // solhint-enable max-line-length - // 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) - } + // Extract addresses to validate from Exchange calldata + address[] memory addressesToValidate = new address[](0); + bytes4 exchangeFunctionSelector = bytes4(exchangeCalldataload(0)); + if( + exchangeFunctionSelector == batchFillOrdersSelector || + exchangeFunctionSelector == batchFillOrdersNoThrowSelector || + exchangeFunctionSelector == batchFillOrKillOrdersSelector || + exchangeFunctionSelector == marketBuyOrdersSelector || + exchangeFunctionSelector == marketBuyOrdersNoThrowSelector || + exchangeFunctionSelector == marketSellOrdersSelector || + exchangeFunctionSelector == marketSellOrdersNoThrowSelector + ) { + addressesToValidate = loadMakerAddressesFromOrderArray(0); + recordAddressToValidate(signerAddress, addressesToValidate); + } else if( + exchangeFunctionSelector == fillOrderSelector || + exchangeFunctionSelector == fillOrderNoThrowSelector || + exchangeFunctionSelector == fillOrKillOrderSelector + ) { + address makerAddress = loadMakerAddressFromOrder(0); + recordAddressToValidate(makerAddress, addressesToValidate); + recordAddressToValidate(signerAddress, addressesToValidate); + } else if(exchangeFunctionSelector == matchOrdersSelector) { + address leftOrderAddress = loadMakerAddressFromOrder(0); + recordAddressToValidate(leftOrderAddress, addressesToValidate); + address rightOrderAddress = loadMakerAddressFromOrder(1); + recordAddressToValidate(rightOrderAddress, addressesToValidate); + recordAddressToValidate(signerAddress, addressesToValidate); + } else if( + exchangeFunctionSelector == cancelOrderSelector || + exchangeFunctionSelector == batchCancelOrdersSelector || + exchangeFunctionSelector == cancelOrdersUpToSelector + ) { + // Do nothing + } else { + revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR"); + } - // 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) - } + // 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"); } - - // Record validated addresses - validatedAddresses := addressesToValidate } - - ///// If we hit this point then all addresses are valid ///// - emit ValidatedAddresses(validatedAddresses); + emit ValidatedAddresses(addressesToValidate); } } diff --git a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol index af7a9453b..6aaa729fb 100644 --- a/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol +++ b/contracts/extensions/contracts/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol @@ -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"; @@ -33,10 +32,10 @@ contract MBalanceThresholdFilterCore { IThresholdAsset internal THRESHOLD_ASSET; // The minimum balance of `THRESHOLD_ASSET` that must be held by makers/takers - uint256 internal THRESHOLD_BALANCE; + uint256 internal BALANCE_THRESHOLD; // solhint-enable var-name-mixedcase - // Addresses that hold at least `THRESHOLD_BALANCE` of `THRESHOLD_ASSET` + // Addresses that hold at least `BALANCE_THRESHOLD` of `THRESHOLD_ASSET` event ValidatedAddresses ( address[] addresses ); @@ -79,5 +78,5 @@ contract MBalanceThresholdFilterCore { /// 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; + function validateBalanceThresholdsOrRevert(address signerAddress) internal; } diff --git a/contracts/utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol b/contracts/utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol new file mode 100644 index 000000000..c361fd075 --- /dev/null +++ b/contracts/utils/contracts/utils/ExchangeSelectors/ExchangeSelectors.sol @@ -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 ExchangeSelectors { + + // 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)')); +} \ No newline at end of file -- cgit v1.2.3