Added ERC1155Proxy tests when data overlaps values in asset data

This commit is contained in:
Greg Hysen 2019-05-22 08:45:24 -07:00
parent 7ee19e1306
commit 8bae0b81aa

View File

@ -752,6 +752,7 @@ describe('ERC1155Proxy', () => {
valuesToTransfer,
receiverCallbackData,
);
// remove the function selector and contract address from check, as these change on each test
const offsetToTokenIds = 74;
const assetDataWithoutContractAddress = assetData.substr(offsetToTokenIds);
const expectedAssetDataWithoutContractAddress =
@ -789,6 +790,268 @@ describe('ERC1155Proxy', () => {
];
expect(finalBalances).to.be.deep.equal(expectedFinalBalances);
});
it('should successfully transfer if token values and data are abi encoded to same entry in calldata', async () => {
/**
* This test ensures that scaling the values does not simultaneously scale the data.
* Note that this test is slightly more contrived than the test above, as asset data must be
* intentionally hand-modified to produce this result: a functioning abi encoder will not produce it.
*/
///// Step 1/5 /////
// Create tokens with ids [1, 2, 3, 4] and mint a balance of 4 for the `spender`
const tokensToCreate = [new BigNumber(1), new BigNumber(2), new BigNumber(3), new BigNumber(4)];
const spenderInitialBalance = new BigNumber(4);
const receiverInitialBalance = new BigNumber(0);
const tokenUri = '';
for (const tokenToCreate of tokensToCreate) {
// create token
await erc1155Wrapper.getContract().createWithType.awaitTransactionSuccessAsync(
tokenToCreate,
tokenUri,
{
from: owner,
},
constants.AWAIT_TRANSACTION_MINED_MS,
);
// mint balance for spender
await erc1155Wrapper.getContract().mintFungible.awaitTransactionSuccessAsync(
tokenToCreate,
[spender],
[spenderInitialBalance],
{
from: owner,
},
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
///// Step 2/5 /////
// Check balances before transfer
const balanceHolders = [
spender,
spender,
spender,
spender,
receiverContract,
receiverContract,
receiverContract,
receiverContract,
];
const balanceTokens = tokensToCreate.concat(tokensToCreate);
const initialBalances = await erc1155Wrapper.getBalancesAsync(balanceHolders, balanceTokens);
const expectedInitialBalances = [
spenderInitialBalance, // Token ID 1 / Spender Balance
spenderInitialBalance, // Token ID 2 / Spender Balance
spenderInitialBalance, // Token ID 3 / Spender Balance
spenderInitialBalance, // Token ID 4 / Spender Balance
receiverInitialBalance, // Token ID 1 / Receiver Balance
receiverInitialBalance, // Token ID 2 / Receiver Balance
receiverInitialBalance, // Token ID 3 / Receiver Balance
receiverInitialBalance, // Token ID 4 / Receiver Balance
];
expect(initialBalances).to.be.deep.equal(expectedInitialBalances);
///// Step 3/5 /////
// Create optimized calldata. We format like the table below.
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 // ERC1155 contract address
// 0x20 0000000000000000000000000000000000000000000000000000000000000080 // Offset to token IDs
// 0x40 00000000000000000000000000000000000000000000000000000000000000e0 // Offset to token values
// 0x60 00000000000000000000000000000000000000000000000000000000000000e0 // Offset to data (same as values)
// 0x80 0000000000000000000000000000000000000000000000000000000000000002 // Length of token Ids
// 0xA0 0000000000000000000000000000000000000000000000000000000000000001 // First Token ID
// 0xC0 0000000000000000000000000000000000000000000000000000000000000002 // Second Token ID
// 0xE0 0000000000000000000000000000000000000000000000000000000000000002 // Length of values (Length of data)
// 0x100 0000000000000000000000000000000000000000000000000000000000000002 // First Value
// 0x120 0000000000000000000000000000000000000000000000000000000000000002 // Second Value
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const tokensToTransfer = [new BigNumber(1), new BigNumber(2)];
const valuesToTransfer = [new BigNumber(2), new BigNumber(2)];
const valueMultiplier = new BigNumber(2);
// create callback data that is the encoded version of `valuesToTransfer`
const generatedAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// remove the function selector and contract address from check, as these change on each test
const offsetToTokenIds = 74;
const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds);
const assetDataParameters =
'000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002';
const assetData = `${assetDataSelectorAndContractAddress}${assetDataParameters}`;
///// Step 4/5 /////
// Transfer tokens
const txReceipt = await erc1155ProxyWrapper.transferFromWithLogsAsync(
spender,
receiverContract,
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
valueMultiplier,
receiverCallbackData,
authorized,
assetData,
);
// check receiver log ignored extra asset data
expect(txReceipt.logs.length).to.be.equal(2);
const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs<
DummyERC1155ReceiverBatchTokenReceivedEventArgs
>;
expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address);
expect(receiverLog.args.from).to.be.equal(spender);
expect(receiverLog.args.tokenIds.length).to.be.deep.equal(2);
expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]);
expect(receiverLog.args.tokenIds[1]).to.be.bignumber.equal(tokensToTransfer[1]);
expect(receiverLog.args.tokenValues.length).to.be.deep.equal(2);
expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(valuesToTransfer[0].times(valueMultiplier));
expect(receiverLog.args.tokenValues[1]).to.be.bignumber.equal(valuesToTransfer[1].times(valueMultiplier));
expect(receiverLog.args.data).to.be.deep.equal('0x0000');
///// Step 5/5 /////
// Validate final balances
const finalBalances = await erc1155Wrapper.getBalancesAsync(balanceHolders, balanceTokens);
const expectedAmountsTransferred = _.map(valuesToTransfer, value => {
return value.times(valueMultiplier);
});
const expectedFinalBalances = [
spenderInitialBalance.minus(expectedAmountsTransferred[0]), // Token ID 1 / Spender Balance
spenderInitialBalance.minus(expectedAmountsTransferred[1]), // Token ID 2 / Spender Balance
spenderInitialBalance, // Token ID 3 / Spender Balance
spenderInitialBalance, // Token ID 4 / Spender Balance
receiverInitialBalance.plus(expectedAmountsTransferred[0]), // Token ID 1 / Receiver Balance
receiverInitialBalance.plus(expectedAmountsTransferred[1]), // Token ID 2 / Receiver Balance
receiverInitialBalance, // Token ID 3 / Receiver Balance
receiverInitialBalance, // Token ID 4 / Receiver Balance
];
expect(finalBalances).to.be.deep.equal(expectedFinalBalances);
});
it('should successfully transfer if token ids, values and data are abi encoded to same entry in calldata', async () => {
/**
* This test combines the two tests above.
* Similar to the test above, the asset data must be manually constructed.
*/
///// Step 1/5 /////
// Create tokens with ids [1, 2, 3, 4] and mint a balance of 4 for the `spender`
const tokensToCreate = [new BigNumber(1), new BigNumber(2), new BigNumber(3), new BigNumber(4)];
const spenderInitialBalance = new BigNumber(4);
const receiverInitialBalance = new BigNumber(0);
const tokenUri = '';
for (const tokenToCreate of tokensToCreate) {
// create token
await erc1155Wrapper.getContract().createWithType.awaitTransactionSuccessAsync(
tokenToCreate,
tokenUri,
{
from: owner,
},
constants.AWAIT_TRANSACTION_MINED_MS,
);
// mint balance for spender
await erc1155Wrapper.getContract().mintFungible.awaitTransactionSuccessAsync(
tokenToCreate,
[spender],
[spenderInitialBalance],
{
from: owner,
},
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
///// Step 2/5 /////
// Check balances before transfer
const balanceHolders = [
spender,
spender,
spender,
spender,
receiverContract,
receiverContract,
receiverContract,
receiverContract,
];
const balanceTokens = tokensToCreate.concat(tokensToCreate);
const initialBalances = await erc1155Wrapper.getBalancesAsync(balanceHolders, balanceTokens);
const expectedInitialBalances = [
spenderInitialBalance, // Token ID 1 / Spender Balance
spenderInitialBalance, // Token ID 2 / Spender Balance
spenderInitialBalance, // Token ID 3 / Spender Balance
spenderInitialBalance, // Token ID 4 / Spender Balance
receiverInitialBalance, // Token ID 1 / Receiver Balance
receiverInitialBalance, // Token ID 2 / Receiver Balance
receiverInitialBalance, // Token ID 3 / Receiver Balance
receiverInitialBalance, // Token ID 4 / Receiver Balance
];
expect(initialBalances).to.be.deep.equal(expectedInitialBalances);
///// Step 3/5 /////
// Create optimized calldata. We format like the table below.
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082 // ERC1155 contract address
// 0x20 0000000000000000000000000000000000000000000000000000000000000080 // Offset to token IDs
// 0x40 0000000000000000000000000000000000000000000000000000000000000080 // Offset to token values
// 0x60 0000000000000000000000000000000000000000000000000000000000000080 // Offset to data (same as values)
// 0x80 0000000000000000000000000000000000000000000000000000000000000002 // Length of token Ids (Length of values / data)
// 0xA0 0000000000000000000000000000000000000000000000000000000000000001 // First Token ID (First Value)
// 0xC0 0000000000000000000000000000000000000000000000000000000000000002 // Second Token ID (Second Value)
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const tokensToTransfer = [new BigNumber(1), new BigNumber(2)];
const valuesToTransfer = [new BigNumber(1), new BigNumber(2)];
const valueMultiplier = new BigNumber(2);
// create callback data that is the encoded version of `valuesToTransfer`
const generatedAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// remove the function selector and contract address from check, as these change on each test
const offsetToTokenIds = 74;
const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds);
const assetDataParameters =
'000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
const assetData = `${assetDataSelectorAndContractAddress}${assetDataParameters}`;
///// Step 4/5 /////
// Transfer tokens
const txReceipt = await erc1155ProxyWrapper.transferFromWithLogsAsync(
spender,
receiverContract,
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
valueMultiplier,
receiverCallbackData,
authorized,
assetData,
);
// check receiver log ignored extra asset data
expect(txReceipt.logs.length).to.be.equal(2);
const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs<
DummyERC1155ReceiverBatchTokenReceivedEventArgs
>;
expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address);
expect(receiverLog.args.from).to.be.equal(spender);
expect(receiverLog.args.tokenIds.length).to.be.deep.equal(2);
expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]);
expect(receiverLog.args.tokenIds[1]).to.be.bignumber.equal(tokensToTransfer[1]);
expect(receiverLog.args.tokenValues.length).to.be.deep.equal(2);
expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(valuesToTransfer[0].times(valueMultiplier));
expect(receiverLog.args.tokenValues[1]).to.be.bignumber.equal(valuesToTransfer[1].times(valueMultiplier));
expect(receiverLog.args.data).to.be.deep.equal('0x0000');
///// Step 5/5 /////
// Validate final balances
const finalBalances = await erc1155Wrapper.getBalancesAsync(balanceHolders, balanceTokens);
const expectedAmountsTransferred = _.map(valuesToTransfer, value => {
return value.times(valueMultiplier);
});
const expectedFinalBalances = [
spenderInitialBalance.minus(expectedAmountsTransferred[0]), // Token ID 1 / Spender Balance
spenderInitialBalance.minus(expectedAmountsTransferred[1]), // Token ID 2 / Spender Balance
spenderInitialBalance, // Token ID 3 / Spender Balance
spenderInitialBalance, // Token ID 4 / Spender Balance
receiverInitialBalance.plus(expectedAmountsTransferred[0]), // Token ID 1 / Receiver Balance
receiverInitialBalance.plus(expectedAmountsTransferred[1]), // Token ID 2 / Receiver Balance
receiverInitialBalance, // Token ID 3 / Receiver Balance
receiverInitialBalance, // Token ID 4 / Receiver Balance
];
expect(finalBalances).to.be.deep.equal(expectedFinalBalances);
});
it('should transfer nothing if value is zero', async () => {
// setup test parameters
const tokenHolders = [spender, receiver];