diff options
Diffstat (limited to 'packages/contracts')
-rw-r--r-- | packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol | 2 | ||||
-rw-r--r-- | packages/contracts/test/asset_proxy/proxies.ts | 355 |
2 files changed, 342 insertions, 15 deletions
diff --git a/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol b/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol index 531ee2264..fc86ee942 100644 --- a/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol +++ b/packages/contracts/contracts/protocol/AssetProxy/MultiAssetProxy.sol @@ -286,4 +286,4 @@ contract MultiAssetProxy is { return PROXY_ID; } -}
\ No newline at end of file +} diff --git a/packages/contracts/test/asset_proxy/proxies.ts b/packages/contracts/test/asset_proxy/proxies.ts index 94ea408f5..913c91320 100644 --- a/packages/contracts/test/asset_proxy/proxies.ts +++ b/packages/contracts/test/asset_proxy/proxies.ts @@ -39,7 +39,7 @@ const assetDataInterface = new IAssetDataContract( ); // tslint:disable:no-unnecessary-type-assertion -describe.only('Asset Transfer Proxies', () => { +describe('Asset Transfer Proxies', () => { let owner: string; let notAuthorized: string; let authorized: string; @@ -721,7 +721,6 @@ describe.only('Asset Transfer Proxies', () => { }), constants.AWAIT_TRANSACTION_MINED_MS, ); - // Verify transfer was successful const newBalances = await erc20Wrapper.getBalancesAsync(); const totalAmount = inputAmount.times(erc20Amount); expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( @@ -755,7 +754,6 @@ describe.only('Asset Transfer Proxies', () => { }), constants.AWAIT_TRANSACTION_MINED_MS, ); - // Verify transfer was successful const newBalances = await erc20Wrapper.getBalancesAsync(); const totalAmount = inputAmount.times(erc20Amount1).plus(inputAmount.times(erc20Amount2)); expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( @@ -789,7 +787,6 @@ describe.only('Asset Transfer Proxies', () => { }), constants.AWAIT_TRANSACTION_MINED_MS, ); - // Verify transfer was successful const newBalances = await erc20Wrapper.getBalancesAsync(); const totalErc20AAmount = inputAmount.times(erc20Amount1); const totalErc20BAmount = inputAmount.times(erc20Amount2); @@ -901,16 +898,346 @@ describe.only('Asset Transfer Proxies', () => { expect(newOwnerFromAsset1).to.be.equal(toAddress); expect(newOwnerFromAsset2).to.be.equal(toAddress); }); - it('should successfully transfer a combination of ERC20 and ERC721 tokens', async () => {}); - it('should successfully transfer tokens and ignore extra assetData', async () => {}); - it('should successfully transfer correct amounts when the `amount` > 1', async () => {}); - it('should revert if a single transfer fails', async () => {}); - it('should revert if an AssetProxy is not registered', async () => {}); - it('should revert if the length of `amounts` does not match the length of `nestedAssetData`', async () => {}); - it('should revert if amounts multiplication results in an overflow', async () => {}); - it('should revert if an element of `nestedAssetData` is < 4 bytes long', async () => {}); - it('should revert with the same reason as the called AssetProxy', async () => {}); - it('should revert if caller is not authorized', async () => {}); + it('should successfully transfer a combination of ERC20 and ERC721 tokens', async () => { + const inputAmount = new BigNumber(1); + const erc20Amount = new BigNumber(10); + const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address); + const erc721Amount = new BigNumber(1); + const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); + const amounts = [erc20Amount, erc721Amount]; + const nestedAssetData = [erc20AssetData, erc721AssetData]; + const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + assetData, + fromAddress, + toAddress, + inputAmount, + ); + const erc20Balances = await erc20Wrapper.getBalancesAsync(); + const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId); + expect(ownerFromAsset).to.be.equal(fromAddress); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: multiAssetProxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const newBalances = await erc20Wrapper.getBalancesAsync(); + const totalAmount = inputAmount.times(erc20Amount); + expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( + erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount), + ); + expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( + erc20Balances[toAddress][erc20TokenA.address].add(totalAmount), + ); + const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId); + expect(newOwnerFromAsset).to.be.equal(toAddress); + }); + it('should successfully transfer tokens and ignore extra assetData', async () => { + const inputAmount = new BigNumber(1); + const erc20Amount = new BigNumber(10); + const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address); + const erc721Amount = new BigNumber(1); + const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); + const amounts = [erc20Amount, erc721Amount]; + const nestedAssetData = [erc20AssetData, erc721AssetData]; + const extraData = '0102030405060708'; + const assetData = `${assetDataInterface.MultiAsset.getABIEncodedTransactionData( + amounts, + nestedAssetData, + )}${extraData}`; + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + assetData, + fromAddress, + toAddress, + inputAmount, + ); + const erc20Balances = await erc20Wrapper.getBalancesAsync(); + const ownerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId); + expect(ownerFromAsset).to.be.equal(fromAddress); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: multiAssetProxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const newBalances = await erc20Wrapper.getBalancesAsync(); + const totalAmount = inputAmount.times(erc20Amount); + expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( + erc20Balances[fromAddress][erc20TokenA.address].minus(totalAmount), + ); + expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( + erc20Balances[toAddress][erc20TokenA.address].add(totalAmount), + ); + const newOwnerFromAsset = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId); + expect(newOwnerFromAsset).to.be.equal(toAddress); + }); + it('should successfully transfer correct amounts when the `amount` > 1', async () => { + const inputAmount = new BigNumber(100); + const erc20Amount1 = new BigNumber(10); + const erc20Amount2 = new BigNumber(20); + const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address); + const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address); + const amounts = [erc20Amount1, erc20Amount2]; + const nestedAssetData = [erc20AssetData1, erc20AssetData2]; + const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + assetData, + fromAddress, + toAddress, + inputAmount, + ); + const erc20Balances = await erc20Wrapper.getBalancesAsync(); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: multiAssetProxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const newBalances = await erc20Wrapper.getBalancesAsync(); + const totalErc20AAmount = inputAmount.times(erc20Amount1); + const totalErc20BAmount = inputAmount.times(erc20Amount2); + expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( + erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount), + ); + expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( + erc20Balances[toAddress][erc20TokenA.address].add(totalErc20AAmount), + ); + expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal( + erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount), + ); + expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal( + erc20Balances[toAddress][erc20TokenB.address].add(totalErc20BAmount), + ); + }); + it('should successfully transfer a large amount of tokens', async () => { + const inputAmount = new BigNumber(1); + const erc20Amount1 = new BigNumber(10); + const erc20Amount2 = new BigNumber(20); + const erc20AssetData1 = assetDataUtils.encodeERC20AssetData(erc20TokenA.address); + const erc20AssetData2 = assetDataUtils.encodeERC20AssetData(erc20TokenB.address); + const erc721Amount = new BigNumber(1); + const erc721Balances = await erc721Wrapper.getBalancesAsync(); + const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1]; + const erc721BFromTokenId2 = erc721Balances[fromAddress][erc721TokenB.address][1]; + const erc721AssetData1 = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); + const erc721AssetData2 = assetDataUtils.encodeERC721AssetData( + erc721TokenA.address, + erc721AFromTokenId2, + ); + const erc721AssetData3 = assetDataUtils.encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId); + const erc721AssetData4 = assetDataUtils.encodeERC721AssetData( + erc721TokenB.address, + erc721BFromTokenId2, + ); + const amounts = [erc721Amount, erc20Amount1, erc721Amount, erc20Amount2, erc721Amount, erc721Amount]; + const nestedAssetData = [ + erc721AssetData1, + erc20AssetData1, + erc721AssetData2, + erc20AssetData2, + erc721AssetData3, + erc721AssetData4, + ]; + const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + assetData, + fromAddress, + toAddress, + inputAmount, + ); + const ownerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId); + expect(ownerFromAsset1).to.be.equal(fromAddress); + const ownerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2); + expect(ownerFromAsset2).to.be.equal(fromAddress); + const ownerFromAsset3 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId); + expect(ownerFromAsset3).to.be.equal(fromAddress); + const ownerFromAsset4 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId2); + expect(ownerFromAsset4).to.be.equal(fromAddress); + const erc20Balances = await erc20Wrapper.getBalancesAsync(); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: multiAssetProxy.address, + data, + from: authorized, + gas: constants.MAX_EXECUTE_TRANSACTION_GAS, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + const newOwnerFromAsset1 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId); + const newOwnerFromAsset2 = await erc721TokenA.ownerOf.callAsync(erc721AFromTokenId2); + const newOwnerFromAsset3 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId); + const newOwnerFromAsset4 = await erc721TokenB.ownerOf.callAsync(erc721BFromTokenId2); + expect(newOwnerFromAsset1).to.be.equal(toAddress); + expect(newOwnerFromAsset2).to.be.equal(toAddress); + expect(newOwnerFromAsset3).to.be.equal(toAddress); + expect(newOwnerFromAsset4).to.be.equal(toAddress); + const newBalances = await erc20Wrapper.getBalancesAsync(); + const totalErc20AAmount = inputAmount.times(erc20Amount1); + const totalErc20BAmount = inputAmount.times(erc20Amount2); + expect(newBalances[fromAddress][erc20TokenA.address]).to.be.bignumber.equal( + erc20Balances[fromAddress][erc20TokenA.address].minus(totalErc20AAmount), + ); + expect(newBalances[toAddress][erc20TokenA.address]).to.be.bignumber.equal( + erc20Balances[toAddress][erc20TokenA.address].add(totalErc20AAmount), + ); + expect(newBalances[fromAddress][erc20TokenB.address]).to.be.bignumber.equal( + erc20Balances[fromAddress][erc20TokenB.address].minus(totalErc20BAmount), + ); + expect(newBalances[toAddress][erc20TokenB.address]).to.be.bignumber.equal( + erc20Balances[toAddress][erc20TokenB.address].add(totalErc20BAmount), + ); + }); + it('should revert if a single transfer fails', async () => { + const inputAmount = new BigNumber(1); + const erc20Amount = new BigNumber(10); + const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address); + // 2 is an invalid erc721 amount + const erc721Amount = new BigNumber(2); + const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); + const amounts = [erc20Amount, erc721Amount]; + const nestedAssetData = [erc20AssetData, erc721AssetData]; + const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + assetData, + fromAddress, + toAddress, + inputAmount, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: multiAssetProxy.address, + data, + from: authorized, + }), + RevertReason.InvalidAmount, + ); + }); + it('should revert if an AssetProxy is not registered', async () => { + const inputAmount = new BigNumber(1); + const erc20Amount = new BigNumber(10); + const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address); + const erc721Amount = new BigNumber(1); + const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); + const invalidProxyId = '0x12345678'; + const invalidErc721AssetData = `${invalidProxyId}${erc721AssetData.slice(10)}`; + const amounts = [erc20Amount, erc721Amount]; + const nestedAssetData = [erc20AssetData, invalidErc721AssetData]; + const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + assetData, + fromAddress, + toAddress, + inputAmount, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: multiAssetProxy.address, + data, + from: authorized, + }), + RevertReason.AssetProxyDoesNotExist, + ); + }); + it('should revert if the length of `amounts` does not match the length of `nestedAssetData`', async () => { + const inputAmount = new BigNumber(1); + const erc20Amount = new BigNumber(10); + const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address); + const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); + const amounts = [erc20Amount]; + const nestedAssetData = [erc20AssetData, erc721AssetData]; + const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + assetData, + fromAddress, + toAddress, + inputAmount, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: multiAssetProxy.address, + data, + from: authorized, + }), + RevertReason.LengthMismatch, + ); + }); + it('should revert if amounts multiplication results in an overflow', async () => { + const inputAmount = new BigNumber(2).pow(128); + const erc20Amount = new BigNumber(2).pow(128); + const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address); + const amounts = [erc20Amount]; + const nestedAssetData = [erc20AssetData]; + const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + assetData, + fromAddress, + toAddress, + inputAmount, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: multiAssetProxy.address, + data, + from: authorized, + }), + RevertReason.Uint256Overflow, + ); + }); + it('should revert if an element of `nestedAssetData` is < 4 bytes long', async () => { + const inputAmount = new BigNumber(1); + const erc20Amount = new BigNumber(10); + const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address); + const erc721Amount = new BigNumber(1); + const erc721AssetData = '0x123456'; + const amounts = [erc20Amount, erc721Amount]; + const nestedAssetData = [erc20AssetData, erc721AssetData]; + const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + assetData, + fromAddress, + toAddress, + inputAmount, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: multiAssetProxy.address, + data, + from: authorized, + }), + RevertReason.LengthGreaterThan3Required, + ); + }); + it('should revert if caller is not authorized', async () => { + const inputAmount = new BigNumber(1); + const erc20Amount = new BigNumber(10); + const erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20TokenA.address); + const erc721Amount = new BigNumber(1); + const erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId); + const amounts = [erc20Amount, erc721Amount]; + const nestedAssetData = [erc20AssetData, erc721AssetData]; + const assetData = assetDataInterface.MultiAsset.getABIEncodedTransactionData(amounts, nestedAssetData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + assetData, + fromAddress, + toAddress, + inputAmount, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: multiAssetProxy.address, + data, + from: notAuthorized, + }), + RevertReason.SenderNotAuthorized, + ); + }); }); }); }); |