@0x:contracts-integrations Addressed review feedback
				
					
				
			This commit is contained in:
		@@ -414,14 +414,19 @@ blockchainTests('Forwarder integration tests', env => {
 | 
			
		||||
        it('should buy an ERC721 asset and pay a WETH fee', async () => {
 | 
			
		||||
            const erc721orderWithWethFee = await maker.signOrderAsync({
 | 
			
		||||
                makerAssetAmount: new BigNumber(1),
 | 
			
		||||
                makerAssetData: deployment.assetDataEncoder.ERC721Token.getABIEncodedTransactionData(erc721Token.address, nftId),
 | 
			
		||||
                makerAssetData: deployment.assetDataEncoder.ERC721Token.getABIEncodedTransactionData(
 | 
			
		||||
                    erc721Token.address,
 | 
			
		||||
                    nftId,
 | 
			
		||||
                ),
 | 
			
		||||
                takerFee: toBaseUnitAmount(1),
 | 
			
		||||
                takerFeeAssetData: wethAssetData,
 | 
			
		||||
            });
 | 
			
		||||
            await testFactory.marketBuyTestAsync([erc721orderWithWethFee], 1);
 | 
			
		||||
        });
 | 
			
		||||
        it('should fail to fill an order with a fee denominated in an asset other than makerAsset or WETH', async () => {
 | 
			
		||||
            const takerFeeAssetData = deployment.assetDataEncoder.ERC20Token.getABIEncodedTransactionData(anotherErc20Token.address);
 | 
			
		||||
            const takerFeeAssetData = deployment.assetDataEncoder.ERC20Token.getABIEncodedTransactionData(
 | 
			
		||||
                anotherErc20Token.address,
 | 
			
		||||
            );
 | 
			
		||||
            const order = await maker.signOrderAsync({
 | 
			
		||||
                takerFeeAssetData,
 | 
			
		||||
                takerFee: toBaseUnitAmount(1),
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,5 +1,4 @@
 | 
			
		||||
import { IAssetDataContract } from '@0x/contracts-asset-proxy';
 | 
			
		||||
import { DevUtilsContract } from '@0x/contracts-dev-utils';
 | 
			
		||||
import { BlockchainBalanceStore, ExchangeContract, LocalBalanceStore } from '@0x/contracts-exchange';
 | 
			
		||||
import { constants, expect, OrderStatus } from '@0x/contracts-test-utils';
 | 
			
		||||
import { orderHashUtils } from '@0x/order-utils';
 | 
			
		||||
@@ -74,18 +73,17 @@ export class MatchOrderTester {
 | 
			
		||||
     * Constructs new MatchOrderTester.
 | 
			
		||||
     */
 | 
			
		||||
    constructor(
 | 
			
		||||
        protected readonly _assetDataEncoder: IAssetDataContract,
 | 
			
		||||
        protected readonly _deployment: DeploymentManager,
 | 
			
		||||
        protected readonly _devUtils: DevUtilsContract,
 | 
			
		||||
        protected readonly _blockchainBalanceStore: BlockchainBalanceStore,
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Performs batch order matching on a set of complementary orders and asserts results.
 | 
			
		||||
     * @param orders The list of orders and filled states
 | 
			
		||||
     * @param takerAddress Address of taker (the address who matched the two orders)
 | 
			
		||||
     * @param value The amount of value that should be sent in the contract call.
 | 
			
		||||
     * @param matchPairs An array of left and right indices that will be used to perform
 | 
			
		||||
     *                   the expected simulation.
 | 
			
		||||
     * @param takerAddress Address of taker (the address who matched the two orders)
 | 
			
		||||
     * @param expectedTransferAmounts Expected amounts transferred as a result of each round of
 | 
			
		||||
     *                                order matching. Omitted fields are either set to 0 or their
 | 
			
		||||
     *                                complementary field.
 | 
			
		||||
@@ -107,12 +105,12 @@ export class MatchOrderTester {
 | 
			
		||||
        expect(orders.rightOrders.length).to.be.eq(orders.rightOrdersTakerAssetFilledAmounts.length);
 | 
			
		||||
 | 
			
		||||
        // Ensure that the exchange is in the expected state.
 | 
			
		||||
        await assertBatchOrderStatesAsync(orders, this._deployment.exchange);
 | 
			
		||||
        await this._assertBatchOrderStatesAsync(orders);
 | 
			
		||||
 | 
			
		||||
        // Update the blockchain balance store and create a new local balance store
 | 
			
		||||
        // with the same initial balances.
 | 
			
		||||
        await this._blockchainBalanceStore.updateBalancesAsync();
 | 
			
		||||
        const localBalanceStore = LocalBalanceStore.create(this._devUtils, this._blockchainBalanceStore);
 | 
			
		||||
        const localBalanceStore = LocalBalanceStore.create(this._deployment.devUtils, this._blockchainBalanceStore);
 | 
			
		||||
 | 
			
		||||
        // Execute `batchMatchOrders()`
 | 
			
		||||
        let actualBatchMatchResults;
 | 
			
		||||
@@ -124,7 +122,7 @@ export class MatchOrderTester {
 | 
			
		||||
                orders.rightOrders,
 | 
			
		||||
                orders.leftOrders.map(order => order.signature),
 | 
			
		||||
                orders.rightOrders.map(order => order.signature),
 | 
			
		||||
                { from: takerAddress, gasPrice: constants.DEFAULT_GAS_PRICE, value },
 | 
			
		||||
                { from: takerAddress, gasPrice: DeploymentManager.gasPrice, value },
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            [actualBatchMatchResults, transactionReceipt] = await this._deployment.txHelper.getResultAndReceiptAsync(
 | 
			
		||||
@@ -133,46 +131,38 @@ export class MatchOrderTester {
 | 
			
		||||
                orders.rightOrders,
 | 
			
		||||
                orders.leftOrders.map(order => order.signature),
 | 
			
		||||
                orders.rightOrders.map(order => order.signature),
 | 
			
		||||
                { from: takerAddress, gasPrice: constants.DEFAULT_GAS_PRICE, value },
 | 
			
		||||
                { from: takerAddress, gasPrice: DeploymentManager.gasPrice, value },
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Burn the gas used to execute the transaction in the local balance store.
 | 
			
		||||
        localBalanceStore.burnGas(takerAddress, constants.DEFAULT_GAS_PRICE * transactionReceipt.gasUsed);
 | 
			
		||||
        localBalanceStore.burnGas(takerAddress, DeploymentManager.gasPrice.times(transactionReceipt.gasUsed));
 | 
			
		||||
 | 
			
		||||
        // Simulate the batch order match.
 | 
			
		||||
        const expectedBatchMatchResults = await simulateBatchMatchOrdersAsync(
 | 
			
		||||
        const expectedBatchMatchResults = await this._simulateBatchMatchOrdersAsync(
 | 
			
		||||
            orders,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            this._deployment,
 | 
			
		||||
            this._blockchainBalanceStore,
 | 
			
		||||
            localBalanceStore,
 | 
			
		||||
            matchPairs,
 | 
			
		||||
            expectedTransferAmounts,
 | 
			
		||||
            this._assetDataEncoder,
 | 
			
		||||
            localBalanceStore,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const expectedResults = convertToBatchMatchResults(expectedBatchMatchResults);
 | 
			
		||||
        expect(actualBatchMatchResults).to.be.eql(expectedResults);
 | 
			
		||||
 | 
			
		||||
        // Validate the simulation against reality.
 | 
			
		||||
        await assertBatchMatchResultsAsync(
 | 
			
		||||
            expectedBatchMatchResults,
 | 
			
		||||
            transactionReceipt,
 | 
			
		||||
            this._blockchainBalanceStore,
 | 
			
		||||
            localBalanceStore,
 | 
			
		||||
            this._deployment.exchange,
 | 
			
		||||
        );
 | 
			
		||||
        await this._assertBatchMatchResultsAsync(expectedBatchMatchResults, transactionReceipt, localBalanceStore);
 | 
			
		||||
        return expectedBatchMatchResults;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Matches two complementary orders and asserts results.
 | 
			
		||||
     * @param orders The matched orders and filled states.
 | 
			
		||||
     * @param takerAddress Address of taker (the address who matched the two orders)
 | 
			
		||||
     * @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
 | 
			
		||||
     *                                Omitted fields are either set to 0 or their complementary
 | 
			
		||||
     *                                field.
 | 
			
		||||
     * @param takerAddress Address of taker (the address who matched the two orders)
 | 
			
		||||
     * @param value The amount of value that should be sent in the contract call.
 | 
			
		||||
     * @param withMaximalFill A boolean that indicates whether the "maximal fill" order matching
 | 
			
		||||
     *                        strategy should be used.
 | 
			
		||||
     * @return Results of `matchOrders()`.
 | 
			
		||||
@@ -184,12 +174,12 @@ export class MatchOrderTester {
 | 
			
		||||
        value: BigNumber,
 | 
			
		||||
        withMaximalFill: boolean,
 | 
			
		||||
    ): Promise<MatchResults> {
 | 
			
		||||
        await assertInitialOrderStatesAsync(orders, this._deployment.exchange);
 | 
			
		||||
        await this._assertInitialOrderStatesAsync(orders);
 | 
			
		||||
 | 
			
		||||
        // Update the blockchain balance store and create a new local balance store
 | 
			
		||||
        // with the same initial balances.
 | 
			
		||||
        await this._blockchainBalanceStore.updateBalancesAsync();
 | 
			
		||||
        const localBalanceStore = LocalBalanceStore.create(this._devUtils, this._blockchainBalanceStore);
 | 
			
		||||
        const localBalanceStore = LocalBalanceStore.create(this._deployment.devUtils, this._blockchainBalanceStore);
 | 
			
		||||
 | 
			
		||||
        // Execute `matchOrders()`
 | 
			
		||||
        let actualMatchResults;
 | 
			
		||||
@@ -201,7 +191,7 @@ export class MatchOrderTester {
 | 
			
		||||
                orders.rightOrder,
 | 
			
		||||
                orders.leftOrder.signature,
 | 
			
		||||
                orders.rightOrder.signature,
 | 
			
		||||
                { from: takerAddress, gasPrice: constants.DEFAULT_GAS_PRICE, value },
 | 
			
		||||
                { from: takerAddress, gasPrice: DeploymentManager.gasPrice, value },
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            [actualMatchResults, transactionReceipt] = await this._deployment.txHelper.getResultAndReceiptAsync(
 | 
			
		||||
@@ -210,227 +200,41 @@ export class MatchOrderTester {
 | 
			
		||||
                orders.rightOrder,
 | 
			
		||||
                orders.leftOrder.signature,
 | 
			
		||||
                orders.rightOrder.signature,
 | 
			
		||||
                { from: takerAddress, gasPrice: constants.DEFAULT_GAS_PRICE, value },
 | 
			
		||||
                { from: takerAddress, gasPrice: DeploymentManager.gasPrice, value },
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        localBalanceStore.burnGas(takerAddress, constants.DEFAULT_GAS_PRICE * transactionReceipt.gasUsed);
 | 
			
		||||
        localBalanceStore.burnGas(takerAddress, DeploymentManager.gasPrice.times(transactionReceipt.gasUsed));
 | 
			
		||||
 | 
			
		||||
        // Simulate the fill.
 | 
			
		||||
        const expectedMatchResults = await simulateMatchOrdersAsync(
 | 
			
		||||
        const expectedMatchResults = await this._simulateMatchOrdersAsync(
 | 
			
		||||
            orders,
 | 
			
		||||
            takerAddress,
 | 
			
		||||
            this._deployment,
 | 
			
		||||
            toFullMatchTransferAmounts(expectedTransferAmounts),
 | 
			
		||||
            this._assetDataEncoder,
 | 
			
		||||
            this._blockchainBalanceStore,
 | 
			
		||||
            localBalanceStore,
 | 
			
		||||
        );
 | 
			
		||||
        const expectedResults = convertToMatchResults(expectedMatchResults);
 | 
			
		||||
        expect(actualMatchResults).to.be.eql(expectedResults);
 | 
			
		||||
 | 
			
		||||
        // Validate the simulation against reality.
 | 
			
		||||
        await assertMatchResultsAsync(
 | 
			
		||||
            expectedMatchResults,
 | 
			
		||||
            transactionReceipt,
 | 
			
		||||
            localBalanceStore,
 | 
			
		||||
            this._blockchainBalanceStore,
 | 
			
		||||
            this._deployment.exchange,
 | 
			
		||||
        );
 | 
			
		||||
        await this._assertMatchResultsAsync(expectedMatchResults, transactionReceipt, localBalanceStore);
 | 
			
		||||
        return expectedMatchResults;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Converts a `Partial<MatchTransferAmounts>` to a `MatchTransferAmounts` by
 | 
			
		||||
 *      filling in missing fields with zero.
 | 
			
		||||
 */
 | 
			
		||||
function toFullMatchTransferAmounts(partial: Partial<MatchTransferAmounts>): MatchTransferAmounts {
 | 
			
		||||
    // prettier-ignore
 | 
			
		||||
    return {
 | 
			
		||||
        leftMakerAssetSoldByLeftMakerAmount:
 | 
			
		||||
            partial.leftMakerAssetSoldByLeftMakerAmount ||
 | 
			
		||||
            partial.leftMakerAssetBoughtByRightMakerAmount ||
 | 
			
		||||
            constants.ZERO_AMOUNT,
 | 
			
		||||
        rightMakerAssetSoldByRightMakerAmount:
 | 
			
		||||
            partial.rightMakerAssetSoldByRightMakerAmount ||
 | 
			
		||||
            partial.rightMakerAssetBoughtByLeftMakerAmount ||
 | 
			
		||||
            constants.ZERO_AMOUNT,
 | 
			
		||||
        rightMakerAssetBoughtByLeftMakerAmount:
 | 
			
		||||
            partial.rightMakerAssetBoughtByLeftMakerAmount ||
 | 
			
		||||
            partial.rightMakerAssetSoldByRightMakerAmount ||
 | 
			
		||||
            constants.ZERO_AMOUNT,
 | 
			
		||||
        leftMakerAssetBoughtByRightMakerAmount: partial.leftMakerAssetBoughtByRightMakerAmount ||
 | 
			
		||||
            partial.leftMakerAssetSoldByLeftMakerAmount ||
 | 
			
		||||
            constants.ZERO_AMOUNT,
 | 
			
		||||
        leftMakerFeeAssetPaidByLeftMakerAmount:
 | 
			
		||||
            partial.leftMakerFeeAssetPaidByLeftMakerAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        rightMakerFeeAssetPaidByRightMakerAmount:
 | 
			
		||||
            partial.rightMakerFeeAssetPaidByRightMakerAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        leftMakerAssetReceivedByTakerAmount:
 | 
			
		||||
            partial.leftMakerAssetReceivedByTakerAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        rightMakerAssetReceivedByTakerAmount:
 | 
			
		||||
            partial.rightMakerAssetReceivedByTakerAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        leftTakerFeeAssetPaidByTakerAmount:
 | 
			
		||||
            partial.leftTakerFeeAssetPaidByTakerAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        rightTakerFeeAssetPaidByTakerAmount:
 | 
			
		||||
            partial.rightTakerFeeAssetPaidByTakerAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        leftProtocolFeePaidByTakerInEthAmount:
 | 
			
		||||
            partial.leftProtocolFeePaidByTakerInEthAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        leftProtocolFeePaidByTakerInWethAmount:
 | 
			
		||||
            partial.leftProtocolFeePaidByTakerInWethAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        rightProtocolFeePaidByTakerInEthAmount:
 | 
			
		||||
            partial.rightProtocolFeePaidByTakerInEthAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        rightProtocolFeePaidByTakerInWethAmount:
 | 
			
		||||
            partial.rightProtocolFeePaidByTakerInWethAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Simulates matching a batch of orders by transferring amounts defined in
 | 
			
		||||
 * `transferAmounts` and returns the results.
 | 
			
		||||
 * @param orders The orders being batch matched and their filled states.
 | 
			
		||||
 * @param takerAddress Address of taker (the address who matched the two orders)
 | 
			
		||||
 * @param tokenBalances Current token balances.
 | 
			
		||||
 * @param transferAmounts Amounts to transfer during the simulation.
 | 
			
		||||
 * @return The new account balances and fill events that occurred during the match.
 | 
			
		||||
 */
 | 
			
		||||
async function simulateBatchMatchOrdersAsync(
 | 
			
		||||
    orders: BatchMatchedOrders,
 | 
			
		||||
    takerAddress: string,
 | 
			
		||||
    deployment: DeploymentManager,
 | 
			
		||||
    blockchainBalanceStore: BlockchainBalanceStore,
 | 
			
		||||
    localBalanceStore: LocalBalanceStore,
 | 
			
		||||
    matchPairs: Array<[number, number]>,
 | 
			
		||||
    transferAmounts: Array<Partial<MatchTransferAmounts>>,
 | 
			
		||||
    assetDataEncoder: IAssetDataContract,
 | 
			
		||||
): Promise<BatchMatchResults> {
 | 
			
		||||
    // Initialize variables
 | 
			
		||||
    let leftIdx = 0;
 | 
			
		||||
    let rightIdx = 0;
 | 
			
		||||
    let lastLeftIdx = -1;
 | 
			
		||||
    let lastRightIdx = -1;
 | 
			
		||||
    let matchedOrders: MatchedOrders;
 | 
			
		||||
    const batchMatchResults: BatchMatchResults = {
 | 
			
		||||
        matches: [],
 | 
			
		||||
        filledAmounts: [],
 | 
			
		||||
        leftFilledResults: [],
 | 
			
		||||
        rightFilledResults: [],
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Loop over all of the matched pairs from the round
 | 
			
		||||
    for (let i = 0; i < matchPairs.length; i++) {
 | 
			
		||||
        leftIdx = matchPairs[i][0];
 | 
			
		||||
        rightIdx = matchPairs[i][1];
 | 
			
		||||
 | 
			
		||||
        // Construct a matched order out of the current left and right orders
 | 
			
		||||
        matchedOrders = {
 | 
			
		||||
            leftOrder: orders.leftOrders[leftIdx],
 | 
			
		||||
            rightOrder: orders.rightOrders[rightIdx],
 | 
			
		||||
            leftOrderTakerAssetFilledAmount: orders.leftOrdersTakerAssetFilledAmounts[leftIdx],
 | 
			
		||||
            rightOrderTakerAssetFilledAmount: orders.rightOrdersTakerAssetFilledAmounts[rightIdx],
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // If there has been a match recorded and one or both of the side indices have not changed,
 | 
			
		||||
        // replace the side's taker asset filled amount
 | 
			
		||||
        if (batchMatchResults.matches.length > 0) {
 | 
			
		||||
            if (lastLeftIdx === leftIdx) {
 | 
			
		||||
                matchedOrders.leftOrderTakerAssetFilledAmount = getLastMatch(
 | 
			
		||||
                    batchMatchResults,
 | 
			
		||||
                ).orders.leftOrderTakerAssetFilledAmount;
 | 
			
		||||
            } else {
 | 
			
		||||
                batchMatchResults.filledAmounts.push([
 | 
			
		||||
                    orders.leftOrders[lastLeftIdx],
 | 
			
		||||
                    getLastMatch(batchMatchResults).orders.leftOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
                    'left',
 | 
			
		||||
                ]);
 | 
			
		||||
            }
 | 
			
		||||
            if (lastRightIdx === rightIdx) {
 | 
			
		||||
                matchedOrders.rightOrderTakerAssetFilledAmount = getLastMatch(
 | 
			
		||||
                    batchMatchResults,
 | 
			
		||||
                ).orders.rightOrderTakerAssetFilledAmount;
 | 
			
		||||
            } else {
 | 
			
		||||
                batchMatchResults.filledAmounts.push([
 | 
			
		||||
                    orders.rightOrders[lastRightIdx],
 | 
			
		||||
                    getLastMatch(batchMatchResults).orders.rightOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
                    'right',
 | 
			
		||||
                ]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Add the latest match to the batch match results
 | 
			
		||||
        batchMatchResults.matches.push(
 | 
			
		||||
            await simulateMatchOrdersAsync(
 | 
			
		||||
                matchedOrders,
 | 
			
		||||
                takerAddress,
 | 
			
		||||
                deployment,
 | 
			
		||||
                toFullMatchTransferAmounts(transferAmounts[i]),
 | 
			
		||||
                assetDataEncoder,
 | 
			
		||||
                blockchainBalanceStore,
 | 
			
		||||
                localBalanceStore,
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Update the left and right fill results
 | 
			
		||||
        if (lastLeftIdx === leftIdx) {
 | 
			
		||||
            addFillResults(batchMatchResults.leftFilledResults[leftIdx], getLastMatch(batchMatchResults).fills[0]);
 | 
			
		||||
        } else {
 | 
			
		||||
            batchMatchResults.leftFilledResults.push({ ...getLastMatch(batchMatchResults).fills[0] });
 | 
			
		||||
        }
 | 
			
		||||
        if (lastRightIdx === rightIdx) {
 | 
			
		||||
            addFillResults(batchMatchResults.rightFilledResults[rightIdx], getLastMatch(batchMatchResults).fills[1]);
 | 
			
		||||
        } else {
 | 
			
		||||
            batchMatchResults.rightFilledResults.push({ ...getLastMatch(batchMatchResults).fills[1] });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        lastLeftIdx = leftIdx;
 | 
			
		||||
        lastRightIdx = rightIdx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (let i = leftIdx + 1; i < orders.leftOrders.length; i++) {
 | 
			
		||||
        batchMatchResults.leftFilledResults.push(emptyFillEventArgs());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (let i = rightIdx + 1; i < orders.rightOrders.length; i++) {
 | 
			
		||||
        batchMatchResults.rightFilledResults.push(emptyFillEventArgs());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The two orders indexed by lastLeftIdx and lastRightIdx were potentially
 | 
			
		||||
    // filled; however, the TakerAssetFilledAmounts that pertain to these orders
 | 
			
		||||
    // will not have been added to batchMatchResults, so we need to write them
 | 
			
		||||
    // here.
 | 
			
		||||
    batchMatchResults.filledAmounts.push([
 | 
			
		||||
        orders.leftOrders[lastLeftIdx],
 | 
			
		||||
        getLastMatch(batchMatchResults).orders.leftOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        'left',
 | 
			
		||||
    ]);
 | 
			
		||||
    batchMatchResults.filledAmounts.push([
 | 
			
		||||
        orders.rightOrders[lastRightIdx],
 | 
			
		||||
        getLastMatch(batchMatchResults).orders.rightOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        'right',
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Return the batch match results
 | 
			
		||||
    return batchMatchResults;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
    /**
 | 
			
		||||
     * Simulates matching two orders by transferring amounts defined in
 | 
			
		||||
     * `transferAmounts` and returns the results.
 | 
			
		||||
     * @param orders The orders being matched and their filled states.
 | 
			
		||||
     * @param takerAddress Address of taker (the address who matched the two orders)
 | 
			
		||||
 * @param tokenBalances Current token balances.
 | 
			
		||||
     * @param transferAmounts Amounts to transfer during the simulation.
 | 
			
		||||
     * @param localBalanceStore The balance store to use for the simulation.
 | 
			
		||||
     * @return The new account balances and fill events that occurred during the match.
 | 
			
		||||
     */
 | 
			
		||||
async function simulateMatchOrdersAsync(
 | 
			
		||||
    protected async _simulateMatchOrdersAsync(
 | 
			
		||||
        orders: MatchedOrders,
 | 
			
		||||
        takerAddress: string,
 | 
			
		||||
    deployment: DeploymentManager,
 | 
			
		||||
        transferAmounts: MatchTransferAmounts,
 | 
			
		||||
    assetDataEncoder: IAssetDataContract,
 | 
			
		||||
    blockchainBalanceStore: BlockchainBalanceStore,
 | 
			
		||||
        localBalanceStore: LocalBalanceStore,
 | 
			
		||||
): Promise<MatchResults> {
 | 
			
		||||
    ): Promise<MatchResults> {
 | 
			
		||||
        // prettier-ignore
 | 
			
		||||
        const matchResults = {
 | 
			
		||||
        orders: {
 | 
			
		||||
@@ -517,47 +321,172 @@ async function simulateMatchOrdersAsync(
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Protocol Fee
 | 
			
		||||
    const wethAssetData = assetDataEncoder.ERC20Token.getABIEncodedTransactionData(deployment.tokens.weth.address);
 | 
			
		||||
        const wethAssetData = this._deployment.assetDataEncoder.ERC20Token.getABIEncodedTransactionData(
 | 
			
		||||
            this._deployment.tokens.weth.address,
 | 
			
		||||
        );
 | 
			
		||||
        localBalanceStore.sendEth(
 | 
			
		||||
            takerAddress,
 | 
			
		||||
        deployment.staking.stakingProxy.address,
 | 
			
		||||
            this._deployment.staking.stakingProxy.address,
 | 
			
		||||
            transferAmounts.leftProtocolFeePaidByTakerInEthAmount,
 | 
			
		||||
        );
 | 
			
		||||
        localBalanceStore.sendEth(
 | 
			
		||||
            takerAddress,
 | 
			
		||||
        deployment.staking.stakingProxy.address,
 | 
			
		||||
            this._deployment.staking.stakingProxy.address,
 | 
			
		||||
            transferAmounts.rightProtocolFeePaidByTakerInEthAmount,
 | 
			
		||||
        );
 | 
			
		||||
        await localBalanceStore.transferAssetAsync(
 | 
			
		||||
            takerAddress,
 | 
			
		||||
        deployment.staking.stakingProxy.address,
 | 
			
		||||
            this._deployment.staking.stakingProxy.address,
 | 
			
		||||
            transferAmounts.leftProtocolFeePaidByTakerInWethAmount,
 | 
			
		||||
            wethAssetData,
 | 
			
		||||
        );
 | 
			
		||||
        await localBalanceStore.transferAssetAsync(
 | 
			
		||||
            takerAddress,
 | 
			
		||||
        deployment.staking.stakingProxy.address,
 | 
			
		||||
            this._deployment.staking.stakingProxy.address,
 | 
			
		||||
            transferAmounts.rightProtocolFeePaidByTakerInWethAmount,
 | 
			
		||||
            wethAssetData,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return matchResults;
 | 
			
		||||
}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
    /**
 | 
			
		||||
     * Simulates matching a batch of orders by transferring amounts defined in
 | 
			
		||||
     * `transferAmounts` and returns the results.
 | 
			
		||||
     * @param orders The orders being batch matched and their filled states.
 | 
			
		||||
     * @param takerAddress Address of taker (the address who matched the two orders)
 | 
			
		||||
     * @param matchPairs The pairs of orders that are expected to be matched.
 | 
			
		||||
     * @param transferAmounts Amounts to transfer during the simulation.
 | 
			
		||||
     * @param localBalanceStore The balance store to use for the simulation.
 | 
			
		||||
     * @return The new account balances and fill events that occurred during the match.
 | 
			
		||||
     */
 | 
			
		||||
    protected async _simulateBatchMatchOrdersAsync(
 | 
			
		||||
        orders: BatchMatchedOrders,
 | 
			
		||||
        takerAddress: string,
 | 
			
		||||
        matchPairs: Array<[number, number]>,
 | 
			
		||||
        transferAmounts: Array<Partial<MatchTransferAmounts>>,
 | 
			
		||||
        localBalanceStore: LocalBalanceStore,
 | 
			
		||||
    ): Promise<BatchMatchResults> {
 | 
			
		||||
        // Initialize variables
 | 
			
		||||
        let leftIdx = 0;
 | 
			
		||||
        let rightIdx = 0;
 | 
			
		||||
        let lastLeftIdx = -1;
 | 
			
		||||
        let lastRightIdx = -1;
 | 
			
		||||
        let matchedOrders: MatchedOrders;
 | 
			
		||||
        const batchMatchResults: BatchMatchResults = {
 | 
			
		||||
            matches: [],
 | 
			
		||||
            filledAmounts: [],
 | 
			
		||||
            leftFilledResults: [],
 | 
			
		||||
            rightFilledResults: [],
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Loop over all of the matched pairs from the round
 | 
			
		||||
        for (let i = 0; i < matchPairs.length; i++) {
 | 
			
		||||
            leftIdx = matchPairs[i][0];
 | 
			
		||||
            rightIdx = matchPairs[i][1];
 | 
			
		||||
 | 
			
		||||
            // Construct a matched order out of the current left and right orders
 | 
			
		||||
            matchedOrders = {
 | 
			
		||||
                leftOrder: orders.leftOrders[leftIdx],
 | 
			
		||||
                rightOrder: orders.rightOrders[rightIdx],
 | 
			
		||||
                leftOrderTakerAssetFilledAmount: orders.leftOrdersTakerAssetFilledAmounts[leftIdx],
 | 
			
		||||
                rightOrderTakerAssetFilledAmount: orders.rightOrdersTakerAssetFilledAmounts[rightIdx],
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // If there has been a match recorded and one or both of the side indices have not changed,
 | 
			
		||||
            // replace the side's taker asset filled amount
 | 
			
		||||
            if (batchMatchResults.matches.length > 0) {
 | 
			
		||||
                if (lastLeftIdx === leftIdx) {
 | 
			
		||||
                    matchedOrders.leftOrderTakerAssetFilledAmount = getLastMatch(
 | 
			
		||||
                        batchMatchResults,
 | 
			
		||||
                    ).orders.leftOrderTakerAssetFilledAmount;
 | 
			
		||||
                } else {
 | 
			
		||||
                    batchMatchResults.filledAmounts.push([
 | 
			
		||||
                        orders.leftOrders[lastLeftIdx],
 | 
			
		||||
                        getLastMatch(batchMatchResults).orders.leftOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
                        'left',
 | 
			
		||||
                    ]);
 | 
			
		||||
                }
 | 
			
		||||
                if (lastRightIdx === rightIdx) {
 | 
			
		||||
                    matchedOrders.rightOrderTakerAssetFilledAmount = getLastMatch(
 | 
			
		||||
                        batchMatchResults,
 | 
			
		||||
                    ).orders.rightOrderTakerAssetFilledAmount;
 | 
			
		||||
                } else {
 | 
			
		||||
                    batchMatchResults.filledAmounts.push([
 | 
			
		||||
                        orders.rightOrders[lastRightIdx],
 | 
			
		||||
                        getLastMatch(batchMatchResults).orders.rightOrderTakerAssetFilledAmount ||
 | 
			
		||||
                            constants.ZERO_AMOUNT,
 | 
			
		||||
                        'right',
 | 
			
		||||
                    ]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Add the latest match to the batch match results
 | 
			
		||||
            batchMatchResults.matches.push(
 | 
			
		||||
                await this._simulateMatchOrdersAsync(
 | 
			
		||||
                    matchedOrders,
 | 
			
		||||
                    takerAddress,
 | 
			
		||||
                    toFullMatchTransferAmounts(transferAmounts[i]),
 | 
			
		||||
                    localBalanceStore,
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Update the left and right fill results
 | 
			
		||||
            if (lastLeftIdx === leftIdx) {
 | 
			
		||||
                addFillResults(batchMatchResults.leftFilledResults[leftIdx], getLastMatch(batchMatchResults).fills[0]);
 | 
			
		||||
            } else {
 | 
			
		||||
                batchMatchResults.leftFilledResults.push({ ...getLastMatch(batchMatchResults).fills[0] });
 | 
			
		||||
            }
 | 
			
		||||
            if (lastRightIdx === rightIdx) {
 | 
			
		||||
                addFillResults(
 | 
			
		||||
                    batchMatchResults.rightFilledResults[rightIdx],
 | 
			
		||||
                    getLastMatch(batchMatchResults).fills[1],
 | 
			
		||||
                );
 | 
			
		||||
            } else {
 | 
			
		||||
                batchMatchResults.rightFilledResults.push({ ...getLastMatch(batchMatchResults).fills[1] });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            lastLeftIdx = leftIdx;
 | 
			
		||||
            lastRightIdx = rightIdx;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = leftIdx + 1; i < orders.leftOrders.length; i++) {
 | 
			
		||||
            batchMatchResults.leftFilledResults.push(emptyFillEventArgs());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = rightIdx + 1; i < orders.rightOrders.length; i++) {
 | 
			
		||||
            batchMatchResults.rightFilledResults.push(emptyFillEventArgs());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // The two orders indexed by lastLeftIdx and lastRightIdx were potentially
 | 
			
		||||
        // filled; however, the TakerAssetFilledAmounts that pertain to these orders
 | 
			
		||||
        // will not have been added to batchMatchResults, so we need to write them
 | 
			
		||||
        // here.
 | 
			
		||||
        batchMatchResults.filledAmounts.push([
 | 
			
		||||
            orders.leftOrders[lastLeftIdx],
 | 
			
		||||
            getLastMatch(batchMatchResults).orders.leftOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
            'left',
 | 
			
		||||
        ]);
 | 
			
		||||
        batchMatchResults.filledAmounts.push([
 | 
			
		||||
            orders.rightOrders[lastRightIdx],
 | 
			
		||||
            getLastMatch(batchMatchResults).orders.rightOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
            'right',
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        // Return the batch match results
 | 
			
		||||
        return batchMatchResults;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks that the results of `simulateBatchMatchOrders()` agrees with reality.
 | 
			
		||||
     * @param batchMatchResults The results of a `simulateBatchMatchOrders()`.
 | 
			
		||||
     * @param transactionReceipt The transaction receipt of a call to `matchOrders()`.
 | 
			
		||||
 * @param actualTokenBalances The actual, on-chain token balances of known addresses.
 | 
			
		||||
 * @param exchangeWrapper The ExchangeWrapper instance.
 | 
			
		||||
     * @param localBalanceStore The balance store to use during the simulation.
 | 
			
		||||
     */
 | 
			
		||||
async function assertBatchMatchResultsAsync(
 | 
			
		||||
    protected async _assertBatchMatchResultsAsync(
 | 
			
		||||
        batchMatchResults: BatchMatchResults,
 | 
			
		||||
        transactionReceipt: TransactionReceiptWithDecodedLogs,
 | 
			
		||||
    blockchainBalanceStore: BlockchainBalanceStore,
 | 
			
		||||
        localBalanceStore: LocalBalanceStore,
 | 
			
		||||
    exchange: ExchangeContract,
 | 
			
		||||
): Promise<void> {
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        // Ensure that the batchMatchResults contain at least one match
 | 
			
		||||
        expect(batchMatchResults.matches.length).to.be.gt(0);
 | 
			
		||||
 | 
			
		||||
@@ -568,49 +497,189 @@ async function assertBatchMatchResultsAsync(
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Update the blockchain balance store balances.
 | 
			
		||||
    await blockchainBalanceStore.updateBalancesAsync();
 | 
			
		||||
        await this._blockchainBalanceStore.updateBalancesAsync();
 | 
			
		||||
 | 
			
		||||
        // Ensure that the actual and expected token balances are equivalent.
 | 
			
		||||
    localBalanceStore.assertEquals(blockchainBalanceStore);
 | 
			
		||||
        localBalanceStore.assertEquals(this._blockchainBalanceStore);
 | 
			
		||||
 | 
			
		||||
        // Check the Exchange state.
 | 
			
		||||
    await assertPostBatchExchangeStateAsync(batchMatchResults, exchange);
 | 
			
		||||
}
 | 
			
		||||
        await this._assertPostBatchExchangeStateAsync(batchMatchResults);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks that the results of `simulateMatchOrders()` agrees with reality.
 | 
			
		||||
     * @param matchResults The results of a `simulateMatchOrders()`.
 | 
			
		||||
     * @param transactionReceipt The transaction receipt of a call to `matchOrders()`.
 | 
			
		||||
 * @param actualTokenBalances The actual, on-chain token balances of known addresses.
 | 
			
		||||
 * @param exchangeWrapper The ExchangeWrapper instance.
 | 
			
		||||
     * @param localBalanceStore The balance store to use during the simulation.
 | 
			
		||||
     */
 | 
			
		||||
async function assertMatchResultsAsync(
 | 
			
		||||
    protected async _assertMatchResultsAsync(
 | 
			
		||||
        matchResults: MatchResults,
 | 
			
		||||
        transactionReceipt: TransactionReceiptWithDecodedLogs,
 | 
			
		||||
        localBalanceStore: LocalBalanceStore,
 | 
			
		||||
    blockchainBalanceStore: BlockchainBalanceStore,
 | 
			
		||||
    exchange: ExchangeContract,
 | 
			
		||||
): Promise<void> {
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        // Check the fill events.
 | 
			
		||||
        assertFillEvents(matchResults.fills, transactionReceipt);
 | 
			
		||||
 | 
			
		||||
        // Update the blockchain balance store balances.
 | 
			
		||||
    await blockchainBalanceStore.updateBalancesAsync();
 | 
			
		||||
        await this._blockchainBalanceStore.updateBalancesAsync();
 | 
			
		||||
 | 
			
		||||
        // Check the token balances.
 | 
			
		||||
    localBalanceStore.assertEquals(blockchainBalanceStore);
 | 
			
		||||
        localBalanceStore.assertEquals(this._blockchainBalanceStore);
 | 
			
		||||
 | 
			
		||||
        // Check the Exchange state.
 | 
			
		||||
    await assertPostExchangeStateAsync(matchResults, exchange);
 | 
			
		||||
        await this._assertPostExchangeStateAsync(matchResults);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Asserts the initial exchange state for batch matched orders.
 | 
			
		||||
     * @param orders Batch matched orders with intial filled amounts.
 | 
			
		||||
     */
 | 
			
		||||
    private async _assertBatchOrderStatesAsync(orders: BatchMatchedOrders): Promise<void> {
 | 
			
		||||
        for (let i = 0; i < orders.leftOrders.length; i++) {
 | 
			
		||||
            await this._assertOrderFilledAmountAsync(
 | 
			
		||||
                orders.leftOrders[i],
 | 
			
		||||
                orders.leftOrdersTakerAssetFilledAmounts[i],
 | 
			
		||||
                'left',
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        for (let i = 0; i < orders.rightOrders.length; i++) {
 | 
			
		||||
            await this._assertOrderFilledAmountAsync(
 | 
			
		||||
                orders.rightOrders[i],
 | 
			
		||||
                orders.rightOrdersTakerAssetFilledAmounts[i],
 | 
			
		||||
                'right',
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Asserts the initial exchange state for matched orders.
 | 
			
		||||
     * @param orders Matched orders with intial filled amounts.
 | 
			
		||||
     */
 | 
			
		||||
    private async _assertInitialOrderStatesAsync(orders: MatchedOrders): Promise<void> {
 | 
			
		||||
        const pairs = [
 | 
			
		||||
            [orders.leftOrder, orders.leftOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT],
 | 
			
		||||
            [orders.rightOrder, orders.rightOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT],
 | 
			
		||||
        ] as Array<[SignedOrder, BigNumber]>;
 | 
			
		||||
        await Promise.all(
 | 
			
		||||
            pairs.map(async ([order, expectedFilledAmount]) => {
 | 
			
		||||
                const side = order === orders.leftOrder ? 'left' : 'right';
 | 
			
		||||
                await this._assertOrderFilledAmountAsync(order, expectedFilledAmount, side);
 | 
			
		||||
            }),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Asserts the exchange state after a call to `batchMatchOrders()`.
 | 
			
		||||
     * @param batchMatchResults Results from a call to `simulateBatchMatchOrders()`.
 | 
			
		||||
     */
 | 
			
		||||
    private async _assertPostBatchExchangeStateAsync(batchMatchResults: BatchMatchResults): Promise<void> {
 | 
			
		||||
        await this._assertTriplesExchangeStateAsync(batchMatchResults.filledAmounts);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Asserts the exchange state after a call to `matchOrders()`.
 | 
			
		||||
     * @param matchResults Results from a call to `simulateMatchOrders()`.
 | 
			
		||||
     */
 | 
			
		||||
    private async _assertPostExchangeStateAsync(matchResults: MatchResults): Promise<void> {
 | 
			
		||||
        const triples = [
 | 
			
		||||
            [matchResults.orders.leftOrder, matchResults.orders.leftOrderTakerAssetFilledAmount, 'left'],
 | 
			
		||||
            [matchResults.orders.rightOrder, matchResults.orders.rightOrderTakerAssetFilledAmount, 'right'],
 | 
			
		||||
        ] as Array<[SignedOrder, BigNumber, string]>;
 | 
			
		||||
        await this._assertTriplesExchangeStateAsync(triples);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Asserts the exchange state represented by provided sequence of triples.
 | 
			
		||||
     * @param triples The sequence of triples to verifiy. Each triple consists
 | 
			
		||||
     *                of an `order`, a `takerAssetFilledAmount`, and a `side`,
 | 
			
		||||
     *                which will be used to determine if the exchange's state
 | 
			
		||||
     *                is valid.
 | 
			
		||||
     */
 | 
			
		||||
    private async _assertTriplesExchangeStateAsync(triples: Array<[SignedOrder, BigNumber, string]>): Promise<void> {
 | 
			
		||||
        await Promise.all(
 | 
			
		||||
            triples.map(async ([order, expectedFilledAmount, side]) => {
 | 
			
		||||
                expect(['left', 'right']).to.include(side);
 | 
			
		||||
                await this._assertOrderFilledAmountAsync(order, expectedFilledAmount, side);
 | 
			
		||||
            }),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Asserts that the provided order's fill amount and order status
 | 
			
		||||
     * are the expected values.
 | 
			
		||||
     * @param order The order to verify for a correct state.
 | 
			
		||||
     * @param expectedFilledAmount The amount that the order should
 | 
			
		||||
     *                             have been filled.
 | 
			
		||||
     * @param side The side that the provided order should be matched on.
 | 
			
		||||
     */
 | 
			
		||||
    private async _assertOrderFilledAmountAsync(
 | 
			
		||||
        order: SignedOrder,
 | 
			
		||||
        expectedFilledAmount: BigNumber,
 | 
			
		||||
        side: string,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const orderInfo = await this._deployment.exchange.getOrderInfo.callAsync(order);
 | 
			
		||||
        // Check filled amount of order.
 | 
			
		||||
        const actualFilledAmount = orderInfo.orderTakerAssetFilledAmount;
 | 
			
		||||
        expect(actualFilledAmount, `${side} order final filled amount`).to.be.bignumber.equal(expectedFilledAmount);
 | 
			
		||||
        // Check status of order.
 | 
			
		||||
        const expectedStatus = expectedFilledAmount.isGreaterThanOrEqualTo(order.takerAssetAmount)
 | 
			
		||||
            ? OrderStatus.FullyFilled
 | 
			
		||||
            : OrderStatus.Fillable;
 | 
			
		||||
        const actualStatus = orderInfo.orderStatus;
 | 
			
		||||
        expect(actualStatus, `${side} order final status`).to.equal(expectedStatus);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Converts a `Partial<MatchTransferAmounts>` to a `MatchTransferAmounts` by
 | 
			
		||||
 *      filling in missing fields with zero.
 | 
			
		||||
 */
 | 
			
		||||
function toFullMatchTransferAmounts(partial: Partial<MatchTransferAmounts>): MatchTransferAmounts {
 | 
			
		||||
    // prettier-ignore
 | 
			
		||||
    return {
 | 
			
		||||
        leftMakerAssetSoldByLeftMakerAmount:
 | 
			
		||||
            partial.leftMakerAssetSoldByLeftMakerAmount ||
 | 
			
		||||
            partial.leftMakerAssetBoughtByRightMakerAmount ||
 | 
			
		||||
            constants.ZERO_AMOUNT,
 | 
			
		||||
        rightMakerAssetSoldByRightMakerAmount:
 | 
			
		||||
            partial.rightMakerAssetSoldByRightMakerAmount ||
 | 
			
		||||
            partial.rightMakerAssetBoughtByLeftMakerAmount ||
 | 
			
		||||
            constants.ZERO_AMOUNT,
 | 
			
		||||
        rightMakerAssetBoughtByLeftMakerAmount:
 | 
			
		||||
            partial.rightMakerAssetBoughtByLeftMakerAmount ||
 | 
			
		||||
            partial.rightMakerAssetSoldByRightMakerAmount ||
 | 
			
		||||
            constants.ZERO_AMOUNT,
 | 
			
		||||
        leftMakerAssetBoughtByRightMakerAmount: partial.leftMakerAssetBoughtByRightMakerAmount ||
 | 
			
		||||
            partial.leftMakerAssetSoldByLeftMakerAmount ||
 | 
			
		||||
            constants.ZERO_AMOUNT,
 | 
			
		||||
        leftMakerFeeAssetPaidByLeftMakerAmount:
 | 
			
		||||
            partial.leftMakerFeeAssetPaidByLeftMakerAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        rightMakerFeeAssetPaidByRightMakerAmount:
 | 
			
		||||
            partial.rightMakerFeeAssetPaidByRightMakerAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        leftMakerAssetReceivedByTakerAmount:
 | 
			
		||||
            partial.leftMakerAssetReceivedByTakerAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        rightMakerAssetReceivedByTakerAmount:
 | 
			
		||||
            partial.rightMakerAssetReceivedByTakerAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        leftTakerFeeAssetPaidByTakerAmount:
 | 
			
		||||
            partial.leftTakerFeeAssetPaidByTakerAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        rightTakerFeeAssetPaidByTakerAmount:
 | 
			
		||||
            partial.rightTakerFeeAssetPaidByTakerAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        leftProtocolFeePaidByTakerInEthAmount:
 | 
			
		||||
            partial.leftProtocolFeePaidByTakerInEthAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        leftProtocolFeePaidByTakerInWethAmount:
 | 
			
		||||
            partial.leftProtocolFeePaidByTakerInWethAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        rightProtocolFeePaidByTakerInEthAmount:
 | 
			
		||||
            partial.rightProtocolFeePaidByTakerInEthAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
        rightProtocolFeePaidByTakerInWethAmount:
 | 
			
		||||
            partial.rightProtocolFeePaidByTakerInWethAmount || constants.ZERO_AMOUNT,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Checks values from the logs produced by Exchange.matchOrders against
 | 
			
		||||
 *      the expected transfer amounts.
 | 
			
		||||
 * @param orders The matched orders.
 | 
			
		||||
 * @param takerAddress Address of taker (account that called Exchange.matchOrders)
 | 
			
		||||
 * @param transactionReceipt Transaction receipt and logs produced by Exchange.matchOrders.
 | 
			
		||||
 * @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
 | 
			
		||||
 */
 | 
			
		||||
function assertFillEvents(expectedFills: FillEventArgs[], transactionReceipt: TransactionReceiptWithDecodedLogs): void {
 | 
			
		||||
    // Extract the actual `Fill` events.
 | 
			
		||||
@@ -703,120 +772,6 @@ function extractFillEventsfromReceipt(receipt: TransactionReceiptWithDecodedLogs
 | 
			
		||||
    }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Asserts the initial exchange state for batch matched orders.
 | 
			
		||||
 * @param orders Batch matched orders with intial filled amounts.
 | 
			
		||||
 * @param exchangeWrapper ExchangeWrapper instance.
 | 
			
		||||
 */
 | 
			
		||||
async function assertBatchOrderStatesAsync(orders: BatchMatchedOrders, exchange: ExchangeContract): Promise<void> {
 | 
			
		||||
    for (let i = 0; i < orders.leftOrders.length; i++) {
 | 
			
		||||
        await assertOrderFilledAmountAsync(
 | 
			
		||||
            orders.leftOrders[i],
 | 
			
		||||
            orders.leftOrdersTakerAssetFilledAmounts[i],
 | 
			
		||||
            'left',
 | 
			
		||||
            exchange,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    for (let i = 0; i < orders.rightOrders.length; i++) {
 | 
			
		||||
        await assertOrderFilledAmountAsync(
 | 
			
		||||
            orders.rightOrders[i],
 | 
			
		||||
            orders.rightOrdersTakerAssetFilledAmounts[i],
 | 
			
		||||
            'right',
 | 
			
		||||
            exchange,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Asserts the initial exchange state for matched orders.
 | 
			
		||||
 * @param orders Matched orders with intial filled amounts.
 | 
			
		||||
 * @param exchangeWrapper ExchangeWrapper instance.
 | 
			
		||||
 */
 | 
			
		||||
async function assertInitialOrderStatesAsync(orders: MatchedOrders, exchange: ExchangeContract): Promise<void> {
 | 
			
		||||
    const pairs = [
 | 
			
		||||
        [orders.leftOrder, orders.leftOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT],
 | 
			
		||||
        [orders.rightOrder, orders.rightOrderTakerAssetFilledAmount || constants.ZERO_AMOUNT],
 | 
			
		||||
    ] as Array<[SignedOrder, BigNumber]>;
 | 
			
		||||
    await Promise.all(
 | 
			
		||||
        pairs.map(async ([order, expectedFilledAmount]) => {
 | 
			
		||||
            const side = order === orders.leftOrder ? 'left' : 'right';
 | 
			
		||||
            await assertOrderFilledAmountAsync(order, expectedFilledAmount, side, exchange);
 | 
			
		||||
        }),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Asserts the exchange state after a call to `batchMatchOrders()`.
 | 
			
		||||
 * @param batchMatchResults Results from a call to `simulateBatchMatchOrders()`.
 | 
			
		||||
 * @param exchangeWrapper The ExchangeWrapper instance.
 | 
			
		||||
 */
 | 
			
		||||
async function assertPostBatchExchangeStateAsync(
 | 
			
		||||
    batchMatchResults: BatchMatchResults,
 | 
			
		||||
    exchange: ExchangeContract,
 | 
			
		||||
): Promise<void> {
 | 
			
		||||
    await assertTriplesExchangeStateAsync(batchMatchResults.filledAmounts, exchange);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Asserts the exchange state after a call to `matchOrders()`.
 | 
			
		||||
 * @param matchResults Results from a call to `simulateMatchOrders()`.
 | 
			
		||||
 * @param exchangeWrapper The ExchangeWrapper instance.
 | 
			
		||||
 */
 | 
			
		||||
async function assertPostExchangeStateAsync(matchResults: MatchResults, exchange: ExchangeContract): Promise<void> {
 | 
			
		||||
    const triples = [
 | 
			
		||||
        [matchResults.orders.leftOrder, matchResults.orders.leftOrderTakerAssetFilledAmount, 'left'],
 | 
			
		||||
        [matchResults.orders.rightOrder, matchResults.orders.rightOrderTakerAssetFilledAmount, 'right'],
 | 
			
		||||
    ] as Array<[SignedOrder, BigNumber, string]>;
 | 
			
		||||
    await assertTriplesExchangeStateAsync(triples, exchange);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Asserts the exchange state represented by provided sequence of triples.
 | 
			
		||||
 * @param triples The sequence of triples to verifiy. Each triple consists
 | 
			
		||||
 *                of an `order`, a `takerAssetFilledAmount`, and a `side`,
 | 
			
		||||
 *                which will be used to determine if the exchange's state
 | 
			
		||||
 *                is valid.
 | 
			
		||||
 * @param exchangeWrapper The ExchangeWrapper instance.
 | 
			
		||||
 */
 | 
			
		||||
async function assertTriplesExchangeStateAsync(
 | 
			
		||||
    triples: Array<[SignedOrder, BigNumber, string]>,
 | 
			
		||||
    exchange: ExchangeContract,
 | 
			
		||||
): Promise<void> {
 | 
			
		||||
    await Promise.all(
 | 
			
		||||
        triples.map(async ([order, expectedFilledAmount, side]) => {
 | 
			
		||||
            expect(['left', 'right']).to.include(side);
 | 
			
		||||
            await assertOrderFilledAmountAsync(order, expectedFilledAmount, side, exchange);
 | 
			
		||||
        }),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Asserts that the provided order's fill amount and order status
 | 
			
		||||
 * are the expected values.
 | 
			
		||||
 * @param order The order to verify for a correct state.
 | 
			
		||||
 * @param expectedFilledAmount The amount that the order should
 | 
			
		||||
 *                             have been filled.
 | 
			
		||||
 * @param side The side that the provided order should be matched on.
 | 
			
		||||
 * @param exchange The exchange contract that is in the current deployment.
 | 
			
		||||
 */
 | 
			
		||||
async function assertOrderFilledAmountAsync(
 | 
			
		||||
    order: SignedOrder,
 | 
			
		||||
    expectedFilledAmount: BigNumber,
 | 
			
		||||
    side: string,
 | 
			
		||||
    exchange: ExchangeContract,
 | 
			
		||||
): Promise<void> {
 | 
			
		||||
    const orderInfo = await exchange.getOrderInfo.callAsync(order);
 | 
			
		||||
    // Check filled amount of order.
 | 
			
		||||
    const actualFilledAmount = orderInfo.orderTakerAssetFilledAmount;
 | 
			
		||||
    expect(actualFilledAmount, `${side} order final filled amount`).to.be.bignumber.equal(expectedFilledAmount);
 | 
			
		||||
    // Check status of order.
 | 
			
		||||
    const expectedStatus = expectedFilledAmount.isGreaterThanOrEqualTo(order.takerAssetAmount)
 | 
			
		||||
        ? OrderStatus.FullyFilled
 | 
			
		||||
        : OrderStatus.Fillable;
 | 
			
		||||
    const actualStatus = orderInfo.orderStatus;
 | 
			
		||||
    expect(actualStatus, `${side} order final status`).to.equal(expectedStatus);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Gets the last match in a BatchMatchResults object.
 | 
			
		||||
 * @param batchMatchResults The BatchMatchResults object.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user