@0x:contracts-integrations Added tests with protocol fees for batch order matching

This commit is contained in:
Alex Towle 2019-11-09 16:31:53 -05:00
parent b976101dca
commit b7d92c3c12
2 changed files with 537 additions and 540 deletions

View File

@ -14,7 +14,7 @@ import { MatchOrderTester, MatchTransferAmounts } from '../utils/match_order_tes
const { isRoundingErrorCeil, isRoundingErrorFloor } = LibReferenceFunctions; const { isRoundingErrorCeil, isRoundingErrorFloor } = LibReferenceFunctions;
blockchainTests.resets('matchOrders', env => { blockchainTests.resets.only('matchOrders', env => {
// The fee recipient addresses. // The fee recipient addresses.
let feeRecipientLeft: Actor; let feeRecipientLeft: Actor;
let feeRecipientRight: Actor; let feeRecipientRight: Actor;
@ -50,6 +50,7 @@ blockchainTests.resets('matchOrders', env => {
numErc721TokensToDeploy: 1, numErc721TokensToDeploy: 1,
numErc1155TokensToDeploy: 1, numErc1155TokensToDeploy: 1,
}); });
makerAssetAddressLeft = deployment.tokens.erc20[0].address; makerAssetAddressLeft = deployment.tokens.erc20[0].address;
makerAssetAddressRight = deployment.tokens.erc20[1].address; makerAssetAddressRight = deployment.tokens.erc20[1].address;
feeAssetAddress = deployment.tokens.erc20[2].address; feeAssetAddress = deployment.tokens.erc20[2].address;
@ -180,6 +181,26 @@ blockchainTests.resets('matchOrders', env => {
await env.blockchainLifecycle.revertAsync(); await env.blockchainLifecycle.revertAsync();
await env.blockchainLifecycle.startAsync(); await env.blockchainLifecycle.startAsync();
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
{
leftOrder: signedOrderLeft,
rightOrder: signedOrderRight,
},
{
...expectedTransferAmounts,
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: constants.ZERO_AMOUNT,
leftProtocolFeePaidByTakerInWethAmount: constants.ZERO_AMOUNT,
rightProtocolFeePaidByTakerInWethAmount: PROTOCOL_FEE,
},
matcherAddress || matcher.address,
PROTOCOL_FEE,
withMaximalFill,
);
await env.blockchainLifecycle.revertAsync();
await env.blockchainLifecycle.startAsync();
await matchOrderTester.matchOrdersAndAssertEffectsAsync( await matchOrderTester.matchOrdersAndAssertEffectsAsync(
{ {
leftOrder: signedOrderLeft, leftOrder: signedOrderLeft,
@ -199,7 +220,7 @@ blockchainTests.resets('matchOrders', env => {
} }
describe('matchOrders', () => { describe('matchOrders', () => {
it('Should transfer correct amounts when right order is fully filled and values pass isRoundingErrorFloor but fail isRoundingErrorCeil', async () => { it('should transfer correct amounts when right order is fully filled and values pass isRoundingErrorFloor but fail isRoundingErrorCeil', async () => {
// Create orders to match // Create orders to match
const signedOrderLeft = await makerLeft.signOrderAsync({ const signedOrderLeft = await makerLeft.signOrderAsync({
makerAssetAmount: toBaseUnitAmount(17, 0), makerAssetAmount: toBaseUnitAmount(17, 0),
@ -253,7 +274,7 @@ blockchainTests.resets('matchOrders', env => {
); );
}); });
it('Should transfer correct amounts when left order is fully filled and values pass isRoundingErrorCeil but fail isRoundingErrorFloor', async () => { it('should transfer correct amounts when left order is fully filled and values pass isRoundingErrorCeil but fail isRoundingErrorFloor', async () => {
// Create orders to match // Create orders to match
const signedOrderLeft = await makerLeft.signOrderAsync({ const signedOrderLeft = await makerLeft.signOrderAsync({
makerAssetAmount: toBaseUnitAmount(15, 0), makerAssetAmount: toBaseUnitAmount(15, 0),
@ -1194,7 +1215,7 @@ blockchainTests.resets('matchOrders', env => {
); );
}); });
it('Should transfer correct amounts when left order is fully filled and values pass isRoundingErrorCeil and isRoundingErrorFloor', async () => { it('should transfer correct amounts when left order is fully filled and values pass isRoundingErrorCeil and isRoundingErrorFloor', async () => {
// Create orders to match // Create orders to match
const signedOrderLeft = await makerLeft.signOrderAsync({ const signedOrderLeft = await makerLeft.signOrderAsync({
makerAssetAmount: toBaseUnitAmount(15, 0), makerAssetAmount: toBaseUnitAmount(15, 0),
@ -1250,7 +1271,7 @@ blockchainTests.resets('matchOrders', env => {
); );
}); });
it('Should transfer correct amounts when left order is fully filled', async () => { it('should transfer correct amounts when left order is fully filled', async () => {
await testMatchOrdersAsync( await testMatchOrdersAsync(
{ {
makerAssetAmount: toBaseUnitAmount(16, 0), makerAssetAmount: toBaseUnitAmount(16, 0),
@ -1310,7 +1331,7 @@ blockchainTests.resets('matchOrders', env => {
); );
}); });
it('Should give left maker a better sell price when rounding', async () => { it('should give left maker a better sell price when rounding', async () => {
await testMatchOrdersAsync( await testMatchOrdersAsync(
{ {
makerAssetAmount: toBaseUnitAmount(12, 0), makerAssetAmount: toBaseUnitAmount(12, 0),
@ -1337,7 +1358,7 @@ blockchainTests.resets('matchOrders', env => {
); );
}); });
it('Should give right maker and right taker a favorable fee price when rounding', async () => { it('should give right maker and right taker a favorable fee price when rounding', async () => {
await testMatchOrdersAsync( await testMatchOrdersAsync(
{ {
makerAssetAmount: toBaseUnitAmount(16, 0), makerAssetAmount: toBaseUnitAmount(16, 0),
@ -1367,7 +1388,7 @@ blockchainTests.resets('matchOrders', env => {
); );
}); });
it('Should give left maker and left taker a favorable fee price when rounding', async () => { it('should give left maker and left taker a favorable fee price when rounding', async () => {
await testMatchOrdersAsync( await testMatchOrdersAsync(
{ {
makerAssetAmount: toBaseUnitAmount(12, 0), makerAssetAmount: toBaseUnitAmount(12, 0),
@ -1396,7 +1417,7 @@ blockchainTests.resets('matchOrders', env => {
); );
}); });
it('Should give left maker a better sell price when rounding', async () => { it('should give left maker a better sell price when rounding', async () => {
await testMatchOrdersAsync( await testMatchOrdersAsync(
{ {
makerAssetAmount: toBaseUnitAmount(12, 0), makerAssetAmount: toBaseUnitAmount(12, 0),
@ -2197,21 +2218,87 @@ blockchainTests.resets('matchOrders', env => {
}); });
}); });
interface TestBatchMatchOrdersArgs {
leftOrders: Array<Partial<Order>>;
rightOrders: Array<Partial<Order>>;
expectedTransferAmounts: Array<Partial<MatchTransferAmounts>>;
leftOrdersTakerAssetFilledAmounts: BigNumber[];
rightOrdersTakerAssetFilledAmounts: BigNumber[];
matchIndices: Array<[number, number]>;
shouldMaximallyFill: boolean;
matcherAddress?: string;
}
async function testBatchMatchOrdersAsync(args: TestBatchMatchOrdersArgs): Promise<void> {
const signedLeftOrders = await Promise.all(args.leftOrders.map(async order => makerLeft.signOrderAsync(order)));
const signedRightOrders = await Promise.all(
args.rightOrders.map(async order => makerRight.signOrderAsync(order)),
);
await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync(
{
leftOrders: signedLeftOrders,
rightOrders: signedRightOrders,
leftOrdersTakerAssetFilledAmounts: args.leftOrdersTakerAssetFilledAmounts,
rightOrdersTakerAssetFilledAmounts: args.rightOrdersTakerAssetFilledAmounts,
},
args.matcherAddress || matcher.address,
PROTOCOL_FEE.times(args.matchIndices.length).times(2),
args.matchIndices,
args.expectedTransferAmounts.map(transferAmounts => {
return {
...transferAmounts,
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
leftProtocolFeePaidByTakerInWethAmount: constants.ZERO_AMOUNT,
rightProtocolFeePaidByTakerInWethAmount: constants.ZERO_AMOUNT,
};
}),
args.shouldMaximallyFill,
);
await env.blockchainLifecycle.revertAsync();
await env.blockchainLifecycle.startAsync();
await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync(
{
leftOrders: signedLeftOrders,
rightOrders: signedRightOrders,
leftOrdersTakerAssetFilledAmounts: args.leftOrdersTakerAssetFilledAmounts,
rightOrdersTakerAssetFilledAmounts: args.rightOrdersTakerAssetFilledAmounts,
},
args.matcherAddress || matcher.address,
constants.ZERO_AMOUNT,
args.matchIndices,
args.expectedTransferAmounts.map(transferAmounts => {
return {
...transferAmounts,
leftProtocolFeePaidByTakerInEthAmount: constants.ZERO_AMOUNT,
rightProtocolFeePaidByTakerInEthAmount: constants.ZERO_AMOUNT,
leftProtocolFeePaidByTakerInWethAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInWethAmount: PROTOCOL_FEE,
};
}),
args.shouldMaximallyFill,
);
}
describe('batchMatchOrders', () => { describe('batchMatchOrders', () => {
it('should correctly match two opposite orders', async () => { it('should correctly match two opposite orders', async () => {
const leftOrders = [ await testBatchMatchOrdersAsync({
await makerLeft.signOrderAsync({ leftOrders: [
{
makerAssetAmount: toBaseUnitAmount(2, 0), makerAssetAmount: toBaseUnitAmount(2, 0),
takerAssetAmount: toBaseUnitAmount(1, 0), takerAssetAmount: toBaseUnitAmount(1, 0),
}), },
]; ],
const rightOrders = [ rightOrders: [
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(1, 0), makerAssetAmount: toBaseUnitAmount(1, 0),
takerAssetAmount: toBaseUnitAmount(2, 0), takerAssetAmount: toBaseUnitAmount(2, 0),
}), },
]; ],
const expectedTransferAmounts = [ expectedTransferAmounts: [
{ {
// Left Maker // Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0), leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0),
@ -2222,38 +2309,30 @@ blockchainTests.resets('matchOrders', env => {
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
]; ],
await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync(
{
leftOrders,
rightOrders,
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
}, matchIndices: [[0, 0]],
matcher.address, shouldMaximallyFill: false,
PROTOCOL_FEE.times(2),
[[0, 0]],
expectedTransferAmounts,
false,
);
}); });
it('Should correctly match a partial fill', async () => { });
const leftOrders = [
await makerLeft.signOrderAsync({ it('should correctly match a partial fill', async () => {
await testBatchMatchOrdersAsync({
leftOrders: [
{
makerAssetAmount: toBaseUnitAmount(4, 0), makerAssetAmount: toBaseUnitAmount(4, 0),
takerAssetAmount: toBaseUnitAmount(2, 0), takerAssetAmount: toBaseUnitAmount(2, 0),
}), },
]; ],
const rightOrders = [ rightOrders: [
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(1, 0), makerAssetAmount: toBaseUnitAmount(1, 0),
takerAssetAmount: toBaseUnitAmount(2, 0), takerAssetAmount: toBaseUnitAmount(2, 0),
}), },
]; ],
const expectedTransferAmounts = [ expectedTransferAmounts: [
{ {
// Left Maker // Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0), leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0),
@ -2264,42 +2343,34 @@ blockchainTests.resets('matchOrders', env => {
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
]; ],
await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync(
{
leftOrders,
rightOrders,
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
}, matchIndices: [[0, 0]],
matcher.address, shouldMaximallyFill: false,
PROTOCOL_FEE.times(2),
[[0, 0]],
expectedTransferAmounts,
false,
);
}); });
});
it('should correctly match two left orders to one complementary right order', async () => { it('should correctly match two left orders to one complementary right order', async () => {
const leftOrders = [ await testBatchMatchOrdersAsync({
await makerLeft.signOrderAsync({ leftOrders: [
{
makerAssetAmount: toBaseUnitAmount(2, 0), makerAssetAmount: toBaseUnitAmount(2, 0),
takerAssetAmount: toBaseUnitAmount(1, 0), takerAssetAmount: toBaseUnitAmount(1, 0),
}), },
await makerLeft.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(2, 0), makerAssetAmount: toBaseUnitAmount(2, 0),
takerAssetAmount: toBaseUnitAmount(1, 0), takerAssetAmount: toBaseUnitAmount(1, 0),
}), },
]; ],
const rightOrders = [ rightOrders: [
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(2, 0), makerAssetAmount: toBaseUnitAmount(2, 0),
takerAssetAmount: toBaseUnitAmount(4, 0), takerAssetAmount: toBaseUnitAmount(4, 0),
}), },
]; ],
const expectedTransferAmounts = [ expectedTransferAmounts: [
{ {
// Left Maker // Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0), leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0),
@ -2311,8 +2382,6 @@ blockchainTests.resets('matchOrders', env => {
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 50% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 50%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
{ {
// Left Maker // Left Maker
@ -2325,42 +2394,34 @@ blockchainTests.resets('matchOrders', env => {
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 50% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 50%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
]; ],
await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync(
{
leftOrders,
rightOrders,
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
}, matchIndices: [[0, 0], [1, 0]],
matcher.address, shouldMaximallyFill: false,
PROTOCOL_FEE.times(4),
[[0, 0], [1, 0]],
expectedTransferAmounts,
false,
);
}); });
});
it('should correctly match one left order to two complementary right orders', async () => { it('should correctly match one left order to two complementary right orders', async () => {
const leftOrders = [ await testBatchMatchOrdersAsync({
await makerLeft.signOrderAsync({ leftOrders: [
{
makerAssetAmount: toBaseUnitAmount(4, 0), makerAssetAmount: toBaseUnitAmount(4, 0),
takerAssetAmount: toBaseUnitAmount(2, 0), takerAssetAmount: toBaseUnitAmount(2, 0),
}), },
]; ],
const rightOrders = [ rightOrders: [
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(1, 0), makerAssetAmount: toBaseUnitAmount(1, 0),
takerAssetAmount: toBaseUnitAmount(2, 0), takerAssetAmount: toBaseUnitAmount(2, 0),
}), },
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(1, 0), makerAssetAmount: toBaseUnitAmount(1, 0),
takerAssetAmount: toBaseUnitAmount(2, 0), takerAssetAmount: toBaseUnitAmount(2, 0),
}), },
]; ],
const expectedTransferAmounts = [ expectedTransferAmounts: [
{ {
// Left Maker // Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0), leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0),
@ -2371,8 +2432,6 @@ blockchainTests.resets('matchOrders', env => {
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
{ {
// Left Maker // Left Maker
@ -2384,42 +2443,34 @@ blockchainTests.resets('matchOrders', env => {
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
]; ],
await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync(
{
leftOrders,
rightOrders,
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
}, matchIndices: [[0, 0], [0, 1]],
matcher.address, shouldMaximallyFill: false,
PROTOCOL_FEE.times(4),
[[0, 0], [0, 1]],
expectedTransferAmounts,
false,
);
}); });
});
it('should correctly match one left order to two right orders, where the last should not be touched', async () => { it('should correctly match one left order to two right orders, where the last should not be touched', async () => {
const leftOrders = [ await testBatchMatchOrdersAsync({
await makerLeft.signOrderAsync({ leftOrders: [
{
makerAssetAmount: toBaseUnitAmount(2, 0), makerAssetAmount: toBaseUnitAmount(2, 0),
takerAssetAmount: toBaseUnitAmount(1, 0), takerAssetAmount: toBaseUnitAmount(1, 0),
}), },
]; ],
const rightOrders = [ rightOrders: [
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(1, 0), makerAssetAmount: toBaseUnitAmount(1, 0),
takerAssetAmount: toBaseUnitAmount(2, 0), takerAssetAmount: toBaseUnitAmount(2, 0),
}), },
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(1, 0), makerAssetAmount: toBaseUnitAmount(1, 0),
takerAssetAmount: toBaseUnitAmount(2, 0), takerAssetAmount: toBaseUnitAmount(2, 0),
}), },
]; ],
const expectedTransferAmounts = [ expectedTransferAmounts: [
{ {
// Left Maker // Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0), leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0),
@ -2430,46 +2481,38 @@ blockchainTests.resets('matchOrders', env => {
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
]; ],
await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync(
{
leftOrders,
rightOrders,
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
}, matchIndices: [[0, 0]],
matcher.address, shouldMaximallyFill: false,
PROTOCOL_FEE.times(2),
[[0, 0]],
expectedTransferAmounts,
false,
);
}); });
});
it('should have three order matchings with only two left orders and two right orders', async () => { it('should have three order matchings with only two left orders and two right orders', async () => {
const leftOrders = [ await testBatchMatchOrdersAsync({
await makerLeft.signOrderAsync({ leftOrders: [
{
makerAssetAmount: toBaseUnitAmount(4, 0), makerAssetAmount: toBaseUnitAmount(4, 0),
takerAssetAmount: toBaseUnitAmount(2, 0), takerAssetAmount: toBaseUnitAmount(2, 0),
}), },
await makerLeft.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(2, 0), makerAssetAmount: toBaseUnitAmount(2, 0),
takerAssetAmount: toBaseUnitAmount(1, 0), takerAssetAmount: toBaseUnitAmount(1, 0),
}), },
]; ],
const rightOrders = [ rightOrders: [
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(1, 0), makerAssetAmount: toBaseUnitAmount(1, 0),
takerAssetAmount: toBaseUnitAmount(2, 0), takerAssetAmount: toBaseUnitAmount(2, 0),
}), },
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(2, 0), makerAssetAmount: toBaseUnitAmount(2, 0),
takerAssetAmount: toBaseUnitAmount(4, 0), takerAssetAmount: toBaseUnitAmount(4, 0),
}), },
]; ],
const expectedTransferAmounts = [ expectedTransferAmounts: [
{ {
// Left Maker // Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0), leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0),
@ -2480,8 +2523,6 @@ blockchainTests.resets('matchOrders', env => {
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
{ {
// Left Maker // Left Maker
@ -2493,8 +2534,6 @@ blockchainTests.resets('matchOrders', env => {
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
{ {
// Left Maker // Left Maker
@ -2506,91 +2545,69 @@ blockchainTests.resets('matchOrders', env => {
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
]; ],
await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync(
{
leftOrders,
rightOrders,
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
}, matchIndices: [[0, 0], [0, 1], [1, 1]],
matcher.address, shouldMaximallyFill: false,
PROTOCOL_FEE.times(6), });
[[0, 0], [0, 1], [1, 1]],
expectedTransferAmounts,
false,
);
}); });
}); });
describe('batchMatchOrdersWithMaximalFill', () => { describe('batchMatchOrdersWithMaximalFill', () => {
it('should fully fill the the right order and pay the profit denominated in the left maker asset', async () => { it('should fully fill the the right order and pay the profit denominated in the left maker asset', async () => {
// Create orders to match await testBatchMatchOrdersAsync({
const leftOrders = [ leftOrders: [
await makerLeft.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(17, 0), makerAssetAmount: toBaseUnitAmount(17, 0),
takerAssetAmount: toBaseUnitAmount(98, 0), takerAssetAmount: toBaseUnitAmount(98, 0),
}), },
]; ],
const rightOrders = [ rightOrders: [
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(75, 0), makerAssetAmount: toBaseUnitAmount(75, 0),
takerAssetAmount: toBaseUnitAmount(13, 0), takerAssetAmount: toBaseUnitAmount(13, 0),
}), },
]; ],
const expectedTransferAmounts = [ expectedTransferAmounts: [
{ {
// Left Maker // Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(13, 0), leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(13, 0),
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(new BigNumber('76.4705882352941176'), 16), // 76.47% leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(
new BigNumber('76.4705882352941176'),
16,
), // 76.47%
// Right Maker // Right Maker
rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(75, 0), rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(75, 0),
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(new BigNumber('76.5306122448979591'), 16), // 76.53% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(new BigNumber('76.5306122448979591'), 16), // 76.53%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
]; ],
await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync(
{
leftOrders,
rightOrders,
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
}, matchIndices: [[0, 0]],
matcher.address, shouldMaximallyFill: true,
PROTOCOL_FEE.times(2),
[[0, 0]],
expectedTransferAmounts,
true,
);
}); });
it('Should transfer correct amounts when left order is fully filled', async () => { });
// Create orders to match
const leftOrders = [ it('should transfer correct amounts when left order is fully filled', async () => {
await makerLeft.signOrderAsync({ await testBatchMatchOrdersAsync({
leftOrders: [
{
makerAssetAmount: toBaseUnitAmount(15, 0), makerAssetAmount: toBaseUnitAmount(15, 0),
takerAssetAmount: toBaseUnitAmount(90, 0), takerAssetAmount: toBaseUnitAmount(90, 0),
}), },
]; ],
const rightOrders = [ rightOrders: [
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(196, 0), makerAssetAmount: toBaseUnitAmount(196, 0),
takerAssetAmount: toBaseUnitAmount(28, 0), takerAssetAmount: toBaseUnitAmount(28, 0),
}), },
]; ],
// Match signedOrderLeft with signedOrderRight expectedTransferAmounts: [
// Note that the right maker received a slightly better purchase price.
// This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
// Because the right maker received a slightly more favorable buy price, the fee
// paid by the right taker is slightly higher than that paid by the right maker.
// Fees can be thought of as a tax paid by the seller, derived from the sale price.
const expectedTransferAmounts = [
{ {
// Left Maker // Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(15, 0), leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(15, 0),
@ -2607,42 +2624,34 @@ blockchainTests.resets('matchOrders', env => {
rightMakerAssetReceivedByTakerAmount: toBaseUnitAmount(15, 0), rightMakerAssetReceivedByTakerAmount: toBaseUnitAmount(15, 0),
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(new BigNumber('53.5714285714285714'), 16), // 53.57% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(new BigNumber('53.5714285714285714'), 16), // 53.57%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
]; ],
await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync(
{
leftOrders,
rightOrders,
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
}, matchIndices: [[0, 0]],
matcher.address, shouldMaximallyFill: true,
PROTOCOL_FEE.times(2),
[[0, 0]],
expectedTransferAmounts,
true,
);
}); });
});
it('should correctly match one left order to two right orders, where the last should not be touched', async () => { it('should correctly match one left order to two right orders, where the last should not be touched', async () => {
const leftOrders = [ await testBatchMatchOrdersAsync({
await makerLeft.signOrderAsync({ leftOrders: [
{
makerAssetAmount: toBaseUnitAmount(2, 0), makerAssetAmount: toBaseUnitAmount(2, 0),
takerAssetAmount: toBaseUnitAmount(1, 0), takerAssetAmount: toBaseUnitAmount(1, 0),
}), },
]; ],
const rightOrders = [ rightOrders: [
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(1, 0), makerAssetAmount: toBaseUnitAmount(1, 0),
takerAssetAmount: toBaseUnitAmount(2, 0), takerAssetAmount: toBaseUnitAmount(2, 0),
}), },
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(1, 0), makerAssetAmount: toBaseUnitAmount(1, 0),
takerAssetAmount: toBaseUnitAmount(2, 0), takerAssetAmount: toBaseUnitAmount(2, 0),
}), },
]; ],
const expectedTransferAmounts = [ expectedTransferAmounts: [
{ {
// Left Maker // Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0), leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0),
@ -2653,63 +2662,59 @@ blockchainTests.resets('matchOrders', env => {
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
]; ],
await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync(
{
leftOrders,
rightOrders,
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
}, matchIndices: [[0, 0]],
matcher.address, shouldMaximallyFill: true,
PROTOCOL_FEE.times(2),
[[0, 0]],
expectedTransferAmounts,
true,
);
}); });
});
it('should correctly fill all four orders in three matches', async () => { it('should correctly fill all four orders in three matches', async () => {
const leftOrders = [ await testBatchMatchOrdersAsync({
await makerLeft.signOrderAsync({ leftOrders: [
{
makerAssetAmount: toBaseUnitAmount(2, 0), makerAssetAmount: toBaseUnitAmount(2, 0),
takerAssetAmount: toBaseUnitAmount(1, 0), takerAssetAmount: toBaseUnitAmount(1, 0),
}), },
await makerLeft.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(72, 0), makerAssetAmount: toBaseUnitAmount(72, 0),
takerAssetAmount: toBaseUnitAmount(36, 0), takerAssetAmount: toBaseUnitAmount(36, 0),
}), },
]; ],
const rightOrders = [ rightOrders: [
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(15, 0), makerAssetAmount: toBaseUnitAmount(15, 0),
takerAssetAmount: toBaseUnitAmount(30, 0), takerAssetAmount: toBaseUnitAmount(30, 0),
}), },
await makerRight.signOrderAsync({ {
makerAssetAmount: toBaseUnitAmount(22, 0), makerAssetAmount: toBaseUnitAmount(22, 0),
takerAssetAmount: toBaseUnitAmount(44, 0), takerAssetAmount: toBaseUnitAmount(44, 0),
}), },
]; ],
const expectedTransferAmounts = [ expectedTransferAmounts: [
{ {
// Left Maker // Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0), leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(2, 0),
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100% leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100%
// Right Maker // Right Maker
rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(1, 0), rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(1, 0),
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(new BigNumber('6.6666666666666666'), 16), // 6.66% rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(
new BigNumber('6.6666666666666666'),
16,
), // 6.66%
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(new BigNumber('6.6666666666666666'), 16), // 6.66% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(new BigNumber('6.6666666666666666'), 16), // 6.66%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
{ {
// Left Maker // Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(28, 0), leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(28, 0),
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(new BigNumber('38.8888888888888888'), 16), // 38.88% leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(
new BigNumber('38.8888888888888888'),
16,
), // 38.88%
// Right Maker // Right Maker
rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(14, 0), rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(14, 0),
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount( rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(
@ -2719,36 +2724,27 @@ blockchainTests.resets('matchOrders', env => {
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(new BigNumber('38.8888888888888888'), 16), // 38.88% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(new BigNumber('38.8888888888888888'), 16), // 38.88%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(new BigNumber('93.3333333333333333'), 16), // 93.33% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(new BigNumber('93.3333333333333333'), 16), // 93.33%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
{ {
// Left Maker // Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(44, 0), leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(44, 0),
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(new BigNumber('61.1111111111111111'), 16), // 61.11% leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(
new BigNumber('61.1111111111111111'),
16,
), // 61.11%
// Right Maker // Right Maker
rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(22, 0), rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(22, 0),
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100% rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
// Taker // Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(new BigNumber('61.1111111111111111'), 16), // 61.11% leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(new BigNumber('61.1111111111111111'), 16), // 61.11%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100% rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
leftProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerInEthAmount: PROTOCOL_FEE,
}, },
]; ],
await matchOrderTester.batchMatchOrdersAndAssertEffectsAsync(
{
leftOrders,
rightOrders,
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
}, matchIndices: [[0, 0], [1, 0], [1, 1]],
matcher.address, shouldMaximallyFill: true,
PROTOCOL_FEE.times(6), });
[[0, 0], [1, 0], [1, 1]],
expectedTransferAmounts,
true,
);
}); });
}); });

View File

@ -149,6 +149,7 @@ export class MatchOrderTester {
expectedTransferAmounts, expectedTransferAmounts,
this._devUtils, this._devUtils,
); );
const expectedResults = convertToBatchMatchResults(expectedBatchMatchResults); const expectedResults = convertToBatchMatchResults(expectedBatchMatchResults);
expect(actualBatchMatchResults).to.be.eql(expectedResults); expect(actualBatchMatchResults).to.be.eql(expectedResults);