From 98c8a6387a2f4c01972a5387f3d0c1eb43495ac9 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 27 May 2019 13:14:21 -0700 Subject: [PATCH] manually copy ids, values, and data fields --- .../contracts/src/ERC1155Proxy.sol | 77 +++++++++++-------- contracts/asset-proxy/test/erc1155_proxy.ts | 2 +- 2 files changed, 44 insertions(+), 35 deletions(-) diff --git a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol index 04b8d93132..9a023777b1 100644 --- a/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol +++ b/contracts/asset-proxy/contracts/src/ERC1155Proxy.sol @@ -160,45 +160,61 @@ contract ERC1155Proxy is // Load length in bytes of `assetData` let assetDataLength := calldataload(assetDataOffset) + + // Load offset to parameters section in asset data + let offsetToParamsInAssetData := add(assetDataOffset, 36) - // Copy the components of asset data (Table #2) that remain the same in Table #3. + // Memory offset of Data Area when stored in memory (Table #3) + let dataPtr := 164 + + // Copy ids from asset data in calldata (Table #2) to memory (Table #3). + let offsetToIds := add(offsetToParamsInAssetData, calldataload(add(assetDataOffset, 68))) + let idsLength := calldataload(offsetToIds) + let idsLengthInBytes := mul(idsLength, 32) calldatacopy( - 68, // aligned such that "offset to ids" is at the correct location for Table #3 - add(assetDataOffset, 68), // beginning of `ids` in asset data (Table #2) - sub(assetDataLength, 36) // length of asset data, starting at `ids` (Table #2) + dataPtr, + offsetToIds, + add(idsLengthInBytes, 32) ) + mstore(68, sub(dataPtr, 4)) + dataPtr := add(dataPtr, add(idsLengthInBytes, 32)) - // 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)) + // Copy values from asset data in calldata (Table #2) to memory (Table #3). + let offsetToValues := add(offsetToParamsInAssetData, calldataload(add(assetDataOffset, 100))) + let valuesLength := calldataload(offsetToValues) + let valuesLengthInBytes := mul(valuesLength, 32) + calldatacopy( + dataPtr, + offsetToValues, + add(valuesLengthInBytes, 32) + ) + mstore(100, sub(dataPtr, 4)) + dataPtr := add(dataPtr, add(valuesLengthInBytes, 32)) + + // Copy data from asset data in calldata (Table #2) to memory (Table #3). + let offsetToData := add(offsetToParamsInAssetData, calldataload(add(assetDataOffset, 132))) + let dataLengthInBytes := calldataload(offsetToData) + let dataLengthInWords := div(add(dataLengthInBytes, 31), 32) + let dataLengthInBytesWordAligned := mul(dataLengthInWords, 32) + calldatacopy( + dataPtr, + offsetToData, + add(dataLengthInBytesWordAligned, 32) + ) + mstore(132, sub(dataPtr, 4)) + dataPtr := add(dataPtr, add(dataLengthInBytesWordAligned, 32)) ////////// STEP 2/4 ////////// // Setup iterators for `values` array (Table #3) let valuesOffset := add(mload(100), 4) // add 4 for calldata offset - let valuesLength := mload(valuesOffset) - let valuesLengthInBytes := mul(valuesLength, 32) let valuesBegin := add(valuesOffset, 32) let valuesEnd := add(valuesBegin, valuesLengthInBytes) - // Setup iterators for `scaledValues` array (Table #3). - // This array is placed at the end of the regular ERC1155 calldata, - // which is 32 bytes longer than `assetData` (Table #2). - let scaledValuesOffset := add(assetDataLength, 32) - let scaledValuesBegin := add(scaledValuesOffset, 32) - let scaledValuesEnd := add(scaledValuesBegin, valuesLengthInBytes) - // Scale `values` by `amount` and store the output in `scaledValues` let amount := calldataload(100) - for { - let tokenValueOffset := valuesBegin - let scaledTokenValueOffset := scaledValuesBegin - } + for {let tokenValueOffset := valuesBegin} lt(tokenValueOffset, valuesEnd) - { - tokenValueOffset := add(tokenValueOffset, 32) - scaledTokenValueOffset := add(scaledTokenValueOffset, 32) - } + {tokenValueOffset := add(tokenValueOffset, 32)} { // Load token value and generate scaled value let tokenValue := mload(tokenValueOffset) @@ -218,16 +234,9 @@ contract ERC1155Proxy is } // There was no overflow, store the scaled token value - mstore(scaledTokenValueOffset, scaledTokenValue) + mstore(tokenValueOffset, scaledTokenValue) } - // Store length of `scaledValues` (which is the same as `values`) - mstore(scaledValuesOffset, valuesLength) - - // Point `values` to `scaledValues` (see Table #3); - // subtract 4 from memory location to account for selector - mstore(100, sub(scaledValuesOffset, 4)) - ////////// STEP 3/4 ////////// // Store the safeBatchTransferFrom function selector, // and copy `from`/`to` fields from Table #1 to Table #3. @@ -258,7 +267,7 @@ contract ERC1155Proxy is assetAddress, // call address of erc1155 asset 0, // don't send any ETH 0, // pointer to start of input - scaledValuesEnd, // length of input (Table #3) is the end of the `scaledValues` + dataPtr, // length of input is the end of the Data Area (Table #3) 0, // write output over memory that won't be reused 0 // don't copy output to memory ) diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index 52bd158cc3..f370fc02ef 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -30,7 +30,7 @@ const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); // tslint:disable:no-unnecessary-type-assertion -describe('ERC1155Proxy', () => { +describe.only('ERC1155Proxy', () => { // constant values used in transfer tests const nftOwnerBalance = new BigNumber(1); const nftNotOwnerBalance = new BigNumber(0);