Merge pull request #1008 from 0xProject/fix/contracts/robustMatching
Robustness in Order Matching
This commit is contained in:
@@ -109,7 +109,7 @@ contract MixinMatchOrders is
|
||||
rightOrderInfo.orderTakerAssetFilledAmount,
|
||||
matchedFillResults.right
|
||||
);
|
||||
|
||||
|
||||
// Settle matched orders. Succeeds or throws.
|
||||
settleMatchedOrders(
|
||||
leftOrder,
|
||||
@@ -165,62 +165,85 @@ contract MixinMatchOrders is
|
||||
pure
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults)
|
||||
{
|
||||
// We settle orders at the exchange rate of the right order.
|
||||
// The amount saved by the left maker goes to the taker.
|
||||
// Either the left or right order will be fully filled; possibly both.
|
||||
// The left order is fully filled iff the right order can sell more than left can buy.
|
||||
// That is: the amount required to fill the left order is less than or equal to
|
||||
// the amount we can spend from the right order:
|
||||
// <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightMakerToTakerRatio>
|
||||
// <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount>
|
||||
// <leftTakerAssetAmountRemaining> * <rightOrder.takerAssetAmount> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount>
|
||||
// Derive maker asset amounts for left & right orders, given store taker assert amounts
|
||||
uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderTakerAssetFilledAmount);
|
||||
uint256 leftMakerAssetAmountRemaining = getPartialAmountFloor(
|
||||
leftOrder.makerAssetAmount,
|
||||
leftOrder.takerAssetAmount,
|
||||
leftTakerAssetAmountRemaining
|
||||
);
|
||||
uint256 rightTakerAssetAmountRemaining = safeSub(rightOrder.takerAssetAmount, rightOrderTakerAssetFilledAmount);
|
||||
uint256 leftTakerAssetFilledAmount;
|
||||
uint256 rightTakerAssetFilledAmount;
|
||||
if (
|
||||
safeMul(leftTakerAssetAmountRemaining, rightOrder.takerAssetAmount) <=
|
||||
safeMul(rightTakerAssetAmountRemaining, rightOrder.makerAssetAmount)
|
||||
) {
|
||||
// Left order will be fully filled: maximally fill left
|
||||
leftTakerAssetFilledAmount = leftTakerAssetAmountRemaining;
|
||||
uint256 rightMakerAssetAmountRemaining = getPartialAmountFloor(
|
||||
rightOrder.makerAssetAmount,
|
||||
rightOrder.takerAssetAmount,
|
||||
rightTakerAssetAmountRemaining
|
||||
);
|
||||
|
||||
// The right order receives an amount proportional to how much was spent.
|
||||
rightTakerAssetFilledAmount = getPartialAmountFloor(
|
||||
rightOrder.takerAssetAmount,
|
||||
rightOrder.makerAssetAmount,
|
||||
leftTakerAssetFilledAmount
|
||||
// Calculate fill results for maker and taker assets: at least one order will be fully filled.
|
||||
// The maximum amount the left maker can buy is `leftTakerAssetAmountRemaining`
|
||||
// The maximum amount the right maker can sell is `rightMakerAssetAmountRemaining`
|
||||
// We have two distinct cases for calculating the fill results:
|
||||
// Case 1.
|
||||
// If the left maker can buy more than the right maker can sell, then only the right order is fully filled.
|
||||
// If the left maker can buy exactly what the right maker can sell, then both orders are fully filled.
|
||||
// Case 2.
|
||||
// If the left maker cannot buy more than the right maker can sell, then only the left order is fully filled.
|
||||
if (leftTakerAssetAmountRemaining >= rightMakerAssetAmountRemaining) {
|
||||
// Case 1: Right order is fully filled
|
||||
matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining;
|
||||
matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining;
|
||||
matchedFillResults.left.takerAssetFilledAmount = matchedFillResults.right.makerAssetFilledAmount;
|
||||
// Round down to ensure the maker's exchange rate does not exceed the price specified by the order.
|
||||
// We favor the maker when the exchange rate must be rounded.
|
||||
matchedFillResults.left.makerAssetFilledAmount = getPartialAmountFloor(
|
||||
leftOrder.makerAssetAmount,
|
||||
leftOrder.takerAssetAmount,
|
||||
matchedFillResults.left.takerAssetFilledAmount
|
||||
);
|
||||
} else {
|
||||
// Right order will be fully filled: maximally fill right
|
||||
rightTakerAssetFilledAmount = rightTakerAssetAmountRemaining;
|
||||
|
||||
// The left order receives an amount proportional to how much was spent.
|
||||
leftTakerAssetFilledAmount = getPartialAmountFloor(
|
||||
rightOrder.makerAssetAmount,
|
||||
// Case 2: Left order is fully filled
|
||||
matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining;
|
||||
matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining;
|
||||
matchedFillResults.right.makerAssetFilledAmount = matchedFillResults.left.takerAssetFilledAmount;
|
||||
// Round up to ensure the maker's exchange rate does not exceed the price specified by the order.
|
||||
// We favor the maker when the exchange rate must be rounded.
|
||||
matchedFillResults.right.takerAssetFilledAmount = getPartialAmountCeil(
|
||||
rightOrder.takerAssetAmount,
|
||||
rightTakerAssetFilledAmount
|
||||
rightOrder.makerAssetAmount,
|
||||
matchedFillResults.right.makerAssetFilledAmount
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate fill results for left order
|
||||
matchedFillResults.left = calculateFillResults(
|
||||
leftOrder,
|
||||
leftTakerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Calculate fill results for right order
|
||||
matchedFillResults.right = calculateFillResults(
|
||||
rightOrder,
|
||||
rightTakerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Calculate amount given to taker
|
||||
matchedFillResults.leftMakerAssetSpreadAmount = safeSub(
|
||||
matchedFillResults.left.makerAssetFilledAmount,
|
||||
matchedFillResults.right.takerAssetFilledAmount
|
||||
);
|
||||
|
||||
// Compute fees for left order
|
||||
matchedFillResults.left.makerFeePaid = getPartialAmountFloor(
|
||||
matchedFillResults.left.makerAssetFilledAmount,
|
||||
leftOrder.makerAssetAmount,
|
||||
leftOrder.makerFee
|
||||
);
|
||||
matchedFillResults.left.takerFeePaid = getPartialAmountFloor(
|
||||
matchedFillResults.left.takerAssetFilledAmount,
|
||||
leftOrder.takerAssetAmount,
|
||||
leftOrder.takerFee
|
||||
);
|
||||
|
||||
// Compute fees for right order
|
||||
matchedFillResults.right.makerFeePaid = getPartialAmountFloor(
|
||||
matchedFillResults.right.makerAssetFilledAmount,
|
||||
rightOrder.makerAssetAmount,
|
||||
rightOrder.makerFee
|
||||
);
|
||||
matchedFillResults.right.takerFeePaid = getPartialAmountFloor(
|
||||
matchedFillResults.right.takerAssetFilledAmount,
|
||||
rightOrder.takerAssetAmount,
|
||||
rightOrder.takerFee
|
||||
);
|
||||
|
||||
// Return fill results
|
||||
return matchedFillResults;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { assetDataUtils } from '@0xproject/order-utils';
|
||||
import { RevertReason } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { DummyERC20TokenContract } from '../../generated_contract_wrappers/dummy_erc20_token';
|
||||
@@ -14,18 +13,15 @@ import { ExchangeContract } from '../../generated_contract_wrappers/exchange';
|
||||
import { ReentrantERC20TokenContract } from '../../generated_contract_wrappers/reentrant_erc20_token';
|
||||
import { artifacts } from '../utils/artifacts';
|
||||
import { expectTransactionFailedAsync } from '../utils/assertions';
|
||||
import { chaiSetup } from '../utils/chai_setup';
|
||||
import { constants } from '../utils/constants';
|
||||
import { ERC20Wrapper } from '../utils/erc20_wrapper';
|
||||
import { ERC721Wrapper } from '../utils/erc721_wrapper';
|
||||
import { ExchangeWrapper } from '../utils/exchange_wrapper';
|
||||
import { MatchOrderTester } from '../utils/match_order_tester';
|
||||
import { OrderFactory } from '../utils/order_factory';
|
||||
import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, OrderInfo, OrderStatus } from '../utils/types';
|
||||
import { ERC20BalancesByOwner, ERC721TokenIdsByOwner } from '../utils/types';
|
||||
import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('matchOrders', () => {
|
||||
@@ -177,6 +173,144 @@ describe('matchOrders', () => {
|
||||
erc721TokenIdsByOwner = await erc721Wrapper.getBalancesAsync();
|
||||
});
|
||||
|
||||
it('Should give right maker a better price when correct price is not integral', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2000), 0),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1001), 0),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(3000), 0),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Note:
|
||||
// The maker/taker fee percentage paid on the right order differs because
|
||||
// they received different sale prices. Similarly, the right maker pays a
|
||||
// slightly higher lower than the right taker.
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2000), 0),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1001), 0),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1001), 0),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(301), 0),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10.01), 16), // 10.01%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1699), 0),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber('10.0333333333333333'), 16), // 10.03%
|
||||
};
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
});
|
||||
|
||||
it('Should give left maker a better price when correct price is not integral', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(12), 0),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(97), 0),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Note:
|
||||
// The maker/taker fee percentage paid on the left order differs because
|
||||
// they received different sale prices.
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(11), 0),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.6666666666666666'), 16), // 91.6%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.7525773195876288'), 16), // 91.75%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
});
|
||||
|
||||
it('Should transfer correct amounts when right order fill amount deviates from amount derived by `Exchange.fillOrder`', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 0),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 0),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// TODO: These values will change after implementation of rounding up has been merged
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
// Note:
|
||||
// For order [4,2] valid fill amounts through `Exchange.fillOrder` would be [2, 1] or [4, 2]
|
||||
// In this case we have fill amounts of [3, 1] which is attainable through
|
||||
// `Exchange.matchOrders` but not `Exchange.fillOrder`
|
||||
// Note:
|
||||
// The right maker fee differs from the right taker fee because their exchange rate differs.
|
||||
// The right maker always receives the better exchange and fee price.
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 0),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 16), // 75%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 0),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
});
|
||||
|
||||
const reentrancyTest = (functionNames: string[]) => {
|
||||
_.forEach(functionNames, async (functionName: string, functionId: number) => {
|
||||
const description = `should not allow matchOrders to reenter the Exchange contract via ${functionName}`;
|
||||
@@ -217,19 +351,28 @@ describe('matchOrders', () => {
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
});
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Verify left order was fully filled
|
||||
const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight);
|
||||
expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => {
|
||||
@@ -242,32 +385,29 @@ describe('matchOrders', () => {
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
});
|
||||
// Store original taker balance
|
||||
const takerInitialBalances = _.cloneDeep(erc20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress]);
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
let newERC20BalancesByOwner: ERC20BalancesByOwner;
|
||||
let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
|
||||
// prettier-ignore
|
||||
[
|
||||
newERC20BalancesByOwner,
|
||||
// tslint:disable-next-line:trailing-comma
|
||||
newERC721TokenIdsByOwner
|
||||
] = await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
// Verify left order was fully filled
|
||||
const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight);
|
||||
expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
// Verify taker did not take a profit
|
||||
expect(takerInitialBalances).to.be.deep.equal(
|
||||
newERC20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress],
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -281,20 +421,30 @@ describe('matchOrders', () => {
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
|
||||
});
|
||||
// Match orders
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50%
|
||||
};
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Verify left order was fully filled
|
||||
const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
// Verify right order was partially filled
|
||||
const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight);
|
||||
expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FILLABLE);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when right order is completely filled and left order is partially filled', async () => {
|
||||
@@ -307,20 +457,30 @@ describe('matchOrders', () => {
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
});
|
||||
// Match orders
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Verify left order was partially filled
|
||||
const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FILLABLE);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight);
|
||||
expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when consecutive calls are used to completely fill the left order', async () => {
|
||||
@@ -336,24 +496,33 @@ describe('matchOrders', () => {
|
||||
// Match orders
|
||||
let newERC20BalancesByOwner: ERC20BalancesByOwner;
|
||||
let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
// prettier-ignore
|
||||
[
|
||||
newERC20BalancesByOwner,
|
||||
// tslint:disable-next-line:trailing-comma
|
||||
newERC721TokenIdsByOwner
|
||||
] = await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
] = await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Verify left order was partially filled
|
||||
const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FILLABLE);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight);
|
||||
expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
// Construct second right order
|
||||
// Note: This order needs makerAssetAmount=90/takerAssetAmount=[anything <= 45] to fully fill the right order.
|
||||
// However, we use 100/50 to ensure a partial fill as we want to go down the "left fill"
|
||||
@@ -365,21 +534,30 @@ describe('matchOrders', () => {
|
||||
// Match signedOrderLeft with signedOrderRight2
|
||||
const leftTakerAssetFilledAmount = signedOrderRight.makerAssetAmount;
|
||||
const rightTakerAssetFilledAmount = new BigNumber(0);
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
const expectedTransferAmounts2 = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(45), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% (10% paid earlier)
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(45), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% (10% paid earlier)
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90%
|
||||
};
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight2,
|
||||
takerAddress,
|
||||
newERC20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
newERC721TokenIdsByOwner,
|
||||
expectedTransferAmounts2,
|
||||
leftTakerAssetFilledAmount,
|
||||
rightTakerAssetFilledAmount,
|
||||
);
|
||||
// Verify left order was fully filled
|
||||
const leftOrderInfo2: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo2.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
// Verify second right order was partially filled
|
||||
const rightOrderInfo2: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight2);
|
||||
expect(rightOrderInfo2.orderStatus as OrderStatus).to.be.equal(OrderStatus.FILLABLE);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when consecutive calls are used to completely fill the right order', async () => {
|
||||
@@ -396,24 +574,34 @@ describe('matchOrders', () => {
|
||||
// Match orders
|
||||
let newERC20BalancesByOwner: ERC20BalancesByOwner;
|
||||
let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 16), // 4%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(6), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 16), // 4%
|
||||
};
|
||||
// prettier-ignore
|
||||
[
|
||||
newERC20BalancesByOwner,
|
||||
// tslint:disable-next-line:trailing-comma
|
||||
newERC721TokenIdsByOwner
|
||||
] = await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
] = await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Verify left order was partially filled
|
||||
const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight);
|
||||
expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FILLABLE);
|
||||
|
||||
// Create second left order
|
||||
// Note: This order needs makerAssetAmount=96/takerAssetAmount=48 to fully fill the right order.
|
||||
// However, we use 100/50 to ensure a partial fill as we want to go down the "right fill"
|
||||
@@ -428,21 +616,30 @@ describe('matchOrders', () => {
|
||||
erc20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress],
|
||||
);
|
||||
const rightTakerAssetFilledAmount = signedOrderLeft.makerAssetAmount.minus(takerAmountReceived);
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
const expectedTransferAmounts2 = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(48), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(48), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96%
|
||||
};
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft2,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
newERC20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
newERC721TokenIdsByOwner,
|
||||
expectedTransferAmounts2,
|
||||
leftTakerAssetFilledAmount,
|
||||
rightTakerAssetFilledAmount,
|
||||
);
|
||||
// Verify second left order was partially filled
|
||||
const leftOrderInfo2: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft2);
|
||||
expect(leftOrderInfo2.orderStatus as OrderStatus).to.be.equal(OrderStatus.FILLABLE);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo2: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight);
|
||||
expect(rightOrderInfo2.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts if fee recipient is the same across both matched orders', async () => {
|
||||
@@ -458,12 +655,27 @@ describe('matchOrders', () => {
|
||||
feeRecipientAddress,
|
||||
});
|
||||
// Match orders
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -479,12 +691,27 @@ describe('matchOrders', () => {
|
||||
});
|
||||
// Match orders
|
||||
takerAddress = signedOrderLeft.makerAddress;
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -500,12 +727,27 @@ describe('matchOrders', () => {
|
||||
});
|
||||
// Match orders
|
||||
takerAddress = signedOrderRight.makerAddress;
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -521,12 +763,27 @@ describe('matchOrders', () => {
|
||||
});
|
||||
// Match orders
|
||||
takerAddress = feeRecipientAddressLeft;
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -542,12 +799,27 @@ describe('matchOrders', () => {
|
||||
});
|
||||
// Match orders
|
||||
takerAddress = feeRecipientAddressRight;
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -562,12 +834,27 @@ describe('matchOrders', () => {
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
});
|
||||
// Match orders
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -680,19 +967,28 @@ describe('matchOrders', () => {
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
});
|
||||
// Match orders
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 50%
|
||||
};
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Verify left order was fully filled
|
||||
const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight);
|
||||
expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
});
|
||||
|
||||
it('should transfer correct amounts when right order maker asset is an ERC721 token', async () => {
|
||||
@@ -706,22 +1002,31 @@ describe('matchOrders', () => {
|
||||
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||
makerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 18),
|
||||
});
|
||||
// Match orders
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
|
||||
feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Right Maker
|
||||
amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0),
|
||||
amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 18),
|
||||
feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
// Taker
|
||||
amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100%
|
||||
};
|
||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Verify left order was fully filled
|
||||
const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight);
|
||||
expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED);
|
||||
});
|
||||
});
|
||||
}); // tslint:disable-line:max-file-line-count
|
||||
|
||||
@@ -4,11 +4,20 @@ import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { TransactionReceiptWithDecodedLogs } from '../../../../node_modules/ethereum-types';
|
||||
|
||||
import { chaiSetup } from './chai_setup';
|
||||
import { ERC20Wrapper } from './erc20_wrapper';
|
||||
import { ERC721Wrapper } from './erc721_wrapper';
|
||||
import { ExchangeWrapper } from './exchange_wrapper';
|
||||
import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, TransferAmountsByMatchOrders as TransferAmounts } from './types';
|
||||
import {
|
||||
ERC20BalancesByOwner,
|
||||
ERC721TokenIdsByOwner,
|
||||
OrderInfo,
|
||||
OrderStatus,
|
||||
TransferAmountsByMatchOrders as TransferAmounts,
|
||||
TransferAmountsLoggedByMatchOrders as LoggedTransferAmounts,
|
||||
} from './types';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
@@ -18,43 +27,107 @@ export class MatchOrderTester {
|
||||
private readonly _erc20Wrapper: ERC20Wrapper;
|
||||
private readonly _erc721Wrapper: ERC721Wrapper;
|
||||
private readonly _feeTokenAddress: string;
|
||||
|
||||
/// @dev Compares a pair of ERC20 balances and a pair of ERC721 token owners.
|
||||
/// @param expectedNewERC20BalancesByOwner Expected ERC20 balances.
|
||||
/// @param realERC20BalancesByOwner Actual ERC20 balances.
|
||||
/// @param expectedNewERC721TokenIdsByOwner Expected ERC721 token owners.
|
||||
/// @param realERC721TokenIdsByOwner Actual ERC20 token owners.
|
||||
/// @return True only if ERC20 balances match and ERC721 token owners match.
|
||||
private static _compareExpectedAndRealBalances(
|
||||
expectedNewERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
realERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
expectedNewERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
realERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
): boolean {
|
||||
// ERC20 Balances
|
||||
const doesErc20BalancesMatch = _.isEqual(expectedNewERC20BalancesByOwner, realERC20BalancesByOwner);
|
||||
if (!doesErc20BalancesMatch) {
|
||||
return false;
|
||||
}
|
||||
// ERC721 Token Ids
|
||||
const sortedExpectedNewERC721TokenIdsByOwner = _.mapValues(
|
||||
expectedNewERC721TokenIdsByOwner,
|
||||
tokenIdsByOwner => {
|
||||
_.mapValues(tokenIdsByOwner, tokenIds => {
|
||||
_.sortBy(tokenIds);
|
||||
});
|
||||
},
|
||||
/// @dev Checks values from the logs produced by Exchange.matchOrders against the expected transfer amounts.
|
||||
/// Values include the amounts transferred from the left/right makers and taker, along with
|
||||
/// the fees paid on each matched order. These are also the return values of MatchOrders.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param transactionReceipt Transaction receipt and logs produced by Exchange.matchOrders.
|
||||
/// @param takerAddress Address of taker (account that called Exchange.matchOrders)
|
||||
/// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
|
||||
private static async _assertLogsAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
transactionReceipt: TransactionReceiptWithDecodedLogs,
|
||||
takerAddress: string,
|
||||
expectedTransferAmounts: TransferAmounts,
|
||||
): Promise<void> {
|
||||
// Should have two fill event logs -- one for each order.
|
||||
const transactionFillLogs = _.filter(transactionReceipt.logs, ['event', 'Fill']);
|
||||
expect(transactionFillLogs.length, 'Checking number of logs').to.be.equal(2);
|
||||
// First log is for left fill
|
||||
const leftLog = (transactionFillLogs[0] as any).args as LoggedTransferAmounts;
|
||||
expect(leftLog.makerAddress, 'Checking logged maker address of left order').to.be.equal(
|
||||
signedOrderLeft.makerAddress,
|
||||
);
|
||||
expect(leftLog.takerAddress, 'Checking logged taker address of right order').to.be.equal(takerAddress);
|
||||
const amountBoughtByLeftMaker = new BigNumber(leftLog.takerAssetFilledAmount);
|
||||
const amountSoldByLeftMaker = new BigNumber(leftLog.makerAssetFilledAmount);
|
||||
const feePaidByLeftMaker = new BigNumber(leftLog.makerFeePaid);
|
||||
const feePaidByTakerLeft = new BigNumber(leftLog.takerFeePaid);
|
||||
// Second log is for right fill
|
||||
const rightLog = (transactionFillLogs[1] as any).args as LoggedTransferAmounts;
|
||||
expect(rightLog.makerAddress, 'Checking logged maker address of right order').to.be.equal(
|
||||
signedOrderRight.makerAddress,
|
||||
);
|
||||
expect(rightLog.takerAddress, 'Checking loggerd taker address of right order').to.be.equal(takerAddress);
|
||||
const amountBoughtByRightMaker = new BigNumber(rightLog.takerAssetFilledAmount);
|
||||
const amountSoldByRightMaker = new BigNumber(rightLog.makerAssetFilledAmount);
|
||||
const feePaidByRightMaker = new BigNumber(rightLog.makerFeePaid);
|
||||
const feePaidByTakerRight = new BigNumber(rightLog.takerFeePaid);
|
||||
// Derive amount received by taker
|
||||
const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker);
|
||||
// Assert log values - left order
|
||||
expect(amountBoughtByLeftMaker, 'Checking logged amount bought by left maker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountBoughtByLeftMaker,
|
||||
);
|
||||
expect(amountSoldByLeftMaker, 'Checking logged amount sold by left maker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountSoldByLeftMaker,
|
||||
);
|
||||
expect(feePaidByLeftMaker, 'Checking logged fee paid by left maker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.feePaidByLeftMaker,
|
||||
);
|
||||
expect(feePaidByTakerLeft, 'Checking logged fee paid on left order by taker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.feePaidByTakerLeft,
|
||||
);
|
||||
// Assert log values - right order
|
||||
expect(amountBoughtByRightMaker, 'Checking logged amount bought by right maker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountBoughtByRightMaker,
|
||||
);
|
||||
expect(amountSoldByRightMaker, 'Checking logged amount sold by right maker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountSoldByRightMaker,
|
||||
);
|
||||
expect(feePaidByRightMaker, 'Checking logged fee paid by right maker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.feePaidByRightMaker,
|
||||
);
|
||||
expect(feePaidByTakerRight, 'Checking logged fee paid on right order by taker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.feePaidByTakerRight,
|
||||
);
|
||||
// Assert derived amount received by taker
|
||||
expect(amountReceivedByTaker, 'Checking logged amount received by taker').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountReceivedByTaker,
|
||||
);
|
||||
}
|
||||
/// @dev Asserts all expected ERC20 and ERC721 account holdings match the real holdings.
|
||||
/// @param expectedERC20BalancesByOwner Expected ERC20 balances.
|
||||
/// @param realERC20BalancesByOwner Real ERC20 balances.
|
||||
/// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners.
|
||||
/// @param realERC721TokenIdsByOwner Real ERC20 token owners.
|
||||
private static async _assertAllKnownBalancesAsync(
|
||||
expectedERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
realERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
realERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
): Promise<void> {
|
||||
// ERC20 Balances
|
||||
const areERC20BalancesEqual = _.isEqual(expectedERC20BalancesByOwner, realERC20BalancesByOwner);
|
||||
expect(areERC20BalancesEqual, 'Checking all known ERC20 account balances').to.be.true();
|
||||
// ERC721 Token Ids
|
||||
const sortedExpectedNewERC721TokenIdsByOwner = _.mapValues(expectedERC721TokenIdsByOwner, tokenIdsByOwner => {
|
||||
_.mapValues(tokenIdsByOwner, tokenIds => {
|
||||
_.sortBy(tokenIds);
|
||||
});
|
||||
});
|
||||
const sortedNewERC721TokenIdsByOwner = _.mapValues(realERC721TokenIdsByOwner, tokenIdsByOwner => {
|
||||
_.mapValues(tokenIdsByOwner, tokenIds => {
|
||||
_.sortBy(tokenIds);
|
||||
});
|
||||
});
|
||||
const doesErc721TokenIdsMatch = _.isEqual(
|
||||
const areERC721TokenIdsEqual = _.isEqual(
|
||||
sortedExpectedNewERC721TokenIdsByOwner,
|
||||
sortedNewERC721TokenIdsByOwner,
|
||||
);
|
||||
return doesErc721TokenIdsMatch;
|
||||
expect(areERC721TokenIdsEqual, 'Checking all known ERC721 account balances').to.be.true();
|
||||
}
|
||||
/// @dev Constructs new MatchOrderTester.
|
||||
/// @param exchangeWrapper Used to call to the Exchange.
|
||||
@@ -72,150 +145,199 @@ export class MatchOrderTester {
|
||||
this._erc721Wrapper = erc721Wrapper;
|
||||
this._feeTokenAddress = feeTokenAddress;
|
||||
}
|
||||
/// @dev Matches two complementary orders and validates results.
|
||||
/// Validation either succeeds or throws.
|
||||
/// @dev Matches two complementary orders and asserts results.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param takerAddress Address of taker (the address who matched the two orders)
|
||||
/// @param erc20BalancesByOwner Current ERC20 balances.
|
||||
/// @param erc721TokenIdsByOwner Current ERC721 token owners.
|
||||
/// @param initialTakerAssetFilledAmountLeft Current amount the left order has been filled.
|
||||
/// @param initialTakerAssetFilledAmountRight Current amount the right order has been filled.
|
||||
/// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
|
||||
/// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders.
|
||||
/// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders.
|
||||
/// @return New ERC20 balances & ERC721 token owners.
|
||||
public async matchOrdersAndVerifyBalancesAsync(
|
||||
public async matchOrdersAndAssertEffectsAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
takerAddress: string,
|
||||
erc20BalancesByOwner: ERC20BalancesByOwner,
|
||||
erc721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
initialTakerAssetFilledAmountLeft?: BigNumber,
|
||||
initialTakerAssetFilledAmountRight?: BigNumber,
|
||||
expectedTransferAmounts: TransferAmounts,
|
||||
initialLeftOrderFilledAmount: BigNumber = new BigNumber(0),
|
||||
initialRightOrderFilledAmount: BigNumber = new BigNumber(0),
|
||||
): Promise<[ERC20BalancesByOwner, ERC721TokenIdsByOwner]> {
|
||||
// Verify Left order preconditions
|
||||
// Assert initial order states
|
||||
await this._assertInitialOrderStatesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
initialLeftOrderFilledAmount,
|
||||
initialRightOrderFilledAmount,
|
||||
);
|
||||
// Match left & right orders
|
||||
const transactionReceipt = await this._exchangeWrapper.matchOrdersAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
);
|
||||
const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync();
|
||||
const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync();
|
||||
// Assert logs
|
||||
await MatchOrderTester._assertLogsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
transactionReceipt,
|
||||
takerAddress,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Assert exchange state
|
||||
await this._assertExchangeStateAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
initialLeftOrderFilledAmount,
|
||||
initialRightOrderFilledAmount,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Assert balances of makers, taker, and fee recipients
|
||||
await this._assertBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
newERC20BalancesByOwner,
|
||||
newERC721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
takerAddress,
|
||||
);
|
||||
return [newERC20BalancesByOwner, newERC721TokenIdsByOwner];
|
||||
}
|
||||
/// @dev Asserts initial exchange state for the left and right orders.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param expectedOrderFilledAmountLeft How much left order has been filled, prior to matching orders.
|
||||
/// @param expectedOrderFilledAmountRight How much the right order has been filled, prior to matching orders.
|
||||
private async _assertInitialOrderStatesAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
expectedOrderFilledAmountLeft: BigNumber,
|
||||
expectedOrderFilledAmountRight: BigNumber,
|
||||
): Promise<void> {
|
||||
// Assert left order initial state
|
||||
const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderLeft),
|
||||
);
|
||||
const expectedOrderFilledAmountLeft = initialTakerAssetFilledAmountLeft
|
||||
? initialTakerAssetFilledAmountLeft
|
||||
: new BigNumber(0);
|
||||
expect(expectedOrderFilledAmountLeft).to.be.bignumber.equal(orderTakerAssetFilledAmountLeft);
|
||||
// Verify Right order preconditions
|
||||
expect(orderTakerAssetFilledAmountLeft, 'Checking inital state of left order').to.be.bignumber.equal(
|
||||
expectedOrderFilledAmountLeft,
|
||||
);
|
||||
// Assert right order initial state
|
||||
const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderRight),
|
||||
);
|
||||
const expectedOrderFilledAmountRight = initialTakerAssetFilledAmountRight
|
||||
? initialTakerAssetFilledAmountRight
|
||||
: new BigNumber(0);
|
||||
expect(expectedOrderFilledAmountRight).to.be.bignumber.equal(orderTakerAssetFilledAmountRight);
|
||||
// Match left & right orders
|
||||
await this._exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress);
|
||||
const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync();
|
||||
const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync();
|
||||
// Calculate expected balance changes
|
||||
const expectedTransferAmounts = await this._calculateExpectedTransferAmountsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
orderTakerAssetFilledAmountLeft,
|
||||
orderTakerAssetFilledAmountRight,
|
||||
expect(orderTakerAssetFilledAmountRight, 'Checking inital state of right order').to.be.bignumber.equal(
|
||||
expectedOrderFilledAmountRight,
|
||||
);
|
||||
}
|
||||
/// @dev Asserts the exchange state against the expected amounts transferred by from matching orders.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders.
|
||||
/// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders.
|
||||
/// @return TransferAmounts A struct containing the expected transfer amounts.
|
||||
private async _assertExchangeStateAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
initialLeftOrderFilledAmount: BigNumber,
|
||||
initialRightOrderFilledAmount: BigNumber,
|
||||
expectedTransferAmounts: TransferAmounts,
|
||||
): Promise<void> {
|
||||
// Assert state for left order: amount bought by left maker
|
||||
let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderLeft),
|
||||
);
|
||||
amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(initialLeftOrderFilledAmount);
|
||||
expect(amountBoughtByLeftMaker, 'Checking exchange state for left order').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountBoughtByLeftMaker,
|
||||
);
|
||||
// Assert state for right order: amount bought by right maker
|
||||
let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderRight),
|
||||
);
|
||||
amountBoughtByRightMaker = amountBoughtByRightMaker.minus(initialRightOrderFilledAmount);
|
||||
expect(amountBoughtByRightMaker, 'Checking exchange state for right order').to.be.bignumber.equal(
|
||||
expectedTransferAmounts.amountBoughtByRightMaker,
|
||||
);
|
||||
// Assert left order status
|
||||
const maxAmountBoughtByLeftMaker = signedOrderLeft.takerAssetAmount.minus(initialLeftOrderFilledAmount);
|
||||
const leftOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
const leftExpectedStatus = expectedTransferAmounts.amountBoughtByLeftMaker.equals(maxAmountBoughtByLeftMaker)
|
||||
? OrderStatus.FULLY_FILLED
|
||||
: OrderStatus.FILLABLE;
|
||||
expect(leftOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for left order').to.be.equal(
|
||||
leftExpectedStatus,
|
||||
);
|
||||
// Assert right order status
|
||||
const maxAmountBoughtByRightMaker = signedOrderRight.takerAssetAmount.minus(initialRightOrderFilledAmount);
|
||||
const rightOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderRight);
|
||||
const rightExpectedStatus = expectedTransferAmounts.amountBoughtByRightMaker.equals(maxAmountBoughtByRightMaker)
|
||||
? OrderStatus.FULLY_FILLED
|
||||
: OrderStatus.FILLABLE;
|
||||
expect(rightOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for right order').to.be.equal(
|
||||
rightExpectedStatus,
|
||||
);
|
||||
}
|
||||
/// @dev Asserts account balances after matching orders.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param initialERC20BalancesByOwner ERC20 balances prior to order matching.
|
||||
/// @param initialERC721TokenIdsByOwner ERC721 token owners prior to order matching.
|
||||
/// @param finalERC20BalancesByOwner ERC20 balances after order matching.
|
||||
/// @param finalERC721TokenIdsByOwner ERC721 token owners after order matching.
|
||||
/// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
|
||||
/// @param takerAddress Address of taker (account that called Exchange.matchOrders).
|
||||
private async _assertBalancesAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
initialERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
initialERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
finalERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
finalERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
expectedTransferAmounts: TransferAmounts,
|
||||
takerAddress: string,
|
||||
): Promise<void> {
|
||||
let expectedERC20BalancesByOwner: ERC20BalancesByOwner;
|
||||
let expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
|
||||
[expectedERC20BalancesByOwner, expectedERC721TokenIdsByOwner] = this._calculateExpectedBalances(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
initialERC20BalancesByOwner,
|
||||
initialERC721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Assert our expected balances are equal to the actual balances
|
||||
const didExpectedBalancesMatchRealBalances = MatchOrderTester._compareExpectedAndRealBalances(
|
||||
// Assert balances of makers, taker, and fee recipients
|
||||
await this._assertMakerTakerAndFeeRecipientBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
expectedERC20BalancesByOwner,
|
||||
newERC20BalancesByOwner,
|
||||
finalERC20BalancesByOwner,
|
||||
expectedERC721TokenIdsByOwner,
|
||||
newERC721TokenIdsByOwner,
|
||||
finalERC721TokenIdsByOwner,
|
||||
takerAddress,
|
||||
);
|
||||
expect(didExpectedBalancesMatchRealBalances).to.be.true();
|
||||
return [newERC20BalancesByOwner, newERC721TokenIdsByOwner];
|
||||
}
|
||||
/// @dev Calculates expected transfer amounts between order makers, fee recipients, and
|
||||
/// the taker when two orders are matched.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param orderTakerAssetFilledAmountLeft How much left order has been filled, prior to matching orders.
|
||||
/// @param orderTakerAssetFilledAmountRight How much the right order has been filled, prior to matching orders.
|
||||
/// @return TransferAmounts A struct containing the expected transfer amounts.
|
||||
private async _calculateExpectedTransferAmountsAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
orderTakerAssetFilledAmountLeft: BigNumber,
|
||||
orderTakerAssetFilledAmountRight: BigNumber,
|
||||
): Promise<TransferAmounts> {
|
||||
let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderLeft),
|
||||
// Assert balances for all known accounts
|
||||
await MatchOrderTester._assertAllKnownBalancesAsync(
|
||||
expectedERC20BalancesByOwner,
|
||||
finalERC20BalancesByOwner,
|
||||
expectedERC721TokenIdsByOwner,
|
||||
finalERC721TokenIdsByOwner,
|
||||
);
|
||||
amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(orderTakerAssetFilledAmountLeft);
|
||||
const amountSoldByLeftMaker = amountBoughtByLeftMaker
|
||||
.times(signedOrderLeft.makerAssetAmount)
|
||||
.dividedToIntegerBy(signedOrderLeft.takerAssetAmount);
|
||||
const amountReceivedByRightMaker = amountBoughtByLeftMaker
|
||||
.times(signedOrderRight.takerAssetAmount)
|
||||
.dividedToIntegerBy(signedOrderRight.makerAssetAmount);
|
||||
const amountReceivedByTaker = amountSoldByLeftMaker.minus(amountReceivedByRightMaker);
|
||||
let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderRight),
|
||||
);
|
||||
amountBoughtByRightMaker = amountBoughtByRightMaker.minus(orderTakerAssetFilledAmountRight);
|
||||
const amountSoldByRightMaker = amountBoughtByRightMaker
|
||||
.times(signedOrderRight.makerAssetAmount)
|
||||
.dividedToIntegerBy(signedOrderRight.takerAssetAmount);
|
||||
const amountReceivedByLeftMaker = amountSoldByRightMaker;
|
||||
const feePaidByLeftMaker = signedOrderLeft.makerFee
|
||||
.times(amountSoldByLeftMaker)
|
||||
.dividedToIntegerBy(signedOrderLeft.makerAssetAmount);
|
||||
const feePaidByRightMaker = signedOrderRight.makerFee
|
||||
.times(amountSoldByRightMaker)
|
||||
.dividedToIntegerBy(signedOrderRight.makerAssetAmount);
|
||||
const feePaidByTakerLeft = signedOrderLeft.takerFee
|
||||
.times(amountSoldByLeftMaker)
|
||||
.dividedToIntegerBy(signedOrderLeft.makerAssetAmount);
|
||||
const feePaidByTakerRight = signedOrderRight.takerFee
|
||||
.times(amountSoldByRightMaker)
|
||||
.dividedToIntegerBy(signedOrderRight.makerAssetAmount);
|
||||
const totalFeePaidByTaker = feePaidByTakerLeft.add(feePaidByTakerRight);
|
||||
const feeReceivedLeft = feePaidByLeftMaker.add(feePaidByTakerLeft);
|
||||
const feeReceivedRight = feePaidByRightMaker.add(feePaidByTakerRight);
|
||||
// Return values
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountBoughtByLeftMaker,
|
||||
amountSoldByLeftMaker,
|
||||
amountReceivedByLeftMaker,
|
||||
feePaidByLeftMaker,
|
||||
// Right Maker
|
||||
amountBoughtByRightMaker,
|
||||
amountSoldByRightMaker,
|
||||
amountReceivedByRightMaker,
|
||||
feePaidByRightMaker,
|
||||
// Taker
|
||||
amountReceivedByTaker,
|
||||
feePaidByTakerLeft,
|
||||
feePaidByTakerRight,
|
||||
totalFeePaidByTaker,
|
||||
// Fee Recipients
|
||||
feeReceivedLeft,
|
||||
feeReceivedRight,
|
||||
};
|
||||
return expectedTransferAmounts;
|
||||
}
|
||||
/// @dev Calculates the expected balances of order makers, fee recipients, and the taker,
|
||||
/// as a result of matching two orders.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param takerAddress Address of taker (the address who matched the two orders)
|
||||
/// @param erc20BalancesByOwner Current ERC20 balances.
|
||||
/// @param erc721TokenIdsByOwner Current ERC721 token owners.
|
||||
/// @param expectedTransferAmounts A struct containing the expected transfer amounts.
|
||||
/// @param expectedTransferAmounts Expected amounts transferred as a result of order matching.
|
||||
/// @return Expected ERC20 balances & ERC721 token owners after orders have been matched.
|
||||
private _calculateExpectedBalances(
|
||||
signedOrderLeft: SignedOrder,
|
||||
@@ -247,7 +369,7 @@ export class MatchOrderTester {
|
||||
expectedNewERC20BalancesByOwner[makerAddressRight][
|
||||
takerAssetAddressRight
|
||||
] = expectedNewERC20BalancesByOwner[makerAddressRight][takerAssetAddressRight].add(
|
||||
expectedTransferAmounts.amountReceivedByRightMaker,
|
||||
expectedTransferAmounts.amountBoughtByRightMaker,
|
||||
);
|
||||
// Taker
|
||||
expectedNewERC20BalancesByOwner[takerAddress][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
|
||||
@@ -277,7 +399,7 @@ export class MatchOrderTester {
|
||||
// Left Maker
|
||||
expectedNewERC20BalancesByOwner[makerAddressLeft][takerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
|
||||
makerAddressLeft
|
||||
][takerAssetAddressLeft].add(expectedTransferAmounts.amountReceivedByLeftMaker);
|
||||
][takerAssetAddressLeft].add(expectedTransferAmounts.amountBoughtByLeftMaker);
|
||||
// Right Maker
|
||||
expectedNewERC20BalancesByOwner[makerAddressRight][
|
||||
makerAssetAddressRight
|
||||
@@ -307,20 +429,138 @@ export class MatchOrderTester {
|
||||
// Taker Fees
|
||||
expectedNewERC20BalancesByOwner[takerAddress][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[
|
||||
takerAddress
|
||||
][this._feeTokenAddress].minus(expectedTransferAmounts.totalFeePaidByTaker);
|
||||
][this._feeTokenAddress].minus(
|
||||
expectedTransferAmounts.feePaidByTakerLeft.add(expectedTransferAmounts.feePaidByTakerRight),
|
||||
);
|
||||
// Left Fee Recipient Fees
|
||||
expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][
|
||||
this._feeTokenAddress
|
||||
] = expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][this._feeTokenAddress].add(
|
||||
expectedTransferAmounts.feeReceivedLeft,
|
||||
expectedTransferAmounts.feePaidByLeftMaker.add(expectedTransferAmounts.feePaidByTakerLeft),
|
||||
);
|
||||
// Right Fee Recipient Fees
|
||||
expectedNewERC20BalancesByOwner[feeRecipientAddressRight][
|
||||
this._feeTokenAddress
|
||||
] = expectedNewERC20BalancesByOwner[feeRecipientAddressRight][this._feeTokenAddress].add(
|
||||
expectedTransferAmounts.feeReceivedRight,
|
||||
expectedTransferAmounts.feePaidByRightMaker.add(expectedTransferAmounts.feePaidByTakerRight),
|
||||
);
|
||||
|
||||
return [expectedNewERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner];
|
||||
}
|
||||
}
|
||||
/// @dev Asserts ERC20 account balances and ERC721 token holdings that result from order matching.
|
||||
/// Specifically checks balances of makers, taker and fee recipients.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param expectedERC20BalancesByOwner Expected ERC20 balances.
|
||||
/// @param realERC20BalancesByOwner Real ERC20 balances.
|
||||
/// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners.
|
||||
/// @param realERC721TokenIdsByOwner Real ERC20 token owners.
|
||||
/// @param takerAddress Address of taker (account that called Exchange.matchOrders).
|
||||
private async _assertMakerTakerAndFeeRecipientBalancesAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
expectedERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
realERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
realERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
takerAddress: string,
|
||||
): Promise<void> {
|
||||
// Individual balance comparisons
|
||||
const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData);
|
||||
const makerERC20AssetDataLeft =
|
||||
makerAssetProxyIdLeft === AssetProxyId.ERC20
|
||||
? assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData)
|
||||
: assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData);
|
||||
const makerAssetAddressLeft = makerERC20AssetDataLeft.tokenAddress;
|
||||
const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData);
|
||||
const makerERC20AssetDataRight =
|
||||
makerAssetProxyIdRight === AssetProxyId.ERC20
|
||||
? assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData)
|
||||
: assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData);
|
||||
const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress;
|
||||
if (makerAssetProxyIdLeft === AssetProxyId.ERC20) {
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft],
|
||||
'Checking left maker egress ERC20 account balance',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]);
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft],
|
||||
'Checking right maker ingress ERC20 account balance',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]);
|
||||
expect(
|
||||
realERC20BalancesByOwner[takerAddress][makerAssetAddressLeft],
|
||||
'Checking taker ingress ERC20 account balance',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]);
|
||||
} else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) {
|
||||
expect(
|
||||
realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(),
|
||||
'Checking left maker egress ERC721 account holdings',
|
||||
).to.be.deep.equal(
|
||||
expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(),
|
||||
);
|
||||
expect(
|
||||
realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(),
|
||||
'Checking right maker ERC721 account holdings',
|
||||
).to.be.deep.equal(
|
||||
expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(),
|
||||
);
|
||||
expect(
|
||||
realERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort(),
|
||||
'Checking taker ingress ERC721 account holdings',
|
||||
).to.be.deep.equal(expectedERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort());
|
||||
} else {
|
||||
throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`);
|
||||
}
|
||||
if (makerAssetProxyIdRight === AssetProxyId.ERC20) {
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight],
|
||||
'Checking left maker ingress ERC20 account balance',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]);
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight],
|
||||
'Checking right maker egress ERC20 account balance',
|
||||
).to.be.bignumber.equal(
|
||||
expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight],
|
||||
);
|
||||
} else if (makerAssetProxyIdRight === AssetProxyId.ERC721) {
|
||||
expect(
|
||||
realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(),
|
||||
'Checking left maker ingress ERC721 account holdings',
|
||||
).to.be.deep.equal(
|
||||
expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(),
|
||||
);
|
||||
expect(
|
||||
realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight],
|
||||
'Checking right maker agress ERC721 account holdings',
|
||||
).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]);
|
||||
} else {
|
||||
throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`);
|
||||
}
|
||||
// Paid fees
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress],
|
||||
'Checking left maker egress ERC20 account fees',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]);
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress],
|
||||
'Checking right maker egress ERC20 account fees',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]);
|
||||
expect(
|
||||
realERC20BalancesByOwner[takerAddress][this._feeTokenAddress],
|
||||
'Checking taker egress ERC20 account fees',
|
||||
).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][this._feeTokenAddress]);
|
||||
// Received fees
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress],
|
||||
'Checking left fee recipient ingress ERC20 account fees',
|
||||
).to.be.bignumber.equal(
|
||||
expectedERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress],
|
||||
);
|
||||
expect(
|
||||
realERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress],
|
||||
'Checking right fee receipient ingress ERC20 account fees',
|
||||
).to.be.bignumber.equal(
|
||||
expectedERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress],
|
||||
);
|
||||
}
|
||||
} // tslint:disable-line:max-file-line-count
|
||||
|
||||
@@ -117,21 +117,24 @@ export interface TransferAmountsByMatchOrders {
|
||||
// Left Maker
|
||||
amountBoughtByLeftMaker: BigNumber;
|
||||
amountSoldByLeftMaker: BigNumber;
|
||||
amountReceivedByLeftMaker: BigNumber;
|
||||
feePaidByLeftMaker: BigNumber;
|
||||
// Right Maker
|
||||
amountBoughtByRightMaker: BigNumber;
|
||||
amountSoldByRightMaker: BigNumber;
|
||||
amountReceivedByRightMaker: BigNumber;
|
||||
feePaidByRightMaker: BigNumber;
|
||||
// Taker
|
||||
amountReceivedByTaker: BigNumber;
|
||||
feePaidByTakerLeft: BigNumber;
|
||||
feePaidByTakerRight: BigNumber;
|
||||
totalFeePaidByTaker: BigNumber;
|
||||
// Fee Recipients
|
||||
feeReceivedLeft: BigNumber;
|
||||
feeReceivedRight: BigNumber;
|
||||
}
|
||||
|
||||
export interface TransferAmountsLoggedByMatchOrders {
|
||||
makerAddress: string;
|
||||
takerAddress: string;
|
||||
makerAssetFilledAmount: string;
|
||||
takerAssetFilledAmount: string;
|
||||
makerFeePaid: string;
|
||||
takerFeePaid: string;
|
||||
}
|
||||
|
||||
export interface OrderInfo {
|
||||
|
||||
Reference in New Issue
Block a user