@0x/contracts-exchange
: Fully incorporate ERC1155 and MultiAsset tests into the fillOrder
and matchOrders
test suites.
This commit is contained in:
parent
57ac0ca6e8
commit
07e3ba014c
@ -29,6 +29,14 @@
|
|||||||
{
|
{
|
||||||
"note": "Add support for `SignatureType.WalletOrderValidator` for orders",
|
"note": "Add support for `SignatureType.WalletOrderValidator` for orders",
|
||||||
"pr": 1774
|
"pr": 1774
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Remove ZRX fees in lieu of arbitrary maker and taker fee tokens.",
|
||||||
|
"pr": 1819
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Incorporate Multi-asset and ERC1155 tests into `fillOrder` and `matchOrders` tests",
|
||||||
|
"pr": 1819
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -177,6 +177,24 @@ describe('FillOrder Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('ERC20', () => {
|
describe('ERC20', () => {
|
||||||
|
const assetCombinations = getAllPossiblePairs([
|
||||||
|
AssetDataScenario.ERC20ZeroDecimals,
|
||||||
|
AssetDataScenario.ERC20FiveDecimals,
|
||||||
|
AssetDataScenario.ERC20EighteenDecimals,
|
||||||
|
]);
|
||||||
|
for (const [makerAsset, takerAsset] of assetCombinations) {
|
||||||
|
it(`should transfer correct amounts between ${makerAsset} and ${takerAsset}`, async () => {
|
||||||
|
const fillScenario = {
|
||||||
|
...defaultFillScenario,
|
||||||
|
orderScenario: {
|
||||||
|
...defaultFillScenario.orderScenario,
|
||||||
|
makerAssetDataScenario: makerAsset,
|
||||||
|
takerAssetDataScenario: takerAsset,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||||
|
});
|
||||||
|
}
|
||||||
it('should be able to pay maker fee with taker asset', async () => {
|
it('should be able to pay maker fee with taker asset', async () => {
|
||||||
const fillScenario = {
|
const fillScenario = {
|
||||||
...defaultFillScenario,
|
...defaultFillScenario,
|
||||||
@ -573,14 +591,14 @@ describe('FillOrder Tests', () => {
|
|||||||
AssetDataScenario.ERC1155NonFungible,
|
AssetDataScenario.ERC1155NonFungible,
|
||||||
AssetDataScenario.MultiAssetERC20,
|
AssetDataScenario.MultiAssetERC20,
|
||||||
];
|
];
|
||||||
for (const [makerAssetData, takerAssetData] of getAllPossiblePairs(assetDataScenarios)) {
|
for (const [makerAsset, takerAsset] of getAllPossiblePairs(assetDataScenarios)) {
|
||||||
it(`should successfully exchange ${makerAssetData} for ${takerAssetData}`, async () => {
|
it(`should successfully exchange ${makerAsset} for ${takerAsset}`, async () => {
|
||||||
const fillScenario = {
|
const fillScenario = {
|
||||||
...defaultFillScenario,
|
...defaultFillScenario,
|
||||||
orderScenario: {
|
orderScenario: {
|
||||||
...defaultFillScenario.orderScenario,
|
...defaultFillScenario.orderScenario,
|
||||||
makerAssetDataScenario: makerAssetData,
|
makerAssetDataScenario: makerAsset,
|
||||||
takerAssetDataScenario: takerAssetData,
|
takerAssetDataScenario: takerAsset,
|
||||||
},
|
},
|
||||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
||||||
};
|
};
|
||||||
@ -590,21 +608,21 @@ describe('FillOrder Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Maker/taker fee asset combinations', () => {
|
describe('Maker/taker fee asset combinations', () => {
|
||||||
const feeAssetDataScenarios = [
|
const feeAssetPairs = getAllPossiblePairs([
|
||||||
FeeAssetDataScenario.ERC20EighteenDecimals,
|
FeeAssetDataScenario.ERC20EighteenDecimals,
|
||||||
FeeAssetDataScenario.ERC721,
|
FeeAssetDataScenario.ERC721,
|
||||||
FeeAssetDataScenario.ERC1155Fungible,
|
FeeAssetDataScenario.ERC1155Fungible,
|
||||||
FeeAssetDataScenario.ERC1155NonFungible,
|
FeeAssetDataScenario.ERC1155NonFungible,
|
||||||
FeeAssetDataScenario.MultiAssetERC20,
|
FeeAssetDataScenario.MultiAssetERC20,
|
||||||
];
|
]);
|
||||||
for (const [makerFeeAssetData, takerFeeAssetData] of getAllPossiblePairs(feeAssetDataScenarios)) {
|
for (const [makerFeeAsset, takerFeeAsset] of feeAssetPairs) {
|
||||||
it(`should successfully pay maker fee ${makerFeeAssetData} and taker fee ${takerFeeAssetData}`, async () => {
|
it(`should successfully pay maker fee ${makerFeeAsset} and taker fee ${takerFeeAsset}`, async () => {
|
||||||
const fillScenario = {
|
const fillScenario = {
|
||||||
...defaultFillScenario,
|
...defaultFillScenario,
|
||||||
orderScenario: {
|
orderScenario: {
|
||||||
...defaultFillScenario.orderScenario,
|
...defaultFillScenario.orderScenario,
|
||||||
makerFeeAssetDataScenario: makerFeeAssetData,
|
makerFeeAssetDataScenario: makerFeeAsset,
|
||||||
takerFeeAssetDataScenario: takerFeeAssetData,
|
takerFeeAssetDataScenario: takerFeeAsset,
|
||||||
},
|
},
|
||||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
||||||
};
|
};
|
||||||
|
@ -14,8 +14,6 @@ import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
|||||||
import {
|
import {
|
||||||
chaiSetup,
|
chaiSetup,
|
||||||
constants,
|
constants,
|
||||||
ERC1155HoldingsByOwner,
|
|
||||||
ERC721TokenIdsByOwner,
|
|
||||||
OrderFactory,
|
OrderFactory,
|
||||||
provider,
|
provider,
|
||||||
txDefaults,
|
txDefaults,
|
||||||
@ -34,17 +32,14 @@ import {
|
|||||||
constants as exchangeConstants,
|
constants as exchangeConstants,
|
||||||
ExchangeContract,
|
ExchangeContract,
|
||||||
ExchangeWrapper,
|
ExchangeWrapper,
|
||||||
MatchOrderTester,
|
|
||||||
ReentrantERC20TokenContract,
|
ReentrantERC20TokenContract,
|
||||||
TestExchangeInternalsContract,
|
TestExchangeInternalsContract,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
|
|
||||||
interface IndividualERC1155Holdings {
|
import { MatchOrderTester, TokenBalances } from './utils/match_order_tester';
|
||||||
fungible: {
|
|
||||||
[tokenId: string]: BigNumber;
|
const ONE = new BigNumber(1);
|
||||||
};
|
const TWO = new BigNumber(2);
|
||||||
nonFungible: BigNumber[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
@ -76,14 +71,12 @@ describe('matchOrders', () => {
|
|||||||
let orderFactoryLeft: OrderFactory;
|
let orderFactoryLeft: OrderFactory;
|
||||||
let orderFactoryRight: OrderFactory;
|
let orderFactoryRight: OrderFactory;
|
||||||
|
|
||||||
let erc721LeftMakerAssetIds: BigNumber[];
|
let tokenBalances: TokenBalances;
|
||||||
let erc721RightMakerAssetIds: BigNumber[];
|
|
||||||
let erc1155LeftMakerHoldings: IndividualERC1155Holdings;
|
|
||||||
let erc1155RightMakerHoldings: IndividualERC1155Holdings;
|
|
||||||
|
|
||||||
let defaultERC20MakerAssetAddress: string;
|
let defaultERC20MakerAssetAddress: string;
|
||||||
let defaultERC20TakerAssetAddress: string;
|
let defaultERC20TakerAssetAddress: string;
|
||||||
let defaultERC721AssetAddress: string;
|
let defaultERC721AssetAddress: string;
|
||||||
|
let defaultERC1155AssetAddress: string;
|
||||||
let defaultFeeTokenAddress: string;
|
let defaultFeeTokenAddress: string;
|
||||||
|
|
||||||
let matchOrderTester: MatchOrderTester;
|
let matchOrderTester: MatchOrderTester;
|
||||||
@ -109,41 +102,25 @@ describe('matchOrders', () => {
|
|||||||
feeRecipientAddressLeft,
|
feeRecipientAddressLeft,
|
||||||
feeRecipientAddressRight,
|
feeRecipientAddressRight,
|
||||||
] = accounts);
|
] = accounts);
|
||||||
|
const addressesWithBalances = usedAddresses.slice(1);
|
||||||
// Create wrappers
|
// Create wrappers
|
||||||
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
|
erc20Wrapper = new ERC20Wrapper(provider, addressesWithBalances, owner);
|
||||||
erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
|
erc721Wrapper = new ERC721Wrapper(provider, addressesWithBalances, owner);
|
||||||
erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner);
|
erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, addressesWithBalances, owner);
|
||||||
// Deploy ERC20 token & ERC20 proxy
|
// Deploy ERC20 token & ERC20 proxy
|
||||||
const numDummyErc20ToDeploy = 4;
|
const numDummyErc20ToDeploy = 4;
|
||||||
erc20Tokens = await erc20Wrapper.deployDummyTokensAsync(
|
erc20Tokens = await erc20Wrapper.deployDummyTokensAsync(numDummyErc20ToDeploy, constants.DUMMY_TOKEN_DECIMALS);
|
||||||
numDummyErc20ToDeploy,
|
|
||||||
constants.DUMMY_TOKEN_DECIMALS,
|
|
||||||
);
|
|
||||||
erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
||||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||||
// Deploy ERC721 token and proxy
|
// Deploy ERC721 token and proxy
|
||||||
[erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
|
[erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
|
||||||
erc721Proxy = await erc721Wrapper.deployProxyAsync();
|
erc721Proxy = await erc721Wrapper.deployProxyAsync();
|
||||||
await erc721Wrapper.setBalancesAndAllowancesAsync();
|
await erc721Wrapper.setBalancesAndAllowancesAsync();
|
||||||
const erc721Balances = await erc721Wrapper.getBalancesAsync();
|
|
||||||
erc721LeftMakerAssetIds = erc721Balances[makerAddressLeft][erc721Token.address];
|
|
||||||
erc721RightMakerAssetIds = erc721Balances[makerAddressRight][erc721Token.address];
|
|
||||||
// Deploy ERC1155 token and proxy
|
// Deploy ERC1155 token and proxy
|
||||||
[erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync();
|
[erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync();
|
||||||
erc1155Token = erc1155Wrapper.getContract();
|
erc1155Token = erc1155Wrapper.getContract();
|
||||||
erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync();
|
erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync();
|
||||||
await erc1155ProxyWrapper.setBalancesAndAllowancesAsync();
|
await erc1155ProxyWrapper.setBalancesAndAllowancesAsync();
|
||||||
const erc1155Holdings = await erc1155ProxyWrapper.getBalancesAsync();
|
|
||||||
erc1155LeftMakerHoldings = getIndividualERC1155Holdings(
|
|
||||||
erc1155Holdings,
|
|
||||||
erc1155Token.address,
|
|
||||||
makerAddressLeft,
|
|
||||||
);
|
|
||||||
erc1155RightMakerHoldings = getIndividualERC1155Holdings(
|
|
||||||
erc1155Holdings,
|
|
||||||
erc1155Token.address,
|
|
||||||
makerAddressRight,
|
|
||||||
);
|
|
||||||
// Deploy MultiAssetProxy.
|
// Deploy MultiAssetProxy.
|
||||||
const multiAssetProxyContract = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
|
const multiAssetProxyContract = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
|
||||||
assetProxyArtifacts.MultiAssetProxy,
|
assetProxyArtifacts.MultiAssetProxy,
|
||||||
@ -178,6 +155,11 @@ describe('matchOrders', () => {
|
|||||||
{ from: owner },
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
|
await multiAssetProxyContract.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
|
exchange.address,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
multiAssetProxyContract.address,
|
multiAssetProxyContract.address,
|
||||||
{ from: owner },
|
{ from: owner },
|
||||||
@ -193,8 +175,18 @@ describe('matchOrders', () => {
|
|||||||
{ from: owner },
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
await multiAssetProxyContract.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
await multiAssetProxyContract.registerAssetProxy.awaitTransactionSuccessAsync(
|
||||||
exchange.address,
|
erc20Proxy.address,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
await multiAssetProxyContract.registerAssetProxy.awaitTransactionSuccessAsync(
|
||||||
|
erc721Proxy.address,
|
||||||
|
{ from: owner },
|
||||||
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
|
);
|
||||||
|
await multiAssetProxyContract.registerAssetProxy.awaitTransactionSuccessAsync(
|
||||||
|
erc1155Proxy.address,
|
||||||
{ from: owner },
|
{ from: owner },
|
||||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||||
);
|
);
|
||||||
@ -211,6 +203,7 @@ describe('matchOrders', () => {
|
|||||||
defaultERC20TakerAssetAddress = erc20Tokens[1].address;
|
defaultERC20TakerAssetAddress = erc20Tokens[1].address;
|
||||||
defaultFeeTokenAddress = erc20Tokens[2].address;
|
defaultFeeTokenAddress = erc20Tokens[2].address;
|
||||||
defaultERC721AssetAddress = erc721Token.address;
|
defaultERC721AssetAddress = erc721Token.address;
|
||||||
|
defaultERC1155AssetAddress = erc1155Token.address;
|
||||||
const domain = {
|
const domain = {
|
||||||
verifyingContractAddress: exchange.address,
|
verifyingContractAddress: exchange.address,
|
||||||
chainId,
|
chainId,
|
||||||
@ -240,17 +233,15 @@ describe('matchOrders', () => {
|
|||||||
orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft);
|
orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft);
|
||||||
const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
|
const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
|
||||||
orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight);
|
orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight);
|
||||||
// Set match order tester
|
|
||||||
matchOrderTester = new MatchOrderTester(exchangeWrapper, erc20Wrapper, erc721Wrapper);
|
|
||||||
testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
|
testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
|
||||||
artifacts.TestExchangeInternals,
|
artifacts.TestExchangeInternals,
|
||||||
provider,
|
provider,
|
||||||
txDefaults,
|
txDefaults,
|
||||||
new BigNumber(chainId),
|
new BigNumber(chainId),
|
||||||
);
|
);
|
||||||
|
// Create match order tester
|
||||||
console.log(erc1155LeftMakerHoldings);
|
matchOrderTester = new MatchOrderTester(exchangeWrapper, erc20Wrapper, erc721Wrapper, erc1155ProxyWrapper);
|
||||||
console.log(erc1155RightMakerHoldings);
|
tokenBalances = await matchOrderTester.getBalancesAsync();
|
||||||
});
|
});
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await blockchainLifecycle.startAsync();
|
await blockchainLifecycle.startAsync();
|
||||||
@ -1266,267 +1257,452 @@ describe('matchOrders', () => {
|
|||||||
return expect(tx).to.revertWith(expectedError);
|
return expect(tx).to.revertWith(expectedError);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should transfer correct amounts when left order maker asset is an ERC721 token', async () => {
|
describe('combinations', () => {
|
||||||
// Create orders to match
|
|
||||||
const erc721TokenToTransfer = erc721LeftMakerAssetIds[0];
|
|
||||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
|
||||||
makerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
|
||||||
makerAssetAmount: new BigNumber(1),
|
|
||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18),
|
|
||||||
});
|
|
||||||
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
|
||||||
takerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
|
||||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18),
|
|
||||||
takerAssetAmount: new BigNumber(1),
|
|
||||||
});
|
|
||||||
// Match orders
|
|
||||||
const expectedTransferAmounts = {
|
|
||||||
// Left Maker
|
|
||||||
leftMakerAssetSoldByLeftMakerAmount: Web3Wrapper.toBaseUnitAmount(1, 0),
|
|
||||||
leftMakerFeeAssetPaidByLeftMakerAmount: Web3Wrapper.toBaseUnitAmount(100, 16), // 100%
|
|
||||||
// Right Maker
|
|
||||||
rightMakerAssetSoldByRightMakerAmount: Web3Wrapper.toBaseUnitAmount(10, 18),
|
|
||||||
rightMakerFeeAssetPaidByRightMakerAmount: Web3Wrapper.toBaseUnitAmount(100, 16), // 100%
|
|
||||||
// Taker
|
|
||||||
leftTakerFeeAssetPaidByTakerAmount: Web3Wrapper.toBaseUnitAmount(100, 16), // 100%
|
|
||||||
rightTakerFeeAssetPaidByTakerAmount: Web3Wrapper.toBaseUnitAmount(100, 16), // 50%
|
|
||||||
};
|
|
||||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
|
||||||
{
|
|
||||||
leftOrder: signedOrderLeft,
|
|
||||||
rightOrder: signedOrderRight,
|
|
||||||
},
|
|
||||||
takerAddress,
|
|
||||||
expectedTransferAmounts,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should transfer correct amounts when right order maker asset is an ERC721 token', async () => {
|
|
||||||
// Create orders to match
|
|
||||||
const erc721TokenToTransfer = erc721RightMakerAssetIds[0];
|
|
||||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
|
||||||
takerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
|
||||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, 18),
|
|
||||||
takerAssetAmount: new BigNumber(1),
|
|
||||||
});
|
|
||||||
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
|
||||||
makerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
|
||||||
makerAssetAmount: new BigNumber(1),
|
|
||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(8, 18),
|
|
||||||
});
|
|
||||||
// Match orders
|
|
||||||
const expectedTransferAmounts = {
|
|
||||||
// Left Maker
|
|
||||||
leftMakerAssetSoldByLeftMakerAmount: Web3Wrapper.toBaseUnitAmount(10, 18),
|
|
||||||
leftMakerFeeAssetPaidByLeftMakerAmount: Web3Wrapper.toBaseUnitAmount(100, 16), // 100%
|
|
||||||
// Right Maker
|
|
||||||
rightMakerAssetSoldByRightMakerAmount: Web3Wrapper.toBaseUnitAmount(1, 0),
|
|
||||||
leftMakerAssetBoughtByRightMakerAmount: Web3Wrapper.toBaseUnitAmount(8, 18),
|
|
||||||
rightMakerFeeAssetPaidByRightMakerAmount: Web3Wrapper.toBaseUnitAmount(100, 16), // 100%
|
|
||||||
// Taker
|
|
||||||
leftMakerAssetReceivedByTakerAmount: Web3Wrapper.toBaseUnitAmount(2, 18),
|
|
||||||
leftTakerFeeAssetPaidByTakerAmount: Web3Wrapper.toBaseUnitAmount(100, 16), // 100%
|
|
||||||
rightTakerFeeAssetPaidByTakerAmount: Web3Wrapper.toBaseUnitAmount(100, 16), // 100%
|
|
||||||
};
|
|
||||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
|
||||||
{
|
|
||||||
leftOrder: signedOrderLeft,
|
|
||||||
rightOrder: signedOrderRight,
|
|
||||||
},
|
|
||||||
takerAddress,
|
|
||||||
expectedTransferAmounts,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('fee tokens', () => {
|
|
||||||
// tslint:disable: enum-naming
|
// tslint:disable: enum-naming
|
||||||
enum TokenType {
|
enum AssetType {
|
||||||
ERC20A = 'ERC20A',
|
ERC20A = 'ERC20_A',
|
||||||
ERC20B = 'ERC20B',
|
ERC20B = 'ERC20_B',
|
||||||
ERC20C = 'ERC20C',
|
ERC20C = 'ERC20_C',
|
||||||
ERC20D = 'ERC20D',
|
ERC20D = 'ERC20_D',
|
||||||
ERC721A = 'ERC721A',
|
ERC721LeftMaker = 'ERC721_LEFT_MAKER',
|
||||||
ERC721B = 'ERC721B',
|
ERC721RightMaker = 'ERC721_RIGHT_MAKER',
|
||||||
ERC721C = 'ERC721C',
|
ERC721Taker = 'ERC721_TAKER',
|
||||||
ERC721D = 'ERC721D',
|
ERC1155FungibleA = 'ERC1155_FUNGIBLE_A',
|
||||||
|
ERC1155FungibleB = 'ERC1155_FUNGIBLE_B',
|
||||||
|
ERC1155FungibleC = 'ERC1155_FUNGIBLE_C',
|
||||||
|
ERC1155FungibleD = 'ERC1155_FUNGIBLE_D',
|
||||||
|
ERC1155NonFungibleLeftMaker = 'ERC1155_NON_FUNGIBLE_LEFT_MAKER',
|
||||||
|
ERC1155NonFungibleRightMaker = 'ERC1155_NON_FUNGIBLE_RIGHT_MAKER',
|
||||||
|
ERC1155NonFungibleTaker = 'ERC1155_NON_FUNGIBLE_TAKER',
|
||||||
|
MultiAssetA = 'MULTI_ASSET_A',
|
||||||
|
MultiAssetB = 'MULTI_ASSET_B',
|
||||||
|
MultiAssetC = 'MULTI_ASSET_C',
|
||||||
|
MultiAssetD = 'MULTI_ASSET_D',
|
||||||
}
|
}
|
||||||
|
const fungibleTypes = [
|
||||||
|
AssetType.ERC20A,
|
||||||
|
AssetType.ERC20B,
|
||||||
|
AssetType.ERC20C,
|
||||||
|
AssetType.ERC20D,
|
||||||
|
AssetType.ERC1155FungibleA,
|
||||||
|
AssetType.ERC1155FungibleB,
|
||||||
|
AssetType.ERC1155FungibleC,
|
||||||
|
AssetType.ERC1155FungibleD,
|
||||||
|
AssetType.MultiAssetA,
|
||||||
|
AssetType.MultiAssetB,
|
||||||
|
AssetType.MultiAssetC,
|
||||||
|
AssetType.MultiAssetD,
|
||||||
|
];
|
||||||
interface AssetCombination {
|
interface AssetCombination {
|
||||||
leftMaker: TokenType;
|
leftMaker: AssetType;
|
||||||
rightMaker: TokenType;
|
rightMaker: AssetType;
|
||||||
leftMakerFee: TokenType;
|
leftMakerFee: AssetType;
|
||||||
rightMakerFee: TokenType;
|
rightMakerFee: AssetType;
|
||||||
leftTakerFee: TokenType;
|
leftTakerFee: AssetType;
|
||||||
rightTakerFee: TokenType;
|
rightTakerFee: AssetType;
|
||||||
description?: string;
|
description?: string;
|
||||||
shouldFail?: boolean;
|
shouldFail?: boolean;
|
||||||
}
|
}
|
||||||
const feeAssetCombinations: AssetCombination[] = [
|
const assetCombinations: AssetCombination[] = [
|
||||||
{
|
{
|
||||||
description: 'Swapping tokens then using them to pay maker fees.',
|
leftMaker: AssetType.ERC20A,
|
||||||
leftMaker: TokenType.ERC20A,
|
rightMaker: AssetType.ERC20B,
|
||||||
rightMaker: TokenType.ERC20B,
|
leftMakerFee: AssetType.ERC20C,
|
||||||
leftMakerFee: TokenType.ERC20B,
|
rightMakerFee: AssetType.ERC20C,
|
||||||
rightMakerFee: TokenType.ERC20A,
|
leftTakerFee: AssetType.ERC20C,
|
||||||
leftTakerFee: TokenType.ERC20C,
|
rightTakerFee: AssetType.ERC20C,
|
||||||
rightTakerFee: TokenType.ERC20C,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Swapping tokens then using them to pay taker fees.',
|
leftMaker: AssetType.ERC721LeftMaker,
|
||||||
leftMaker: TokenType.ERC20A,
|
rightMaker: AssetType.ERC721RightMaker,
|
||||||
rightMaker: TokenType.ERC20B,
|
leftMakerFee: AssetType.ERC20C,
|
||||||
leftMakerFee: TokenType.ERC20C,
|
rightMakerFee: AssetType.ERC20C,
|
||||||
rightMakerFee: TokenType.ERC20C,
|
leftTakerFee: AssetType.ERC20C,
|
||||||
leftTakerFee: TokenType.ERC20B,
|
rightTakerFee: AssetType.ERC20C,
|
||||||
rightTakerFee: TokenType.ERC20A,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Swapping tokens then using them to pay maker and taker fees.',
|
leftMaker: AssetType.ERC721LeftMaker,
|
||||||
leftMaker: TokenType.ERC20A,
|
rightMaker: AssetType.ERC20A,
|
||||||
rightMaker: TokenType.ERC20B,
|
leftMakerFee: AssetType.ERC20C,
|
||||||
leftMakerFee: TokenType.ERC20B,
|
rightMakerFee: AssetType.ERC20C,
|
||||||
rightMakerFee: TokenType.ERC20A,
|
leftTakerFee: AssetType.ERC20C,
|
||||||
leftTakerFee: TokenType.ERC20C,
|
rightTakerFee: AssetType.ERC20C,
|
||||||
rightTakerFee: TokenType.ERC20C,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Paying maker and taker fees with same tokens being sold.',
|
leftMaker: AssetType.ERC20A,
|
||||||
leftMaker: TokenType.ERC20A,
|
rightMaker: AssetType.ERC721RightMaker,
|
||||||
rightMaker: TokenType.ERC20B,
|
leftMakerFee: AssetType.ERC20C,
|
||||||
leftMakerFee: TokenType.ERC20A,
|
rightMakerFee: AssetType.ERC20C,
|
||||||
rightMakerFee: TokenType.ERC20B,
|
leftTakerFee: AssetType.ERC20C,
|
||||||
leftTakerFee: TokenType.ERC20A,
|
rightTakerFee: AssetType.ERC20C,
|
||||||
rightTakerFee: TokenType.ERC20B,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Paying maker and taker fees with same tokens being bought.',
|
leftMaker: AssetType.ERC1155FungibleA,
|
||||||
leftMaker: TokenType.ERC20A,
|
rightMaker: AssetType.ERC20A,
|
||||||
rightMaker: TokenType.ERC20B,
|
leftMakerFee: AssetType.ERC20C,
|
||||||
leftMakerFee: TokenType.ERC20B,
|
rightMakerFee: AssetType.ERC20C,
|
||||||
rightMakerFee: TokenType.ERC20A,
|
leftTakerFee: AssetType.ERC20C,
|
||||||
leftTakerFee: TokenType.ERC20B,
|
rightTakerFee: AssetType.ERC20C,
|
||||||
rightTakerFee: TokenType.ERC20A,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Buy an ERC721 then use it to pay maker fees.',
|
leftMaker: AssetType.ERC20A,
|
||||||
leftMaker: TokenType.ERC20A,
|
rightMaker: AssetType.ERC1155FungibleB,
|
||||||
rightMaker: TokenType.ERC721A,
|
leftMakerFee: AssetType.ERC20C,
|
||||||
leftMakerFee: TokenType.ERC721A,
|
rightMakerFee: AssetType.ERC20C,
|
||||||
rightMakerFee: TokenType.ERC20B,
|
leftTakerFee: AssetType.ERC20C,
|
||||||
leftTakerFee: TokenType.ERC20C,
|
rightTakerFee: AssetType.ERC20C,
|
||||||
rightTakerFee: TokenType.ERC20C,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Buy an ERC721 then use it to pay maker fee (the other way).',
|
leftMaker: AssetType.ERC1155FungibleA,
|
||||||
leftMaker: TokenType.ERC721A,
|
rightMaker: AssetType.ERC1155FungibleA,
|
||||||
rightMaker: TokenType.ERC20A,
|
leftMakerFee: AssetType.ERC20C,
|
||||||
leftMakerFee: TokenType.ERC20B,
|
rightMakerFee: AssetType.ERC20C,
|
||||||
rightMakerFee: TokenType.ERC721A,
|
leftTakerFee: AssetType.ERC20C,
|
||||||
leftTakerFee: TokenType.ERC20C,
|
rightTakerFee: AssetType.ERC20C,
|
||||||
rightTakerFee: TokenType.ERC20C,
|
},
|
||||||
|
{
|
||||||
|
leftMaker: AssetType.ERC1155NonFungibleLeftMaker,
|
||||||
|
rightMaker: AssetType.ERC20A,
|
||||||
|
leftMakerFee: AssetType.ERC20C,
|
||||||
|
rightMakerFee: AssetType.ERC20C,
|
||||||
|
leftTakerFee: AssetType.ERC20C,
|
||||||
|
rightTakerFee: AssetType.ERC20C,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leftMaker: AssetType.ERC20A,
|
||||||
|
rightMaker: AssetType.ERC1155NonFungibleRightMaker,
|
||||||
|
leftMakerFee: AssetType.ERC20C,
|
||||||
|
rightMakerFee: AssetType.ERC20C,
|
||||||
|
leftTakerFee: AssetType.ERC20C,
|
||||||
|
rightTakerFee: AssetType.ERC20C,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leftMaker: AssetType.ERC1155NonFungibleLeftMaker,
|
||||||
|
rightMaker: AssetType.ERC1155NonFungibleRightMaker,
|
||||||
|
leftMakerFee: AssetType.ERC20C,
|
||||||
|
rightMakerFee: AssetType.ERC20C,
|
||||||
|
leftTakerFee: AssetType.ERC20C,
|
||||||
|
rightTakerFee: AssetType.ERC20C,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leftMaker: AssetType.ERC1155FungibleA,
|
||||||
|
rightMaker: AssetType.ERC20A,
|
||||||
|
leftMakerFee: AssetType.ERC20C,
|
||||||
|
rightMakerFee: AssetType.ERC20C,
|
||||||
|
leftTakerFee: AssetType.ERC20C,
|
||||||
|
rightTakerFee: AssetType.ERC20C,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leftMaker: AssetType.ERC20A,
|
||||||
|
rightMaker: AssetType.ERC1155FungibleB,
|
||||||
|
leftMakerFee: AssetType.ERC20C,
|
||||||
|
rightMakerFee: AssetType.ERC20C,
|
||||||
|
leftTakerFee: AssetType.ERC20C,
|
||||||
|
rightTakerFee: AssetType.ERC20C,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leftMaker: AssetType.ERC1155FungibleB,
|
||||||
|
rightMaker: AssetType.ERC1155FungibleB,
|
||||||
|
leftMakerFee: AssetType.ERC20C,
|
||||||
|
rightMakerFee: AssetType.ERC20C,
|
||||||
|
leftTakerFee: AssetType.ERC20C,
|
||||||
|
rightTakerFee: AssetType.ERC20C,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leftMaker: AssetType.MultiAssetA,
|
||||||
|
rightMaker: AssetType.ERC20A,
|
||||||
|
leftMakerFee: AssetType.ERC20C,
|
||||||
|
rightMakerFee: AssetType.ERC20C,
|
||||||
|
leftTakerFee: AssetType.ERC20C,
|
||||||
|
rightTakerFee: AssetType.ERC20C,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leftMaker: AssetType.ERC20A,
|
||||||
|
rightMaker: AssetType.MultiAssetB,
|
||||||
|
leftMakerFee: AssetType.ERC20C,
|
||||||
|
rightMakerFee: AssetType.ERC20C,
|
||||||
|
leftTakerFee: AssetType.ERC20C,
|
||||||
|
rightTakerFee: AssetType.ERC20C,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leftMaker: AssetType.MultiAssetA,
|
||||||
|
rightMaker: AssetType.MultiAssetB,
|
||||||
|
leftMakerFee: AssetType.ERC20C,
|
||||||
|
rightMakerFee: AssetType.ERC20C,
|
||||||
|
leftTakerFee: AssetType.ERC20C,
|
||||||
|
rightTakerFee: AssetType.ERC20C,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leftMaker: AssetType.MultiAssetA,
|
||||||
|
rightMaker: AssetType.ERC1155FungibleA,
|
||||||
|
leftMakerFee: AssetType.ERC1155FungibleA,
|
||||||
|
rightMakerFee: AssetType.MultiAssetA,
|
||||||
|
leftTakerFee: AssetType.ERC20C,
|
||||||
|
rightTakerFee: AssetType.ERC20C,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Paying maker fees with the same ERC20 tokens being bought.',
|
||||||
|
leftMaker: AssetType.ERC20A,
|
||||||
|
rightMaker: AssetType.ERC20B,
|
||||||
|
leftMakerFee: AssetType.ERC20B,
|
||||||
|
rightMakerFee: AssetType.ERC20A,
|
||||||
|
leftTakerFee: AssetType.ERC20B,
|
||||||
|
rightTakerFee: AssetType.ERC20A,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Paying maker fees with the same ERC20 tokens being sold.',
|
||||||
|
leftMaker: AssetType.ERC20A,
|
||||||
|
rightMaker: AssetType.ERC20B,
|
||||||
|
leftMakerFee: AssetType.ERC20A,
|
||||||
|
rightMakerFee: AssetType.ERC20B,
|
||||||
|
leftTakerFee: AssetType.ERC20A,
|
||||||
|
rightTakerFee: AssetType.ERC20B,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Using all the same ERC20 asset.',
|
||||||
|
leftMaker: AssetType.ERC20A,
|
||||||
|
rightMaker: AssetType.ERC20A,
|
||||||
|
leftMakerFee: AssetType.ERC20A,
|
||||||
|
rightMakerFee: AssetType.ERC20A,
|
||||||
|
leftTakerFee: AssetType.ERC20A,
|
||||||
|
rightTakerFee: AssetType.ERC20A,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Paying fees with the same MAP assets being sold.',
|
||||||
|
leftMaker: AssetType.MultiAssetA,
|
||||||
|
rightMaker: AssetType.MultiAssetB,
|
||||||
|
leftMakerFee: AssetType.MultiAssetA,
|
||||||
|
rightMakerFee: AssetType.MultiAssetB,
|
||||||
|
leftTakerFee: AssetType.MultiAssetA,
|
||||||
|
rightTakerFee: AssetType.MultiAssetB,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Paying fees with the same MAP assets being bought.',
|
||||||
|
leftMaker: AssetType.MultiAssetA,
|
||||||
|
rightMaker: AssetType.MultiAssetB,
|
||||||
|
leftMakerFee: AssetType.MultiAssetB,
|
||||||
|
rightMakerFee: AssetType.MultiAssetA,
|
||||||
|
leftTakerFee: AssetType.MultiAssetB,
|
||||||
|
rightTakerFee: AssetType.MultiAssetA,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Using all the same MAP assets.',
|
||||||
|
leftMaker: AssetType.MultiAssetA,
|
||||||
|
rightMaker: AssetType.MultiAssetA,
|
||||||
|
leftMakerFee: AssetType.MultiAssetA,
|
||||||
|
rightMakerFee: AssetType.MultiAssetA,
|
||||||
|
leftTakerFee: AssetType.MultiAssetA,
|
||||||
|
rightTakerFee: AssetType.MultiAssetA,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Swapping ERC721s then using them to pay maker fees.',
|
description: 'Swapping ERC721s then using them to pay maker fees.',
|
||||||
leftMaker: TokenType.ERC721A,
|
leftMaker: AssetType.ERC721LeftMaker,
|
||||||
rightMaker: TokenType.ERC721B,
|
rightMaker: AssetType.ERC721RightMaker,
|
||||||
leftMakerFee: TokenType.ERC721B,
|
leftMakerFee: AssetType.ERC721RightMaker,
|
||||||
rightMakerFee: TokenType.ERC721A,
|
rightMakerFee: AssetType.ERC721LeftMaker,
|
||||||
leftTakerFee: TokenType.ERC20A,
|
leftTakerFee: AssetType.ERC20A,
|
||||||
rightTakerFee: TokenType.ERC20A,
|
rightTakerFee: AssetType.ERC20A,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Swapping ERC1155 NFTs then using them to pay maker fees.',
|
||||||
|
leftMaker: AssetType.ERC1155NonFungibleLeftMaker,
|
||||||
|
rightMaker: AssetType.ERC1155NonFungibleRightMaker,
|
||||||
|
leftMakerFee: AssetType.ERC1155NonFungibleRightMaker,
|
||||||
|
rightMakerFee: AssetType.ERC1155NonFungibleLeftMaker,
|
||||||
|
leftTakerFee: AssetType.ERC20A,
|
||||||
|
rightTakerFee: AssetType.ERC20A,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Double-spend by trying to pay maker fees with sold ERC721 token (fail).',
|
description: 'Double-spend by trying to pay maker fees with sold ERC721 token (fail).',
|
||||||
leftMaker: TokenType.ERC721A,
|
leftMaker: AssetType.ERC721LeftMaker,
|
||||||
rightMaker: TokenType.ERC721B,
|
rightMaker: AssetType.ERC721RightMaker,
|
||||||
leftMakerFee: TokenType.ERC721A,
|
leftMakerFee: AssetType.ERC721LeftMaker,
|
||||||
rightMakerFee: TokenType.ERC721A,
|
rightMakerFee: AssetType.ERC721LeftMaker,
|
||||||
leftTakerFee: TokenType.ERC20A,
|
leftTakerFee: AssetType.ERC20A,
|
||||||
rightTakerFee: TokenType.ERC20A,
|
rightTakerFee: AssetType.ERC20A,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Double-spend by trying to pay maker fees with sold ERC1155 NFT (fail).',
|
||||||
|
leftMaker: AssetType.ERC20A,
|
||||||
|
rightMaker: AssetType.ERC1155NonFungibleLeftMaker,
|
||||||
|
leftMakerFee: AssetType.ERC20C,
|
||||||
|
rightMakerFee: AssetType.ERC1155NonFungibleLeftMaker,
|
||||||
|
leftTakerFee: AssetType.ERC20C,
|
||||||
|
rightTakerFee: AssetType.ERC20C,
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let erc721TokenIdsByOwner: ERC721TokenIdsByOwner;
|
let nameToERC20Asset: { [name: string]: string };
|
||||||
let nameToERC20Tokens: { [name: string]: string };
|
let nameToERC721Asset: { [name: string]: [string, BigNumber] };
|
||||||
let nameToERC721Tokens: { [name: string]: string };
|
let nameToERC1155FungibleAsset: { [name: string]: [string, BigNumber] };
|
||||||
|
let nameToERC1155NonFungibleAsset: { [name: string]: [string, BigNumber] };
|
||||||
|
let nameToMultiAssetAsset: { [name: string]: [BigNumber[], string[]] };
|
||||||
|
|
||||||
function getAssetData(tokenType: TokenType, ownerAddress: string): string {
|
function getAssetData(assetType: AssetType): string {
|
||||||
const encodeERC20AssetData = assetDataUtils.encodeERC20AssetData;
|
const encodeERC20AssetData = assetDataUtils.encodeERC20AssetData;
|
||||||
const encodeERC721AssetData = assetDataUtils.encodeERC721AssetData;
|
const encodeERC721AssetData = assetDataUtils.encodeERC721AssetData;
|
||||||
if (nameToERC20Tokens[tokenType] !== undefined) {
|
const encodeERC1155AssetData = assetDataUtils.encodeERC1155AssetData;
|
||||||
const tokenAddress = nameToERC20Tokens[tokenType];
|
const encodeMultiAssetData = assetDataUtils.encodeMultiAssetData;
|
||||||
|
if (nameToERC20Asset[assetType] !== undefined) {
|
||||||
|
const tokenAddress = nameToERC20Asset[assetType];
|
||||||
return encodeERC20AssetData(tokenAddress);
|
return encodeERC20AssetData(tokenAddress);
|
||||||
}
|
}
|
||||||
if (nameToERC721Tokens[tokenType] !== undefined) {
|
if (nameToERC721Asset[assetType] !== undefined) {
|
||||||
const tokenAddress = nameToERC721Tokens[tokenType];
|
const [tokenAddress, tokenId] = nameToERC721Asset[assetType];
|
||||||
const tokenIdx = tokenType.charCodeAt(tokenType.length - 1) - 'A'.charCodeAt(0);
|
return encodeERC721AssetData(tokenAddress, tokenId);
|
||||||
const tokenId = erc721TokenIdsByOwner[ownerAddress][tokenAddress][tokenIdx];
|
|
||||||
return encodeERC721AssetData(nameToERC721Tokens[tokenType], tokenId);
|
|
||||||
}
|
}
|
||||||
return '0x';
|
if (nameToERC1155FungibleAsset[assetType] !== undefined) {
|
||||||
|
const [tokenAddress, tokenId] = nameToERC1155FungibleAsset[assetType];
|
||||||
|
return encodeERC1155AssetData(tokenAddress, [tokenId], [ONE], constants.NULL_BYTES);
|
||||||
|
}
|
||||||
|
if (nameToERC1155NonFungibleAsset[assetType] !== undefined) {
|
||||||
|
const [tokenAddress, tokenId] = nameToERC1155NonFungibleAsset[assetType];
|
||||||
|
return encodeERC1155AssetData(tokenAddress, [tokenId], [ONE], constants.NULL_BYTES);
|
||||||
|
}
|
||||||
|
if (nameToMultiAssetAsset[assetType] !== undefined) {
|
||||||
|
const [amounts, nestedAssetData] = nameToMultiAssetAsset[assetType];
|
||||||
|
return encodeMultiAssetData(amounts, nestedAssetData);
|
||||||
|
}
|
||||||
|
throw new Error(`Unknown asset type: ${assetType}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
erc721TokenIdsByOwner = await erc721Wrapper.getBalancesAsync();
|
nameToERC20Asset = {
|
||||||
nameToERC20Tokens = {
|
ERC20_A: erc20Tokens[0].address,
|
||||||
ERC20A: erc20Tokens[0].address,
|
ERC20_B: erc20Tokens[1].address,
|
||||||
ERC20B: erc20Tokens[1].address,
|
ERC20_C: erc20Tokens[2].address,
|
||||||
ERC20C: erc20Tokens[0].address,
|
ERC20_D: erc20Tokens[3].address,
|
||||||
ERC20D: erc20Tokens[1].address,
|
|
||||||
};
|
};
|
||||||
nameToERC721Tokens = {
|
const erc721TokenIds = _.mapValues(tokenBalances.erc721, v => v[defaultERC721AssetAddress.address][0]);
|
||||||
ERC721A: erc721Token.address,
|
nameToERC721Asset = {
|
||||||
ERC721B: erc721Token.address,
|
ERC721_LEFT_MAKER: [defaultERC721AssetAddress.address, erc721TokenIds[makerAddressLeft]],
|
||||||
ERC721C: erc721Token.address,
|
ERC721_RIGHT_MAKER: [defaultERC721AssetAddress.address, erc721TokenIds[makerAddressRight]],
|
||||||
ERC721D: erc721Token.address,
|
ERC721_TAKER: [defaultERC721AssetAddress.address, erc721TokenIds[takerAddress]],
|
||||||
|
};
|
||||||
|
const erc1155FungibleTokens = _.keys(
|
||||||
|
_.values(tokenBalances.erc1155)[0][defaultERC1155AssetAddress].fungible,
|
||||||
|
).map(k => new BigNumber(k));
|
||||||
|
nameToERC1155FungibleAsset = {
|
||||||
|
ERC1155_FUNGIBLE_A: [defaultERC1155AssetAddress, erc1155FungibleTokens[0]],
|
||||||
|
ERC1155_FUNGIBLE_B: [defaultERC1155AssetAddress, erc1155FungibleTokens[1]],
|
||||||
|
ERC1155_FUNGIBLE_C: [defaultERC1155AssetAddress, erc1155FungibleTokens[2]],
|
||||||
|
ERC1155_FUNGIBLE_D: [defaultERC1155AssetAddress, erc1155FungibleTokens[3]],
|
||||||
|
};
|
||||||
|
const erc1155NonFungibleTokenIds = _.mapValues(
|
||||||
|
tokenBalances.erc1155,
|
||||||
|
v => v[defaultERC1155AssetAddress].nonFungible[0],
|
||||||
|
);
|
||||||
|
nameToERC1155NonFungibleAsset = {
|
||||||
|
ERC1155_NON_FUNGIBLE_LEFT_MAKER: [
|
||||||
|
defaultERC1155AssetAddress,
|
||||||
|
erc1155NonFungibleTokenIds[makerAddressLeft],
|
||||||
|
],
|
||||||
|
ERC1155_NON_FUNGIBLE_RIGHT_MAKER: [
|
||||||
|
defaultERC1155AssetAddress,
|
||||||
|
erc1155NonFungibleTokenIds[makerAddressRight],
|
||||||
|
],
|
||||||
|
ERC1155_NON_FUNGIBLE_TAKER: [defaultERC1155AssetAddress, erc1155NonFungibleTokenIds[takerAddress]],
|
||||||
|
};
|
||||||
|
nameToMultiAssetAsset = {
|
||||||
|
MULTI_ASSET_A: [
|
||||||
|
[ONE, TWO],
|
||||||
|
[
|
||||||
|
assetDataUtils.encodeERC20AssetData(erc20Tokens[0].address),
|
||||||
|
assetDataUtils.encodeERC1155AssetData(
|
||||||
|
defaultERC1155AssetAddress,
|
||||||
|
[erc1155FungibleTokens[0]],
|
||||||
|
[ONE],
|
||||||
|
constants.NULL_BYTES,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
MULTI_ASSET_B: [
|
||||||
|
[ONE, TWO],
|
||||||
|
[
|
||||||
|
assetDataUtils.encodeERC20AssetData(erc20Tokens[1].address),
|
||||||
|
assetDataUtils.encodeERC1155AssetData(
|
||||||
|
defaultERC1155AssetAddress,
|
||||||
|
[erc1155FungibleTokens[1]],
|
||||||
|
[ONE],
|
||||||
|
constants.NULL_BYTES,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
MULTI_ASSET_C: [
|
||||||
|
[ONE, TWO],
|
||||||
|
[
|
||||||
|
assetDataUtils.encodeERC20AssetData(erc20Tokens[2].address),
|
||||||
|
assetDataUtils.encodeERC1155AssetData(
|
||||||
|
defaultERC1155AssetAddress,
|
||||||
|
[erc1155FungibleTokens[2]],
|
||||||
|
[ONE],
|
||||||
|
constants.NULL_BYTES,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
MULTI_ASSET_D: [
|
||||||
|
[ONE, TWO],
|
||||||
|
[
|
||||||
|
assetDataUtils.encodeERC20AssetData(erc20Tokens[3].address),
|
||||||
|
assetDataUtils.encodeERC1155AssetData(
|
||||||
|
erc1155Token.address,
|
||||||
|
[erc1155FungibleTokens[3]],
|
||||||
|
[ONE],
|
||||||
|
constants.NULL_BYTES,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const combo of feeAssetCombinations) {
|
for (const combo of assetCombinations) {
|
||||||
const description = combo.description || JSON.stringify(combo);
|
const description = combo.description || JSON.stringify(combo);
|
||||||
it(description, async () => {
|
it(description, async () => {
|
||||||
// Create orders to match. For ERC20s, there will be a spread.
|
// Create orders to match. For ERC20s, there will be a spread.
|
||||||
const leftMakerAssetAmount = combo.leftMaker.startsWith('ERC20')
|
const leftMakerAssetAmount = _.includes(fungibleTypes, combo.leftMaker)
|
||||||
? Web3Wrapper.toBaseUnitAmount(15, 18)
|
? Web3Wrapper.toBaseUnitAmount(15, 18)
|
||||||
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
||||||
const leftTakerAssetAmount = combo.rightMaker.startsWith('ERC20')
|
const leftTakerAssetAmount = _.includes(fungibleTypes, combo.rightMaker)
|
||||||
? Web3Wrapper.toBaseUnitAmount(30, 18)
|
? Web3Wrapper.toBaseUnitAmount(30, 18)
|
||||||
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
||||||
const rightMakerAssetAmount = combo.rightMaker.startsWith('ERC20')
|
const rightMakerAssetAmount = _.includes(fungibleTypes, combo.rightMaker)
|
||||||
? Web3Wrapper.toBaseUnitAmount(30, 18)
|
? Web3Wrapper.toBaseUnitAmount(30, 18)
|
||||||
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
||||||
const rightTakerAssetAmount = combo.leftMaker.startsWith('ERC20')
|
const rightTakerAssetAmount = _.includes(fungibleTypes, combo.leftMaker)
|
||||||
? Web3Wrapper.toBaseUnitAmount(14, 18)
|
? Web3Wrapper.toBaseUnitAmount(14, 18)
|
||||||
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
||||||
const leftMakerFeeAssetAmount = combo.leftMakerFee.startsWith('ERC20')
|
const leftMakerFeeAssetAmount = _.includes(fungibleTypes, combo.leftMakerFee)
|
||||||
? Web3Wrapper.toBaseUnitAmount(8, 12)
|
? Web3Wrapper.toBaseUnitAmount(8, 12)
|
||||||
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
||||||
const rightMakerFeeAssetAmount = combo.rightMakerFee.startsWith('ERC20')
|
const rightMakerFeeAssetAmount = _.includes(fungibleTypes, combo.rightMakerFee)
|
||||||
? Web3Wrapper.toBaseUnitAmount(7, 12)
|
? Web3Wrapper.toBaseUnitAmount(7, 12)
|
||||||
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
||||||
const leftTakerFeeAssetAmount = combo.leftTakerFee.startsWith('ERC20')
|
const leftTakerFeeAssetAmount = _.includes(fungibleTypes, combo.leftTakerFee)
|
||||||
? Web3Wrapper.toBaseUnitAmount(6, 12)
|
? Web3Wrapper.toBaseUnitAmount(6, 12)
|
||||||
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
||||||
const rightTakerFeeAssetAmount = combo.rightTakerFee.startsWith('ERC20')
|
const rightTakerFeeAssetAmount = _.includes(fungibleTypes, combo.rightTakerFee)
|
||||||
? Web3Wrapper.toBaseUnitAmount(5, 12)
|
? Web3Wrapper.toBaseUnitAmount(5, 12)
|
||||||
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
: Web3Wrapper.toBaseUnitAmount(1, 0);
|
||||||
const leftMakerAssetReceivedByTakerAmount = combo.leftMaker.startsWith('ERC20')
|
const leftMakerAssetReceivedByTakerAmount = _.includes(fungibleTypes, combo.leftMaker)
|
||||||
? leftMakerAssetAmount.minus(rightTakerAssetAmount)
|
? leftMakerAssetAmount.minus(rightTakerAssetAmount)
|
||||||
: Web3Wrapper.toBaseUnitAmount(0, 0);
|
: Web3Wrapper.toBaseUnitAmount(0, 0);
|
||||||
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
|
||||||
makerAssetData: getAssetData(combo.leftMaker, makerAddressLeft),
|
makerAssetData: getAssetData(combo.leftMaker),
|
||||||
takerAssetData: getAssetData(combo.rightMaker, makerAddressRight),
|
takerAssetData: getAssetData(combo.rightMaker),
|
||||||
makerFeeAssetData: getAssetData(combo.leftMakerFee, makerAddressLeft),
|
makerFeeAssetData: getAssetData(combo.leftMakerFee),
|
||||||
takerFeeAssetData: getAssetData(combo.leftTakerFee, takerAddress),
|
takerFeeAssetData: getAssetData(combo.leftTakerFee),
|
||||||
makerAssetAmount: leftMakerAssetAmount,
|
makerAssetAmount: leftMakerAssetAmount,
|
||||||
takerAssetAmount: leftTakerAssetAmount,
|
takerAssetAmount: leftTakerAssetAmount,
|
||||||
makerFee: leftMakerFeeAssetAmount,
|
makerFee: leftMakerFeeAssetAmount,
|
||||||
takerFee: leftTakerFeeAssetAmount,
|
takerFee: leftTakerFeeAssetAmount,
|
||||||
});
|
});
|
||||||
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
|
||||||
makerAssetData: getAssetData(combo.rightMaker, makerAddressRight),
|
makerAssetData: getAssetData(combo.rightMaker),
|
||||||
takerAssetData: getAssetData(combo.leftMaker, makerAddressLeft),
|
takerAssetData: getAssetData(combo.leftMaker),
|
||||||
makerFeeAssetData: getAssetData(combo.rightMakerFee, makerAddressRight),
|
makerFeeAssetData: getAssetData(combo.rightMakerFee),
|
||||||
takerFeeAssetData: getAssetData(combo.rightTakerFee, takerAddress),
|
takerFeeAssetData: getAssetData(combo.rightTakerFee),
|
||||||
makerAssetAmount: rightMakerAssetAmount,
|
makerAssetAmount: rightMakerAssetAmount,
|
||||||
takerAssetAmount: rightTakerAssetAmount,
|
takerAssetAmount: rightTakerAssetAmount,
|
||||||
makerFee: rightMakerFeeAssetAmount,
|
makerFee: rightMakerFeeAssetAmount,
|
||||||
@ -1536,15 +1712,15 @@ describe('matchOrders', () => {
|
|||||||
const expectedTransferAmounts = {
|
const expectedTransferAmounts = {
|
||||||
// Left Maker
|
// Left Maker
|
||||||
leftMakerAssetSoldByLeftMakerAmount: leftMakerAssetAmount,
|
leftMakerAssetSoldByLeftMakerAmount: leftMakerAssetAmount,
|
||||||
leftMakerFeeAssetPaidByLeftMakerAmount: leftMakerFeeAssetAmount, // 100%
|
leftMakerFeeAssetPaidByLeftMakerAmount: leftMakerFeeAssetAmount,
|
||||||
// Right Maker
|
// Right Maker
|
||||||
rightMakerAssetSoldByRightMakerAmount: rightMakerAssetAmount,
|
rightMakerAssetSoldByRightMakerAmount: rightMakerAssetAmount,
|
||||||
leftMakerAssetBoughtByRightMakerAmount: rightTakerAssetAmount,
|
leftMakerAssetBoughtByRightMakerAmount: rightTakerAssetAmount,
|
||||||
rightMakerFeeAssetPaidByRightMakerAmount: rightMakerFeeAssetAmount, // 100%
|
rightMakerFeeAssetPaidByRightMakerAmount: rightMakerFeeAssetAmount,
|
||||||
// Taker
|
// Taker
|
||||||
leftMakerAssetReceivedByTakerAmount,
|
leftMakerAssetReceivedByTakerAmount,
|
||||||
leftTakerFeeAssetPaidByTakerAmount: leftTakerFeeAssetAmount, // 100%
|
leftTakerFeeAssetPaidByTakerAmount: leftTakerFeeAssetAmount,
|
||||||
rightTakerFeeAssetPaidByTakerAmount: rightTakerFeeAssetAmount, // 100%
|
rightTakerFeeAssetPaidByTakerAmount: rightTakerFeeAssetAmount,
|
||||||
};
|
};
|
||||||
if (!combo.shouldFail) {
|
if (!combo.shouldFail) {
|
||||||
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
await matchOrderTester.matchOrdersAndAssertEffectsAsync(
|
||||||
@ -1564,18 +1740,4 @@ describe('matchOrders', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function getIndividualERC1155Holdings(
|
|
||||||
erc1155HoldingsByOwner: ERC1155HoldingsByOwner,
|
|
||||||
tokenAddress: string,
|
|
||||||
ownerAddress: string,
|
|
||||||
): IndividualERC1155Holdings {
|
|
||||||
return {
|
|
||||||
fungible: erc1155HoldingsByOwner.fungible[ownerAddress][tokenAddress],
|
|
||||||
nonFungible: _.uniqBy(_.flatten(_.values(
|
|
||||||
erc1155HoldingsByOwner.nonFungible[ownerAddress][tokenAddress])),
|
|
||||||
v => v.toString(10),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// tslint:disable-line:max-file-line-count
|
// tslint:disable-line:max-file-line-count
|
||||||
|
@ -96,24 +96,24 @@ export class AssetWrapper {
|
|||||||
assetProxyData.tokenAddress,
|
assetProxyData.tokenAddress,
|
||||||
assetProxyData.tokenId,
|
assetProxyData.tokenId,
|
||||||
);
|
);
|
||||||
if (!doesTokenExist && desiredBalance.gt(0)) {
|
if (!doesTokenExist && desiredBalance.gte(1)) {
|
||||||
await erc721Wrapper.mintAsync(assetProxyData.tokenAddress, assetProxyData.tokenId, userAddress);
|
await erc721Wrapper.mintAsync(assetProxyData.tokenAddress, assetProxyData.tokenId, userAddress);
|
||||||
return;
|
return;
|
||||||
} else if (!doesTokenExist && desiredBalance.lte(0)) {
|
} else if (!doesTokenExist && desiredBalance.lt(1)) {
|
||||||
return; // noop
|
return; // noop
|
||||||
}
|
}
|
||||||
const tokenOwner = await erc721Wrapper.ownerOfAsync(
|
const tokenOwner = await erc721Wrapper.ownerOfAsync(
|
||||||
assetProxyData.tokenAddress,
|
assetProxyData.tokenAddress,
|
||||||
assetProxyData.tokenId,
|
assetProxyData.tokenId,
|
||||||
);
|
);
|
||||||
if (userAddress !== tokenOwner && desiredBalance.gt(0)) {
|
if (userAddress !== tokenOwner && desiredBalance.gte(1)) {
|
||||||
await erc721Wrapper.transferFromAsync(
|
await erc721Wrapper.transferFromAsync(
|
||||||
assetProxyData.tokenAddress,
|
assetProxyData.tokenAddress,
|
||||||
assetProxyData.tokenId,
|
assetProxyData.tokenId,
|
||||||
tokenOwner,
|
tokenOwner,
|
||||||
userAddress,
|
userAddress,
|
||||||
);
|
);
|
||||||
} else if (tokenOwner === userAddress && desiredBalance.lte(0)) {
|
} else if (tokenOwner === userAddress && desiredBalance.lt(1)) {
|
||||||
// Burn token
|
// Burn token
|
||||||
await erc721Wrapper.transferFromAsync(
|
await erc721Wrapper.transferFromAsync(
|
||||||
assetProxyData.tokenAddress,
|
assetProxyData.tokenAddress,
|
||||||
@ -123,8 +123,8 @@ export class AssetWrapper {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
} else if (
|
} else if (
|
||||||
(userAddress !== tokenOwner && desiredBalance.lte(0)) ||
|
(userAddress !== tokenOwner && desiredBalance.lt(1)) ||
|
||||||
(tokenOwner === userAddress && desiredBalance.gt(0))
|
(tokenOwner === userAddress && desiredBalance.gte(1))
|
||||||
) {
|
) {
|
||||||
return; // noop
|
return; // noop
|
||||||
}
|
}
|
||||||
@ -168,7 +168,7 @@ export class AssetWrapper {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const nftOwner = await assetWrapper.getOwnerOfAsync(tokenId);
|
const nftOwner = await assetWrapper.getOwnerOfAsync(tokenId);
|
||||||
if (scaledDesiredBalance.gt(0)) {
|
if (scaledDesiredBalance.gte(1)) {
|
||||||
if (nftOwner === userAddress) {
|
if (nftOwner === userAddress) {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
} else if (nftOwner !== constants.NULL_ADDRESS) {
|
} else if (nftOwner !== constants.NULL_ADDRESS) {
|
||||||
|
@ -254,7 +254,8 @@ export class FillOrderCombinatorialUtils {
|
|||||||
// ExpirationTimeSecondsScenario.InPast,
|
// ExpirationTimeSecondsScenario.InPast,
|
||||||
];
|
];
|
||||||
const makerAssetDataScenario = [
|
const makerAssetDataScenario = [
|
||||||
AssetDataScenario.ERC20FiveDecimals,
|
// FeeAssetDataScenario.ERC20ZeroDecimals,
|
||||||
|
// AssetDataScenario.ERC20FiveDecimals,
|
||||||
AssetDataScenario.ERC20EighteenDecimals,
|
AssetDataScenario.ERC20EighteenDecimals,
|
||||||
AssetDataScenario.ERC721,
|
AssetDataScenario.ERC721,
|
||||||
AssetDataScenario.ERC1155Fungible,
|
AssetDataScenario.ERC1155Fungible,
|
||||||
@ -262,7 +263,8 @@ export class FillOrderCombinatorialUtils {
|
|||||||
AssetDataScenario.MultiAssetERC20,
|
AssetDataScenario.MultiAssetERC20,
|
||||||
];
|
];
|
||||||
const takerAssetDataScenario = [
|
const takerAssetDataScenario = [
|
||||||
AssetDataScenario.ERC20FiveDecimals,
|
// FeeAssetDataScenario.ERC20ZeroDecimals,
|
||||||
|
// AssetDataScenario.ERC20FiveDecimals,
|
||||||
AssetDataScenario.ERC20EighteenDecimals,
|
AssetDataScenario.ERC20EighteenDecimals,
|
||||||
AssetDataScenario.ERC721,
|
AssetDataScenario.ERC721,
|
||||||
AssetDataScenario.ERC1155Fungible,
|
AssetDataScenario.ERC1155Fungible,
|
||||||
@ -270,7 +272,8 @@ export class FillOrderCombinatorialUtils {
|
|||||||
AssetDataScenario.MultiAssetERC20,
|
AssetDataScenario.MultiAssetERC20,
|
||||||
];
|
];
|
||||||
const makerFeeAssetDataScenario = [
|
const makerFeeAssetDataScenario = [
|
||||||
FeeAssetDataScenario.ERC20FiveDecimals,
|
// FeeAssetDataScenario.ERC20ZeroDecimals,
|
||||||
|
// FeeAssetDataScenario.ERC20FiveDecimals,
|
||||||
FeeAssetDataScenario.ERC20EighteenDecimals,
|
FeeAssetDataScenario.ERC20EighteenDecimals,
|
||||||
FeeAssetDataScenario.ERC721,
|
FeeAssetDataScenario.ERC721,
|
||||||
FeeAssetDataScenario.ERC1155Fungible,
|
FeeAssetDataScenario.ERC1155Fungible,
|
||||||
@ -280,7 +283,8 @@ export class FillOrderCombinatorialUtils {
|
|||||||
FeeAssetDataScenario.TakerToken,
|
FeeAssetDataScenario.TakerToken,
|
||||||
];
|
];
|
||||||
const takerFeeAssetDataScenario = [
|
const takerFeeAssetDataScenario = [
|
||||||
FeeAssetDataScenario.ERC20FiveDecimals,
|
// FeeAssetDataScenario.ERC20ZeroDecimals,
|
||||||
|
// FeeAssetDataScenario.ERC20FiveDecimals,
|
||||||
FeeAssetDataScenario.ERC20EighteenDecimals,
|
FeeAssetDataScenario.ERC20EighteenDecimals,
|
||||||
FeeAssetDataScenario.ERC721,
|
FeeAssetDataScenario.ERC721,
|
||||||
FeeAssetDataScenario.ERC1155Fungible,
|
FeeAssetDataScenario.ERC1155Fungible,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
export * from './exchange_wrapper';
|
export * from './exchange_wrapper';
|
||||||
export * from './match_order_tester';
|
|
||||||
export * from './exchange_data_encoder';
|
export * from './exchange_data_encoder';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
export * from './constants';
|
export * from './constants';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ERC20Wrapper, ERC721Wrapper } from '@0x/contracts-asset-proxy';
|
import { ERC1155ProxyWrapper, ERC20Wrapper, ERC721Wrapper } from '@0x/contracts-asset-proxy';
|
||||||
import { chaiSetup, OrderStatus, TokenBalancesByOwner } from '@0x/contracts-test-utils';
|
import { chaiSetup, ERC1155HoldingsByOwner, OrderStatus } from '@0x/contracts-test-utils';
|
||||||
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
|
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
|
||||||
import { AssetProxyId, SignedOrder } from '@0x/types';
|
import { AssetProxyId, SignedOrder } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
@ -14,6 +14,13 @@ const ZERO = new BigNumber(0);
|
|||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
export interface IndividualERC1155Holdings {
|
||||||
|
fungible: {
|
||||||
|
[tokenId: string]: BigNumber;
|
||||||
|
};
|
||||||
|
nonFungible: BigNumber[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface FillEventArgs {
|
export interface FillEventArgs {
|
||||||
orderHash: string;
|
orderHash: string;
|
||||||
makerAddress: string;
|
makerAddress: string;
|
||||||
@ -46,7 +53,32 @@ export interface MatchTransferAmounts {
|
|||||||
export interface MatchResults {
|
export interface MatchResults {
|
||||||
orders: MatchedOrders;
|
orders: MatchedOrders;
|
||||||
fills: FillEventArgs[];
|
fills: FillEventArgs[];
|
||||||
balances: TokenBalancesByOwner;
|
balances: TokenBalances;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ERC1155Holdings {
|
||||||
|
[owner: string]: {
|
||||||
|
[contract: string]: {
|
||||||
|
fungible: {
|
||||||
|
[tokenId: string]: BigNumber;
|
||||||
|
};
|
||||||
|
nonFungible: BigNumber[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenBalances {
|
||||||
|
erc20: {
|
||||||
|
[owner: string]: {
|
||||||
|
[contract: string]: BigNumber;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
erc721: {
|
||||||
|
[owner: string]: {
|
||||||
|
[contract: string]: BigNumber[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
erc1155: ERC1155Holdings;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MatchedOrders {
|
export interface MatchedOrders {
|
||||||
@ -66,14 +98,16 @@ export class MatchOrderTester {
|
|||||||
public exchangeWrapper: ExchangeWrapper;
|
public exchangeWrapper: ExchangeWrapper;
|
||||||
public erc20Wrapper: ERC20Wrapper;
|
public erc20Wrapper: ERC20Wrapper;
|
||||||
public erc721Wrapper: ERC721Wrapper;
|
public erc721Wrapper: ERC721Wrapper;
|
||||||
|
public erc1155ProxyWrapper: ERC1155ProxyWrapper;
|
||||||
public matchOrdersCallAsync?: MatchOrdersAsyncCall;
|
public matchOrdersCallAsync?: MatchOrdersAsyncCall;
|
||||||
private readonly _initialTokenBalancesPromise: Promise<TokenBalancesByOwner>;
|
private readonly _initialTokenBalancesPromise: Promise<TokenBalances>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs new MatchOrderTester.
|
* Constructs new MatchOrderTester.
|
||||||
* @param exchangeWrapper Used to call to the Exchange.
|
* @param exchangeWrapper Used to call to the Exchange.
|
||||||
* @param erc20Wrapper Used to fetch ERC20 balances.
|
* @param erc20Wrapper Used to fetch ERC20 balances.
|
||||||
* @param erc721Wrapper Used to fetch ERC721 token owners.
|
* @param erc721Wrapper Used to fetch ERC721 token owners.
|
||||||
|
* @param erc1155Wrapper Used to fetch ERC1155 token owners.
|
||||||
* @param matchOrdersCallAsync Optional, custom caller for
|
* @param matchOrdersCallAsync Optional, custom caller for
|
||||||
* `ExchangeWrapper.matchOrdersAsync()`.
|
* `ExchangeWrapper.matchOrdersAsync()`.
|
||||||
*/
|
*/
|
||||||
@ -81,11 +115,13 @@ export class MatchOrderTester {
|
|||||||
exchangeWrapper: ExchangeWrapper,
|
exchangeWrapper: ExchangeWrapper,
|
||||||
erc20Wrapper: ERC20Wrapper,
|
erc20Wrapper: ERC20Wrapper,
|
||||||
erc721Wrapper: ERC721Wrapper,
|
erc721Wrapper: ERC721Wrapper,
|
||||||
|
erc1155ProxyWrapper: ERC1155ProxyWrapper,
|
||||||
matchOrdersCallAsync?: MatchOrdersAsyncCall,
|
matchOrdersCallAsync?: MatchOrdersAsyncCall,
|
||||||
) {
|
) {
|
||||||
this.exchangeWrapper = exchangeWrapper;
|
this.exchangeWrapper = exchangeWrapper;
|
||||||
this.erc20Wrapper = erc20Wrapper;
|
this.erc20Wrapper = erc20Wrapper;
|
||||||
this.erc721Wrapper = erc721Wrapper;
|
this.erc721Wrapper = erc721Wrapper;
|
||||||
|
this.erc1155ProxyWrapper = erc1155ProxyWrapper;
|
||||||
this.matchOrdersCallAsync = matchOrdersCallAsync;
|
this.matchOrdersCallAsync = matchOrdersCallAsync;
|
||||||
this._initialTokenBalancesPromise = this.getBalancesAsync();
|
this._initialTokenBalancesPromise = this.getBalancesAsync();
|
||||||
}
|
}
|
||||||
@ -103,7 +139,7 @@ export class MatchOrderTester {
|
|||||||
orders: MatchedOrders,
|
orders: MatchedOrders,
|
||||||
takerAddress: string,
|
takerAddress: string,
|
||||||
expectedTransferAmounts: Partial<MatchTransferAmounts>,
|
expectedTransferAmounts: Partial<MatchTransferAmounts>,
|
||||||
initialTokenBalances?: TokenBalancesByOwner,
|
initialTokenBalances?: TokenBalances,
|
||||||
): Promise<MatchResults> {
|
): Promise<MatchResults> {
|
||||||
await assertInitialOrderStatesAsync(orders, this.exchangeWrapper);
|
await assertInitialOrderStatesAsync(orders, this.exchangeWrapper);
|
||||||
// Get the token balances before executing `matchOrders()`.
|
// Get the token balances before executing `matchOrders()`.
|
||||||
@ -136,8 +172,8 @@ export class MatchOrderTester {
|
|||||||
/**
|
/**
|
||||||
* Fetch the current token balances of all known accounts.
|
* Fetch the current token balances of all known accounts.
|
||||||
*/
|
*/
|
||||||
public async getBalancesAsync(): Promise<TokenBalancesByOwner> {
|
public async getBalancesAsync(): Promise<TokenBalances> {
|
||||||
return getTokenBalancesAsync(this.erc20Wrapper, this.erc721Wrapper);
|
return getTokenBalancesAsync(this.erc20Wrapper, this.erc721Wrapper, this.erc1155ProxyWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _executeMatchOrdersAsync(
|
private async _executeMatchOrdersAsync(
|
||||||
@ -203,7 +239,7 @@ function toFullMatchTransferAmounts(partial: Partial<MatchTransferAmounts>): Mat
|
|||||||
function simulateMatchOrders(
|
function simulateMatchOrders(
|
||||||
orders: MatchedOrders,
|
orders: MatchedOrders,
|
||||||
takerAddress: string,
|
takerAddress: string,
|
||||||
tokenBalances: TokenBalancesByOwner,
|
tokenBalances: TokenBalances,
|
||||||
transferAmounts: MatchTransferAmounts,
|
transferAmounts: MatchTransferAmounts,
|
||||||
): MatchResults {
|
): MatchResults {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
@ -336,8 +372,47 @@ function transferAsset(
|
|||||||
const tokenId = erc721AssetData.tokenId;
|
const tokenId = erc721AssetData.tokenId;
|
||||||
const fromTokens = matchResults.balances.erc721[fromAddress][assetAddress];
|
const fromTokens = matchResults.balances.erc721[fromAddress][assetAddress];
|
||||||
const toTokens = matchResults.balances.erc721[toAddress][assetAddress];
|
const toTokens = matchResults.balances.erc721[toAddress][assetAddress];
|
||||||
_.remove(fromTokens, tokenId);
|
if (amount.gte(1)) {
|
||||||
toTokens.push(tokenId);
|
const tokenIndex = _.findIndex(fromTokens, t => t.eq(tokenId));
|
||||||
|
if (tokenIndex !== -1) {
|
||||||
|
fromTokens.splice(tokenIndex, 1);
|
||||||
|
toTokens.push(tokenId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AssetProxyId.ERC1155: {
|
||||||
|
const erc1155AssetData = assetDataUtils.decodeERC1155AssetData(assetData);
|
||||||
|
const assetAddress = erc1155AssetData.tokenAddress;
|
||||||
|
const fromBalances = matchResults.balances.erc1155[fromAddress][assetAddress];
|
||||||
|
const toBalances = matchResults.balances.erc1155[toAddress][assetAddress];
|
||||||
|
for (const i of _.times(erc1155AssetData.tokenIds.length)) {
|
||||||
|
const tokenId = erc1155AssetData.tokenIds[i];
|
||||||
|
const tokenValue = erc1155AssetData.tokenValues[i];
|
||||||
|
const tokenAmount = amount.times(tokenValue);
|
||||||
|
if (tokenAmount.gt(0)) {
|
||||||
|
const tokenIndex = _.findIndex(fromBalances.nonFungible, t => t.eq(tokenId));
|
||||||
|
if (tokenIndex !== -1) {
|
||||||
|
// Transfer a non-fungible.
|
||||||
|
fromBalances.nonFungible.splice(tokenIndex, 1);
|
||||||
|
toBalances.nonFungible.push(tokenId);
|
||||||
|
} else {
|
||||||
|
// Transfer a fungible.
|
||||||
|
const _tokenId = tokenId.toString(10);
|
||||||
|
fromBalances.fungible[_tokenId] = fromBalances.fungible[_tokenId].minus(tokenAmount);
|
||||||
|
toBalances.fungible[_tokenId] = toBalances.fungible[_tokenId].plus(tokenAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AssetProxyId.MultiAsset: {
|
||||||
|
const multiAssetData = assetDataUtils.decodeMultiAssetData(assetData);
|
||||||
|
for (const i of _.times(multiAssetData.amounts.length)) {
|
||||||
|
const nestedAmount = amount.times(multiAssetData.amounts[i]);
|
||||||
|
const nestedAssetData = multiAssetData.nestedAssetData[i];
|
||||||
|
transferAsset(fromAddress, toAddress, nestedAmount, nestedAssetData, matchResults);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -355,7 +430,7 @@ function transferAsset(
|
|||||||
async function assertMatchResultsAsync(
|
async function assertMatchResultsAsync(
|
||||||
matchResults: MatchResults,
|
matchResults: MatchResults,
|
||||||
transactionReceipt: TransactionReceiptWithDecodedLogs,
|
transactionReceipt: TransactionReceiptWithDecodedLogs,
|
||||||
actualTokenBalances: TokenBalancesByOwner,
|
actualTokenBalances: TokenBalances,
|
||||||
exchangeWrapper: ExchangeWrapper,
|
exchangeWrapper: ExchangeWrapper,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Check the fill events.
|
// Check the fill events.
|
||||||
@ -462,21 +537,8 @@ function extractFillEventsfromReceipt(receipt: TransactionReceiptWithDecodedLogs
|
|||||||
* @param expectedBalances Expected balances.
|
* @param expectedBalances Expected balances.
|
||||||
* @param actualBalances Actual balances.
|
* @param actualBalances Actual balances.
|
||||||
*/
|
*/
|
||||||
function assertBalances(expectedBalances: TokenBalancesByOwner, actualBalances: TokenBalancesByOwner): void {
|
function assertBalances(expectedBalances: TokenBalances, actualBalances: TokenBalances): void {
|
||||||
// ERC20 Balances
|
expect(encodeTokenBalances(expectedBalances)).to.deep.equal(encodeTokenBalances(actualBalances));
|
||||||
expect(actualBalances.erc20, 'ERC20 balances').to.deep.equal(expectedBalances.erc20);
|
|
||||||
// ERC721 Token Ids
|
|
||||||
const sortedExpectedERC721Balances = _.mapValues(expectedBalances.erc721, tokenIdsByOwner => {
|
|
||||||
_.mapValues(tokenIdsByOwner, tokenIds => {
|
|
||||||
_.sortBy(tokenIds);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const sortedActualERC721Balances = _.mapValues(actualBalances.erc721, tokenIdsByOwner => {
|
|
||||||
_.mapValues(tokenIdsByOwner, tokenIds => {
|
|
||||||
_.sortBy(tokenIds);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
expect(sortedExpectedERC721Balances, 'ERC721 balances').to.deep.equal(sortedActualERC721Balances);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -533,17 +595,57 @@ async function assertPostExchangeStateAsync(
|
|||||||
* Retrive the current token balances of all known addresses.
|
* Retrive the current token balances of all known addresses.
|
||||||
* @param erc20Wrapper The ERC20Wrapper instance.
|
* @param erc20Wrapper The ERC20Wrapper instance.
|
||||||
* @param erc721Wrapper The ERC721Wrapper instance.
|
* @param erc721Wrapper The ERC721Wrapper instance.
|
||||||
* @return A promise that resolves to a `TokenBalancesByOwner`.
|
* @param erc1155Wrapper The ERC1155ProxyWrapper instance.
|
||||||
|
* @return A promise that resolves to a `TokenBalances`.
|
||||||
*/
|
*/
|
||||||
export async function getTokenBalancesAsync(
|
export async function getTokenBalancesAsync(
|
||||||
erc20Wrapper: ERC20Wrapper,
|
erc20Wrapper: ERC20Wrapper,
|
||||||
erc721Wrapper: ERC721Wrapper,
|
erc721Wrapper: ERC721Wrapper,
|
||||||
): Promise<TokenBalancesByOwner> {
|
erc1155ProxyWrapper: ERC1155ProxyWrapper,
|
||||||
const [erc20, erc721] = await Promise.all([erc20Wrapper.getBalancesAsync(), erc721Wrapper.getBalancesAsync()]);
|
): Promise<TokenBalances> {
|
||||||
|
const [erc20, erc721, erc1155] = await Promise.all([
|
||||||
|
erc20Wrapper.getBalancesAsync(),
|
||||||
|
erc721Wrapper.getBalancesAsync(),
|
||||||
|
erc1155ProxyWrapper.getBalancesAsync(),
|
||||||
|
]);
|
||||||
return {
|
return {
|
||||||
erc20,
|
erc20,
|
||||||
erc721,
|
erc721,
|
||||||
|
erc1155: transformERC1155Holdings(erc1155),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restructures `ERC1155HoldingsByOwner` to be compatible with `TokenBalances.erc1155`.
|
||||||
|
* @param erc1155HoldingsByOwner Holdings returned by `ERC1155ProxyWrapper.getBalancesAsync()`.
|
||||||
|
*/
|
||||||
|
function transformERC1155Holdings(erc1155HoldingsByOwner: ERC1155HoldingsByOwner): ERC1155Holdings {
|
||||||
|
const result = {};
|
||||||
|
for (const owner of _.keys(erc1155HoldingsByOwner.fungible)) {
|
||||||
|
for (const contract of _.keys(erc1155HoldingsByOwner.fungible[owner])) {
|
||||||
|
_.set(result as any, [owner, contract, 'fungible'], erc1155HoldingsByOwner.fungible[owner][contract]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const owner of _.keys(erc1155HoldingsByOwner.nonFungible)) {
|
||||||
|
for (const contract of _.keys(erc1155HoldingsByOwner.nonFungible[owner])) {
|
||||||
|
const tokenIds = _.flatten(_.values(erc1155HoldingsByOwner.nonFungible[owner][contract]));
|
||||||
|
_.set(result as any, [owner, contract, 'nonFungible'], _.uniqBy(tokenIds, v => v.toString(10)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeTokenBalances(obj: any): any {
|
||||||
|
if (!_.isPlainObject(obj)) {
|
||||||
|
if (BigNumber.isBigNumber(obj)) {
|
||||||
|
return obj.toString(10);
|
||||||
|
}
|
||||||
|
if (_.isArray(obj)) {
|
||||||
|
return _.sortBy(obj, v => encodeTokenBalances(v));
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
const keys = _.keys(obj).sort();
|
||||||
|
return _.zip(keys, keys.map(k => encodeTokenBalances(obj[k])));
|
||||||
|
}
|
||||||
// tslint:disable-line:max-file-line-count
|
// tslint:disable-line:max-file-line-count
|
||||||
|
Loading…
x
Reference in New Issue
Block a user