diff options
author | Fabio Berger <me@fabioberger.com> | 2018-07-24 23:13:21 +0800 |
---|---|---|
committer | Fabio Berger <me@fabioberger.com> | 2018-07-24 23:13:21 +0800 |
commit | 56f21f4bab2fd844961eb3f8366a421660d04706 (patch) | |
tree | 287b86096263641b9d0c3e7441dfdeb85e1ebb93 /packages/contracts/src/2.0.0/protocol | |
parent | 9a36e73f4ed62871b2c39d129de0ac2c04aeba2b (diff) | |
parent | a05b14e4d9659be1cc495ee33fd8962ce773f87f (diff) | |
download | dexon-0x-contracts-56f21f4bab2fd844961eb3f8366a421660d04706.tar dexon-0x-contracts-56f21f4bab2fd844961eb3f8366a421660d04706.tar.gz dexon-0x-contracts-56f21f4bab2fd844961eb3f8366a421660d04706.tar.bz2 dexon-0x-contracts-56f21f4bab2fd844961eb3f8366a421660d04706.tar.lz dexon-0x-contracts-56f21f4bab2fd844961eb3f8366a421660d04706.tar.xz dexon-0x-contracts-56f21f4bab2fd844961eb3f8366a421660d04706.tar.zst dexon-0x-contracts-56f21f4bab2fd844961eb3f8366a421660d04706.zip |
Merge v2-prototype
Diffstat (limited to 'packages/contracts/src/2.0.0/protocol')
5 files changed, 80 insertions, 108 deletions
diff --git a/packages/contracts/src/2.0.0/protocol/AssetProxy/ERC721Proxy.sol b/packages/contracts/src/2.0.0/protocol/AssetProxy/ERC721Proxy.sol index 1f9958b43..6a70c9f60 100644 --- a/packages/contracts/src/2.0.0/protocol/AssetProxy/ERC721Proxy.sol +++ b/packages/contracts/src/2.0.0/protocol/AssetProxy/ERC721Proxy.sol @@ -26,7 +26,7 @@ contract ERC721Proxy is MixinAuthorizable { // Id of this proxy. - bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256,bytes)")); + bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)")); // solhint-disable-next-line payable-fallback function () @@ -83,34 +83,26 @@ contract ERC721Proxy is // WARNING: The ABIv2 specification allows additional padding between // the Params and Data section. This will result in a larger // offset to assetData. - + // Asset data itself is encoded as follows: // // | Area | Offset | Length | Contents | // |----------|--------|---------|-------------------------------------| // | Header | 0 | 4 | function selector | - // | Params | | 3 * 32 | function parameters: | + // | Params | | 2 * 32 | function parameters: | // | | 4 | 12 + 20 | 1. token address | // | | 36 | | 2. tokenId | - // | | 68 | | 3. offset to receiverData (*) | - // | Data | | | receiverData: | - // | | 100 | 32 | receiverData Length | - // | | 132 | ** | receiverData Contents | - // We construct calldata for the `token.safeTransferFrom` ABI. + // We construct calldata for the `token.transferFrom` ABI. // The layout of this calldata is in the table below. // // | Area | Offset | Length | Contents | // |----------|--------|---------|-------------------------------------| // | Header | 0 | 4 | function selector | - // | Params | | 4 * 32 | function parameters: | + // | Params | | 3 * 32 | function parameters: | // | | 4 | | 1. from | // | | 36 | | 2. to | // | | 68 | | 3. tokenId | - // | | 100 | | 4. offset to receiverData (*) | - // | Data | | | receiverData: | - // | | 132 | 32 | receiverData Length | - // | | 164 | ** | receiverData Contents | // There exists only 1 of each token. // require(amount == 1, "INVALID_AMOUNT") @@ -122,76 +114,32 @@ contract ERC721Proxy is mstore(96, 0) revert(0, 100) } - - // Require assetData to be at least 132 bytes - let offset := calldataload(4) - if lt(calldataload(add(offset, 4)), 132) { - // Revert with `Error("LENGTH_GREATER_THAN_131_REQUIRED")` - mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) - mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) - mstore(64, 0x000000204c454e4754485f475245415445525f5448414e5f3133315f52455155) - mstore(96, 0x4952454400000000000000000000000000000000000000000000000000000000) - revert(0, 100) - } - - /////// Setup State /////// - // `cdStart` is the start of the calldata for - // `token.safeTransferFrom` (equal to free memory ptr). - let cdStart := mload(64) - // `dataAreaLength` is the total number of words - // needed to store `receiverData` - // As-per the ABI spec, this value is padded up to - // the nearest multiple of 32, - // and includes 32-bytes for length. - // It's calculated as folows: - // - Unpadded length in bytes = `mload(receiverData) + 32` - // - Add 31 to convert rounding down to rounding up. - // Combined with the previous and this is `63`. - // - Round down to nearest multiple of 32 by clearing - // bits 0x1F. This is done with `and` and a mask. /////// Setup Header Area /////// - // This area holds the 4-byte `transferFromSelector`. + // This area holds the 4-byte `transferFrom` selector. // Any trailing data in transferFromSelector will be // overwritten in the next `mstore` call. - mstore(cdStart, 0xb88d4fde00000000000000000000000000000000000000000000000000000000) + mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000) /////// Setup Params Area /////// - // Each parameter is padded to 32-bytes. - // The entire Params Area is 128 bytes. - // Notes: - // 1. A 20-byte mask is applied to addresses - // to zero-out the unused bytes. - // 2. The offset to `receiverData` is the length - // of the Params Area (128 bytes). - - let length := calldataload(add(offset, 136)) - let token := calldataload(add(offset, 40)) - - // Round length up to multiple of 32 - length := and(add(length, 31), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0) - - // Copy `from` and `to` - calldatacopy(add(cdStart, 4), 36, 64) - - // TokenId - mstore(add(cdStart, 68), calldataload(add(offset, 72))) - - // Offset to receiverData - mstore(add(cdStart, 100), 128) - - // receiverData (including length) - calldatacopy(add(cdStart, 132), add(offset, 136), add(length, 32)) - - /////// Call `token.safeTransferFrom` using the calldata /////// + // We copy the fields `from` and `to` in bulk + // from our own calldata to the new calldata. + calldatacopy(4, 36, 64) + + // Copy `tokenId` field from our own calldata to the new calldata. + let assetDataOffset := calldataload(4) + calldatacopy(68, add(assetDataOffset, 72), 32) + + /////// Call `token.transferFrom` using the calldata /////// + let token := calldataload(add(assetDataOffset, 40)) let success := call( - gas, // forward all gas - token, // call address of token contract - 0, // don't send any ETH - cdStart, // pointer to start of input - add(length, 164), // length of input - 0, // write output to null - 0 // output size is 0 bytes + gas, // forward all gas + token, // call address of token contract + 0, // don't send any ETH + 0, // pointer to start of input + 100, // length of input + 0, // write output to null + 0 // output size is 0 bytes ) if success { return(0, 0) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol index 567f26c52..86194f461 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol @@ -32,6 +32,7 @@ contract MixinWrapperFunctions is LibAbiEncoder, MExchangeCore { + /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled. /// @param order Order struct containing order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. @@ -56,7 +57,7 @@ contract MixinWrapperFunctions is return fillResults; } - /// @dev Fills an order with specified parameters and ECDSA signature. + /// @dev Fills the input order. /// Returns false if the transaction would otherwise revert. /// @param order Order struct containing order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. @@ -118,7 +119,8 @@ contract MixinWrapperFunctions is public returns (FillResults memory totalFillResults) { - for (uint256 i = 0; i < orders.length; i++) { + uint256 ordersLength = orders.length; + for (uint256 i = 0; i != ordersLength; i++) { FillResults memory singleFillResults = fillOrder( orders[i], takerAssetFillAmounts[i], @@ -143,7 +145,8 @@ contract MixinWrapperFunctions is public returns (FillResults memory totalFillResults) { - for (uint256 i = 0; i < orders.length; i++) { + uint256 ordersLength = orders.length; + for (uint256 i = 0; i != ordersLength; i++) { FillResults memory singleFillResults = fillOrKillOrder( orders[i], takerAssetFillAmounts[i], @@ -169,7 +172,8 @@ contract MixinWrapperFunctions is public returns (FillResults memory totalFillResults) { - for (uint256 i = 0; i < orders.length; i++) { + uint256 ordersLength = orders.length; + for (uint256 i = 0; i != ordersLength; i++) { FillResults memory singleFillResults = fillOrderNoThrow( orders[i], takerAssetFillAmounts[i], @@ -195,7 +199,8 @@ contract MixinWrapperFunctions is { bytes memory takerAssetData = orders[0].takerAssetData; - for (uint256 i = 0; i < orders.length; i++) { + uint256 ordersLength = orders.length; + for (uint256 i = 0; i != ordersLength; i++) { // We assume that asset being sold by taker is the same for each order. // Rather than passing this in as calldata, we use the takerAssetData from the first order in all later orders. @@ -215,7 +220,7 @@ contract MixinWrapperFunctions is addFillResults(totalFillResults, singleFillResults); // Stop execution if the entire amount of takerAsset has been sold - if (totalFillResults.takerAssetFilledAmount == takerAssetFillAmount) { + if (totalFillResults.takerAssetFilledAmount >= takerAssetFillAmount) { break; } } @@ -238,7 +243,8 @@ contract MixinWrapperFunctions is { bytes memory takerAssetData = orders[0].takerAssetData; - for (uint256 i = 0; i < orders.length; i++) { + uint256 ordersLength = orders.length; + for (uint256 i = 0; i != ordersLength; i++) { // We assume that asset being sold by taker is the same for each order. // Rather than passing this in as calldata, we use the takerAssetData from the first order in all later orders. @@ -258,7 +264,7 @@ contract MixinWrapperFunctions is addFillResults(totalFillResults, singleFillResults); // Stop execution if the entire amount of takerAsset has been sold - if (totalFillResults.takerAssetFilledAmount == takerAssetFillAmount) { + if (totalFillResults.takerAssetFilledAmount >= takerAssetFillAmount) { break; } } @@ -280,7 +286,8 @@ contract MixinWrapperFunctions is { bytes memory makerAssetData = orders[0].makerAssetData; - for (uint256 i = 0; i < orders.length; i++) { + uint256 ordersLength = orders.length; + for (uint256 i = 0; i != ordersLength; i++) { // We assume that asset being bought by taker is the same for each order. // Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders. @@ -308,7 +315,7 @@ contract MixinWrapperFunctions is addFillResults(totalFillResults, singleFillResults); // Stop execution if the entire amount of makerAsset has been bought - if (totalFillResults.makerAssetFilledAmount == makerAssetFillAmount) { + if (totalFillResults.makerAssetFilledAmount >= makerAssetFillAmount) { break; } } @@ -331,7 +338,8 @@ contract MixinWrapperFunctions is { bytes memory makerAssetData = orders[0].makerAssetData; - for (uint256 i = 0; i < orders.length; i++) { + uint256 ordersLength = orders.length; + for (uint256 i = 0; i != ordersLength; i++) { // We assume that asset being bought by taker is the same for each order. // Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders. @@ -359,7 +367,7 @@ contract MixinWrapperFunctions is addFillResults(totalFillResults, singleFillResults); // Stop execution if the entire amount of makerAsset has been bought - if (totalFillResults.makerAssetFilledAmount == makerAssetFillAmount) { + if (totalFillResults.makerAssetFilledAmount >= makerAssetFillAmount) { break; } } @@ -371,7 +379,8 @@ contract MixinWrapperFunctions is function batchCancelOrders(LibOrder.Order[] memory orders) public { - for (uint256 i = 0; i < orders.length; i++) { + uint256 ordersLength = orders.length; + for (uint256 i = 0; i != ordersLength; i++) { cancelOrder(orders[i]); } } @@ -384,9 +393,9 @@ contract MixinWrapperFunctions is view returns (LibOrder.OrderInfo[] memory) { - uint256 length = orders.length; - LibOrder.OrderInfo[] memory ordersInfo = new LibOrder.OrderInfo[](length); - for (uint256 i = 0; i < length; i++) { + uint256 ordersLength = orders.length; + LibOrder.OrderInfo[] memory ordersInfo = new LibOrder.OrderInfo[](ordersLength); + for (uint256 i = 0; i != ordersLength; i++) { ordersInfo[i] = getOrderInfo(orders[i]); } return ordersInfo; diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibConstants.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibConstants.sol index 6918d755e..8d2732cd3 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibConstants.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibConstants.sol @@ -19,11 +19,23 @@ pragma solidity 0.4.24; +// solhint-disable max-line-length contract LibConstants { // Asset data for ZRX token. Used for fee transfers. // @TODO: Hardcode constant when we deploy. Currently // not constant to make testing easier. + + // The proxyId for ZRX_ASSET_DATA is bytes4(keccak256("ERC20Token(address)")) = 0xf47261b0 + + // Kovan ZRX address is 0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570. + // The ABI encoded proxyId and address is 0xf47261b00000000000000000000000006ff6c0ff1d68b964901f986d4c9fa3ac68346570 + // bytes constant public ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70"; + + // Mainnet ZRX address is 0xe41d2489571d322189246dafa5ebde1f4699f498. + // The ABI encoded proxyId and address is 0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498 + // bytes constant public ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98"; + // solhint-disable-next-line var-name-mixedcase bytes public ZRX_ASSET_DATA; @@ -34,3 +46,4 @@ contract LibConstants { ZRX_ASSET_DATA = zrxAssetData; } } +// solhint-enable max-line-length diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol index 46c13d390..fa09da6ac 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol @@ -33,7 +33,8 @@ contract LibMath is function getPartialAmount( uint256 numerator, uint256 denominator, - uint256 target) + uint256 target + ) internal pure returns (uint256 partialAmount) @@ -53,7 +54,8 @@ contract LibMath is function isRoundingError( uint256 numerator, uint256 denominator, - uint256 target) + uint256 target + ) internal pure returns (bool isError) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibOrder.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibOrder.sol index 68f2c8aed..4031ff26b 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibOrder.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibOrder.sol @@ -103,20 +103,20 @@ contract LibOrder is bytes32 takerAssetDataHash = keccak256(order.takerAssetData); // Assembly for more efficiently computing: - // keccak256(abi.encode( - // order.makerAddress, - // order.takerAddress, - // order.feeRecipientAddress, - // order.senderAddress, - // order.makerAssetAmount, - // order.takerAssetAmount, - // order.makerFee, - // order.takerFee, - // order.expirationTimeSeconds, - // order.salt, - // keccak256(order.makerAssetData), - // keccak256(order.takerAssetData) - // )); + // keccak256(abi.encode( + // order.makerAddress, + // order.takerAddress, + // order.feeRecipientAddress, + // order.senderAddress, + // order.makerAssetAmount, + // order.takerAssetAmount, + // order.makerFee, + // order.takerFee, + // order.expirationTimeSeconds, + // order.salt, + // keccak256(order.makerAssetData), + // keccak256(order.takerAssetData) + // )); assembly { // Backup |