@0x:contracts-integrations Added a sanity check for different token types

This commit is contained in:
Alex Towle 2019-11-06 21:29:51 -05:00
parent 4e50b9b479
commit 301b5e1721
3 changed files with 114 additions and 49 deletions

View File

@ -1,3 +1,4 @@
import { ERC1155MintableContract } 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, getRandomInteger, TransactionFactory } from '@0x/contracts-test-utils';
@ -95,6 +96,37 @@ export class Actor {
return tokenIds; return tokenIds;
} }
/**
* Mints some number of ERC1115 fungible tokens and approves a spender (defaults to the ERC1155 asset proxy)
* to transfer the token.
*/
public async configureERC1155TokenAsync(
token: ERC1155MintableContract,
spender?: string,
amount?: BigNumber,
): Promise<BigNumber> {
// Create a fungible token.
const id = await token.create.callAsync('', false, { from: this.address });
await token.create.awaitTransactionSuccessAsync('', false, { from: this.address });
// Mint the token
await token.mintFungible.awaitTransactionSuccessAsync(
id,
[this.address],
[amount || constants.INITIAL_ERC20_BALANCE],
{ from: this.address },
);
// Set approval for all token types for the spender.
await token.setApprovalForAll.awaitTransactionSuccessAsync(
spender || this.deployment.assetProxies.erc1155Proxy.address,
true,
{ from: this.address },
);
return id;
}
/** /**
* Signs a transaction. * Signs a transaction.
*/ */

View File

