aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/contracts/contracts/extensions/BalanceThresholdFilter/BalanceThresholdFilter.sol44
-rw-r--r--packages/contracts/contracts/extensions/BalanceThresholdFilter/MixinBalanceThresholdFilterCore.sol319
-rw-r--r--packages/contracts/contracts/extensions/BalanceThresholdFilter/interfaces/IThresholdAsset.sol30
-rw-r--r--packages/contracts/contracts/extensions/BalanceThresholdFilter/mixins/MBalanceThresholdFilterCore.sol81
-rw-r--r--packages/contracts/test/extensions/balance_threshold_filter.ts1521
-rw-r--r--packages/contracts/test/utils/balance_threshold_wrapper.ts247
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;
- }
-}