Addressed more review feedback and fixed a bug in Actor
This commit is contained in:
parent
4fe57ba025
commit
bb923d2b7d
@ -99,6 +99,10 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
Actor.count = 0;
|
||||||
|
});
|
||||||
|
|
||||||
async function simulateFillsAsync(
|
async function simulateFillsAsync(
|
||||||
orders: SignedOrder[],
|
orders: SignedOrder[],
|
||||||
txReceipt: TransactionReceiptWithDecodedLogs,
|
txReceipt: TransactionReceiptWithDecodedLogs,
|
||||||
|
862
contracts/integrations/test/exchange/batch_match_orders_test.ts
Normal file
862
contracts/integrations/test/exchange/batch_match_orders_test.ts
Normal file
@ -0,0 +1,862 @@
|
|||||||
|
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||||
|
import { ExchangeRevertErrors } from '@0x/contracts-exchange';
|
||||||
|
import { blockchainTests, constants, expect, toBaseUnitAmount } from '@0x/contracts-test-utils';
|
||||||
|
import { Order, SignedOrder } from '@0x/types';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
|
import { Actor } from '../framework/actors/base';
|
||||||
|
import { Maker } from '../framework/actors/maker';
|
||||||
|
import { actorAddressesByName } from '../framework/actors/utils';
|
||||||
|
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
||||||
|
import { TokenIds } from '../framework/balances/types';
|
||||||
|
import { DeploymentManager } from '../framework/deployment_manager';
|
||||||
|
|
||||||
|
import { MatchOrderTester, MatchTransferAmounts } from './match_order_tester';
|
||||||
|
|
||||||
|
blockchainTests.resets('matchOrders integration tests', env => {
|
||||||
|
// The fee recipient addresses.
|
||||||
|
let feeRecipientLeft: Actor;
|
||||||
|
let feeRecipientRight: Actor;
|
||||||
|
|
||||||
|
// The address that should be responsible for matching orders.
|
||||||
|
let matcher: Actor;
|
||||||
|
|
||||||
|
// Market makers who have opposite maker and taker assets.
|
||||||
|
let makerLeft: Maker;
|
||||||
|
let makerRight: Maker;
|
||||||
|
|
||||||
|
// The addresses of important assets for testing.
|
||||||
|
let makerAssetLeft: DummyERC20TokenContract;
|
||||||
|
let makerAssetRight: DummyERC20TokenContract;
|
||||||
|
let feeAsset: DummyERC20TokenContract;
|
||||||
|
|
||||||
|
let makerAssetDataLeft: string;
|
||||||
|
let makerAssetDataRight: string;
|
||||||
|
let feeAssetData: string;
|
||||||
|
|
||||||
|
let deployment: DeploymentManager;
|
||||||
|
let matchOrderTester: MatchOrderTester;
|
||||||
|
let leftId: BigNumber;
|
||||||
|
let rightId: BigNumber;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
deployment = await DeploymentManager.deployAsync(env, {
|
||||||
|
numErc20TokensToDeploy: 3,
|
||||||
|
numErc721TokensToDeploy: 1,
|
||||||
|
numErc1155TokensToDeploy: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
makerAssetLeft = deployment.tokens.erc20[0];
|
||||||
|
makerAssetRight = deployment.tokens.erc20[1];
|
||||||
|
feeAsset = deployment.tokens.erc20[2];
|
||||||
|
|
||||||
|
// Create the fee recipient actors.
|
||||||
|
feeRecipientLeft = new Actor({
|
||||||
|
name: 'left fee recipient',
|
||||||
|
deployment,
|
||||||
|
});
|
||||||
|
feeRecipientRight = new Actor({
|
||||||
|
name: 'right fee recipient',
|
||||||
|
deployment,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Encode the asset data.
|
||||||
|
makerAssetDataLeft = deployment.assetDataEncoder
|
||||||
|
.ERC20Token(makerAssetLeft.address)
|
||||||
|
.getABIEncodedTransactionData();
|
||||||
|
makerAssetDataRight = deployment.assetDataEncoder
|
||||||
|
.ERC20Token(makerAssetRight.address)
|
||||||
|
.getABIEncodedTransactionData();
|
||||||
|
feeAssetData = deployment.assetDataEncoder.ERC20Token(feeAsset.address).getABIEncodedTransactionData();
|
||||||
|
|
||||||
|
// Create two market makers with compatible orders for matching.
|
||||||
|
makerLeft = new Maker({
|
||||||
|
name: 'left maker',
|
||||||
|
deployment,
|
||||||
|
orderConfig: {
|
||||||
|
makerAssetData: makerAssetDataLeft,
|
||||||
|
takerAssetData: makerAssetDataRight,
|
||||||
|
makerFeeAssetData: feeAssetData,
|
||||||
|
takerFeeAssetData: feeAssetData,
|
||||||
|
feeRecipientAddress: feeRecipientLeft.address,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
makerRight = new Maker({
|
||||||
|
name: 'right maker',
|
||||||
|
deployment,
|
||||||
|
orderConfig: {
|
||||||
|
makerAssetData: makerAssetDataRight,
|
||||||
|
takerAssetData: makerAssetDataLeft,
|
||||||
|
makerFeeAssetData: feeAssetData,
|
||||||
|
takerFeeAssetData: feeAssetData,
|
||||||
|
feeRecipientAddress: feeRecipientRight.address,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a matcher.
|
||||||
|
matcher = new Actor({
|
||||||
|
name: 'matcher',
|
||||||
|
deployment,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configure the appropriate actors with initial balances.
|
||||||
|
await Promise.all([
|
||||||
|
...deployment.tokens.erc20.map(async token => makerLeft.configureERC20TokenAsync(token)),
|
||||||
|
...deployment.tokens.erc20.map(async token => makerRight.configureERC20TokenAsync(token)),
|
||||||
|
makerLeft.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address),
|
||||||
|
makerRight.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address),
|
||||||
|
matcher.configureERC20TokenAsync(feeAsset),
|
||||||
|
matcher.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address),
|
||||||
|
feeRecipientLeft.configureERC20TokenAsync(feeAsset),
|
||||||
|
feeRecipientLeft.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address),
|
||||||
|
feeRecipientRight.configureERC20TokenAsync(feeAsset),
|
||||||
|
feeRecipientRight.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address),
|
||||||
|
]);
|
||||||
|
|
||||||
|
leftId = await makerLeft.configureERC1155TokenAsync(deployment.tokens.erc1155[0]);
|
||||||
|
[rightId] = await makerRight.configureERC721TokenAsync(deployment.tokens.erc721[0]);
|
||||||
|
|
||||||
|
const tokenIds: TokenIds = { erc721: {}, erc1155: {} };
|
||||||
|
tokenIds.erc1155[deployment.tokens.erc1155[0].address] = { fungible: [leftId], nonFungible: [] };
|
||||||
|
tokenIds.erc721[deployment.tokens.erc721[0].address] = [rightId];
|
||||||
|
|
||||||
|
const blockchainBalanceStore = new BlockchainBalanceStore(
|
||||||
|
{
|
||||||
|
...actorAddressesByName([feeRecipientLeft, feeRecipientRight, makerLeft, makerRight, matcher]),
|
||||||
|
stakingProxy: deployment.staking.stakingProxy.address,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
erc20: {
|
||||||
|
makerTokenLeft: deployment.tokens.erc20[0],
|
||||||
|
makerTokenRight: deployment.tokens.erc20[1],
|
||||||
|
feeToken: deployment.tokens.erc20[2],
|
||||||
|
weth: deployment.tokens.weth,
|
||||||
|
},
|
||||||
|
erc721: {
|
||||||
|
nft: deployment.tokens.erc721[0],
|
||||||
|
},
|
||||||
|
erc1155: {
|
||||||
|
fungible: deployment.tokens.erc1155[0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tokenIds,
|
||||||
|
);
|
||||||
|
|
||||||
|
matchOrderTester = new MatchOrderTester(deployment, blockchainBalanceStore);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
Actor.count = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('batchMatchOrders and batchMatchOrdersWithMaximalFill rich errors', async () => {
|
||||||
|
it('should fail if there are zero leftOrders with the ZeroLeftOrders rich error reason', async () => {
|
||||||
|
const leftOrders: SignedOrder[] = [];
|
||||||
|
const rightOrders = [
|
||||||
|
await makerRight.signOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
const expectedError = new ExchangeRevertErrors.BatchMatchOrdersError(
|
||||||
|
ExchangeRevertErrors.BatchMatchOrdersErrorCodes.ZeroLeftOrders,
|
||||||
|
);
|
||||||
|
let tx = deployment.exchange
|
||||||
|
.batchMatchOrders(
|
||||||
|
leftOrders,
|
||||||
|
rightOrders,
|
||||||
|
leftOrders.map(order => order.signature),
|
||||||
|
rightOrders.map(order => order.signature),
|
||||||
|
)
|
||||||
|
.awaitTransactionSuccessAsync({ from: matcher.address });
|
||||||
|
await expect(tx).to.revertWith(expectedError);
|
||||||
|
tx = deployment.exchange
|
||||||
|
.batchMatchOrdersWithMaximalFill(
|
||||||
|
leftOrders,
|
||||||
|
rightOrders,
|
||||||
|
leftOrders.map(order => order.signature),
|
||||||
|
rightOrders.map(order => order.signature),
|
||||||
|
)
|
||||||
|
.awaitTransactionSuccessAsync({ from: matcher.address });
|
||||||
|
return expect(tx).to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail if there are zero rightOrders', async () => {
|
||||||
|
const leftOrders = [
|
||||||
|
await makerLeft.signOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
const rightOrders: SignedOrder[] = [];
|
||||||
|
const expectedError = new ExchangeRevertErrors.BatchMatchOrdersError(
|
||||||
|
ExchangeRevertErrors.BatchMatchOrdersErrorCodes.ZeroRightOrders,
|
||||||
|
);
|
||||||
|
let tx = deployment.exchange
|
||||||
|
.batchMatchOrders(
|
||||||
|
leftOrders,
|
||||||
|
rightOrders,
|
||||||
|
leftOrders.map(order => order.signature),
|
||||||
|
rightOrders.map(order => order.signature),
|
||||||
|
)
|
||||||
|
.awaitTransactionSuccessAsync({ from: matcher.address });
|
||||||
|
await expect(tx).to.revertWith(expectedError);
|
||||||
|
tx = deployment.exchange
|
||||||
|
.batchMatchOrdersWithMaximalFill(
|
||||||
|
leftOrders,
|
||||||
|
rightOrders,
|
||||||
|
leftOrders.map(order => order.signature),
|
||||||
|
rightOrders.map(order => order.signature),
|
||||||
|
)
|
||||||
|
.awaitTransactionSuccessAsync({ from: matcher.address });
|
||||||
|
return expect(tx).to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail if there are a different number of left orders and signatures', async () => {
|
||||||
|
const leftOrders = [
|
||||||
|
await makerLeft.signOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(2),
|
||||||
|
takerAssetAmount: new BigNumber(1),
|
||||||
|
}),
|
||||||
|
await makerRight.signOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
const rightOrders = [
|
||||||
|
await makerRight.signOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
}),
|
||||||
|
await makerRight.signOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
const expectedError = new ExchangeRevertErrors.BatchMatchOrdersError(
|
||||||
|
ExchangeRevertErrors.BatchMatchOrdersErrorCodes.InvalidLengthLeftSignatures,
|
||||||
|
);
|
||||||
|
let tx = deployment.exchange
|
||||||
|
.batchMatchOrders(
|
||||||
|
leftOrders,
|
||||||
|
rightOrders,
|
||||||
|
[leftOrders[0].signature],
|
||||||
|
rightOrders.map(order => order.signature),
|
||||||
|
)
|
||||||
|
.awaitTransactionSuccessAsync({ from: matcher.address });
|
||||||
|
await expect(tx).to.revertWith(expectedError);
|
||||||
|
tx = deployment.exchange
|
||||||
|
.batchMatchOrdersWithMaximalFill(
|
||||||
|
leftOrders,
|
||||||
|
rightOrders,
|
||||||
|
[leftOrders[0].signature],
|
||||||
|
rightOrders.map(order => order.signature),
|
||||||
|
)
|
||||||
|
.awaitTransactionSuccessAsync({ from: matcher.address });
|
||||||
|
return expect(tx).to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail if there are a different number of right orders and signatures', async () => {
|
||||||
|
const leftOrders = [
|
||||||
|
await makerLeft.signOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(2),
|
||||||
|
takerAssetAmount: new BigNumber(1),
|
||||||
|
}),
|
||||||
|
await makerLeft.signOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(2),
|
||||||
|
takerAssetAmount: new BigNumber(1),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
const rightOrders = [
|
||||||
|
await makerRight.signOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
}),
|
||||||
|
await makerRight.signOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
const expectedError = new ExchangeRevertErrors.BatchMatchOrdersError(
|
||||||
|
ExchangeRevertErrors.BatchMatchOrdersErrorCodes.InvalidLengthRightSignatures,
|
||||||
|
);
|
||||||
|
let tx = deployment.exchange
|
||||||
|
.batchMatchOrders(leftOrders, rightOrders, leftOrders.map(order => order.signature), [
|
||||||
|
rightOrders[0].signature,
|
||||||
|
])
|
||||||
|
.awaitTransactionSuccessAsync({ from: matcher.address });
|
||||||
|
await expect(tx).to.revertWith(expectedError);
|
||||||
|
tx = deployment.exchange
|
||||||
|
.batchMatchOrdersWithMaximalFill(leftOrders, rightOrders, leftOrders.map(order => order.signature), [
|
||||||
|
rightOrders[0].signature,
|
||||||
|
])
|
||||||
|
.awaitTransactionSuccessAsync({ from: matcher.address });
|
||||||
|
return expect(tx).to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests a batch order matching scenario with both eth and weth protocol fees.
|
||||||
|
*/
|
||||||
|
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,
|
||||||
|
DeploymentManager.protocolFee.times(args.matchIndices.length).times(2),
|
||||||
|
args.matchIndices,
|
||||||
|
args.expectedTransferAmounts.map(transferAmounts => {
|
||||||
|
return {
|
||||||
|
...transferAmounts,
|
||||||
|
leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee,
|
||||||
|
rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee,
|
||||||
|
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: DeploymentManager.protocolFee,
|
||||||
|
rightProtocolFeePaidByTakerInWethAmount: DeploymentManager.protocolFee,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
args.shouldMaximallyFill,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('batchMatchOrders', () => {
|
||||||
|
it('should correctly match two opposite orders', async () => {
|
||||||
|
await testBatchMatchOrdersAsync({
|
||||||
|
leftOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(2),
|
||||||
|
takerAssetAmount: new BigNumber(1),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rightOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
expectedTransferAmounts: [
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
},
|
||||||
|
],
|
||||||
|
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
|
||||||
|
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
|
||||||
|
matchIndices: [[0, 0]],
|
||||||
|
shouldMaximallyFill: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly match a partial fill', async () => {
|
||||||
|
await testBatchMatchOrdersAsync({
|
||||||
|
leftOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(4),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rightOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
expectedTransferAmounts: [
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
},
|
||||||
|
],
|
||||||
|
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
|
||||||
|
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
|
||||||
|
matchIndices: [[0, 0]],
|
||||||
|
shouldMaximallyFill: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly match two left orders to one complementary right order', async () => {
|
||||||
|
await testBatchMatchOrdersAsync({
|
||||||
|
leftOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(2),
|
||||||
|
takerAssetAmount: new BigNumber(1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(2),
|
||||||
|
takerAssetAmount: new BigNumber(1),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rightOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(2),
|
||||||
|
takerAssetAmount: new BigNumber(4),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
expectedTransferAmounts: [
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Right Maker
|
||||||
|
leftMakerAssetBoughtByRightMakerAmount: new BigNumber(2),
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 50%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 50%
|
||||||
|
// Right Maker
|
||||||
|
leftMakerAssetBoughtByRightMakerAmount: new BigNumber(2),
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 50%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
},
|
||||||
|
],
|
||||||
|
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
|
||||||
|
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
|
||||||
|
matchIndices: [[0, 0], [1, 0]],
|
||||||
|
shouldMaximallyFill: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly match one left order to two complementary right orders', async () => {
|
||||||
|
await testBatchMatchOrdersAsync({
|
||||||
|
leftOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(4),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rightOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
expectedTransferAmounts: [
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
},
|
||||||
|
],
|
||||||
|
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
|
||||||
|
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
|
||||||
|
matchIndices: [[0, 0], [0, 1]],
|
||||||
|
shouldMaximallyFill: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly match one left order to two right orders, where the last should not be touched', async () => {
|
||||||
|
await testBatchMatchOrdersAsync({
|
||||||
|
leftOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(2),
|
||||||
|
takerAssetAmount: new BigNumber(1),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rightOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
expectedTransferAmounts: [
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
},
|
||||||
|
],
|
||||||
|
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
|
||||||
|
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
|
||||||
|
matchIndices: [[0, 0]],
|
||||||
|
shouldMaximallyFill: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have three order matchings with only two left orders and two right orders', async () => {
|
||||||
|
await testBatchMatchOrdersAsync({
|
||||||
|
leftOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(4),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(2),
|
||||||
|
takerAssetAmount: new BigNumber(1),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rightOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(2),
|
||||||
|
takerAssetAmount: new BigNumber(4),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
expectedTransferAmounts: [
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(50, 16), // 50%
|
||||||
|
},
|
||||||
|
],
|
||||||
|
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
|
||||||
|
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
|
||||||
|
matchIndices: [[0, 0], [0, 1], [1, 1]],
|
||||||
|
shouldMaximallyFill: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('batchMatchOrdersWithMaximalFill', () => {
|
||||||
|
it('should fully fill the the right order and pay the profit denominated in the left maker asset', async () => {
|
||||||
|
await testBatchMatchOrdersAsync({
|
||||||
|
leftOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(17),
|
||||||
|
takerAssetAmount: new BigNumber(98),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rightOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(75),
|
||||||
|
takerAssetAmount: new BigNumber(13),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
expectedTransferAmounts: [
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(13),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount('76.4705882352941176', 16), // 76.47%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(75),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('76.5306122448979591', 16), // 76.53%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
},
|
||||||
|
],
|
||||||
|
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
|
||||||
|
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
|
||||||
|
matchIndices: [[0, 0]],
|
||||||
|
shouldMaximallyFill: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should transfer correct amounts when left order is fully filled', async () => {
|
||||||
|
await testBatchMatchOrdersAsync({
|
||||||
|
leftOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(15),
|
||||||
|
takerAssetAmount: new BigNumber(90),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rightOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(196),
|
||||||
|
takerAssetAmount: new BigNumber(28),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
expectedTransferAmounts: [
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(15),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
rightMakerAssetBoughtByLeftMakerAmount: new BigNumber(90),
|
||||||
|
// Right Maker
|
||||||
|
leftMakerAssetBoughtByRightMakerAmount: new BigNumber(15),
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(105),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount('53.5714285714285714', 16), // 53.57%
|
||||||
|
// Taker
|
||||||
|
rightMakerAssetReceivedByTakerAmount: new BigNumber(15),
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('53.5714285714285714', 16), // 53.57%
|
||||||
|
},
|
||||||
|
],
|
||||||
|
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
|
||||||
|
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
|
||||||
|
matchIndices: [[0, 0]],
|
||||||
|
shouldMaximallyFill: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly match one left order to two right orders, where the last should not be touched', async () => {
|
||||||
|
await testBatchMatchOrdersAsync({
|
||||||
|
leftOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(2),
|
||||||
|
takerAssetAmount: new BigNumber(1),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rightOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(2),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
expectedTransferAmounts: [
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
},
|
||||||
|
],
|
||||||
|
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
|
||||||
|
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
|
||||||
|
matchIndices: [[0, 0]],
|
||||||
|
shouldMaximallyFill: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly fill all four orders in three matches', async () => {
|
||||||
|
await testBatchMatchOrdersAsync({
|
||||||
|
leftOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(2),
|
||||||
|
takerAssetAmount: new BigNumber(1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(72),
|
||||||
|
takerAssetAmount: new BigNumber(36),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rightOrders: [
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(15),
|
||||||
|
takerAssetAmount: new BigNumber(30),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
makerAssetAmount: new BigNumber(22),
|
||||||
|
takerAssetAmount: new BigNumber(44),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
expectedTransferAmounts: [
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(2),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount('6.6666666666666666', 16), // 6.66%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('6.6666666666666666', 16), // 6.66%
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(28),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount('38.8888888888888888', 16), // 38.88%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(14),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount('93.3333333333333333', 16), // 93.33%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('38.8888888888888888', 16), // 38.88%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('93.3333333333333333', 16), // 93.33%
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(44),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount('61.1111111111111111', 16), // 61.11%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(22),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount('61.1111111111111111', 16), // 61.11%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
},
|
||||||
|
],
|
||||||
|
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
|
||||||
|
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
|
||||||
|
matchIndices: [[0, 0], [1, 0], [1, 1]],
|
||||||
|
shouldMaximallyFill: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('token sanity checks', () => {
|
||||||
|
it('should be able to match ERC721 tokens with ERC1155 tokens', async () => {
|
||||||
|
const leftMakerAssetData = deployment.assetDataEncoder
|
||||||
|
.ERC1155Assets(deployment.tokens.erc1155[0].address, [leftId], [new BigNumber(1)], '0x')
|
||||||
|
.getABIEncodedTransactionData();
|
||||||
|
const rightMakerAssetData = deployment.assetDataEncoder
|
||||||
|
.ERC721Token(deployment.tokens.erc721[0].address, rightId)
|
||||||
|
.getABIEncodedTransactionData();
|
||||||
|
|
||||||
|
const signedOrderLeft = await makerLeft.signOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(4),
|
||||||
|
takerAssetAmount: new BigNumber(1),
|
||||||
|
makerAssetData: leftMakerAssetData,
|
||||||
|
takerAssetData: rightMakerAssetData,
|
||||||
|
});
|
||||||
|
const signedOrderRight = await makerRight.signOrderAsync({
|
||||||
|
makerAssetAmount: new BigNumber(1),
|
||||||
|
takerAssetAmount: new BigNumber(4),
|
||||||
|
makerAssetData: rightMakerAssetData,
|
||||||
|
takerAssetData: leftMakerAssetData,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expectedTransferAmounts = {
|
||||||
|
// Left Maker
|
||||||
|
leftMakerAssetSoldByLeftMakerAmount: new BigNumber(4),
|
||||||
|
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Right Maker
|
||||||
|
rightMakerAssetSoldByRightMakerAmount: new BigNumber(1),
|
||||||
|
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
// Taker
|
||||||
|
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
|
||||||
|
leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee,
|
||||||
|
rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee,
|
||||||
|
};
|
||||||
|
|
||||||
|
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||||
|
{
|
||||||
|
leftOrder: signedOrderLeft,
|
||||||
|
rightOrder: signedOrderRight,
|
||||||
|
},
|
||||||
|
expectedTransferAmounts,
|
||||||
|
matcher.address,
|
||||||
|
DeploymentManager.protocolFee.times(2),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// tslint:disable-line:max-file-line-count
|
@ -123,6 +123,10 @@ blockchainTests.resets('Exchange wrappers', env => {
|
|||||||
localBalances = LocalBalanceStore.create(deployment.devUtils, initialLocalBalances);
|
localBalances = LocalBalanceStore.create(deployment.devUtils, initialLocalBalances);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
Actor.count = 0;
|
||||||
|
});
|
||||||
|
|
||||||
interface SignedOrderWithValidity {
|
interface SignedOrderWithValidity {
|
||||||
signedOrder: SignedOrder;
|
signedOrder: SignedOrder;
|
||||||
isValid: boolean;
|
isValid: boolean;
|
||||||
|
@ -21,6 +21,7 @@ import { SignedOrder } from '@0x/types';
|
|||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
|
|
||||||
|
import { Actor } from '../framework/actors/base';
|
||||||
import { FeeRecipient } from '../framework/actors/fee_recipient';
|
import { FeeRecipient } from '../framework/actors/fee_recipient';
|
||||||
import { OperatorStakerMaker, StakerKeeper } from '../framework/actors/hybrids';
|
import { OperatorStakerMaker, StakerKeeper } from '../framework/actors/hybrids';
|
||||||
import { Maker } from '../framework/actors/maker';
|
import { Maker } from '../framework/actors/maker';
|
||||||
@ -107,6 +108,10 @@ blockchainTests.resets('fillOrder integration tests', env => {
|
|||||||
await balanceStore.updateBalancesAsync();
|
await balanceStore.updateBalancesAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
Actor.count = 0;
|
||||||
|
});
|
||||||
|
|
||||||
async function simulateFillAsync(
|
async function simulateFillAsync(
|
||||||
order: SignedOrder,
|
order: SignedOrder,
|
||||||
txReceipt: TransactionReceiptWithDecodedLogs,
|
txReceipt: TransactionReceiptWithDecodedLogs,
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import { BlockchainBalanceStore, LocalBalanceStore } from '@0x/contracts-exchange';
|
import { BlockchainTestsEnvironment, constants, expect, orderHashUtils, OrderStatus } from '@0x/contracts-test-utils';
|
||||||
import { constants, expect, orderHashUtils, OrderStatus } from '@0x/contracts-test-utils';
|
import { BatchMatchedFillResults, FillResults, MatchedFillResults, Order, SignedOrder } from '@0x/types';
|
||||||
import { BatchMatchedFillResults, FillResults, MatchedFillResults, SignedOrder } from '@0x/types';
|
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { DeploymentManager } from '../deployment_manager';
|
import { Maker } from '../framework/actors/maker';
|
||||||
|
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
||||||
|
import { LocalBalanceStore } from '../framework/balances/local_balance_store';
|
||||||
|
import { DeploymentManager } from '../framework/deployment_manager';
|
||||||
|
|
||||||
export interface FillEventArgs {
|
export interface FillEventArgs {
|
||||||
orderHash: string;
|
orderHash: string;
|
||||||
@ -66,6 +68,64 @@ export interface MatchedOrders {
|
|||||||
rightOrderTakerAssetFilledAmount?: BigNumber;
|
rightOrderTakerAssetFilledAmount?: BigNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TestMatchOrdersArgs {
|
||||||
|
env: BlockchainTestsEnvironment;
|
||||||
|
matchOrderTester: MatchOrderTester;
|
||||||
|
leftOrder: Partial<Order>;
|
||||||
|
rightOrder: Partial<Order>;
|
||||||
|
makerLeft: Maker;
|
||||||
|
makerRight: Maker;
|
||||||
|
expectedTransferAmounts: Partial<MatchTransferAmounts>;
|
||||||
|
withMaximalFill: boolean;
|
||||||
|
matcherAddress: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests an order matching scenario with both eth and weth protocol fees.
|
||||||
|
*/
|
||||||
|
export async function testMatchOrdersAsync(args: TestMatchOrdersArgs): Promise<void> {
|
||||||
|
// Create orders to match.
|
||||||
|
const signedOrderLeft = await args.makerLeft.signOrderAsync(args.leftOrder);
|
||||||
|
const signedOrderRight = await args.makerRight.signOrderAsync(args.rightOrder);
|
||||||
|
|
||||||
|
await args.matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||||
|
{
|
||||||
|
leftOrder: signedOrderLeft,
|
||||||
|
rightOrder: signedOrderRight,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...args.expectedTransferAmounts,
|
||||||
|
leftProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee,
|
||||||
|
rightProtocolFeePaidByTakerInEthAmount: DeploymentManager.protocolFee,
|
||||||
|
leftProtocolFeePaidByTakerInWethAmount: constants.ZERO_AMOUNT,
|
||||||
|
rightProtocolFeePaidByTakerInWethAmount: constants.ZERO_AMOUNT,
|
||||||
|
},
|
||||||
|
args.matcherAddress,
|
||||||
|
DeploymentManager.protocolFee.times(2),
|
||||||
|
args.withMaximalFill,
|
||||||
|
);
|
||||||
|
|
||||||
|
await args.env.blockchainLifecycle.revertAsync();
|
||||||
|
await args.env.blockchainLifecycle.startAsync();
|
||||||
|
|
||||||
|
await args.matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||||
|
{
|
||||||
|
leftOrder: signedOrderLeft,
|
||||||
|
rightOrder: signedOrderRight,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...args.expectedTransferAmounts,
|
||||||
|
leftProtocolFeePaidByTakerInEthAmount: constants.ZERO_AMOUNT,
|
||||||
|
rightProtocolFeePaidByTakerInEthAmount: constants.ZERO_AMOUNT,
|
||||||
|
leftProtocolFeePaidByTakerInWethAmount: DeploymentManager.protocolFee,
|
||||||
|
rightProtocolFeePaidByTakerInWethAmount: DeploymentManager.protocolFee,
|
||||||
|
},
|
||||||
|
args.matcherAddress,
|
||||||
|
constants.ZERO_AMOUNT,
|
||||||
|
args.withMaximalFill,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export class MatchOrderTester {
|
export class MatchOrderTester {
|
||||||
/**
|
/**
|
||||||
* Constructs new MatchOrderTester.
|
* Constructs new MatchOrderTester.
|
File diff suppressed because it is too large
Load Diff
1090
contracts/integrations/test/exchange/match_orders_test.ts
Normal file
1090
contracts/integrations/test/exchange/match_orders_test.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,7 @@ import {
|
|||||||
} from '@0x/contracts-test-utils';
|
} from '@0x/contracts-test-utils';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
|
import { Actor } from '../framework/actors/base';
|
||||||
import { FeeRecipient } from '../framework/actors/fee_recipient';
|
import { FeeRecipient } from '../framework/actors/fee_recipient';
|
||||||
import { Maker } from '../framework/actors/maker';
|
import { Maker } from '../framework/actors/maker';
|
||||||
import { Taker } from '../framework/actors/taker';
|
import { Taker } from '../framework/actors/taker';
|
||||||
@ -117,6 +118,10 @@ blockchainTests('Forwarder integration tests', env => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
Actor.count = 0;
|
||||||
|
});
|
||||||
|
|
||||||
blockchainTests.resets('constructor', () => {
|
blockchainTests.resets('constructor', () => {
|
||||||
it('should revert if assetProxy is unregistered', async () => {
|
it('should revert if assetProxy is unregistered', async () => {
|
||||||
const chainId = await env.getChainIdAsync();
|
const chainId = await env.getChainIdAsync();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ERC1155MintableContract } from '@0x/contracts-erc1155';
|
import { ERC1155MintableContract, ERC1155TransferSingleEventArgs } from '@0x/contracts-erc1155';
|
||||||
import { DummyERC20TokenContract, WETH9Contract } from '@0x/contracts-erc20';
|
import { DummyERC20TokenContract, WETH9Contract } from '@0x/contracts-erc20';
|
||||||
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
||||||
import { constants, getRandomInteger, TransactionFactory } from '@0x/contracts-test-utils';
|
import { constants, filterLogsToArguments, getRandomInteger, TransactionFactory } from '@0x/contracts-test-utils';
|
||||||
import { SignatureType, SignedZeroExTransaction, ZeroExTransaction } from '@0x/types';
|
import { SignatureType, SignedZeroExTransaction, ZeroExTransaction } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
@ -33,6 +33,12 @@ export class Actor {
|
|||||||
|
|
||||||
constructor(config: ActorConfig) {
|
constructor(config: ActorConfig) {
|
||||||
Actor.count++;
|
Actor.count++;
|
||||||
|
|
||||||
|
// Emit an error if the actor count is too high.
|
||||||
|
if (Actor.count >= config.deployment.accounts.length) {
|
||||||
|
throw new Error('Actor count too large');
|
||||||
|
}
|
||||||
|
|
||||||
this.address = config.deployment.accounts[Actor.count];
|
this.address = config.deployment.accounts[Actor.count];
|
||||||
this.name = config.name || this.address;
|
this.name = config.name || this.address;
|
||||||
this.deployment = config.deployment;
|
this.deployment = config.deployment;
|
||||||
@ -106,8 +112,15 @@ export class Actor {
|
|||||||
amount?: BigNumber,
|
amount?: BigNumber,
|
||||||
): Promise<BigNumber> {
|
): Promise<BigNumber> {
|
||||||
// Create a fungible token.
|
// Create a fungible token.
|
||||||
const id = await token.create('', false).callAsync({ from: this.address });
|
const receipt = await token.create('', false).awaitTransactionSuccessAsync({ from: this.address });
|
||||||
await token.create('', false).awaitTransactionSuccessAsync({ from: this.address });
|
const logs = filterLogsToArguments<ERC1155TransferSingleEventArgs>(receipt.logs, 'TransferSingle');
|
||||||
|
|
||||||
|
// Throw if the wrong number of logs were received.
|
||||||
|
if (logs.length !== 1) {
|
||||||
|
throw new Error('Invalid number of `TransferSingle` logs');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = logs[0];
|
||||||
|
|
||||||
// Mint the token
|
// Mint the token
|
||||||
await token
|
await token
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { blockchainTests } from '@0x/contracts-test-utils';
|
import { blockchainTests } from '@0x/contracts-test-utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { Actor } from '../framework/actors/base';
|
||||||
import { PoolOperator } from '../framework/actors/pool_operator';
|
import { PoolOperator } from '../framework/actors/pool_operator';
|
||||||
import { AssertionResult } from '../framework/assertions/function_assertion';
|
import { AssertionResult } from '../framework/assertions/function_assertion';
|
||||||
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
||||||
@ -28,6 +29,10 @@ export class PoolManagementSimulation extends Simulation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
blockchainTests.skip('Pool management fuzz test', env => {
|
blockchainTests.skip('Pool management fuzz test', env => {
|
||||||
|
after(async () => {
|
||||||
|
Actor.count = 0;
|
||||||
|
});
|
||||||
|
|
||||||
it('fuzz', async () => {
|
it('fuzz', async () => {
|
||||||
const deployment = await DeploymentManager.deployAsync(env, {
|
const deployment = await DeploymentManager.deployAsync(env, {
|
||||||
numErc20TokensToDeploy: 0,
|
numErc20TokensToDeploy: 0,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { blockchainTests } from '@0x/contracts-test-utils';
|
import { blockchainTests } from '@0x/contracts-test-utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { Actor } from '../framework/actors/base';
|
||||||
import { Staker } from '../framework/actors/staker';
|
import { Staker } from '../framework/actors/staker';
|
||||||
import { AssertionResult } from '../framework/assertions/function_assertion';
|
import { AssertionResult } from '../framework/assertions/function_assertion';
|
||||||
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
||||||
@ -32,6 +33,10 @@ export class StakeManagementSimulation extends Simulation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
blockchainTests.skip('Stake management fuzz test', env => {
|
blockchainTests.skip('Stake management fuzz test', env => {
|
||||||
|
after(async () => {
|
||||||
|
Actor.count = 0;
|
||||||
|
});
|
||||||
|
|
||||||
it('fuzz', async () => {
|
it('fuzz', async () => {
|
||||||
const deployment = await DeploymentManager.deployAsync(env, {
|
const deployment = await DeploymentManager.deployAsync(env, {
|
||||||
numErc20TokensToDeploy: 0,
|
numErc20TokensToDeploy: 0,
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user