@ -1,5 +1,5 @@
import { DevUtilsContract } from '@0x/contracts-dev-utils'; import { DevUtilsContract } from '@0x/contracts-dev-utils';
import { BlockchainBalanceStore } from '@0x/contracts-exchange'; import { BlockchainBalanceStore, TokenIds } from '@0x/contracts-exchange';
import { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs'; import { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs';
import { toBaseUnitAmount } from '@0x/contracts-staking'; import { toBaseUnitAmount } from '@0x/contracts-staking';
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils'; import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
@ -17,23 +17,29 @@ const { isRoundingErrorCeil, isRoundingErrorFloor } = LibReferenceFunctions;
const ZERO = constants.ZERO_AMOUNT; const ZERO = constants.ZERO_AMOUNT;
blockchainTests.resets.only('matchOrders', env => { blockchainTests.resets('matchOrders', env => {
// The fee recipient addresses.
let feeRecipientLeft: Actor; let feeRecipientLeft: Actor;
let feeRecipientRight: Actor; let feeRecipientRight: Actor;
// The address that should be responsible for matching orders.
let matcher: Actor; let matcher: Actor;
// Market makers who have opposite maker and taker assets.
let makerLeft: Maker; let makerLeft: Maker;
let makerRight: Maker; let makerRight: Maker;
// The addresses of important assets for testing.
let makerAssetAddressLeft: string; let makerAssetAddressLeft: string;
let makerAssetAddressRight: string; let makerAssetAddressRight: string;
let feeAssetAddress: string; let feeAssetAddress: string;
let deployment: DeploymentManager;
let matchOrderTester: MatchOrderTester; let matchOrderTester: MatchOrderTester;
const devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider, txDefaults); const devUtils = new DevUtilsContract(constants.NULL_ADDRESS, env.provider, env.txDefaults);
let deployment: DeploymentManager; let leftId: BigNumber;
let rightId: BigNumber;
const PROTOCOL_FEE = DeploymentManager.protocolFeeMultiplier.times(constants.DEFAULT_GAS_PRICE); const PROTOCOL_FEE = DeploymentManager.protocolFeeMultiplier.times(constants.DEFAULT_GAS_PRICE);
@ -99,6 +105,13 @@ blockchainTests.resets.only('matchOrders', env => {
feeRecipientRight.configureERC20TokenAsync(deployment.tokens.weth), feeRecipientRight.configureERC20TokenAsync(deployment.tokens.weth),
]); ]);
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( const blockchainBalanceStore = new BlockchainBalanceStore(
{ {
feeRecipientLeft: feeRecipientLeft.address, feeRecipientLeft: feeRecipientLeft.address,
@ -115,8 +128,14 @@ blockchainTests.resets.only('matchOrders', env => {
feeToken: deployment.tokens.erc20[2], feeToken: deployment.tokens.erc20[2],
weth: deployment.tokens.weth, weth: deployment.tokens.weth,
}, },
erc721: {
token: deployment.tokens.erc721[0],
},
erc1155: {
token: deployment.tokens.erc1155[0],
},
}, },
{}, tokenIds,
); );
matchOrderTester = new MatchOrderTester(deployment, blockchainBalanceStore); matchOrderTester = new MatchOrderTester(deployment, blockchainBalanceStore);
@ -2418,39 +2437,6 @@ blockchainTests.resets.only('matchOrders', env => {
}); });
}); });
/* FIXME
const leftMakerAssetAmount = _.includes(fungibleTypes, combo.leftMaker)
? toBaseUnitAmount(15, 18)
: toBaseUnitAmount(1, 0);
const leftTakerAssetAmount = _.includes(fungibleTypes, combo.rightMaker)
? toBaseUnitAmount(30, 18)
: toBaseUnitAmount(1, 0);
const rightMakerAssetAmount = _.includes(fungibleTypes, combo.rightMaker)
? toBaseUnitAmount(30, 18)
: toBaseUnitAmount(1, 0);
const rightTakerAssetAmount = _.includes(fungibleTypes, combo.leftMaker)
? toBaseUnitAmount(14, 18)
: toBaseUnitAmount(1, 0);
const leftMakerFeeAssetAmount = _.includes(fungibleTypes, combo.leftMakerFee)
? toBaseUnitAmount(8, 12)
: toBaseUnitAmount(1, 0);
const rightMakerFeeAssetAmount = _.includes(fungibleTypes, combo.rightMakerFee)
? toBaseUnitAmount(7, 12)
: toBaseUnitAmount(1, 0);
const leftTakerFeeAssetAmount = _.includes(fungibleTypes, combo.leftTakerFee)
? toBaseUnitAmount(6, 12)
: toBaseUnitAmount(1, 0);
const rightTakerFeeAssetAmount = _.includes(fungibleTypes, combo.rightTakerFee)
? toBaseUnitAmount(5, 12)
: toBaseUnitAmount(1, 0);
const leftMakerAssetReceivedByTakerAmount = _.includes(fungibleTypes, combo.leftMaker)
? leftMakerAssetAmount.minus(rightTakerAssetAmount)
: toBaseUnitAmount(0, 0);
const rightMakerAssetReceivedByTakerAmount = _.includes(fungibleTypes, combo.leftMaker)
? rightMakerAssetAmount.minus(leftTakerAssetAmount)
: toBaseUnitAmount(0, 0);
*/
describe('batchMatchOrders and batchMatchOrdersWithMaximalFill rich errors', async () => { describe('batchMatchOrders and batchMatchOrdersWithMaximalFill rich errors', async () => {
it('should fail if there are zero leftOrders with the ZeroLeftOrders rich error reason', async () => { it('should fail if there are zero leftOrders with the ZeroLeftOrders rich error reason', async () => {
const leftOrders: SignedOrder[] = []; const leftOrders: SignedOrder[] = [];
@ -3149,5 +3135,58 @@ blockchainTests.resets.only('matchOrders', env => {
); );
}); });
}); });
describe('token sanity checks', () => {
it('should be able to match ERC721 tokens with ERC1155 tokens', async () => {
const leftMakerAssetData = assetDataUtils.encodeERC1155AssetData(
deployment.tokens.erc1155[0].address,
[leftId],
[new BigNumber(1)],
'0x',
);
const rightMakerAssetData = assetDataUtils.encodeERC721AssetData(
deployment.tokens.erc721[0].address,
rightId,
);
const signedOrderLeft = await makerLeft.signOrderAsync({
makerAssetAmount: toBaseUnitAmount(100, 0),
takerAssetAmount: toBaseUnitAmount(1, 0),
makerAssetData: leftMakerAssetData,
takerAssetData: rightMakerAssetData,
});
const signedOrderRight = await makerRight.signOrderAsync({
makerAssetAmount: toBaseUnitAmount(1, 0),
takerAssetAmount: toBaseUnitAmount(100, 0),
makerAssetData: rightMakerAssetData,
takerAssetData: leftMakerAssetData,
});
const expectedTransferAmounts = {
// Left Maker
leftMakerAssetSoldByLeftMakerAmount: toBaseUnitAmount(100, 0),
leftMakerFeeAssetPaidByLeftMakerAmount: toBaseUnitAmount(100, 16), // 100%
// Right Maker
rightMakerAssetSoldByRightMakerAmount: toBaseUnitAmount(1, 0),
rightMakerFeeAssetPaidByRightMakerAmount: toBaseUnitAmount(100, 16), // 100%
// Taker
leftTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
rightTakerFeeAssetPaidByTakerAmount: toBaseUnitAmount(100, 16), // 100%
leftProtocolFeePaidByTakerAmount: PROTOCOL_FEE,
rightProtocolFeePaidByTakerAmount: PROTOCOL_FEE,
};
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
{
leftOrder: signedOrderLeft,
rightOrder: signedOrderRight,
},
expectedTransferAmounts,
matcher.address,
PROTOCOL_FEE.times(2),
false,
);
});
});
}); });
// tslint:disable-line:max-file-line-count // tslint:disable-line:max-file-line-count

