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