add integrations tests
This commit is contained in:
parent
4bc55551c6
commit
295811ed5a
@ -513,7 +513,10 @@ contract MixinExchangeWrapper is
|
||||
{
|
||||
return (
|
||||
takerFee == 0 ||
|
||||
(
|
||||
takerFeeAssetData.length > 3 &&
|
||||
takerFeeAssetData.readBytes4(0) == IAssetData(address(0)).StaticCall.selector
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -234,8 +234,10 @@ blockchainTests.resets('Supported asset type unit tests', env => {
|
||||
.transferAssetToSender(assortedMultiAssetData, TRANSFER_AMOUNT)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
expect(txReceipt.logs.length).to.equal(2);
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
const erc20TransferEvent = (txReceipt.logs[0] as LogWithDecodedArgs<ERC20TokenTransferEventArgs>).args;
|
||||
const erc721TransferEvent = (txReceipt.logs[1] as LogWithDecodedArgs<ERC721TokenTransferEventArgs>).args;
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
expect(erc20TransferEvent).to.deep.equal({
|
||||
_from: forwarder.address,
|
||||
_to: receiver,
|
||||
@ -252,8 +254,10 @@ blockchainTests.resets('Supported asset type unit tests', env => {
|
||||
.transferAssetToSender(assortedMultiAssetData, TRANSFER_AMOUNT)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
expect(txReceipt.logs.length).to.equal(2);
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
const erc20TransferEvent = (txReceipt.logs[0] as LogWithDecodedArgs<ERC20TokenTransferEventArgs>).args;
|
||||
const erc721TransferEvent = (txReceipt.logs[1] as LogWithDecodedArgs<ERC721TokenTransferEventArgs>).args;
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
expect(erc20TransferEvent).to.deep.equal({
|
||||
_from: forwarder.address,
|
||||
_to: receiver,
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { artifacts as assetProxyArtifacts, TestStaticCallTargetContract } from '@0x/contracts-asset-proxy';
|
||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
||||
import { artifacts as exchangeArtifacts, ExchangeContract } from '@0x/contracts-exchange';
|
||||
@ -37,6 +38,8 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
let nftId: BigNumber;
|
||||
let wethAssetData: string;
|
||||
let makerAssetData: string;
|
||||
let staticCallSuccessAssetData: string;
|
||||
let staticCallFailureAssetData: string;
|
||||
|
||||
let maker: Maker;
|
||||
let taker: Taker;
|
||||
@ -51,12 +54,33 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
});
|
||||
forwarder = await deployForwarderAsync(deployment, env);
|
||||
|
||||
const staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(
|
||||
assetProxyArtifacts.TestStaticCallTarget,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
assetProxyArtifacts,
|
||||
);
|
||||
|
||||
[makerToken, makerFeeToken, anotherErc20Token] = deployment.tokens.erc20;
|
||||
[erc721Token] = deployment.tokens.erc721;
|
||||
wethAssetData = deployment.assetDataEncoder
|
||||
.ERC20Token(deployment.tokens.weth.address)
|
||||
.getABIEncodedTransactionData();
|
||||
makerAssetData = deployment.assetDataEncoder.ERC20Token(makerToken.address).getABIEncodedTransactionData();
|
||||
staticCallSuccessAssetData = deployment.assetDataEncoder
|
||||
.StaticCall(
|
||||
staticCallTarget.address,
|
||||
staticCallTarget.assertEvenNumber(new BigNumber(2)).getABIEncodedTransactionData(),
|
||||
constants.KECCAK256_NULL,
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
staticCallFailureAssetData = deployment.assetDataEncoder
|
||||
.StaticCall(
|
||||
staticCallTarget.address,
|
||||
staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData(),
|
||||
constants.KECCAK256_NULL,
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
|
||||
taker = new Taker({ name: 'Taker', deployment });
|
||||
orderFeeRecipient = new FeeRecipient({
|
||||
@ -266,14 +290,14 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
makerAssetAmount: constants.ZERO_AMOUNT,
|
||||
});
|
||||
const fillableOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5);
|
||||
await testFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5, { noopOrders: [0] });
|
||||
});
|
||||
it('should skip over an order with an invalid taker asset amount', async () => {
|
||||
const unfillableOrder = await maker.signOrderAsync({
|
||||
takerAssetAmount: constants.ZERO_AMOUNT,
|
||||
});
|
||||
const fillableOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5);
|
||||
await testFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5, { noopOrders: [0] });
|
||||
});
|
||||
it('should skip over an expired order', async () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
@ -281,19 +305,65 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
|
||||
});
|
||||
const fillableOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketSellTestAsync([expiredOrder, fillableOrder], 1.5);
|
||||
await testFactory.marketSellTestAsync([expiredOrder, fillableOrder], 1.5, { noopOrders: [0] });
|
||||
});
|
||||
it('should skip over a fully filled order', async () => {
|
||||
const fullyFilledOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketSellTestAsync([fullyFilledOrder], 1);
|
||||
const fillableOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketSellTestAsync([fullyFilledOrder, fillableOrder], 1.5);
|
||||
await testFactory.marketSellTestAsync([fullyFilledOrder, fillableOrder], 1.5, { noopOrders: [0] });
|
||||
});
|
||||
it('should skip over a cancelled order', async () => {
|
||||
const cancelledOrder = await maker.signOrderAsync();
|
||||
await maker.cancelOrderAsync(cancelledOrder);
|
||||
const fillableOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketSellTestAsync([cancelledOrder, fillableOrder], 1.5);
|
||||
await testFactory.marketSellTestAsync([cancelledOrder, fillableOrder], 1.5, { noopOrders: [0] });
|
||||
});
|
||||
for (const orderAssetData of ['makerAssetData', 'makerFeeAssetData', 'takerFeeAssetData']) {
|
||||
it(`should fill an order with StaticCall ${orderAssetData} if the StaticCall succeeds`, async () => {
|
||||
const staticCallOrder = await maker.signOrderAsync({
|
||||
[orderAssetData]: staticCallSuccessAssetData,
|
||||
});
|
||||
const nonStaticCallOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketSellTestAsync([staticCallOrder, nonStaticCallOrder], 1.5);
|
||||
});
|
||||
it(`should not fill an order with StaticCall ${orderAssetData} if the StaticCall fails`, async () => {
|
||||
const staticCallOrder = await maker.signOrderAsync({
|
||||
[orderAssetData]: staticCallFailureAssetData,
|
||||
});
|
||||
const nonStaticCallOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketSellTestAsync([staticCallOrder, nonStaticCallOrder], 1.5, { noopOrders: [0] });
|
||||
});
|
||||
}
|
||||
it('should fill an order with multiAsset makerAssetData', async () => {
|
||||
const multiAssetData = deployment.assetDataEncoder
|
||||
.MultiAsset([new BigNumber(2)], [makerAssetData])
|
||||
.getABIEncodedTransactionData();
|
||||
const multiAssetOrder = await maker.signOrderAsync({
|
||||
makerAssetData: multiAssetData,
|
||||
});
|
||||
const nonMultiAssetOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketSellTestAsync([multiAssetOrder, nonMultiAssetOrder], 1.3);
|
||||
});
|
||||
it('should fill an order with multiAsset makerAssetData (nested StaticCall succeeds)', async () => {
|
||||
const multiAssetData = deployment.assetDataEncoder
|
||||
.MultiAsset([new BigNumber(2), new BigNumber(3)], [makerAssetData, staticCallSuccessAssetData])
|
||||
.getABIEncodedTransactionData();
|
||||
const multiAssetOrder = await maker.signOrderAsync({
|
||||
makerAssetData: multiAssetData,
|
||||
});
|
||||
const nonMultiAssetOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketSellTestAsync([multiAssetOrder, nonMultiAssetOrder], 1.3);
|
||||
});
|
||||
it('should skip over an order with multiAsset makerAssetData where the nested StaticCall fails', async () => {
|
||||
const multiAssetData = deployment.assetDataEncoder
|
||||
.MultiAsset([new BigNumber(2), new BigNumber(3)], [makerAssetData, staticCallFailureAssetData])
|
||||
.getABIEncodedTransactionData();
|
||||
const multiAssetOrder = await maker.signOrderAsync({
|
||||
makerAssetData: multiAssetData,
|
||||
});
|
||||
const nonMultiAssetOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketSellTestAsync([multiAssetOrder, nonMultiAssetOrder], 1.3, { noopOrders: [0] });
|
||||
});
|
||||
});
|
||||
blockchainTests.resets('marketSellOrdersWithEth with extra fees', () => {
|
||||
@ -495,14 +565,14 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
makerAssetAmount: constants.ZERO_AMOUNT,
|
||||
});
|
||||
const fillableOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5);
|
||||
await testFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5, { noopOrders: [0] });
|
||||
});
|
||||
it('should skip over an order with an invalid taker asset amount', async () => {
|
||||
const unfillableOrder = await maker.signOrderAsync({
|
||||
takerAssetAmount: constants.ZERO_AMOUNT,
|
||||
});
|
||||
const fillableOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5);
|
||||
await testFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5, { noopOrders: [0] });
|
||||
});
|
||||
it('should skip over an expired order', async () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
@ -510,19 +580,19 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
|
||||
});
|
||||
const fillableOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketBuyTestAsync([expiredOrder, fillableOrder], 1.5);
|
||||
await testFactory.marketBuyTestAsync([expiredOrder, fillableOrder], 1.5, { noopOrders: [0] });
|
||||
});
|
||||
it('should skip over a fully filled order', async () => {
|
||||
const fullyFilledOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketBuyTestAsync([fullyFilledOrder], 1);
|
||||
const fillableOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketBuyTestAsync([fullyFilledOrder, fillableOrder], 1.5);
|
||||
await testFactory.marketBuyTestAsync([fullyFilledOrder, fillableOrder], 1.5, { noopOrders: [0] });
|
||||
});
|
||||
it('should skip over a cancelled order', async () => {
|
||||
const cancelledOrder = await maker.signOrderAsync();
|
||||
await maker.cancelOrderAsync(cancelledOrder);
|
||||
const fillableOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketBuyTestAsync([cancelledOrder, fillableOrder], 1.5);
|
||||
await testFactory.marketBuyTestAsync([cancelledOrder, fillableOrder], 1.5, { noopOrders: [0] });
|
||||
});
|
||||
it('Should buy slightly greater makerAsset when exchange rate is rounded', async () => {
|
||||
// The 0x Protocol contracts round the exchange rate in favor of the Maker.
|
||||
@ -622,6 +692,52 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
});
|
||||
for (const orderAssetData of ['makerAssetData', 'makerFeeAssetData', 'takerFeeAssetData']) {
|
||||
it(`should fill an order with StaticCall ${orderAssetData} if the StaticCall succeeds`, async () => {
|
||||
const staticCallOrder = await maker.signOrderAsync({
|
||||
[orderAssetData]: staticCallSuccessAssetData,
|
||||
});
|
||||
const nonStaticCallOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketBuyTestAsync([staticCallOrder, nonStaticCallOrder], 1.5);
|
||||
});
|
||||
it(`should not fill an order with StaticCall ${orderAssetData} if the StaticCall fails`, async () => {
|
||||
const staticCallOrder = await maker.signOrderAsync({
|
||||
[orderAssetData]: staticCallFailureAssetData,
|
||||
});
|
||||
const nonStaticCallOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketBuyTestAsync([staticCallOrder, nonStaticCallOrder], 1.5, { noopOrders: [0] });
|
||||
});
|
||||
}
|
||||
it('should fill an order with multiAsset makerAssetData', async () => {
|
||||
const multiAssetData = deployment.assetDataEncoder
|
||||
.MultiAsset([new BigNumber(2)], [makerAssetData])
|
||||
.getABIEncodedTransactionData();
|
||||
const multiAssetOrder = await maker.signOrderAsync({
|
||||
makerAssetData: multiAssetData,
|
||||
});
|
||||
const nonMultiAssetOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketBuyTestAsync([multiAssetOrder, nonMultiAssetOrder], 1.3);
|
||||
});
|
||||
it('should fill an order with multiAsset makerAssetData (nested StaticCall succeeds)', async () => {
|
||||
const multiAssetData = deployment.assetDataEncoder
|
||||
.MultiAsset([new BigNumber(2), new BigNumber(3)], [makerAssetData, staticCallSuccessAssetData])
|
||||
.getABIEncodedTransactionData();
|
||||
const multiAssetOrder = await maker.signOrderAsync({
|
||||
makerAssetData: multiAssetData,
|
||||
});
|
||||
const nonMultiAssetOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketBuyTestAsync([multiAssetOrder, nonMultiAssetOrder], 1.3);
|
||||
});
|
||||
it('should skip over an order with multiAsset makerAssetData where the nested StaticCall fails', async () => {
|
||||
const multiAssetData = deployment.assetDataEncoder
|
||||
.MultiAsset([new BigNumber(2), new BigNumber(3)], [makerAssetData, staticCallFailureAssetData])
|
||||
.getABIEncodedTransactionData();
|
||||
const multiAssetOrder = await maker.signOrderAsync({
|
||||
makerAssetData: multiAssetData,
|
||||
});
|
||||
const nonMultiAssetOrder = await maker.signOrderAsync();
|
||||
await testFactory.marketBuyTestAsync([multiAssetOrder, nonMultiAssetOrder], 1.3, { noopOrders: [0] });
|
||||
});
|
||||
});
|
||||
blockchainTests.resets('marketBuyOrdersWithEth with extra fees', () => {
|
||||
it('should buy the asset and send fee to feeRecipient', async () => {
|
||||
|
@ -22,6 +22,7 @@ interface MarketSellOptions {
|
||||
forwarderFeeRecipientAddresses: string[];
|
||||
revertError: RevertError;
|
||||
bridgeExcessBuyAmount: BigNumber;
|
||||
noopOrders: number[]; // Indices of orders expected to noop on _fillOrderNoThrow (e.g. cancelled orders)
|
||||
}
|
||||
|
||||
interface MarketBuyOptions extends MarketSellOptions {
|
||||
@ -71,7 +72,7 @@ export class ForwarderTestFactory {
|
||||
orders.map(order => this._deployment.exchange.getOrderInfo(order).callAsync()),
|
||||
);
|
||||
const expectedOrderStatuses = orderInfoBefore.map((orderInfo, i) =>
|
||||
fractionalNumberOfOrdersToFill >= i + 1 && orderInfo.orderStatus === OrderStatus.Fillable
|
||||
fractionalNumberOfOrdersToFill >= i + 1 && !(options.noopOrders || []).includes(i)
|
||||
? OrderStatus.FullyFilled
|
||||
: orderInfo.orderStatus,
|
||||
);
|
||||
@ -112,7 +113,7 @@ export class ForwarderTestFactory {
|
||||
orders.map(order => this._deployment.exchange.getOrderInfo(order).callAsync()),
|
||||
);
|
||||
const expectedOrderStatuses = orderInfoBefore.map((orderInfo, i) =>
|
||||
fractionalNumberOfOrdersToFill >= i + 1 && orderInfo.orderStatus === OrderStatus.Fillable
|
||||
fractionalNumberOfOrdersToFill >= i + 1 && !(options.noopOrders || []).includes(i)
|
||||
? OrderStatus.FullyFilled
|
||||
: orderInfo.orderStatus,
|
||||
);
|
||||
@ -198,8 +199,8 @@ export class ForwarderTestFactory {
|
||||
for (const [i, order] of orders.entries()) {
|
||||
if (remainingOrdersToFill === 0) {
|
||||
break;
|
||||
} else if (ordersInfoBefore[i].orderStatus !== OrderStatus.Fillable) {
|
||||
// If the order is not fillable, skip over it but still count it towards fractionalNumberOfOrdersToFill
|
||||
} else if ((options.noopOrders || []).includes(i)) {
|
||||
// If the order won't be filled, skip over it but still count it towards fractionalNumberOfOrdersToFill
|
||||
remainingOrdersToFill = Math.max(remainingOrdersToFill - 1, 0);
|
||||
continue;
|
||||
}
|
||||
@ -245,7 +246,10 @@ export class ForwarderTestFactory {
|
||||
const makerFeeFilled = takerAssetFilled.times(order.makerFee).dividedToIntegerBy(order.takerAssetAmount);
|
||||
makerFee = BigNumber.max(makerFee.minus(makerFeeFilled), 0);
|
||||
const takerFeeFilled = takerAssetFilled.times(order.takerFee).dividedToIntegerBy(order.takerAssetAmount);
|
||||
takerFee = BigNumber.max(takerFee.minus(takerFeeFilled), 0);
|
||||
takerFee =
|
||||
hexUtils.slice(order.takerFeeAssetData, 0, 4) === AssetProxyId.StaticCall
|
||||
? constants.ZERO_AMOUNT
|
||||
: BigNumber.max(takerFee.minus(takerFeeFilled), 0);
|
||||
|
||||
makerAssetAmount = makerAssetAmount.plus(bridgeExcessBuyAmount);
|
||||
let wethSpentAmount = takerAssetAmount.plus(DeploymentManager.protocolFee);
|
||||
|
Loading…
x
Reference in New Issue
Block a user