aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts/src/2.0.0/protocol
diff options
context:
space:
mode:
Diffstat (limited to 'packages/contracts/src/2.0.0/protocol')
-rw-r--r--packages/contracts/src/2.0.0/protocol/AssetProxy/ERC721Proxy.sol100
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol41
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/libs/LibConstants.sol13
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol6
-rw-r--r--packages/contracts/src/2.0.0/protocol/Exchange/libs/LibOrder.sol28
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