diff options
author | Greg Hysen <greg.hysen@gmail.com> | 2018-12-12 06:47:52 +0800 |
---|---|---|
committer | Greg Hysen <greg.hysen@gmail.com> | 2018-12-19 05:36:05 +0800 |
commit | 4417c76b130655da3b14209148191d43037e8f8a (patch) | |
tree | 1cb3cf7ea3104d2dd68d9f5f48c1183e037ad244 /packages | |
parent | 8799f9bb90c6bcfffc74550d74ed87422467f9e1 (diff) | |
download | dexon-sol-tools-4417c76b130655da3b14209148191d43037e8f8a.tar.gz dexon-sol-tools-4417c76b130655da3b14209148191d43037e8f8a.tar.zst dexon-sol-tools-4417c76b130655da3b14209148191d43037e8f8a.zip |
Ported Balance Threshold Filter to new contract directory structure
Diffstat (limited to 'packages')
6 files changed, 0 insertions, 2242 deletions
diff --git a/packages/contracts/contracts/extensions/BalanceThresholdFilter/BalanceThresholdFilter.sol b/packages/contracts/contracts/extensions/BalanceThresholdFilter/BalanceThresholdFilter.sol deleted file mode 100644 index bf4a94509..000000000 --- a/packages/contracts/contracts/extensions/BalanceThresholdFilter/BalanceThresholdFilter.sol +++ /dev/null @@ -1,44 +0,0 @@ -/* - - 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 "../../protocol/Exchange/interfaces/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; - } -}
\ No newline at end of file diff --git a/packages/contracts/contracts/extensions/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol b/packages/contracts/contracts/extensions/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol deleted file mode 100644 index 0ad8ccddf..000000000 --- a/packages/contracts/contracts/extensions/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol +++ /dev/null @@ -1,319 +0,0 @@ -/* - - 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); - } -}
\ No newline at end of file diff --git a/packages/contracts/contracts/extensions/BalanceThresholdFilter/interfaces/IThresholdAsset.sol b/packages/contracts/contracts/extensions/BalanceThresholdFilter/interfaces/IThresholdAsset.sol deleted file mode 100644 index 61acaba0a..000000000 --- a/packages/contracts/contracts/extensions/BalanceThresholdFilter/interfaces/IThresholdAsset.sol +++ /dev/null @@ -1,30 +0,0 @@ -/* - - 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); - -}
\ No newline at end of file diff --git a/packages/contracts/contracts/extensions/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol b/packages/contracts/contracts/extensions/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol deleted file mode 100644 index 612fd481c..000000000 --- a/packages/contracts/contracts/extensions/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol +++ /dev/null @@ -1,81 +0,0 @@ -/* - - 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 "../../../protocol/Exchange/interfaces/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; -}
\ No newline at end of file diff --git a/packages/contracts/test/extensions/balance_threshold_filter.ts b/packages/contracts/test/extensions/balance_threshold_filter.ts deleted file mode 100644 index c4723e7aa..000000000 --- a/packages/contracts/test/extensions/balance_threshold_filter.ts +++ /dev/null @@ -1,1521 +0,0 @@ -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { assetDataUtils } from '@0x/order-utils'; -import { RevertReason, SignedOrder, Order } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; - -import { DummyERC20TokenContract } from '../../generated-wrappers/dummy_erc20_token'; -import { ExchangeContract } from '../../generated-wrappers/exchange'; -import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter'; - -import { artifacts } from '../../src/artifacts'; -import { - expectTransactionFailedAsync, - expectTransactionFailedWithoutReasonAsync, -} from '../utils/assertions'; -import { chaiSetup } from '../utils/chai_setup'; -import { constants } from '../utils/constants'; -import { ERC20Wrapper } from '../utils/erc20_wrapper'; -import { ExchangeWrapper } from '../utils/exchange_wrapper'; -import { MatchOrderTester } from '../utils/match_order_tester'; -import { OrderFactory } from '../utils/order_factory'; -import { orderUtils } from '../utils/order_utils'; -import { TransactionFactory } from '../utils/transaction_factory'; -import { BalanceThresholdWrapper } from '../utils/balance_threshold_wrapper'; -import { ContractName, ERC20BalancesByOwner, SignedTransaction, OrderStatus } from '../utils/types'; -import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; -import { TestExchangeInternalsContract } from '../../generated-wrappers/test_exchange_internals'; - -import { MethodAbi, AbiDefinition } from 'ethereum-types'; -import { AbiEncoder } from '@0x/utils'; -import { Method } from '@0x/utils/lib/src/abi_encoder'; -import { LogDecoder } from '../utils/log_decoder'; -import { ERC721Wrapper } from '../utils/erc721_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -const DECIMALS_DEFAULT = 18; - -interface ValidatedAddressesLog { - args: {addresses: string[]} -} - -describe.only(ContractName.BalanceThresholdFilter, () => { - let compliantMakerAddress: string; - let compliantMakerAddress2: string; - let owner: string; - let compliantTakerAddress: string; - let feeRecipientAddress: string; - let nonCompliantAddress: string; - let defaultMakerAssetAddress: string; - let defaultTakerAssetAddress: string; - let zrxAssetData: string; - let zrxToken: DummyERC20TokenContract; - let exchangeInstance: ExchangeContract; - let exchangeWrapper: ExchangeWrapper; - - let orderFactory: OrderFactory; - let orderFactory2: OrderFactory; - let nonCompliantOrderFactory: OrderFactory; - let erc20Wrapper: ERC20Wrapper; - let erc20Balances: ERC20BalancesByOwner; - let erc20TakerBalanceThresholdWrapper: BalanceThresholdWrapper; - let erc721TakerBalanceThresholdWrapper: BalanceThresholdWrapper; - let erc721MakerBalanceThresholdWrapper: BalanceThresholdWrapper; - let erc721NonCompliantBalanceThresholdWrapper: BalanceThresholdWrapper; - - let takerTransactionFactory: TransactionFactory; - let makerTransactionFactory: TransactionFactory; - let compliantSignedOrder: SignedOrder; - let compliantSignedOrder2: SignedOrder; - let compliantSignedFillOrderTx: SignedTransaction; - - let logDecoder: LogDecoder; - let exchangeInternals: TestExchangeInternalsContract; - - let defaultOrderParams: Partial<Order>; - - const takerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(500), DECIMALS_DEFAULT); - const makerAssetAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), DECIMALS_DEFAULT); - const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(250), DECIMALS_DEFAULT); - - let erc721CompliantForwarderInstance: BalanceThresholdFilterContract; - let erc20CompliantForwarderInstance: BalanceThresholdFilterContract; - - const assertValidatedAddressesLog = async (txReceipt: TransactionReceiptWithDecodedLogs, expectedValidatedAddresses: string[]) => { - expect(txReceipt.logs.length).to.be.gte(1); - const validatedAddressesLog = (txReceipt.logs[0] as any) as ValidatedAddressesLog; - const validatedAddresses = validatedAddressesLog.args.addresses; - // @HACK-hysz: Nested addresses are not translated to lower-case but this will change once - // the new ABI Encoder/Decoder is used by the contract templates. - let validatedAddressesNormalized: string[] = []; - _.each(validatedAddresses, (address) => { - const normalizedAddress = _.toLower(address); - validatedAddressesNormalized.push(normalizedAddress); - }); - expect(validatedAddressesNormalized).to.be.deep.equal(expectedValidatedAddresses); - }; - - before(async () => { - // Create accounts - await blockchainLifecycle.startAsync(); - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([ - owner, - compliantMakerAddress, - compliantMakerAddress2, - compliantTakerAddress, - feeRecipientAddress, - nonCompliantAddress, - ] = accounts); - // Create wrappers - erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); - let compliantAddresses = _.cloneDeepWith(usedAddresses); - _.remove(compliantAddresses, (address: string) => { - return address === nonCompliantAddress; - }); - const erc721Wrapper = new ERC721Wrapper(provider, compliantAddresses, owner); - // Deploy ERC20 tokens - const numDummyErc20ToDeploy = 4; - let erc20TokenA: DummyERC20TokenContract; - let erc20TokenB: DummyERC20TokenContract; - let erc20BalanceThresholdAsset: DummyERC20TokenContract; - [erc20TokenA, erc20TokenB, zrxToken, erc20BalanceThresholdAsset] = await erc20Wrapper.deployDummyTokensAsync( - numDummyErc20ToDeploy, - constants.DUMMY_TOKEN_DECIMALS, - ); - defaultMakerAssetAddress = erc20TokenA.address; - defaultTakerAssetAddress = erc20TokenB.address; - zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); - // Create proxies - const erc20Proxy = await erc20Wrapper.deployProxyAsync(); - await erc20Wrapper.setBalancesAndAllowancesAsync(); - // Deploy Exchange congtract - exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync( - artifacts.Exchange, - provider, - txDefaults, - zrxAssetData, - ); - exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider); - // Register proxies - await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); - await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, { - from: owner, - }); - // Deploy Compliant Forwarder - const erc721alanceThreshold = new BigNumber(1); - await erc721Wrapper.deployProxyAsync(); - const [erc721BalanceThresholdAsset] = await erc721Wrapper.deployDummyTokensAsync(); - await erc721Wrapper.setBalancesAndAllowancesAsync(); - erc721CompliantForwarderInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync( - artifacts.BalanceThresholdFilter, - provider, - txDefaults, - exchangeInstance.address, - erc721BalanceThresholdAsset.address, - erc721alanceThreshold - ); - const erc20BalanceThreshold = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 10); - erc20CompliantForwarderInstance = await BalanceThresholdFilterContract.deployFrom0xArtifactAsync( - artifacts.BalanceThresholdFilter, - provider, - txDefaults, - exchangeInstance.address, - erc20BalanceThresholdAsset.address, - erc20BalanceThreshold - ); - - // Default order parameters - defaultOrderParams = { - exchangeAddress: exchangeInstance.address, - feeRecipientAddress, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress), - makerAssetAmount, - takerAssetAmount, - makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), DECIMALS_DEFAULT), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(150), DECIMALS_DEFAULT), - senderAddress: erc721CompliantForwarderInstance.address, - }; - const defaultOrderParams1 = { - makerAddress: compliantMakerAddress, - ... - defaultOrderParams, - } - const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantMakerAddress)]; - takerTransactionFactory = new TransactionFactory(makerPrivateKey, exchangeInstance.address); - orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams1); - const defaultOrderParams2 = { - makerAddress: compliantMakerAddress2, - ... - defaultOrderParams, - } - const secondMakerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantMakerAddress2)]; - orderFactory2 = new OrderFactory(secondMakerPrivateKey, defaultOrderParams2); - - const nonCompliantPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(nonCompliantAddress)]; - const defaultNonCompliantOrderParams = { - makerAddress: nonCompliantAddress, - ... - defaultOrderParams, - }; - nonCompliantOrderFactory = new OrderFactory(nonCompliantPrivateKey, defaultNonCompliantOrderParams); - // Create Valid/Invalid orders - const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(compliantTakerAddress)]; - takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchangeInstance.address); - compliantSignedOrder = await orderFactory.newSignedOrderAsync({ - senderAddress: erc721CompliantForwarderInstance.address, - }); - const compliantSignedOrderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress( - compliantSignedOrder, - ); - const compliantSignedOrderWithoutExchangeAddressData = exchangeInstance.fillOrder.getABIEncodedTransactionData( - compliantSignedOrderWithoutExchangeAddress, - takerAssetFillAmount, - compliantSignedOrder.signature, - ); - compliantSignedFillOrderTx = takerTransactionFactory.newSignedTransaction( - compliantSignedOrderWithoutExchangeAddressData, - ); - - logDecoder = new LogDecoder(web3Wrapper); - erc20TakerBalanceThresholdWrapper = new BalanceThresholdWrapper(erc20CompliantForwarderInstance, exchangeInstance, new TransactionFactory(takerPrivateKey, exchangeInstance.address), provider); - erc721TakerBalanceThresholdWrapper = new BalanceThresholdWrapper(erc721CompliantForwarderInstance, exchangeInstance, new TransactionFactory(takerPrivateKey, exchangeInstance.address), provider); - erc721MakerBalanceThresholdWrapper = new BalanceThresholdWrapper(erc721CompliantForwarderInstance, exchangeInstance, new TransactionFactory(makerPrivateKey, exchangeInstance.address), provider); - erc721NonCompliantBalanceThresholdWrapper = new BalanceThresholdWrapper(erc721CompliantForwarderInstance, exchangeInstance, new TransactionFactory(nonCompliantPrivateKey, exchangeInstance.address), provider); - - // Instantiate internal exchange contract - exchangeInternals = await TestExchangeInternalsContract.deployFrom0xArtifactAsync( - artifacts.TestExchangeInternals, - provider, - txDefaults, - ); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - - describe.only('General Sanity Checks', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it.only('should transfer the correct amounts and validate both maker/taker when both maker and taker exceed the balance threshold of an ERC20 token', async () => { - const compliantSignedOrderERC20Sender = await orderFactory.newSignedOrderAsync({ - ... - defaultOrderParams, - makerAddress: compliantMakerAddress, - senderAddress: erc20TakerBalanceThresholdWrapper.getBalanceThresholdAddress(), - }); - // Execute a valid fill - const txReceipt = await erc20TakerBalanceThresholdWrapper.fillOrderAsync(compliantSignedOrderERC20Sender, compliantTakerAddress, {takerAssetFillAmount}); - // Assert validated addresses - const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress]; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerAssetFillAmount = takerAssetFillAmount - .times(compliantSignedOrder.makerAssetAmount) - .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount); - const makerFeePaid = compliantSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); - const takerFeePaid = compliantSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); - expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), - ); - }); - it('should revert if the signed transaction is not intended for supported', async () => { - // Create signed order without the fillOrder function selector - const txDataBuf = ethUtil.toBuffer(compliantSignedFillOrderTx.data); - const selectorLengthInBytes = 4; - const txDataBufMinusSelector = txDataBuf.slice(selectorLengthInBytes); - const badSelector = '0x00000000'; - const badSelectorBuf = ethUtil.toBuffer(badSelector); - const txDataBufWithBadSelector = Buffer.concat([badSelectorBuf, txDataBufMinusSelector]); - const txDataBufWithBadSelectorHex = ethUtil.bufferToHex(txDataBufWithBadSelector); - // Call compliant forwarder - return expectTransactionFailedWithoutReasonAsync(erc721CompliantForwarderInstance.executeTransaction.sendTransactionAsync( - compliantSignedFillOrderTx.salt, - compliantSignedFillOrderTx.signerAddress, - txDataBufWithBadSelectorHex, - compliantSignedFillOrderTx.signature, - )); - }); - it('should revert if senderAddress is not set to the compliant forwarding contract', async () => { - // Create signed order with incorrect senderAddress - const notBalanceThresholdFilterAddress = zrxToken.address; - const signedOrderWithBadSenderAddress = await orderFactory.newSignedOrderAsync({ - senderAddress: notBalanceThresholdFilterAddress, - }); - const signedOrderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress( - signedOrderWithBadSenderAddress, - ); - const signedOrderWithoutExchangeAddressData = exchangeInstance.fillOrder.getABIEncodedTransactionData( - signedOrderWithoutExchangeAddress, - takerAssetFillAmount, - compliantSignedOrder.signature, - ); - const signedFillOrderTx = takerTransactionFactory.newSignedTransaction( - signedOrderWithoutExchangeAddressData, - ); - // Call compliant forwarder - return expectTransactionFailedWithoutReasonAsync(erc721CompliantForwarderInstance.executeTransaction.sendTransactionAsync( - signedFillOrderTx.salt, - signedFillOrderTx.signerAddress, - signedFillOrderTx.data, - signedFillOrderTx.signature, - )); - }); - // @TODO - greater than 1 balance - }); - - describe('batchFillOrders', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both maker and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync(orders, compliantTakerAddress, {takerAssetFillAmounts}); - // Assert validated addresses - const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress]; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2); - const makerAssetFillAmount = takerAssetFillAmount - .times(compliantSignedOrder.makerAssetAmount) - .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount); - const makerFeePaid = compliantSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); - const takerFeePaid = compliantSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount) - .times(2); - // Maker #1 - expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - // Maker #2 - expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid), - ); - // Taker - expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - - expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)), - ); - expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.times(2).add(takerFeePaid)), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-compliant maker address - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: nonCompliantAddress - }); - const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.batchFillOrdersAsync( - orders, - compliantTakerAddress, - {takerAssetFillAmounts} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - return expectTransactionFailedAsync( - erc721NonCompliantBalanceThresholdWrapper.batchFillOrdersAsync( - orders, - nonCompliantAddress, - {takerAssetFillAmounts} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - }); - - describe('batchFillOrdersNoThrow', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both maker and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync(orders, compliantTakerAddress, {takerAssetFillAmounts}); - // Assert validated addresses - const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress]; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2); - const makerAssetFillAmount = takerAssetFillAmount - .times(compliantSignedOrder.makerAssetAmount) - .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount); - const makerFeePaid = compliantSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); - const takerFeePaid = compliantSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount) - .times(2); - // Maker #1 - expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - // Maker #2 - expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid), - ); - // Taker - expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - - expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)), - ); - expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.times(2).add(takerFeePaid)), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-compliant maker address - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: nonCompliantAddress - }); - const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.batchFillOrdersNoThrowAsync( - orders, - compliantTakerAddress, - {takerAssetFillAmounts} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - return expectTransactionFailedAsync( - erc721NonCompliantBalanceThresholdWrapper.batchFillOrdersNoThrowAsync( - orders, - nonCompliantAddress, - {takerAssetFillAmounts} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - }); - - describe('batchFillOrKillOrders', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - const txReceipt = await erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync(orders, compliantTakerAddress, {takerAssetFillAmounts}); - // Assert validated addresses - const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress]; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const cumulativeTakerAssetFillAmount = takerAssetFillAmount.times(2); - const makerAssetFillAmount = takerAssetFillAmount - .times(compliantSignedOrder.makerAssetAmount) - .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount); - const makerFeePaid = compliantSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); - const takerFeePaid = compliantSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount) - .times(2); - // Maker #1 - expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - // Maker #2 - expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid), - ); - // Taker - expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - - expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount.times(2)), - ); - expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.times(2).add(takerFeePaid)), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-compliant maker address - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: nonCompliantAddress - }); - const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync( - orders, - compliantTakerAddress, - {takerAssetFillAmounts} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, takerAssetFillAmount]; - return expectTransactionFailedAsync( - erc721NonCompliantBalanceThresholdWrapper.batchFillOrKillOrdersAsync( - orders, - nonCompliantAddress, - {takerAssetFillAmounts} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if one takerAssetFillAmount is not fully filled', async () => { - const tooBigTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.times(2); - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const takerAssetFillAmounts = [takerAssetFillAmount, tooBigTakerAssetFillAmount]; - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.batchFillOrKillOrdersAsync( - orders, - compliantTakerAddress, - {takerAssetFillAmounts} - ), - RevertReason.FailedExecution - ); - }); - }); - - describe('fillOrder', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => { - // Execute a valid fill - const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderAsync(compliantSignedOrder, compliantTakerAddress, {takerAssetFillAmount}); - // Assert validated addresses - const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress]; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerAssetFillAmount = takerAssetFillAmount - .times(compliantSignedOrder.makerAssetAmount) - .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount); - const makerFeePaid = compliantSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); - const takerFeePaid = compliantSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); - expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), - ); - }); - it('should revert if maker does not meet the balance threshold', async () => { - // Create signed order with non-compliant maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - senderAddress: erc721CompliantForwarderInstance.address, - makerAddress: nonCompliantAddress - }); - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.fillOrderAsync( - signedOrderWithBadMakerAddress, - compliantTakerAddress, - {takerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - return expectTransactionFailedAsync( - erc721NonCompliantBalanceThresholdWrapper.fillOrderAsync( - compliantSignedOrder, - nonCompliantAddress, - {takerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - }); - - describe('fillOrderNoThrow', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => { - // Execute a valid fill - const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync(compliantSignedOrder, compliantTakerAddress, {takerAssetFillAmount}); - // Assert validated addresses - const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress]; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerAssetFillAmount = takerAssetFillAmount - .times(compliantSignedOrder.makerAssetAmount) - .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount); - const makerFeePaid = compliantSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); - const takerFeePaid = compliantSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); - expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), - ); - }); - it('should revert if maker does not meet the balance threshold', async () => { - // Create signed order with non-compliant maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - senderAddress: erc721CompliantForwarderInstance.address, - makerAddress: nonCompliantAddress - }); - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.fillOrderNoThrowAsync( - signedOrderWithBadMakerAddress, - compliantTakerAddress, - {takerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - return expectTransactionFailedAsync( - erc721NonCompliantBalanceThresholdWrapper.fillOrderNoThrowAsync( - compliantSignedOrder, - nonCompliantAddress, - {takerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - }); - - describe('fillOrKillOrder', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both maker/taker when both maker and taker meet the balance threshold', async () => { - // Execute a valid fill - const takerAssetFillAmount_ = compliantSignedOrder.takerAssetAmount; - const txReceipt = await erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync(compliantSignedOrder, compliantTakerAddress, {takerAssetFillAmount: takerAssetFillAmount_}); - // Assert validated addresses - const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedFillOrderTx.signerAddress]; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerAssetFillAmount = takerAssetFillAmount_ - .times(compliantSignedOrder.makerAssetAmount) - .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount); - const makerFeePaid = compliantSignedOrder.makerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); - const takerFeePaid = compliantSignedOrder.takerFee - .times(makerAssetFillAmount) - .dividedToIntegerBy(compliantSignedOrder.makerAssetAmount); - expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(takerAssetFillAmount_), - ); - expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][zrxToken.address].minus(makerFeePaid), - ); - expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount_), - ); - expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(makerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), - ); - }); - it('should revert if maker does not meet the balance threshold', async () => { - // Create signed order with non-compliant maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - senderAddress: erc721CompliantForwarderInstance.address, - makerAddress: nonCompliantAddress - }); - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync( - signedOrderWithBadMakerAddress, - compliantTakerAddress, - {takerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - return expectTransactionFailedAsync( - erc721NonCompliantBalanceThresholdWrapper.fillOrKillOrderAsync( - compliantSignedOrder, - nonCompliantAddress, - {takerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if takerAssetFillAmount is not fully filled', async () => { - const tooBigTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.times(2); - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.fillOrKillOrderAsync( - compliantSignedOrder, - compliantTakerAddress, - {takerAssetFillAmount: tooBigTakerAssetFillAmount} - ), - RevertReason.FailedExecution - ); - }); - }); - - describe('marketSellOrders', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount); - const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync(orders, compliantTakerAddress, {takerAssetFillAmount: cumulativeTakerAssetFillAmount}); - // Assert validated addresses - const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress]; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerAssetFillAmount2 = takerAssetFillAmount - .times(compliantSignedOrder.makerAssetAmount) - .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount); - const makerFeePaid2 = compliantSignedOrder2.makerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount); - const takerFeePaid2 = compliantSignedOrder2.takerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount); - const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2); - const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2); - // Maker #1 - expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(compliantSignedOrder.makerAssetAmount), - ); - expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(compliantSignedOrder.takerAssetAmount), - ); - expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee), - ); - // Maker #2 - expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2), - ); - expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2), - ); - // Taker - expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(compliantSignedOrder.makerFee).add(makerFeePaid2).add(takerFeePaid), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-compliant maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: nonCompliantAddress - }); - const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.marketSellOrdersAsync( - orders, - compliantTakerAddress, - {takerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [compliantSignedOrder, compliantSignedOrder2]; - return expectTransactionFailedAsync( - erc721NonCompliantBalanceThresholdWrapper.marketSellOrdersAsync( - orders, - nonCompliantAddress, - {takerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - }); - - describe('marketSellOrdersNoThrow', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount); - const txReceipt = await erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync(orders, compliantTakerAddress, {takerAssetFillAmount: cumulativeTakerAssetFillAmount}); - // Assert validated addresses - const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress]; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerAssetFillAmount2 = takerAssetFillAmount - .times(compliantSignedOrder.makerAssetAmount) - .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount); - const makerFeePaid2 = compliantSignedOrder2.makerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount); - const takerFeePaid2 = compliantSignedOrder2.takerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount); - const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2); - const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2); - // Maker #1 - expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(compliantSignedOrder.makerAssetAmount), - ); - expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(compliantSignedOrder.takerAssetAmount), - ); - expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee), - ); - // Maker #2 - expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2), - ); - expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2), - ); - // Taker - expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(compliantSignedOrder.makerFee).add(makerFeePaid2).add(takerFeePaid), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-compliant maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: nonCompliantAddress - }); - const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.marketSellOrdersNoThrowAsync( - orders, - compliantTakerAddress, - {takerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [compliantSignedOrder, compliantSignedOrder2]; - return expectTransactionFailedAsync( - erc721NonCompliantBalanceThresholdWrapper.marketSellOrdersNoThrowAsync( - orders, - nonCompliantAddress, - {takerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - }); - - describe('marketBuyOrders', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount); - const makerAssetFillAmount2 = takerAssetFillAmount - .times(compliantSignedOrder.makerAssetAmount) - .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount); - const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2); - const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync(orders, compliantTakerAddress, {makerAssetFillAmount: cumulativeMakerAssetFillAmount}); - // Assert validated addresses - const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress]; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerFeePaid2 = compliantSignedOrder2.makerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount); - const takerFeePaid2 = compliantSignedOrder2.takerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount); - const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2); - // Maker #1 - expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(compliantSignedOrder.makerAssetAmount), - ); - expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(compliantSignedOrder.takerAssetAmount), - ); - expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee), - ); - // Maker #2 - expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2), - ); - expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2), - ); - // Taker - expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(compliantSignedOrder.makerFee).add(makerFeePaid2).add(takerFeePaid), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-compliant maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: nonCompliantAddress - }); - const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - const dummyMakerAssetFillAmount = new BigNumber(0); - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.marketBuyOrdersAsync( - orders, - compliantTakerAddress, - {makerAssetFillAmount: dummyMakerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const dummyMakerAssetFillAmount = new BigNumber(0); - return expectTransactionFailedAsync( - erc721NonCompliantBalanceThresholdWrapper.marketBuyOrdersAsync( - orders, - nonCompliantAddress, - {makerAssetFillAmount: dummyMakerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - }); - - describe('marketBuyOrdersNoThrowAsync', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('should transfer the correct amounts and validate both makers/taker when both makers and taker meet the balance threshold', async () => { - // Execute a valid fill - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const cumulativeTakerAssetFillAmount = compliantSignedOrder.takerAssetAmount.plus(takerAssetFillAmount); - const makerAssetFillAmount2 = takerAssetFillAmount - .times(compliantSignedOrder.makerAssetAmount) - .dividedToIntegerBy(compliantSignedOrder.takerAssetAmount); - const cumulativeMakerAssetFillAmount = compliantSignedOrder.makerAssetAmount.plus(makerAssetFillAmount2); - const txReceipt = await erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync(orders, compliantTakerAddress, {makerAssetFillAmount: cumulativeMakerAssetFillAmount}); - // Assert validated addresses - const expectedValidatedAddresseses = [compliantSignedOrder.makerAddress, compliantSignedOrder2.makerAddress, compliantSignedFillOrderTx.signerAddress]; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - const makerFeePaid2 = compliantSignedOrder2.makerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount); - const takerFeePaid2 = compliantSignedOrder2.takerFee - .times(makerAssetFillAmount2) - .dividedToIntegerBy(compliantSignedOrder2.makerAssetAmount); - const takerFeePaid = compliantSignedOrder.takerFee.plus(takerFeePaid2); - // Maker #1 - expect(newBalances[compliantMakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultMakerAssetAddress].minus(compliantSignedOrder.makerAssetAmount), - ); - expect(newBalances[compliantMakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][defaultTakerAssetAddress].add(compliantSignedOrder.takerAssetAmount), - ); - expect(newBalances[compliantMakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress][zrxToken.address].minus(compliantSignedOrder.makerFee), - ); - // Maker #2 - expect(newBalances[compliantMakerAddress2][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultMakerAssetAddress].minus(makerAssetFillAmount2), - ); - expect(newBalances[compliantMakerAddress2][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][defaultTakerAssetAddress].add(takerAssetFillAmount), - ); - expect(newBalances[compliantMakerAddress2][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantMakerAddress2][zrxToken.address].minus(makerFeePaid2), - ); - // Taker - expect(newBalances[compliantTakerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultTakerAssetAddress].minus(cumulativeTakerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(cumulativeMakerAssetFillAmount), - ); - expect(newBalances[compliantTakerAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[compliantTakerAddress][zrxToken.address].minus(takerFeePaid), - ); - // Fee recipient - expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(compliantSignedOrder.makerFee).add(makerFeePaid2).add(takerFeePaid), - ); - }); - it('should revert if one maker does not meet the balance threshold', async () => { - // Create order set with one non-compliant maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - makerAddress: nonCompliantAddress - }); - const orders = [compliantSignedOrder, signedOrderWithBadMakerAddress]; - // Execute transaction - const dummyMakerAssetFillAmount = new BigNumber(0); - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync( - orders, - compliantTakerAddress, - {makerAssetFillAmount: dummyMakerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - const orders = [compliantSignedOrder, compliantSignedOrder2]; - const dummyMakerAssetFillAmount = new BigNumber(0); - return expectTransactionFailedAsync( - erc721NonCompliantBalanceThresholdWrapper.marketBuyOrdersNoThrowAsync( - orders, - nonCompliantAddress, - {makerAssetFillAmount: dummyMakerAssetFillAmount} - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - }); - - describe('matchOrders', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('Should transfer correct amounts when both makers and taker meet the balance threshold', async () => { - // Test values/results taken from Match Orders test: - // 'Should transfer correct amounts when right order is fully filled and values pass isRoundingErrorFloor but fail isRoundingErrorCeil' - // Create orders to match - const signedOrderLeft = await orderFactory.newSignedOrderAsync({ - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(17), 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(98), 0), - makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), - feeRecipientAddress: feeRecipientAddress, - }); - const signedOrderRight = await orderFactory2.newSignedOrderAsync({ - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0), - makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), - feeRecipientAddress: feeRecipientAddress, - }); - // Compute expected transfer amounts - const expectedTransferAmounts = { - // Left Maker - amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0), - amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0), - feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.4705882352941176'), 16), // 76.47% - // Right Maker - amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 0), - amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(13), 0), - feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% - // Taker - amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 0), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('76.5306122448979591'), 16), // 76.53% - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% - }; - const txReceipt = await erc721TakerBalanceThresholdWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, compliantTakerAddress); - // Assert validated addresses - const expectedValidatedAddresseses = [signedOrderLeft.makerAddress, signedOrderRight.makerAddress, compliantTakerAddress]; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check balances - const newBalances = await erc20Wrapper.getBalancesAsync(); - expect( - newBalances[signedOrderLeft.makerAddress][defaultMakerAssetAddress], - 'Checking left maker egress ERC20 account balance', - ).to.be.bignumber.equal(erc20Balances[signedOrderLeft.makerAddress][defaultMakerAssetAddress].sub(expectedTransferAmounts.amountSoldByLeftMaker)); - expect( - newBalances[signedOrderRight.makerAddress][defaultTakerAssetAddress], - 'Checking right maker ingress ERC20 account balance', - ).to.be.bignumber.equal(erc20Balances[signedOrderRight.makerAddress][defaultTakerAssetAddress].sub(expectedTransferAmounts.amountSoldByRightMaker)); - expect( - newBalances[compliantTakerAddress][defaultMakerAssetAddress], - 'Checking taker ingress ERC20 account balance', - ).to.be.bignumber.equal(erc20Balances[compliantTakerAddress][defaultMakerAssetAddress].add(expectedTransferAmounts.amountReceivedByTaker)); - expect( - newBalances[signedOrderLeft.makerAddress][defaultTakerAssetAddress], - 'Checking left maker ingress ERC20 account balance', - ).to.be.bignumber.equal(erc20Balances[signedOrderLeft.makerAddress][defaultTakerAssetAddress].add(expectedTransferAmounts.amountBoughtByLeftMaker)); - expect( - newBalances[signedOrderRight.makerAddress][defaultMakerAssetAddress], - 'Checking right maker egress ERC20 account balance', - ).to.be.bignumber.equal( - erc20Balances[signedOrderRight.makerAddress][defaultMakerAssetAddress].add(expectedTransferAmounts.amountBoughtByRightMaker), - ); - // Paid fees - expect( - newBalances[signedOrderLeft.makerAddress][zrxToken.address], - 'Checking left maker egress ERC20 account fees', - ).to.be.bignumber.equal(erc20Balances[signedOrderLeft.makerAddress][zrxToken.address].minus(expectedTransferAmounts.feePaidByLeftMaker)); - expect( - newBalances[signedOrderRight.makerAddress][zrxToken.address], - 'Checking right maker egress ERC20 account fees', - ).to.be.bignumber.equal(erc20Balances[signedOrderRight.makerAddress][zrxToken.address].minus(expectedTransferAmounts.feePaidByRightMaker)); - expect( - newBalances[compliantTakerAddress][zrxToken.address], - 'Checking taker egress ERC20 account fees', - ).to.be.bignumber.equal(erc20Balances[compliantTakerAddress][zrxToken.address].minus(expectedTransferAmounts.feePaidByTakerLeft).sub(expectedTransferAmounts.feePaidByTakerRight)); - // Received fees - expect( - newBalances[signedOrderLeft.feeRecipientAddress][zrxToken.address], - 'Checking left fee recipient ingress ERC20 account fees', - ).to.be.bignumber.equal( - erc20Balances[feeRecipientAddress][zrxToken.address].add(expectedTransferAmounts.feePaidByLeftMaker).add(expectedTransferAmounts.feePaidByRightMaker).add(expectedTransferAmounts.feePaidByTakerLeft).add(expectedTransferAmounts.feePaidByTakerRight), - ); - }); - it('should revert if left maker does not meet the balance threshold', async () => { - // Create signed order with non-compliant maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - senderAddress: erc721CompliantForwarderInstance.address, - makerAddress: nonCompliantAddress - }); - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.matchOrdersAsync( - compliantSignedOrder, - signedOrderWithBadMakerAddress, - compliantTakerAddress, - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if right maker does not meet the balance threshold', async () => { - // Create signed order with non-compliant maker address - const signedOrderWithBadMakerAddress = await orderFactory.newSignedOrderAsync({ - senderAddress: erc721CompliantForwarderInstance.address, - makerAddress: nonCompliantAddress - }); - // Execute transaction - return expectTransactionFailedAsync( - erc721TakerBalanceThresholdWrapper.matchOrdersAsync( - signedOrderWithBadMakerAddress, - compliantSignedOrder, - compliantTakerAddress, - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - it('should revert if taker does not meet the balance threshold', async () => { - return expectTransactionFailedAsync( - erc721NonCompliantBalanceThresholdWrapper.matchOrdersAsync( - compliantSignedOrder, - compliantSignedOrder, - nonCompliantAddress, - ), - RevertReason.AtLeastOneAddressDoesNotMeetBalanceThreshold - ); - }); - }); - - describe('cancelOrder', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - compliantSignedOrder = await orderFactory.newSignedOrderAsync(); - compliantSignedOrder2 = await orderFactory2.newSignedOrderAsync(); - }); - it('Should successfully cancel order if maker meets balance threshold', async () => { - // Verify order is not cancelled - const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder) - expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); - // Cancel - const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrderAsync(compliantSignedOrder, compliantSignedOrder.makerAddress); - // Assert validated addresses - const expectedValidatedAddresseses: string[] = []; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check that order was cancelled - const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder) - expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED); - }); - it('Should successfully cancel order if maker does not meet balance threshold', async () => { - // Create order where maker does not meet balance threshold - const signedOrderWithBadMakerAddress = await nonCompliantOrderFactory.newSignedOrderAsync({}); - // Verify order is not cancelled - const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(signedOrderWithBadMakerAddress) - expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); - // Cancel - const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.cancelOrderAsync(signedOrderWithBadMakerAddress, signedOrderWithBadMakerAddress.makerAddress); - // Assert validated addresses - const expectedValidatedAddresseses: string[] = []; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check that order was cancelled - const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(signedOrderWithBadMakerAddress) - expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED); - }); - }); - - describe('batchCancelOrders', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - }); - it('Should successfully batch cancel orders if maker meets balance threshold', async () => { - // Create orders to cancel - const compliantSignedOrders = [ - await orderFactory.newSignedOrderAsync(), - await orderFactory.newSignedOrderAsync(), - await orderFactory.newSignedOrderAsync(), - ]; - // Verify orders are not cancelled - await _.each(compliantSignedOrders, async (compliantSignedOrder) => { - const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder) - return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); - }); - // Cancel - const txReceipt = await erc721MakerBalanceThresholdWrapper.batchCancelOrdersAsync(compliantSignedOrders, compliantSignedOrder.makerAddress); - // Assert validated addresses - const expectedValidatedAddresseses: string[] = []; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check that order was cancelled - await _.each(compliantSignedOrders, async (compliantSignedOrder) => { - const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder) - return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED); - }); - }); - it('Should successfully batch cancel order if maker does not meet balance threshold', async () => { - // Create orders to cancel - const nonCompliantSignedOrders = [ - await nonCompliantOrderFactory.newSignedOrderAsync(), - await nonCompliantOrderFactory.newSignedOrderAsync(), - await nonCompliantOrderFactory.newSignedOrderAsync(), - ]; - // Verify orders are not cancelled - await _.each(nonCompliantSignedOrders, async (nonCompliantSignedOrder) => { - const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(nonCompliantSignedOrder) - return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); - }); - // Cancel - const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.batchCancelOrdersAsync(nonCompliantSignedOrders, nonCompliantAddress); - // Assert validated addresses - const expectedValidatedAddresseses: string[] = []; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check that order was cancelled - await _.each(nonCompliantSignedOrders, async (nonCompliantSignedOrder) => { - const orderInfoAfterCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(nonCompliantSignedOrder) - return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED); - }); - }); - }); - - describe('cancelOrdersUpTo', () => { - beforeEach(async () => { - erc20Balances = await erc20Wrapper.getBalancesAsync(); - }); - it('Should successfully batch cancel orders if maker meets balance threshold', async () => { - // Create orders to cancel - const compliantSignedOrders = [ - await orderFactory.newSignedOrderAsync({salt: new BigNumber(0)}), - await orderFactory.newSignedOrderAsync({salt: new BigNumber(1)}), - await orderFactory.newSignedOrderAsync({salt: new BigNumber(2)}), - ]; - // Verify orders are not cancelled - await _.each(compliantSignedOrders, async (compliantSignedOrder) => { - const orderInfoBeforeCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder) - return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); - }); - // Cancel - const cancelOrdersUpToThisSalt = new BigNumber(1); - const txReceipt = await erc721MakerBalanceThresholdWrapper.cancelOrdersUpToAsync(cancelOrdersUpToThisSalt, compliantSignedOrder.makerAddress); - // Assert validated addresses - const expectedValidatedAddresseses: string[] = []; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check that order was cancelled - await _.each(compliantSignedOrders, async (compliantSignedOrder, salt: number) => { - const orderInfoAfterCancelling = await erc721MakerBalanceThresholdWrapper.getOrderInfoAsync(compliantSignedOrder) - const saltAsBigNumber = new BigNumber(salt); - if (saltAsBigNumber.lessThanOrEqualTo(cancelOrdersUpToThisSalt)) { - return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED); - } else { - return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); - } - }); - }); - it('Should successfully batch cancel order if maker does not meet balance threshold', async () => { - // Create orders to cancel - const nonCompliantSignedOrders = [ - await nonCompliantOrderFactory.newSignedOrderAsync({salt: new BigNumber(0)}), - await nonCompliantOrderFactory.newSignedOrderAsync({salt: new BigNumber(1)}), - await nonCompliantOrderFactory.newSignedOrderAsync({salt: new BigNumber(2)}), - ]; - // Verify orders are not cancelled - await _.each(nonCompliantSignedOrders, async (nonCompliantSignedOrder) => { - const orderInfoBeforeCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(nonCompliantSignedOrder) - return expect(orderInfoBeforeCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); - }); - // Cancel - const cancelOrdersUpToThisSalt = new BigNumber(1); - const txReceipt = await erc721NonCompliantBalanceThresholdWrapper.cancelOrdersUpToAsync(cancelOrdersUpToThisSalt, nonCompliantAddress); - // Assert validated addresses - const expectedValidatedAddresseses: string[] = []; - assertValidatedAddressesLog(txReceipt, expectedValidatedAddresseses); - // Check that order was cancelled - await _.each(nonCompliantSignedOrders, async (nonCompliantSignedOrder, salt: number) => { - const orderInfoAfterCancelling = await erc721NonCompliantBalanceThresholdWrapper.getOrderInfoAsync(nonCompliantSignedOrder) - const saltAsBigNumber = new BigNumber(salt); - if (saltAsBigNumber.lessThanOrEqualTo(cancelOrdersUpToThisSalt)) { - return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.CANCELLED); - } else { - return expect(orderInfoAfterCancelling.orderStatus).to.be.equal(OrderStatus.FILLABLE); - } - }); - }); - }); -}); -// tslint:disable:max-file-line-count -// tslint:enable:no-unnecessary-type-assertion diff --git a/packages/contracts/test/utils/balance_threshold_wrapper.ts b/packages/contracts/test/utils/balance_threshold_wrapper.ts deleted file mode 100644 index cff40aa52..000000000 --- a/packages/contracts/test/utils/balance_threshold_wrapper.ts +++ /dev/null @@ -1,247 +0,0 @@ -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 '../../generated-wrappers/exchange'; -import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter'; - -import { formatters } from './formatters'; -import { LogDecoder } from './log_decoder'; -import { orderUtils } from './order_utils'; -import { TransactionFactory } from '../utils/transaction_factory'; -import { OrderInfo } from './types'; - -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); - } - 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; - } -} |