aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts/src
diff options
context:
space:
mode:
authorGreg Hysen <hysz@users.noreply.github.com>2018-06-09 02:58:23 +0800
committerGitHub <noreply@github.com>2018-06-09 02:58:23 +0800
commit817c332d11835f02726f0609374d1c25c9ab39b5 (patch)
treed84c9a96465b5e862629be3dd04325dcccdbc780 /packages/contracts/src
parentadd9a9db9ba4294cf12489bf589c527b0921ed1e (diff)
parent05fbc8e6b061e5cef5bb8b8078176f9b375c2ec5 (diff)
downloaddexon-sol-tools-817c332d11835f02726f0609374d1c25c9ab39b5.tar
dexon-sol-tools-817c332d11835f02726f0609374d1c25c9ab39b5.tar.gz
dexon-sol-tools-817c332d11835f02726f0609374d1c25c9ab39b5.tar.bz2
dexon-sol-tools-817c332d11835f02726f0609374d1c25c9ab39b5.tar.lz
dexon-sol-tools-817c332d11835f02726f0609374d1c25c9ab39b5.tar.xz
dexon-sol-tools-817c332d11835f02726f0609374d1c25c9ab39b5.tar.zst
dexon-sol-tools-817c332d11835f02726f0609374d1c25c9ab39b5.zip
Merge pull request #627 from 0xProject/feature/contracts/erc721SafeTransferFrom
On-Chain AssetData Decoding Lib + safeTransferFrom for ERC721 + Memcpy
Diffstat (limited to 'packages/contracts/src')
-rw-r--r--packages/contracts/src/contracts/current/protocol/AssetProxy/ERC20Proxy.sol48
-rw-r--r--packages/contracts/src/contracts/current/protocol/AssetProxy/ERC721Proxy.sol77
-rw-r--r--packages/contracts/src/contracts/current/protocol/AssetProxy/MixinAssetProxy.sol14
-rw-r--r--packages/contracts/src/contracts/current/protocol/AssetProxy/interfaces/IAssetProxy.sol8
-rw-r--r--packages/contracts/src/contracts/current/protocol/AssetProxy/libs/LibAssetProxyErrors.sol4
-rw-r--r--packages/contracts/src/contracts/current/protocol/AssetProxy/mixins/MAssetProxy.sol4
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/Exchange.sol4
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/MixinAssetProxyDispatcher.sol10
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/MixinSettlement.sol10
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol59
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol3
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/interfaces/ITransactions.sol3
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IWrapperFunctions.sol27
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/mixins/MAssetProxyDispatcher.sol4
-rw-r--r--packages/contracts/src/contracts/current/test/DummyERC20Token/DummyERC20Token.sol3
-rw-r--r--packages/contracts/src/contracts/current/test/DummyERC721Receiver/DummyERC721Receiver.sol63
-rw-r--r--packages/contracts/src/contracts/current/test/DummyERC721Token/DummyERC721Token.sol3
-rw-r--r--packages/contracts/src/contracts/current/test/TestAssetDataDecoders/TestAssetDataDecoders.sol77
-rw-r--r--packages/contracts/src/contracts/current/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol4
-rw-r--r--packages/contracts/src/contracts/current/test/TestLibBytes/TestLibBytes.sol52
-rw-r--r--packages/contracts/src/contracts/current/test/TestLibMem/TestLibMem.sol56
-rw-r--r--packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol97
-rw-r--r--packages/contracts/src/contracts/current/utils/LibMem/LibMem.sol140
-rw-r--r--packages/contracts/src/utils/artifacts.ts6
-rw-r--r--packages/contracts/src/utils/constants.ts10
-rw-r--r--packages/contracts/src/utils/match_order_tester.ts24
-rw-r--r--packages/contracts/src/utils/types.ts3
27 files changed, 673 insertions, 140 deletions
diff --git a/packages/contracts/src/contracts/current/protocol/AssetProxy/ERC20Proxy.sol b/packages/contracts/src/contracts/current/protocol/AssetProxy/ERC20Proxy.sol
index 2c321e134..dd25bf41a 100644
--- a/packages/contracts/src/contracts/current/protocol/AssetProxy/ERC20Proxy.sol
+++ b/packages/contracts/src/contracts/current/protocol/AssetProxy/ERC20Proxy.sol
@@ -34,34 +34,30 @@ contract ERC20Proxy is
uint8 constant PROXY_ID = 1;
/// @dev Internal version of `transferFrom`.
- /// @param assetMetadata Encoded byte array.
+ /// @param assetData Encoded byte array.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer.
function transferFromInternal(
- bytes memory assetMetadata,
+ bytes memory assetData,
address from,
address to,
uint256 amount
)
internal
{
- // Data must be intended for this proxy.
- uint256 length = assetMetadata.length;
+ // Decode asset data.
+ (
+ uint8 proxyId,
+ address token
+ ) = decodeERC20AssetData(assetData);
+ // Data must be intended for this proxy.
require(
- length == 21,
- LENGTH_21_REQUIRED
- );
- // TODO: Is this too inflexible in the future?
- require(
- uint8(assetMetadata[length - 1]) == PROXY_ID,
+ proxyId == PROXY_ID,
ASSET_PROXY_ID_MISMATCH
);
- // Decode metadata.
- address token = readAddress(assetMetadata, 0);
-
// Transfer tokens.
bool success = IERC20Token(token).transferFrom(from, to, amount);
require(
@@ -79,4 +75,30 @@ contract ERC20Proxy is
{
return PROXY_ID;
}
+
+ /// @dev Decodes ERC20 Asset data.
+ /// @param assetData Encoded byte array.
+ /// @return proxyId Intended ERC20 proxy id.
+ /// @return token ERC20 token address.
+ function decodeERC20AssetData(bytes memory assetData)
+ internal
+ pure
+ returns (
+ uint8 proxyId,
+ address token
+ )
+ {
+ // Validate encoded data length
+ uint256 length = assetData.length;
+ require(
+ length == 21,
+ LENGTH_21_REQUIRED
+ );
+
+ // Decode data
+ token = readAddress(assetData, 0);
+ proxyId = uint8(assetData[length - 1]);
+
+ return (proxyId, token);
+ }
}
diff --git a/packages/contracts/src/contracts/current/protocol/AssetProxy/ERC721Proxy.sol b/packages/contracts/src/contracts/current/protocol/AssetProxy/ERC721Proxy.sol
index 07e01c774..25136133d 100644
--- a/packages/contracts/src/contracts/current/protocol/AssetProxy/ERC721Proxy.sol
+++ b/packages/contracts/src/contracts/current/protocol/AssetProxy/ERC721Proxy.sol
@@ -34,29 +34,30 @@ contract ERC721Proxy is
uint8 constant PROXY_ID = 2;
/// @dev Internal version of `transferFrom`.
- /// @param assetMetadata Encoded byte array.
+ /// @param assetData Encoded byte array.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer.
function transferFromInternal(
- bytes memory assetMetadata,
+ bytes memory assetData,
address from,
address to,
uint256 amount
)
internal
{
- // Data must be intended for this proxy.
- uint256 length = assetMetadata.length;
+ // Decode asset data.
+ (
+ uint8 proxyId,
+ address token,
+ uint256 tokenId,
+ bytes memory receiverData
+ ) = decodeERC721AssetData(assetData);
- require(
- length == 53,
- LENGTH_53_REQUIRED
- );
- // TODO: Is this too inflexible in the future?
+ // Data must be intended for this proxy.
require(
- uint8(assetMetadata[length - 1]) == PROXY_ID,
+ proxyId == PROXY_ID,
ASSET_PROXY_ID_MISMATCH
);
@@ -66,15 +67,13 @@ contract ERC721Proxy is
INVALID_AMOUNT
);
- // Decode metadata
- address token = readAddress(assetMetadata, 0);
- uint256 tokenId = readUint256(assetMetadata, 20);
-
- // Transfer token.
- // Either succeeds or throws.
- // @TODO: Call safeTransferFrom if there is additional
- // data stored in `assetMetadata`.
- ERC721Token(token).transferFrom(from, to, tokenId);
+ // Transfer token. Saves gas by calling safeTransferFrom only
+ // when there is receiverData present. Either succeeds or throws.
+ if(receiverData.length > 0) {
+ ERC721Token(token).safeTransferFrom(from, to, tokenId, receiverData);
+ } else {
+ ERC721Token(token).transferFrom(from, to, tokenId);
+ }
}
/// @dev Gets the proxy id associated with the proxy address.
@@ -86,4 +85,44 @@ contract ERC721Proxy is
{
return PROXY_ID;
}
+
+ /// @dev Decodes ERC721 Asset data.
+ /// @param assetData Encoded byte array.
+ /// @return proxyId Intended ERC721 proxy id.
+ /// @return token ERC721 token address.
+ /// @return tokenId ERC721 token id.
+ /// @return receiverData Additional data with no specific format, which
+ /// is passed to the receiving contract's onERC721Received.
+ function decodeERC721AssetData(bytes memory assetData)
+ internal
+ pure
+ returns (
+ uint8 proxyId,
+ address token,
+ uint256 tokenId,
+ bytes memory receiverData
+ )
+ {
+ // Validate encoded data length
+ uint256 length = assetData.length;
+ require(
+ length >= 53,
+ LENGTH_AT_LEAST_53_REQUIRED
+ );
+
+ // Decode asset data.
+ token = readAddress(assetData, 0);
+ tokenId = readUint256(assetData, 20);
+ if (length > 53) {
+ receiverData = readBytes(assetData, 52);
+ }
+ proxyId = uint8(assetData[length - 1]);
+
+ return (
+ proxyId,
+ token,
+ tokenId,
+ receiverData
+ );
+ }
}
diff --git a/packages/contracts/src/contracts/current/protocol/AssetProxy/MixinAssetProxy.sol b/packages/contracts/src/contracts/current/protocol/AssetProxy/MixinAssetProxy.sol
index 5fa33cbef..9032658e7 100644
--- a/packages/contracts/src/contracts/current/protocol/AssetProxy/MixinAssetProxy.sol
+++ b/packages/contracts/src/contracts/current/protocol/AssetProxy/MixinAssetProxy.sol
@@ -28,12 +28,12 @@ contract MixinAssetProxy is
{
/// @dev Transfers assets. Either succeeds or throws.
- /// @param assetMetadata Encoded byte array.
+ /// @param assetData Encoded byte array.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer.
function transferFrom(
- bytes assetMetadata,
+ bytes assetData,
address from,
address to,
uint256 amount
@@ -42,7 +42,7 @@ contract MixinAssetProxy is
onlyAuthorized
{
transferFromInternal(
- assetMetadata,
+ assetData,
from,
to,
amount
@@ -50,12 +50,12 @@ contract MixinAssetProxy is
}
/// @dev Makes multiple transfers of assets. Either succeeds or throws.
- /// @param assetMetadata Array of byte arrays encoded for the respective asset proxy.
+ /// @param assetData Array of byte arrays encoded for the respective asset proxy.
/// @param from Array of addresses to transfer assets from.
/// @param to Array of addresses to transfer assets to.
/// @param amounts Array of amounts of assets to transfer.
function batchTransferFrom(
- bytes[] memory assetMetadata,
+ bytes[] memory assetData,
address[] memory from,
address[] memory to,
uint256[] memory amounts
@@ -63,9 +63,9 @@ contract MixinAssetProxy is
public
onlyAuthorized
{
- for (uint256 i = 0; i < assetMetadata.length; i++) {
+ for (uint256 i = 0; i < assetData.length; i++) {
transferFromInternal(
- assetMetadata[i],
+ assetData[i],
from[i],
to[i],
amounts[i]
diff --git a/packages/contracts/src/contracts/current/protocol/AssetProxy/interfaces/IAssetProxy.sol b/packages/contracts/src/contracts/current/protocol/AssetProxy/interfaces/IAssetProxy.sol
index 7e1848889..22f43b12f 100644
--- a/packages/contracts/src/contracts/current/protocol/AssetProxy/interfaces/IAssetProxy.sol
+++ b/packages/contracts/src/contracts/current/protocol/AssetProxy/interfaces/IAssetProxy.sol
@@ -26,12 +26,12 @@ contract IAssetProxy is
{
/// @dev Transfers assets. Either succeeds or throws.
- /// @param assetMetadata Byte array encoded for the respective asset proxy.
+ /// @param assetData Byte array encoded for the respective asset proxy.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer.
function transferFrom(
- bytes assetMetadata,
+ bytes assetData,
address from,
address to,
uint256 amount
@@ -39,12 +39,12 @@ contract IAssetProxy is
external;
/// @dev Makes multiple transfers of assets. Either succeeds or throws.
- /// @param assetMetadata Array of byte arrays encoded for the respective asset proxy.
+ /// @param assetData Array of byte arrays encoded for the respective asset proxy.
/// @param from Array of addresses to transfer assets from.
/// @param to Array of addresses to transfer assets to.
/// @param amounts Array of amounts of assets to transfer.
function batchTransferFrom(
- bytes[] memory assetMetadata,
+ bytes[] memory assetData,
address[] memory from,
address[] memory to,
uint256[] memory amounts
diff --git a/packages/contracts/src/contracts/current/protocol/AssetProxy/libs/LibAssetProxyErrors.sol b/packages/contracts/src/contracts/current/protocol/AssetProxy/libs/LibAssetProxyErrors.sol
index e0c7fc796..80180a0d9 100644
--- a/packages/contracts/src/contracts/current/protocol/AssetProxy/libs/LibAssetProxyErrors.sol
+++ b/packages/contracts/src/contracts/current/protocol/AssetProxy/libs/LibAssetProxyErrors.sol
@@ -29,9 +29,9 @@ contract LibAssetProxyErrors {
/// AssetProxy errors ///
string constant ASSET_PROXY_ID_MISMATCH = "ASSET_PROXY_ID_MISMATCH"; // Proxy id in metadata does not match this proxy id.
string constant INVALID_AMOUNT = "INVALID_AMOUNT"; // Transfer amount must equal 1.
- string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Transfer failed.
+ string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Transfer failed.
/// Length validation errors ///
string constant LENGTH_21_REQUIRED = "LENGTH_21_REQUIRED"; // Byte array must have a length of 21.
- string constant LENGTH_53_REQUIRED = "LENGTH_53_REQUIRED"; // Byte array must have a length of 53.
+ string constant LENGTH_AT_LEAST_53_REQUIRED = "LENGTH_AT_LEAST_53_REQUIRED"; // Byte array must have a length of at least 53.
}
diff --git a/packages/contracts/src/contracts/current/protocol/AssetProxy/mixins/MAssetProxy.sol b/packages/contracts/src/contracts/current/protocol/AssetProxy/mixins/MAssetProxy.sol
index de9d65a53..a52cb56f9 100644
--- a/packages/contracts/src/contracts/current/protocol/AssetProxy/mixins/MAssetProxy.sol
+++ b/packages/contracts/src/contracts/current/protocol/AssetProxy/mixins/MAssetProxy.sol
@@ -26,12 +26,12 @@ contract MAssetProxy is
{
/// @dev Internal version of `transferFrom`.
- /// @param assetMetadata Encoded byte array.
+ /// @param assetData Encoded byte array.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer.
function transferFromInternal(
- bytes memory assetMetadata,
+ bytes memory assetData,
address from,
address to,
uint256 amount
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/Exchange.sol b/packages/contracts/src/contracts/current/protocol/Exchange/Exchange.sol
index b7b308069..51f99bafa 100644
--- a/packages/contracts/src/contracts/current/protocol/Exchange/Exchange.sol
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/Exchange.sol
@@ -40,11 +40,11 @@ contract Exchange is
string constant public VERSION = "2.0.1-alpha";
// Mixins are instantiated in the order they are inherited
- constructor (bytes memory _zrxProxyData)
+ constructor (bytes memory _zrxAssetData)
public
MixinExchangeCore()
MixinMatchOrders()
- MixinSettlement(_zrxProxyData)
+ MixinSettlement(_zrxAssetData)
MixinSignatureValidator()
MixinTransactions()
MixinAssetProxyDispatcher()
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/MixinAssetProxyDispatcher.sol b/packages/contracts/src/contracts/current/protocol/Exchange/MixinAssetProxyDispatcher.sol
index 8f9342739..e77d81c06 100644
--- a/packages/contracts/src/contracts/current/protocol/Exchange/MixinAssetProxyDispatcher.sol
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/MixinAssetProxyDispatcher.sol
@@ -80,12 +80,12 @@ contract MixinAssetProxyDispatcher is
}
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
- /// @param assetMetadata Byte array encoded for the respective asset proxy.
+ /// @param assetData Byte array encoded for the respective asset proxy.
/// @param from Address to transfer token from.
/// @param to Address to transfer token to.
/// @param amount Amount of token to transfer.
function dispatchTransferFrom(
- bytes memory assetMetadata,
+ bytes memory assetData,
address from,
address to,
uint256 amount
@@ -96,16 +96,16 @@ contract MixinAssetProxyDispatcher is
if (amount > 0) {
// Lookup asset proxy
- uint256 length = assetMetadata.length;
+ uint256 length = assetData.length;
require(
length > 0,
LENGTH_GREATER_THAN_0_REQUIRED
);
- uint8 assetProxyId = uint8(assetMetadata[length - 1]);
+ uint8 assetProxyId = uint8(assetData[length - 1]);
IAssetProxy assetProxy = assetProxies[assetProxyId];
// transferFrom will either succeed or throw.
- assetProxy.transferFrom(assetMetadata, from, to, amount);
+ assetProxy.transferFrom(assetData, from, to, amount);
}
}
}
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/MixinSettlement.sol b/packages/contracts/src/contracts/current/protocol/Exchange/MixinSettlement.sol
index 646d3ed58..83e9dfdf4 100644
--- a/packages/contracts/src/contracts/current/protocol/Exchange/MixinSettlement.sol
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/MixinSettlement.sol
@@ -40,7 +40,7 @@ contract MixinSettlement is
bytes internal ZRX_PROXY_DATA;
/// @dev Gets the ZRX metadata used for fee transfers.
- function zrxProxyData()
+ function zrxAssetData()
external
view
returns (bytes memory)
@@ -48,13 +48,13 @@ contract MixinSettlement is
return ZRX_PROXY_DATA;
}
- /// TODO: _zrxProxyData should be a constant in production.
+ /// TODO: _zrxAssetData should be a constant in production.
/// @dev Constructor sets the metadata that will be used for paying ZRX fees.
- /// @param _zrxProxyData Byte array containing ERC20 proxy id concatenated with address of ZRX.
- constructor (bytes memory _zrxProxyData)
+ /// @param _zrxAssetData Byte array containing ERC20 proxy id concatenated with address of ZRX.
+ constructor (bytes memory _zrxAssetData)
public
{
- ZRX_PROXY_DATA = _zrxProxyData;
+ ZRX_PROXY_DATA = _zrxAssetData;
}
/// @dev Settles an order by transferring assets between counterparties.
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol
index 0ad0710ce..e09f80bcc 100644
--- a/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol
@@ -40,7 +40,8 @@ contract MixinWrapperFunctions is
function fillOrKillOrder(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
- bytes memory signature)
+ bytes memory signature
+ )
public
returns (FillResults memory fillResults)
{
@@ -65,7 +66,8 @@ contract MixinWrapperFunctions is
function fillOrderNoThrow(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
- bytes memory signature)
+ bytes memory signature
+ )
public
returns (FillResults memory fillResults)
{
@@ -91,12 +93,12 @@ contract MixinWrapperFunctions is
// | | 0x0E0 | | 8. takerFeeAmount |
// | | 0x100 | | 9. expirationTimeSeconds |
// | | 0x120 | | 10. salt |
- // | | 0x140 | | 11. Offset to makerAssetProxyMetadata (*) |
- // | | 0x160 | | 12. Offset to takerAssetProxyMetadata (*) |
- // | | 0x180 | 32 | makerAssetProxyMetadata Length |
- // | | 0x1A0 | ** | makerAssetProxyMetadata Contents |
- // | | 0x1C0 | 32 | takerAssetProxyMetadata Length |
- // | | 0x1E0 | ** | takerAssetProxyMetadata Contents |
+ // | | 0x140 | | 11. Offset to makerAssetData (*) |
+ // | | 0x160 | | 12. Offset to takerAssetData (*) |
+ // | | 0x180 | 32 | makerAssetData Length |
+ // | | 0x1A0 | ** | makerAssetData Contents |
+ // | | 0x1C0 | 32 | takerAssetData Length |
+ // | | 0x1E0 | ** | takerAssetData Contents |
// | | 0x200 | 32 | signature Length |
// | | 0x220 | ** | signature Contents |
@@ -163,43 +165,43 @@ contract MixinWrapperFunctions is
mstore(add(dataAreaEnd, 0xE0), mload(add(sourceOffset, 0xE0))) // takerFeeAmount
mstore(add(dataAreaEnd, 0x100), mload(add(sourceOffset, 0x100))) // expirationTimeSeconds
mstore(add(dataAreaEnd, 0x120), mload(add(sourceOffset, 0x120))) // salt
- mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetProxyMetadata
- mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetProxyMetadata
+ mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetData
+ mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetData
dataAreaEnd := add(dataAreaEnd, 0x180)
sourceOffset := add(sourceOffset, 0x180)
- // Write offset to <order.makerAssetProxyMetadata>
+ // Write offset to <order.makerAssetData>
mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
- // Calculate length of <order.makerAssetProxyMetadata>
+ // Calculate length of <order.makerAssetData>
arrayLenBytes := mload(sourceOffset)
sourceOffset := add(sourceOffset, 0x20)
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
- // Write length of <order.makerAssetProxyMetadata>
+ // Write length of <order.makerAssetData>
mstore(dataAreaEnd, arrayLenBytes)
dataAreaEnd := add(dataAreaEnd, 0x20)
- // Write contents of <order.makerAssetProxyMetadata>
+ // Write contents of <order.makerAssetData>
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
mstore(dataAreaEnd, mload(sourceOffset))
dataAreaEnd := add(dataAreaEnd, 0x20)
sourceOffset := add(sourceOffset, 0x20)
}
- // Write offset to <order.takerAssetProxyMetadata>
+ // Write offset to <order.takerAssetData>
mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
- // Calculate length of <order.takerAssetProxyMetadata>
+ // Calculate length of <order.takerAssetData>
arrayLenBytes := mload(sourceOffset)
sourceOffset := add(sourceOffset, 0x20)
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
- // Write length of <order.takerAssetProxyMetadata>
+ // Write length of <order.takerAssetData>
mstore(dataAreaEnd, arrayLenBytes)
dataAreaEnd := add(dataAreaEnd, 0x20)
- // Write contents of <order.takerAssetProxyMetadata>
+ // Write contents of <order.takerAssetData>
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
mstore(dataAreaEnd, mload(sourceOffset))
dataAreaEnd := add(dataAreaEnd, 0x20)
@@ -264,7 +266,8 @@ contract MixinWrapperFunctions is
function batchFillOrders(
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public
{
for (uint256 i = 0; i < orders.length; i++) {
@@ -283,7 +286,8 @@ contract MixinWrapperFunctions is
function batchFillOrKillOrders(
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public
{
for (uint256 i = 0; i < orders.length; i++) {
@@ -303,7 +307,8 @@ contract MixinWrapperFunctions is
function batchFillOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public
{
for (uint256 i = 0; i < orders.length; i++) {
@@ -323,7 +328,8 @@ contract MixinWrapperFunctions is
function marketSellOrders(
LibOrder.Order[] memory orders,
uint256 takerAssetFillAmount,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public
returns (FillResults memory totalFillResults)
{
@@ -366,7 +372,8 @@ contract MixinWrapperFunctions is
function marketSellOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256 takerAssetFillAmount,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public
returns (FillResults memory totalFillResults)
{
@@ -408,7 +415,8 @@ contract MixinWrapperFunctions is
function marketBuyOrders(
LibOrder.Order[] memory orders,
uint256 makerAssetFillAmount,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public
returns (FillResults memory totalFillResults)
{
@@ -459,7 +467,8 @@ contract MixinWrapperFunctions is
function marketBuyOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256 makerAssetFillAmount,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public
returns (FillResults memory totalFillResults)
{
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol b/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol
index 3ce5ef157..2c331dc34 100644
--- a/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IAssetProxyDispatcher.sol
@@ -28,7 +28,8 @@ contract IAssetProxyDispatcher {
function registerAssetProxy(
uint8 assetProxyId,
address newAssetProxy,
- address oldAssetProxy)
+ address oldAssetProxy
+ )
external;
/// @dev Gets an asset proxy.
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/ITransactions.sol b/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/ITransactions.sol
index d973bf001..2f9a5bc7c 100644
--- a/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/ITransactions.sol
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/ITransactions.sol
@@ -28,6 +28,7 @@ contract ITransactions {
uint256 salt,
address signer,
bytes data,
- bytes signature)
+ bytes signature
+ )
external;
}
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IWrapperFunctions.sol b/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IWrapperFunctions.sol
index 8682b394a..acd4f359c 100644
--- a/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IWrapperFunctions.sol
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/interfaces/IWrapperFunctions.sol
@@ -33,7 +33,8 @@ contract IWrapperFunctions is
function fillOrKillOrder(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
- bytes memory signature)
+ bytes memory signature
+ )
public
returns (LibFillResults.FillResults memory fillResults);
@@ -46,7 +47,8 @@ contract IWrapperFunctions is
function fillOrderNoThrow(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
- bytes memory signature)
+ bytes memory signature
+ )
public
returns (LibFillResults.FillResults memory fillResults);
@@ -57,7 +59,8 @@ contract IWrapperFunctions is
function batchFillOrders(
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public;
/// @dev Synchronously executes multiple calls of fillOrKill.
@@ -67,7 +70,8 @@ contract IWrapperFunctions is
function batchFillOrKillOrders(
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public;
/// @dev Fills an order with specified parameters and ECDSA signature.
@@ -78,7 +82,8 @@ contract IWrapperFunctions is
function batchFillOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public;
/// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
@@ -89,7 +94,8 @@ contract IWrapperFunctions is
function marketSellOrders(
LibOrder.Order[] memory orders,
uint256 takerAssetFillAmount,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public
returns (LibFillResults.FillResults memory totalFillResults);
@@ -102,7 +108,8 @@ contract IWrapperFunctions is
function marketSellOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256 takerAssetFillAmount,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public
returns (LibFillResults.FillResults memory totalFillResults);
@@ -114,7 +121,8 @@ contract IWrapperFunctions is
function marketBuyOrders(
LibOrder.Order[] memory orders,
uint256 makerAssetFillAmount,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public
returns (LibFillResults.FillResults memory totalFillResults);
@@ -127,7 +135,8 @@ contract IWrapperFunctions is
function marketBuyOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256 makerAssetFillAmount,
- bytes[] memory signatures)
+ bytes[] memory signatures
+ )
public
returns (LibFillResults.FillResults memory totalFillResults);
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/mixins/MAssetProxyDispatcher.sol b/packages/contracts/src/contracts/current/protocol/Exchange/mixins/MAssetProxyDispatcher.sol
index 87c5f6361..82eafb529 100644
--- a/packages/contracts/src/contracts/current/protocol/Exchange/mixins/MAssetProxyDispatcher.sol
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/mixins/MAssetProxyDispatcher.sol
@@ -33,12 +33,12 @@ contract MAssetProxyDispatcher is
);
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
- /// @param assetMetadata Byte array encoded for the respective asset proxy.
+ /// @param assetData Byte array encoded for the respective asset proxy.
/// @param from Address to transfer token from.
/// @param to Address to transfer token to.
/// @param amount Amount of token to transfer.
function dispatchTransferFrom(
- bytes memory assetMetadata,
+ bytes memory assetData,
address from,
address to,
uint256 amount
diff --git a/packages/contracts/src/contracts/current/test/DummyERC20Token/DummyERC20Token.sol b/packages/contracts/src/contracts/current/test/DummyERC20Token/DummyERC20Token.sol
index 0c7b18c0c..b2fe2df06 100644
--- a/packages/contracts/src/contracts/current/test/DummyERC20Token/DummyERC20Token.sol
+++ b/packages/contracts/src/contracts/current/test/DummyERC20Token/DummyERC20Token.sol
@@ -31,7 +31,8 @@ contract DummyERC20Token is Mintable, Ownable {
string _name,
string _symbol,
uint256 _decimals,
- uint256 _totalSupply)
+ uint256 _totalSupply
+ )
public
{
name = _name;
diff --git a/packages/contracts/src/contracts/current/test/DummyERC721Receiver/DummyERC721Receiver.sol b/packages/contracts/src/contracts/current/test/DummyERC721Receiver/DummyERC721Receiver.sol
new file mode 100644
index 000000000..c584d0b54
--- /dev/null
+++ b/packages/contracts/src/contracts/current/test/DummyERC721Receiver/DummyERC721Receiver.sol
@@ -0,0 +1,63 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2016 Smart Contract Solutions, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+pragma solidity ^0.4.24;
+
+import "../../tokens/ERC721Token/IERC721Receiver.sol";
+
+contract DummyERC721Receiver is
+ IERC721Receiver
+{
+
+ event TokenReceived(
+ address from,
+ uint256 tokenId,
+ bytes data
+ );
+
+ /**
+ * @notice Handle the receipt of an NFT
+ * @dev The ERC721 smart contract calls this function on the recipient
+ * after a `safetransfer`. This function MAY throw to revert and reject the
+ * transfer. This function MUST use 50,000 gas or less. Return of other
+ * than the magic value MUST result in the transaction being reverted.
+ * Note: the contract address is always the message sender.
+ * @param _from The sending address
+ * @param _tokenId The NFT identifier which is being transfered
+ * @param _data Additional data with no specified format
+ * @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
+ */
+ function onERC721Received(
+ address _from,
+ uint256 _tokenId,
+ bytes _data
+ )
+ public
+ returns (bytes4)
+ {
+ emit TokenReceived(_from, _tokenId, _data);
+ return ERC721_RECEIVED;
+ }
+}
diff --git a/packages/contracts/src/contracts/current/test/DummyERC721Token/DummyERC721Token.sol b/packages/contracts/src/contracts/current/test/DummyERC721Token/DummyERC721Token.sol
index 369a2950d..5503eb2f2 100644
--- a/packages/contracts/src/contracts/current/test/DummyERC721Token/DummyERC721Token.sol
+++ b/packages/contracts/src/contracts/current/test/DummyERC721Token/DummyERC721Token.sol
@@ -34,7 +34,8 @@ contract DummyERC721Token is
*/
constructor (
string name,
- string symbol)
+ string symbol
+ )
public
ERC721Token(name, symbol)
{}
diff --git a/packages/contracts/src/contracts/current/test/TestAssetDataDecoders/TestAssetDataDecoders.sol b/packages/contracts/src/contracts/current/test/TestAssetDataDecoders/TestAssetDataDecoders.sol
new file mode 100644
index 000000000..2c6a8fdb0
--- /dev/null
+++ b/packages/contracts/src/contracts/current/test/TestAssetDataDecoders/TestAssetDataDecoders.sol
@@ -0,0 +1,77 @@
+/*
+
+ 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;
+pragma experimental ABIEncoderV2;
+
+import "../../protocol/AssetProxy/ERC20Proxy.sol";
+import "../../protocol/AssetProxy/ERC721Proxy.sol";
+
+contract TestAssetDataDecoders is
+ ERC20Proxy,
+ ERC721Proxy
+{
+
+ /// @dev Decodes ERC20 Asset data.
+ /// @param assetData Encoded byte array.
+ /// @return proxyId Intended ERC20 proxy id.
+ /// @return token ERC20 token address.
+ function publicDecodeERC20Data(bytes memory assetData)
+ public
+ pure
+ returns (
+ uint8 proxyId,
+ address token
+ )
+ {
+ (proxyId, token) = decodeERC20AssetData(assetData);
+ return (proxyId, token);
+ }
+
+ /// @dev Decodes ERC721 Asset data.
+ /// @param assetData Encoded byte array.
+ /// @return proxyId Intended ERC721 proxy id.
+ /// @return token ERC721 token address.
+ /// @return tokenId ERC721 token id.
+ /// @return receiverData Additional data with no specific format, which
+ /// is passed to the receiving contract's onERC721Received.
+ function publicDecodeERC721Data(bytes memory assetData)
+ public
+ pure
+ returns (
+ uint8 proxyId,
+ address token,
+ uint256 tokenId,
+ bytes memory receiverData
+ )
+ {
+ (
+ proxyId,
+ token,
+ tokenId,
+ receiverData
+ ) = decodeERC721AssetData(assetData);
+
+ return (
+ proxyId,
+ token,
+ tokenId,
+ receiverData
+ );
+ }
+}
diff --git a/packages/contracts/src/contracts/current/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol b/packages/contracts/src/contracts/current/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol
index 11ca0617d..2ae69e0ef 100644
--- a/packages/contracts/src/contracts/current/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol
+++ b/packages/contracts/src/contracts/current/test/TestAssetProxyDispatcher/TestAssetProxyDispatcher.sol
@@ -23,12 +23,12 @@ import "../../protocol/Exchange/MixinAssetProxyDispatcher.sol";
contract TestAssetProxyDispatcher is MixinAssetProxyDispatcher {
function publicDispatchTransferFrom(
- bytes memory assetMetadata,
+ bytes memory assetData,
address from,
address to,
uint256 amount)
public
{
- dispatchTransferFrom(assetMetadata, from, to, amount);
+ dispatchTransferFrom(assetData, from, to, amount);
}
}
diff --git a/packages/contracts/src/contracts/current/test/TestLibBytes/TestLibBytes.sol b/packages/contracts/src/contracts/current/test/TestLibBytes/TestLibBytes.sol
index 69554605d..22c84504c 100644
--- a/packages/contracts/src/contracts/current/test/TestLibBytes/TestLibBytes.sol
+++ b/packages/contracts/src/contracts/current/test/TestLibBytes/TestLibBytes.sol
@@ -68,7 +68,8 @@ contract TestLibBytes is
/// @return address from byte array.
function publicReadAddress(
bytes memory b,
- uint256 index)
+ uint256 index
+ )
public
pure
returns (address result)
@@ -84,7 +85,8 @@ contract TestLibBytes is
function publicWriteAddress(
bytes memory b,
uint256 index,
- address input)
+ address input
+ )
public
pure
returns (bytes memory)
@@ -99,7 +101,8 @@ contract TestLibBytes is
/// @return bytes32 value from byte array.
function publicReadBytes32(
bytes memory b,
- uint256 index)
+ uint256 index
+ )
public
pure
returns (bytes32 result)
@@ -115,7 +118,8 @@ contract TestLibBytes is
function publicWriteBytes32(
bytes memory b,
uint256 index,
- bytes32 input)
+ bytes32 input
+ )
public
pure
returns (bytes memory)
@@ -130,7 +134,8 @@ contract TestLibBytes is
/// @return uint256 value from byte array.
function publicReadUint256(
bytes memory b,
- uint256 index)
+ uint256 index
+ )
public
pure
returns (uint256 result)
@@ -146,7 +151,8 @@ contract TestLibBytes is
function publicWriteUint256(
bytes memory b,
uint256 index,
- uint256 input)
+ uint256 input
+ )
public
pure
returns (bytes memory)
@@ -166,4 +172,38 @@ contract TestLibBytes is
result = readFirst4(b);
return result;
}
+
+ /// @dev Reads nested bytes from a specific position.
+ /// @param b Byte array containing nested bytes.
+ /// @param index Index of nested bytes.
+ /// @return result Nested bytes.
+ function publicReadBytes(
+ bytes memory b,
+ uint256 index
+ )
+ public
+ pure
+ returns (bytes memory result)
+ {
+ result = readBytes(b, index);
+ return result;
+ }
+
+ /// @dev Inserts bytes at a specific position in a byte array.
+ /// @param b Byte array to insert <input> into.
+ /// @param index Index in byte array of <input>.
+ /// @param input bytes to insert.
+ /// @return b Updated input byte array
+ function publicWriteBytes(
+ bytes memory b,
+ uint256 index,
+ bytes memory input
+ )
+ public
+ pure
+ returns (bytes memory)
+ {
+ writeBytes(b, index, input);
+ return b;
+ }
}
diff --git a/packages/contracts/src/contracts/current/test/TestLibMem/TestLibMem.sol b/packages/contracts/src/contracts/current/test/TestLibMem/TestLibMem.sol
new file mode 100644
index 000000000..b7e2e06b8
--- /dev/null
+++ b/packages/contracts/src/contracts/current/test/TestLibMem/TestLibMem.sol
@@ -0,0 +1,56 @@
+/*
+
+ 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 "../../utils/LibMem/LibMem.sol";
+
+contract TestLibMem is
+ LibMem
+{
+
+ /// @dev Copies a block of memory from one location to another.
+ /// @param mem Memory contents we want to apply memCopy to
+ /// @param dest Destination offset into <mem>.
+ /// @param source Source offset into <mem>.
+ /// @param length Length of bytes to copy from <source> to <dest>
+ /// @return mem Memory contents after calling memCopy.
+ function testMemcpy(
+ bytes mem,
+ uint256 dest,
+ uint256 source,
+ uint256 length
+ )
+ public // not external, we need input in memory
+ pure
+ returns (bytes)
+ {
+ // Sanity check. Overflows are not checked.
+ require(source + length <= mem.length);
+ require(dest + length <= mem.length);
+
+ // Get pointer to memory contents
+ uint256 offset = getMemAddress(mem) + 32;
+
+ // Execute memCopy adjusted for memory array location
+ memCopy(offset + dest, offset + source, length);
+
+ // Return modified memory contents
+ return mem;
+ }
+}
diff --git a/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol b/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol
index df2221c93..d1d10476f 100644
--- a/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol
+++ b/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol
@@ -18,14 +18,18 @@
pragma solidity ^0.4.24;
-contract LibBytes {
+import "../LibMem/LibMem.sol";
+
+contract LibBytes is
+ LibMem
+{
// Revert reasons
- string constant GT_ZERO_LENGTH_REQUIRED = "Length must be greater than 0.";
- string constant GTE_4_LENGTH_REQUIRED = "Length must be greater than or equal to 4.";
- string constant GTE_20_LENGTH_REQUIRED = "Length must be greater than or equal to 20.";
- string constant GTE_32_LENGTH_REQUIRED = "Length must be greater than or equal to 32.";
- string constant INDEX_OUT_OF_BOUNDS = "Specified array index is out of bounds.";
+ string constant GREATER_THAN_ZERO_LENGTH_REQUIRED = "GREATER_THAN_ZERO_LENGTH_REQUIRED";
+ string constant GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED";
+ string constant GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED";
+ string constant GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED";
+ string constant GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED";
/// @dev Pops the last byte off of a byte array by modifying its length.
/// @param b Byte array that will be modified.
@@ -37,12 +41,12 @@ contract LibBytes {
{
require(
b.length > 0,
- GT_ZERO_LENGTH_REQUIRED
+ GREATER_THAN_ZERO_LENGTH_REQUIRED
);
// Store last byte.
result = b[b.length - 1];
-
+
assembly {
// Decrement length of byte array.
let newLen := sub(mload(b), 1)
@@ -61,7 +65,7 @@ contract LibBytes {
{
require(
b.length >= 20,
- GTE_20_LENGTH_REQUIRED
+ GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED
);
// Store last 20 bytes.
@@ -124,8 +128,8 @@ contract LibBytes {
{
require(
b.length >= index + 20, // 20 is length of address
- GTE_20_LENGTH_REQUIRED
- );
+ GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED
+ );
// Add offset to index:
// 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
@@ -156,8 +160,8 @@ contract LibBytes {
{
require(
b.length >= index + 20, // 20 is length of address
- GTE_20_LENGTH_REQUIRED
- );
+ GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED
+ );
// Add offset to index:
// 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
@@ -195,7 +199,7 @@ contract LibBytes {
{
require(
b.length >= index + 32,
- GTE_32_LENGTH_REQUIRED
+ GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED
);
// Arrays are prefixed by a 256 bit length parameter
@@ -222,7 +226,7 @@ contract LibBytes {
{
require(
b.length >= index + 32,
- GTE_32_LENGTH_REQUIRED
+ GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED
);
// Arrays are prefixed by a 256 bit length parameter
@@ -274,11 +278,72 @@ contract LibBytes {
{
require(
b.length >= 4,
- GTE_4_LENGTH_REQUIRED
+ GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED
);
assembly {
result := mload(add(b, 32))
}
return result;
}
+
+ /// @dev Reads nested bytes from a specific position.
+ /// @param b Byte array containing nested bytes.
+ /// @param index Index of nested bytes.
+ /// @return result Nested bytes.
+ function readBytes(
+ bytes memory b,
+ uint256 index
+ )
+ internal
+ pure
+ returns (bytes memory result)
+ {
+ // Read length of nested bytes
+ uint256 nestedBytesLength = readUint256(b, index);
+ index += 32;
+
+ // Assert length of <b> is valid, given
+ // length of nested bytes
+ require(
+ b.length >= index + nestedBytesLength,
+ GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED
+ );
+
+ // Allocate memory and copy value to result
+ result = new bytes(nestedBytesLength);
+ memCopy(
+ getMemAddress(result) + 32, // +32 skips array length
+ getMemAddress(b) + index + 32,
+ nestedBytesLength
+ );
+
+ return result;
+ }
+
+ /// @dev Inserts bytes at a specific position in a byte array.
+ /// @param b Byte array to insert <input> into.
+ /// @param index Index in byte array of <input>.
+ /// @param input bytes to insert.
+ function writeBytes(
+ bytes memory b,
+ uint256 index,
+ bytes memory input
+ )
+ internal
+ pure
+ {
+ // Assert length of <b> is valid, given
+ // length of input
+ require(
+ b.length >= index + 32 /* 32 bytes to store length */ + input.length,
+ GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED
+ );
+
+ // Copy <input> into <b>
+ memCopy(
+ getMemAddress(b) + 32 + index, // +32 to skip length of <b>
+ getMemAddress(input), // includes length of <input>
+ input.length + 32 // +32 bytes to store <input> length
+ );
+ }
}
diff --git a/packages/contracts/src/contracts/current/utils/LibMem/LibMem.sol b/packages/contracts/src/contracts/current/utils/LibMem/LibMem.sol
new file mode 100644
index 000000000..6afb9973a
--- /dev/null
+++ b/packages/contracts/src/contracts/current/utils/LibMem/LibMem.sol
@@ -0,0 +1,140 @@
+/*
+
+ 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;
+
+contract LibMem
+{
+
+ /// @dev Gets the memory address for a byte array.
+ /// @param input Byte array to lookup.
+ /// @return memoryAddress Memory address of byte array.
+ function getMemAddress(bytes memory input)
+ internal
+ pure
+ returns (uint256 memoryAddress)
+ {
+ assembly {
+ memoryAddress := input
+ }
+ return memoryAddress;
+ }
+
+ /// @dev Copies `length` bytes from memory location `source` to `dest`.
+ /// @param dest memory address to copy bytes to.
+ /// @param source memory address to copy bytes from.
+ /// @param length number of bytes to copy.
+ function memCopy(
+ uint256 dest,
+ uint256 source,
+ uint256 length
+ )
+ internal
+ pure
+ {
+ if (length < 32) {
+ // Handle a partial word by reading destination and masking
+ // off the bits we are interested in.
+ // This correctly handles overlap, zero lengths and source == dest
+ assembly {
+ let mask := sub(exp(256, sub(32, length)), 1)
+ let s := and(mload(source), not(mask))
+ let d := and(mload(dest), mask)
+ mstore(dest, or(s, d))
+ }
+ } else {
+ // Skip the O(length) loop when source == dest.
+ if (source == dest) {
+ return;
+ }
+
+ // For large copies we copy whole words at a time. The final
+ // word is aligned to the end of the range (instead of after the
+ // previous) to handle partial words. So a copy will look like this:
+ //
+ // ####
+ // ####
+ // ####
+ // ####
+ //
+ // We handle overlap in the source and destination range by
+ // changing the copying direction. This prevents us from
+ // overwriting parts of source that we still need to copy.
+ //
+ // This correctly handles source == dest
+ //
+ if (source > dest) {
+ assembly {
+ // Record the total number of full words to copy
+ let nWords := div(length, 32)
+
+ // We subtract 32 from `sEnd` and `dEnd` because it
+ // is easier to compare with in the loop, and these
+ // are also the addresses we need for copying the
+ // last bytes.
+ length := sub(length, 32)
+ let sEnd := add(source, length)
+ let dEnd := add(dest, length)
+
+ // Remember the last 32 bytes of source
+ // This needs to be done here and not after the loop
+ // because we may have overwritten the last bytes in
+ // source already due to overlap.
+ let last := mload(sEnd)
+
+ // Copy whole words front to back
+ for {let i := 0} lt(i, nWords) {i := add(i, 1)} {
+ mstore(dest, mload(source))
+ source := add(source, 32)
+ dest := add(dest, 32)
+ }
+
+ // Write the last 32 bytes
+ mstore(dEnd, last)
+ }
+ } else {
+ assembly {
+ // Record the total number of full words to copy
+ let nWords := div(length, 32)
+
+ // We subtract 32 from `sEnd` and `dEnd` because those
+ // are the starting points when copying a word at the end.
+ length := sub(length, 32)
+ let sEnd := add(source, length)
+ let dEnd := add(dest, length)
+
+ // Remember the first 32 bytes of source
+ // This needs to be done here and not after the loop
+ // because we may have overwritten the first bytes in
+ // source already due to overlap.
+ let first := mload(source)
+
+ // Copy whole words back to front
+ for {let i := 0} lt(i, nWords) {i := add(i, 1)} {
+ mstore(dEnd, mload(sEnd))
+ sEnd := sub(sEnd, 32)
+ dEnd := sub(dEnd, 32)
+ }
+
+ // Write the first 32 bytes
+ mstore(dest, first)
+ }
+ }
+ }
+ }
+}
diff --git a/packages/contracts/src/utils/artifacts.ts b/packages/contracts/src/utils/artifacts.ts
index 357c66a0a..bf7221d6d 100644
--- a/packages/contracts/src/utils/artifacts.ts
+++ b/packages/contracts/src/utils/artifacts.ts
@@ -2,6 +2,7 @@ import { ContractArtifact } from '@0xproject/sol-compiler';
import * as AssetProxyOwner from '../artifacts/AssetProxyOwner.json';
import * as DummyERC20Token from '../artifacts/DummyERC20Token.json';
+import * as DummyERC721Receiver from '../artifacts/DummyERC721Receiver.json';
import * as DummyERC721Token from '../artifacts/DummyERC721Token.json';
import * as ERC20Proxy from '../artifacts/ERC20Proxy.json';
import * as ERC721Proxy from '../artifacts/ERC721Proxy.json';
@@ -9,8 +10,10 @@ import * as Exchange from '../artifacts/Exchange.json';
import * as MixinAuthorizable from '../artifacts/MixinAuthorizable.json';
import * as MultiSigWallet from '../artifacts/MultiSigWallet.json';
import * as MultiSigWalletWithTimeLock from '../artifacts/MultiSigWalletWithTimeLock.json';
+import * as TestAssetDataDecoders from '../artifacts/TestAssetDataDecoders.json';
import * as TestAssetProxyDispatcher from '../artifacts/TestAssetProxyDispatcher.json';
import * as TestLibBytes from '../artifacts/TestLibBytes.json';
+import * as TestLibMem from '../artifacts/TestLibMem.json';
import * as TestLibs from '../artifacts/TestLibs.json';
import * as TestSignatureValidator from '../artifacts/TestSignatureValidator.json';
import * as TokenRegistry from '../artifacts/TokenRegistry.json';
@@ -21,6 +24,7 @@ import * as ZRX from '../artifacts/ZRXToken.json';
export const artifacts = {
AssetProxyOwner: (AssetProxyOwner as any) as ContractArtifact,
DummyERC20Token: (DummyERC20Token as any) as ContractArtifact,
+ DummyERC721Receiver: (DummyERC721Receiver as any) as ContractArtifact,
DummyERC721Token: (DummyERC721Token as any) as ContractArtifact,
ERC20Proxy: (ERC20Proxy as any) as ContractArtifact,
ERC721Proxy: (ERC721Proxy as any) as ContractArtifact,
@@ -30,7 +34,9 @@ export const artifacts = {
MultiSigWallet: (MultiSigWallet as any) as ContractArtifact,
MultiSigWalletWithTimeLock: (MultiSigWalletWithTimeLock as any) as ContractArtifact,
TestAssetProxyDispatcher: (TestAssetProxyDispatcher as any) as ContractArtifact,
+ TestAssetDataDecoders: (TestAssetDataDecoders as any) as ContractArtifact,
TestLibBytes: (TestLibBytes as any) as ContractArtifact,
+ TestLibMem: (TestLibMem as any) as ContractArtifact,
TestLibs: (TestLibs as any) as ContractArtifact,
TestSignatureValidator: (TestSignatureValidator as any) as ContractArtifact,
TokenRegistry: (TokenRegistry as any) as ContractArtifact,
diff --git a/packages/contracts/src/utils/constants.ts b/packages/contracts/src/utils/constants.ts
index fa2a4af3c..af3f26d82 100644
--- a/packages/contracts/src/utils/constants.ts
+++ b/packages/contracts/src/utils/constants.ts
@@ -19,11 +19,11 @@ const TESTRPC_PRIVATE_KEYS_STRINGS = [
export const constants = {
INVALID_OPCODE: 'invalid opcode',
REVERT: 'revert',
- LIB_BYTES_GT_ZERO_LENGTH_REQUIRED: 'Length must be greater than 0.',
- LIB_BYTES_GTE_4_LENGTH_REQUIRED: 'Length must be greater than or equal to 4.',
- LIB_BYTES_GTE_20_LENGTH_REQUIRED: 'Length must be greater than or equal to 20.',
- LIB_BYTES_GTE_32_LENGTH_REQUIRED: 'Length must be greater than or equal to 32.',
- LIB_BYTES_INDEX_OUT_OF_BOUNDS: 'Specified array index is out of bounds.',
+ LIB_BYTES_GREATER_THAN_ZERO_LENGTH_REQUIRED: 'GREATER_THAN_ZERO_LENGTH_REQUIRED',
+ LIB_BYTES_GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED',
+ LIB_BYTES_GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED',
+ LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED',
+ LIB_BYTES_GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED',
ERC20_INSUFFICIENT_BALANCE: 'Insufficient balance to complete transfer.',
ERC20_INSUFFICIENT_ALLOWANCE: 'Insufficient allowance to complete transfer.',
TESTRPC_NETWORK_ID: 50,
diff --git a/packages/contracts/src/utils/match_order_tester.ts b/packages/contracts/src/utils/match_order_tester.ts
index f4f7f965b..fbb1b99db 100644
--- a/packages/contracts/src/utils/match_order_tester.ts
+++ b/packages/contracts/src/utils/match_order_tester.ts
@@ -237,11 +237,11 @@ export class MatchOrderTester {
const expectedNewERC20BalancesByOwner = _.cloneDeep(erc20BalancesByOwner);
const expectedNewERC721TokenIdsByOwner = _.cloneDeep(erc721TokenIdsByOwner);
// Left Maker Asset (Right Taker Asset)
- const makerAssetProxyIdLeft = assetProxyUtils.decodeProxyDataId(signedOrderLeft.makerAssetData);
+ const makerAssetProxyIdLeft = assetProxyUtils.decodeAssetDataId(signedOrderLeft.makerAssetData);
if (makerAssetProxyIdLeft === AssetProxyId.ERC20) {
// Decode asset data
- const erc20ProxyData = assetProxyUtils.decodeERC20ProxyData(signedOrderLeft.makerAssetData);
- const makerAssetAddressLeft = erc20ProxyData.tokenAddress;
+ const erc20AssetData = assetProxyUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData);
+ const makerAssetAddressLeft = erc20AssetData.tokenAddress;
const takerAssetAddressRight = makerAssetAddressLeft;
// Left Maker
expectedNewERC20BalancesByOwner[makerAddressLeft][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
@@ -259,9 +259,9 @@ export class MatchOrderTester {
][makerAssetAddressLeft].add(expectedTransferAmounts.amountReceivedByTaker);
} else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) {
// Decode asset data
- const erc721ProxyData = assetProxyUtils.decodeERC721ProxyData(signedOrderLeft.makerAssetData);
- const makerAssetAddressLeft = erc721ProxyData.tokenAddress;
- const makerAssetIdLeft = erc721ProxyData.tokenId;
+ const erc721AssetData = assetProxyUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData);
+ const makerAssetAddressLeft = erc721AssetData.tokenAddress;
+ const makerAssetIdLeft = erc721AssetData.tokenId;
const takerAssetAddressRight = makerAssetAddressLeft;
const takerAssetIdRight = makerAssetIdLeft;
// Left Maker
@@ -272,11 +272,11 @@ export class MatchOrderTester {
}
// Left Taker Asset (Right Maker Asset)
// Note: This exchange is only between the order makers: the Taker does not receive any of the left taker asset.
- const takerAssetProxyIdLeft = assetProxyUtils.decodeProxyDataId(signedOrderLeft.takerAssetData);
+ const takerAssetProxyIdLeft = assetProxyUtils.decodeAssetDataId(signedOrderLeft.takerAssetData);
if (takerAssetProxyIdLeft === AssetProxyId.ERC20) {
// Decode asset data
- const erc20ProxyData = assetProxyUtils.decodeERC20ProxyData(signedOrderLeft.takerAssetData);
- const takerAssetAddressLeft = erc20ProxyData.tokenAddress;
+ const erc20AssetData = assetProxyUtils.decodeERC20AssetData(signedOrderLeft.takerAssetData);
+ const takerAssetAddressLeft = erc20AssetData.tokenAddress;
const makerAssetAddressRight = takerAssetAddressLeft;
// Left Maker
expectedNewERC20BalancesByOwner[makerAddressLeft][takerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
@@ -290,9 +290,9 @@ export class MatchOrderTester {
);
} else if (takerAssetProxyIdLeft === AssetProxyId.ERC721) {
// Decode asset data
- const erc721ProxyData = assetProxyUtils.decodeERC721ProxyData(signedOrderRight.makerAssetData);
- const makerAssetAddressRight = erc721ProxyData.tokenAddress;
- const makerAssetIdRight = erc721ProxyData.tokenId;
+ const erc721AssetData = assetProxyUtils.decodeERC721AssetData(signedOrderRight.makerAssetData);
+ const makerAssetAddressRight = erc721AssetData.tokenAddress;
+ const makerAssetIdRight = erc721AssetData.tokenId;
const takerAssetAddressLeft = makerAssetAddressRight;
const takerAssetIdLeft = makerAssetIdRight;
// Right Maker
diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts
index 491890fa1..bb8c12088 100644
--- a/packages/contracts/src/utils/types.ts
+++ b/packages/contracts/src/utils/types.ts
@@ -90,11 +90,14 @@ export enum ContractName {
AccountLevels = 'AccountLevels',
EtherDelta = 'EtherDelta',
Arbitrage = 'Arbitrage',
+ TestAssetDataDecoders = 'TestAssetDataDecoders',
TestAssetProxyDispatcher = 'TestAssetProxyDispatcher',
+ TestLibMem = 'TestLibMem',
TestLibs = 'TestLibs',
TestSignatureValidator = 'TestSignatureValidator',
ERC20Proxy = 'ERC20Proxy',
ERC721Proxy = 'ERC721Proxy',
+ DummyERC721Receiver = 'DummyERC721Receiver',
DummyERC721Token = 'DummyERC721Token',
TestLibBytes = 'TestLibBytes',
Authorizable = 'Authorizable',