diff --git a/contracts/exchange-forwarder/package.json b/contracts/exchange-forwarder/package.json index 8d137b6eb8..c60f34ecc0 100644 --- a/contracts/exchange-forwarder/package.json +++ b/contracts/exchange-forwarder/package.json @@ -39,7 +39,7 @@ }, "config": { "publicInterfaceContracts": "Forwarder,IExchangeV2", - "abis": "./test/generated-artifacts/@(Forwarder|IAssets|IExchangeV2|IForwarder|IForwarderCore|LibConstants|LibForwarderRichErrors|MixinAssets|MixinExchangeWrapper|MixinForwarderCore|MixinWeth|TestForwarder).json", + "abis": "./test/generated-artifacts/@(Forwarder|IAssets|IExchangeV2|IForwarder|IForwarderCore|LibAssetDataTransfer|LibConstants|LibForwarderRichErrors|MixinAssets|MixinExchangeWrapper|MixinForwarderCore|MixinReceiver|MixinWeth|TestForwarder).json", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." }, "repository": { @@ -57,6 +57,7 @@ "@0x/contracts-dev-utils": "^1.0.3", "@0x/contracts-erc20": "^3.0.3", "@0x/contracts-erc721": "^3.0.3", + "@0x/contracts-erc1155": "^2.0.3", "@0x/contracts-exchange": "^3.0.3", "@0x/contracts-exchange-libs": "^4.0.3", "@0x/contracts-gen": "^2.0.3", diff --git a/contracts/exchange-forwarder/test/artifacts.ts b/contracts/exchange-forwarder/test/artifacts.ts index f1ca2b9d64..1b706dbba4 100644 --- a/contracts/exchange-forwarder/test/artifacts.ts +++ b/contracts/exchange-forwarder/test/artifacts.ts @@ -10,11 +10,13 @@ import * as IAssets from '../test/generated-artifacts/IAssets.json'; import * as IExchangeV2 from '../test/generated-artifacts/IExchangeV2.json'; import * as IForwarder from '../test/generated-artifacts/IForwarder.json'; import * as IForwarderCore from '../test/generated-artifacts/IForwarderCore.json'; +import * as LibAssetDataTransfer from '../test/generated-artifacts/LibAssetDataTransfer.json'; import * as LibConstants from '../test/generated-artifacts/LibConstants.json'; import * as LibForwarderRichErrors from '../test/generated-artifacts/LibForwarderRichErrors.json'; import * as MixinAssets from '../test/generated-artifacts/MixinAssets.json'; import * as MixinExchangeWrapper from '../test/generated-artifacts/MixinExchangeWrapper.json'; import * as MixinForwarderCore from '../test/generated-artifacts/MixinForwarderCore.json'; +import * as MixinReceiver from '../test/generated-artifacts/MixinReceiver.json'; import * as MixinWeth from '../test/generated-artifacts/MixinWeth.json'; import * as TestForwarder from '../test/generated-artifacts/TestForwarder.json'; export const artifacts = { @@ -22,11 +24,13 @@ export const artifacts = { MixinAssets: MixinAssets as ContractArtifact, MixinExchangeWrapper: MixinExchangeWrapper as ContractArtifact, MixinForwarderCore: MixinForwarderCore as ContractArtifact, + MixinReceiver: MixinReceiver as ContractArtifact, MixinWeth: MixinWeth as ContractArtifact, IAssets: IAssets as ContractArtifact, IExchangeV2: IExchangeV2 as ContractArtifact, IForwarder: IForwarder as ContractArtifact, IForwarderCore: IForwarderCore as ContractArtifact, + LibAssetDataTransfer: LibAssetDataTransfer as ContractArtifact, LibConstants: LibConstants as ContractArtifact, LibForwarderRichErrors: LibForwarderRichErrors as ContractArtifact, TestForwarder: TestForwarder as ContractArtifact, diff --git a/contracts/exchange-forwarder/test/asset_test.ts b/contracts/exchange-forwarder/test/asset_test.ts index 51fe246e24..ab93968829 100644 --- a/contracts/exchange-forwarder/test/asset_test.ts +++ b/contracts/exchange-forwarder/test/asset_test.ts @@ -1,4 +1,10 @@ import { IAssetDataContract } from '@0x/contracts-asset-proxy'; +import { + artifacts as ERC1155Artifacts, + ERC1155MintableContract, + ERC1155TransferBatchEventArgs, + Erc1155Wrapper, +} from '@0x/contracts-erc1155'; import { artifacts as ERC20Artifacts, DummyERC20TokenContract, @@ -25,6 +31,7 @@ import { LogWithDecodedArgs } from 'ethereum-types'; import { artifacts } from './artifacts'; import { TestForwarderContract } from './wrappers'; +// tslint:disable:no-unnecessary-type-assertion blockchainTests.resets('Supported asset type unit tests', env => { let forwarder: TestForwarderContract; let assetDataEncoder: IAssetDataContract; @@ -34,6 +41,8 @@ blockchainTests.resets('Supported asset type unit tests', env => { let erc20Token: DummyERC20TokenContract; let erc721Token: DummyERC721TokenContract; + let erc1155Token: ERC1155MintableContract; + let erc1155Wrapper: Erc1155Wrapper; let nftId: BigNumber; let erc20AssetData: string; @@ -50,7 +59,7 @@ blockchainTests.resets('Supported asset type unit tests', env => { artifacts.TestForwarder, env.provider, env.txDefaults, - { ...artifacts, ...ERC20Artifacts, ...ERC721Artifacts }, + { ...artifacts, ...ERC20Artifacts, ...ERC721Artifacts, ...ERC1155Artifacts }, ); erc20Token = await DummyERC20TokenContract.deployFrom0xArtifactAsync( @@ -76,6 +85,14 @@ blockchainTests.resets('Supported asset type unit tests', env => { nftId = getRandomInteger(0, constants.MAX_UINT256); erc721AssetData = assetDataEncoder.ERC721Token(erc721Token.address, nftId).getABIEncodedTransactionData(); + erc1155Token = await ERC1155MintableContract.deployFrom0xArtifactAsync( + ERC1155Artifacts.ERC1155Mintable, + env.provider, + env.txDefaults, + ERC1155Artifacts, + ); + erc1155Wrapper = new Erc1155Wrapper(erc1155Token, receiver); + bridgeAddress = randomAddress(); bridgeData = hexUtils.random(); erc20BridgeAssetData = assetDataEncoder @@ -183,7 +200,7 @@ blockchainTests.resets('Supported asset type unit tests', env => { }); }); - describe('_transferAssetToSender', () => { + describe('transferOut', () => { const TRANSFER_AMOUNT = new BigNumber(1); before(async () => { await erc20Token @@ -194,7 +211,7 @@ blockchainTests.resets('Supported asset type unit tests', env => { it('transfers an ERC20 token given ERC20 assetData', async () => { const txReceipt = await forwarder - .transferAssetToSender(erc20AssetData, TRANSFER_AMOUNT) + .transferOut(erc20AssetData, TRANSFER_AMOUNT) .awaitTransactionSuccessAsync({ from: receiver }); verifyEventsFromLogs( txReceipt.logs, @@ -204,7 +221,7 @@ blockchainTests.resets('Supported asset type unit tests', env => { }); it('transfers an ERC721 token given ERC721 assetData and amount == 1', async () => { const txReceipt = await forwarder - .transferAssetToSender(erc721AssetData, TRANSFER_AMOUNT) + .transferOut(erc721AssetData, TRANSFER_AMOUNT) .awaitTransactionSuccessAsync({ from: receiver }); verifyEventsFromLogs( txReceipt.logs, @@ -215,11 +232,67 @@ blockchainTests.resets('Supported asset type unit tests', env => { it('reverts if attempting to transfer an ERC721 token with amount != 1', async () => { const invalidAmount = new BigNumber(2); const tx = forwarder - .transferAssetToSender(erc721AssetData, invalidAmount) + .transferOut(erc721AssetData, invalidAmount) .awaitTransactionSuccessAsync({ from: receiver }); const expectedError = new ExchangeForwarderRevertErrors.Erc721AmountMustEqualOneError(invalidAmount); return expect(tx).to.revertWith(expectedError); }); + it('transfers a single ERC1155 token', async () => { + const values = [new BigNumber(1)]; + const amount = new BigNumber(1); + const ids = [await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], values)]; + const assetData = assetDataEncoder + .ERC1155Assets(erc1155Token.address, ids, values, constants.NULL_BYTES) + .getABIEncodedTransactionData(); + const txReceipt = await forwarder + .transferOut(assetData, amount) + .awaitTransactionSuccessAsync({ from: receiver }); + const logArgs = (txReceipt.logs[0] as LogWithDecodedArgs).args; + expect(logArgs.operator).to.eq(forwarder.address); + expect(logArgs.from).to.eq(forwarder.address); + expect(logArgs.to).to.eq(receiver); + logArgs.ids.forEach((id, i) => expect(new BigNumber(id)).to.bignumber.eq(ids[i])); + logArgs.values.forEach((value, i) => expect(new BigNumber(value)).to.bignumber.eq(values[i])); + }); + it('transfers multiple ids of an ERC1155 token', async () => { + const amount = new BigNumber(1); + const ids = [ + await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [amount]), + await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [amount]), + ]; + const values = [amount, amount]; + const assetData = assetDataEncoder + .ERC1155Assets(erc1155Token.address, ids, values, constants.NULL_BYTES) + .getABIEncodedTransactionData(); + const txReceipt = await forwarder.transferOut(assetData, amount).awaitTransactionSuccessAsync(); + const logArgs = (txReceipt.logs[0] as LogWithDecodedArgs).args; + expect(logArgs.operator).to.eq(forwarder.address); + expect(logArgs.from).to.eq(forwarder.address); + expect(logArgs.to).to.eq(receiver); + logArgs.ids.forEach((id, i) => expect(new BigNumber(id)).to.bignumber.eq(ids[i])); + logArgs.values.forEach((value, i) => expect(new BigNumber(value)).to.bignumber.eq(values[i])); + }); + it('scales up values when transfering ERC1155 tokens', async () => { + it('transfers multiple ids of an ERC1155 token', async () => { + const amount = new BigNumber(2); + const ids = [ + await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [amount]), + await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [amount]), + ]; + const values = [new BigNumber(1), new BigNumber(2)]; + const assetData = assetDataEncoder + .ERC1155Assets(erc1155Token.address, ids, values, constants.NULL_BYTES) + .getABIEncodedTransactionData(); + const txReceipt = await forwarder.transferOut(assetData, amount).awaitTransactionSuccessAsync(); + const scaledValues = values.map(value => value.times(amount)); + const logArgs = (txReceipt.logs[0] as LogWithDecodedArgs).args; + expect(logArgs.operator).to.eq(forwarder.address); + expect(logArgs.from).to.eq(forwarder.address); + expect(logArgs.to).to.eq(receiver); + logArgs.ids.forEach((id, i) => expect(new BigNumber(id)).to.bignumber.eq(ids[i])); + logArgs.values.forEach((value, i) => expect(new BigNumber(value)).to.bignumber.eq(scaledValues[i])); + }); + }); it('transfers a single ERC20 token wrapped as MultiAsset', async () => { const nestedAmount = new BigNumber(1337); const erc20MultiAssetData = assetDataEncoder @@ -227,7 +300,7 @@ blockchainTests.resets('Supported asset type unit tests', env => { .getABIEncodedTransactionData(); const multiAssetAmount = new BigNumber(2); const txReceipt = await forwarder - .transferAssetToSender(erc20MultiAssetData, multiAssetAmount) + .transferOut(erc20MultiAssetData, multiAssetAmount) .awaitTransactionSuccessAsync({ from: receiver }); verifyEventsFromLogs( txReceipt.logs, @@ -241,7 +314,7 @@ blockchainTests.resets('Supported asset type unit tests', env => { .MultiAsset(nestedAmounts, [erc20AssetData, erc721AssetData, staticCallAssetData]) .getABIEncodedTransactionData(); const txReceipt = await forwarder - .transferAssetToSender(assortedMultiAssetData, TRANSFER_AMOUNT) + .transferOut(assortedMultiAssetData, TRANSFER_AMOUNT) .awaitTransactionSuccessAsync({ from: receiver }); expect(txReceipt.logs.length).to.equal(2); // tslint:disable:no-unnecessary-type-assertion @@ -261,7 +334,7 @@ blockchainTests.resets('Supported asset type unit tests', env => { .MultiAsset(nestedAmounts, [multiAssetData, erc721AssetData, staticCallAssetData]) .getABIEncodedTransactionData(); const txReceipt = await forwarder - .transferAssetToSender(assortedMultiAssetData, TRANSFER_AMOUNT) + .transferOut(assortedMultiAssetData, TRANSFER_AMOUNT) .awaitTransactionSuccessAsync({ from: receiver }); expect(txReceipt.logs.length).to.equal(2); // tslint:disable:no-unnecessary-type-assertion @@ -277,7 +350,7 @@ blockchainTests.resets('Supported asset type unit tests', env => { }); it('transfers an ERC20 token given ERC20Bridge assetData', async () => { const txReceipt = await forwarder - .transferAssetToSender(erc20BridgeAssetData, TRANSFER_AMOUNT) + .transferOut(erc20BridgeAssetData, TRANSFER_AMOUNT) .awaitTransactionSuccessAsync({ from: receiver }); verifyEventsFromLogs( txReceipt.logs, @@ -287,14 +360,14 @@ blockchainTests.resets('Supported asset type unit tests', env => { }); it('noops (emits no events) for StaticCall assetData', async () => { const txReceipt = await forwarder - .transferAssetToSender(staticCallAssetData, TRANSFER_AMOUNT) + .transferOut(staticCallAssetData, TRANSFER_AMOUNT) .awaitTransactionSuccessAsync({ from: receiver }); expect(txReceipt.logs.length).to.equal(0); }); it('reverts if assetData is unsupported', async () => { const randomBytes = hexUtils.random(); const tx = forwarder - .transferAssetToSender(randomBytes, TRANSFER_AMOUNT) + .transferOut(randomBytes, TRANSFER_AMOUNT) .awaitTransactionSuccessAsync({ from: receiver }); const expectedError = new ExchangeForwarderRevertErrors.UnsupportedAssetProxyError( hexUtils.slice(randomBytes, 0, 4), diff --git a/contracts/exchange-forwarder/test/wrappers.ts b/contracts/exchange-forwarder/test/wrappers.ts index 68dfe360b0..37796558fa 100644 --- a/contracts/exchange-forwarder/test/wrappers.ts +++ b/contracts/exchange-forwarder/test/wrappers.ts @@ -8,10 +8,12 @@ export * from '../test/generated-wrappers/i_assets'; export * from '../test/generated-wrappers/i_exchange_v2'; export * from '../test/generated-wrappers/i_forwarder'; export * from '../test/generated-wrappers/i_forwarder_core'; +export * from '../test/generated-wrappers/lib_asset_data_transfer'; export * from '../test/generated-wrappers/lib_constants'; export * from '../test/generated-wrappers/lib_forwarder_rich_errors'; export * from '../test/generated-wrappers/mixin_assets'; export * from '../test/generated-wrappers/mixin_exchange_wrapper'; export * from '../test/generated-wrappers/mixin_forwarder_core'; +export * from '../test/generated-wrappers/mixin_receiver'; export * from '../test/generated-wrappers/mixin_weth'; export * from '../test/generated-wrappers/test_forwarder'; diff --git a/contracts/exchange-forwarder/tsconfig.json b/contracts/exchange-forwarder/tsconfig.json index 7fb86aa0f2..a02b1463ff 100644 --- a/contracts/exchange-forwarder/tsconfig.json +++ b/contracts/exchange-forwarder/tsconfig.json @@ -10,11 +10,13 @@ "test/generated-artifacts/IExchangeV2.json", "test/generated-artifacts/IForwarder.json", "test/generated-artifacts/IForwarderCore.json", + "test/generated-artifacts/LibAssetDataTransfer.json", "test/generated-artifacts/LibConstants.json", "test/generated-artifacts/LibForwarderRichErrors.json", "test/generated-artifacts/MixinAssets.json", "test/generated-artifacts/MixinExchangeWrapper.json", "test/generated-artifacts/MixinForwarderCore.json", + "test/generated-artifacts/MixinReceiver.json", "test/generated-artifacts/MixinWeth.json", "test/generated-artifacts/TestForwarder.json" ],