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 {