@0x/contracts-exchange: Make marketBuy/SellNoThrow the default.
				
					
				
			`@0x/contracts-exchange`: Add more `wrapper_unit_tests` tests.
This commit is contained in:
		@@ -164,57 +164,12 @@ contract MixinWrapperFunctions is
 | 
			
		||||
        return fillResults;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
 | 
			
		||||
    /// @param orders Array of order specifications.
 | 
			
		||||
    /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
 | 
			
		||||
    /// @param signatures Proofs that orders have been created by makers.
 | 
			
		||||
    /// @return Amounts filled and fees paid by makers and taker.
 | 
			
		||||
    function marketSellOrders(
 | 
			
		||||
        LibOrder.Order[] memory orders,
 | 
			
		||||
        uint256 takerAssetFillAmount,
 | 
			
		||||
        bytes[] memory signatures
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        nonReentrant
 | 
			
		||||
        returns (FillResults memory fillResults)
 | 
			
		||||
    {
 | 
			
		||||
        bytes memory takerAssetData = orders[0].takerAssetData;
 | 
			
		||||
 | 
			
		||||
        uint256 ordersLength = orders.length;
 | 
			
		||||
        for (uint256 i = 0; i != ordersLength; i++) {
 | 
			
		||||
 | 
			
		||||
            // The `takerAssetData` must be the same for each order.
 | 
			
		||||
            // Rather than checking equality, we point the `takerAssetData` of each order to the same memory location.
 | 
			
		||||
            // This is less expensive than checking equality.
 | 
			
		||||
            orders[i].takerAssetData = takerAssetData;
 | 
			
		||||
 | 
			
		||||
            // Calculate the remaining amount of takerAsset to sell
 | 
			
		||||
            uint256 remainingTakerAssetFillAmount = _safeSub(takerAssetFillAmount, fillResults.takerAssetFilledAmount);
 | 
			
		||||
 | 
			
		||||
            // Attempt to sell the remaining amount of takerAsset
 | 
			
		||||
            FillResults memory singleFillResults = _fillOrder(
 | 
			
		||||
                orders[i],
 | 
			
		||||
                remainingTakerAssetFillAmount,
 | 
			
		||||
                signatures[i]
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Update amounts filled and fees paid by maker and taker
 | 
			
		||||
            _addFillResults(fillResults, singleFillResults);
 | 
			
		||||
 | 
			
		||||
            // Stop execution if the entire amount of takerAsset has been sold
 | 
			
		||||
            if (fillResults.takerAssetFilledAmount >= takerAssetFillAmount) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return fillResults;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes multiple calls of fillOrderNoThrow until total amount of takerAsset is sold by taker.
 | 
			
		||||
    /// @param orders Array of order specifications.
 | 
			
		||||
    /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
 | 
			
		||||
    /// @param signatures Proofs that orders have been signed by makers.
 | 
			
		||||
    /// @return Amounts filled and fees paid by makers and taker.
 | 
			
		||||
    function marketSellOrdersNoThrow(
 | 
			
		||||
    function marketSellOrders(
 | 
			
		||||
        LibOrder.Order[] memory orders,
 | 
			
		||||
        uint256 takerAssetFillAmount,
 | 
			
		||||
        bytes[] memory signatures
 | 
			
		||||
@@ -253,65 +208,12 @@ contract MixinWrapperFunctions is
 | 
			
		||||
        return fillResults;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes multiple calls of fillOrder until total amount of makerAsset is bought by taker.
 | 
			
		||||
    /// @param orders Array of order specifications.
 | 
			
		||||
    /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
 | 
			
		||||
    /// @param signatures Proofs that orders have been signed by makers.
 | 
			
		||||
    /// @return Amounts filled and fees paid by makers and taker.
 | 
			
		||||
    function marketBuyOrders(
 | 
			
		||||
        LibOrder.Order[] memory orders,
 | 
			
		||||
        uint256 makerAssetFillAmount,
 | 
			
		||||
        bytes[] memory signatures
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        nonReentrant
 | 
			
		||||
        returns (FillResults memory fillResults)
 | 
			
		||||
    {
 | 
			
		||||
        bytes memory makerAssetData = orders[0].makerAssetData;
 | 
			
		||||
 | 
			
		||||
        uint256 ordersLength = orders.length;
 | 
			
		||||
        for (uint256 i = 0; i != ordersLength; i++) {
 | 
			
		||||
 | 
			
		||||
            // The `makerAssetData` must be the same for each order.
 | 
			
		||||
            // Rather than checking equality, we point the `makerAssetData` of each order to the same memory location.
 | 
			
		||||
            // This is less expensive than checking equality.
 | 
			
		||||
            orders[i].makerAssetData = makerAssetData;
 | 
			
		||||
 | 
			
		||||
            // Calculate the remaining amount of makerAsset to buy
 | 
			
		||||
            uint256 remainingMakerAssetFillAmount = _safeSub(makerAssetFillAmount, fillResults.makerAssetFilledAmount);
 | 
			
		||||
 | 
			
		||||
            // Convert the remaining amount of makerAsset to buy into remaining amount
 | 
			
		||||
            // of takerAsset to sell, assuming entire amount can be sold in the current order
 | 
			
		||||
            uint256 remainingTakerAssetFillAmount = _getPartialAmountFloor(
 | 
			
		||||
                orders[i].takerAssetAmount,
 | 
			
		||||
                orders[i].makerAssetAmount,
 | 
			
		||||
                remainingMakerAssetFillAmount
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Attempt to sell the remaining amount of takerAsset
 | 
			
		||||
            FillResults memory singleFillResults = _fillOrder(
 | 
			
		||||
                orders[i],
 | 
			
		||||
                remainingTakerAssetFillAmount,
 | 
			
		||||
                signatures[i]
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Update amounts filled and fees paid by maker and taker
 | 
			
		||||
            _addFillResults(fillResults, singleFillResults);
 | 
			
		||||
 | 
			
		||||
            // Stop execution if the entire amount of makerAsset has been bought
 | 
			
		||||
            if (fillResults.makerAssetFilledAmount >= makerAssetFillAmount) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return fillResults;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes multiple calls of fillOrderNoThrow until total amount of makerAsset is bought by taker.
 | 
			
		||||
    /// @param orders Array of order specifications.
 | 
			
		||||
    /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
 | 
			
		||||
    /// @param signatures Proofs that orders have been signed by makers.
 | 
			
		||||
    /// @return Amounts filled and fees paid by makers and taker.
 | 
			
		||||
    function marketBuyOrdersNoThrow(
 | 
			
		||||
    function marketBuyOrders(
 | 
			
		||||
        LibOrder.Order[] memory orders,
 | 
			
		||||
        uint256 makerAssetFillAmount,
 | 
			
		||||
        bytes[] memory signatures
 | 
			
		||||
 
 | 
			
		||||
@@ -91,26 +91,13 @@ contract IWrapperFunctions {
 | 
			
		||||
        public
 | 
			
		||||
        returns (LibFillResults.FillResults[] memory fillResults);
 | 
			
		||||
 | 
			
		||||
    /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
 | 
			
		||||
    /// @param orders Array of order specifications.
 | 
			
		||||
    /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
 | 
			
		||||
    /// @param signatures Proofs that orders have been created by makers.
 | 
			
		||||
    /// @return Amounts filled and fees paid by makers and taker.
 | 
			
		||||
    function marketSellOrders(
 | 
			
		||||
        LibOrder.Order[] memory orders,
 | 
			
		||||
        uint256 takerAssetFillAmount,
 | 
			
		||||
        bytes[] memory signatures
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        returns (LibFillResults.FillResults memory fillResults);
 | 
			
		||||
 | 
			
		||||
    /// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
 | 
			
		||||
    ///      Returns false if the transaction would otherwise revert.
 | 
			
		||||
    /// @param orders Array of order specifications.
 | 
			
		||||
    /// @param takerAssetFillAmount Desired amount of takerAsset to sell.
 | 
			
		||||
    /// @param signatures Proofs that orders have been signed by makers.
 | 
			
		||||
    /// @return Amounts filled and fees paid by makers and taker.
 | 
			
		||||
    function marketSellOrdersNoThrow(
 | 
			
		||||
    function marketSellOrders(
 | 
			
		||||
        LibOrder.Order[] memory orders,
 | 
			
		||||
        uint256 takerAssetFillAmount,
 | 
			
		||||
        bytes[] memory signatures
 | 
			
		||||
@@ -118,26 +105,13 @@ contract IWrapperFunctions {
 | 
			
		||||
        public
 | 
			
		||||
        returns (LibFillResults.FillResults memory fillResults);
 | 
			
		||||
 | 
			
		||||
    /// @dev Synchronously executes multiple calls of fillOrder until total amount of makerAsset is bought by taker.
 | 
			
		||||
    /// @param orders Array of order specifications.
 | 
			
		||||
    /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
 | 
			
		||||
    /// @param signatures Proofs that orders have been signed by makers.
 | 
			
		||||
    /// @return Amounts filled and fees paid by makers and taker.
 | 
			
		||||
    function marketBuyOrders(
 | 
			
		||||
        LibOrder.Order[] memory orders,
 | 
			
		||||
        uint256 makerAssetFillAmount,
 | 
			
		||||
        bytes[] memory signatures
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        returns (LibFillResults.FillResults memory fillResults);
 | 
			
		||||
 | 
			
		||||
    /// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
 | 
			
		||||
    ///      Returns false if the transaction would otherwise revert.
 | 
			
		||||
    /// @param orders Array of order specifications.
 | 
			
		||||
    /// @param makerAssetFillAmount Desired amount of makerAsset to buy.
 | 
			
		||||
    /// @param signatures Proofs that orders have been signed by makers.
 | 
			
		||||
    /// @return Amounts filled and fees paid by makers and taker.
 | 
			
		||||
    function marketBuyOrdersNoThrow(
 | 
			
		||||
    function marketBuyOrders(
 | 
			
		||||
        LibOrder.Order[] memory orders,
 | 
			
		||||
        uint256 makerAssetFillAmount,
 | 
			
		||||
        bytes[] memory signatures
 | 
			
		||||
 
 | 
			
		||||
@@ -133,25 +133,11 @@ export class ExchangeWrapper {
 | 
			
		||||
        return tx;
 | 
			
		||||
    }
 | 
			
		||||
    public async marketSellOrdersAsync(
 | 
			
		||||
        orders: SignedOrder[],
 | 
			
		||||
        from: string,
 | 
			
		||||
        opts: { takerAssetFillAmount: BigNumber },
 | 
			
		||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        const txHash = await this._exchange.marketSellOrders.sendTransactionAsync(
 | 
			
		||||
            orders,
 | 
			
		||||
            opts.takerAssetFillAmount,
 | 
			
		||||
            orders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
            { from },
 | 
			
		||||
        );
 | 
			
		||||
        const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
 | 
			
		||||
        return tx;
 | 
			
		||||
    }
 | 
			
		||||
    public async marketSellOrdersNoThrowAsync(
 | 
			
		||||
        orders: SignedOrder[],
 | 
			
		||||
        from: string,
 | 
			
		||||
        opts: { takerAssetFillAmount: BigNumber; gas?: number },
 | 
			
		||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        const txHash = await this._exchange.marketSellOrdersNoThrow.sendTransactionAsync(
 | 
			
		||||
        const txHash = await this._exchange.marketSellOrders.sendTransactionAsync(
 | 
			
		||||
            orders,
 | 
			
		||||
            opts.takerAssetFillAmount,
 | 
			
		||||
            orders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
@@ -161,25 +147,11 @@ export class ExchangeWrapper {
 | 
			
		||||
        return tx;
 | 
			
		||||
    }
 | 
			
		||||
    public async marketBuyOrdersAsync(
 | 
			
		||||
        orders: SignedOrder[],
 | 
			
		||||
        from: string,
 | 
			
		||||
        opts: { makerAssetFillAmount: BigNumber },
 | 
			
		||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        const txHash = await this._exchange.marketBuyOrders.sendTransactionAsync(
 | 
			
		||||
            orders,
 | 
			
		||||
            opts.makerAssetFillAmount,
 | 
			
		||||
            orders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
            { from },
 | 
			
		||||
        );
 | 
			
		||||
        const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
 | 
			
		||||
        return tx;
 | 
			
		||||
    }
 | 
			
		||||
    public async marketBuyOrdersNoThrowAsync(
 | 
			
		||||
        orders: SignedOrder[],
 | 
			
		||||
        from: string,
 | 
			
		||||
        opts: { makerAssetFillAmount: BigNumber; gas?: number },
 | 
			
		||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        const txHash = await this._exchange.marketBuyOrdersNoThrow.sendTransactionAsync(
 | 
			
		||||
        const txHash = await this._exchange.marketBuyOrders.sendTransactionAsync(
 | 
			
		||||
            orders,
 | 
			
		||||
            opts.makerAssetFillAmount,
 | 
			
		||||
            orders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
 
 | 
			
		||||
@@ -925,167 +925,7 @@ describe('Exchange wrappers', () => {
 | 
			
		||||
                            await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId),
 | 
			
		||||
                            constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                        );
 | 
			
		||||
                        const expectedError = new ReentrancyGuardRevertErrors.IllegalReentrancyError();
 | 
			
		||||
                        const tx = exchangeWrapper.marketSellOrdersAsync([signedOrder], takerAddress, {
 | 
			
		||||
                            takerAssetFillAmount: signedOrder.takerAssetAmount,
 | 
			
		||||
                        });
 | 
			
		||||
                        return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            describe('marketSellOrders reentrancy tests', () => reentrancyTest(exchangeConstants.FUNCTIONS_WITH_MUTEX));
 | 
			
		||||
 | 
			
		||||
            it('should stop when the entire takerAssetFillAmount is filled', async () => {
 | 
			
		||||
                const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus(
 | 
			
		||||
                    signedOrders[1].takerAssetAmount.div(2),
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                const fillResults = await exchange.marketSellOrders.callAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    takerAssetFillAmount,
 | 
			
		||||
                    signedOrders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
                    { from: takerAddress },
 | 
			
		||||
                );
 | 
			
		||||
                await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
 | 
			
		||||
                    takerAssetFillAmount,
 | 
			
		||||
                });
 | 
			
		||||
                const newBalances = await erc20Wrapper.getBalancesAsync();
 | 
			
		||||
 | 
			
		||||
                const makerAssetFilledAmount = signedOrders[0].makerAssetAmount.plus(
 | 
			
		||||
                    signedOrders[1].makerAssetAmount.dividedToIntegerBy(2),
 | 
			
		||||
                );
 | 
			
		||||
                const makerFee = signedOrders[0].makerFee.plus(signedOrders[1].makerFee.dividedToIntegerBy(2));
 | 
			
		||||
                const takerFee = signedOrders[0].takerFee.plus(signedOrders[1].takerFee.dividedToIntegerBy(2));
 | 
			
		||||
 | 
			
		||||
                expect(fillResults.makerAssetFilledAmount).to.bignumber.equal(makerAssetFilledAmount);
 | 
			
		||||
                expect(fillResults.takerAssetFilledAmount).to.bignumber.equal(takerAssetFillAmount);
 | 
			
		||||
                expect(fillResults.makerFeePaid).to.bignumber.equal(makerFee);
 | 
			
		||||
                expect(fillResults.takerFeePaid).to.bignumber.equal(takerFee);
 | 
			
		||||
 | 
			
		||||
                expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
 | 
			
		||||
                );
 | 
			
		||||
                expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[makerAddress][defaultTakerAssetAddress].plus(takerAssetFillAmount),
 | 
			
		||||
                );
 | 
			
		||||
                expect(newBalances[makerAddress][feeToken.address]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[makerAddress][feeToken.address].minus(makerFee),
 | 
			
		||||
                );
 | 
			
		||||
                expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[takerAddress][defaultTakerAssetAddress].minus(takerAssetFillAmount),
 | 
			
		||||
                );
 | 
			
		||||
                expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFilledAmount),
 | 
			
		||||
                );
 | 
			
		||||
                expect(newBalances[takerAddress][feeToken.address]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[takerAddress][feeToken.address].minus(takerFee),
 | 
			
		||||
                );
 | 
			
		||||
                expect(newBalances[feeRecipientAddress][feeToken.address]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[feeRecipientAddress][feeToken.address].plus(makerFee.plus(takerFee)),
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('should fill all signedOrders if cannot fill entire takerAssetFillAmount', async () => {
 | 
			
		||||
                const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
 | 
			
		||||
                _.forEach(signedOrders, signedOrder => {
 | 
			
		||||
                    erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
 | 
			
		||||
                        defaultMakerAssetAddress
 | 
			
		||||
                    ].minus(signedOrder.makerAssetAmount);
 | 
			
		||||
                    erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
 | 
			
		||||
                        defaultTakerAssetAddress
 | 
			
		||||
                    ].plus(signedOrder.takerAssetAmount);
 | 
			
		||||
                    erc20Balances[makerAddress][feeToken.address] = erc20Balances[makerAddress][feeToken.address].minus(
 | 
			
		||||
                        signedOrder.makerFee,
 | 
			
		||||
                    );
 | 
			
		||||
                    erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
 | 
			
		||||
                        defaultMakerAssetAddress
 | 
			
		||||
                    ].plus(signedOrder.makerAssetAmount);
 | 
			
		||||
                    erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
 | 
			
		||||
                        defaultTakerAssetAddress
 | 
			
		||||
                    ].minus(signedOrder.takerAssetAmount);
 | 
			
		||||
                    erc20Balances[takerAddress][feeToken.address] = erc20Balances[takerAddress][feeToken.address].minus(
 | 
			
		||||
                        signedOrder.takerFee,
 | 
			
		||||
                    );
 | 
			
		||||
                    erc20Balances[feeRecipientAddress][feeToken.address] = erc20Balances[feeRecipientAddress][
 | 
			
		||||
                        feeToken.address
 | 
			
		||||
                    ].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                const fillResults = await exchange.marketSellOrders.callAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    takerAssetFillAmount,
 | 
			
		||||
                    signedOrders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
                    { from: takerAddress },
 | 
			
		||||
                );
 | 
			
		||||
                await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
 | 
			
		||||
                    takerAssetFillAmount,
 | 
			
		||||
                });
 | 
			
		||||
                const newBalances = await erc20Wrapper.getBalancesAsync();
 | 
			
		||||
 | 
			
		||||
                const expectedFillResults = signedOrders
 | 
			
		||||
                    .map(signedOrder => ({
 | 
			
		||||
                        makerAssetFilledAmount: signedOrder.makerAssetAmount,
 | 
			
		||||
                        takerAssetFilledAmount: signedOrder.takerAssetAmount,
 | 
			
		||||
                        makerFeePaid: signedOrder.makerFee,
 | 
			
		||||
                        takerFeePaid: signedOrder.takerFee,
 | 
			
		||||
                    }))
 | 
			
		||||
                    .reduce(
 | 
			
		||||
                        (totalFillResults, currentFillResults) => ({
 | 
			
		||||
                            makerAssetFilledAmount: totalFillResults.makerAssetFilledAmount.plus(
 | 
			
		||||
                                currentFillResults.makerAssetFilledAmount,
 | 
			
		||||
                            ),
 | 
			
		||||
                            takerAssetFilledAmount: totalFillResults.takerAssetFilledAmount.plus(
 | 
			
		||||
                                currentFillResults.takerAssetFilledAmount,
 | 
			
		||||
                            ),
 | 
			
		||||
                            makerFeePaid: totalFillResults.makerFeePaid.plus(currentFillResults.makerFeePaid),
 | 
			
		||||
                            takerFeePaid: totalFillResults.takerFeePaid.plus(currentFillResults.takerFeePaid),
 | 
			
		||||
                        }),
 | 
			
		||||
                        nullFillResults,
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                expect(fillResults).to.deep.equal(expectedFillResults);
 | 
			
		||||
                expect(newBalances).to.be.deep.equal(erc20Balances);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('should revert when a signedOrder does not use the same takerAssetAddress', async () => {
 | 
			
		||||
                signedOrders = [
 | 
			
		||||
                    await orderFactory.newSignedOrderAsync(),
 | 
			
		||||
                    await orderFactory.newSignedOrderAsync({
 | 
			
		||||
                        takerAssetData: assetDataUtils.encodeERC20AssetData(feeToken.address),
 | 
			
		||||
                    }),
 | 
			
		||||
                    await orderFactory.newSignedOrderAsync(),
 | 
			
		||||
                ];
 | 
			
		||||
                const reconstructedOrder = {
 | 
			
		||||
                    ...signedOrders[1],
 | 
			
		||||
                    takerAssetData: signedOrders[0].takerAssetData,
 | 
			
		||||
                };
 | 
			
		||||
                const orderHashHex = orderHashUtils.getOrderHashHex(reconstructedOrder);
 | 
			
		||||
                const expectedError = new ExchangeRevertErrors.SignatureError(
 | 
			
		||||
                    ExchangeRevertErrors.SignatureErrorCode.BadSignature,
 | 
			
		||||
                    orderHashHex,
 | 
			
		||||
                    signedOrders[1].makerAddress,
 | 
			
		||||
                    signedOrders[1].signature,
 | 
			
		||||
                );
 | 
			
		||||
                const tx = exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
 | 
			
		||||
                    takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
 | 
			
		||||
                });
 | 
			
		||||
                return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe('marketSellOrdersNoThrow', () => {
 | 
			
		||||
            const reentrancyTest = (functionNames: string[]) => {
 | 
			
		||||
                for (const [functionId, functionName] of functionNames.entries()) {
 | 
			
		||||
                    const description = `should not allow marketSellOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
 | 
			
		||||
                    it(description, async () => {
 | 
			
		||||
                        const signedOrder = await orderFactory.newSignedOrderAsync({
 | 
			
		||||
                            makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
 | 
			
		||||
                        });
 | 
			
		||||
                        await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                            await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId),
 | 
			
		||||
                            constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                        );
 | 
			
		||||
                        await exchangeWrapper.marketSellOrdersNoThrowAsync([signedOrder], takerAddress, {
 | 
			
		||||
                        await exchangeWrapper.marketSellOrdersAsync([signedOrder], takerAddress, {
 | 
			
		||||
                            takerAssetFillAmount: signedOrder.takerAssetAmount,
 | 
			
		||||
                        });
 | 
			
		||||
                        const newBalances = await erc20Wrapper.getBalancesAsync();
 | 
			
		||||
@@ -1093,7 +933,7 @@ describe('Exchange wrappers', () => {
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            describe('marketSellOrdersNoThrow reentrancy tests', () =>
 | 
			
		||||
            describe('marketSellOrders reentrancy tests', () =>
 | 
			
		||||
                reentrancyTest(exchangeConstants.FUNCTIONS_WITH_MUTEX));
 | 
			
		||||
 | 
			
		||||
            it('should stop when the entire takerAssetFillAmount is filled', async () => {
 | 
			
		||||
@@ -1101,13 +941,13 @@ describe('Exchange wrappers', () => {
 | 
			
		||||
                    signedOrders[1].takerAssetAmount.div(2),
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                const fillResults = await exchange.marketSellOrdersNoThrow.callAsync(
 | 
			
		||||
                const fillResults = await exchange.marketSellOrders.callAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    takerAssetFillAmount,
 | 
			
		||||
                    signedOrders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
                    { from: takerAddress },
 | 
			
		||||
                );
 | 
			
		||||
                await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
 | 
			
		||||
                await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
 | 
			
		||||
                    takerAssetFillAmount,
 | 
			
		||||
                    // HACK(albrow): We need to hardcode the gas estimate here because
 | 
			
		||||
                    // the Geth gas estimator doesn't work with the way we use
 | 
			
		||||
@@ -1176,13 +1016,13 @@ describe('Exchange wrappers', () => {
 | 
			
		||||
                    ].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                const fillResults = await exchange.marketSellOrdersNoThrow.callAsync(
 | 
			
		||||
                const fillResults = await exchange.marketSellOrders.callAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    takerAssetFillAmount,
 | 
			
		||||
                    signedOrders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
                    { from: takerAddress },
 | 
			
		||||
                );
 | 
			
		||||
                await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
 | 
			
		||||
                await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
 | 
			
		||||
                    takerAssetFillAmount,
 | 
			
		||||
                    // HACK(albrow): We need to hardcode the gas estimate here because
 | 
			
		||||
                    // the Geth gas estimator doesn't work with the way we use
 | 
			
		||||
@@ -1250,13 +1090,13 @@ describe('Exchange wrappers', () => {
 | 
			
		||||
                    ].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                const fillResults = await exchange.marketSellOrdersNoThrow.callAsync(
 | 
			
		||||
                const fillResults = await exchange.marketSellOrders.callAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    takerAssetFillAmount,
 | 
			
		||||
                    signedOrders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
                    { from: takerAddress },
 | 
			
		||||
                );
 | 
			
		||||
                await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
 | 
			
		||||
                await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
 | 
			
		||||
                    takerAssetFillAmount,
 | 
			
		||||
                    // HACK(albrow): We need to hardcode the gas estimate here because
 | 
			
		||||
                    // the Geth gas estimator doesn't work with the way we use
 | 
			
		||||
@@ -1303,167 +1143,7 @@ describe('Exchange wrappers', () => {
 | 
			
		||||
                            await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId),
 | 
			
		||||
                            constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                        );
 | 
			
		||||
                        const expectedError = new ReentrancyGuardRevertErrors.IllegalReentrancyError();
 | 
			
		||||
                        const tx = exchangeWrapper.marketBuyOrdersAsync([signedOrder], takerAddress, {
 | 
			
		||||
                            makerAssetFillAmount: signedOrder.makerAssetAmount,
 | 
			
		||||
                        });
 | 
			
		||||
                        return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            describe('marketBuyOrders reentrancy tests', () => reentrancyTest(exchangeConstants.FUNCTIONS_WITH_MUTEX));
 | 
			
		||||
 | 
			
		||||
            it('should stop when the entire makerAssetFillAmount is filled', async () => {
 | 
			
		||||
                const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus(
 | 
			
		||||
                    signedOrders[1].makerAssetAmount.div(2),
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                const fillResults = await exchange.marketBuyOrders.callAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    makerAssetFillAmount,
 | 
			
		||||
                    signedOrders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
                    { from: takerAddress },
 | 
			
		||||
                );
 | 
			
		||||
                await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
 | 
			
		||||
                    makerAssetFillAmount,
 | 
			
		||||
                });
 | 
			
		||||
                const newBalances = await erc20Wrapper.getBalancesAsync();
 | 
			
		||||
 | 
			
		||||
                const makerAmountBought = signedOrders[0].takerAssetAmount.plus(
 | 
			
		||||
                    signedOrders[1].takerAssetAmount.dividedToIntegerBy(2),
 | 
			
		||||
                );
 | 
			
		||||
                const makerFee = signedOrders[0].makerFee.plus(signedOrders[1].makerFee.dividedToIntegerBy(2));
 | 
			
		||||
                const takerFee = signedOrders[0].takerFee.plus(signedOrders[1].takerFee.dividedToIntegerBy(2));
 | 
			
		||||
 | 
			
		||||
                expect(fillResults.makerAssetFilledAmount).to.bignumber.equal(makerAssetFillAmount);
 | 
			
		||||
                expect(fillResults.takerAssetFilledAmount).to.bignumber.equal(makerAmountBought);
 | 
			
		||||
                expect(fillResults.makerFeePaid).to.bignumber.equal(makerFee);
 | 
			
		||||
                expect(fillResults.takerFeePaid).to.bignumber.equal(takerFee);
 | 
			
		||||
 | 
			
		||||
                expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFillAmount),
 | 
			
		||||
                );
 | 
			
		||||
                expect(newBalances[makerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[makerAddress][defaultTakerAssetAddress].plus(makerAmountBought),
 | 
			
		||||
                );
 | 
			
		||||
                expect(newBalances[makerAddress][feeToken.address]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[makerAddress][feeToken.address].minus(makerFee),
 | 
			
		||||
                );
 | 
			
		||||
                expect(newBalances[takerAddress][defaultTakerAssetAddress]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[takerAddress][defaultTakerAssetAddress].minus(makerAmountBought),
 | 
			
		||||
                );
 | 
			
		||||
                expect(newBalances[takerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[takerAddress][defaultMakerAssetAddress].plus(makerAssetFillAmount),
 | 
			
		||||
                );
 | 
			
		||||
                expect(newBalances[takerAddress][feeToken.address]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[takerAddress][feeToken.address].minus(takerFee),
 | 
			
		||||
                );
 | 
			
		||||
                expect(newBalances[feeRecipientAddress][feeToken.address]).to.be.bignumber.equal(
 | 
			
		||||
                    erc20Balances[feeRecipientAddress][feeToken.address].plus(makerFee.plus(takerFee)),
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('should fill all signedOrders if cannot fill entire makerAssetFillAmount', async () => {
 | 
			
		||||
                const makerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
 | 
			
		||||
                _.forEach(signedOrders, signedOrder => {
 | 
			
		||||
                    erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
 | 
			
		||||
                        defaultMakerAssetAddress
 | 
			
		||||
                    ].minus(signedOrder.makerAssetAmount);
 | 
			
		||||
                    erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
 | 
			
		||||
                        defaultTakerAssetAddress
 | 
			
		||||
                    ].plus(signedOrder.takerAssetAmount);
 | 
			
		||||
                    erc20Balances[makerAddress][feeToken.address] = erc20Balances[makerAddress][feeToken.address].minus(
 | 
			
		||||
                        signedOrder.makerFee,
 | 
			
		||||
                    );
 | 
			
		||||
                    erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
 | 
			
		||||
                        defaultMakerAssetAddress
 | 
			
		||||
                    ].plus(signedOrder.makerAssetAmount);
 | 
			
		||||
                    erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
 | 
			
		||||
                        defaultTakerAssetAddress
 | 
			
		||||
                    ].minus(signedOrder.takerAssetAmount);
 | 
			
		||||
                    erc20Balances[takerAddress][feeToken.address] = erc20Balances[takerAddress][feeToken.address].minus(
 | 
			
		||||
                        signedOrder.takerFee,
 | 
			
		||||
                    );
 | 
			
		||||
                    erc20Balances[feeRecipientAddress][feeToken.address] = erc20Balances[feeRecipientAddress][
 | 
			
		||||
                        feeToken.address
 | 
			
		||||
                    ].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                const fillResults = await exchange.marketBuyOrders.callAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    makerAssetFillAmount,
 | 
			
		||||
                    signedOrders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
                    { from: takerAddress },
 | 
			
		||||
                );
 | 
			
		||||
                await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
 | 
			
		||||
                    makerAssetFillAmount,
 | 
			
		||||
                });
 | 
			
		||||
                const newBalances = await erc20Wrapper.getBalancesAsync();
 | 
			
		||||
 | 
			
		||||
                const expectedFillResults = signedOrders
 | 
			
		||||
                    .map(signedOrder => ({
 | 
			
		||||
                        makerAssetFilledAmount: signedOrder.makerAssetAmount,
 | 
			
		||||
                        takerAssetFilledAmount: signedOrder.takerAssetAmount,
 | 
			
		||||
                        makerFeePaid: signedOrder.makerFee,
 | 
			
		||||
                        takerFeePaid: signedOrder.takerFee,
 | 
			
		||||
                    }))
 | 
			
		||||
                    .reduce(
 | 
			
		||||
                        (totalFillResults, currentFillResults) => ({
 | 
			
		||||
                            makerAssetFilledAmount: totalFillResults.makerAssetFilledAmount.plus(
 | 
			
		||||
                                currentFillResults.makerAssetFilledAmount,
 | 
			
		||||
                            ),
 | 
			
		||||
                            takerAssetFilledAmount: totalFillResults.takerAssetFilledAmount.plus(
 | 
			
		||||
                                currentFillResults.takerAssetFilledAmount,
 | 
			
		||||
                            ),
 | 
			
		||||
                            makerFeePaid: totalFillResults.makerFeePaid.plus(currentFillResults.makerFeePaid),
 | 
			
		||||
                            takerFeePaid: totalFillResults.takerFeePaid.plus(currentFillResults.takerFeePaid),
 | 
			
		||||
                        }),
 | 
			
		||||
                        nullFillResults,
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                expect(fillResults).to.deep.equal(expectedFillResults);
 | 
			
		||||
                expect(newBalances).to.be.deep.equal(erc20Balances);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('should revert when a signedOrder does not use the same makerAssetAddress', async () => {
 | 
			
		||||
                signedOrders = [
 | 
			
		||||
                    await orderFactory.newSignedOrderAsync(),
 | 
			
		||||
                    await orderFactory.newSignedOrderAsync({
 | 
			
		||||
                        makerAssetData: assetDataUtils.encodeERC20AssetData(feeToken.address),
 | 
			
		||||
                    }),
 | 
			
		||||
                    await orderFactory.newSignedOrderAsync(),
 | 
			
		||||
                ];
 | 
			
		||||
                const reconstructedOrder = {
 | 
			
		||||
                    ...signedOrders[1],
 | 
			
		||||
                    makerAssetData: signedOrders[0].makerAssetData,
 | 
			
		||||
                };
 | 
			
		||||
                const orderHashHex = orderHashUtils.getOrderHashHex(reconstructedOrder);
 | 
			
		||||
                const expectedError = new ExchangeRevertErrors.SignatureError(
 | 
			
		||||
                    ExchangeRevertErrors.SignatureErrorCode.BadSignature,
 | 
			
		||||
                    orderHashHex,
 | 
			
		||||
                    signedOrders[1].makerAddress,
 | 
			
		||||
                    signedOrders[1].signature,
 | 
			
		||||
                );
 | 
			
		||||
                const tx = exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
 | 
			
		||||
                    makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
 | 
			
		||||
                });
 | 
			
		||||
                return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe('marketBuyOrdersNoThrow', () => {
 | 
			
		||||
            const reentrancyTest = (functionNames: string[]) => {
 | 
			
		||||
                for (const [functionId, functionName] of functionNames.entries()) {
 | 
			
		||||
                    const description = `should not allow marketBuyOrdersNoThrow to reenter the Exchange contract via ${functionName}`;
 | 
			
		||||
                    it(description, async () => {
 | 
			
		||||
                        const signedOrder = await orderFactory.newSignedOrderAsync({
 | 
			
		||||
                            makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address),
 | 
			
		||||
                        });
 | 
			
		||||
                        await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                            await reentrantErc20Token.setReentrantFunction.sendTransactionAsync(functionId),
 | 
			
		||||
                            constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                        );
 | 
			
		||||
                        await exchangeWrapper.marketBuyOrdersNoThrowAsync([signedOrder], takerAddress, {
 | 
			
		||||
                        await exchangeWrapper.marketBuyOrdersAsync([signedOrder], takerAddress, {
 | 
			
		||||
                            makerAssetFillAmount: signedOrder.makerAssetAmount,
 | 
			
		||||
                        });
 | 
			
		||||
                        const newBalances = await erc20Wrapper.getBalancesAsync();
 | 
			
		||||
@@ -1471,7 +1151,7 @@ describe('Exchange wrappers', () => {
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            describe('marketBuyOrdersNoThrow reentrancy tests', () =>
 | 
			
		||||
            describe('marketBuyOrders reentrancy tests', () =>
 | 
			
		||||
                reentrancyTest(exchangeConstants.FUNCTIONS_WITH_MUTEX));
 | 
			
		||||
 | 
			
		||||
            it('should stop when the entire makerAssetFillAmount is filled', async () => {
 | 
			
		||||
@@ -1479,13 +1159,13 @@ describe('Exchange wrappers', () => {
 | 
			
		||||
                    signedOrders[1].makerAssetAmount.div(2),
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                const fillResults = await exchange.marketBuyOrdersNoThrow.callAsync(
 | 
			
		||||
                const fillResults = await exchange.marketBuyOrders.callAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    makerAssetFillAmount,
 | 
			
		||||
                    signedOrders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
                    { from: takerAddress },
 | 
			
		||||
                );
 | 
			
		||||
                await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
 | 
			
		||||
                await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
 | 
			
		||||
                    makerAssetFillAmount,
 | 
			
		||||
                    // HACK(albrow): We need to hardcode the gas estimate here because
 | 
			
		||||
                    // the Geth gas estimator doesn't work with the way we use
 | 
			
		||||
@@ -1554,13 +1234,13 @@ describe('Exchange wrappers', () => {
 | 
			
		||||
                    ].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                const fillResults = await exchange.marketBuyOrdersNoThrow.callAsync(
 | 
			
		||||
                const fillResults = await exchange.marketBuyOrders.callAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    makerAssetFillAmount,
 | 
			
		||||
                    signedOrders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
                    { from: takerAddress },
 | 
			
		||||
                );
 | 
			
		||||
                await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
 | 
			
		||||
                await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
 | 
			
		||||
                    makerAssetFillAmount,
 | 
			
		||||
                    // HACK(albrow): We need to hardcode the gas estimate here because
 | 
			
		||||
                    // the Geth gas estimator doesn't work with the way we use
 | 
			
		||||
@@ -1629,13 +1309,13 @@ describe('Exchange wrappers', () => {
 | 
			
		||||
                    ].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                const fillResults = await exchange.marketBuyOrdersNoThrow.callAsync(
 | 
			
		||||
                const fillResults = await exchange.marketBuyOrders.callAsync(
 | 
			
		||||
                    signedOrders,
 | 
			
		||||
                    makerAssetFillAmount,
 | 
			
		||||
                    signedOrders.map(signedOrder => signedOrder.signature),
 | 
			
		||||
                    { from: takerAddress },
 | 
			
		||||
                );
 | 
			
		||||
                await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
 | 
			
		||||
                await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
 | 
			
		||||
                    makerAssetFillAmount,
 | 
			
		||||
                    // HACK(albrow): We need to hardcode the gas estimate here because
 | 
			
		||||
                    // the Geth gas estimator doesn't work with the way we use
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ import {
 | 
			
		||||
    artifacts,
 | 
			
		||||
    TestWrapperFunctionsContract,
 | 
			
		||||
    TestWrapperFunctionsFillOrderCalledEventArgs as FillOrderCalledEventArgs,
 | 
			
		||||
    TestWrapperFunctionsCancelOrderCalledEventArgs as CancelOrderCalledEventArgs,
 | 
			
		||||
} from '../src';
 | 
			
		||||
 | 
			
		||||
blockchainTests.only('Exchange wrapper functions unit tests.', env => {
 | 
			
		||||
@@ -37,8 +38,10 @@ blockchainTests.only('Exchange wrapper functions unit tests.', env => {
 | 
			
		||||
    };
 | 
			
		||||
    let testContract: TestWrapperFunctionsContract;
 | 
			
		||||
    let txHelper: TransactionHelper;
 | 
			
		||||
    let senderAddress: string;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        [ senderAddress ] = await env.getAccountAddressesAsync();
 | 
			
		||||
        txHelper = new TransactionHelper(env.web3Wrapper, artifacts);
 | 
			
		||||
        testContract = await TestWrapperFunctionsContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.TestWrapperFunctions,
 | 
			
		||||
@@ -585,6 +588,66 @@ blockchainTests.only('Exchange wrapper functions unit tests.', env => {
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Asserts that `_cancelOrder()` was called in the same order and with the same
 | 
			
		||||
    // arguments as given by examining receipt logs.
 | 
			
		||||
    function assertCancelOrderCallsFromLogs(
 | 
			
		||||
        logs: LogEntry[],
 | 
			
		||||
        calls: Order[],
 | 
			
		||||
    ): void {
 | 
			
		||||
        expect(logs.length).to.eq(calls.length);
 | 
			
		||||
        for (const i of _.times(calls.length)) {
 | 
			
		||||
            const log = logs[i] as LogWithDecodedArgs<CancelOrderCalledEventArgs>;
 | 
			
		||||
            const expectedOrder = calls[i];
 | 
			
		||||
            expect(log.event).to.eq('CancelOrderCalled');
 | 
			
		||||
            assertSameOrderFromEvent(log.args.order as any, expectedOrder);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    describe('batchCancelOrders', () => {
 | 
			
		||||
        it('works with no orders', async () => {
 | 
			
		||||
            const [ , receipt ] = await txHelper.getResultAndReceiptAsync(
 | 
			
		||||
                testContract.batchCancelOrders,
 | 
			
		||||
                [],
 | 
			
		||||
            );
 | 
			
		||||
            assertCancelOrderCallsFromLogs(receipt.logs, []);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('works with many orders', async () => {
 | 
			
		||||
            const COUNT = 8;
 | 
			
		||||
            const orders = _.times(COUNT, () => randomOrder({ makerAddress: senderAddress }));
 | 
			
		||||
            const [ , receipt ] = await txHelper.getResultAndReceiptAsync(
 | 
			
		||||
                testContract.batchCancelOrders,
 | 
			
		||||
                orders,
 | 
			
		||||
            );
 | 
			
		||||
            assertCancelOrderCallsFromLogs(receipt.logs, orders);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('works with duplicate orders', async () => {
 | 
			
		||||
            const COUNT = 3;
 | 
			
		||||
            const order = randomOrder({ makerAddress: senderAddress });
 | 
			
		||||
            const orders = _.times(COUNT, () => order);
 | 
			
		||||
            const [ , receipt ] = await txHelper.getResultAndReceiptAsync(
 | 
			
		||||
                testContract.batchCancelOrders,
 | 
			
		||||
                orders,
 | 
			
		||||
            );
 | 
			
		||||
            assertCancelOrderCallsFromLogs(receipt.logs, orders);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('reverts if one `_cancelOrder()` reverts', async () => {
 | 
			
		||||
            const COUNT = 8;
 | 
			
		||||
            const FAILING_ORDER_INDEX = 4;
 | 
			
		||||
            const orders = _.times(COUNT, () => randomOrder({ makerAddress: senderAddress }));
 | 
			
		||||
            const failingOrder = orders[FAILING_ORDER_INDEX];
 | 
			
		||||
            failingOrder.salt = ALWAYS_FAILING_SALT;
 | 
			
		||||
            const expectedError = ALWAYS_FAILING_SALT_REVERT_ERROR;
 | 
			
		||||
            const tx = txHelper.getResultAndReceiptAsync(
 | 
			
		||||
                testContract.batchCancelOrders,
 | 
			
		||||
                orders,
 | 
			
		||||
            );
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('getOrdersInfo', () => {
 | 
			
		||||
        // Computes the expected (fake) order info generated by the `TestWrapperFunctions` contract.
 | 
			
		||||
        function getExpectedOrderInfo(order: Order): OrderInfo {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user