From b77dcbd39b8350a3b65dfc28a8487f89bf829fd7 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 27 Feb 2019 14:01:41 -0800 Subject: [PATCH 01/29] bumped revision verson for types package --- packages/types/CHANGELOG.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json index 36c97647b0..a248a2cd71 100644 --- a/packages/types/CHANGELOG.json +++ b/packages/types/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "2.1.2", + "changes": [ + { + "note": "Added `Uint256Underflow` and `TransferRejected` revert reasons", + "pr": 0 + } + ] + }, { "version": "2.2.1", "changes": [ From 243a04b756579fd3147b26c26afbe31f9e7b6cb7 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 28 Feb 2019 11:00:21 -0800 Subject: [PATCH 02/29] tests for allowance approvals on erc1155 --- contracts/erc1155/test/utils/erc1155_wrapper.ts | 16 ++++++++++++++++ packages/types/CHANGELOG.json | 7 ++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/contracts/erc1155/test/utils/erc1155_wrapper.ts b/contracts/erc1155/test/utils/erc1155_wrapper.ts index 7f620ece02..82e8705b1a 100644 --- a/contracts/erc1155/test/utils/erc1155_wrapper.ts +++ b/contracts/erc1155/test/utils/erc1155_wrapper.ts @@ -138,6 +138,22 @@ export class Erc1155Wrapper { const isApprovedForAll = await this._erc1155Contract.isApprovedForAll.callAsync(owner, beneficiary); return isApprovedForAll; } + public async setApprovalForAllAsync( + owner: string, + beneficiary: string, + isApproved: boolean, + ): Promise { + const tx = await this._logDecoder.getTxWithDecodedLogsAsync( + await this._erc1155Contract.setApprovalForAll.sendTransactionAsync(beneficiary, isApproved, { + from: owner, + }), + ); + return tx; + } + public async isApprovedForAllAsync(owner: string, beneficiary: string): Promise { + const isApprovedForAll = await this._erc1155Contract.isApprovedForAll.callAsync(owner, beneficiary); + return isApprovedForAll; + } public async assertBalancesAsync( owners: string[], tokens: BigNumber[], diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json index a248a2cd71..bf01f7cc28 100644 --- a/packages/types/CHANGELOG.json +++ b/packages/types/CHANGELOG.json @@ -1,10 +1,11 @@ [ { - "version": "2.1.2", + "version": "2.2.2", "changes": [ { - "note": "Added `Uint256Underflow` and `TransferRejected` revert reasons", - "pr": 0 + "note": "Added `Uint256Underflow`, `TransferRejected`, and `InsufficientAllowance` revert reasons", + "pr": 1657 + } ] }, From d5d9df383e9b637d036db93c4bd9bc5813f84467 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 5 Mar 2019 11:31:49 -0800 Subject: [PATCH 03/29] Added remaining erc1155 revert reasons to `types` package --- packages/types/CHANGELOG.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json index bf01f7cc28..9b7a07ffcd 100644 --- a/packages/types/CHANGELOG.json +++ b/packages/types/CHANGELOG.json @@ -3,7 +3,7 @@ "version": "2.2.2", "changes": [ { - "note": "Added `Uint256Underflow`, `TransferRejected`, and `InsufficientAllowance` revert reasons", + "note": "Added ERC1155 revert reasons", "pr": 1657 } From 15d9e2d3d5d37c88ec2fa2d1c2efbd23815a7eab Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 27 Feb 2019 14:44:54 -0800 Subject: [PATCH 04/29] Split ERC1155 Asset Proxy from ERC1155 POC implementation - squashed --- contracts/asset-proxy/DEPLOYS.json | 11 + .../contracts/src/ERC1155Proxy.sol | 257 +++++++++++ contracts/asset-proxy/package.json | 2 +- contracts/asset-proxy/src/artifacts.ts | 6 + contracts/asset-proxy/src/wrappers.ts | 3 + contracts/asset-proxy/test/proxies.ts | 409 +++++++++++++++++- .../asset-proxy/test/utils/erc1155_wrapper.ts | 288 ++++++++++++ contracts/asset-proxy/test/utils/index.ts | 1 + contracts/asset-proxy/tsconfig.json | 3 + contracts/test-utils/src/constants.ts | 5 + contracts/test-utils/src/index.ts | 3 + contracts/test-utils/src/types.ts | 21 + packages/order-utils/src/asset_data_utils.ts | 16 + packages/types/src/index.ts | 11 +- 14 files changed, 1032 insertions(+), 4 deletions(-) create mode 100644 contracts/asset-proxy/contracts/src/ERC1155Proxy.sol create mode 100644 contracts/asset-proxy/test/utils/erc1155_wrapper.ts diff --git a/contracts/asset-proxy/DEPLOYS.json b/contracts/asset-proxy/DEPLOYS.json index 0f25da1c3a..81b19daf59 100644 --- a/contracts/asset-proxy/DEPLOYS.json +++ b/contracts/asset-proxy/DEPLOYS.json @@ -1,4 +1,15 @@ [ + { + "name": "ERC1155Proxy", + "version": "1.0.0", + "changes": [ + { + "note": "Add ERC1155Proxy implementation", + "pr": 0, + "networks": { + } + } + ] { "name": "MultiAssetProxy", "version": "1.0.0", diff --git a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol new file mode 100644 index 0000000000..410eaf4786 --- /dev/null +++ b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol @@ -0,0 +1,257 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity 0.4.24; + +import "./MixinAuthorizable.sol"; + + +contract ERC1155Proxy is + MixinAuthorizable +{ + + // Id of this proxy. + bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC1155Token(address,uint256[],uint256[],bytes)")); + + function () + external + { + // Input calldata to this function is encoded as follows: + // -- TABLE #1 -- + // | Area | Offset (**) | Length | Contents | + // |----------|-------------|-------------|---------------------------------| + // | Header | 0 | 4 | function selector | + // | Params | | 4 * 32 | function parameters: | + // | | 4 | | 1. offset to assetData (*) | + // | | 36 | | 2. from | + // | | 68 | | 3. to | + // | | 100 | | 4. amount | + // | Data | | | assetData: | + // | | 132 | 32 | assetData Length | + // | | 164 | (see below) | assetData Contents | + // + // + // Asset data is encoded as follows: + // -- TABLE #2 -- + // | Area | Offset | Length | Contents | + // |----------|-------------|---------|-------------------------------------| + // | Header | 0 | 4 | assetProxyId | + // | Params | | 4 * 32 | function parameters: | + // | | 4 | | 1. address of ERC1155 contract | + // | | 36 | | 2. offset to tokenIds (*) | + // | | 68 | | 3. offset to tokenValues (*) | + // | | 100 | | 4. offset to callbackData (*) | + // | Data | | | tokenIds: | + // | | 132 | 32 | 1. tokenIds Length | + // | | 164 | a | 2. tokenIds Contents | + // | | | | tokenValues: | + // | | 164 + a | 32 | 1. tokenValues Length | + // | | 196 + a | b | 2. tokenValues Contents | + // | | | | callbackData | + // | | 196 + a + b | 32 | 1. callbackData Length | + // | | 228 + a + b | c | 2. callbackData Contents | + // + // + // Calldata for target ERC155 asset is encoded for safeBatchTransferFrom: + // -- TABLE #3 -- + // | Area | Offset (**) | Length | Contents | + // |----------|-------------|---------|-------------------------------------| + // | Header | 0 | 4 | safeBatchTransferFrom selector | + // | Params | | 5 * 32 | function parameters: | + // | | 4 | | 1. from address | + // | | 36 | | 2. to address | + // | | 68 | | 3. offset to tokenIds (*) | + // | | 100 | | 4. offset to tokenValues (*) | + // | | 132 | | 5. offset to callbackData (*) | + // | Data | | | tokenIds: | + // | | 164 | 32 | 1. tokenIds Length | + // | | 196 | a | 2. tokenIds Contents | + // | | | | tokenValues: | + // | | 196 + a | 32 | 1. tokenValues Length | + // | | 228 + a | b | 2. tokenValues Contents | + // | | | | callbackData | + // | | 228 + a + b | 32 | 1. callbackData Length | + // | | 260 + a + b | c | 2. callbackData Contents | + // + // + // (*): offset is computed from start of function parameters, so offset + // by an additional 4 bytes in the calldata. + // + // (**): the `Offset` column is computed assuming no calldata compression; + // offsets in the Data Area are dynamic and should be evaluated in + // real-time. + // + // WARNING: The ABIv2 specification allows additional padding between + // the Params and Data section. This will result in a larger + // offset to assetData. + // + // Note: Table #1 and Table #2 exists in Calldata. We construct Table #3 in memory. + // + // + assembly { + // The first 4 bytes of calldata holds the function selector + let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000) + + // `transferFrom` will be called with the following parameters: + // assetData Encoded byte array. + // from Address to transfer asset from. + // to Address to transfer asset to. + // amount Amount of asset to transfer. + // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4 + if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) { + + // To lookup a value in a mapping, we load from the storage location keccak256(k, p), + // where k is the key left padded to 32 bytes and p is the storage slot + mstore(0, caller) + mstore(32, authorized_slot) + + // Revert if authorized[msg.sender] == false + if iszero(sload(keccak256(0, 64))) { + // Revert with `Error("SENDER_NOT_AUTHORIZED")` + mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) + mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) + mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000) + mstore(96, 0) + revert(0, 100) + } + + // Construct Table #3 in memory, starting at memory offset 0. + // The algorithm below maps asset data from Table #1 and Table #2 to Table #3, while + // scaling the `tokenValues` (Table #2) by `amount` (Table #1). Once Table #3 has + // been constructed in memory, the destination erc1155 contract is called using this + // as its calldata. This process is divided into four steps, below. + + ////////// STEP 1/4 ////////// + // Map relevant fields from assetData (Table #2) into memory (Table #3) + // The Contents column of Table #2 is the same as Table #3, + // beginning from parameter 3 - `offset to tokenIds (*)` + // The offsets in these rows are offset by 32 bytes in Table #3. + // Strategy: + // 1. Copy the assetData into memory at offset 32 + // 2. Increment by 32 the offsets to `tokenIds`, `tokenValues`, and `callbackData` + + // Load offset to `assetData` + let assetDataOffset := calldataload(4) + + // Load length in bytes of `assetData`, computed by: + // 4 (function selector) + // + assetDataOffset + let assetDataLength := calldataload(add(4, assetDataOffset)) + + // This corresponds to the beginning of the Data Area for Table #3. + // Computed by: + // 4 (function selector) + // + assetDataOffset + // + 32 (length of assetData) + calldatacopy(32, add(36, assetDataOffset), assetDataLength) + + // Increment by 32 the offsets to `tokenIds`, `tokenValues`, and `callbackData` + mstore(68, add(mload(68), 32)) + mstore(100, add(mload(100), 32)) + mstore(132, add(mload(132), 32)) + + // Record the address of the destination erc1155 asset for later. + let assetAddress := and( + mload(36), + 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff + ) + + ////////// STEP 2/4 ////////// + let scaleAmount := calldataload(100) + let tokenValuesOffset := add(mload(100), 4) // add 4 for calldata offset + let tokenValuesLengthInBytes := mul( + mload(tokenValuesOffset), + 32 + ) + let tokenValuesBegin := add(tokenValuesOffset, 32) + let tokenValuesEnd := add(tokenValuesBegin, add(tokenValuesLengthInBytes, 32)) + for { let tokenValueOffset := tokenValuesBegin } + lt(tokenValueOffset, tokenValuesEnd) + { tokenValueOffset := add(tokenValueOffset, 32) } + { + // Load token value and revert if multiplication would result in an overflow + let tokenValue := mload(tokenValueOffset) + let scaledTokenValue := mul(tokenValue, scaleAmount) + let expectedTokenValue := div(scaledTokenValue, scaleAmount) + + // check for multiplication overflow + if iszero(eq(expectedTokenValue, tokenValue)) { + // Revert with `Error("UINT256_OVERFLOW")` + mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) + mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) + mstore(64, 0x0000001055494e543235365f4f564552464c4f57000000000000000000000000) + mstore(96, 0) + revert(0, 100) + } + + // There was no overflow, update `tokenValue` with its scaled counterpart + mstore(tokenValueOffset, scaledTokenValue) + } + + ////////// STEP 3/4 ////////// + // Store the safeBatchTransferFrom function selector, + // and copy `from`/`to` fields from Table #1 to Table #3. + + // The function selector is computed using: + // bytes4(keccak256("safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)")) + mstore(0, 0x2eb2c2d600000000000000000000000000000000000000000000000000000000) + + // Copy `from` and `to` fields from Table #1 to Table #3 + calldatacopy(4, 36, 64) + + ////////// STEP 4/4 ////////// + // Call into the destination erc1155 contract using as calldata Table #3 (constructed in-memory above) + let success := call( + gas, // forward all gas + assetAddress, // call address of erc1155 asset + 0, // don't send any ETH + 0, // pointer to start of input + add(assetDataLength, 32), // length of input (Table #3) is 32 bytes longer than `assetData` (Table #2) + 0, // write output over memory that won't be reused + 0 // don't copy output to memory + ) + + // Revert with reason given by AssetProxy if `transferFrom` call failed + if iszero(success) { + returndatacopy( + 0, // copy to memory at 0 + 0, // copy from return data at 0 + returndatasize() // copy all return data + ) + revert(0, returndatasize()) + } + + // Return if call was successful + return(0, 0) + } + + // Revert if undefined function is called + revert(0, 0) + } + } + + /// @dev Gets the proxy id associated with the proxy address. + /// @return Proxy id. + function getProxyId() + external + pure + returns (bytes4) + { + return PROXY_ID; + } +} diff --git a/contracts/asset-proxy/package.json b/contracts/asset-proxy/package.json index 2ab998dc74..3af5307d74 100644 --- a/contracts/asset-proxy/package.json +++ b/contracts/asset-proxy/package.json @@ -33,7 +33,7 @@ "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol" }, "config": { - "abis": "./generated-artifacts/@(ERC20Proxy|ERC721Proxy|IAssetData|IAssetProxy|IAuthorizable|MixinAuthorizable|MultiAssetProxy).json", + "abis": "./generated-artifacts/@(ERC20Proxy|ERC721Proxy|ERC1155Proxy|IAssetData|IAssetProxy|IAuthorizable|MixinAuthorizable|MultiAssetProxy).json", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." }, "repository": { diff --git a/contracts/asset-proxy/src/artifacts.ts b/contracts/asset-proxy/src/artifacts.ts index 4cef199512..c7c7f25dbb 100644 --- a/contracts/asset-proxy/src/artifacts.ts +++ b/contracts/asset-proxy/src/artifacts.ts @@ -5,6 +5,9 @@ */ import { ContractArtifact } from 'ethereum-types'; +import * as DummyERC1155Receiver from '../generated-artifacts/DummyERC1155Receiver.json'; +import * as ERC1155Mintable from '../generated-artifacts/ERC1155Mintable.json'; +import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json'; import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json'; import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json'; import * as IAssetData from '../generated-artifacts/IAssetData.json'; @@ -13,6 +16,9 @@ import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json'; import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json'; import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json'; export const artifacts = { + DummyERC1155Receiver: DummyERC1155Receiver as ContractArtifact, + ERC1155Mintable: ERC1155Mintable as ContractArtifact, + ERC1155Proxy: ERC1155Proxy as ContractArtifact, ERC20Proxy: ERC20Proxy as ContractArtifact, ERC721Proxy: ERC721Proxy as ContractArtifact, MixinAuthorizable: MixinAuthorizable as ContractArtifact, diff --git a/contracts/asset-proxy/src/wrappers.ts b/contracts/asset-proxy/src/wrappers.ts index 06fa9dedc9..50de349723 100644 --- a/contracts/asset-proxy/src/wrappers.ts +++ b/contracts/asset-proxy/src/wrappers.ts @@ -3,6 +3,9 @@ * Warning: This file is auto-generated by contracts-gen. Don't edit manually. * ----------------------------------------------------------------------------- */ +export * from '../generated-wrappers/dummy_erc1155_receiver'; +export * from '../generated-wrappers/erc1155_mintable'; +export * from '../generated-wrappers/erc1155_proxy'; export * from '../generated-wrappers/erc20_proxy'; export * from '../generated-wrappers/erc721_proxy'; export * from '../generated-wrappers/i_asset_data'; diff --git a/contracts/asset-proxy/test/proxies.ts b/contracts/asset-proxy/test/proxies.ts index 7977871358..744a42ab72 100644 --- a/contracts/asset-proxy/test/proxies.ts +++ b/contracts/asset-proxy/test/proxies.ts @@ -34,10 +34,16 @@ import { ERC20Wrapper, ERC721ProxyContract, ERC721Wrapper, + ERC1155Wrapper, + ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract, MultiAssetProxyContract, + ERC1155MintableContract, + DummyERC1155ReceiverContract, + DummyERC1155ReceiverBatchTokenReceivedEventArgs, } from '../src'; +import values from 'ramda/es/values'; chaiSetup.configure(); const expect = chai.expect; @@ -68,15 +74,22 @@ describe('Asset Transfer Proxies', () => { let erc721Receiver: DummyERC721ReceiverContract; let erc20Proxy: ERC20ProxyContract; let erc721Proxy: ERC721ProxyContract; + let erc1155Proxy: ERC721ProxyContract; + let erc1155Receiver: DummyERC1155ReceiverContract; let noReturnErc20Token: DummyNoReturnERC20TokenContract; let multipleReturnErc20Token: DummyMultipleReturnERC20TokenContract; let multiAssetProxy: MultiAssetProxyContract; let erc20Wrapper: ERC20Wrapper; let erc721Wrapper: ERC721Wrapper; + let erc1155Wrapper: ERC1155Wrapper; let erc721AFromTokenId: BigNumber; let erc721BFromTokenId: BigNumber; + let erc1155Token: ERC1155MintableContract; + let erc1155FungibleTokenIds: BigNumber[]; + let erc1155NonFungibleTokenIds: BigNumber[]; + before(async () => { await blockchainLifecycle.startAsync(); }); @@ -89,10 +102,12 @@ describe('Asset Transfer Proxies', () => { erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); + erc1155Wrapper = new ERC1155Wrapper(provider, usedAddresses, owner); // Deploy AssetProxies erc20Proxy = await erc20Wrapper.deployProxyAsync(); erc721Proxy = await erc721Wrapper.deployProxyAsync(); + erc1155Proxy = await erc1155Wrapper.deployProxyAsync(); multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync( artifacts.MultiAssetProxy, provider, @@ -127,6 +142,20 @@ describe('Asset Transfer Proxies', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); + // Configure ERC1155Proxy + await web3Wrapper.awaitTransactionSuccessAsync( + await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, { + from: owner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, { + from: owner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Configure MultiAssetProxy await web3Wrapper.awaitTransactionSuccessAsync( await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(authorized, { @@ -208,11 +237,21 @@ describe('Asset Transfer Proxies', () => { provider, txDefaults, ); - await erc721Wrapper.setBalancesAndAllowancesAsync(); const erc721Balances = await erc721Wrapper.getBalancesAsync(); erc721AFromTokenId = erc721Balances[fromAddress][erc721TokenA.address][0]; erc721BFromTokenId = erc721Balances[fromAddress][erc721TokenB.address][0]; + + // Deploy and configure ERC1155 tokens and receiver + [erc1155Token] = await erc1155Wrapper.deployDummyTokensAsync(); + erc1155Receiver = await DummyERC1155ReceiverContract.deployFrom0xArtifactAsync( + artifacts.DummyERC1155Receiver, + provider, + txDefaults, + ); + await erc1155Wrapper.setBalancesAndAllowancesAsync(); + erc1155FungibleTokenIds = erc1155Wrapper.getFungibleTokenIds(); + erc1155NonFungibleTokenIds = erc1155Wrapper.getNonFungibleTokenIds(); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); @@ -477,7 +516,6 @@ describe('Asset Transfer Proxies', () => { }); }); }); - describe('ERC721Proxy', () => { it('should revert if undefined function is called', async () => { const undefinedSelector = '0x01020304'; @@ -1286,6 +1324,373 @@ describe('Asset Transfer Proxies', () => { }); }); }); + describe.only('ERC1155Proxy', () => { + it('should revert if undefined function is called', async () => { + const undefinedSelector = '0x01020304'; + await expectTransactionFailedWithoutReasonAsync( + web3Wrapper.sendTransactionAsync({ + from: owner, + to: erc1155Proxy.address, + value: constants.ZERO_AMOUNT, + data: undefinedSelector, + }), + ); + }); + it('should have an id of 0x9645780d', async () => { + const proxyId = await erc1155Proxy.getProxyId.callAsync(); + // proxy computed using -- bytes4(keccak256("ERC1155Token(address,uint256[],uint256[],bytes)")); + const expectedProxyId = '0x9645780d'; + expect(proxyId).to.equal(expectedProxyId); + }); + describe('transferFrom', () => { + it('should successfully transfer value for a single token', async () => { + // Construct ERC1155 asset data + const callbackData = "0x"; + const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; + const tokenIdsToTransfer = [fungibleTokenIdToTransfer]; + const tokenValuesToTransfer = [new BigNumber(10)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Verify pre-condition + const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1000); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + toAddress, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Verify transfer was successful + const totalValueTransferred = tokenValuesToTransfer[0].times(perUnitValue); + const newHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); + const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const expectedNewReceiverBalance = initialReceiverBalance.plus(totalValueTransferred); + expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); + expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); + }); + it('should successfully transfer value for a collection of fungible tokens of the same id', async () => { + // Construct ERC1155 asset data + const callbackData = "0x"; + const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; + const tokenIdsToTransfer = [fungibleTokenIdToTransfer, fungibleTokenIdToTransfer, fungibleTokenIdToTransfer]; + const tokenValuesToTransfer = [new BigNumber(10), new BigNumber(20), new BigNumber(30)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Verify pre-condition + const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1000); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + toAddress, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Verify transfer was successful + const totalValueTransferred = _.reduce(tokenValuesToTransfer, (sum: BigNumber, value: BigNumber) => {return sum.plus(value)}, new BigNumber(0)).times(perUnitValue); + const newHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); + const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const expectedNewReceiverBalance = initialReceiverBalance.plus(totalValueTransferred); + expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); + expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); + }); + it('should successfully transfer value for a collection of fungible tokens of different ids', async () => { + // Construct ERC1155 asset data + const callbackData = "0x"; + const tokenIdsToTransfer = erc1155FungibleTokenIds.slice(0, 2); + const tokenValuesToTransfer = [new BigNumber(10), new BigNumber(20)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Verify pre-condition + const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const initialSenderBalances: BigNumber[] = []; + const initialReceiverBalances: BigNumber[] = []; + _.each(tokenIdsToTransfer, (tokenIdToTransfer: BigNumber) => { + initialSenderBalances.push(initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][tokenIdToTransfer.toString()]); + initialReceiverBalances.push(initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][tokenIdToTransfer.toString()]); + }); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1000); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + toAddress, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Verify transfer was successful + const newHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + _.each(tokenIdsToTransfer, (tokenIdToTransfer: BigNumber, i: number) => { + const totalValueTransferred = tokenValuesToTransfer[i].times(perUnitValue); + const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][tokenIdToTransfer.toString()]; + const expectedNewSenderBalance = initialSenderBalances[i].minus(totalValueTransferred); + const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][tokenIdToTransfer.toString()]; + const expectedNewReceiverBalance = initialReceiverBalances[i].plus(totalValueTransferred); + expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); + expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); + }); + }); + it('should successfully transfer a non-fungible token', async () => { + // Construct ERC1155 asset data + const callbackData = "0x"; + const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; + const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; + const tokenIdsToTransfer = [nftToTransfer]; + const tokenValuesToTransfer = [new BigNumber(1)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Verify precondition + const nftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + expect(nftHolder).to.be.equal(fromAddress); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + toAddress, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Verify transfer was successful + const newNftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + expect(newNftHolder).to.be.equal(toAddress); + // Verify balances updated successfully + const newHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const newNftsForFromAddress = newHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; + const newNftsForToAddress = newHoldingsByOwner.nonFungible[toAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; + expect(_.find(newNftsForFromAddress, nftToTransfer)).to.be.undefined(); + expect(_.find(newNftsForToAddress, nftToTransfer)).to.be.not.undefined(); + }); + it('should successfully transfer value for a combination of fungible/non-fungible tokens', async () => { + // Construct ERC1155 asset data + const callbackData = "0x"; + const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; + const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; + const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; + const tokenIdsToTransfer = [fungibleTokenIdToTransfer, nftToTransfer]; + const tokenValuesToTransfer = [new BigNumber(10), new BigNumber(1)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Verify precondition + const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const nftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + expect(nftHolder).to.be.equal(fromAddress); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + toAddress, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Verify non-fungible transfer was successful + const newNftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + expect(newNftHolder).to.be.equal(toAddress); + // Verify non-fungible balances updated successfully + const newHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const newNftsForFromAddress = newHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; + const newNftsForToAddress = newHoldingsByOwner.nonFungible[toAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; + expect(_.find(newNftsForFromAddress, nftToTransfer)).to.be.undefined(); + expect(_.find(newNftsForToAddress, nftToTransfer)).to.be.not.undefined(); + // Verify fungible transfer was successful + const totalValueTransferred = tokenValuesToTransfer[0].times(perUnitValue); + const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); + const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const expectedNewReceiverBalance = initialReceiverBalance.plus(totalValueTransferred); + expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); + expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); + }); + it('should successfully transfer value and ignore extra assetData', async () => { + // Construct ERC1155 asset data + const callbackData = "0x"; + const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; + const tokenIdsToTransfer = [fungibleTokenIdToTransfer]; + const tokenValuesToTransfer = [new BigNumber(10)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + const extraData = '0102030405060708'; + const encodedAssetDataPlusExtraData = `${encodedAssetData}${extraData}`; + // Verify pre-condition + const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1000); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetDataPlusExtraData, + fromAddress, + toAddress, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Verify transfer was successful + const totalValueTransferred = tokenValuesToTransfer[0].times(perUnitValue); + const newHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); + const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const expectedNewReceiverBalance = initialReceiverBalance.plus(totalValueTransferred); + expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); + expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); + }); + it.only('should successfully execute callback when transferring to a smart contract', async () => { + // Construct ERC1155 asset data + const callbackData = "0x"; + const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; + const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; + const tokenIdsToTransfer = [nftToTransfer]; + const tokenValuesToTransfer = [new BigNumber(1)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Verify precondition + const nftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + expect(nftHolder).to.be.equal(fromAddress); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + erc1155Receiver.address, + perUnitValue, + ); + const logDecoder = new LogDecoder(web3Wrapper, artifacts); + const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }) + ); + // Verify logs + expect(txReceipt.logs.length).to.be.equal(2); + const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs; + expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address); + expect(receiverLog.args.from).to.be.equal(fromAddress); + expect(receiverLog.args.tokenIds.length).to.be.deep.equal(1); + expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokenIdsToTransfer[0]); + expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); + expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(tokenValuesToTransfer[0]); + expect(receiverLog.args.data).to.be.deep.equal(callbackData); + // Verify transfer was successful + const newNftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + expect(newNftHolder).to.be.equal(erc1155Receiver.address); + }); + it.only('should successfully execute callback when transferring to a smart conract when there is callback data', async () => { + // Construct ERC1155 asset data + const callbackData = "0x12345678"; + const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; + const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; + const tokenIdsToTransfer = [nftToTransfer]; + const tokenValuesToTransfer = [new BigNumber(1)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Verify precondition + const nftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + expect(nftHolder).to.be.equal(fromAddress); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + erc1155Receiver.address, + perUnitValue, + ); + const logDecoder = new LogDecoder(web3Wrapper, artifacts); + const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }) + ); + // Verify logs + expect(txReceipt.logs.length).to.be.equal(2); + const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs; + expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address); + expect(receiverLog.args.from).to.be.equal(fromAddress); + expect(receiverLog.args.tokenIds.length).to.be.deep.equal(1); + expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokenIdsToTransfer[0]); + expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); + expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(tokenValuesToTransfer[0]); + expect(receiverLog.args.data).to.be.deep.equal(callbackData); + // Verify transfer was successful + const newNftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + expect(newNftHolder).to.be.equal(erc1155Receiver.address); + }); + it('should propagate revert reason from erc1155 contract failure', async () => { + }); + it('should revert if transferring the same non-fungible token more than once', async () => { + }); + it('should revert if tansferring 0 amount of any token', async () => { + }); + it('should revert if there is a multiplication overflow', async () => { + }); + it('should revert if there is a multiplication overflow, when transferring multiple tokens', async () => { + }); + it('should revert if transferring > 1 instances of a non-fungible token (amount field >1)', async () => { + }); + it('should revert if transferring > 1 instances of a non-fungible token (value field >1)', async () => { + }); + it('should revert if sender balance is insufficient', async () => { + }); + it('should revert if sender allowance is insufficient', async () => { + }); + it('should revert if caller is not authorized', async () => { + }); + }); + }); }); // tslint:enable:no-unnecessary-type-assertion // tslint:disable:max-file-line-count diff --git a/contracts/asset-proxy/test/utils/erc1155_wrapper.ts b/contracts/asset-proxy/test/utils/erc1155_wrapper.ts new file mode 100644 index 0000000000..7f20ca25aa --- /dev/null +++ b/contracts/asset-proxy/test/utils/erc1155_wrapper.ts @@ -0,0 +1,288 @@ +import { constants, ERC1155HoldingsByOwner, ERC1155FungibleHoldingsByOwner, ERC1155NonFungibleHoldingsByOwner, LogDecoder, txDefaults } from '@0x/contracts-test-utils'; +import { generatePseudoRandomSalt } from '@0x/order-utils'; +import { BigNumber } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import { Provider } from 'ethereum-types'; +import * as _ from 'lodash'; + +import { LogWithDecodedArgs } from 'ethereum-types'; + +import { artifacts, ERC1155MintableContract, ERC1155ProxyContract, ERC1155MintableTransferSingleEventArgs } from '../../src'; + + +export class ERC1155Wrapper { + private readonly _tokenOwnerAddresses: string[]; + private readonly _fungibleTokenIds: string[]; + private readonly _nonFungibleTokenIds: string[]; + private readonly _nfts: {id: BigNumber, tokenId: BigNumber}[]; + private readonly _contractOwnerAddress: string; + private readonly _web3Wrapper: Web3Wrapper; + private readonly _provider: Provider; + private readonly _logDecoder: LogDecoder; + private readonly _dummyTokenContracts: ERC1155MintableContract[]; + private _proxyContract?: ERC1155ProxyContract; + private _proxyIdIfExists?: string; + private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = {fungible: {}, nonFungible: {}}; + constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { + this._web3Wrapper = new Web3Wrapper(provider); + this._provider = provider; + this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); + this._dummyTokenContracts = []; + this._tokenOwnerAddresses = tokenOwnerAddresses; + this._contractOwnerAddress = contractOwnerAddress; + this._fungibleTokenIds = []; + this._nonFungibleTokenIds = []; + this._nfts = []; + } + public async deployDummyTokensAsync(): Promise { + // tslint:disable-next-line:no-unused-variable + for (const i of _.times(constants.NUM_DUMMY_ERC1155_TO_DEPLOY)) { + this._dummyTokenContracts.push( + await ERC1155MintableContract.deployFrom0xArtifactAsync( + artifacts.ERC1155Mintable, + this._provider, + txDefaults, + ), + ); + } + return this._dummyTokenContracts; + } + public async deployProxyAsync(): Promise { + this._proxyContract = await ERC1155ProxyContract.deployFrom0xArtifactAsync( + artifacts.ERC1155Proxy, + this._provider, + txDefaults, + ); + this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); + return this._proxyContract; + } + public getProxyId(): string { + this._validateProxyContractExistsOrThrow(); + return this._proxyIdIfExists as string; + } + public async setBalancesAndAllowancesAsync(): Promise { + this._validateDummyTokenContractsExistOrThrow(); + this._validateProxyContractExistsOrThrow(); + this._initialTokenIdsByOwner = { + fungible: {} as ERC1155FungibleHoldingsByOwner, + nonFungible: {} + }; + const fungibleHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {}; + const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {}; + for (const dummyTokenContract of this._dummyTokenContracts) { + // Fungible Tokens + for (const i of _.times(constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT)) { + // Create a fungible token + const tokenUri = generatePseudoRandomSalt().toString(); + const tokenIsNonFungible = false; + const tokenId = await this.createTokenAsync(dummyTokenContract.address, tokenUri, tokenIsNonFungible); + const tokenIdAsString = tokenId.toString(); + this._fungibleTokenIds.push(tokenIdAsString); + // Mint tokens for each owner for this token + for (const tokenOwnerAddress of this._tokenOwnerAddresses) { + // tslint:disable-next-line:no-unused-variable + await this.mintFungibleAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress); + if (_.isUndefined(fungibleHoldingsByOwner[tokenOwnerAddress])) { + fungibleHoldingsByOwner[tokenOwnerAddress] = {}; + } + if (_.isUndefined(fungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address])) { + fungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address] = {}; + } + fungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address][tokenIdAsString] = constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; + await this.approveProxyAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress); + } + } + // Non-Fungible Tokens + for (const i of _.times(constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT)) { + const tokenUri = generatePseudoRandomSalt().toString(); + const tokenIsNonFungible = true; + const tokenId = await this.createTokenAsync(dummyTokenContract.address, tokenUri, tokenIsNonFungible); + const tokenIdAsString = tokenId.toString(); + this._nonFungibleTokenIds.push(tokenIdAsString); + await this.mintNonFungibleAsync(dummyTokenContract.address, tokenId, this._tokenOwnerAddresses); + let tokenNonce = 0; + for (const tokenOwnerAddress of this._tokenOwnerAddresses) { + if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress])) { + nonFungibleHoldingsByOwner[tokenOwnerAddress] = {}; + } + if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address])) { + nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address] = {}; + } + if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address][tokenIdAsString])) { + nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address][tokenIdAsString] = []; + } + const nonFungibleId = tokenId.plus(++tokenNonce); + this._nfts.push({id: nonFungibleId, tokenId}); + nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address][tokenIdAsString].push(nonFungibleId); + await this.approveProxyAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress); + } + } + } + this._initialTokenIdsByOwner = { + fungible: fungibleHoldingsByOwner, + nonFungible: nonFungibleHoldingsByOwner, + } + return this._initialTokenIdsByOwner; + } + public async approveProxyAsync(tokenAddress: string, tokenId: BigNumber, tokenOwner: string): Promise { + const proxyAddress = (this._proxyContract as ERC1155ProxyContract).address; + await this.approveProxyForAllAsync(proxyAddress, tokenAddress, tokenOwner); + } + public async approveProxyForAllAsync(to: string, tokenAddress: string, tokenOwner: string): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.setApprovalForAll.sendTransactionAsync(to, true, { + from: tokenOwner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } + public async createTokenAsync(tokenAddress: string, tokenUri: string, tokenIsNonFungible: boolean): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync( + await tokenContract.create.sendTransactionAsync(tokenUri, tokenIsNonFungible), + ); + const createFungibleTokenLog = txReceipt.logs[0] as LogWithDecodedArgs; + const dummyFungibleTokenId = createFungibleTokenLog.args._id; + return dummyFungibleTokenId; + } + public async mintFungibleAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.mintFungible.sendTransactionAsync( + tokenId, + [userAddress], + [constants.INITIAL_ERC1155_FUNGIBLE_BALANCE], + { from: this._contractOwnerAddress } + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } + public async mintNonFungibleAsync(tokenAddress: string, tokenId: BigNumber, userAddresses: string[]): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + await this._web3Wrapper.awaitTransactionSuccessAsync( + await tokenContract.mintNonFungible.sendTransactionAsync( + tokenId, + userAddresses, + { from: this._contractOwnerAddress } + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + } + public async ownerOfNonFungibleAsync(tokenAddress: string, tokenId: BigNumber): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const owner = await tokenContract.ownerOf.callAsync(tokenId); + return owner; + } + public async isNonFungibleOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise { + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId); + const isOwner = tokenOwner === userAddress; + return isOwner; + } + public async isProxyApprovedForAllAsync(userAddress: string, tokenAddress: string): Promise { + this._validateProxyContractExistsOrThrow(); + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const operator = (this._proxyContract as ERC1155ProxyContract).address; + const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator); + return didApproveAll; + } + public async getBalancesAsync(): Promise { + this._validateDummyTokenContractsExistOrThrow(); + this._validateBalancesAndAllowancesSetOrThrow(); + const tokenHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {}; + const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {}; + for (const dummyTokenContract of this._dummyTokenContracts) { + const tokenAddress = dummyTokenContract.address; + const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + // Construct batch balance call + const tokenOwners: string[] = []; + const tokenIds: BigNumber[] = []; + for (const tokenOwnerAddress of this._tokenOwnerAddresses) { + for (const tokenId of this._fungibleTokenIds) { + tokenOwners.push(tokenOwnerAddress); + tokenIds.push(new BigNumber(tokenId)); + } + for (const nft of this._nfts) { + tokenOwners.push(tokenOwnerAddress); + tokenIds.push(nft.id); + } + } + const balances = await tokenContract.balanceOfBatch.callAsync(tokenOwners, tokenIds); + // Parse out balances into fungible / non-fungible token holdings + let i = 0; + for (const tokenOwnerAddress of this._tokenOwnerAddresses) { + // Fungible tokens + for (const tokenId of this._fungibleTokenIds) { + if (_.isUndefined(tokenHoldingsByOwner[tokenOwnerAddress])) { + tokenHoldingsByOwner[tokenOwnerAddress] = {}; + } + if (_.isUndefined(tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress])) { + tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {}; + } + tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress][tokenId] = balances[i++]; + } + // Non-fungible tokens + for (const nft of this._nfts) { + if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress])) { + nonFungibleHoldingsByOwner[tokenOwnerAddress] = {}; + } + if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress])) { + nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {}; + } + if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()])) { + nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] = []; + } + const isOwner = balances[i++]; + if (isOwner.isEqualTo(1)) { + nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()].push(nft.id); + } + } + } + } + const holdingsByOwner = { + fungible: tokenHoldingsByOwner, + nonFungible: nonFungibleHoldingsByOwner, + } + return holdingsByOwner; + } + public getFungibleTokenIds(): BigNumber[] { + const fungibleTokenIds = _.map(this._fungibleTokenIds, (tokenIdAsString: string) => {return new BigNumber(tokenIdAsString)}); + return fungibleTokenIds; + } + public getNonFungibleTokenIds(): BigNumber[] { + const nonFungibleTokenIds = _.map(this._nonFungibleTokenIds, (tokenIdAsString: string) => {return new BigNumber(tokenIdAsString)}); + return nonFungibleTokenIds; + } + public getTokenOwnerAddresses(): string[] { + return this._tokenOwnerAddresses; + } + public getTokenAddresses(): string[] { + const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address); + return tokenAddresses; + } + private _getTokenContractFromAssetData(tokenAddress: string): ERC1155MintableContract { + const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); + if (_.isUndefined(tokenContractIfExists)) { + throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155Wrapper`); + } + return tokenContractIfExists; + } + private _validateDummyTokenContractsExistOrThrow(): void { + if (_.isUndefined(this._dummyTokenContracts)) { + throw new Error('Dummy ERC1155 tokens not yet deployed, please call "deployDummyTokensAsync"'); + } + } + private _validateProxyContractExistsOrThrow(): void { + if (_.isUndefined(this._proxyContract)) { + throw new Error('ERC1155 proxy contract not yet deployed, please call "deployProxyAsync"'); + } + } + private _validateBalancesAndAllowancesSetOrThrow(): void { + if (_.keys(this._initialTokenIdsByOwner.fungible).length === 0 || _.keys(this._initialTokenIdsByOwner.nonFungible).length === 0) { + throw new Error( + 'Dummy ERC1155 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"', + ); + } + } +} diff --git a/contracts/asset-proxy/test/utils/index.ts b/contracts/asset-proxy/test/utils/index.ts index b11f6a45de..877ea5751d 100644 --- a/contracts/asset-proxy/test/utils/index.ts +++ b/contracts/asset-proxy/test/utils/index.ts @@ -1,2 +1,3 @@ export * from './erc20_wrapper'; export * from './erc721_wrapper'; +export * from './erc1155_wrapper'; diff --git a/contracts/asset-proxy/tsconfig.json b/contracts/asset-proxy/tsconfig.json index aaff338de9..2ea279b4e5 100644 --- a/contracts/asset-proxy/tsconfig.json +++ b/contracts/asset-proxy/tsconfig.json @@ -3,6 +3,9 @@ "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], "files": [ + "generated-artifacts/DummyERC1155Receiver.json", + "generated-artifacts/ERC1155Mintable.json", + "generated-artifacts/ERC1155Proxy.json", "generated-artifacts/ERC20Proxy.json", "generated-artifacts/ERC721Proxy.json", "generated-artifacts/IAssetData.json", diff --git a/contracts/test-utils/src/constants.ts b/contracts/test-utils/src/constants.ts index 99378c1fec..e1d9b8dbb4 100644 --- a/contracts/test-utils/src/constants.ts +++ b/contracts/test-utils/src/constants.ts @@ -38,11 +38,16 @@ export const constants = { NUM_DUMMY_ERC20_TO_DEPLOY: 3, NUM_DUMMY_ERC721_TO_DEPLOY: 2, NUM_ERC721_TOKENS_TO_MINT: 2, + NUM_DUMMY_ERC1155_TO_DEPLOY: 1, + NUM_ERC1155_FUNGIBLE_TOKENS_MINT: 3, + NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT: 3, NULL_ADDRESS: '0x0000000000000000000000000000000000000000', UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1), TESTRPC_PRIVATE_KEYS: _.map(TESTRPC_PRIVATE_KEYS_STRINGS, privateKeyString => ethUtil.toBuffer(privateKeyString)), INITIAL_ERC20_BALANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18), INITIAL_ERC20_ALLOWANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18), + INITIAL_ERC1155_FUNGIBLE_BALANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18), + INITIAL_ERC1155_FUNGIBLE_ALLOWANCE: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 18), STATIC_ORDER_PARAMS: { makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18), diff --git a/contracts/test-utils/src/index.ts b/contracts/test-utils/src/index.ts index 331913af80..c12a71bfda 100644 --- a/contracts/test-utils/src/index.ts +++ b/contracts/test-utils/src/index.ts @@ -32,6 +32,9 @@ export { MarketBuyOrders, MarketSellOrders, ERC721TokenIdsByOwner, + ERC1155FungibleHoldingsByOwner, + ERC1155NonFungibleHoldingsByOwner, + ERC1155HoldingsByOwner, OrderStatus, AllowanceAmountScenario, AssetDataScenario, diff --git a/contracts/test-utils/src/types.ts b/contracts/test-utils/src/types.ts index 16c3a9f3da..9cd098bc6a 100644 --- a/contracts/test-utils/src/types.ts +++ b/contracts/test-utils/src/types.ts @@ -14,6 +14,27 @@ export interface ERC721TokenIdsByOwner { }; } +export interface ERC1155FungibleHoldingsByOwner { + [ownerAddress: string]: { + [tokenAddress: string]: { + [tokenId: string]: BigNumber + } + }; +} + +export interface ERC1155NonFungibleHoldingsByOwner { + [ownerAddress: string]: { + [tokenAddress: string]: { + [tokenId: string]: BigNumber[] + } + }; +} + +export interface ERC1155HoldingsByOwner { + fungible: ERC1155FungibleHoldingsByOwner, + nonFungible: ERC1155NonFungibleHoldingsByOwner, +} + export interface SubmissionContractEventArgs { transactionId: BigNumber; } diff --git a/packages/order-utils/src/asset_data_utils.ts b/packages/order-utils/src/asset_data_utils.ts index f314891e20..ab8aa3443e 100644 --- a/packages/order-utils/src/asset_data_utils.ts +++ b/packages/order-utils/src/asset_data_utils.ts @@ -94,6 +94,18 @@ export const assetDataUtils = { const assetData = abiEncoder.encode(args, encodingRules); return assetData; }, + /** + * Encodes assetData for multiple AssetProxies into a single hex encoded assetData string, usable in the makerAssetData or + * takerAssetData fields in a 0x order. + + * @return The hex encoded assetData string + */ + encodeERC1155AssetData(tokenAddress: string, tokenIds: BigNumber[], tokenValues: BigNumber[], callbackData: string): string { + const abiEncoder = AbiEncoder.createMethod('ERC1155Token', ['address','uint256[]','uint256[]','bytes']); + const args = [tokenAddress, tokenIds, tokenValues, callbackData]; + const assetData = abiEncoder.encode(args, encodingRules); + return assetData; + }, /** * Decodes a MultiAsset assetData hex string into it's corresponding amounts and nestedAssetData * @param assetData Hex encoded assetData string to decode @@ -174,6 +186,7 @@ export const assetDataUtils = { if ( assetProxyId !== AssetProxyId.ERC20 && assetProxyId !== AssetProxyId.ERC721 && + assetProxyId !== AssetProxyId.ERC1155 && assetProxyId !== AssetProxyId.MultiAsset ) { throw new Error(`Invalid assetProxyId: ${assetProxyId}`); @@ -201,6 +214,9 @@ export const assetDataUtils = { isMultiAssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is MultiAssetData { return decodedAssetData.assetProxyId === AssetProxyId.MultiAsset; }, + isER1155AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is MultiAssetData { + return decodedAssetData.assetProxyId === AssetProxyId.MultiAsset; + }, /** * Throws if the length or assetProxyId are invalid for the ERC20Proxy. * @param assetData Hex encoded assetData string diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index ff2c87b79d..89a7d35da5 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -163,6 +163,7 @@ export enum AssetProxyId { ERC20 = '0xf47261b0', ERC721 = '0x02571792', MultiAsset = '0x94cfcdd7', + ERC1155 = '0x9645780d', } export interface ERC20AssetData { @@ -176,7 +177,15 @@ export interface ERC721AssetData { tokenId: BigNumber; } -export type SingleAssetData = ERC20AssetData | ERC721AssetData; +export interface ERC1155AssetData { + assetProxyId: string; + tokenAddress: string; + tokenIds: BigNumber[]; + tokenValues: BigNumber[]; + callbackData: string; +} + +export type SingleAssetData = ERC20AssetData | ERC721AssetData | ERC1155AssetData; export interface MultiAssetData { assetProxyId: string; From 4473851f5b86baaa43e287211741475b62360ff9 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 1 Mar 2019 15:25:10 -0800 Subject: [PATCH 05/29] Remaining tests for erc1155 proxy --- .../contracts/src/ERC1155Proxy.sol | 19 +- contracts/asset-proxy/test/proxies.ts | 374 ++++++++++++++++-- ...55_wrapper.ts => erc1155_proxy_wrapper.ts} | 136 +++---- contracts/asset-proxy/test/utils/index.ts | 2 +- packages/types/src/index.ts | 2 + 5 files changed, 407 insertions(+), 126 deletions(-) rename contracts/asset-proxy/test/utils/{erc1155_wrapper.ts => erc1155_proxy_wrapper.ts} (66%) diff --git a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol index 410eaf4786..81b4bf7080 100644 --- a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol +++ b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol @@ -179,17 +179,28 @@ contract ERC1155Proxy is 32 ) let tokenValuesBegin := add(tokenValuesOffset, 32) - let tokenValuesEnd := add(tokenValuesBegin, add(tokenValuesLengthInBytes, 32)) + let tokenValuesEnd := add(tokenValuesBegin, tokenValuesLengthInBytes) for { let tokenValueOffset := tokenValuesBegin } lt(tokenValueOffset, tokenValuesEnd) { tokenValueOffset := add(tokenValueOffset, 32) } { - // Load token value and revert if multiplication would result in an overflow + // Load token value and generate scaled value let tokenValue := mload(tokenValueOffset) let scaledTokenValue := mul(tokenValue, scaleAmount) - let expectedTokenValue := div(scaledTokenValue, scaleAmount) + + // Check if scaled value is zero + if iszero(scaledTokenValue) { + // Revert with `Error("TRANSFER_GREATER_THAN_ZERO_REQUIRED")` + mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) + mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) + mstore(64, 0x000000235452414e534645525f475245415445525f5448414e5f5a45524f5f52) + mstore(96, 0x4551554952454400000000000000000000000000000000000000000000000000) + mstore(128, 0) + revert(0, 132) + } - // check for multiplication overflow + // Check for multiplication overflow + let expectedTokenValue := div(scaledTokenValue, scaleAmount) if iszero(eq(expectedTokenValue, tokenValue)) { // Revert with `Error("UINT256_OVERFLOW")` mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) diff --git a/contracts/asset-proxy/test/proxies.ts b/contracts/asset-proxy/test/proxies.ts index 744a42ab72..697940775c 100644 --- a/contracts/asset-proxy/test/proxies.ts +++ b/contracts/asset-proxy/test/proxies.ts @@ -23,7 +23,7 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils } from '@0x/order-utils'; import { RevertReason } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, AbiEncoder } from '@0x/utils'; import * as chai from 'chai'; import { LogWithDecodedArgs } from 'ethereum-types'; import * as _ from 'lodash'; @@ -34,7 +34,7 @@ import { ERC20Wrapper, ERC721ProxyContract, ERC721Wrapper, - ERC1155Wrapper, + ERC1155ProxyWrapper, ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract, @@ -82,7 +82,7 @@ describe('Asset Transfer Proxies', () => { let erc20Wrapper: ERC20Wrapper; let erc721Wrapper: ERC721Wrapper; - let erc1155Wrapper: ERC1155Wrapper; + let erc1155ProxyWrapper: ERC1155ProxyWrapper; let erc721AFromTokenId: BigNumber; let erc721BFromTokenId: BigNumber; @@ -102,12 +102,12 @@ describe('Asset Transfer Proxies', () => { erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); - erc1155Wrapper = new ERC1155Wrapper(provider, usedAddresses, owner); + erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner); // Deploy AssetProxies erc20Proxy = await erc20Wrapper.deployProxyAsync(); erc721Proxy = await erc721Wrapper.deployProxyAsync(); - erc1155Proxy = await erc1155Wrapper.deployProxyAsync(); + erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync(); multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync( artifacts.MultiAssetProxy, provider, @@ -243,15 +243,16 @@ describe('Asset Transfer Proxies', () => { erc721BFromTokenId = erc721Balances[fromAddress][erc721TokenB.address][0]; // Deploy and configure ERC1155 tokens and receiver - [erc1155Token] = await erc1155Wrapper.deployDummyTokensAsync(); + const [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyTokensAsync(); + erc1155Token = erc1155Wrapper.getContract(); erc1155Receiver = await DummyERC1155ReceiverContract.deployFrom0xArtifactAsync( artifacts.DummyERC1155Receiver, provider, txDefaults, ); - await erc1155Wrapper.setBalancesAndAllowancesAsync(); - erc1155FungibleTokenIds = erc1155Wrapper.getFungibleTokenIds(); - erc1155NonFungibleTokenIds = erc1155Wrapper.getNonFungibleTokenIds(); + await erc1155ProxyWrapper.setBalancesAndAllowancesAsync(); + erc1155FungibleTokenIds = erc1155ProxyWrapper.getFungibleTokenIds(); + erc1155NonFungibleTokenIds = erc1155ProxyWrapper.getNonFungibleTokenIds(); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); @@ -1351,7 +1352,7 @@ describe('Asset Transfer Proxies', () => { const tokenValuesToTransfer = [new BigNumber(10)]; const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); // Verify pre-condition - const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; // Perform a transfer from fromAddress to toAddress @@ -1372,7 +1373,7 @@ describe('Asset Transfer Proxies', () => { ); // Verify transfer was successful const totalValueTransferred = tokenValuesToTransfer[0].times(perUnitValue); - const newHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; @@ -1388,7 +1389,7 @@ describe('Asset Transfer Proxies', () => { const tokenValuesToTransfer = [new BigNumber(10), new BigNumber(20), new BigNumber(30)]; const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); // Verify pre-condition - const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; // Perform a transfer from fromAddress to toAddress @@ -1409,7 +1410,7 @@ describe('Asset Transfer Proxies', () => { ); // Verify transfer was successful const totalValueTransferred = _.reduce(tokenValuesToTransfer, (sum: BigNumber, value: BigNumber) => {return sum.plus(value)}, new BigNumber(0)).times(perUnitValue); - const newHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; @@ -1424,7 +1425,7 @@ describe('Asset Transfer Proxies', () => { const tokenValuesToTransfer = [new BigNumber(10), new BigNumber(20)]; const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); // Verify pre-condition - const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const initialSenderBalances: BigNumber[] = []; const initialReceiverBalances: BigNumber[] = []; _.each(tokenIdsToTransfer, (tokenIdToTransfer: BigNumber) => { @@ -1448,7 +1449,7 @@ describe('Asset Transfer Proxies', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); // Verify transfer was successful - const newHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); _.each(tokenIdsToTransfer, (tokenIdToTransfer: BigNumber, i: number) => { const totalValueTransferred = tokenValuesToTransfer[i].times(perUnitValue); const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][tokenIdToTransfer.toString()]; @@ -1463,13 +1464,13 @@ describe('Asset Transfer Proxies', () => { // Construct ERC1155 asset data const callbackData = "0x"; const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; const tokenIdsToTransfer = [nftToTransfer]; const tokenValuesToTransfer = [new BigNumber(1)]; const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); // Verify precondition - const nftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + const nftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); expect(nftHolder).to.be.equal(fromAddress); // Perform a transfer from fromAddress to toAddress const perUnitValue = new BigNumber(1); @@ -1488,10 +1489,10 @@ describe('Asset Transfer Proxies', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); // Verify transfer was successful - const newNftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + const newNftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); expect(newNftHolder).to.be.equal(toAddress); // Verify balances updated successfully - const newHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const newNftsForFromAddress = newHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; const newNftsForToAddress = newHoldingsByOwner.nonFungible[toAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; expect(_.find(newNftsForFromAddress, nftToTransfer)).to.be.undefined(); @@ -1502,7 +1503,7 @@ describe('Asset Transfer Proxies', () => { const callbackData = "0x"; const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; const tokenIdsToTransfer = [fungibleTokenIdToTransfer, nftToTransfer]; const tokenValuesToTransfer = [new BigNumber(10), new BigNumber(1)]; @@ -1510,7 +1511,7 @@ describe('Asset Transfer Proxies', () => { // Verify precondition const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const nftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + const nftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); expect(nftHolder).to.be.equal(fromAddress); // Perform a transfer from fromAddress to toAddress const perUnitValue = new BigNumber(1); @@ -1529,10 +1530,59 @@ describe('Asset Transfer Proxies', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); // Verify non-fungible transfer was successful - const newNftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + const newNftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); expect(newNftHolder).to.be.equal(toAddress); // Verify non-fungible balances updated successfully - const newHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); + const newNftsForFromAddress = newHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; + const newNftsForToAddress = newHoldingsByOwner.nonFungible[toAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; + expect(_.find(newNftsForFromAddress, nftToTransfer)).to.be.undefined(); + expect(_.find(newNftsForToAddress, nftToTransfer)).to.be.not.undefined(); + // Verify fungible transfer was successful + const totalValueTransferred = tokenValuesToTransfer[0].times(perUnitValue); + const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); + const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const expectedNewReceiverBalance = initialReceiverBalance.plus(totalValueTransferred); + expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); + expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); + }); + it.skip('should successfully transfer value for a combination of several fungible/non-fungible tokens', async () => { + // Construct ERC1155 asset data + const callbackData = "0x"; + const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; + const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); + const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; + const tokenIdsToTransfer = [fungibleTokenIdToTransfer, nftToTransfer]; + const tokenValuesToTransfer = [new BigNumber(10), new BigNumber(1)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Verify precondition + const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + const nftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + expect(nftHolder).to.be.equal(fromAddress); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + toAddress, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Verify non-fungible transfer was successful + const newNftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + expect(newNftHolder).to.be.equal(toAddress); + // Verify non-fungible balances updated successfully + const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const newNftsForFromAddress = newHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; const newNftsForToAddress = newHoldingsByOwner.nonFungible[toAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; expect(_.find(newNftsForFromAddress, nftToTransfer)).to.be.undefined(); @@ -1556,7 +1606,7 @@ describe('Asset Transfer Proxies', () => { const extraData = '0102030405060708'; const encodedAssetDataPlusExtraData = `${encodedAssetData}${extraData}`; // Verify pre-condition - const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; // Perform a transfer from fromAddress to toAddress @@ -1577,7 +1627,7 @@ describe('Asset Transfer Proxies', () => { ); // Verify transfer was successful const totalValueTransferred = tokenValuesToTransfer[0].times(perUnitValue); - const newHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; @@ -1585,17 +1635,17 @@ describe('Asset Transfer Proxies', () => { expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); }); - it.only('should successfully execute callback when transferring to a smart contract', async () => { + it('should successfully execute callback when transferring to a smart contract', async () => { // Construct ERC1155 asset data const callbackData = "0x"; const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; const tokenIdsToTransfer = [nftToTransfer]; const tokenValuesToTransfer = [new BigNumber(1)]; const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); // Verify precondition - const nftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + const nftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); expect(nftHolder).to.be.equal(fromAddress); // Perform a transfer from fromAddress to toAddress const perUnitValue = new BigNumber(1); @@ -1624,20 +1674,20 @@ describe('Asset Transfer Proxies', () => { expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(tokenValuesToTransfer[0]); expect(receiverLog.args.data).to.be.deep.equal(callbackData); // Verify transfer was successful - const newNftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + const newNftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); expect(newNftHolder).to.be.equal(erc1155Receiver.address); }); - it.only('should successfully execute callback when transferring to a smart conract when there is callback data', async () => { + it('should successfully execute callback when transferring to a smart contract when there is callback data', async () => { // Construct ERC1155 asset data const callbackData = "0x12345678"; const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155Wrapper.getBalancesAsync(); + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; const tokenIdsToTransfer = [nftToTransfer]; const tokenValuesToTransfer = [new BigNumber(1)]; const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); // Verify precondition - const nftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + const nftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); expect(nftHolder).to.be.equal(fromAddress); // Perform a transfer from fromAddress to toAddress const perUnitValue = new BigNumber(1); @@ -1666,28 +1716,286 @@ describe('Asset Transfer Proxies', () => { expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(tokenValuesToTransfer[0]); expect(receiverLog.args.data).to.be.deep.equal(callbackData); // Verify transfer was successful - const newNftHolder = await erc1155Wrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + const newNftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); expect(newNftHolder).to.be.equal(erc1155Receiver.address); }); it('should propagate revert reason from erc1155 contract failure', async () => { + // Disable transfers + const shouldRejectTransfer = true; + await web3Wrapper.awaitTransactionSuccessAsync( + await erc1155Receiver.setRejectTransferFlag.sendTransactionAsync(shouldRejectTransfer), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // Construct ERC1155 asset data + const callbackData = "0x12345678"; + const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); + const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; + const tokenIdsToTransfer = [nftToTransfer]; + const tokenValuesToTransfer = [new BigNumber(1)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + erc1155Receiver.address, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.TransferRejected, + ); }); it('should revert if transferring the same non-fungible token more than once', async () => { + // Construct ERC1155 asset data + const callbackData = "0x12345678"; + const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); + const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; + const tokenIdsToTransfer = [nftToTransfer, nftToTransfer]; + const tokenValuesToTransfer = [new BigNumber(1), new BigNumber(1)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Verify precondition + const nftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); + expect(nftHolder).to.be.equal(fromAddress); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + erc1155Receiver.address, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.nftNotOwnedByFromAddress, + ); }); it('should revert if tansferring 0 amount of any token', async () => { + // Construct ERC1155 asset data + const callbackData = "0x12345678"; + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); + const tokenIdsToTransfer = [ + initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][erc1155NonFungibleTokenIds[0].toString()][0], + initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][erc1155NonFungibleTokenIds[1].toString()][0], + initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][erc1155NonFungibleTokenIds[2].toString()][0], + ]; + const tokenValuesToTransfer = [new BigNumber(1), new BigNumber(0), new BigNumber(1)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + erc1155Receiver.address, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.transferGreaterThanZeroRequired, + ); }); it('should revert if there is a multiplication overflow', async () => { + // Construct ERC1155 asset data + const callbackData = "0x"; + const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; + const tokenIdsToTransfer = [fungibleTokenIdToTransfer]; + const maxUintValue = (new BigNumber(2)).pow(256).minus(1); + const tokenValuesToTransfer = [maxUintValue]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(2); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + toAddress, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.Uint256Overflow, + ); }); it('should revert if there is a multiplication overflow, when transferring multiple tokens', async () => { + // Construct ERC1155 asset data + const callbackData = "0x"; + const tokenIdsToTransfer = erc1155FungibleTokenIds.slice(3); + const maxUintValue = (new BigNumber(2)).pow(256).minus(1); + // Note - the second token will fail + const tokenValuesToTransfer = [new BigNumber(1), maxUintValue, new BigNumber(1)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(2); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + toAddress, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.Uint256Overflow, + ); }); it('should revert if transferring > 1 instances of a non-fungible token (amount field >1)', async () => { + // Construct ERC1155 asset data + const callbackData = "0x"; + const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); + const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; + const tokenIdsToTransfer = [nftToTransfer]; + const tokenValuesToTransfer = [new BigNumber(1)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(2); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + toAddress, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.amountEqualToOneRequired, + ); }); it('should revert if transferring > 1 instances of a non-fungible token (value field >1)', async () => { + // Construct ERC1155 asset data + const callbackData = "0x"; + const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); + const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; + const tokenIdsToTransfer = [nftToTransfer]; + const tokenValuesToTransfer = [new BigNumber(2)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + toAddress, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.amountEqualToOneRequired, + ); }); it('should revert if sender balance is insufficient', async () => { + // Verify pre-condition + const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); + const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + // Construct ERC1155 asset data + const callbackData = "0x"; + const tokenIdsToTransfer = [fungibleTokenIdToTransfer]; + const tokenValuesToTransfer = [initialSenderBalance.plus(1)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + toAddress, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.Uint256Underflow, + ); }); it('should revert if sender allowance is insufficient', async () => { + // Unapprove ERC1155 proxy + const wrapper = erc1155ProxyWrapper.getTokenWrapper(erc1155Token.address); + const isApproved = false; + await wrapper.setApprovalForAllAsync(fromAddress, erc1155Proxy.address, isApproved); + const isApprovedActualValue = await wrapper.isApprovedForAllAsync(fromAddress, erc1155Proxy.address); + expect(isApprovedActualValue).to.be.equal(isApproved); + // Verify pre-condition + const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); + const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; + // Construct ERC1155 asset data + const callbackData = "0x"; + console.log('init sender balance - ', initialSenderBalance.toString()); + const tokenIdsToTransfer = [fungibleTokenIdToTransfer]; + const tokenValuesToTransfer = [initialSenderBalance]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + toAddress, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.InsufficientAllowance, + ); }); it('should revert if caller is not authorized', async () => { + // Construct ERC1155 asset data + const callbackData = "0x12345678"; + const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; + const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); + const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; + const tokenIdsToTransfer = [nftToTransfer]; + const tokenValuesToTransfer = [new BigNumber(1)]; + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); + // Perform a transfer from fromAddress to toAddress + const perUnitValue = new BigNumber(1); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + fromAddress, + erc1155Receiver.address, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: notAuthorized, + }), + RevertReason.SenderNotAuthorized, + ); }); }); }); diff --git a/contracts/asset-proxy/test/utils/erc1155_wrapper.ts b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts similarity index 66% rename from contracts/asset-proxy/test/utils/erc1155_wrapper.ts rename to contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts index 7f20ca25aa..b70bdb641f 100644 --- a/contracts/asset-proxy/test/utils/erc1155_wrapper.ts +++ b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts @@ -5,12 +5,14 @@ import { Web3Wrapper } from '@0x/web3-wrapper'; import { Provider } from 'ethereum-types'; import * as _ from 'lodash'; +import { Erc1155Wrapper } from '@0x/contracts-erc1155'; + import { LogWithDecodedArgs } from 'ethereum-types'; import { artifacts, ERC1155MintableContract, ERC1155ProxyContract, ERC1155MintableTransferSingleEventArgs } from '../../src'; -export class ERC1155Wrapper { +export class ERC1155ProxyWrapper { private readonly _tokenOwnerAddresses: string[]; private readonly _fungibleTokenIds: string[]; private readonly _nonFungibleTokenIds: string[]; @@ -19,7 +21,7 @@ export class ERC1155Wrapper { private readonly _web3Wrapper: Web3Wrapper; private readonly _provider: Provider; private readonly _logDecoder: LogDecoder; - private readonly _dummyTokenContracts: ERC1155MintableContract[]; + private readonly _dummyTokenWrappers: Erc1155Wrapper[]; private _proxyContract?: ERC1155ProxyContract; private _proxyIdIfExists?: string; private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = {fungible: {}, nonFungible: {}}; @@ -27,25 +29,26 @@ export class ERC1155Wrapper { this._web3Wrapper = new Web3Wrapper(provider); this._provider = provider; this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); - this._dummyTokenContracts = []; + this._dummyTokenWrappers = []; this._tokenOwnerAddresses = tokenOwnerAddresses; this._contractOwnerAddress = contractOwnerAddress; this._fungibleTokenIds = []; this._nonFungibleTokenIds = []; this._nfts = []; } - public async deployDummyTokensAsync(): Promise { + public async deployDummyTokensAsync(): Promise { // tslint:disable-next-line:no-unused-variable for (const i of _.times(constants.NUM_DUMMY_ERC1155_TO_DEPLOY)) { - this._dummyTokenContracts.push( - await ERC1155MintableContract.deployFrom0xArtifactAsync( - artifacts.ERC1155Mintable, - this._provider, - txDefaults, - ), + const erc1155Contract = await ERC1155MintableContract.deployFrom0xArtifactAsync( + artifacts.ERC1155Mintable, + this._provider, + txDefaults, ); + console.log(erc1155Contract.address); + const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._provider, this._contractOwnerAddress); + this._dummyTokenWrappers.push(erc1155Wrapper); } - return this._dummyTokenContracts; + return this._dummyTokenWrappers; } public async deployProxyAsync(): Promise { this._proxyContract = await ERC1155ProxyContract.deployFrom0xArtifactAsync( @@ -69,53 +72,46 @@ export class ERC1155Wrapper { }; const fungibleHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {}; const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {}; - for (const dummyTokenContract of this._dummyTokenContracts) { - // Fungible Tokens + // set balances accordingly + for (const dummyWrapper of this._dummyTokenWrappers) { + const dummyAddress = dummyWrapper.getContract().address; for (const i of _.times(constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT)) { // Create a fungible token - const tokenUri = generatePseudoRandomSalt().toString(); - const tokenIsNonFungible = false; - const tokenId = await this.createTokenAsync(dummyTokenContract.address, tokenUri, tokenIsNonFungible); + const tokenId = await dummyWrapper.mintFungibleTokensAsync(this._tokenOwnerAddresses, constants.INITIAL_ERC1155_FUNGIBLE_BALANCE); const tokenIdAsString = tokenId.toString(); this._fungibleTokenIds.push(tokenIdAsString); // Mint tokens for each owner for this token for (const tokenOwnerAddress of this._tokenOwnerAddresses) { // tslint:disable-next-line:no-unused-variable - await this.mintFungibleAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress); if (_.isUndefined(fungibleHoldingsByOwner[tokenOwnerAddress])) { fungibleHoldingsByOwner[tokenOwnerAddress] = {}; } - if (_.isUndefined(fungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address])) { - fungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address] = {}; + if (_.isUndefined(fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress])) { + fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {}; } - fungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address][tokenIdAsString] = constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; - await this.approveProxyAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress); + fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; + await dummyWrapper.setApprovalForAllAsync(tokenOwnerAddress, (this._proxyContract as ERC1155ProxyContract).address, true); } } // Non-Fungible Tokens for (const i of _.times(constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT)) { - const tokenUri = generatePseudoRandomSalt().toString(); - const tokenIsNonFungible = true; - const tokenId = await this.createTokenAsync(dummyTokenContract.address, tokenUri, tokenIsNonFungible); + const [tokenId, nftIds] = await dummyWrapper.mintNonFungibleTokensAsync(this._tokenOwnerAddresses); const tokenIdAsString = tokenId.toString(); this._nonFungibleTokenIds.push(tokenIdAsString); - await this.mintNonFungibleAsync(dummyTokenContract.address, tokenId, this._tokenOwnerAddresses); - let tokenNonce = 0; - for (const tokenOwnerAddress of this._tokenOwnerAddresses) { + _.each(this._tokenOwnerAddresses, async (tokenOwnerAddress: string, i: number) => { if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress])) { nonFungibleHoldingsByOwner[tokenOwnerAddress] = {}; } - if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address])) { - nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address] = {}; + if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress])) { + nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {}; } - if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address][tokenIdAsString])) { - nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address][tokenIdAsString] = []; + if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString])) { + nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = []; } - const nonFungibleId = tokenId.plus(++tokenNonce); - this._nfts.push({id: nonFungibleId, tokenId}); - nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyTokenContract.address][tokenIdAsString].push(nonFungibleId); - await this.approveProxyAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress); - } + this._nfts.push({id: nftIds[i], tokenId}); + nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString].push(nftIds[i]); + await dummyWrapper.setApprovalForAllAsync(tokenOwnerAddress, (this._proxyContract as ERC1155ProxyContract).address, true); + }); } } this._initialTokenIdsByOwner = { @@ -124,51 +120,6 @@ export class ERC1155Wrapper { } return this._initialTokenIdsByOwner; } - public async approveProxyAsync(tokenAddress: string, tokenId: BigNumber, tokenOwner: string): Promise { - const proxyAddress = (this._proxyContract as ERC1155ProxyContract).address; - await this.approveProxyForAllAsync(proxyAddress, tokenAddress, tokenOwner); - } - public async approveProxyForAllAsync(to: string, tokenAddress: string, tokenOwner: string): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - await this._web3Wrapper.awaitTransactionSuccessAsync( - await tokenContract.setApprovalForAll.sendTransactionAsync(to, true, { - from: tokenOwner, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - } - public async createTokenAsync(tokenAddress: string, tokenUri: string, tokenIsNonFungible: boolean): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync( - await tokenContract.create.sendTransactionAsync(tokenUri, tokenIsNonFungible), - ); - const createFungibleTokenLog = txReceipt.logs[0] as LogWithDecodedArgs; - const dummyFungibleTokenId = createFungibleTokenLog.args._id; - return dummyFungibleTokenId; - } - public async mintFungibleAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - await this._web3Wrapper.awaitTransactionSuccessAsync( - await tokenContract.mintFungible.sendTransactionAsync( - tokenId, - [userAddress], - [constants.INITIAL_ERC1155_FUNGIBLE_BALANCE], - { from: this._contractOwnerAddress } - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - } - public async mintNonFungibleAsync(tokenAddress: string, tokenId: BigNumber, userAddresses: string[]): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); - await this._web3Wrapper.awaitTransactionSuccessAsync( - await tokenContract.mintNonFungible.sendTransactionAsync( - tokenId, - userAddresses, - { from: this._contractOwnerAddress } - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - } public async ownerOfNonFungibleAsync(tokenAddress: string, tokenId: BigNumber): Promise { const tokenContract = this._getTokenContractFromAssetData(tokenAddress); const owner = await tokenContract.ownerOf.callAsync(tokenId); @@ -192,9 +143,9 @@ export class ERC1155Wrapper { this._validateBalancesAndAllowancesSetOrThrow(); const tokenHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {}; const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {}; - for (const dummyTokenContract of this._dummyTokenContracts) { - const tokenAddress = dummyTokenContract.address; - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + for (const dummyTokenWrapper of this._dummyTokenWrappers) { + const tokenContract = dummyTokenWrapper.getContract(); + const tokenAddress = tokenContract.address; // Construct batch balance call const tokenOwners: string[] = []; const tokenIds: BigNumber[] = []; @@ -208,7 +159,7 @@ export class ERC1155Wrapper { tokenIds.push(nft.id); } } - const balances = await tokenContract.balanceOfBatch.callAsync(tokenOwners, tokenIds); + const balances = await dummyTokenWrapper.getBalancesAsync(tokenOwners, tokenIds); // Parse out balances into fungible / non-fungible token holdings let i = 0; for (const tokenOwnerAddress of this._tokenOwnerAddresses) { @@ -257,19 +208,28 @@ export class ERC1155Wrapper { public getTokenOwnerAddresses(): string[] { return this._tokenOwnerAddresses; } + public getTokenWrapper(tokenAddress: string): Erc1155Wrapper { + const tokenWrapper = _.find(this._dummyTokenWrappers, (wrapper: Erc1155Wrapper) => {return wrapper.getContract().address === tokenAddress}); + if (_.isUndefined(tokenWrapper)) { + throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155Wrapper`); + } + return tokenWrapper; + } + /* public getTokenAddresses(): string[] { const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address); return tokenAddresses; } + */ private _getTokenContractFromAssetData(tokenAddress: string): ERC1155MintableContract { - const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress); + const tokenContractIfExists = _.find(this._dummyTokenWrappers, c => c.getContract().address === tokenAddress); if (_.isUndefined(tokenContractIfExists)) { throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155Wrapper`); } - return tokenContractIfExists; + return tokenContractIfExists.getContract(); } private _validateDummyTokenContractsExistOrThrow(): void { - if (_.isUndefined(this._dummyTokenContracts)) { + if (_.isUndefined(this._dummyTokenWrappers)) { throw new Error('Dummy ERC1155 tokens not yet deployed, please call "deployDummyTokensAsync"'); } } diff --git a/contracts/asset-proxy/test/utils/index.ts b/contracts/asset-proxy/test/utils/index.ts index 877ea5751d..897806e703 100644 --- a/contracts/asset-proxy/test/utils/index.ts +++ b/contracts/asset-proxy/test/utils/index.ts @@ -1,3 +1,3 @@ export * from './erc20_wrapper'; export * from './erc721_wrapper'; -export * from './erc1155_wrapper'; +export * from './erc1155_proxy_wrapper'; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 89a7d35da5..4dfc6285bd 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -295,6 +295,8 @@ export enum RevertReason { TriedToMintNonFungibleForFungibleToken = 'TRIED_TO_MINT_NON_FUNGIBLE_FOR_FUNGIBLE_TOKEN', TransferRejected = 'TRANSFER_REJECTED', Uint256Underflow = 'UINT256_UNDERFLOW', + // ERC1155 Proxy + transferGreaterThanZeroRequired = 'TRANSFER_GREATER_THAN_ZERO_REQUIRED', } export enum StatusCodes { From 2882c4bb897a41cf2995a3b9ef93ed9d4e982693 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 4 Mar 2019 10:52:11 -0800 Subject: [PATCH 06/29] test with several tokens erc1155 proxy --- contracts/asset-proxy/test/proxies.ts | 80 ++++++++++++++++----------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/contracts/asset-proxy/test/proxies.ts b/contracts/asset-proxy/test/proxies.ts index 697940775c..061d0271a6 100644 --- a/contracts/asset-proxy/test/proxies.ts +++ b/contracts/asset-proxy/test/proxies.ts @@ -1547,21 +1547,41 @@ describe('Asset Transfer Proxies', () => { expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); }); - it.skip('should successfully transfer value for a combination of several fungible/non-fungible tokens', async () => { - // Construct ERC1155 asset data - const callbackData = "0x"; - const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; - const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; + it('should successfully transfer value for a combination of several fungible/non-fungible tokens', async () => { + // Check inital balances and construct asset data + const erc1155Wrapper = erc1155ProxyWrapper.getTokenWrapper(erc1155Token.address); + const spenderInitialFungibleBalance = constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; + const receiverInitialFungibleBalance = constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; + const expectedInitialBalances = [ + // spender balances + spenderInitialFungibleBalance, + spenderInitialFungibleBalance, + spenderInitialFungibleBalance, + new BigNumber(1), + new BigNumber(1), + // receiver balances + receiverInitialFungibleBalance, + receiverInitialFungibleBalance, + receiverInitialFungibleBalance, + new BigNumber(0), + new BigNumber(0), + ]; + const tokenHolders = [ + fromAddress, + toAddress, + ]; + const fungibleTokenIdsToTransfer = erc1155FungibleTokenIds.slice(0, 3); + const nonFungibleTokenIdsToTransfer = erc1155NonFungibleTokenIds.slice(0, 2); const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; - const tokenIdsToTransfer = [fungibleTokenIdToTransfer, nftToTransfer]; - const tokenValuesToTransfer = [new BigNumber(10), new BigNumber(1)]; + const nftsToTransfer = [ + initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdsToTransfer[0].toString()][0], + initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdsToTransfer[1].toString()][0], + ]; + const tokenIdsToTransfer = fungibleTokenIdsToTransfer.concat(nftsToTransfer); + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokenIdsToTransfer, expectedInitialBalances); + const callbackData = "0x"; + const tokenValuesToTransfer = [spenderInitialFungibleBalance, spenderInitialFungibleBalance, spenderInitialFungibleBalance, new BigNumber(1),new BigNumber(1)]; const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Verify precondition - const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const nftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); - expect(nftHolder).to.be.equal(fromAddress); // Perform a transfer from fromAddress to toAddress const perUnitValue = new BigNumber(1); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( @@ -1578,23 +1598,22 @@ describe('Asset Transfer Proxies', () => { }), constants.AWAIT_TRANSACTION_MINED_MS, ); - // Verify non-fungible transfer was successful - const newNftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); - expect(newNftHolder).to.be.equal(toAddress); - // Verify non-fungible balances updated successfully - const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const newNftsForFromAddress = newHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; - const newNftsForToAddress = newHoldingsByOwner.nonFungible[toAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; - expect(_.find(newNftsForFromAddress, nftToTransfer)).to.be.undefined(); - expect(_.find(newNftsForToAddress, nftToTransfer)).to.be.not.undefined(); - // Verify fungible transfer was successful - const totalValueTransferred = tokenValuesToTransfer[0].times(perUnitValue); - const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); - const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const expectedNewReceiverBalance = initialReceiverBalance.plus(totalValueTransferred); - expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); - expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); + // Check final balances + const expectedFinalBalances = [ + // spender balances + new BigNumber(0), + new BigNumber(0), + new BigNumber(0), + new BigNumber(0), + new BigNumber(0), + // receiver balances + receiverInitialFungibleBalance.plus(spenderInitialFungibleBalance), + receiverInitialFungibleBalance.plus(spenderInitialFungibleBalance), + receiverInitialFungibleBalance.plus(spenderInitialFungibleBalance), + new BigNumber(1), + new BigNumber(1), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokenIdsToTransfer, expectedFinalBalances); }); it('should successfully transfer value and ignore extra assetData', async () => { // Construct ERC1155 asset data @@ -1950,7 +1969,6 @@ describe('Asset Transfer Proxies', () => { const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; // Construct ERC1155 asset data const callbackData = "0x"; - console.log('init sender balance - ', initialSenderBalance.toString()); const tokenIdsToTransfer = [fungibleTokenIdToTransfer]; const tokenValuesToTransfer = [initialSenderBalance]; const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); From 008eb8dd8b5dba47aa02196f1e67260c930390c1 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 4 Mar 2019 12:15:17 -0800 Subject: [PATCH 07/29] cleaning up erc1155 proxy tests --- contracts/asset-proxy/test/proxies.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/asset-proxy/test/proxies.ts b/contracts/asset-proxy/test/proxies.ts index 061d0271a6..1dbec9f394 100644 --- a/contracts/asset-proxy/test/proxies.ts +++ b/contracts/asset-proxy/test/proxies.ts @@ -1325,7 +1325,7 @@ describe('Asset Transfer Proxies', () => { }); }); }); - describe.only('ERC1155Proxy', () => { + describe('ERC1155Proxy', () => { it('should revert if undefined function is called', async () => { const undefinedSelector = '0x01020304'; await expectTransactionFailedWithoutReasonAsync( From 4dfb610ebab7bd3d9fbbfccfba3c12b9299f16e1 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 4 Mar 2019 13:25:56 -0800 Subject: [PATCH 08/29] updated erc1155 proxy tests and moved to their own test file --- contracts/asset-proxy/test/erc1155_proxy.ts | 860 ++++++++++++++++++++ 1 file changed, 860 insertions(+) create mode 100644 contracts/asset-proxy/test/erc1155_proxy.ts diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts new file mode 100644 index 0000000000..14db6c3c91 --- /dev/null +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -0,0 +1,860 @@ +import { + chaiSetup, + constants, + expectTransactionFailedAsync, + expectTransactionFailedWithoutReasonAsync, + LogDecoder, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; +import { BlockchainLifecycle } from '@0x/dev-utils'; +import { assetDataUtils } from '@0x/order-utils'; +import { RevertReason } from '@0x/types'; +import { BigNumber, AbiEncoder } from '@0x/utils'; +import * as chai from 'chai'; +import { LogWithDecodedArgs } from 'ethereum-types'; +import * as _ from 'lodash'; + +import { + artifacts, + DummyERC20TokenContract, + DummyERC20TokenTransferEventArgs, + DummyERC721ReceiverContract, + DummyERC721TokenContract, + DummyMultipleReturnERC20TokenContract, + DummyNoReturnERC20TokenContract, + ERC20ProxyContract, + ERC20Wrapper, + ERC721ProxyContract, + ERC721Wrapper, + ERC1155ProxyWrapper, + ERC1155ProxyContract, + IAssetDataContract, + IAssetProxyContract, + MultiAssetProxyContract, + ERC1155MintableContract, + DummyERC1155ReceiverContract, + DummyERC1155ReceiverBatchTokenReceivedEventArgs, +} from '../src'; +import values from 'ramda/es/values'; +import { Erc1155Wrapper } from '../../erc1155/lib/src'; + +chaiSetup.configure(); +const expect = chai.expect; +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); +const assetProxyInterface = new IAssetProxyContract( + artifacts.IAssetProxy.compilerOutput.abi, + constants.NULL_ADDRESS, + provider, +); +const assetDataInterface = new IAssetDataContract( + artifacts.IAssetData.compilerOutput.abi, + constants.NULL_ADDRESS, + provider, +); + +// tslint:disable:no-unnecessary-type-assertion +describe.only('ERC1155Proxy', () => { + // constant values used in transfer tests + const nftOwnerBalance = new BigNumber(1); + const nftNotOwnerBalance = new BigNumber(0); + const spenderInitialFungibleBalance = constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; + const receiverInitialFungibleBalance = constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; + const receiverContractInitialFungibleBalance = new BigNumber(0); + const fungibleValueToTransferSmall = spenderInitialFungibleBalance.div(100); + const fungibleValueToTransferLarge = spenderInitialFungibleBalance.div(4); + const perUnitValueSmall = new BigNumber(2); + const perUnitValueLarge = new BigNumber(100); + const perUnitValueNft = new BigNumber(1); + const nonFungibleValueToTransfer = nftOwnerBalance; + const receiverCallbackData = '0x01020304'; + // addresses + let owner: string; + let notAuthorized: string; + let authorized: string; + let spender: string; + let receiver: string; + let receiverContract: string; + // contracts & wrappers + let erc1155Proxy: ERC721ProxyContract; + let erc1155Receiver: DummyERC1155ReceiverContract; + let erc1155ProxyWrapper: ERC1155ProxyWrapper; + let erc1155Token: ERC1155MintableContract; + let erc1155Wrapper: Erc1155Wrapper; + // tokens + let fungibleTokens: BigNumber[]; + let nonFungibleTokensOwnedBySpender: BigNumber[]; + // tests + before(async () => { + await blockchainLifecycle.startAsync(); + }); + after(async () => { + await blockchainLifecycle.revertAsync(); + }); + before(async () => { + /// deploy & configure ERC1155Proxy + const accounts = await web3Wrapper.getAvailableAddressesAsync(); + const usedAddresses = ([owner, notAuthorized, authorized, spender, receiver] = _.slice(accounts, 0, 5)); + erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner); + erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync(); + await web3Wrapper.awaitTransactionSuccessAsync( + await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, { + from: owner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(erc1155Proxy.address, { + from: owner, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + );; + // deploy & configure ERC1155 tokens and receiver + [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyTokensAsync(); + erc1155Token = erc1155Wrapper.getContract(); + erc1155Receiver = await DummyERC1155ReceiverContract.deployFrom0xArtifactAsync( + artifacts.DummyERC1155Receiver, + provider, + txDefaults, + ); + receiverContract = erc1155Receiver.address; + await erc1155ProxyWrapper.setBalancesAndAllowancesAsync(); + fungibleTokens = erc1155ProxyWrapper.getFungibleTokenIds(); + const nonFungibleTokens = erc1155ProxyWrapper.getNonFungibleTokenIds(); + const tokenBalances = await erc1155ProxyWrapper.getBalancesAsync(); + nonFungibleTokensOwnedBySpender = []; + _.each(nonFungibleTokens, (nonFungibleToken: BigNumber) => { + const nonFungibleTokenAsString = nonFungibleToken.toString(); + const nonFungibleTokenHeldBySpender = tokenBalances.nonFungible[spender][erc1155Token.address][nonFungibleTokenAsString][0]; + nonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender); + }); + }); + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + describe('general', () => { + it('should revert if undefined function is called', async () => { + const undefinedSelector = '0x01020304'; + await expectTransactionFailedWithoutReasonAsync( + web3Wrapper.sendTransactionAsync({ + from: owner, + to: erc1155Proxy.address, + value: constants.ZERO_AMOUNT, + data: undefinedSelector, + }), + ); + }); + it('should have an id of 0x9645780d', async () => { + const proxyId = await erc1155Proxy.getProxyId.callAsync(); + // proxy computed using -- bytes4(keccak256("ERC1155Token(address,uint256[],uint256[],bytes)")); + const expectedProxyId = '0x9645780d'; + expect(proxyId).to.equal(expectedProxyId); + }); + describe.only('transferFrom', () => { + it('should successfully transfer value for a single, fungible token', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // check balances after transfer + const totalValueTransferred = valuesToTransfer[0].times(perUnitValue); + const expectedFinalBalances = [ + spenderInitialFungibleBalance.minus(totalValueTransferred), + receiverInitialFungibleBalance.plus(totalValueTransferred), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should successfully transfer value for the same fungible token several times', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokenToTransfer = fungibleTokens[0]; + const tokensToTransfer = [tokenToTransfer, tokenToTransfer, tokenToTransfer]; + const valuesToTransfer = [fungibleValueToTransferSmall.plus(10), fungibleValueToTransferSmall.plus(20), fungibleValueToTransferSmall.plus(30)]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [ + // spender + spenderInitialFungibleBalance, + // receiver + receiverInitialFungibleBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Token.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // check balances after transfer + let totalValueTransferred = _.reduce(valuesToTransfer, (sum: BigNumber, value: BigNumber) => {return sum.plus(value)}) as BigNumber; + totalValueTransferred = totalValueTransferred.times(perUnitValue); + const expectedFinalBalances = [ + // spender + spenderInitialFungibleBalance.minus(totalValueTransferred), + // receiver + receiverInitialFungibleBalance.plus(totalValueTransferred), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedFinalBalances); + }); + it('should successfully transfer value for several fungible tokens', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = fungibleTokens.slice(0, 3); + const valuesToTransfer = [fungibleValueToTransferSmall.plus(10), fungibleValueToTransferSmall.plus(20), fungibleValueToTransferSmall.plus(30)]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [ + // spender + spenderInitialFungibleBalance, + spenderInitialFungibleBalance, + spenderInitialFungibleBalance, + // receiver + receiverInitialFungibleBalance, + receiverInitialFungibleBalance, + receiverInitialFungibleBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Token.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // check balances after transfer + const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => {return value.times(perUnitValue)}); + const expectedFinalBalances = [ + // spender + spenderInitialFungibleBalance.minus(totalValuesTransferred[0]), + spenderInitialFungibleBalance.minus(totalValuesTransferred[1]), + spenderInitialFungibleBalance.minus(totalValuesTransferred[2]), + // receiver + receiverInitialFungibleBalance.plus(totalValuesTransferred[0]), + receiverInitialFungibleBalance.plus(totalValuesTransferred[1]), + receiverInitialFungibleBalance.plus(totalValuesTransferred[2]), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should successfully transfer a non-fungible token', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); + const valuesToTransfer = [nonFungibleValueToTransfer]; + const perUnitValue = perUnitValueNft; + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Token.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // check balances after transfer + const expectedFinalBalances = [ + // spender + nftNotOwnerBalance, + // receiver + nftOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should successfully transfer multiple non-fungible tokens', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); + const valuesToTransfer = [nonFungibleValueToTransfer, nonFungibleValueToTransfer, nonFungibleValueToTransfer]; + const perUnitValue = perUnitValueNft; + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + nftOwnerBalance, + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + nftNotOwnerBalance, + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Token.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // check balances after transfer + const expectedFinalBalances = [ + // spender + nftNotOwnerBalance, + nftNotOwnerBalance, + nftNotOwnerBalance, + // receiver + nftOwnerBalance, + nftOwnerBalance, + nftOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should successfully transfer value for a combination of several fungible/non-fungible tokens', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const fungibleTokensToTransfer = fungibleTokens.slice(0, 3); + const nonFungibleTokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 2); + const tokensToTransfer = fungibleTokensToTransfer.concat(nonFungibleTokensToTransfer); + const valuesToTransfer = [ + fungibleValueToTransferLarge, + fungibleValueToTransferSmall, + fungibleValueToTransferSmall, + nonFungibleValueToTransfer, + nonFungibleValueToTransfer, + ]; + const perUnitValue = perUnitValueNft; + // check balances before transfer + const expectedInitialBalances = [ + // spender + spenderInitialFungibleBalance, + spenderInitialFungibleBalance, + spenderInitialFungibleBalance, + nftOwnerBalance, + nftOwnerBalance, + // receiver + receiverInitialFungibleBalance, + receiverInitialFungibleBalance, + receiverInitialFungibleBalance, + nftNotOwnerBalance, + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Token.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // check balances after transfer + const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => {return value.times(perUnitValue)}); + const expectedFinalBalances = [ + // spender + expectedInitialBalances[0].minus(totalValuesTransferred[0]), + expectedInitialBalances[1].minus(totalValuesTransferred[1]), + expectedInitialBalances[2].minus(totalValuesTransferred[2]), + expectedInitialBalances[3].minus(totalValuesTransferred[3]), + expectedInitialBalances[4].minus(totalValuesTransferred[4]), + // receiver + expectedInitialBalances[5].plus(totalValuesTransferred[0]), + expectedInitialBalances[6].plus(totalValuesTransferred[1]), + expectedInitialBalances[7].plus(totalValuesTransferred[2]), + expectedInitialBalances[8].plus(totalValuesTransferred[3]), + expectedInitialBalances[9].plus(totalValuesTransferred[4]), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should successfully transfer value to a smart contract and trigger its callback', async () => { + // setup test parameters + const tokenHolders = [spender, receiverContract]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = perUnitValueSmall; + const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => {return value.times(perUnitValue)}); + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiverContract, + perUnitValue, + ); + const logDecoder = new LogDecoder(web3Wrapper, artifacts); + const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }) + ); + // check receiver log ignored extra asset data + expect(txReceipt.logs.length).to.be.equal(2); + const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs; + 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(1); + expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); + expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); + expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]); + // note - if the `extraData` is ignored then the receiver log should ignore it as well. + expect(receiverLog.args.data).to.be.deep.equal(receiverCallbackData); + // check balances after transfer + const expectedFinalBalances = [ + expectedInitialBalances[0].minus(totalValuesTransferred[0]), + expectedInitialBalances[1].plus(totalValuesTransferred[0]), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should successfully transfer value and ignore extra assetData', async () => { + // setup test parameters + const tokenHolders = [spender, receiverContract]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = perUnitValueSmall; + const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => {return value.times(perUnitValue)}); + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const extraData = '0102030405060708'; + const encodedAssetDataPlusExtraData = `${encodedAssetData}${extraData}`; + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetDataPlusExtraData, + spender, + receiverContract, + perUnitValue, + ); + const logDecoder = new LogDecoder(web3Wrapper, artifacts); + const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }) + ); + // check receiver log ignored extra asset data + expect(txReceipt.logs.length).to.be.equal(2); + const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs; + 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(1); + expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); + expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); + expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]); + // note - if the `extraData` is ignored then the receiver log should ignore it as well. + expect(receiverLog.args.data).to.be.deep.equal(receiverCallbackData); + // check balances after transfer + const expectedFinalBalances = [ + expectedInitialBalances[0].minus(totalValuesTransferred[0]), + expectedInitialBalances[1].plus(totalValuesTransferred[0]), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should propagate revert reason from erc1155 contract failure', async () => { + // disable transfers + const shouldRejectTransfer = true; + await web3Wrapper.awaitTransactionSuccessAsync( + await erc1155Receiver.setRejectTransferFlag.sendTransactionAsync(shouldRejectTransfer), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // setup test parameters + const tokenHolders = [spender, receiverContract]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiverContract, + perUnitValue, + ); + return await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.TransferRejected, + ); + }); + it('should revert if transferring the same non-fungible token more than once', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const nftToTransfer = nonFungibleTokensOwnedBySpender[0]; + const tokensToTransfer = [nftToTransfer, nftToTransfer]; + const valuesToTransfer = [nonFungibleValueToTransfer, nonFungibleValueToTransfer]; + const perUnitValue = perUnitValueNft; + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Token.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.nftNotOwnedByFromAddress, + ); + }); + it('should revert if tansferring 0 amount of any token', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); + const valuesToTransfer = [nonFungibleValueToTransfer, new BigNumber(0), nonFungibleValueToTransfer]; + const perUnitValue = perUnitValueNft; + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + nftOwnerBalance, + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + nftNotOwnerBalance, + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Token.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.transferGreaterThanZeroRequired, + ); + }); + it('should revert if there is a multiplication overflow', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); + const maxUintValue = (new BigNumber(2)).pow(256).minus(1); + const valuesToTransfer = [nonFungibleValueToTransfer, maxUintValue, nonFungibleValueToTransfer]; + const perUnitValue = new BigNumber(2); + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + nftOwnerBalance, + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + nftNotOwnerBalance, + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + // note - this will overflow because we are trying to transfer `maxUintValue * 2` of the 2nd token + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Token.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.Uint256Overflow, + ); + }); + it('should revert if transferring > 1 instances of a non-fungible token (perUnitValue field >1)', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); + const valuesToTransfer = [nonFungibleValueToTransfer]; + const perUnitValue = new BigNumber(2); + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Token.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.amountEqualToOneRequired, + ); + }); + it('should revert if transferring > 1 instances of a non-fungible token (`valuesToTransfer` field >1)', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); + const valuesToTransfer = [new BigNumber(2)]; + const perUnitValue = perUnitValueNft; + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Token.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.amountEqualToOneRequired, + ); + }); + it('should revert if sender balance is insufficient', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valueGreaterThanSpenderBalance = spenderInitialFungibleBalance.plus(1); + const valuesToTransfer = [valueGreaterThanSpenderBalance]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.Uint256Underflow, + ); + }); + it('should revert if sender allowance is insufficient', async () => { + // dremove allowance for ERC1155 proxy + const wrapper = erc1155ProxyWrapper.getTokenWrapper(erc1155Token.address); + const isApproved = false; + await wrapper.setApprovalForAllAsync(spender, erc1155Proxy.address, isApproved); + const isApprovedActualValue = await wrapper.isApprovedForAllAsync(spender, erc1155Proxy.address); + expect(isApprovedActualValue).to.be.equal(isApproved); + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.InsufficientAllowance, + ); + }); + it('should revert if caller is not authorized', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: notAuthorized, + }), + RevertReason.SenderNotAuthorized, + ); + }); + }); + }); +}); +// tslint:enable:no-unnecessary-type-assertion +// tslint:disable:max-file-line-count From 054c0e91a34860bc9746bbe318f459ad4fd52a3a Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 4 Mar 2019 13:28:10 -0800 Subject: [PATCH 09/29] removed erc1155 proxy tests from general proxy test file --- contracts/asset-proxy/test/erc1155_proxy.ts | 19 +- contracts/asset-proxy/test/proxies.ts | 737 +------------------- 2 files changed, 4 insertions(+), 752 deletions(-) diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index 14db6c3c91..4a2982f6b8 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -11,33 +11,21 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils } from '@0x/order-utils'; import { RevertReason } from '@0x/types'; -import { BigNumber, AbiEncoder } from '@0x/utils'; +import { BigNumber } from '@0x/utils'; import * as chai from 'chai'; import { LogWithDecodedArgs } from 'ethereum-types'; import * as _ from 'lodash'; import { artifacts, - DummyERC20TokenContract, - DummyERC20TokenTransferEventArgs, - DummyERC721ReceiverContract, - DummyERC721TokenContract, - DummyMultipleReturnERC20TokenContract, - DummyNoReturnERC20TokenContract, - ERC20ProxyContract, - ERC20Wrapper, ERC721ProxyContract, - ERC721Wrapper, ERC1155ProxyWrapper, - ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract, - MultiAssetProxyContract, ERC1155MintableContract, DummyERC1155ReceiverContract, DummyERC1155ReceiverBatchTokenReceivedEventArgs, } from '../src'; -import values from 'ramda/es/values'; import { Erc1155Wrapper } from '../../erc1155/lib/src'; chaiSetup.configure(); @@ -48,11 +36,6 @@ const assetProxyInterface = new IAssetProxyContract( constants.NULL_ADDRESS, provider, ); -const assetDataInterface = new IAssetDataContract( - artifacts.IAssetData.compilerOutput.abi, - constants.NULL_ADDRESS, - provider, -); // tslint:disable:no-unnecessary-type-assertion describe.only('ERC1155Proxy', () => { diff --git a/contracts/asset-proxy/test/proxies.ts b/contracts/asset-proxy/test/proxies.ts index 1dbec9f394..7977871358 100644 --- a/contracts/asset-proxy/test/proxies.ts +++ b/contracts/asset-proxy/test/proxies.ts @@ -23,7 +23,7 @@ import { import { BlockchainLifecycle } from '@0x/dev-utils'; import { assetDataUtils } from '@0x/order-utils'; import { RevertReason } from '@0x/types'; -import { BigNumber, AbiEncoder } from '@0x/utils'; +import { BigNumber } from '@0x/utils'; import * as chai from 'chai'; import { LogWithDecodedArgs } from 'ethereum-types'; import * as _ from 'lodash'; @@ -34,16 +34,10 @@ import { ERC20Wrapper, ERC721ProxyContract, ERC721Wrapper, - ERC1155ProxyWrapper, - ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract, MultiAssetProxyContract, - ERC1155MintableContract, - DummyERC1155ReceiverContract, - DummyERC1155ReceiverBatchTokenReceivedEventArgs, } from '../src'; -import values from 'ramda/es/values'; chaiSetup.configure(); const expect = chai.expect; @@ -74,22 +68,15 @@ describe('Asset Transfer Proxies', () => { let erc721Receiver: DummyERC721ReceiverContract; let erc20Proxy: ERC20ProxyContract; let erc721Proxy: ERC721ProxyContract; - let erc1155Proxy: ERC721ProxyContract; - let erc1155Receiver: DummyERC1155ReceiverContract; let noReturnErc20Token: DummyNoReturnERC20TokenContract; let multipleReturnErc20Token: DummyMultipleReturnERC20TokenContract; let multiAssetProxy: MultiAssetProxyContract; let erc20Wrapper: ERC20Wrapper; let erc721Wrapper: ERC721Wrapper; - let erc1155ProxyWrapper: ERC1155ProxyWrapper; let erc721AFromTokenId: BigNumber; let erc721BFromTokenId: BigNumber; - let erc1155Token: ERC1155MintableContract; - let erc1155FungibleTokenIds: BigNumber[]; - let erc1155NonFungibleTokenIds: BigNumber[]; - before(async () => { await blockchainLifecycle.startAsync(); }); @@ -102,12 +89,10 @@ describe('Asset Transfer Proxies', () => { erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner); - erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner); // Deploy AssetProxies erc20Proxy = await erc20Wrapper.deployProxyAsync(); erc721Proxy = await erc721Wrapper.deployProxyAsync(); - erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync(); multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync( artifacts.MultiAssetProxy, provider, @@ -142,20 +127,6 @@ describe('Asset Transfer Proxies', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); - // Configure ERC1155Proxy - await web3Wrapper.awaitTransactionSuccessAsync( - await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, { - from: owner, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, { - from: owner, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Configure MultiAssetProxy await web3Wrapper.awaitTransactionSuccessAsync( await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(authorized, { @@ -237,22 +208,11 @@ describe('Asset Transfer Proxies', () => { provider, txDefaults, ); + await erc721Wrapper.setBalancesAndAllowancesAsync(); const erc721Balances = await erc721Wrapper.getBalancesAsync(); erc721AFromTokenId = erc721Balances[fromAddress][erc721TokenA.address][0]; erc721BFromTokenId = erc721Balances[fromAddress][erc721TokenB.address][0]; - - // Deploy and configure ERC1155 tokens and receiver - const [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyTokensAsync(); - erc1155Token = erc1155Wrapper.getContract(); - erc1155Receiver = await DummyERC1155ReceiverContract.deployFrom0xArtifactAsync( - artifacts.DummyERC1155Receiver, - provider, - txDefaults, - ); - await erc1155ProxyWrapper.setBalancesAndAllowancesAsync(); - erc1155FungibleTokenIds = erc1155ProxyWrapper.getFungibleTokenIds(); - erc1155NonFungibleTokenIds = erc1155ProxyWrapper.getNonFungibleTokenIds(); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); @@ -517,6 +477,7 @@ describe('Asset Transfer Proxies', () => { }); }); }); + describe('ERC721Proxy', () => { it('should revert if undefined function is called', async () => { const undefinedSelector = '0x01020304'; @@ -1325,698 +1286,6 @@ describe('Asset Transfer Proxies', () => { }); }); }); - describe('ERC1155Proxy', () => { - it('should revert if undefined function is called', async () => { - const undefinedSelector = '0x01020304'; - await expectTransactionFailedWithoutReasonAsync( - web3Wrapper.sendTransactionAsync({ - from: owner, - to: erc1155Proxy.address, - value: constants.ZERO_AMOUNT, - data: undefinedSelector, - }), - ); - }); - it('should have an id of 0x9645780d', async () => { - const proxyId = await erc1155Proxy.getProxyId.callAsync(); - // proxy computed using -- bytes4(keccak256("ERC1155Token(address,uint256[],uint256[],bytes)")); - const expectedProxyId = '0x9645780d'; - expect(proxyId).to.equal(expectedProxyId); - }); - describe('transferFrom', () => { - it('should successfully transfer value for a single token', async () => { - // Construct ERC1155 asset data - const callbackData = "0x"; - const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; - const tokenIdsToTransfer = [fungibleTokenIdToTransfer]; - const tokenValuesToTransfer = [new BigNumber(10)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Verify pre-condition - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1000); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - toAddress, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify transfer was successful - const totalValueTransferred = tokenValuesToTransfer[0].times(perUnitValue); - const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); - const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const expectedNewReceiverBalance = initialReceiverBalance.plus(totalValueTransferred); - expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); - expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); - }); - it('should successfully transfer value for a collection of fungible tokens of the same id', async () => { - // Construct ERC1155 asset data - const callbackData = "0x"; - const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; - const tokenIdsToTransfer = [fungibleTokenIdToTransfer, fungibleTokenIdToTransfer, fungibleTokenIdToTransfer]; - const tokenValuesToTransfer = [new BigNumber(10), new BigNumber(20), new BigNumber(30)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Verify pre-condition - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1000); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - toAddress, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify transfer was successful - const totalValueTransferred = _.reduce(tokenValuesToTransfer, (sum: BigNumber, value: BigNumber) => {return sum.plus(value)}, new BigNumber(0)).times(perUnitValue); - const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); - const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const expectedNewReceiverBalance = initialReceiverBalance.plus(totalValueTransferred); - expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); - expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); - }); - it('should successfully transfer value for a collection of fungible tokens of different ids', async () => { - // Construct ERC1155 asset data - const callbackData = "0x"; - const tokenIdsToTransfer = erc1155FungibleTokenIds.slice(0, 2); - const tokenValuesToTransfer = [new BigNumber(10), new BigNumber(20)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Verify pre-condition - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const initialSenderBalances: BigNumber[] = []; - const initialReceiverBalances: BigNumber[] = []; - _.each(tokenIdsToTransfer, (tokenIdToTransfer: BigNumber) => { - initialSenderBalances.push(initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][tokenIdToTransfer.toString()]); - initialReceiverBalances.push(initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][tokenIdToTransfer.toString()]); - }); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1000); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - toAddress, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify transfer was successful - const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - _.each(tokenIdsToTransfer, (tokenIdToTransfer: BigNumber, i: number) => { - const totalValueTransferred = tokenValuesToTransfer[i].times(perUnitValue); - const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][tokenIdToTransfer.toString()]; - const expectedNewSenderBalance = initialSenderBalances[i].minus(totalValueTransferred); - const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][tokenIdToTransfer.toString()]; - const expectedNewReceiverBalance = initialReceiverBalances[i].plus(totalValueTransferred); - expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); - expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); - }); - }); - it('should successfully transfer a non-fungible token', async () => { - // Construct ERC1155 asset data - const callbackData = "0x"; - const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; - const tokenIdsToTransfer = [nftToTransfer]; - const tokenValuesToTransfer = [new BigNumber(1)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Verify precondition - const nftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); - expect(nftHolder).to.be.equal(fromAddress); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - toAddress, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify transfer was successful - const newNftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); - expect(newNftHolder).to.be.equal(toAddress); - // Verify balances updated successfully - const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const newNftsForFromAddress = newHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; - const newNftsForToAddress = newHoldingsByOwner.nonFungible[toAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; - expect(_.find(newNftsForFromAddress, nftToTransfer)).to.be.undefined(); - expect(_.find(newNftsForToAddress, nftToTransfer)).to.be.not.undefined(); - }); - it('should successfully transfer value for a combination of fungible/non-fungible tokens', async () => { - // Construct ERC1155 asset data - const callbackData = "0x"; - const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; - const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; - const tokenIdsToTransfer = [fungibleTokenIdToTransfer, nftToTransfer]; - const tokenValuesToTransfer = [new BigNumber(10), new BigNumber(1)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Verify precondition - const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const nftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); - expect(nftHolder).to.be.equal(fromAddress); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - toAddress, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify non-fungible transfer was successful - const newNftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); - expect(newNftHolder).to.be.equal(toAddress); - // Verify non-fungible balances updated successfully - const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const newNftsForFromAddress = newHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; - const newNftsForToAddress = newHoldingsByOwner.nonFungible[toAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()]; - expect(_.find(newNftsForFromAddress, nftToTransfer)).to.be.undefined(); - expect(_.find(newNftsForToAddress, nftToTransfer)).to.be.not.undefined(); - // Verify fungible transfer was successful - const totalValueTransferred = tokenValuesToTransfer[0].times(perUnitValue); - const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); - const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const expectedNewReceiverBalance = initialReceiverBalance.plus(totalValueTransferred); - expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); - expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); - }); - it('should successfully transfer value for a combination of several fungible/non-fungible tokens', async () => { - // Check inital balances and construct asset data - const erc1155Wrapper = erc1155ProxyWrapper.getTokenWrapper(erc1155Token.address); - const spenderInitialFungibleBalance = constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; - const receiverInitialFungibleBalance = constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; - const expectedInitialBalances = [ - // spender balances - spenderInitialFungibleBalance, - spenderInitialFungibleBalance, - spenderInitialFungibleBalance, - new BigNumber(1), - new BigNumber(1), - // receiver balances - receiverInitialFungibleBalance, - receiverInitialFungibleBalance, - receiverInitialFungibleBalance, - new BigNumber(0), - new BigNumber(0), - ]; - const tokenHolders = [ - fromAddress, - toAddress, - ]; - const fungibleTokenIdsToTransfer = erc1155FungibleTokenIds.slice(0, 3); - const nonFungibleTokenIdsToTransfer = erc1155NonFungibleTokenIds.slice(0, 2); - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const nftsToTransfer = [ - initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdsToTransfer[0].toString()][0], - initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdsToTransfer[1].toString()][0], - ]; - const tokenIdsToTransfer = fungibleTokenIdsToTransfer.concat(nftsToTransfer); - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokenIdsToTransfer, expectedInitialBalances); - const callbackData = "0x"; - const tokenValuesToTransfer = [spenderInitialFungibleBalance, spenderInitialFungibleBalance, spenderInitialFungibleBalance, new BigNumber(1),new BigNumber(1)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - toAddress, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Check final balances - const expectedFinalBalances = [ - // spender balances - new BigNumber(0), - new BigNumber(0), - new BigNumber(0), - new BigNumber(0), - new BigNumber(0), - // receiver balances - receiverInitialFungibleBalance.plus(spenderInitialFungibleBalance), - receiverInitialFungibleBalance.plus(spenderInitialFungibleBalance), - receiverInitialFungibleBalance.plus(spenderInitialFungibleBalance), - new BigNumber(1), - new BigNumber(1), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokenIdsToTransfer, expectedFinalBalances); - }); - it('should successfully transfer value and ignore extra assetData', async () => { - // Construct ERC1155 asset data - const callbackData = "0x"; - const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; - const tokenIdsToTransfer = [fungibleTokenIdToTransfer]; - const tokenValuesToTransfer = [new BigNumber(10)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - const extraData = '0102030405060708'; - const encodedAssetDataPlusExtraData = `${encodedAssetData}${extraData}`; - // Verify pre-condition - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const initialReceiverBalance = initialHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1000); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetDataPlusExtraData, - fromAddress, - toAddress, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Verify transfer was successful - const totalValueTransferred = tokenValuesToTransfer[0].times(perUnitValue); - const newHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const newSenderBalance = newHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const expectedNewSenderBalance = initialSenderBalance.minus(totalValueTransferred); - const newReceiverBalance = newHoldingsByOwner.fungible[toAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - const expectedNewReceiverBalance = initialReceiverBalance.plus(totalValueTransferred); - expect(newSenderBalance).to.be.bignumber.equal(expectedNewSenderBalance); - expect(newReceiverBalance).to.be.bignumber.equal(expectedNewReceiverBalance); - }); - it('should successfully execute callback when transferring to a smart contract', async () => { - // Construct ERC1155 asset data - const callbackData = "0x"; - const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; - const tokenIdsToTransfer = [nftToTransfer]; - const tokenValuesToTransfer = [new BigNumber(1)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Verify precondition - const nftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); - expect(nftHolder).to.be.equal(fromAddress); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - erc1155Receiver.address, - perUnitValue, - ); - const logDecoder = new LogDecoder(web3Wrapper, artifacts); - const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }) - ); - // Verify logs - expect(txReceipt.logs.length).to.be.equal(2); - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs; - expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address); - expect(receiverLog.args.from).to.be.equal(fromAddress); - expect(receiverLog.args.tokenIds.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokenIdsToTransfer[0]); - expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(tokenValuesToTransfer[0]); - expect(receiverLog.args.data).to.be.deep.equal(callbackData); - // Verify transfer was successful - const newNftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); - expect(newNftHolder).to.be.equal(erc1155Receiver.address); - }); - it('should successfully execute callback when transferring to a smart contract when there is callback data', async () => { - // Construct ERC1155 asset data - const callbackData = "0x12345678"; - const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; - const tokenIdsToTransfer = [nftToTransfer]; - const tokenValuesToTransfer = [new BigNumber(1)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Verify precondition - const nftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); - expect(nftHolder).to.be.equal(fromAddress); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - erc1155Receiver.address, - perUnitValue, - ); - const logDecoder = new LogDecoder(web3Wrapper, artifacts); - const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }) - ); - // Verify logs - expect(txReceipt.logs.length).to.be.equal(2); - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs; - expect(receiverLog.args.operator).to.be.equal(erc1155Proxy.address); - expect(receiverLog.args.from).to.be.equal(fromAddress); - expect(receiverLog.args.tokenIds.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokenIdsToTransfer[0]); - expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(tokenValuesToTransfer[0]); - expect(receiverLog.args.data).to.be.deep.equal(callbackData); - // Verify transfer was successful - const newNftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); - expect(newNftHolder).to.be.equal(erc1155Receiver.address); - }); - it('should propagate revert reason from erc1155 contract failure', async () => { - // Disable transfers - const shouldRejectTransfer = true; - await web3Wrapper.awaitTransactionSuccessAsync( - await erc1155Receiver.setRejectTransferFlag.sendTransactionAsync(shouldRejectTransfer), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // Construct ERC1155 asset data - const callbackData = "0x12345678"; - const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; - const tokenIdsToTransfer = [nftToTransfer]; - const tokenValuesToTransfer = [new BigNumber(1)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - erc1155Receiver.address, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.TransferRejected, - ); - }); - it('should revert if transferring the same non-fungible token more than once', async () => { - // Construct ERC1155 asset data - const callbackData = "0x12345678"; - const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; - const tokenIdsToTransfer = [nftToTransfer, nftToTransfer]; - const tokenValuesToTransfer = [new BigNumber(1), new BigNumber(1)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Verify precondition - const nftHolder = await erc1155ProxyWrapper.ownerOfNonFungibleAsync(erc1155Token.address, nftToTransfer); - expect(nftHolder).to.be.equal(fromAddress); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - erc1155Receiver.address, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.nftNotOwnedByFromAddress, - ); - }); - it('should revert if tansferring 0 amount of any token', async () => { - // Construct ERC1155 asset data - const callbackData = "0x12345678"; - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const tokenIdsToTransfer = [ - initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][erc1155NonFungibleTokenIds[0].toString()][0], - initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][erc1155NonFungibleTokenIds[1].toString()][0], - initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][erc1155NonFungibleTokenIds[2].toString()][0], - ]; - const tokenValuesToTransfer = [new BigNumber(1), new BigNumber(0), new BigNumber(1)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - erc1155Receiver.address, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.transferGreaterThanZeroRequired, - ); - }); - it('should revert if there is a multiplication overflow', async () => { - // Construct ERC1155 asset data - const callbackData = "0x"; - const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; - const tokenIdsToTransfer = [fungibleTokenIdToTransfer]; - const maxUintValue = (new BigNumber(2)).pow(256).minus(1); - const tokenValuesToTransfer = [maxUintValue]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(2); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - toAddress, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.Uint256Overflow, - ); - }); - it('should revert if there is a multiplication overflow, when transferring multiple tokens', async () => { - // Construct ERC1155 asset data - const callbackData = "0x"; - const tokenIdsToTransfer = erc1155FungibleTokenIds.slice(3); - const maxUintValue = (new BigNumber(2)).pow(256).minus(1); - // Note - the second token will fail - const tokenValuesToTransfer = [new BigNumber(1), maxUintValue, new BigNumber(1)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(2); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - toAddress, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.Uint256Overflow, - ); - }); - it('should revert if transferring > 1 instances of a non-fungible token (amount field >1)', async () => { - // Construct ERC1155 asset data - const callbackData = "0x"; - const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; - const tokenIdsToTransfer = [nftToTransfer]; - const tokenValuesToTransfer = [new BigNumber(1)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(2); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - toAddress, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.amountEqualToOneRequired, - ); - }); - it('should revert if transferring > 1 instances of a non-fungible token (value field >1)', async () => { - // Construct ERC1155 asset data - const callbackData = "0x"; - const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; - const tokenIdsToTransfer = [nftToTransfer]; - const tokenValuesToTransfer = [new BigNumber(2)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - toAddress, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.amountEqualToOneRequired, - ); - }); - it('should revert if sender balance is insufficient', async () => { - // Verify pre-condition - const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - // Construct ERC1155 asset data - const callbackData = "0x"; - const tokenIdsToTransfer = [fungibleTokenIdToTransfer]; - const tokenValuesToTransfer = [initialSenderBalance.plus(1)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - toAddress, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.Uint256Underflow, - ); - }); - it('should revert if sender allowance is insufficient', async () => { - // Unapprove ERC1155 proxy - const wrapper = erc1155ProxyWrapper.getTokenWrapper(erc1155Token.address); - const isApproved = false; - await wrapper.setApprovalForAllAsync(fromAddress, erc1155Proxy.address, isApproved); - const isApprovedActualValue = await wrapper.isApprovedForAllAsync(fromAddress, erc1155Proxy.address); - expect(isApprovedActualValue).to.be.equal(isApproved); - // Verify pre-condition - const fungibleTokenIdToTransfer = erc1155FungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const initialSenderBalance = initialHoldingsByOwner.fungible[fromAddress][erc1155Token.address][fungibleTokenIdToTransfer.toString()]; - // Construct ERC1155 asset data - const callbackData = "0x"; - const tokenIdsToTransfer = [fungibleTokenIdToTransfer]; - const tokenValuesToTransfer = [initialSenderBalance]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - toAddress, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.InsufficientAllowance, - ); - }); - it('should revert if caller is not authorized', async () => { - // Construct ERC1155 asset data - const callbackData = "0x12345678"; - const nonFungibleTokenIdToTransfer = erc1155NonFungibleTokenIds[0]; - const initialHoldingsByOwner = await erc1155ProxyWrapper.getBalancesAsync(); - const nftToTransfer = initialHoldingsByOwner.nonFungible[fromAddress][erc1155Token.address][nonFungibleTokenIdToTransfer.toString()][0]; - const tokenIdsToTransfer = [nftToTransfer]; - const tokenValuesToTransfer = [new BigNumber(1)]; - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokenIdsToTransfer, tokenValuesToTransfer, callbackData); - // Perform a transfer from fromAddress to toAddress - const perUnitValue = new BigNumber(1); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - fromAddress, - erc1155Receiver.address, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: notAuthorized, - }), - RevertReason.SenderNotAuthorized, - ); - }); - }); - }); }); // tslint:enable:no-unnecessary-type-assertion // tslint:disable:max-file-line-count From 888c17353b328e368cbf98e386a0f32a1d062d1f Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 4 Mar 2019 18:12:12 -0800 Subject: [PATCH 10/29] Renamed erc1155token to erc1155Contract in proxy tests --- contracts/asset-proxy/test/erc1155_proxy.ts | 45 ++++++++++----------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index 4a2982f6b8..9002b7579c 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -48,7 +48,6 @@ describe.only('ERC1155Proxy', () => { const fungibleValueToTransferSmall = spenderInitialFungibleBalance.div(100); const fungibleValueToTransferLarge = spenderInitialFungibleBalance.div(4); const perUnitValueSmall = new BigNumber(2); - const perUnitValueLarge = new BigNumber(100); const perUnitValueNft = new BigNumber(1); const nonFungibleValueToTransfer = nftOwnerBalance; const receiverCallbackData = '0x01020304'; @@ -63,7 +62,7 @@ describe.only('ERC1155Proxy', () => { let erc1155Proxy: ERC721ProxyContract; let erc1155Receiver: DummyERC1155ReceiverContract; let erc1155ProxyWrapper: ERC1155ProxyWrapper; - let erc1155Token: ERC1155MintableContract; + let erc1155Contract: ERC1155MintableContract; let erc1155Wrapper: Erc1155Wrapper; // tokens let fungibleTokens: BigNumber[]; @@ -95,7 +94,7 @@ describe.only('ERC1155Proxy', () => { );; // deploy & configure ERC1155 tokens and receiver [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyTokensAsync(); - erc1155Token = erc1155Wrapper.getContract(); + erc1155Contract = erc1155Wrapper.getContract(); erc1155Receiver = await DummyERC1155ReceiverContract.deployFrom0xArtifactAsync( artifacts.DummyERC1155Receiver, provider, @@ -109,7 +108,7 @@ describe.only('ERC1155Proxy', () => { nonFungibleTokensOwnedBySpender = []; _.each(nonFungibleTokens, (nonFungibleToken: BigNumber) => { const nonFungibleTokenAsString = nonFungibleToken.toString(); - const nonFungibleTokenHeldBySpender = tokenBalances.nonFungible[spender][erc1155Token.address][nonFungibleTokenAsString][0]; + const nonFungibleTokenHeldBySpender = tokenBalances.nonFungible[spender][erc1155Contract.address][nonFungibleTokenAsString][0]; nonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender); }); }); @@ -133,7 +132,7 @@ describe.only('ERC1155Proxy', () => { }); it('should have an id of 0x9645780d', async () => { const proxyId = await erc1155Proxy.getProxyId.callAsync(); - // proxy computed using -- bytes4(keccak256("ERC1155Token(address,uint256[],uint256[],bytes)")); + // proxy computed using -- bytes4(keccak256("erc1155Contract(address,uint256[],uint256[],bytes)")); const expectedProxyId = '0x9645780d'; expect(proxyId).to.equal(expectedProxyId); }); @@ -148,7 +147,7 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, spender, @@ -188,7 +187,7 @@ describe.only('ERC1155Proxy', () => { await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedInitialBalances); // execute transfer const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Token.address, + erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData @@ -238,7 +237,7 @@ describe.only('ERC1155Proxy', () => { await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Token.address, + erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData @@ -287,7 +286,7 @@ describe.only('ERC1155Proxy', () => { await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Token.address, + erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData @@ -335,7 +334,7 @@ describe.only('ERC1155Proxy', () => { await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Token.address, + erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData @@ -399,7 +398,7 @@ describe.only('ERC1155Proxy', () => { await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Token.address, + erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData @@ -447,7 +446,7 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, spender, @@ -491,7 +490,7 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); const extraData = '0102030405060708'; const encodedAssetDataPlusExtraData = `${encodedAssetData}${extraData}`; const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( @@ -542,7 +541,7 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, spender, @@ -577,7 +576,7 @@ describe.only('ERC1155Proxy', () => { await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Token.address, + erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData @@ -617,7 +616,7 @@ describe.only('ERC1155Proxy', () => { await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Token.address, + erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData @@ -659,7 +658,7 @@ describe.only('ERC1155Proxy', () => { // execute transfer // note - this will overflow because we are trying to transfer `maxUintValue * 2` of the 2nd token const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Token.address, + erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData @@ -695,7 +694,7 @@ describe.only('ERC1155Proxy', () => { await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Token.address, + erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData @@ -731,7 +730,7 @@ describe.only('ERC1155Proxy', () => { await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Token.address, + erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData @@ -762,7 +761,7 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, spender, @@ -780,7 +779,7 @@ describe.only('ERC1155Proxy', () => { }); it('should revert if sender allowance is insufficient', async () => { // dremove allowance for ERC1155 proxy - const wrapper = erc1155ProxyWrapper.getTokenWrapper(erc1155Token.address); + const wrapper = erc1155ProxyWrapper.getTokenWrapper(erc1155Contract.address); const isApproved = false; await wrapper.setApprovalForAllAsync(spender, erc1155Proxy.address, isApproved); const isApprovedActualValue = await wrapper.isApprovedForAllAsync(spender, erc1155Proxy.address); @@ -794,7 +793,7 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, spender, @@ -820,7 +819,7 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Token.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, spender, From 55c4fc9aca3144abeaa561d1f76b775cfee5f699 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 5 Mar 2019 08:02:52 -0800 Subject: [PATCH 11/29] Ran prettier / linter --- contracts/asset-proxy/package.json | 1 + contracts/asset-proxy/test/erc1155_proxy.ts | 207 ++++++++++++------ .../test/utils/erc1155_proxy_wrapper.ts | 120 ++++++---- contracts/test-utils/src/types.ts | 12 +- packages/order-utils/src/asset_data_utils.ts | 11 +- 5 files changed, 228 insertions(+), 123 deletions(-) diff --git a/contracts/asset-proxy/package.json b/contracts/asset-proxy/package.json index 3af5307d74..c59e6bde7e 100644 --- a/contracts/asset-proxy/package.json +++ b/contracts/asset-proxy/package.json @@ -70,6 +70,7 @@ "@0x/base-contract": "^5.0.2", "@0x/contracts-erc20": "^1.0.9", "@0x/contracts-erc721": "^1.0.9", + "@0x/contracts-erc1155": "^1.0.0", "@0x/contracts-utils": "2.0.1", "@0x/order-utils": "^7.0.2", "@0x/types": "^2.1.1", diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index 9002b7579c..c80a6b7212 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -16,17 +16,16 @@ import * as chai from 'chai'; import { LogWithDecodedArgs } from 'ethereum-types'; import * as _ from 'lodash'; +import { Erc1155Wrapper } from '../../erc1155/lib/src'; import { artifacts, - ERC721ProxyContract, - ERC1155ProxyWrapper, - IAssetDataContract, - IAssetProxyContract, - ERC1155MintableContract, - DummyERC1155ReceiverContract, DummyERC1155ReceiverBatchTokenReceivedEventArgs, + DummyERC1155ReceiverContract, + ERC1155MintableContract, + ERC1155ProxyWrapper, + ERC721ProxyContract, + IAssetProxyContract, } from '../src'; -import { Erc1155Wrapper } from '../../erc1155/lib/src'; chaiSetup.configure(); const expect = chai.expect; @@ -91,7 +90,7 @@ describe.only('ERC1155Proxy', () => { from: owner, }), constants.AWAIT_TRANSACTION_MINED_MS, - );; + ); // deploy & configure ERC1155 tokens and receiver [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyTokensAsync(); erc1155Contract = erc1155Wrapper.getContract(); @@ -108,7 +107,8 @@ describe.only('ERC1155Proxy', () => { nonFungibleTokensOwnedBySpender = []; _.each(nonFungibleTokens, (nonFungibleToken: BigNumber) => { const nonFungibleTokenAsString = nonFungibleToken.toString(); - const nonFungibleTokenHeldBySpender = tokenBalances.nonFungible[spender][erc1155Contract.address][nonFungibleTokenAsString][0]; + const nonFungibleTokenHeldBySpender = + tokenBalances.nonFungible[spender][erc1155Contract.address][nonFungibleTokenAsString][0]; nonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender); }); }); @@ -147,7 +147,12 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, spender, @@ -175,7 +180,11 @@ describe.only('ERC1155Proxy', () => { const tokenHolders = [spender, receiver]; const tokenToTransfer = fungibleTokens[0]; const tokensToTransfer = [tokenToTransfer, tokenToTransfer, tokenToTransfer]; - const valuesToTransfer = [fungibleValueToTransferSmall.plus(10), fungibleValueToTransferSmall.plus(20), fungibleValueToTransferSmall.plus(30)]; + const valuesToTransfer = [ + fungibleValueToTransferSmall.plus(10), + fungibleValueToTransferSmall.plus(20), + fungibleValueToTransferSmall.plus(30), + ]; const perUnitValue = perUnitValueSmall; // check balances before transfer const expectedInitialBalances = [ @@ -190,7 +199,7 @@ describe.only('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - receiverCallbackData + receiverCallbackData, ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, @@ -207,7 +216,9 @@ describe.only('ERC1155Proxy', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); // check balances after transfer - let totalValueTransferred = _.reduce(valuesToTransfer, (sum: BigNumber, value: BigNumber) => {return sum.plus(value)}) as BigNumber; + let totalValueTransferred = _.reduce(valuesToTransfer, (sum: BigNumber, value: BigNumber) => { + return sum.plus(value); + }) as BigNumber; totalValueTransferred = totalValueTransferred.times(perUnitValue); const expectedFinalBalances = [ // spender @@ -221,7 +232,11 @@ describe.only('ERC1155Proxy', () => { // setup test parameters const tokenHolders = [spender, receiver]; const tokensToTransfer = fungibleTokens.slice(0, 3); - const valuesToTransfer = [fungibleValueToTransferSmall.plus(10), fungibleValueToTransferSmall.plus(20), fungibleValueToTransferSmall.plus(30)]; + const valuesToTransfer = [ + fungibleValueToTransferSmall.plus(10), + fungibleValueToTransferSmall.plus(20), + fungibleValueToTransferSmall.plus(30), + ]; const perUnitValue = perUnitValueSmall; // check balances before transfer const expectedInitialBalances = [ @@ -240,7 +255,7 @@ describe.only('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - receiverCallbackData + receiverCallbackData, ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, @@ -257,7 +272,9 @@ describe.only('ERC1155Proxy', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); // check balances after transfer - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => {return value.times(perUnitValue)}); + const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { + return value.times(perUnitValue); + }); const expectedFinalBalances = [ // spender spenderInitialFungibleBalance.minus(totalValuesTransferred[0]), @@ -289,7 +306,7 @@ describe.only('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - receiverCallbackData + receiverCallbackData, ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, @@ -318,7 +335,11 @@ describe.only('ERC1155Proxy', () => { // setup test parameters const tokenHolders = [spender, receiver]; const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); - const valuesToTransfer = [nonFungibleValueToTransfer, nonFungibleValueToTransfer, nonFungibleValueToTransfer]; + const valuesToTransfer = [ + nonFungibleValueToTransfer, + nonFungibleValueToTransfer, + nonFungibleValueToTransfer, + ]; const perUnitValue = perUnitValueNft; // check balances before transfer const expectedInitialBalances = [ @@ -337,7 +358,7 @@ describe.only('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - receiverCallbackData + receiverCallbackData, ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, @@ -401,7 +422,7 @@ describe.only('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - receiverCallbackData + receiverCallbackData, ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, @@ -418,7 +439,9 @@ describe.only('ERC1155Proxy', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); // check balances after transfer - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => {return value.times(perUnitValue)}); + const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { + return value.times(perUnitValue); + }); const expectedFinalBalances = [ // spender expectedInitialBalances[0].minus(totalValuesTransferred[0]), @@ -441,12 +464,19 @@ describe.only('ERC1155Proxy', () => { const tokensToTransfer = fungibleTokens.slice(0, 1); const valuesToTransfer = [fungibleValueToTransferLarge]; const perUnitValue = perUnitValueSmall; - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => {return value.times(perUnitValue)}); + const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { + return value.times(perUnitValue); + }); // check balances before transfer const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, spender, @@ -459,11 +489,13 @@ describe.only('ERC1155Proxy', () => { to: erc1155Proxy.address, data, from: authorized, - }) + }), ); // check receiver log ignored extra asset data expect(txReceipt.logs.length).to.be.equal(2); - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs; + 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(1); @@ -485,12 +517,19 @@ describe.only('ERC1155Proxy', () => { const tokensToTransfer = fungibleTokens.slice(0, 1); const valuesToTransfer = [fungibleValueToTransferLarge]; const perUnitValue = perUnitValueSmall; - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => {return value.times(perUnitValue)}); + const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { + return value.times(perUnitValue); + }); // check balances before transfer const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); const extraData = '0102030405060708'; const encodedAssetDataPlusExtraData = `${encodedAssetData}${extraData}`; const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( @@ -505,11 +544,13 @@ describe.only('ERC1155Proxy', () => { to: erc1155Proxy.address, data, from: authorized, - }) + }), ); // check receiver log ignored extra asset data expect(txReceipt.logs.length).to.be.equal(2); - const receiverLog = txReceipt.logs[1] as LogWithDecodedArgs; + 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(1); @@ -541,14 +582,19 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, spender, receiverContract, perUnitValue, ); - return await expectTransactionFailedAsync( + await expectTransactionFailedAsync( web3Wrapper.sendTransactionAsync({ to: erc1155Proxy.address, data, @@ -579,7 +625,7 @@ describe.only('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - receiverCallbackData + receiverCallbackData, ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, @@ -619,7 +665,7 @@ describe.only('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - receiverCallbackData + receiverCallbackData, ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, @@ -640,7 +686,7 @@ describe.only('ERC1155Proxy', () => { // setup test parameters const tokenHolders = [spender, receiver]; const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); - const maxUintValue = (new BigNumber(2)).pow(256).minus(1); + const maxUintValue = new BigNumber(2).pow(256).minus(1); const valuesToTransfer = [nonFungibleValueToTransfer, maxUintValue, nonFungibleValueToTransfer]; const perUnitValue = new BigNumber(2); // check balances before transfer @@ -661,7 +707,7 @@ describe.only('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - receiverCallbackData + receiverCallbackData, ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, @@ -679,32 +725,32 @@ describe.only('ERC1155Proxy', () => { ); }); it('should revert if transferring > 1 instances of a non-fungible token (perUnitValue field >1)', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); - const valuesToTransfer = [nonFungibleValueToTransfer]; - const perUnitValue = new BigNumber(2); - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); + const valuesToTransfer = [nonFungibleValueToTransfer]; + const perUnitValue = new BigNumber(2); + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); await expectTransactionFailedAsync( web3Wrapper.sendTransactionAsync({ to: erc1155Proxy.address, @@ -733,7 +779,7 @@ describe.only('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - receiverCallbackData + receiverCallbackData, ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, @@ -741,14 +787,14 @@ describe.only('ERC1155Proxy', () => { receiver, perUnitValue, ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.amountEqualToOneRequired, - ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.amountEqualToOneRequired, + ); }); it('should revert if sender balance is insufficient', async () => { // setup test parameters @@ -761,7 +807,12 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, spender, @@ -793,7 +844,12 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, spender, @@ -819,7 +875,12 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData(erc1155Contract.address, tokensToTransfer, valuesToTransfer, receiverCallbackData); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, spender, diff --git a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts index b70bdb641f..1f73abd62f 100644 --- a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts +++ b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts @@ -1,22 +1,28 @@ -import { constants, ERC1155HoldingsByOwner, ERC1155FungibleHoldingsByOwner, ERC1155NonFungibleHoldingsByOwner, LogDecoder, txDefaults } from '@0x/contracts-test-utils'; -import { generatePseudoRandomSalt } from '@0x/order-utils'; +import { Erc1155Wrapper } from '@0x/contracts-erc1155'; +import { + constants, + ERC1155FungibleHoldingsByOwner, + ERC1155HoldingsByOwner, + ERC1155NonFungibleHoldingsByOwner, + LogDecoder, + txDefaults, +} from '@0x/contracts-test-utils'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { Provider } from 'ethereum-types'; import * as _ from 'lodash'; -import { Erc1155Wrapper } from '@0x/contracts-erc1155'; - -import { LogWithDecodedArgs } from 'ethereum-types'; - -import { artifacts, ERC1155MintableContract, ERC1155ProxyContract, ERC1155MintableTransferSingleEventArgs } from '../../src'; - +import { + artifacts, + ERC1155MintableContract, + ERC1155ProxyContract, +} from '../../src'; export class ERC1155ProxyWrapper { private readonly _tokenOwnerAddresses: string[]; private readonly _fungibleTokenIds: string[]; private readonly _nonFungibleTokenIds: string[]; - private readonly _nfts: {id: BigNumber, tokenId: BigNumber}[]; + private readonly _nfts: Array<{ id: BigNumber; tokenId: BigNumber }>; private readonly _contractOwnerAddress: string; private readonly _web3Wrapper: Web3Wrapper; private readonly _provider: Provider; @@ -24,7 +30,7 @@ export class ERC1155ProxyWrapper { private readonly _dummyTokenWrappers: Erc1155Wrapper[]; private _proxyContract?: ERC1155ProxyContract; private _proxyIdIfExists?: string; - private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = {fungible: {}, nonFungible: {}}; + private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} }; constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { this._web3Wrapper = new Web3Wrapper(provider); this._provider = provider; @@ -44,7 +50,6 @@ export class ERC1155ProxyWrapper { this._provider, txDefaults, ); - console.log(erc1155Contract.address); const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._provider, this._contractOwnerAddress); this._dummyTokenWrappers.push(erc1155Wrapper); } @@ -67,17 +72,22 @@ export class ERC1155ProxyWrapper { this._validateDummyTokenContractsExistOrThrow(); this._validateProxyContractExistsOrThrow(); this._initialTokenIdsByOwner = { - fungible: {} as ERC1155FungibleHoldingsByOwner, - nonFungible: {} + fungible: {}, + nonFungible: {}, }; - const fungibleHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {}; + const fungibleHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {}; const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {}; - // set balances accordingly + // Set balances accordingly + const fungibleTokensToMintRange = _.range(0, constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT); + const nonFungibleTokensToMintRange = _.range(0, constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT); for (const dummyWrapper of this._dummyTokenWrappers) { const dummyAddress = dummyWrapper.getContract().address; - for (const i of _.times(constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT)) { + _.each(fungibleTokensToMintRange, async () => { // Create a fungible token - const tokenId = await dummyWrapper.mintFungibleTokensAsync(this._tokenOwnerAddresses, constants.INITIAL_ERC1155_FUNGIBLE_BALANCE); + const tokenId = await dummyWrapper.mintFungibleTokensAsync( + this._tokenOwnerAddresses, + constants.INITIAL_ERC1155_FUNGIBLE_BALANCE, + ); const tokenIdAsString = tokenId.toString(); this._fungibleTokenIds.push(tokenIdAsString); // Mint tokens for each owner for this token @@ -89,35 +99,44 @@ export class ERC1155ProxyWrapper { if (_.isUndefined(fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress])) { fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {}; } - fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; - await dummyWrapper.setApprovalForAllAsync(tokenOwnerAddress, (this._proxyContract as ERC1155ProxyContract).address, true); + fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = + constants.INITIAL_ERC1155_FUNGIBLE_BALANCE; + await dummyWrapper.setApprovalForAllAsync( + tokenOwnerAddress, + (this._proxyContract as ERC1155ProxyContract).address, + true, + ); } - } - // Non-Fungible Tokens - for (const i of _.times(constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT)) { + }); + // Non-fungible tokens + _.each(nonFungibleTokensToMintRange, async () => { const [tokenId, nftIds] = await dummyWrapper.mintNonFungibleTokensAsync(this._tokenOwnerAddresses); const tokenIdAsString = tokenId.toString(); this._nonFungibleTokenIds.push(tokenIdAsString); _.each(this._tokenOwnerAddresses, async (tokenOwnerAddress: string, i: number) => { - if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress])) { + if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress])) { nonFungibleHoldingsByOwner[tokenOwnerAddress] = {}; - } - if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress])) { + } + if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress])) { nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {}; - } - if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString])) { + } + if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString])) { nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = []; - } - this._nfts.push({id: nftIds[i], tokenId}); - nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString].push(nftIds[i]); - await dummyWrapper.setApprovalForAllAsync(tokenOwnerAddress, (this._proxyContract as ERC1155ProxyContract).address, true); + } + this._nfts.push({ id: nftIds[i], tokenId }); + nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString].push(nftIds[i]); + await dummyWrapper.setApprovalForAllAsync( + tokenOwnerAddress, + (this._proxyContract as ERC1155ProxyContract).address, + true, + ); }); - } + }); } this._initialTokenIdsByOwner = { fungible: fungibleHoldingsByOwner, nonFungible: nonFungibleHoldingsByOwner, - } + }; return this._initialTokenIdsByOwner; } public async ownerOfNonFungibleAsync(tokenAddress: string, tokenId: BigNumber): Promise { @@ -125,7 +144,11 @@ export class ERC1155ProxyWrapper { const owner = await tokenContract.ownerOf.callAsync(tokenId); return owner; } - public async isNonFungibleOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise { + public async isNonFungibleOwnerAsync( + userAddress: string, + tokenAddress: string, + tokenId: BigNumber, + ): Promise { const tokenContract = this._getTokenContractFromAssetData(tokenAddress); const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId); const isOwner = tokenOwner === userAddress; @@ -181,12 +204,18 @@ export class ERC1155ProxyWrapper { if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress])) { nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {}; } - if (_.isUndefined(nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()])) { + if ( + _.isUndefined( + nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()], + ) + ) { nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] = []; } const isOwner = balances[i++]; if (isOwner.isEqualTo(1)) { - nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()].push(nft.id); + nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()].push( + nft.id, + ); } } } @@ -194,22 +223,28 @@ export class ERC1155ProxyWrapper { const holdingsByOwner = { fungible: tokenHoldingsByOwner, nonFungible: nonFungibleHoldingsByOwner, - } + }; return holdingsByOwner; } public getFungibleTokenIds(): BigNumber[] { - const fungibleTokenIds = _.map(this._fungibleTokenIds, (tokenIdAsString: string) => {return new BigNumber(tokenIdAsString)}); + const fungibleTokenIds = _.map(this._fungibleTokenIds, (tokenIdAsString: string) => { + return new BigNumber(tokenIdAsString); + }); return fungibleTokenIds; } public getNonFungibleTokenIds(): BigNumber[] { - const nonFungibleTokenIds = _.map(this._nonFungibleTokenIds, (tokenIdAsString: string) => {return new BigNumber(tokenIdAsString)}); + const nonFungibleTokenIds = _.map(this._nonFungibleTokenIds, (tokenIdAsString: string) => { + return new BigNumber(tokenIdAsString); + }); return nonFungibleTokenIds; } public getTokenOwnerAddresses(): string[] { return this._tokenOwnerAddresses; } public getTokenWrapper(tokenAddress: string): Erc1155Wrapper { - const tokenWrapper = _.find(this._dummyTokenWrappers, (wrapper: Erc1155Wrapper) => {return wrapper.getContract().address === tokenAddress}); + const tokenWrapper = _.find(this._dummyTokenWrappers, (wrapper: Erc1155Wrapper) => { + return wrapper.getContract().address === tokenAddress; + }); if (_.isUndefined(tokenWrapper)) { throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155Wrapper`); } @@ -239,7 +274,10 @@ export class ERC1155ProxyWrapper { } } private _validateBalancesAndAllowancesSetOrThrow(): void { - if (_.keys(this._initialTokenIdsByOwner.fungible).length === 0 || _.keys(this._initialTokenIdsByOwner.nonFungible).length === 0) { + if ( + _.keys(this._initialTokenIdsByOwner.fungible).length === 0 || + _.keys(this._initialTokenIdsByOwner.nonFungible).length === 0 + ) { throw new Error( 'Dummy ERC1155 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"', ); diff --git a/contracts/test-utils/src/types.ts b/contracts/test-utils/src/types.ts index 9cd098bc6a..2b21a7323e 100644 --- a/contracts/test-utils/src/types.ts +++ b/contracts/test-utils/src/types.ts @@ -17,22 +17,22 @@ export interface ERC721TokenIdsByOwner { export interface ERC1155FungibleHoldingsByOwner { [ownerAddress: string]: { [tokenAddress: string]: { - [tokenId: string]: BigNumber - } + [tokenId: string]: BigNumber; + }; }; } export interface ERC1155NonFungibleHoldingsByOwner { [ownerAddress: string]: { [tokenAddress: string]: { - [tokenId: string]: BigNumber[] - } + [tokenId: string]: BigNumber[]; + }; }; } export interface ERC1155HoldingsByOwner { - fungible: ERC1155FungibleHoldingsByOwner, - nonFungible: ERC1155NonFungibleHoldingsByOwner, + fungible: ERC1155FungibleHoldingsByOwner; + nonFungible: ERC1155NonFungibleHoldingsByOwner; } export interface SubmissionContractEventArgs { diff --git a/packages/order-utils/src/asset_data_utils.ts b/packages/order-utils/src/asset_data_utils.ts index ab8aa3443e..68370098ea 100644 --- a/packages/order-utils/src/asset_data_utils.ts +++ b/packages/order-utils/src/asset_data_utils.ts @@ -100,8 +100,13 @@ export const assetDataUtils = { * @return The hex encoded assetData string */ - encodeERC1155AssetData(tokenAddress: string, tokenIds: BigNumber[], tokenValues: BigNumber[], callbackData: string): string { - const abiEncoder = AbiEncoder.createMethod('ERC1155Token', ['address','uint256[]','uint256[]','bytes']); + encodeERC1155AssetData( + tokenAddress: string, + tokenIds: BigNumber[], + tokenValues: BigNumber[], + callbackData: string, + ): string { + const abiEncoder = AbiEncoder.createMethod('ERC1155Token', ['address', 'uint256[]', 'uint256[]', 'bytes']); const args = [tokenAddress, tokenIds, tokenValues, callbackData]; const assetData = abiEncoder.encode(args, encodingRules); return assetData; @@ -186,7 +191,7 @@ export const assetDataUtils = { if ( assetProxyId !== AssetProxyId.ERC20 && assetProxyId !== AssetProxyId.ERC721 && - assetProxyId !== AssetProxyId.ERC1155 && + assetProxyId !== AssetProxyId.ERC1155 && assetProxyId !== AssetProxyId.MultiAsset ) { throw new Error(`Invalid assetProxyId: ${assetProxyId}`); From 5704afc54ca60681479be84507619a75fe438d57 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 5 Mar 2019 08:52:33 -0800 Subject: [PATCH 12/29] ERC1155 Asset Data tests + types --- packages/order-utils/CHANGELOG.json | 9 ++ packages/order-utils/src/asset_data_utils.ts | 86 ++++++++++++++----- .../order-utils/test/asset_data_utils_test.ts | 25 ++++++ packages/types/CHANGELOG.json | 9 ++ packages/types/src/index.ts | 14 +++ 5 files changed, 122 insertions(+), 21 deletions(-) diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index 5d20b98fa1..df3c7e247e 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "7.1.0", + "changes": [ + { + "note": "Added `encodeERC721AssetData` and `decodeERC721AssetData`", + "pr": 1661 + } + ] + }, { "timestamp": 1551479279, "version": "7.0.2", diff --git a/packages/order-utils/src/asset_data_utils.ts b/packages/order-utils/src/asset_data_utils.ts index 68370098ea..e0b9a62771 100644 --- a/packages/order-utils/src/asset_data_utils.ts +++ b/packages/order-utils/src/asset_data_utils.ts @@ -2,6 +2,9 @@ import { AssetProxyId, ERC20AssetData, ERC721AssetData, + ERC1155AssetData, + ERC1155AssetDataAbi, + ERC1155AssetDataNoProxyId, MultiAssetData, MultiAssetDataWithRecursiveDecoding, SingleAssetData, @@ -73,6 +76,46 @@ export const assetDataUtils = { tokenId: (decodedAssetData as any).tokenId, }; }, + /** + * Encodes a set of ERC1155 assets into an assetData string, usable in the makerAssetData or + * takerAssetData fields of a 0x order. + * @param tokenAddress The token address of the ERC1155 contract + * @param tokenIds The Id's of the ERC1155 tokens to transfer + * @param tokenValues The values of each respective token Id to transfer + * @param callbackData The data forwarded to a receiver, if receiver is a contract. + * @return The hex encoded assetData string + */ + encodeERC1155AssetData( + tokenAddress: string, + tokenIds: BigNumber[], + tokenValues: BigNumber[], + callbackData: string, + ): string { + const abiEncoder = AbiEncoder.createMethod('ERC1155Token', ERC1155AssetDataAbi); + const args = [tokenAddress, tokenIds, tokenValues, callbackData]; + const assetData = abiEncoder.encode(args, encodingRules); + return assetData; + }, + /** + * Decodes an ERC1155 assetData hex string into it's corresponding ERC1155 components. + * @param assetData Hex encoded assetData string to decode + * @return An object containing the decoded tokenAddress, tokenIds, tokenValues, callbackData & assetProxyId + */ + decodeERC1155AssetData(assetData: string): ERC1155AssetData { + const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData); + if (assetProxyId !== AssetProxyId.ERC1155) { + throw new Error(`Invalid assetProxyId. Expected '${AssetProxyId.ERC1155}', got '${assetProxyId}'`); + } + const abiEncoder = AbiEncoder.createMethod('ERC1155Token', ERC1155AssetDataAbi); + const decodedAssetData = abiEncoder.decode(assetData, decodingRules) as ERC1155AssetDataNoProxyId; + return { + assetProxyId, + tokenAddress: decodedAssetData.tokenAddress, + tokenIds: decodedAssetData.tokenIds, + tokenValues: decodedAssetData.tokenValues, + callbackData: decodedAssetData.callbackData, + }; + }, /** * Encodes assetData for multiple AssetProxies into a single hex encoded assetData string, usable in the makerAssetData or * takerAssetData fields in a 0x order. @@ -94,23 +137,6 @@ export const assetDataUtils = { const assetData = abiEncoder.encode(args, encodingRules); return assetData; }, - /** - * Encodes assetData for multiple AssetProxies into a single hex encoded assetData string, usable in the makerAssetData or - * takerAssetData fields in a 0x order. - - * @return The hex encoded assetData string - */ - encodeERC1155AssetData( - tokenAddress: string, - tokenIds: BigNumber[], - tokenValues: BigNumber[], - callbackData: string, - ): string { - const abiEncoder = AbiEncoder.createMethod('ERC1155Token', ['address', 'uint256[]', 'uint256[]', 'bytes']); - const args = [tokenAddress, tokenIds, tokenValues, callbackData]; - const assetData = abiEncoder.encode(args, encodingRules); - return assetData; - }, /** * Decodes a MultiAsset assetData hex string into it's corresponding amounts and nestedAssetData * @param assetData Hex encoded assetData string to decode @@ -212,6 +238,13 @@ export const assetDataUtils = { isERC721AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is ERC721AssetData { return decodedAssetData.assetProxyId === AssetProxyId.ERC721; }, + /** + * Checks if the decoded asset data is valid ERC1155 data + * @param decodedAssetData The decoded asset data to check + */ + isERC1155AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is ERC1155AssetData { + return decodedAssetData.assetProxyId === AssetProxyId.ERC1155; + }, /** * Checks if the decoded asset data is valid MultiAsset data * @param decodedAssetData The decoded asset data to check @@ -219,9 +252,6 @@ export const assetDataUtils = { isMultiAssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is MultiAssetData { return decodedAssetData.assetProxyId === AssetProxyId.MultiAsset; }, - isER1155AssetData(decodedAssetData: SingleAssetData | MultiAssetData): decodedAssetData is MultiAssetData { - return decodedAssetData.assetProxyId === AssetProxyId.MultiAsset; - }, /** * Throws if the length or assetProxyId are invalid for the ERC20Proxy. * @param assetData Hex encoded assetData string @@ -264,6 +294,14 @@ export const assetDataUtils = { ); } }, + /** + * Throws if the assetData is not ERC1155. + * @param assetData Hex encoded assetData string + */ + assertIsERC1155AssetData(assetData: string): void { + // If the asset data is correctly decoded then it is valid. + assetDataUtils.decodeERC1155AssetData(assetData); + }, /** * Throws if the length or assetProxyId are invalid for the MultiAssetProxy. * @param assetData Hex encoded assetData string @@ -298,6 +336,9 @@ export const assetDataUtils = { case AssetProxyId.ERC721: assetDataUtils.assertIsERC721AssetData(assetData); break; + case AssetProxyId.ERC1155: + assetDataUtils.assertIsERC1155AssetData(assetData); + break; case AssetProxyId.MultiAsset: assetDataUtils.assertIsMultiAssetData(assetData); break; @@ -308,7 +349,7 @@ export const assetDataUtils = { /** * Decode any assetData into it's corresponding assetData object * @param assetData Hex encoded assetData string to decode - * @return Either a ERC20 or ERC721 assetData object + * @return Either a ERC20, ERC721, ERC1155, or MultiAsset assetData object */ decodeAssetDataOrThrow(assetData: string): SingleAssetData | MultiAssetData { const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData); @@ -319,6 +360,9 @@ export const assetDataUtils = { case AssetProxyId.ERC721: const erc721AssetData = assetDataUtils.decodeERC721AssetData(assetData); return erc721AssetData; + case AssetProxyId.ERC1155: + const erc1155AssetData = assetDataUtils.decodeERC1155AssetData(assetData); + return erc1155AssetData; case AssetProxyId.MultiAsset: const multiAssetData = assetDataUtils.decodeMultiAssetData(assetData); return multiAssetData; diff --git a/packages/order-utils/test/asset_data_utils_test.ts b/packages/order-utils/test/asset_data_utils_test.ts index c498c5a00f..5d28000caf 100644 --- a/packages/order-utils/test/asset_data_utils_test.ts +++ b/packages/order-utils/test/asset_data_utils_test.ts @@ -20,6 +20,14 @@ const KNOWN_ERC721_ENCODING = { assetData: '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001', }; +const KNOWN_ERC1155_ENCODING = { + tokenAddress: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48', + tokenIds: [new BigNumber(100), new BigNumber(1001), new BigNumber(10001)], + tokenValues: [new BigNumber(200), new BigNumber(2001), new BigNumber(20001)], + callbackData: '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001', + assetData: + '0x9645780d0000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000', +}; const KNOWN_MULTI_ASSET_ENCODING = { amounts: [new BigNumber(1), new BigNumber(1)], nestedAssetData: [KNOWN_ERC20_ENCODING.assetData, KNOWN_ERC721_ENCODING.assetData], @@ -50,6 +58,23 @@ describe('assetDataUtils', () => { expect(decodedAssetData.assetProxyId).to.equal(AssetProxyId.ERC721); expect(decodedAssetData.tokenId).to.be.bignumber.equal(KNOWN_ERC721_ENCODING.tokenId); }); + it('should encode ERC1155', () => { + const assetData = assetDataUtils.encodeERC1155AssetData( + KNOWN_ERC1155_ENCODING.tokenAddress, + KNOWN_ERC1155_ENCODING.tokenIds, + KNOWN_ERC1155_ENCODING.tokenValues, + KNOWN_ERC1155_ENCODING.callbackData + ); + expect(assetData).to.equal(KNOWN_ERC1155_ENCODING.assetData); + }); + it('should decode ERC1155', () => { + const decodedAssetData = assetDataUtils.decodeERC1155AssetData(KNOWN_ERC1155_ENCODING.assetData); + expect(decodedAssetData.assetProxyId).to.be.equal(AssetProxyId.ERC1155); + expect(decodedAssetData.tokenAddress).to.be.equal(KNOWN_ERC1155_ENCODING.tokenAddress); + expect(decodedAssetData.tokenValues).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenValues); + expect(decodedAssetData.tokenIds).to.be.deep.equal(KNOWN_ERC1155_ENCODING.tokenIds); + expect(decodedAssetData.callbackData).to.be.equal(KNOWN_ERC1155_ENCODING.callbackData); + }); it('should encode ERC20 and ERC721 multiAssetData', () => { const assetData = assetDataUtils.encodeMultiAssetData( KNOWN_MULTI_ASSET_ENCODING.amounts, diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json index 9b7a07ffcd..1250688fc6 100644 --- a/packages/types/CHANGELOG.json +++ b/packages/types/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "2.2.3", + "changes": [ + { + "note": "Added `ERC1155AssetData`, `ERC1155AssetDataNoProxyId`, and `ERC1155AssetDataAbi`", + "pr": 1661 + } + ] + }, { "version": "2.2.2", "changes": [ diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 4dfc6285bd..f9e809446d 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -185,6 +185,20 @@ export interface ERC1155AssetData { callbackData: string; } +export interface ERC1155AssetDataNoProxyId { + tokenAddress: string, + tokenValues: BigNumber[], + tokenIds: BigNumber[], + callbackData: string +}; + +export const ERC1155AssetDataAbi = [ + {name: 'tokenAddress', type: 'address'}, + {name: 'tokenIds', type: 'uint256[]'}, + {name: 'tokenValues', type: 'uint256[]'}, + {name: 'callbackData', type: 'bytes'}, +]; + export type SingleAssetData = ERC20AssetData | ERC721AssetData | ERC1155AssetData; export interface MultiAssetData { From a86ba7af2e48a1fc4f902c2708c648a1c8b0f05e Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 5 Mar 2019 09:59:20 -0800 Subject: [PATCH 13/29] moved transferFrom into ERC1155 Proxy Wrapper --- contracts/asset-proxy/test/erc1155_proxy.ts | 1442 ++++++++--------- .../test/utils/erc1155_proxy_wrapper.ts | 69 +- 2 files changed, 738 insertions(+), 773 deletions(-) diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index c80a6b7212..0e96a62ff8 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -136,766 +136,696 @@ describe.only('ERC1155Proxy', () => { const expectedProxyId = '0x9645780d'; expect(proxyId).to.equal(expectedProxyId); }); - describe.only('transferFrom', () => { - it('should successfully transfer value for a single, fungible token', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = perUnitValueSmall; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // check balances after transfer - const totalValueTransferred = valuesToTransfer[0].times(perUnitValue); - const expectedFinalBalances = [ - spenderInitialFungibleBalance.minus(totalValueTransferred), - receiverInitialFungibleBalance.plus(totalValueTransferred), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + describe('transferFrom', () => { + it('should successfully transfer value for a single, fungible token', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + await erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ); + // check balances after transfer + const totalValueTransferred = valuesToTransfer[0].times(perUnitValue); + const expectedFinalBalances = [ + spenderInitialFungibleBalance.minus(totalValueTransferred), + receiverInitialFungibleBalance.plus(totalValueTransferred), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should successfully transfer value for the same fungible token several times', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokenToTransfer = fungibleTokens[0]; + const tokensToTransfer = [tokenToTransfer, tokenToTransfer, tokenToTransfer]; + const valuesToTransfer = [ + fungibleValueToTransferSmall.plus(10), + fungibleValueToTransferSmall.plus(20), + fungibleValueToTransferSmall.plus(30), + ]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [ + // spender + spenderInitialFungibleBalance, + // receiver + receiverInitialFungibleBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedInitialBalances); + // execute transfer + await erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ); + // check balances after transfer + let totalValueTransferred = _.reduce(valuesToTransfer, (sum: BigNumber, value: BigNumber) => { + return sum.plus(value); + }) as BigNumber; + totalValueTransferred = totalValueTransferred.times(perUnitValue); + const expectedFinalBalances = [ + // spender + spenderInitialFungibleBalance.minus(totalValueTransferred), + // receiver + receiverInitialFungibleBalance.plus(totalValueTransferred), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedFinalBalances); + }); + it('should successfully transfer value for several fungible tokens', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = fungibleTokens.slice(0, 3); + const valuesToTransfer = [ + fungibleValueToTransferSmall.plus(10), + fungibleValueToTransferSmall.plus(20), + fungibleValueToTransferSmall.plus(30), + ]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [ + // spender + spenderInitialFungibleBalance, + spenderInitialFungibleBalance, + spenderInitialFungibleBalance, + // receiver + receiverInitialFungibleBalance, + receiverInitialFungibleBalance, + receiverInitialFungibleBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + await erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ); + // check balances after transfer + const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { + return value.times(perUnitValue); }); - it('should successfully transfer value for the same fungible token several times', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokenToTransfer = fungibleTokens[0]; - const tokensToTransfer = [tokenToTransfer, tokenToTransfer, tokenToTransfer]; - const valuesToTransfer = [ - fungibleValueToTransferSmall.plus(10), - fungibleValueToTransferSmall.plus(20), - fungibleValueToTransferSmall.plus(30), - ]; - const perUnitValue = perUnitValueSmall; - // check balances before transfer - const expectedInitialBalances = [ - // spender - spenderInitialFungibleBalance, - // receiver - receiverInitialFungibleBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // check balances after transfer - let totalValueTransferred = _.reduce(valuesToTransfer, (sum: BigNumber, value: BigNumber) => { - return sum.plus(value); - }) as BigNumber; - totalValueTransferred = totalValueTransferred.times(perUnitValue); - const expectedFinalBalances = [ - // spender - spenderInitialFungibleBalance.minus(totalValueTransferred), - // receiver - receiverInitialFungibleBalance.plus(totalValueTransferred), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, [tokenToTransfer], expectedFinalBalances); + const expectedFinalBalances = [ + // spender + spenderInitialFungibleBalance.minus(totalValuesTransferred[0]), + spenderInitialFungibleBalance.minus(totalValuesTransferred[1]), + spenderInitialFungibleBalance.minus(totalValuesTransferred[2]), + // receiver + receiverInitialFungibleBalance.plus(totalValuesTransferred[0]), + receiverInitialFungibleBalance.plus(totalValuesTransferred[1]), + receiverInitialFungibleBalance.plus(totalValuesTransferred[2]), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should successfully transfer a non-fungible token', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); + const valuesToTransfer = [nonFungibleValueToTransfer]; + const perUnitValue = perUnitValueNft; + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + await erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ); + // check balances after transfer + const expectedFinalBalances = [ + // spender + nftNotOwnerBalance, + // receiver + nftOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should successfully transfer multiple non-fungible tokens', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); + const valuesToTransfer = [ + nonFungibleValueToTransfer, + nonFungibleValueToTransfer, + nonFungibleValueToTransfer, + ]; + const perUnitValue = perUnitValueNft; + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + nftOwnerBalance, + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + nftNotOwnerBalance, + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + await erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ); + // check balances after transfer + const expectedFinalBalances = [ + // spender + nftNotOwnerBalance, + nftNotOwnerBalance, + nftNotOwnerBalance, + // receiver + nftOwnerBalance, + nftOwnerBalance, + nftOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should successfully transfer value for a combination of several fungible/non-fungible tokens', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const fungibleTokensToTransfer = fungibleTokens.slice(0, 3); + const nonFungibleTokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 2); + const tokensToTransfer = fungibleTokensToTransfer.concat(nonFungibleTokensToTransfer); + const valuesToTransfer = [ + fungibleValueToTransferLarge, + fungibleValueToTransferSmall, + fungibleValueToTransferSmall, + nonFungibleValueToTransfer, + nonFungibleValueToTransfer, + ]; + const perUnitValue = perUnitValueNft; + // check balances before transfer + const expectedInitialBalances = [ + // spender + spenderInitialFungibleBalance, + spenderInitialFungibleBalance, + spenderInitialFungibleBalance, + nftOwnerBalance, + nftOwnerBalance, + // receiver + receiverInitialFungibleBalance, + receiverInitialFungibleBalance, + receiverInitialFungibleBalance, + nftNotOwnerBalance, + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + await erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ); + // check balances after transfer + const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { + return value.times(perUnitValue); }); - it('should successfully transfer value for several fungible tokens', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = fungibleTokens.slice(0, 3); - const valuesToTransfer = [ - fungibleValueToTransferSmall.plus(10), - fungibleValueToTransferSmall.plus(20), - fungibleValueToTransferSmall.plus(30), - ]; - const perUnitValue = perUnitValueSmall; - // check balances before transfer - const expectedInitialBalances = [ - // spender - spenderInitialFungibleBalance, - spenderInitialFungibleBalance, - spenderInitialFungibleBalance, - // receiver - receiverInitialFungibleBalance, - receiverInitialFungibleBalance, - receiverInitialFungibleBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // check balances after transfer - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(perUnitValue); - }); - const expectedFinalBalances = [ - // spender - spenderInitialFungibleBalance.minus(totalValuesTransferred[0]), - spenderInitialFungibleBalance.minus(totalValuesTransferred[1]), - spenderInitialFungibleBalance.minus(totalValuesTransferred[2]), - // receiver - receiverInitialFungibleBalance.plus(totalValuesTransferred[0]), - receiverInitialFungibleBalance.plus(totalValuesTransferred[1]), - receiverInitialFungibleBalance.plus(totalValuesTransferred[2]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + const expectedFinalBalances = [ + // spender + expectedInitialBalances[0].minus(totalValuesTransferred[0]), + expectedInitialBalances[1].minus(totalValuesTransferred[1]), + expectedInitialBalances[2].minus(totalValuesTransferred[2]), + expectedInitialBalances[3].minus(totalValuesTransferred[3]), + expectedInitialBalances[4].minus(totalValuesTransferred[4]), + // receiver + expectedInitialBalances[5].plus(totalValuesTransferred[0]), + expectedInitialBalances[6].plus(totalValuesTransferred[1]), + expectedInitialBalances[7].plus(totalValuesTransferred[2]), + expectedInitialBalances[8].plus(totalValuesTransferred[3]), + expectedInitialBalances[9].plus(totalValuesTransferred[4]), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should successfully transfer value to a smart contract and trigger its callback', async () => { + // setup test parameters + const tokenHolders = [spender, receiverContract]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = perUnitValueSmall; + const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { + return value.times(perUnitValue); }); - it('should successfully transfer a non-fungible token', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); - const valuesToTransfer = [nonFungibleValueToTransfer]; - const perUnitValue = perUnitValueNft; - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // check balances after transfer - const expectedFinalBalances = [ - // spender - nftNotOwnerBalance, - // receiver - nftOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer multiple non-fungible tokens', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); - const valuesToTransfer = [ - nonFungibleValueToTransfer, - nonFungibleValueToTransfer, - nonFungibleValueToTransfer, - ]; - const perUnitValue = perUnitValueNft; - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - nftOwnerBalance, - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - nftNotOwnerBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // check balances after transfer - const expectedFinalBalances = [ - // spender - nftNotOwnerBalance, - nftNotOwnerBalance, - nftNotOwnerBalance, - // receiver - nftOwnerBalance, - nftOwnerBalance, - nftOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer value for a combination of several fungible/non-fungible tokens', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const fungibleTokensToTransfer = fungibleTokens.slice(0, 3); - const nonFungibleTokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 2); - const tokensToTransfer = fungibleTokensToTransfer.concat(nonFungibleTokensToTransfer); - const valuesToTransfer = [ - fungibleValueToTransferLarge, - fungibleValueToTransferSmall, - fungibleValueToTransferSmall, - nonFungibleValueToTransfer, - nonFungibleValueToTransfer, - ]; - const perUnitValue = perUnitValueNft; - // check balances before transfer - const expectedInitialBalances = [ - // spender - spenderInitialFungibleBalance, - spenderInitialFungibleBalance, - spenderInitialFungibleBalance, - nftOwnerBalance, - nftOwnerBalance, - // receiver - receiverInitialFungibleBalance, - receiverInitialFungibleBalance, - receiverInitialFungibleBalance, - nftNotOwnerBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // check balances after transfer - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(perUnitValue); - }); - const expectedFinalBalances = [ - // spender - expectedInitialBalances[0].minus(totalValuesTransferred[0]), - expectedInitialBalances[1].minus(totalValuesTransferred[1]), - expectedInitialBalances[2].minus(totalValuesTransferred[2]), - expectedInitialBalances[3].minus(totalValuesTransferred[3]), - expectedInitialBalances[4].minus(totalValuesTransferred[4]), - // receiver - expectedInitialBalances[5].plus(totalValuesTransferred[0]), - expectedInitialBalances[6].plus(totalValuesTransferred[1]), - expectedInitialBalances[7].plus(totalValuesTransferred[2]), - expectedInitialBalances[8].plus(totalValuesTransferred[3]), - expectedInitialBalances[9].plus(totalValuesTransferred[4]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer value to a smart contract and trigger its callback', async () => { - // setup test parameters - const tokenHolders = [spender, receiverContract]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = perUnitValueSmall; - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(perUnitValue); - }); - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiverContract, - perUnitValue, - ); - const logDecoder = new LogDecoder(web3Wrapper, artifacts); - const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - ); - // 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(1); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); - expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]); - // note - if the `extraData` is ignored then the receiver log should ignore it as well. - expect(receiverLog.args.data).to.be.deep.equal(receiverCallbackData); - // check balances after transfer - const expectedFinalBalances = [ - expectedInitialBalances[0].minus(totalValuesTransferred[0]), - expectedInitialBalances[1].plus(totalValuesTransferred[0]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should successfully transfer value and ignore extra assetData', async () => { - // setup test parameters - const tokenHolders = [spender, receiverContract]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = perUnitValueSmall; - const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(perUnitValue); - }); - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const extraData = '0102030405060708'; - const encodedAssetDataPlusExtraData = `${encodedAssetData}${extraData}`; - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetDataPlusExtraData, - spender, - receiverContract, - perUnitValue, - ); - const logDecoder = new LogDecoder(web3Wrapper, artifacts); - const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - ); - // 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(1); - expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); - expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); - expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]); - // note - if the `extraData` is ignored then the receiver log should ignore it as well. - expect(receiverLog.args.data).to.be.deep.equal(receiverCallbackData); - // check balances after transfer - const expectedFinalBalances = [ - expectedInitialBalances[0].minus(totalValuesTransferred[0]), - expectedInitialBalances[1].plus(totalValuesTransferred[0]), - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); - }); - it('should propagate revert reason from erc1155 contract failure', async () => { - // disable transfers - const shouldRejectTransfer = true; - await web3Wrapper.awaitTransactionSuccessAsync( - await erc1155Receiver.setRejectTransferFlag.sendTransactionAsync(shouldRejectTransfer), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - // setup test parameters - const tokenHolders = [spender, receiverContract]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = perUnitValueSmall; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiverContract, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.TransferRejected, - ); - }); - it('should revert if transferring the same non-fungible token more than once', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const nftToTransfer = nonFungibleTokensOwnedBySpender[0]; - const tokensToTransfer = [nftToTransfer, nftToTransfer]; - const valuesToTransfer = [nonFungibleValueToTransfer, nonFungibleValueToTransfer]; - const perUnitValue = perUnitValueNft; - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.nftNotOwnedByFromAddress, - ); - }); - it('should revert if tansferring 0 amount of any token', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); - const valuesToTransfer = [nonFungibleValueToTransfer, new BigNumber(0), nonFungibleValueToTransfer]; - const perUnitValue = perUnitValueNft; - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - nftOwnerBalance, - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - nftNotOwnerBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.transferGreaterThanZeroRequired, - ); - }); - it('should revert if there is a multiplication overflow', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); - const maxUintValue = new BigNumber(2).pow(256).minus(1); - const valuesToTransfer = [nonFungibleValueToTransfer, maxUintValue, nonFungibleValueToTransfer]; - const perUnitValue = new BigNumber(2); - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - nftOwnerBalance, - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - nftNotOwnerBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - // note - this will overflow because we are trying to transfer `maxUintValue * 2` of the 2nd token - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.Uint256Overflow, - ); - }); - it('should revert if transferring > 1 instances of a non-fungible token (perUnitValue field >1)', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); - const valuesToTransfer = [nonFungibleValueToTransfer]; - const perUnitValue = new BigNumber(2); - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.amountEqualToOneRequired, - ); - }); - it('should revert if transferring > 1 instances of a non-fungible token (`valuesToTransfer` field >1)', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); - const valuesToTransfer = [new BigNumber(2)]; - const perUnitValue = perUnitValueNft; - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.amountEqualToOneRequired, - ); - }); - it('should revert if sender balance is insufficient', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valueGreaterThanSpenderBalance = spenderInitialFungibleBalance.plus(1); - const valuesToTransfer = [valueGreaterThanSpenderBalance]; - const perUnitValue = perUnitValueSmall; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.Uint256Underflow, - ); - }); - it('should revert if sender allowance is insufficient', async () => { - // dremove allowance for ERC1155 proxy - const wrapper = erc1155ProxyWrapper.getTokenWrapper(erc1155Contract.address); - const isApproved = false; - await wrapper.setApprovalForAllAsync(spender, erc1155Proxy.address, isApproved); - const isApprovedActualValue = await wrapper.isApprovedForAllAsync(spender, erc1155Proxy.address); - expect(isApprovedActualValue).to.be.equal(isApproved); - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = perUnitValueSmall; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), - RevertReason.InsufficientAllowance, - ); - }); - it('should revert if caller is not authorized', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = fungibleTokens.slice(0, 1); - const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = perUnitValueSmall; - // check balances before transfer - const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); - await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: notAuthorized, - }), - RevertReason.SenderNotAuthorized, - ); + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const txReceipt = await erc1155ProxyWrapper.transferFromAsync( + spender, + receiverContract, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ); + // 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(1); + expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); + expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); + expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]); + // note - if the `extraData` is ignored then the receiver log should ignore it as well. + expect(receiverLog.args.data).to.be.deep.equal(receiverCallbackData); + // check balances after transfer + const expectedFinalBalances = [ + expectedInitialBalances[0].minus(totalValuesTransferred[0]), + expectedInitialBalances[1].plus(totalValuesTransferred[0]), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should successfully transfer value and ignore extra assetData', async () => { + // setup test parameters + const tokenHolders = [spender, receiverContract]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = perUnitValueSmall; + const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { + return value.times(perUnitValue); }); + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); + const extraData = '0102030405060708'; + const encodedAssetDataPlusExtraData = `${encodedAssetData}${extraData}`; + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetDataPlusExtraData, + spender, + receiverContract, + perUnitValue, + ); + const logDecoder = new LogDecoder(web3Wrapper, artifacts); + const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( + await web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + ); + // 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(1); + expect(receiverLog.args.tokenIds[0]).to.be.bignumber.equal(tokensToTransfer[0]); + expect(receiverLog.args.tokenValues.length).to.be.deep.equal(1); + expect(receiverLog.args.tokenValues[0]).to.be.bignumber.equal(totalValuesTransferred[0]); + // note - if the `extraData` is ignored then the receiver log should ignore it as well. + expect(receiverLog.args.data).to.be.deep.equal(receiverCallbackData); + // check balances after transfer + const expectedFinalBalances = [ + expectedInitialBalances[0].minus(totalValuesTransferred[0]), + expectedInitialBalances[1].plus(totalValuesTransferred[0]), + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should propagate revert reason from erc1155 contract failure', async () => { + // disable transfers + const shouldRejectTransfer = true; + await web3Wrapper.awaitTransactionSuccessAsync( + await erc1155Receiver.setRejectTransferFlag.sendTransactionAsync(shouldRejectTransfer), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + // setup test parameters + const tokenHolders = [spender, receiverContract]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiverContract, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.TransferRejected, + ); + }); + it('should revert if transferring the same non-fungible token more than once', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const nftToTransfer = nonFungibleTokensOwnedBySpender[0]; + const tokensToTransfer = [nftToTransfer, nftToTransfer]; + const valuesToTransfer = [nonFungibleValueToTransfer, nonFungibleValueToTransfer]; + const perUnitValue = perUnitValueNft; + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.nftNotOwnedByFromAddress, + ); + }); + it('should revert if tansferring 0 amount of any token', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); + const valuesToTransfer = [nonFungibleValueToTransfer, new BigNumber(0), nonFungibleValueToTransfer]; + const perUnitValue = perUnitValueNft; + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + nftOwnerBalance, + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + nftNotOwnerBalance, + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.transferGreaterThanZeroRequired, + ); + }); + it('should revert if there is a multiplication overflow', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); + const maxUintValue = new BigNumber(2).pow(256).minus(1); + const valuesToTransfer = [nonFungibleValueToTransfer, maxUintValue, nonFungibleValueToTransfer]; + const perUnitValue = new BigNumber(2); + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + nftOwnerBalance, + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + nftNotOwnerBalance, + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + // note - this will overflow because we are trying to transfer `maxUintValue * 2` of the 2nd token + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.Uint256Overflow, + ); + }); + it('should revert if transferring > 1 instances of a non-fungible token (perUnitValue field >1)', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); + const valuesToTransfer = [nonFungibleValueToTransfer]; + const perUnitValue = new BigNumber(2); + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.amountEqualToOneRequired, + ); + }); + it('should revert if transferring > 1 instances of a non-fungible token (`valuesToTransfer` field >1)', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); + const valuesToTransfer = [new BigNumber(2)]; + const perUnitValue = perUnitValueNft; + // check balances before transfer + const expectedInitialBalances = [ + // spender + nftOwnerBalance, + // receiver + nftNotOwnerBalance, + ]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.amountEqualToOneRequired, + ); + }); + it('should revert if sender balance is insufficient', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valueGreaterThanSpenderBalance = spenderInitialFungibleBalance.plus(1); + const valuesToTransfer = [valueGreaterThanSpenderBalance]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.Uint256Underflow, + ); + }); + it('should revert if sender allowance is insufficient', async () => { + // dremove allowance for ERC1155 proxy + const wrapper = erc1155ProxyWrapper.getTokenWrapper(erc1155Contract.address); + const isApproved = false; + await wrapper.setApprovalForAllAsync(spender, erc1155Proxy.address, isApproved); + const isApprovedActualValue = await wrapper.isApprovedForAllAsync(spender, erc1155Proxy.address); + expect(isApprovedActualValue).to.be.equal(isApproved); + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: authorized, + }), + RevertReason.InsufficientAllowance, + ); + }); + it('should revert if caller is not authorized', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = perUnitValueSmall; + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); + const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + spender, + receiver, + perUnitValue, + ); + await expectTransactionFailedAsync( + web3Wrapper.sendTransactionAsync({ + to: erc1155Proxy.address, + data, + from: notAuthorized, + }), + RevertReason.SenderNotAuthorized, + ); }); }); }); diff --git a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts index 1f73abd62f..1363a5539c 100644 --- a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts +++ b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts @@ -7,15 +7,17 @@ import { LogDecoder, txDefaults, } from '@0x/contracts-test-utils'; +import { assetDataUtils } from '@0x/order-utils'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; -import { Provider } from 'ethereum-types'; +import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import * as _ from 'lodash'; import { artifacts, ERC1155MintableContract, ERC1155ProxyContract, + IAssetProxyContract, } from '../../src'; export class ERC1155ProxyWrapper { @@ -28,14 +30,21 @@ export class ERC1155ProxyWrapper { private readonly _provider: Provider; private readonly _logDecoder: LogDecoder; private readonly _dummyTokenWrappers: Erc1155Wrapper[]; + private readonly _assetProxyInterface: IAssetProxyContract; private _proxyContract?: ERC1155ProxyContract; private _proxyIdIfExists?: string; private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} }; + constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { this._web3Wrapper = new Web3Wrapper(provider); this._provider = provider; this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); this._dummyTokenWrappers = []; + this._assetProxyInterface = new IAssetProxyContract( + artifacts.IAssetProxy.compilerOutput.abi, + constants.NULL_ADDRESS, + provider, + ); this._tokenOwnerAddresses = tokenOwnerAddresses; this._contractOwnerAddress = contractOwnerAddress; this._fungibleTokenIds = []; @@ -68,6 +77,38 @@ export class ERC1155ProxyWrapper { this._validateProxyContractExistsOrThrow(); return this._proxyIdIfExists as string; } + public async transferFromAsync( + from: string, + to: string, + contractAddress: string, + tokensToTransfer: BigNumber[], + valuesToTransfer: BigNumber[], + valueMultiplier: BigNumber, + receiverCallbackData: string, + authorizedSender: string + ): Promise { + this._validateProxyContractExistsOrThrow(); + const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + contractAddress, + tokensToTransfer, + valuesToTransfer, + receiverCallbackData, + ); + const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData( + encodedAssetData, + from, + to, + valueMultiplier, + ); + const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync( + await this._web3Wrapper.sendTransactionAsync({ + to: (this._proxyContract as ERC1155ProxyContract).address, + data, + from: authorizedSender, + }), + ); + return txReceipt; + } public async setBalancesAndAllowancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); this._validateProxyContractExistsOrThrow(); @@ -78,11 +119,10 @@ export class ERC1155ProxyWrapper { const fungibleHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {}; const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {}; // Set balances accordingly - const fungibleTokensToMintRange = _.range(0, constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT); - const nonFungibleTokensToMintRange = _.range(0, constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT); for (const dummyWrapper of this._dummyTokenWrappers) { const dummyAddress = dummyWrapper.getContract().address; - _.each(fungibleTokensToMintRange, async () => { + // tslint:disable-next-line:no-unused-variable + for (const i of _.times(constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT)) { // Create a fungible token const tokenId = await dummyWrapper.mintFungibleTokensAsync( this._tokenOwnerAddresses, @@ -107,9 +147,10 @@ export class ERC1155ProxyWrapper { true, ); } - }); + } // Non-fungible tokens - _.each(nonFungibleTokensToMintRange, async () => { + // tslint:disable-next-line:no-unused-variable + for (const i of _.times(constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT)) { const [tokenId, nftIds] = await dummyWrapper.mintNonFungibleTokensAsync(this._tokenOwnerAddresses); const tokenIdAsString = tokenId.toString(); this._nonFungibleTokenIds.push(tokenIdAsString); @@ -131,7 +172,7 @@ export class ERC1155ProxyWrapper { true, ); }); - }); + } } this._initialTokenIdsByOwner = { fungible: fungibleHoldingsByOwner, @@ -140,7 +181,7 @@ export class ERC1155ProxyWrapper { return this._initialTokenIdsByOwner; } public async ownerOfNonFungibleAsync(tokenAddress: string, tokenId: BigNumber): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const tokenContract = this._getContractFromTokenAddress(tokenAddress); const owner = await tokenContract.ownerOf.callAsync(tokenId); return owner; } @@ -149,14 +190,14 @@ export class ERC1155ProxyWrapper { tokenAddress: string, tokenId: BigNumber, ): Promise { - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const tokenContract = this._getContractFromTokenAddress(tokenAddress); const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId); const isOwner = tokenOwner === userAddress; return isOwner; } public async isProxyApprovedForAllAsync(userAddress: string, tokenAddress: string): Promise { this._validateProxyContractExistsOrThrow(); - const tokenContract = this._getTokenContractFromAssetData(tokenAddress); + const tokenContract = this._getContractFromTokenAddress(tokenAddress); const operator = (this._proxyContract as ERC1155ProxyContract).address; const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator); return didApproveAll; @@ -250,13 +291,7 @@ export class ERC1155ProxyWrapper { } return tokenWrapper; } - /* - public getTokenAddresses(): string[] { - const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address); - return tokenAddresses; - } - */ - private _getTokenContractFromAssetData(tokenAddress: string): ERC1155MintableContract { + private _getContractFromTokenAddress(tokenAddress: string): ERC1155MintableContract { const tokenContractIfExists = _.find(this._dummyTokenWrappers, c => c.getContract().address === tokenAddress); if (_.isUndefined(tokenContractIfExists)) { throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155Wrapper`); From 38e4871f328a0a1c4289c47b2f4dc590718aaf4e Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 5 Mar 2019 10:55:56 -0800 Subject: [PATCH 14/29] Moved transferFrom with/without logs into ERC1155 Proxy Wrapper --- contracts/asset-proxy/test/erc1155_proxy.ts | 269 +++++++----------- .../test/utils/erc1155_proxy_wrapper.ts | 44 ++- 2 files changed, 134 insertions(+), 179 deletions(-) diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index 0e96a62ff8..d9e2236977 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -412,7 +412,7 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const txReceipt = await erc1155ProxyWrapper.transferFromAsync( + const txReceipt = await erc1155ProxyWrapper.transferFromWithLogsAsync( spender, receiverContract, erc1155Contract.address, @@ -451,31 +451,21 @@ describe.only('ERC1155Proxy', () => { const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { return value.times(perUnitValue); }); + const extraData = '0102030405060708'; // check balances before transfer const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + const txReceipt = await erc1155ProxyWrapper.transferFromWithLogsAsync( + spender, + receiverContract, erc1155Contract.address, tokensToTransfer, valuesToTransfer, - receiverCallbackData, - ); - const extraData = '0102030405060708'; - const encodedAssetDataPlusExtraData = `${encodedAssetData}${extraData}`; - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetDataPlusExtraData, - spender, - receiverContract, perUnitValue, - ); - const logDecoder = new LogDecoder(web3Wrapper, artifacts); - const txReceipt = await logDecoder.getTxWithDecodedLogsAsync( - await web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), + receiverCallbackData, + authorized, + extraData ); // check receiver log ignored extra asset data expect(txReceipt.logs.length).to.be.equal(2); @@ -513,24 +503,17 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiverContract, - perUnitValue, - ); await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), + erc1155ProxyWrapper.transferFromAsync( + spender, + receiverContract, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ), RevertReason.TransferRejected, ); }); @@ -552,24 +535,17 @@ describe.only('ERC1155Proxy', () => { ]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), + erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ), RevertReason.nftNotOwnedByFromAddress, ); }); @@ -592,24 +568,17 @@ describe.only('ERC1155Proxy', () => { ]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), + erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ), RevertReason.transferGreaterThanZeroRequired, ); }); @@ -634,24 +603,17 @@ describe.only('ERC1155Proxy', () => { await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer // note - this will overflow because we are trying to transfer `maxUintValue * 2` of the 2nd token - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), + erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ), RevertReason.Uint256Overflow, ); }); @@ -670,24 +632,17 @@ describe.only('ERC1155Proxy', () => { ]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), + erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ), RevertReason.amountEqualToOneRequired, ); }); @@ -706,24 +661,17 @@ describe.only('ERC1155Proxy', () => { ]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), + erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ), RevertReason.amountEqualToOneRequired, ); }); @@ -738,24 +686,17 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), + erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ), RevertReason.Uint256Underflow, ); }); @@ -775,24 +716,17 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: authorized, - }), + erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized + ), RevertReason.InsufficientAllowance, ); }); @@ -806,24 +740,17 @@ describe.only('ERC1155Proxy', () => { const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); // execute transfer - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - receiverCallbackData, - ); - const data = assetProxyInterface.transferFrom.getABIEncodedTransactionData( - encodedAssetData, - spender, - receiver, - perUnitValue, - ); await expectTransactionFailedAsync( - web3Wrapper.sendTransactionAsync({ - to: erc1155Proxy.address, - data, - from: notAuthorized, - }), + erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + notAuthorized + ), RevertReason.SenderNotAuthorized, ); }); diff --git a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts index 1363a5539c..1ba6929cdb 100644 --- a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts +++ b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts @@ -85,27 +85,55 @@ export class ERC1155ProxyWrapper { valuesToTransfer: BigNumber[], valueMultiplier: BigNumber, receiverCallbackData: string, - authorizedSender: string - ): Promise { + authorizedSender: string, + extraData?: string, + ): Promise { this._validateProxyContractExistsOrThrow(); - const encodedAssetData = assetDataUtils.encodeERC1155AssetData( + let encodedAssetData = assetDataUtils.encodeERC1155AssetData( contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData, ); + if (!_.isUndefined(extraData)) { + encodedAssetData = `${encodedAssetData}${extraData}`; + } const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData( encodedAssetData, from, to, valueMultiplier, ); + const txHash = await this._web3Wrapper.sendTransactionAsync({ + to: (this._proxyContract as ERC1155ProxyContract).address, + data, + from: authorizedSender, + }); + return txHash; + } + public async transferFromWithLogsAsync( + from: string, + to: string, + contractAddress: string, + tokensToTransfer: BigNumber[], + valuesToTransfer: BigNumber[], + valueMultiplier: BigNumber, + receiverCallbackData: string, + authorizedSender: string, + extraData?: string, + ): Promise { const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync( - await this._web3Wrapper.sendTransactionAsync({ - to: (this._proxyContract as ERC1155ProxyContract).address, - data, - from: authorizedSender, - }), + await this.transferFromAsync( + from, + to, + contractAddress, + tokensToTransfer, + valuesToTransfer, + valueMultiplier, + receiverCallbackData, + authorizedSender, + extraData + ) ); return txReceipt; } From 05ef250ab413ed5972394404c9769d5ed53b95e7 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 5 Mar 2019 10:58:26 -0800 Subject: [PATCH 15/29] Ran prettier & linter --- contracts/asset-proxy/test/erc1155_proxy.ts | 44 ++++++++----------- .../test/utils/erc1155_proxy_wrapper.ts | 17 +++---- .../order-utils/test/asset_data_utils_test.ts | 5 ++- packages/types/src/index.ts | 18 ++++---- 4 files changed, 36 insertions(+), 48 deletions(-) diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index d9e2236977..10ecb35d37 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -3,13 +3,11 @@ import { constants, expectTransactionFailedAsync, expectTransactionFailedWithoutReasonAsync, - LogDecoder, provider, txDefaults, web3Wrapper, } from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; -import { assetDataUtils } from '@0x/order-utils'; import { RevertReason } from '@0x/types'; import { BigNumber } from '@0x/utils'; import * as chai from 'chai'; @@ -24,20 +22,14 @@ import { ERC1155MintableContract, ERC1155ProxyWrapper, ERC721ProxyContract, - IAssetProxyContract, } from '../src'; chaiSetup.configure(); const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -const assetProxyInterface = new IAssetProxyContract( - artifacts.IAssetProxy.compilerOutput.abi, - constants.NULL_ADDRESS, - provider, -); // tslint:disable:no-unnecessary-type-assertion -describe.only('ERC1155Proxy', () => { +describe('ERC1155Proxy', () => { // constant values used in transfer tests const nftOwnerBalance = new BigNumber(1); const nftNotOwnerBalance = new BigNumber(0); @@ -156,7 +148,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ); // check balances after transfer const totalValueTransferred = valuesToTransfer[0].times(perUnitValue); @@ -194,7 +186,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ); // check balances after transfer let totalValueTransferred = _.reduce(valuesToTransfer, (sum: BigNumber, value: BigNumber) => { @@ -240,7 +232,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ); // check balances after transfer const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { @@ -281,7 +273,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ); // check balances after transfer const expectedFinalBalances = [ @@ -323,7 +315,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ); // check balances after transfer const expectedFinalBalances = [ @@ -377,7 +369,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ); // check balances after transfer const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { @@ -420,7 +412,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ); // check receiver log ignored extra asset data expect(txReceipt.logs.length).to.be.equal(2); @@ -465,7 +457,7 @@ describe.only('ERC1155Proxy', () => { perUnitValue, receiverCallbackData, authorized, - extraData + extraData, ); // check receiver log ignored extra asset data expect(txReceipt.logs.length).to.be.equal(2); @@ -512,7 +504,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ), RevertReason.TransferRejected, ); @@ -544,7 +536,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ), RevertReason.nftNotOwnedByFromAddress, ); @@ -577,7 +569,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ), RevertReason.transferGreaterThanZeroRequired, ); @@ -612,7 +604,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ), RevertReason.Uint256Overflow, ); @@ -641,7 +633,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ), RevertReason.amountEqualToOneRequired, ); @@ -670,7 +662,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ), RevertReason.amountEqualToOneRequired, ); @@ -695,7 +687,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ), RevertReason.Uint256Underflow, ); @@ -725,7 +717,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - authorized + authorized, ), RevertReason.InsufficientAllowance, ); @@ -749,7 +741,7 @@ describe.only('ERC1155Proxy', () => { valuesToTransfer, perUnitValue, receiverCallbackData, - notAuthorized + notAuthorized, ), RevertReason.SenderNotAuthorized, ); diff --git a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts index 1ba6929cdb..272f6ecfd6 100644 --- a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts +++ b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts @@ -13,12 +13,7 @@ import { Web3Wrapper } from '@0x/web3-wrapper'; import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import * as _ from 'lodash'; -import { - artifacts, - ERC1155MintableContract, - ERC1155ProxyContract, - IAssetProxyContract, -} from '../../src'; +import { artifacts, ERC1155MintableContract, ERC1155ProxyContract, IAssetProxyContract } from '../../src'; export class ERC1155ProxyWrapper { private readonly _tokenOwnerAddresses: string[]; @@ -34,13 +29,13 @@ export class ERC1155ProxyWrapper { private _proxyContract?: ERC1155ProxyContract; private _proxyIdIfExists?: string; private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} }; - + constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { this._web3Wrapper = new Web3Wrapper(provider); this._provider = provider; this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); this._dummyTokenWrappers = []; - this._assetProxyInterface = new IAssetProxyContract( + this._assetProxyInterface = new IAssetProxyContract( artifacts.IAssetProxy.compilerOutput.abi, constants.NULL_ADDRESS, provider, @@ -132,8 +127,8 @@ export class ERC1155ProxyWrapper { valueMultiplier, receiverCallbackData, authorizedSender, - extraData - ) + extraData, + ), ); return txReceipt; } @@ -178,7 +173,7 @@ export class ERC1155ProxyWrapper { } // Non-fungible tokens // tslint:disable-next-line:no-unused-variable - for (const i of _.times(constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT)) { + for (const j of _.times(constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT)) { const [tokenId, nftIds] = await dummyWrapper.mintNonFungibleTokensAsync(this._tokenOwnerAddresses); const tokenIdAsString = tokenId.toString(); this._nonFungibleTokenIds.push(tokenIdAsString); diff --git a/packages/order-utils/test/asset_data_utils_test.ts b/packages/order-utils/test/asset_data_utils_test.ts index 5d28000caf..2634e7f595 100644 --- a/packages/order-utils/test/asset_data_utils_test.ts +++ b/packages/order-utils/test/asset_data_utils_test.ts @@ -24,7 +24,8 @@ const KNOWN_ERC1155_ENCODING = { tokenAddress: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48', tokenIds: [new BigNumber(100), new BigNumber(1001), new BigNumber(10001)], tokenValues: [new BigNumber(200), new BigNumber(2001), new BigNumber(20001)], - callbackData: '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001', + callbackData: + '0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001', assetData: '0x9645780d0000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000', }; @@ -63,7 +64,7 @@ describe('assetDataUtils', () => { KNOWN_ERC1155_ENCODING.tokenAddress, KNOWN_ERC1155_ENCODING.tokenIds, KNOWN_ERC1155_ENCODING.tokenValues, - KNOWN_ERC1155_ENCODING.callbackData + KNOWN_ERC1155_ENCODING.callbackData, ); expect(assetData).to.equal(KNOWN_ERC1155_ENCODING.assetData); }); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index f9e809446d..95110a85b4 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -186,17 +186,17 @@ export interface ERC1155AssetData { } export interface ERC1155AssetDataNoProxyId { - tokenAddress: string, - tokenValues: BigNumber[], - tokenIds: BigNumber[], - callbackData: string -}; + tokenAddress: string; + tokenValues: BigNumber[]; + tokenIds: BigNumber[]; + callbackData: string; +} export const ERC1155AssetDataAbi = [ - {name: 'tokenAddress', type: 'address'}, - {name: 'tokenIds', type: 'uint256[]'}, - {name: 'tokenValues', type: 'uint256[]'}, - {name: 'callbackData', type: 'bytes'}, + { name: 'tokenAddress', type: 'address' }, + { name: 'tokenIds', type: 'uint256[]' }, + { name: 'tokenValues', type: 'uint256[]' }, + { name: 'callbackData', type: 'bytes' }, ]; export type SingleAssetData = ERC20AssetData | ERC721AssetData | ERC1155AssetData; From ae51cfe8b993760c45d83193f116dc9bd4d6aa09 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 5 Mar 2019 11:18:22 -0800 Subject: [PATCH 16/29] Added method descriptions to erc1155 proxy wrapper --- contracts/asset-proxy/test/erc1155_proxy.ts | 4 +- .../test/utils/erc1155_proxy_wrapper.ts | 94 +++++++++++++------ 2 files changed, 68 insertions(+), 30 deletions(-) diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index 10ecb35d37..810f5da0a3 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -84,7 +84,7 @@ describe('ERC1155Proxy', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); // deploy & configure ERC1155 tokens and receiver - [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyTokensAsync(); + [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync(); erc1155Contract = erc1155Wrapper.getContract(); erc1155Receiver = await DummyERC1155ReceiverContract.deployFrom0xArtifactAsync( artifacts.DummyERC1155Receiver, @@ -694,7 +694,7 @@ describe('ERC1155Proxy', () => { }); it('should revert if sender allowance is insufficient', async () => { // dremove allowance for ERC1155 proxy - const wrapper = erc1155ProxyWrapper.getTokenWrapper(erc1155Contract.address); + const wrapper = erc1155ProxyWrapper.getContractWrapper(erc1155Contract.address); const isApproved = false; await wrapper.setApprovalForAllAsync(spender, erc1155Proxy.address, isApproved); const isApprovedActualValue = await wrapper.isApprovedForAllAsync(spender, erc1155Proxy.address); diff --git a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts index 272f6ecfd6..e671e08a72 100644 --- a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts +++ b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts @@ -46,7 +46,11 @@ export class ERC1155ProxyWrapper { this._nonFungibleTokenIds = []; this._nfts = []; } - public async deployDummyTokensAsync(): Promise { + /** + * @dev Deploys dummy ERC1155 contracts + * @return An array of ERC1155 wrappers; one for each deployed contract. + */ + public async deployDummyContractsAsync(): Promise { // tslint:disable-next-line:no-unused-variable for (const i of _.times(constants.NUM_DUMMY_ERC1155_TO_DEPLOY)) { const erc1155Contract = await ERC1155MintableContract.deployFrom0xArtifactAsync( @@ -59,6 +63,10 @@ export class ERC1155ProxyWrapper { } return this._dummyTokenWrappers; } + /** + * @dev Deploys the ERC1155 proxy + * @return Deployed ERC1155 proxy contract instance + */ public async deployProxyAsync(): Promise { this._proxyContract = await ERC1155ProxyContract.deployFrom0xArtifactAsync( artifacts.ERC1155Proxy, @@ -68,10 +76,26 @@ export class ERC1155ProxyWrapper { this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); return this._proxyContract; } + /** + * @dev Gets the ERC1155 proxy id + */ public getProxyId(): string { this._validateProxyContractExistsOrThrow(); return this._proxyIdIfExists as string; } + /** + * @dev transfers erc1155 fungible/non-fungible tokens. + * @param from source address + * @param to destination address + * @param contractAddress address of erc155 contract + * @param tokensToTransfer array of erc1155 tokens to transfer + * @param valuesToTransfer array of corresponding values for each erc1155 token to transfer + * @param valueMultiplier each value in `valuesToTransfer` is multiplied by this + * @param receiverCallbackData callback data if `to` is a contract + * @param authorizedSender sender of `transferFrom` transaction + * @param extraData extra data to append to `transferFrom` transaction. Optional. + * @return tranasction hash. + */ public async transferFromAsync( from: string, to: string, @@ -106,6 +130,19 @@ export class ERC1155ProxyWrapper { }); return txHash; } + /** + * @dev transfers erc1155 fungible/non-fungible tokens. + * @param from source address + * @param to destination address + * @param contractAddress address of erc155 contract + * @param tokensToTransfer array of erc1155 tokens to transfer + * @param valuesToTransfer array of corresponding values for each erc1155 token to transfer + * @param valueMultiplier each value in `valuesToTransfer` is multiplied by this + * @param receiverCallbackData callback data if `to` is a contract + * @param authorizedSender sender of `transferFrom` transaction + * @param extraData extra data to append to `transferFrom` transaction. Optional. + * @return tranasction receipt with decoded logs. + */ public async transferFromWithLogsAsync( from: string, to: string, @@ -132,6 +169,11 @@ export class ERC1155ProxyWrapper { ); return txReceipt; } + /** + * @dev For each deployed ERC1155 contract, this function mints a set of fungible/non-fungible + * tokens for each token owner address (`_tokenOwnerAddresses`). + * @return Balances of each token owner, across all ERC1155 contracts and tokens. + */ public async setBalancesAndAllowancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); this._validateProxyContractExistsOrThrow(); @@ -203,28 +245,11 @@ export class ERC1155ProxyWrapper { }; return this._initialTokenIdsByOwner; } - public async ownerOfNonFungibleAsync(tokenAddress: string, tokenId: BigNumber): Promise { - const tokenContract = this._getContractFromTokenAddress(tokenAddress); - const owner = await tokenContract.ownerOf.callAsync(tokenId); - return owner; - } - public async isNonFungibleOwnerAsync( - userAddress: string, - tokenAddress: string, - tokenId: BigNumber, - ): Promise { - const tokenContract = this._getContractFromTokenAddress(tokenAddress); - const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId); - const isOwner = tokenOwner === userAddress; - return isOwner; - } - public async isProxyApprovedForAllAsync(userAddress: string, tokenAddress: string): Promise { - this._validateProxyContractExistsOrThrow(); - const tokenContract = this._getContractFromTokenAddress(tokenAddress); - const operator = (this._proxyContract as ERC1155ProxyContract).address; - const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator); - return didApproveAll; - } + /** + * @dev For each deployed ERC1155 contract, this function quieries the set of fungible/non-fungible + * tokens for each token owner address (`_tokenOwnerAddresses`). + * @return Balances of each token owner, across all ERC1155 contracts and tokens. + */ public async getBalancesAsync(): Promise { this._validateDummyTokenContractsExistOrThrow(); this._validateBalancesAndAllowancesSetOrThrow(); @@ -290,6 +315,19 @@ export class ERC1155ProxyWrapper { }; return holdingsByOwner; } + /** + * @dev Checks if proxy is approved to transfer tokens on behalf of `userAddress`. + * @param userAddress owner of ERC1155 tokens. + * @param contractAddress address of ERC1155 contract. + * @return True iff the proxy is approved for all. False otherwise. + */ + public async isProxyApprovedForAllAsync(userAddress: string, contractAddress: string): Promise { + this._validateProxyContractExistsOrThrow(); + const tokenContract = this._getContractFromAddress(contractAddress); + const operator = (this._proxyContract as ERC1155ProxyContract).address; + const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator); + return didApproveAll; + } public getFungibleTokenIds(): BigNumber[] { const fungibleTokenIds = _.map(this._fungibleTokenIds, (tokenIdAsString: string) => { return new BigNumber(tokenIdAsString); @@ -305,19 +343,19 @@ export class ERC1155ProxyWrapper { public getTokenOwnerAddresses(): string[] { return this._tokenOwnerAddresses; } - public getTokenWrapper(tokenAddress: string): Erc1155Wrapper { + public getContractWrapper(contractAddress: string): Erc1155Wrapper { const tokenWrapper = _.find(this._dummyTokenWrappers, (wrapper: Erc1155Wrapper) => { - return wrapper.getContract().address === tokenAddress; + return wrapper.getContract().address === contractAddress; }); if (_.isUndefined(tokenWrapper)) { - throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155Wrapper`); + throw new Error(`Contract: ${contractAddress} was not deployed through ERC1155ProxyWrapper`); } return tokenWrapper; } - private _getContractFromTokenAddress(tokenAddress: string): ERC1155MintableContract { + private _getContractFromAddress(tokenAddress: string): ERC1155MintableContract { const tokenContractIfExists = _.find(this._dummyTokenWrappers, c => c.getContract().address === tokenAddress); if (_.isUndefined(tokenContractIfExists)) { - throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155Wrapper`); + throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155ProxyWrapper`); } return tokenContractIfExists.getContract(); } From 1e5648111e3b467cd8dc28b5a7418b6618343878 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 5 Mar 2019 15:23:15 -0800 Subject: [PATCH 17/29] Updated changelogs and documentation for erc1155 proxy --- contracts/asset-proxy/CHANGELOG.json | 9 +++++++++ contracts/asset-proxy/DEPLOYS.json | 11 ----------- contracts/asset-proxy/test/erc1155_proxy.ts | 10 +++++----- .../asset-proxy/test/utils/erc1155_proxy_wrapper.ts | 2 +- contracts/test-utils/CHANGELOG.json | 9 +++++++++ contracts/test-utils/src/constants.ts | 2 +- packages/order-utils/CHANGELOG.json | 2 +- packages/types/src/index.ts | 2 +- 8 files changed, 27 insertions(+), 20 deletions(-) diff --git a/contracts/asset-proxy/CHANGELOG.json b/contracts/asset-proxy/CHANGELOG.json index 59ab099079..f2ebf8f49a 100644 --- a/contracts/asset-proxy/CHANGELOG.json +++ b/contracts/asset-proxy/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "2.1.0", + "changes": [ + { + "note": "Add ERC1155Proxy", + "pr": 1661 + } + ] + }, { "version": "2.0.0", "changes": [ diff --git a/contracts/asset-proxy/DEPLOYS.json b/contracts/asset-proxy/DEPLOYS.json index 81b19daf59..0f25da1c3a 100644 --- a/contracts/asset-proxy/DEPLOYS.json +++ b/contracts/asset-proxy/DEPLOYS.json @@ -1,15 +1,4 @@ [ - { - "name": "ERC1155Proxy", - "version": "1.0.0", - "changes": [ - { - "note": "Add ERC1155Proxy implementation", - "pr": 0, - "networks": { - } - } - ] { "name": "MultiAssetProxy", "version": "1.0.0", diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index 810f5da0a3..9452301ff1 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -124,7 +124,7 @@ describe('ERC1155Proxy', () => { }); it('should have an id of 0x9645780d', async () => { const proxyId = await erc1155Proxy.getProxyId.callAsync(); - // proxy computed using -- bytes4(keccak256("erc1155Contract(address,uint256[],uint256[],bytes)")); + // proxy computed using -- bytes4(keccak256("erc1155Token(address,uint256[],uint256[],bytes)")); const expectedProxyId = '0x9645780d'; expect(proxyId).to.equal(expectedProxyId); }); @@ -538,7 +538,7 @@ describe('ERC1155Proxy', () => { receiverCallbackData, authorized, ), - RevertReason.nftNotOwnedByFromAddress, + RevertReason.NFTNotOwnedByFromAddress, ); }); it('should revert if tansferring 0 amount of any token', async () => { @@ -571,7 +571,7 @@ describe('ERC1155Proxy', () => { receiverCallbackData, authorized, ), - RevertReason.transferGreaterThanZeroRequired, + RevertReason.TransferGreaterThanZeroRequired, ); }); it('should revert if there is a multiplication overflow', async () => { @@ -635,7 +635,7 @@ describe('ERC1155Proxy', () => { receiverCallbackData, authorized, ), - RevertReason.amountEqualToOneRequired, + RevertReason.AmountEqualToOneRequired, ); }); it('should revert if transferring > 1 instances of a non-fungible token (`valuesToTransfer` field >1)', async () => { @@ -664,7 +664,7 @@ describe('ERC1155Proxy', () => { receiverCallbackData, authorized, ), - RevertReason.amountEqualToOneRequired, + RevertReason.AmountEqualToOneRequired, ); }); it('should revert if sender balance is insufficient', async () => { diff --git a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts index e671e08a72..c29a8330de 100644 --- a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts +++ b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts @@ -52,7 +52,7 @@ export class ERC1155ProxyWrapper { */ public async deployDummyContractsAsync(): Promise { // tslint:disable-next-line:no-unused-variable - for (const i of _.times(constants.NUM_DUMMY_ERC1155_TO_DEPLOY)) { + for (const i of _.times(constants.NUM_DUMMY_ERC1155_CONTRACTS_TO_DEPLOY)) { const erc1155Contract = await ERC1155MintableContract.deployFrom0xArtifactAsync( artifacts.ERC1155Mintable, this._provider, diff --git a/contracts/test-utils/CHANGELOG.json b/contracts/test-utils/CHANGELOG.json index 5a01a0d2b5..c9088fbaab 100644 --- a/contracts/test-utils/CHANGELOG.json +++ b/contracts/test-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "3.1.0", + "changes": [ + { + "note": "Added ERC1155Proxy test constants and interfaces", + "pr": 1661 + } + ] + }, { "version": "3.0.9", "changes": [ diff --git a/contracts/test-utils/src/constants.ts b/contracts/test-utils/src/constants.ts index e1d9b8dbb4..af56912ce3 100644 --- a/contracts/test-utils/src/constants.ts +++ b/contracts/test-utils/src/constants.ts @@ -38,7 +38,7 @@ export const constants = { NUM_DUMMY_ERC20_TO_DEPLOY: 3, NUM_DUMMY_ERC721_TO_DEPLOY: 2, NUM_ERC721_TOKENS_TO_MINT: 2, - NUM_DUMMY_ERC1155_TO_DEPLOY: 1, + NUM_DUMMY_ERC1155_CONTRACTS_TO_DEPLOY: 1, NUM_ERC1155_FUNGIBLE_TOKENS_MINT: 3, NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT: 3, NULL_ADDRESS: '0x0000000000000000000000000000000000000000', diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index df3c7e247e..aeb628b49a 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -3,7 +3,7 @@ "version": "7.1.0", "changes": [ { - "note": "Added `encodeERC721AssetData` and `decodeERC721AssetData`", + "note": "Added encoding/decoding fdor ERC1155 asset data", "pr": 1661 } ] diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 95110a85b4..49bf741e48 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -310,7 +310,7 @@ export enum RevertReason { TransferRejected = 'TRANSFER_REJECTED', Uint256Underflow = 'UINT256_UNDERFLOW', // ERC1155 Proxy - transferGreaterThanZeroRequired = 'TRANSFER_GREATER_THAN_ZERO_REQUIRED', + TransferGreaterThanZeroRequired = 'TRANSFER_GREATER_THAN_ZERO_REQUIRED', } export enum StatusCodes { From 8916d0d367f85ada970e75d94454657dc200a75a Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 7 Mar 2019 14:58:22 -0800 Subject: [PATCH 18/29] Ran prettier --- contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts | 2 +- packages/order-utils/CHANGELOG.json | 2 +- packages/order-utils/src/asset_data_utils.ts | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts index c29a8330de..a04008486b 100644 --- a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts +++ b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts @@ -47,7 +47,7 @@ export class ERC1155ProxyWrapper { this._nfts = []; } /** - * @dev Deploys dummy ERC1155 contracts + * @dev Deploys dummy ERC1155 contracts * @return An array of ERC1155 wrappers; one for each deployed contract. */ public async deployDummyContractsAsync(): Promise { diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index aeb628b49a..0b2b7791f7 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -1,6 +1,6 @@ [ { - "version": "7.1.0", + "version": "7.1.0", "changes": [ { "note": "Added encoding/decoding fdor ERC1155 asset data", diff --git a/packages/order-utils/src/asset_data_utils.ts b/packages/order-utils/src/asset_data_utils.ts index e0b9a62771..bb61f3be9a 100644 --- a/packages/order-utils/src/asset_data_utils.ts +++ b/packages/order-utils/src/asset_data_utils.ts @@ -1,10 +1,10 @@ import { AssetProxyId, - ERC20AssetData, - ERC721AssetData, ERC1155AssetData, ERC1155AssetDataAbi, ERC1155AssetDataNoProxyId, + ERC20AssetData, + ERC721AssetData, MultiAssetData, MultiAssetDataWithRecursiveDecoding, SingleAssetData, @@ -107,7 +107,7 @@ export const assetDataUtils = { throw new Error(`Invalid assetProxyId. Expected '${AssetProxyId.ERC1155}', got '${assetProxyId}'`); } const abiEncoder = AbiEncoder.createMethod('ERC1155Token', ERC1155AssetDataAbi); - const decodedAssetData = abiEncoder.decode(assetData, decodingRules) as ERC1155AssetDataNoProxyId; + const decodedAssetData: ERC1155AssetDataNoProxyId = abiEncoder.decode(assetData, decodingRules); return { assetProxyId, tokenAddress: decodedAssetData.tokenAddress, From 9ec380777a267d5d0501aa21233fc1e0bd60e6f4 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 11 Mar 2019 17:30:42 -0700 Subject: [PATCH 19/29] Rebased against development --- contracts/asset-proxy/compiler.json | 1 + contracts/asset-proxy/package.json | 2 +- contracts/asset-proxy/src/artifacts.ts | 6 +----- contracts/asset-proxy/src/wrappers.ts | 2 -- contracts/asset-proxy/test/erc1155_proxy.ts | 19 +++++++++---------- .../test/utils/erc1155_proxy_wrapper.ts | 9 +++++---- contracts/asset-proxy/tsconfig.json | 4 +--- .../erc1155/test/utils/erc1155_wrapper.ts | 16 ---------------- packages/order-utils/src/asset_data_utils.ts | 3 ++- packages/types/CHANGELOG.json | 3 +-- 10 files changed, 21 insertions(+), 44 deletions(-) diff --git a/contracts/asset-proxy/compiler.json b/contracts/asset-proxy/compiler.json index 13d150d70c..28f73402ca 100644 --- a/contracts/asset-proxy/compiler.json +++ b/contracts/asset-proxy/compiler.json @@ -23,6 +23,7 @@ } }, "contracts": [ + "src/ERC1155Proxy.sol", "src/ERC20Proxy.sol", "src/ERC721Proxy.sol", "src/MixinAuthorizable.sol", diff --git a/contracts/asset-proxy/package.json b/contracts/asset-proxy/package.json index c59e6bde7e..138485472a 100644 --- a/contracts/asset-proxy/package.json +++ b/contracts/asset-proxy/package.json @@ -33,7 +33,7 @@ "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol" }, "config": { - "abis": "./generated-artifacts/@(ERC20Proxy|ERC721Proxy|ERC1155Proxy|IAssetData|IAssetProxy|IAuthorizable|MixinAuthorizable|MultiAssetProxy).json", + "abis": "./generated-artifacts/@(ERC1155Proxy|ERC20Proxy|ERC721Proxy|IAssetData|IAssetProxy|IAuthorizable|MixinAuthorizable|MultiAssetProxy).json", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." }, "repository": { diff --git a/contracts/asset-proxy/src/artifacts.ts b/contracts/asset-proxy/src/artifacts.ts index c7c7f25dbb..0dc768bc11 100644 --- a/contracts/asset-proxy/src/artifacts.ts +++ b/contracts/asset-proxy/src/artifacts.ts @@ -5,8 +5,6 @@ */ import { ContractArtifact } from 'ethereum-types'; -import * as DummyERC1155Receiver from '../generated-artifacts/DummyERC1155Receiver.json'; -import * as ERC1155Mintable from '../generated-artifacts/ERC1155Mintable.json'; import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json'; import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json'; import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json'; @@ -16,11 +14,9 @@ import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json'; import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json'; import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json'; export const artifacts = { - DummyERC1155Receiver: DummyERC1155Receiver as ContractArtifact, - ERC1155Mintable: ERC1155Mintable as ContractArtifact, - ERC1155Proxy: ERC1155Proxy as ContractArtifact, ERC20Proxy: ERC20Proxy as ContractArtifact, ERC721Proxy: ERC721Proxy as ContractArtifact, + ERC1155Proxy: ERC1155Proxy as ContractArtifact, MixinAuthorizable: MixinAuthorizable as ContractArtifact, MultiAssetProxy: MultiAssetProxy as ContractArtifact, IAssetData: IAssetData as ContractArtifact, diff --git a/contracts/asset-proxy/src/wrappers.ts b/contracts/asset-proxy/src/wrappers.ts index 50de349723..3412cb0266 100644 --- a/contracts/asset-proxy/src/wrappers.ts +++ b/contracts/asset-proxy/src/wrappers.ts @@ -3,8 +3,6 @@ * Warning: This file is auto-generated by contracts-gen. Don't edit manually. * ----------------------------------------------------------------------------- */ -export * from '../generated-wrappers/dummy_erc1155_receiver'; -export * from '../generated-wrappers/erc1155_mintable'; export * from '../generated-wrappers/erc1155_proxy'; export * from '../generated-wrappers/erc20_proxy'; export * from '../generated-wrappers/erc721_proxy'; diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index 9452301ff1..01368f7833 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -1,3 +1,10 @@ +import { + artifacts as erc1155Artifacts, + DummyERC1155ReceiverBatchTokenReceivedEventArgs, + DummyERC1155ReceiverContract, + ERC1155MintableContract, + Erc1155Wrapper, +} from '@0x/contracts-erc1155'; import { chaiSetup, constants, @@ -14,15 +21,7 @@ import * as chai from 'chai'; import { LogWithDecodedArgs } from 'ethereum-types'; import * as _ from 'lodash'; -import { Erc1155Wrapper } from '../../erc1155/lib/src'; -import { - artifacts, - DummyERC1155ReceiverBatchTokenReceivedEventArgs, - DummyERC1155ReceiverContract, - ERC1155MintableContract, - ERC1155ProxyWrapper, - ERC721ProxyContract, -} from '../src'; +import { ERC1155ProxyWrapper, ERC721ProxyContract } from '../src'; chaiSetup.configure(); const expect = chai.expect; @@ -87,7 +86,7 @@ describe('ERC1155Proxy', () => { [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync(); erc1155Contract = erc1155Wrapper.getContract(); erc1155Receiver = await DummyERC1155ReceiverContract.deployFrom0xArtifactAsync( - artifacts.DummyERC1155Receiver, + erc1155Artifacts.DummyERC1155Receiver, provider, txDefaults, ); diff --git a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts index a04008486b..4a43a4711b 100644 --- a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts +++ b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts @@ -1,4 +1,4 @@ -import { Erc1155Wrapper } from '@0x/contracts-erc1155'; +import { artifacts as erc1155Artifacts, ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155'; import { constants, ERC1155FungibleHoldingsByOwner, @@ -13,7 +13,7 @@ import { Web3Wrapper } from '@0x/web3-wrapper'; import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import * as _ from 'lodash'; -import { artifacts, ERC1155MintableContract, ERC1155ProxyContract, IAssetProxyContract } from '../../src'; +import { artifacts, ERC1155ProxyContract, IAssetProxyContract } from '../../src'; export class ERC1155ProxyWrapper { private readonly _tokenOwnerAddresses: string[]; @@ -33,7 +33,8 @@ export class ERC1155ProxyWrapper { constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { this._web3Wrapper = new Web3Wrapper(provider); this._provider = provider; - this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); + const allArtifacts = _.merge(artifacts, erc1155Artifacts); + this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts); this._dummyTokenWrappers = []; this._assetProxyInterface = new IAssetProxyContract( artifacts.IAssetProxy.compilerOutput.abi, @@ -54,7 +55,7 @@ export class ERC1155ProxyWrapper { // tslint:disable-next-line:no-unused-variable for (const i of _.times(constants.NUM_DUMMY_ERC1155_CONTRACTS_TO_DEPLOY)) { const erc1155Contract = await ERC1155MintableContract.deployFrom0xArtifactAsync( - artifacts.ERC1155Mintable, + erc1155Artifacts.ERC1155Mintable, this._provider, txDefaults, ); diff --git a/contracts/asset-proxy/tsconfig.json b/contracts/asset-proxy/tsconfig.json index 2ea279b4e5..31358217c9 100644 --- a/contracts/asset-proxy/tsconfig.json +++ b/contracts/asset-proxy/tsconfig.json @@ -3,9 +3,7 @@ "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], "files": [ - "generated-artifacts/DummyERC1155Receiver.json", - "generated-artifacts/ERC1155Mintable.json", - "generated-artifacts/ERC1155Proxy.json", + "generated-artifacts/ERC1155Proxy.json", "generated-artifacts/ERC20Proxy.json", "generated-artifacts/ERC721Proxy.json", "generated-artifacts/IAssetData.json", diff --git a/contracts/erc1155/test/utils/erc1155_wrapper.ts b/contracts/erc1155/test/utils/erc1155_wrapper.ts index 82e8705b1a..7f620ece02 100644 --- a/contracts/erc1155/test/utils/erc1155_wrapper.ts +++ b/contracts/erc1155/test/utils/erc1155_wrapper.ts @@ -138,22 +138,6 @@ export class Erc1155Wrapper { const isApprovedForAll = await this._erc1155Contract.isApprovedForAll.callAsync(owner, beneficiary); return isApprovedForAll; } - public async setApprovalForAllAsync( - owner: string, - beneficiary: string, - isApproved: boolean, - ): Promise { - const tx = await this._logDecoder.getTxWithDecodedLogsAsync( - await this._erc1155Contract.setApprovalForAll.sendTransactionAsync(beneficiary, isApproved, { - from: owner, - }), - ); - return tx; - } - public async isApprovedForAllAsync(owner: string, beneficiary: string): Promise { - const isApprovedForAll = await this._erc1155Contract.isApprovedForAll.callAsync(owner, beneficiary); - return isApprovedForAll; - } public async assertBalancesAsync( owners: string[], tokens: BigNumber[], diff --git a/packages/order-utils/src/asset_data_utils.ts b/packages/order-utils/src/asset_data_utils.ts index bb61f3be9a..2acf57d5f6 100644 --- a/packages/order-utils/src/asset_data_utils.ts +++ b/packages/order-utils/src/asset_data_utils.ts @@ -107,7 +107,8 @@ export const assetDataUtils = { throw new Error(`Invalid assetProxyId. Expected '${AssetProxyId.ERC1155}', got '${assetProxyId}'`); } const abiEncoder = AbiEncoder.createMethod('ERC1155Token', ERC1155AssetDataAbi); - const decodedAssetData: ERC1155AssetDataNoProxyId = abiEncoder.decode(assetData, decodingRules); + // tslint:disable-next-line:no-unnecessary-type-assertion + const decodedAssetData = abiEncoder.decode(assetData, decodingRules) as ERC1155AssetDataNoProxyId; return { assetProxyId, tokenAddress: decodedAssetData.tokenAddress, diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json index 1250688fc6..43f9ba0845 100644 --- a/packages/types/CHANGELOG.json +++ b/packages/types/CHANGELOG.json @@ -7,14 +7,13 @@ "pr": 1661 } ] - }, + }, { "version": "2.2.2", "changes": [ { "note": "Added ERC1155 revert reasons", "pr": 1657 - } ] }, From 2a6ed0c96e146dec57020601b22775d35390dfb6 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 12 Mar 2019 17:13:41 -0700 Subject: [PATCH 20/29] Renamed tokenIds -> ids, tokenValues -> values, callbackData -> data to be consistent with the ERC1155 reference implementation. --- .../contracts/src/ERC1155Proxy.sol | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol index 81b4bf7080..1b2b1df3be 100644 --- a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol +++ b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol @@ -53,18 +53,18 @@ contract ERC1155Proxy is // | Header | 0 | 4 | assetProxyId | // | Params | | 4 * 32 | function parameters: | // | | 4 | | 1. address of ERC1155 contract | - // | | 36 | | 2. offset to tokenIds (*) | - // | | 68 | | 3. offset to tokenValues (*) | - // | | 100 | | 4. offset to callbackData (*) | - // | Data | | | tokenIds: | - // | | 132 | 32 | 1. tokenIds Length | - // | | 164 | a | 2. tokenIds Contents | - // | | | | tokenValues: | - // | | 164 + a | 32 | 1. tokenValues Length | - // | | 196 + a | b | 2. tokenValues Contents | - // | | | | callbackData | - // | | 196 + a + b | 32 | 1. callbackData Length | - // | | 228 + a + b | c | 2. callbackData Contents | + // | | 36 | | 2. offset to ids (*) | + // | | 68 | | 3. offset to values (*) | + // | | 100 | | 4. offset to data (*) | + // | Data | | | ids: | + // | | 132 | 32 | 1. ids Length | + // | | 164 | a | 2. ids Contents | + // | | | | values: | + // | | 164 + a | 32 | 1. values Length | + // | | 196 + a | b | 2. values Contents | + // | | | | data | + // | | 196 + a + b | 32 | 1. data Length | + // | | 228 + a + b | c | 2. data Contents | // // // Calldata for target ERC155 asset is encoded for safeBatchTransferFrom: @@ -75,18 +75,18 @@ contract ERC1155Proxy is // | Params | | 5 * 32 | function parameters: | // | | 4 | | 1. from address | // | | 36 | | 2. to address | - // | | 68 | | 3. offset to tokenIds (*) | - // | | 100 | | 4. offset to tokenValues (*) | - // | | 132 | | 5. offset to callbackData (*) | - // | Data | | | tokenIds: | - // | | 164 | 32 | 1. tokenIds Length | - // | | 196 | a | 2. tokenIds Contents | - // | | | | tokenValues: | - // | | 196 + a | 32 | 1. tokenValues Length | - // | | 228 + a | b | 2. tokenValues Contents | - // | | | | callbackData | - // | | 228 + a + b | 32 | 1. callbackData Length | - // | | 260 + a + b | c | 2. callbackData Contents | + // | | 68 | | 3. offset to ids (*) | + // | | 100 | | 4. offset to values (*) | + // | | 132 | | 5. offset to data (*) | + // | Data | | | ids: | + // | | 164 | 32 | 1. ids Length | + // | | 196 | a | 2. ids Contents | + // | | | | values: | + // | | 196 + a | 32 | 1. values Length | + // | | 228 + a | b | 2. values Contents | + // | | | | data | + // | | 228 + a + b | 32 | 1. data Length | + // | | 260 + a + b | c | 2. data Contents | // // // (*): offset is computed from start of function parameters, so offset @@ -132,18 +132,18 @@ contract ERC1155Proxy is // Construct Table #3 in memory, starting at memory offset 0. // The algorithm below maps asset data from Table #1 and Table #2 to Table #3, while - // scaling the `tokenValues` (Table #2) by `amount` (Table #1). Once Table #3 has + // scaling the `values` (Table #2) by `amount` (Table #1). Once Table #3 has // been constructed in memory, the destination erc1155 contract is called using this // as its calldata. This process is divided into four steps, below. ////////// STEP 1/4 ////////// // Map relevant fields from assetData (Table #2) into memory (Table #3) // The Contents column of Table #2 is the same as Table #3, - // beginning from parameter 3 - `offset to tokenIds (*)` + // beginning from parameter 3 - `offset to ids (*)` // The offsets in these rows are offset by 32 bytes in Table #3. // Strategy: // 1. Copy the assetData into memory at offset 32 - // 2. Increment by 32 the offsets to `tokenIds`, `tokenValues`, and `callbackData` + // 2. Increment by 32 the offsets to `ids`, `values`, and `data` // Load offset to `assetData` let assetDataOffset := calldataload(4) @@ -160,7 +160,7 @@ contract ERC1155Proxy is // + 32 (length of assetData) calldatacopy(32, add(36, assetDataOffset), assetDataLength) - // Increment by 32 the offsets to `tokenIds`, `tokenValues`, and `callbackData` + // Increment by 32 the offsets to `ids`, `values`, and `data` mstore(68, add(mload(68), 32)) mstore(100, add(mload(100), 32)) mstore(132, add(mload(132), 32)) @@ -173,15 +173,15 @@ contract ERC1155Proxy is ////////// STEP 2/4 ////////// let scaleAmount := calldataload(100) - let tokenValuesOffset := add(mload(100), 4) // add 4 for calldata offset - let tokenValuesLengthInBytes := mul( - mload(tokenValuesOffset), + let valuesOffset := add(mload(100), 4) // add 4 for calldata offset + let valuesLengthInBytes := mul( + mload(valuesOffset), 32 ) - let tokenValuesBegin := add(tokenValuesOffset, 32) - let tokenValuesEnd := add(tokenValuesBegin, tokenValuesLengthInBytes) - for { let tokenValueOffset := tokenValuesBegin } - lt(tokenValueOffset, tokenValuesEnd) + let valuesBegin := add(valuesOffset, 32) + let valuesEnd := add(valuesBegin, valuesLengthInBytes) + for { let tokenValueOffset := valuesBegin } + lt(tokenValueOffset, valuesEnd) { tokenValueOffset := add(tokenValueOffset, 32) } { // Load token value and generate scaled value From de971e6c464236f976015741f2304856a15fef20 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 12 Mar 2019 17:45:23 -0700 Subject: [PATCH 21/29] added exports for 1155 proxy --- packages/0x.js/src/index.ts | 2 ++ packages/contract-wrappers/src/index.ts | 1 + packages/order-utils/src/index.ts | 2 ++ packages/types/CHANGELOG.json | 13 ++++--------- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts index 0a30cd3d5c..6656decc7c 100644 --- a/packages/0x.js/src/index.ts +++ b/packages/0x.js/src/index.ts @@ -91,6 +91,8 @@ export { SingleAssetData, ERC20AssetData, ERC721AssetData, + ERC1155AssetData, + ERC1155AssetDataAbi, MultiAssetData, MultiAssetDataWithRecursiveDecoding, SignatureType, diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index f4d5898f41..9a1579104f 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -64,6 +64,7 @@ export { AssetData, ERC20AssetData, ERC721AssetData, + ERC1155AssetData, SingleAssetData, MultiAssetData, MultiAssetDataWithRecursiveDecoding, diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts index 2dc6fc71ca..68b50cc53f 100644 --- a/packages/order-utils/src/index.ts +++ b/packages/order-utils/src/index.ts @@ -46,6 +46,8 @@ export { SingleAssetData, ERC20AssetData, ERC721AssetData, + ERC1155AssetData, + ERC1155AssetDataAbi, MultiAssetData, MultiAssetDataWithRecursiveDecoding, AssetProxyId, diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json index 43f9ba0845..392c7adf15 100644 --- a/packages/types/CHANGELOG.json +++ b/packages/types/CHANGELOG.json @@ -1,19 +1,14 @@ [ - { - "version": "2.2.3", - "changes": [ - { - "note": "Added `ERC1155AssetData`, `ERC1155AssetDataNoProxyId`, and `ERC1155AssetDataAbi`", - "pr": 1661 - } - ] - }, { "version": "2.2.2", "changes": [ { "note": "Added ERC1155 revert reasons", "pr": 1657 + }, + { + "note": "Added `ERC1155AssetData`, `ERC1155AssetDataNoProxyId`, and `ERC1155AssetDataAbi`", + "pr": 1661 } ] }, From df5786deda62135d6bbc975d38e48aeba2b6977d Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 12 Mar 2019 17:45:45 -0700 Subject: [PATCH 22/29] yarn.lock for erc1155 proxy --- yarn.lock | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4601cd467b..4f342df7da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11371,9 +11371,8 @@ nan@2.10.0, nan@>=2.5.1, nan@^2.0.8, nan@^2.2.1, nan@^2.3.0, nan@^2.3.3, nan@^2. resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" nan@^2.11.0: - version "2.13.1" - resolved "https://registry.npmjs.org/nan/-/nan-2.13.1.tgz#a15bee3790bde247e8f38f1d446edcdaeb05f2dd" - integrity sha512-I6YB/YEuDeUZMmhscXKxGgZlFnhsn5y0hgOZBadkzfTRrZBtJDZeg6eQf7PYMIEclwmorTKK8GztsyOUSVBREA== + version "2.12.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" nano-json-stream-parser@^0.1.2: version "0.1.2" @@ -13507,15 +13506,6 @@ react-dom@^16.3.2: object-assign "^4.1.1" prop-types "^15.6.0" -react-dom@^16.4.2: - version "16.8.4" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-16.8.4.tgz#1061a8e01a2b3b0c8160037441c3bf00a0e3bc48" - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.13.4" - react-dom@^16.5.2: version "16.5.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.5.2.tgz#b69ee47aa20bab5327b2b9d7c1fe2a30f2cfa9d7" @@ -13573,6 +13563,8 @@ react-highlight@0xproject/react-highlight#react-peer-deps: dependencies: highlight.js "^9.11.0" highlightjs-solidity "^1.0.5" + react "^16.4.2" + react-dom "^16.4.2" react-hot-loader@^4.3.3: version "4.3.4" @@ -13817,15 +13809,6 @@ react@^16.3.2: object-assign "^4.1.1" prop-types "^15.6.0" -react@^16.4.2: - version "16.8.4" - resolved "https://registry.npmjs.org/react/-/react-16.8.4.tgz#fdf7bd9ae53f03a9c4cd1a371432c206be1c4768" - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.13.4" - react@^16.5.2: version "16.5.2" resolved "https://registry.yarnpkg.com/react/-/react-16.5.2.tgz#19f6b444ed139baa45609eee6dc3d318b3895d42" @@ -14697,13 +14680,6 @@ schedule@^0.5.0: dependencies: object-assign "^4.1.1" -scheduler@^0.13.4: - version "0.13.4" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.13.4.tgz#8fef05e7a3580c76c0364d2df5e550e4c9140298" - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - schema-utils@^0.4.4: version "0.4.7" resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" @@ -17678,8 +17654,7 @@ websocket@1.0.26: websocket@^1.0.26: version "1.0.28" - resolved "https://registry.npmjs.org/websocket/-/websocket-1.0.28.tgz#9e5f6fdc8a3fe01d4422647ef93abdd8d45a78d3" - integrity sha512-00y/20/80P7H4bCYkzuuvvfDvh+dgtXi5kzDf3UcZwN6boTYaKvsrtZ5lIYm1Gsg48siMErd9M4zjSYfYFHTrA== + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.28.tgz#9e5f6fdc8a3fe01d4422647ef93abdd8d45a78d3" dependencies: debug "^2.2.0" nan "^2.11.0" From f783c9bb25fcfb35fa0d10b52064726e3c5fc288 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 12 Mar 2019 17:53:03 -0700 Subject: [PATCH 23/29] updated comment for calldatacopy --- contracts/asset-proxy/contracts/src/ERC1155Proxy.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol index 1b2b1df3be..57862138e0 100644 --- a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol +++ b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol @@ -158,7 +158,11 @@ contract ERC1155Proxy is // 4 (function selector) // + assetDataOffset // + 32 (length of assetData) - calldatacopy(32, add(36, assetDataOffset), assetDataLength) + calldatacopy( + 32, // aligned such that "offset to ids" is at the correct location for Table #3 + add(36, assetDataOffset), // beginning of asset data contents + assetDataLength // length of asset data + ) // Increment by 32 the offsets to `ids`, `values`, and `data` mstore(68, add(mload(68), 32)) From 9207d1c68038e346bf15603bca6d64b8f9bf3a86 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 14 Mar 2019 13:38:16 -0700 Subject: [PATCH 24/29] Do not revert if value or amount are zero. Only if amount is non-zero and there is an overflow. --- .../contracts/src/ERC1155Proxy.sol | 23 ++++--------- contracts/asset-proxy/test/erc1155_proxy.ts | 33 ------------------- packages/types/src/index.ts | 2 -- 3 files changed, 7 insertions(+), 51 deletions(-) diff --git a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol index 57862138e0..c847d07779 100644 --- a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol +++ b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol @@ -176,7 +176,7 @@ contract ERC1155Proxy is ) ////////// STEP 2/4 ////////// - let scaleAmount := calldataload(100) + let amount := calldataload(100) let valuesOffset := add(mload(100), 4) // add 4 for calldata offset let valuesLengthInBytes := mul( mload(valuesOffset), @@ -190,22 +190,13 @@ contract ERC1155Proxy is { // Load token value and generate scaled value let tokenValue := mload(tokenValueOffset) - let scaledTokenValue := mul(tokenValue, scaleAmount) - - // Check if scaled value is zero - if iszero(scaledTokenValue) { - // Revert with `Error("TRANSFER_GREATER_THAN_ZERO_REQUIRED")` - mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) - mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) - mstore(64, 0x000000235452414e534645525f475245415445525f5448414e5f5a45524f5f52) - mstore(96, 0x4551554952454400000000000000000000000000000000000000000000000000) - mstore(128, 0) - revert(0, 132) - } + let scaledTokenValue := mul(tokenValue, amount) - // Check for multiplication overflow - let expectedTokenValue := div(scaledTokenValue, scaleAmount) - if iszero(eq(expectedTokenValue, tokenValue)) { + // Revert if `amount` != 0 and multiplication resulted in an overflow + if iszero(or( + iszero(amount), + eq(div(scaledTokenValue, amount), tokenValue) + )) { // Revert with `Error("UINT256_OVERFLOW")` mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index 01368f7833..e69bfb6900 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -540,39 +540,6 @@ describe('ERC1155Proxy', () => { RevertReason.NFTNotOwnedByFromAddress, ); }); - it('should revert if tansferring 0 amount of any token', async () => { - // setup test parameters - const tokenHolders = [spender, receiver]; - const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); - const valuesToTransfer = [nonFungibleValueToTransfer, new BigNumber(0), nonFungibleValueToTransfer]; - const perUnitValue = perUnitValueNft; - // check balances before transfer - const expectedInitialBalances = [ - // spender - nftOwnerBalance, - nftOwnerBalance, - nftOwnerBalance, - // receiver - nftNotOwnerBalance, - nftNotOwnerBalance, - nftNotOwnerBalance, - ]; - await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); - // execute transfer - await expectTransactionFailedAsync( - erc1155ProxyWrapper.transferFromAsync( - spender, - receiver, - erc1155Contract.address, - tokensToTransfer, - valuesToTransfer, - perUnitValue, - receiverCallbackData, - authorized, - ), - RevertReason.TransferGreaterThanZeroRequired, - ); - }); it('should revert if there is a multiplication overflow', async () => { // setup test parameters const tokenHolders = [spender, receiver]; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 49bf741e48..23cc118b2e 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -309,8 +309,6 @@ export enum RevertReason { TriedToMintNonFungibleForFungibleToken = 'TRIED_TO_MINT_NON_FUNGIBLE_FOR_FUNGIBLE_TOKEN', TransferRejected = 'TRANSFER_REJECTED', Uint256Underflow = 'UINT256_UNDERFLOW', - // ERC1155 Proxy - TransferGreaterThanZeroRequired = 'TRANSFER_GREATER_THAN_ZERO_REQUIRED', } export enum StatusCodes { From b6571d0ca3c27177f0ecc2701a0e46bdb4c2ad87 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 14 Mar 2019 20:46:11 -0700 Subject: [PATCH 25/29] Added calldatacopy comment --- contracts/asset-proxy/contracts/src/ERC1155Proxy.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol index c847d07779..b11f0d8d7d 100644 --- a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol +++ b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol @@ -218,7 +218,11 @@ contract ERC1155Proxy is mstore(0, 0x2eb2c2d600000000000000000000000000000000000000000000000000000000) // Copy `from` and `to` fields from Table #1 to Table #3 - calldatacopy(4, 36, 64) + calldatacopy( + 4, // aligned such that `from` and `to` are at the correct location for Table #3 + 36, // beginning of `from` field from Table #1 + 64 // 32 bytes for `from` + 32 bytes for `to` field + ) ////////// STEP 4/4 ////////// // Call into the destination erc1155 contract using as calldata Table #3 (constructed in-memory above) From eb9bf7c4f93a4bcdb5775cb013f414174acbcea8 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 14 Mar 2019 21:35:35 -0700 Subject: [PATCH 26/29] Adjusted changelog version since nothing has been published during this PR --- contracts/asset-proxy/CHANGELOG.json | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/contracts/asset-proxy/CHANGELOG.json b/contracts/asset-proxy/CHANGELOG.json index f2ebf8f49a..40f67bad8e 100644 --- a/contracts/asset-proxy/CHANGELOG.json +++ b/contracts/asset-proxy/CHANGELOG.json @@ -1,13 +1,4 @@ [ - { - "version": "2.1.0", - "changes": [ - { - "note": "Add ERC1155Proxy", - "pr": 1661 - } - ] - }, { "version": "2.0.0", "changes": [ @@ -18,6 +9,10 @@ { "note": "Do not reexport external dependencies", "pr": 1682 + }, + { + "note": "Add ERC1155Proxy", + "pr": 1661 } ] }, From 6a7530d741d717445fcd29a9b4ae4dd1c3df09ba Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 15 Mar 2019 14:30:18 -0700 Subject: [PATCH 27/29] added test for amount=0 --- contracts/asset-proxy/test/erc1155_proxy.ts | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index e69bfb6900..f2d2dec444 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -478,6 +478,30 @@ describe('ERC1155Proxy', () => { ]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); }); + it('should transfer nothing if amount=0', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [fungibleValueToTransferLarge]; + const perUnitValue = new BigNumber(0); + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + await erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + perUnitValue, + receiverCallbackData, + authorized, + ); + // check balances after transfer + const expectedFinalBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); it('should propagate revert reason from erc1155 contract failure', async () => { // disable transfers const shouldRejectTransfer = true; From 63ba764de852b3e03c4e719b2eecaf66c44438bf Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 15 Mar 2019 14:36:21 -0700 Subject: [PATCH 28/29] renamed perUnitValue to valueMultiplier --- contracts/asset-proxy/test/erc1155_proxy.ts | 86 ++++++++++----------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index f2d2dec444..3959a71fc2 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -37,8 +37,8 @@ describe('ERC1155Proxy', () => { const receiverContractInitialFungibleBalance = new BigNumber(0); const fungibleValueToTransferSmall = spenderInitialFungibleBalance.div(100); const fungibleValueToTransferLarge = spenderInitialFungibleBalance.div(4); - const perUnitValueSmall = new BigNumber(2); - const perUnitValueNft = new BigNumber(1); + const valueMultiplierSmall = new BigNumber(2); + const valueMultiplierNft = new BigNumber(1); const nonFungibleValueToTransfer = nftOwnerBalance; const receiverCallbackData = '0x01020304'; // addresses @@ -134,7 +134,7 @@ describe('ERC1155Proxy', () => { const tokenHolders = [spender, receiver]; const tokensToTransfer = fungibleTokens.slice(0, 1); const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = perUnitValueSmall; + const valueMultiplier = valueMultiplierSmall; // check balances before transfer const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); @@ -145,12 +145,12 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ); // check balances after transfer - const totalValueTransferred = valuesToTransfer[0].times(perUnitValue); + const totalValueTransferred = valuesToTransfer[0].times(valueMultiplier); const expectedFinalBalances = [ spenderInitialFungibleBalance.minus(totalValueTransferred), receiverInitialFungibleBalance.plus(totalValueTransferred), @@ -167,7 +167,7 @@ describe('ERC1155Proxy', () => { fungibleValueToTransferSmall.plus(20), fungibleValueToTransferSmall.plus(30), ]; - const perUnitValue = perUnitValueSmall; + const valueMultiplier = valueMultiplierSmall; // check balances before transfer const expectedInitialBalances = [ // spender @@ -183,7 +183,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ); @@ -191,7 +191,7 @@ describe('ERC1155Proxy', () => { let totalValueTransferred = _.reduce(valuesToTransfer, (sum: BigNumber, value: BigNumber) => { return sum.plus(value); }) as BigNumber; - totalValueTransferred = totalValueTransferred.times(perUnitValue); + totalValueTransferred = totalValueTransferred.times(valueMultiplier); const expectedFinalBalances = [ // spender spenderInitialFungibleBalance.minus(totalValueTransferred), @@ -209,7 +209,7 @@ describe('ERC1155Proxy', () => { fungibleValueToTransferSmall.plus(20), fungibleValueToTransferSmall.plus(30), ]; - const perUnitValue = perUnitValueSmall; + const valueMultiplier = valueMultiplierSmall; // check balances before transfer const expectedInitialBalances = [ // spender @@ -229,13 +229,13 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ); // check balances after transfer const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(perUnitValue); + return value.times(valueMultiplier); }); const expectedFinalBalances = [ // spender @@ -254,7 +254,7 @@ describe('ERC1155Proxy', () => { const tokenHolders = [spender, receiver]; const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); const valuesToTransfer = [nonFungibleValueToTransfer]; - const perUnitValue = perUnitValueNft; + const valueMultiplier = valueMultiplierNft; // check balances before transfer const expectedInitialBalances = [ // spender @@ -270,7 +270,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ); @@ -292,7 +292,7 @@ describe('ERC1155Proxy', () => { nonFungibleValueToTransfer, nonFungibleValueToTransfer, ]; - const perUnitValue = perUnitValueNft; + const valueMultiplier = valueMultiplierNft; // check balances before transfer const expectedInitialBalances = [ // spender @@ -312,7 +312,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ); @@ -342,7 +342,7 @@ describe('ERC1155Proxy', () => { nonFungibleValueToTransfer, nonFungibleValueToTransfer, ]; - const perUnitValue = perUnitValueNft; + const valueMultiplier = valueMultiplierNft; // check balances before transfer const expectedInitialBalances = [ // spender @@ -366,13 +366,13 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ); // check balances after transfer const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(perUnitValue); + return value.times(valueMultiplier); }); const expectedFinalBalances = [ // spender @@ -395,9 +395,9 @@ describe('ERC1155Proxy', () => { const tokenHolders = [spender, receiverContract]; const tokensToTransfer = fungibleTokens.slice(0, 1); const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = perUnitValueSmall; + const valueMultiplier = valueMultiplierSmall; const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(perUnitValue); + return value.times(valueMultiplier); }); // check balances before transfer const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; @@ -409,7 +409,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ); @@ -438,9 +438,9 @@ describe('ERC1155Proxy', () => { const tokenHolders = [spender, receiverContract]; const tokensToTransfer = fungibleTokens.slice(0, 1); const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = perUnitValueSmall; + const valueMultiplier = valueMultiplierSmall; const totalValuesTransferred = _.map(valuesToTransfer, (value: BigNumber) => { - return value.times(perUnitValue); + return value.times(valueMultiplier); }); const extraData = '0102030405060708'; // check balances before transfer @@ -453,7 +453,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, extraData, @@ -483,7 +483,7 @@ describe('ERC1155Proxy', () => { const tokenHolders = [spender, receiver]; const tokensToTransfer = fungibleTokens.slice(0, 1); const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = new BigNumber(0); + const valueMultiplier = new BigNumber(0); // check balances before transfer const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); @@ -494,7 +494,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ); @@ -513,7 +513,7 @@ describe('ERC1155Proxy', () => { const tokenHolders = [spender, receiverContract]; const tokensToTransfer = fungibleTokens.slice(0, 1); const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = perUnitValueSmall; + const valueMultiplier = valueMultiplierSmall; // check balances before transfer const expectedInitialBalances = [spenderInitialFungibleBalance, receiverContractInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); @@ -525,7 +525,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ), @@ -538,7 +538,7 @@ describe('ERC1155Proxy', () => { const nftToTransfer = nonFungibleTokensOwnedBySpender[0]; const tokensToTransfer = [nftToTransfer, nftToTransfer]; const valuesToTransfer = [nonFungibleValueToTransfer, nonFungibleValueToTransfer]; - const perUnitValue = perUnitValueNft; + const valueMultiplier = valueMultiplierNft; // check balances before transfer const expectedInitialBalances = [ // spender @@ -557,7 +557,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ), @@ -570,7 +570,7 @@ describe('ERC1155Proxy', () => { const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 3); const maxUintValue = new BigNumber(2).pow(256).minus(1); const valuesToTransfer = [nonFungibleValueToTransfer, maxUintValue, nonFungibleValueToTransfer]; - const perUnitValue = new BigNumber(2); + const valueMultiplier = new BigNumber(2); // check balances before transfer const expectedInitialBalances = [ // spender @@ -592,19 +592,19 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ), RevertReason.Uint256Overflow, ); }); - it('should revert if transferring > 1 instances of a non-fungible token (perUnitValue field >1)', async () => { + it('should revert if transferring > 1 instances of a non-fungible token (valueMultiplier field >1)', async () => { // setup test parameters const tokenHolders = [spender, receiver]; const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); const valuesToTransfer = [nonFungibleValueToTransfer]; - const perUnitValue = new BigNumber(2); + const valueMultiplier = new BigNumber(2); // check balances before transfer const expectedInitialBalances = [ // spender @@ -621,7 +621,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ), @@ -633,7 +633,7 @@ describe('ERC1155Proxy', () => { const tokenHolders = [spender, receiver]; const tokensToTransfer = nonFungibleTokensOwnedBySpender.slice(0, 1); const valuesToTransfer = [new BigNumber(2)]; - const perUnitValue = perUnitValueNft; + const valueMultiplier = valueMultiplierNft; // check balances before transfer const expectedInitialBalances = [ // spender @@ -650,7 +650,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ), @@ -663,7 +663,7 @@ describe('ERC1155Proxy', () => { const tokensToTransfer = fungibleTokens.slice(0, 1); const valueGreaterThanSpenderBalance = spenderInitialFungibleBalance.plus(1); const valuesToTransfer = [valueGreaterThanSpenderBalance]; - const perUnitValue = perUnitValueSmall; + const valueMultiplier = valueMultiplierSmall; // check balances before transfer const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); @@ -675,7 +675,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ), @@ -693,7 +693,7 @@ describe('ERC1155Proxy', () => { const tokenHolders = [spender, receiver]; const tokensToTransfer = fungibleTokens.slice(0, 1); const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = perUnitValueSmall; + const valueMultiplier = valueMultiplierSmall; // check balances before transfer const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); @@ -705,7 +705,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, authorized, ), @@ -717,7 +717,7 @@ describe('ERC1155Proxy', () => { const tokenHolders = [spender, receiver]; const tokensToTransfer = fungibleTokens.slice(0, 1); const valuesToTransfer = [fungibleValueToTransferLarge]; - const perUnitValue = perUnitValueSmall; + const valueMultiplier = valueMultiplierSmall; // check balances before transfer const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); @@ -729,7 +729,7 @@ describe('ERC1155Proxy', () => { erc1155Contract.address, tokensToTransfer, valuesToTransfer, - perUnitValue, + valueMultiplier, receiverCallbackData, notAuthorized, ), From 22bc1fb21edb4eb3f948920d15a53869b789a312 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 15 Mar 2019 14:44:32 -0700 Subject: [PATCH 29/29] additional zero outcome tests --- contracts/asset-proxy/test/erc1155_proxy.ts | 50 ++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index 3959a71fc2..7931fdfda0 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -478,7 +478,31 @@ describe('ERC1155Proxy', () => { ]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); }); - it('should transfer nothing if amount=0', async () => { + it('should transfer nothing if value is zero', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer = fungibleTokens.slice(0, 1); + const valuesToTransfer = [new BigNumber(0)]; + const valueMultiplier = valueMultiplierSmall; + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + await erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + valueMultiplier, + receiverCallbackData, + authorized, + ); + // check balances after transfer + const expectedFinalBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); + it('should transfer nothing if value multiplier is zero', async () => { // setup test parameters const tokenHolders = [spender, receiver]; const tokensToTransfer = fungibleTokens.slice(0, 1); @@ -502,6 +526,30 @@ describe('ERC1155Proxy', () => { const expectedFinalBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); }); + it('should transfer nothing if there are no tokens in asset data', async () => { + // setup test parameters + const tokenHolders = [spender, receiver]; + const tokensToTransfer: BigNumber[] = []; + const valuesToTransfer: BigNumber[] = []; + const valueMultiplier = valueMultiplierSmall; + // check balances before transfer + const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances); + // execute transfer + await erc1155ProxyWrapper.transferFromAsync( + spender, + receiver, + erc1155Contract.address, + tokensToTransfer, + valuesToTransfer, + valueMultiplier, + receiverCallbackData, + authorized, + ); + // check balances after transfer + const expectedFinalBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance]; + await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances); + }); it('should propagate revert reason from erc1155 contract failure', async () => { // disable transfers const shouldRejectTransfer = true;