@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 { DummyERC721TokenContract } from '@0x/contracts-erc721';
import { constants, getRandomInteger, TransactionFactory } from '@0x/contracts-test-utils';
@ -95,6 +96,37 @@ export class Actor {
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.
*/

View File

@ -1,5 +1,5 @@
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 { toBaseUnitAmount } from '@0x/contracts-staking';
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
@ -17,23 +17,29 @@ const { isRoundingErrorCeil, isRoundingErrorFloor } = LibReferenceFunctions;
const ZERO = constants.ZERO_AMOUNT;
blockchainTests.resets.only('matchOrders', env => {
blockchainTests.resets('matchOrders', 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 makerAssetAddressLeft: string;
let makerAssetAddressRight: string;
let feeAssetAddress: string;
let deployment: DeploymentManager;
let matchOrderTester: MatchOrderTester;
const devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider, txDefaults);
let deployment: DeploymentManager;
const devUtils = new DevUtilsContract(constants.NULL_ADDRESS, env.provider, env.txDefaults);
let leftId: BigNumber;
let rightId: BigNumber;
const PROTOCOL_FEE = DeploymentManager.protocolFeeMultiplier.times(constants.DEFAULT_GAS_PRICE);
@ -99,6 +105,13 @@ blockchainTests.resets.only('matchOrders', env => {
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(
{
feeRecipientLeft: feeRecipientLeft.address,
@ -115,8 +128,14 @@ blockchainTests.resets.only('matchOrders', env => {
feeToken: deployment.tokens.erc20[2],
weth: deployment.tokens.weth,
},
erc721: {
token: deployment.tokens.erc721[0],
},
erc1155: {
token: deployment.tokens.erc1155[0],
},
},
{},
tokenIds,
);
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 () => {
it('should fail if there are zero leftOrders with the ZeroLeftOrders rich error reason', async () => {
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

View File

@ -1,6 +1,6 @@
import { DevUtilsContract } from '@0x/contracts-dev-utils';
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 { BatchMatchedFillResults, FillResults, MatchedFillResults, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
@ -244,9 +244,9 @@ export class MatchOrderTester {
orders,
takerAddress,
this._deployment.staking.stakingProxy.address,
this._blockchainBalanceStore,
toFullMatchTransferAmounts(expectedTransferAmounts),
this._devUtils,
this._blockchainBalanceStore,
localBalanceStore,
);
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
batchMatchResults.matches.push(
await simulateMatchOrdersAsync(
matchedOrders,
takerAddress,
stakingProxyAddress,
blockchainBalanceStore,
toFullMatchTransferAmounts(transferAmounts[i]),
devUtils,
blockchainBalanceStore,
localBalanceStore,
),
);
@ -434,7 +433,6 @@ async function simulateBatchMatchOrdersAsync(
return batchMatchResults;
}
// FIXME - Is it possible to remove `transferAmounts`
/**
* Simulates matching two orders by transferring amounts defined in
* `transferAmounts` and returns the results.
@ -448,9 +446,9 @@ async function simulateMatchOrdersAsync(
orders: MatchedOrders,
takerAddress: string,
stakingProxyAddress: string,
blockchainBalanceStore: BlockchainBalanceStore, // FIXME - Is this right?
transferAmounts: MatchTransferAmounts,
devUtils: DevUtilsContract,
blockchainBalanceStore: BlockchainBalanceStore,
localBalanceStore: LocalBalanceStore,
): Promise<MatchResults> {
// prettier-ignore
@ -478,7 +476,6 @@ async function simulateMatchOrdersAsync(
orders.rightOrder.makerAssetData,
);
// FIXME - Is this a necessary condition?
if (orders.leftOrder.makerAddress !== orders.leftOrder.feeRecipientAddress) {
// Left maker fees
localBalanceStore.transferAsset(
@ -489,7 +486,6 @@ async function simulateMatchOrdersAsync(
);
}
// FIXME - Is this a necessary condition?
// Left maker asset -> right maker
localBalanceStore.transferAsset(
orders.leftOrder.makerAddress,
@ -498,7 +494,6 @@ async function simulateMatchOrdersAsync(
orders.leftOrder.makerAssetData,
);
// FIXME - Is this a necessary condition?
if (orders.rightOrder.makerAddress !== orders.rightOrder.feeRecipientAddress) {
// Right maker fees
localBalanceStore.transferAsset(
@ -676,7 +671,6 @@ function simulateFillEvents(
];
}
// FIXME - Refactor this to use filterToLogsArguments
/**
* Extract `Fill` events from a transaction receipt.
*/
@ -830,7 +824,6 @@ function getLastMatch(batchMatchResults: BatchMatchResults): MatchResults {
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.
* @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.makerAddress).to.be.eq(fill.makerAddress);
expect(total.takerAddress).to.be.eq(fill.takerAddress);
// Add the fill results together
total.makerAssetFilledAmount = total.makerAssetFilledAmount.plus(fill.makerAssetFilledAmount);
total.takerAssetFilledAmount = total.takerAssetFilledAmount.plus(fill.takerAssetFilledAmount);