View File

@ -1,6 +1,6 @@
import { DevUtilsContract } from '@0x/contracts-dev-utils'; 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, TransactionHelper } from '@0x/contracts-test-utils';
import { orderHashUtils } from '@0x/order-utils'; import { orderHashUtils } from '@0x/order-utils';
import { BatchMatchedFillResults, FillResults, MatchedFillResults, SignedOrder } from '@0x/types'; import { BatchMatchedFillResults, FillResults, MatchedFillResults, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
@ -244,9 +244,9 @@ export class MatchOrderTester {
orders, orders,
takerAddress, takerAddress,
this._deployment.staking.stakingProxy.address, this._deployment.staking.stakingProxy.address,
this._blockchainBalanceStore,
toFullMatchTransferAmounts(expectedTransferAmounts), toFullMatchTransferAmounts(expectedTransferAmounts),
this._devUtils, this._devUtils,
this._blockchainBalanceStore,
localBalanceStore, localBalanceStore,
); );
const expectedResults = convertToMatchResults(expectedMatchResults); const expectedResults = convertToMatchResults(expectedMatchResults);
@ -377,16 +377,15 @@ async function simulateBatchMatchOrdersAsync(
} }
} }
// FIXME - These arguments should be reordered
// Add the latest match to the batch match results // Add the latest match to the batch match results
batchMatchResults.matches.push( batchMatchResults.matches.push(
await simulateMatchOrdersAsync( await simulateMatchOrdersAsync(
matchedOrders, matchedOrders,
takerAddress, takerAddress,
stakingProxyAddress, stakingProxyAddress,
blockchainBalanceStore,
toFullMatchTransferAmounts(transferAmounts[i]), toFullMatchTransferAmounts(transferAmounts[i]),
devUtils, devUtils,
blockchainBalanceStore,
localBalanceStore, localBalanceStore,
), ),
); );
@ -434,7 +433,6 @@ async function simulateBatchMatchOrdersAsync(
return batchMatchResults; return batchMatchResults;
} }
// FIXME - Is it possible to remove `transferAmounts`
/** /**
* 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.
@ -448,9 +446,9 @@ async function simulateMatchOrdersAsync(
orders: MatchedOrders, orders: MatchedOrders,
takerAddress: string, takerAddress: string,
stakingProxyAddress: string, stakingProxyAddress: string,
blockchainBalanceStore: BlockchainBalanceStore, // FIXME - Is this right?
transferAmounts: MatchTransferAmounts, transferAmounts: MatchTransferAmounts,
devUtils: DevUtilsContract, devUtils: DevUtilsContract,
blockchainBalanceStore: BlockchainBalanceStore,
localBalanceStore: LocalBalanceStore, localBalanceStore: LocalBalanceStore,
): Promise<MatchResults> { ): Promise<MatchResults> {
// prettier-ignore // prettier-ignore
@ -478,7 +476,6 @@ async function simulateMatchOrdersAsync(
orders.rightOrder.makerAssetData, orders.rightOrder.makerAssetData,
); );
// FIXME - Is this a necessary condition?
if (orders.leftOrder.makerAddress !== orders.leftOrder.feeRecipientAddress) { if (orders.leftOrder.makerAddress !== orders.leftOrder.feeRecipientAddress) {
// Left maker fees // Left maker fees
localBalanceStore.transferAsset( localBalanceStore.transferAsset(
@ -489,7 +486,6 @@ async function simulateMatchOrdersAsync(
); );
} }
// FIXME - Is this a necessary condition?
// Left maker asset -> right maker // Left maker asset -> right maker
localBalanceStore.transferAsset( localBalanceStore.transferAsset(
orders.leftOrder.makerAddress, orders.leftOrder.makerAddress,
@ -498,7 +494,6 @@ async function simulateMatchOrdersAsync(
orders.leftOrder.makerAssetData, orders.leftOrder.makerAssetData,
); );
// FIXME - Is this a necessary condition?
if (orders.rightOrder.makerAddress !== orders.rightOrder.feeRecipientAddress) { if (orders.rightOrder.makerAddress !== orders.rightOrder.feeRecipientAddress) {
// Right maker fees // Right maker fees
localBalanceStore.transferAsset( localBalanceStore.transferAsset(
@ -676,7 +671,6 @@ function simulateFillEvents(
]; ];
} }
// FIXME - Refactor this to use filterToLogsArguments
/** /**
* Extract `Fill` events from a transaction receipt. * Extract `Fill` events from a transaction receipt.
*/ */
@ -830,7 +824,6 @@ function getLastMatch(batchMatchResults: BatchMatchResults): MatchResults {
return batchMatchResults.matches[batchMatchResults.matches.length - 1]; return batchMatchResults.matches[batchMatchResults.matches.length - 1];
} }
// FIXME - This can probably be removed in favor of the reference functions.
/** /**
* Add a new fill results object to a total fill results object destructively. * Add a new fill results object to a total fill results object destructively.
* @param total The total fill results that should be updated. * @param total The total fill results that should be updated.
@ -841,6 +834,7 @@ function addFillResults(total: FillEventArgs, fill: FillEventArgs): void {
expect(total.orderHash).to.be.eq(fill.orderHash); expect(total.orderHash).to.be.eq(fill.orderHash);
expect(total.makerAddress).to.be.eq(fill.makerAddress); expect(total.makerAddress).to.be.eq(fill.makerAddress);
expect(total.takerAddress).to.be.eq(fill.takerAddress); expect(total.takerAddress).to.be.eq(fill.takerAddress);
// Add the fill results together // Add the fill results together
total.makerAssetFilledAmount = total.makerAssetFilledAmount.plus(fill.makerAssetFilledAmount); total.makerAssetFilledAmount = total.makerAssetFilledAmount.plus(fill.makerAssetFilledAmount);
total.takerAssetFilledAmount = total.takerAssetFilledAmount.plus(fill.takerAssetFilledAmount); total.takerAssetFilledAmount = total.takerAssetFilledAmount.plus(fill.takerAssetFilledAmount);