Remove redundant files, hard code function selector in dispatchTransferFrom, and modify revert reason
This commit is contained in:
		@@ -32,7 +32,6 @@
 | 
				
			|||||||
        "MultiSigWallet",
 | 
					        "MultiSigWallet",
 | 
				
			||||||
        "MultiSigWalletWithTimeLock",
 | 
					        "MultiSigWalletWithTimeLock",
 | 
				
			||||||
        "TestAssetProxyOwner",
 | 
					        "TestAssetProxyOwner",
 | 
				
			||||||
        "TestAssetDataDecoders",
 | 
					 | 
				
			||||||
        "TestAssetProxyDispatcher",
 | 
					        "TestAssetProxyDispatcher",
 | 
				
			||||||
        "TestLibBytes",
 | 
					        "TestLibBytes",
 | 
				
			||||||
        "TestLibs",
 | 
					        "TestLibs",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,8 @@
 | 
				
			|||||||
        "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
 | 
					        "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
 | 
				
			||||||
        "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
 | 
					        "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
 | 
				
			||||||
        "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
 | 
					        "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
 | 
				
			||||||
        "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
 | 
					        "run_mocha":
 | 
				
			||||||
 | 
					            "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
 | 
				
			||||||
        "compile": "sol-compiler",
 | 
					        "compile": "sol-compiler",
 | 
				
			||||||
        "clean": "shx rm -rf lib src/generated_contract_wrappers",
 | 
					        "clean": "shx rm -rf lib src/generated_contract_wrappers",
 | 
				
			||||||
        "generate_contract_wrappers":
 | 
					        "generate_contract_wrappers":
 | 
				
			||||||
@@ -34,7 +35,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "config": {
 | 
					    "config": {
 | 
				
			||||||
        "abis":
 | 
					        "abis":
 | 
				
			||||||
            "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|ExchangeWrapper|IAssetData|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetProxyOwner|TestAssetDataDecoders|TestAssetProxyDispatcher|TestLibBytes|TestLibs|TestSignatureValidator|TestValidator|TestWallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
 | 
					            "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|ExchangeWrapper|IAssetData|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetProxyOwner|TestAssetProxyDispatcher|TestLibBytes|TestLibs|TestSignatureValidator|TestValidator|TestWallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "repository": {
 | 
					    "repository": {
 | 
				
			||||||
        "type": "git",
 | 
					        "type": "git",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,28 +20,16 @@ pragma solidity ^0.4.24;
 | 
				
			|||||||
pragma experimental ABIEncoderV2;
 | 
					pragma experimental ABIEncoderV2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "../../utils/LibBytes/LibBytes.sol";
 | 
					import "../../utils/LibBytes/LibBytes.sol";
 | 
				
			||||||
import "./MixinAssetProxy.sol";
 | 
					import "./interfaces/IAssetProxy.sol";
 | 
				
			||||||
import "./MixinAuthorizable.sol";
 | 
					import "./MixinAuthorizable.sol";
 | 
				
			||||||
import "./MixinERC20Transfer.sol";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
contract ERC20Proxy is
 | 
					contract ERC20Proxy is
 | 
				
			||||||
    MixinAssetProxy,
 | 
					    IAssetProxy,
 | 
				
			||||||
    MixinAuthorizable,
 | 
					    MixinAuthorizable
 | 
				
			||||||
    MixinERC20Transfer
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Id of this proxy.
 | 
					    // Id of this proxy.
 | 
				
			||||||
    bytes4 constant PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
 | 
					    bytes4 constant PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    /// @dev Gets the proxy id associated with the proxy address.
 | 
					 | 
				
			||||||
    /// @return Proxy id.
 | 
					 | 
				
			||||||
    function getProxyId()
 | 
					 | 
				
			||||||
        external
 | 
					 | 
				
			||||||
        view
 | 
					 | 
				
			||||||
        returns (bytes4)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return PROXY_ID;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /// @dev Internal version of `transferFrom`.
 | 
					    /// @dev Internal version of `transferFrom`.
 | 
				
			||||||
    /// @param assetData Encoded byte array.
 | 
					    /// @param assetData Encoded byte array.
 | 
				
			||||||
    /// @param from Address to transfer asset from.
 | 
					    /// @param from Address to transfer asset from.
 | 
				
			||||||
@@ -55,6 +43,11 @@ contract ERC20Proxy is
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
        external
 | 
					        external
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        require(
 | 
				
			||||||
 | 
					            authorized[msg.sender],
 | 
				
			||||||
 | 
					            "SENDER_NOT_AUTHORIZED"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // `transferFrom`.
 | 
					        // `transferFrom`.
 | 
				
			||||||
        // The function is marked `external`, so no abi decodeding is done for
 | 
					        // The function is marked `external`, so no abi decodeding is done for
 | 
				
			||||||
        // us. Instead, we expect the `calldata` memory to contain the
 | 
					        // us. Instead, we expect the `calldata` memory to contain the
 | 
				
			||||||
@@ -102,15 +95,6 @@ contract ERC20Proxy is
 | 
				
			|||||||
        // |          | 68     |         |   3. amount                         |
 | 
					        // |          | 68     |         |   3. amount                         |
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        assembly {
 | 
					        assembly {
 | 
				
			||||||
            if iszero(sload(caller)) {
 | 
					 | 
				
			||||||
                // Revert with `Error("SENDER_NOT_AUTHORIZED")`
 | 
					 | 
				
			||||||
                mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
					 | 
				
			||||||
                mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
					 | 
				
			||||||
                mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000)
 | 
					 | 
				
			||||||
                mstore(96, 0)
 | 
					 | 
				
			||||||
                revert(0, 100)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            /////// Token contract address ///////
 | 
					            /////// Token contract address ///////
 | 
				
			||||||
            // The token address is found as follows:
 | 
					            // The token address is found as follows:
 | 
				
			||||||
            // * It is stored at offset 4 in `assetData` contents.
 | 
					            // * It is stored at offset 4 in `assetData` contents.
 | 
				
			||||||
@@ -170,4 +154,14 @@ contract ERC20Proxy is
 | 
				
			|||||||
            revert(0, 100)
 | 
					            revert(0, 100)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Gets the proxy id associated with the proxy address.
 | 
				
			||||||
 | 
					    /// @return Proxy id.
 | 
				
			||||||
 | 
					    function getProxyId()
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					        view
 | 
				
			||||||
 | 
					        returns (bytes4)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return PROXY_ID;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,18 +20,181 @@ pragma solidity ^0.4.24;
 | 
				
			|||||||
pragma experimental ABIEncoderV2;
 | 
					pragma experimental ABIEncoderV2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "../../utils/LibBytes/LibBytes.sol";
 | 
					import "../../utils/LibBytes/LibBytes.sol";
 | 
				
			||||||
import "./MixinAssetProxy.sol";
 | 
					import "./interfaces/IAssetProxy.sol";
 | 
				
			||||||
import "./MixinAuthorizable.sol";
 | 
					import "./MixinAuthorizable.sol";
 | 
				
			||||||
import "./MixinERC721Transfer.sol";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
contract ERC721Proxy is
 | 
					contract ERC721Proxy is
 | 
				
			||||||
    MixinAssetProxy,
 | 
					    IAssetProxy,
 | 
				
			||||||
    MixinAuthorizable,
 | 
					    MixinAuthorizable
 | 
				
			||||||
    MixinERC721Transfer
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Id of this proxy.
 | 
					    // Id of this proxy.
 | 
				
			||||||
    bytes4 constant PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256,bytes)"));
 | 
					    bytes4 constant PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256,bytes)"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// @dev Internal version of `transferFrom`.
 | 
				
			||||||
 | 
					    /// @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 assetData,
 | 
				
			||||||
 | 
					        address from,
 | 
				
			||||||
 | 
					        address to,
 | 
				
			||||||
 | 
					        uint256 amount
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        external
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        require(
 | 
				
			||||||
 | 
					            authorized[msg.sender],
 | 
				
			||||||
 | 
					            "SENDER_NOT_AUTHORIZED"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        // `transferFrom`.
 | 
				
			||||||
 | 
					        // The function is marked `external`, so no abi decodeding is done for
 | 
				
			||||||
 | 
					        // us. Instead, we expect the `calldata` memory to contain the
 | 
				
			||||||
 | 
					        // following:
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // | Area     | Offset | Length  | Contents                            |
 | 
				
			||||||
 | 
					        // |----------|--------|---------|-------------------------------------|
 | 
				
			||||||
 | 
					        // | Header   | 0      | 4       | function selector                   |
 | 
				
			||||||
 | 
					        // | Params   |        | 4 * 32  | function parameters:                |
 | 
				
			||||||
 | 
					        // |          | 4      |         |   1. offset to assetData (*)        |
 | 
				
			||||||
 | 
					        // |          | 36     |         |   2. from                           |
 | 
				
			||||||
 | 
					        // |          | 68     |         |   3. to                             |
 | 
				
			||||||
 | 
					        // |          | 100    |         |   4. amount                         |
 | 
				
			||||||
 | 
					        // | Data     |        |         | assetData:                          |
 | 
				
			||||||
 | 
					        // |          | 132    | 32      | assetData Length                    |
 | 
				
			||||||
 | 
					        // |          | 164    | **      | assetData Contents                  |
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // (*): offset is computed from start of function parameters, so offset
 | 
				
			||||||
 | 
					        //      by an additional 4 bytes in the calldata.
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // 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:                |
 | 
				
			||||||
 | 
					        // |          | 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.
 | 
				
			||||||
 | 
					        // The layout of this calldata is in the table below.
 | 
				
			||||||
 | 
					        // 
 | 
				
			||||||
 | 
					        // | Area     | Offset | Length  | Contents                            |
 | 
				
			||||||
 | 
					        // |----------|--------|---------|-------------------------------------|
 | 
				
			||||||
 | 
					        // | Header   | 0      | 4       | function selector                   |
 | 
				
			||||||
 | 
					        // | Params   |        | 4 * 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               |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assembly {
 | 
				
			||||||
 | 
					            // There exists only 1 of each token.
 | 
				
			||||||
 | 
					            // require(amount == 1, "INVALID_AMOUNT")
 | 
				
			||||||
 | 
					            if sub(calldataload(100), 1) {
 | 
				
			||||||
 | 
					                // Revert with `Error("INVALID_AMOUNT")`
 | 
				
			||||||
 | 
					                mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
				
			||||||
 | 
					                mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
				
			||||||
 | 
					                mstore(64, 0x0000000e494e56414c49445f414d4f554e540000000000000000000000000000)
 | 
				
			||||||
 | 
					                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`.
 | 
				
			||||||
 | 
					            // Any trailing data in transferFromSelector will be
 | 
				
			||||||
 | 
					            // overwritten in the next `mstore` call.
 | 
				
			||||||
 | 
					            mstore(cdStart, 0xb88d4fde00000000000000000000000000000000000000000000000000000000)
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            /////// 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 ///////
 | 
				
			||||||
 | 
					            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
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            if success {
 | 
				
			||||||
 | 
					                return(0, 0)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // Revert with `Error("TRANSFER_FAILED")`
 | 
				
			||||||
 | 
					            mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
				
			||||||
 | 
					            mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
				
			||||||
 | 
					            mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
 | 
				
			||||||
 | 
					            mstore(96, 0)
 | 
				
			||||||
 | 
					            revert(0, 100)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// @dev Gets the proxy id associated with the proxy address.
 | 
					    /// @dev Gets the proxy id associated with the proxy address.
 | 
				
			||||||
    /// @return Proxy id.
 | 
					    /// @return Proxy id.
 | 
				
			||||||
    function getProxyId()
 | 
					    function getProxyId()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,75 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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 "./mixins/MAuthorizable.sol";
 | 
					 | 
				
			||||||
import "./mixins/MAssetProxy.sol";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
contract MixinAssetProxy is
 | 
					 | 
				
			||||||
    MAuthorizable,
 | 
					 | 
				
			||||||
    MAssetProxy
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// @dev Transfers assets. Either succeeds or throws.
 | 
					 | 
				
			||||||
    /// @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 assetData,
 | 
					 | 
				
			||||||
        address from,
 | 
					 | 
				
			||||||
        address to,
 | 
					 | 
				
			||||||
        uint256 amount
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
        external
 | 
					 | 
				
			||||||
        onlyAuthorized
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        transferFromInternal(
 | 
					 | 
				
			||||||
            assetData,
 | 
					 | 
				
			||||||
            from,
 | 
					 | 
				
			||||||
            to,
 | 
					 | 
				
			||||||
            amount
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// @dev Makes multiple transfers of assets. Either succeeds or throws.
 | 
					 | 
				
			||||||
    /// @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 assetData,
 | 
					 | 
				
			||||||
        address[] memory from,
 | 
					 | 
				
			||||||
        address[] memory to,
 | 
					 | 
				
			||||||
        uint256[] memory amounts
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
        public
 | 
					 | 
				
			||||||
        onlyAuthorized
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        for (uint256 i = 0; i < assetData.length; i++) {
 | 
					 | 
				
			||||||
            transferFromInternal(
 | 
					 | 
				
			||||||
                assetData[i],
 | 
					 | 
				
			||||||
                from[i],
 | 
					 | 
				
			||||||
                to[i],
 | 
					 | 
				
			||||||
                amounts[i]
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -49,10 +49,6 @@ contract MixinAuthorizable is
 | 
				
			|||||||
            !authorized[target],
 | 
					            !authorized[target],
 | 
				
			||||||
            "TARGET_ALREADY_AUTHORIZED"
 | 
					            "TARGET_ALREADY_AUTHORIZED"
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        assembly {
 | 
					 | 
				
			||||||
            sstore(target, 1)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        authorized[target] = true;
 | 
					        authorized[target] = true;
 | 
				
			||||||
        authorities.push(target);
 | 
					        authorities.push(target);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,115 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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 "./mixins/MAuthorizable.sol";
 | 
					 | 
				
			||||||
import "../../utils/LibBytes/LibBytes.sol";
 | 
					 | 
				
			||||||
import "../../tokens/ERC20Token/IERC20Token.sol";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
contract MixinERC20Transfer is
 | 
					 | 
				
			||||||
    MAuthorizable
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    using LibBytes for bytes;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /// @dev Internal version of `transferFrom`.
 | 
					 | 
				
			||||||
    /// @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 assetData,
 | 
					 | 
				
			||||||
        address from,
 | 
					 | 
				
			||||||
        address to,
 | 
					 | 
				
			||||||
        uint256 amount
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
        internal
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // Decode asset data.
 | 
					 | 
				
			||||||
        address token = assetData.readAddress(16);
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        // Transfer tokens.
 | 
					 | 
				
			||||||
        // We do a raw call so we can check the success separate
 | 
					 | 
				
			||||||
        // from the return data.
 | 
					 | 
				
			||||||
        // 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   |        | 3 * 32  | function parameters:                |
 | 
					 | 
				
			||||||
        // |          | 4      |         |   1. from                           |
 | 
					 | 
				
			||||||
        // |          | 36     |         |   2. to                             |
 | 
					 | 
				
			||||||
        // |          | 68     |         |   3. amount                         |
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        bytes4 transferFromSelector = IERC20Token(token).transferFrom.selector;
 | 
					 | 
				
			||||||
        bool success;
 | 
					 | 
				
			||||||
        assembly {
 | 
					 | 
				
			||||||
            /////// Setup State ///////
 | 
					 | 
				
			||||||
            // `cdStart` is the start of the calldata for `token.transferFrom` (equal to free memory ptr).
 | 
					 | 
				
			||||||
            let cdStart := mload(64)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /////// Setup Header Area ///////
 | 
					 | 
				
			||||||
            // This area holds the 4-byte `transferFromSelector`.
 | 
					 | 
				
			||||||
            // Any trailing data in transferFromSelector will be
 | 
					 | 
				
			||||||
            // overwritten in the next `mstore` call.
 | 
					 | 
				
			||||||
            mstore(cdStart, transferFromSelector)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /////// Setup Params Area ///////
 | 
					 | 
				
			||||||
            // Each parameter is padded to 32-bytes.
 | 
					 | 
				
			||||||
            // The entire Params Area is 96 bytes.
 | 
					 | 
				
			||||||
            // A 20-byte mask is applied to addresses to
 | 
					 | 
				
			||||||
            // zero-out the unused bytes.
 | 
					 | 
				
			||||||
            mstore(add(cdStart, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
 | 
					 | 
				
			||||||
            mstore(add(cdStart, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
 | 
					 | 
				
			||||||
            mstore(add(cdStart, 68), amount)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /////// Call `token.transferFrom` using the calldata ///////
 | 
					 | 
				
			||||||
            success := call(
 | 
					 | 
				
			||||||
                gas,            // forward all gas
 | 
					 | 
				
			||||||
                token,          // call address of token contract
 | 
					 | 
				
			||||||
                0,              // don't send any ETH
 | 
					 | 
				
			||||||
                cdStart,        // pointer to start of input
 | 
					 | 
				
			||||||
                100,            // length of input
 | 
					 | 
				
			||||||
                cdStart,        // write output over input
 | 
					 | 
				
			||||||
                32              // output size should be 32 bytes
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /////// Check return data. ///////
 | 
					 | 
				
			||||||
            // If there is no return data, we assume the token incorrectly
 | 
					 | 
				
			||||||
            // does not return a bool. In this case we expect it to revert
 | 
					 | 
				
			||||||
            // on failure, which was handled above.
 | 
					 | 
				
			||||||
            // If the token does return data, we require that it is a single
 | 
					 | 
				
			||||||
            // nonzero 32 bytes value.
 | 
					 | 
				
			||||||
            // So the transfer succeeded if the call succeeded and either
 | 
					 | 
				
			||||||
            // returned nothing, or returned a non-zero 32 byte value. 
 | 
					 | 
				
			||||||
            success := and(success, or(
 | 
					 | 
				
			||||||
                iszero(returndatasize),
 | 
					 | 
				
			||||||
                and(
 | 
					 | 
				
			||||||
                    eq(returndatasize, 32),
 | 
					 | 
				
			||||||
                    gt(mload(cdStart), 0)
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            ))
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        require(
 | 
					 | 
				
			||||||
            success,
 | 
					 | 
				
			||||||
            "TRANSFER_FAILED"
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,331 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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 "./mixins/MAuthorizable.sol";
 | 
					 | 
				
			||||||
import "../../utils/LibBytes/LibBytes.sol";
 | 
					 | 
				
			||||||
import "./libs/LibTransferErrors.sol";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
contract MixinERC721Transfer is
 | 
					 | 
				
			||||||
    LibTransferErrors,
 | 
					 | 
				
			||||||
    MAuthorizable
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    using LibBytes for bytes;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    bytes4 constant SAFE_TRANSFER_FROM_SELECTOR = bytes4(keccak256("safeTransferFrom(address,address,uint256,bytes)"));
 | 
					 | 
				
			||||||
    /// @dev Internal version of `transferFrom`.
 | 
					 | 
				
			||||||
    /// @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 assetData,
 | 
					 | 
				
			||||||
        address from,
 | 
					 | 
				
			||||||
        address to,
 | 
					 | 
				
			||||||
        uint256 amount
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
        external
 | 
					 | 
				
			||||||
        onlyAuthorized()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // `transferFrom`.
 | 
					 | 
				
			||||||
        // The function is marked `external`, so no abi decodeding is done for
 | 
					 | 
				
			||||||
        // us. Instead, we expect the `calldata` memory to contain the
 | 
					 | 
				
			||||||
        // following:
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        // | Area     | Offset | Length  | Contents                            |
 | 
					 | 
				
			||||||
        // |----------|--------|---------|-------------------------------------|
 | 
					 | 
				
			||||||
        // | Header   | 0      | 4       | function selector                   |
 | 
					 | 
				
			||||||
        // | Params   |        | 4 * 32  | function parameters:                |
 | 
					 | 
				
			||||||
        // |          | 4      |         |   1. offset to assetData (*)        |
 | 
					 | 
				
			||||||
        // |          | 36     |         |   2. from                           |
 | 
					 | 
				
			||||||
        // |          | 68     |         |   3. to                             |
 | 
					 | 
				
			||||||
        // |          | 100    |         |   4. amount                         |
 | 
					 | 
				
			||||||
        // | Data     |        |         | assetData:                          |
 | 
					 | 
				
			||||||
        // |          | 132    | 32      | assetData Length                    |
 | 
					 | 
				
			||||||
        // |          | 164    | **      | assetData Contents                  |
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        // (*): offset is computed from start of function parameters, so offset
 | 
					 | 
				
			||||||
        //      by an additional 4 bytes in the calldata.
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        // 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:                |
 | 
					 | 
				
			||||||
        // |          | 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.
 | 
					 | 
				
			||||||
        // The layout of this calldata is in the table below.
 | 
					 | 
				
			||||||
        // 
 | 
					 | 
				
			||||||
        // | Area     | Offset | Length  | Contents                            |
 | 
					 | 
				
			||||||
        // |----------|--------|---------|-------------------------------------|
 | 
					 | 
				
			||||||
        // | Header   | 0      | 4       | function selector                   |
 | 
					 | 
				
			||||||
        // | Params   |        | 4 * 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               |
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // bytes4 safeTransferFromSelector = SAFE_TRANSFER_FROM_SELECTOR;
 | 
					 | 
				
			||||||
        // bool success;
 | 
					 | 
				
			||||||
        assembly {
 | 
					 | 
				
			||||||
            // There exists only 1 of each token.
 | 
					 | 
				
			||||||
            // require(amount == 1, "INVALID_AMOUNT")
 | 
					 | 
				
			||||||
            if sub(calldataload(100), 1) {
 | 
					 | 
				
			||||||
                // Revert with `Error("INVALID_AMOUNT")`
 | 
					 | 
				
			||||||
                mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
					 | 
				
			||||||
                mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
					 | 
				
			||||||
                mstore(64, 0x0000000e494e56414c49445f414d4f554e540000000000000000000000000000)
 | 
					 | 
				
			||||||
                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("ASSET_DATA_TO_SHORT")`
 | 
					 | 
				
			||||||
                mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
					 | 
				
			||||||
                mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
					 | 
				
			||||||
                mstore(64, 0x0000001341535345545f444154415f544f5f53484f5254000000000000000000)
 | 
					 | 
				
			||||||
                mstore(96, 0)
 | 
					 | 
				
			||||||
                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`.
 | 
					 | 
				
			||||||
            // Any trailing data in transferFromSelector will be
 | 
					 | 
				
			||||||
            // overwritten in the next `mstore` call.
 | 
					 | 
				
			||||||
            mstore(cdStart, 0xb88d4fde00000000000000000000000000000000000000000000000000000000)
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            /////// 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 ///////
 | 
					 | 
				
			||||||
            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
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            if success {
 | 
					 | 
				
			||||||
                return(0, 0)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            // Revert with `Error("TRANSFER_FAILED")`
 | 
					 | 
				
			||||||
            mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
					 | 
				
			||||||
            mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
					 | 
				
			||||||
            mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
 | 
					 | 
				
			||||||
            mstore(96, 0)
 | 
					 | 
				
			||||||
            revert(0, 100)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// @dev Internal version of `transferFrom`.
 | 
					 | 
				
			||||||
    /// @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 assetData,
 | 
					 | 
				
			||||||
        address from,
 | 
					 | 
				
			||||||
        address to,
 | 
					 | 
				
			||||||
        uint256 amount
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
        internal
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // There exists only 1 of each token.
 | 
					 | 
				
			||||||
        require(
 | 
					 | 
				
			||||||
            amount == 1,
 | 
					 | 
				
			||||||
            INVALID_AMOUNT
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
        // Decode asset data.
 | 
					 | 
				
			||||||
        (
 | 
					 | 
				
			||||||
            address token,
 | 
					 | 
				
			||||||
            uint256 tokenId,
 | 
					 | 
				
			||||||
            bytes memory receiverData
 | 
					 | 
				
			||||||
        ) = decodeERC721AssetData(assetData);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // We construct calldata for the `token.safeTransferFrom` 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:                |
 | 
					 | 
				
			||||||
        // |          | 4      |         |   1. from                           |
 | 
					 | 
				
			||||||
        // |          | 36     |         |   2. to                             |
 | 
					 | 
				
			||||||
        // |          | 68     |         |   3. tokenId                        |
 | 
					 | 
				
			||||||
        // |          | 100    |         |   4. offset to receiverData (*)     |
 | 
					 | 
				
			||||||
        // | Data     |        |         | receiverData:                       |
 | 
					 | 
				
			||||||
        // |          | 132    | 32      | receiverData Length                 |
 | 
					 | 
				
			||||||
        // |          | 164    | **      | receiverData Contents               |
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bytes4 safeTransferFromSelector = SAFE_TRANSFER_FROM_SELECTOR;
 | 
					 | 
				
			||||||
        bool success;
 | 
					 | 
				
			||||||
        assembly {
 | 
					 | 
				
			||||||
            /////// 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.
 | 
					 | 
				
			||||||
            let dataAreaLength := and(add(mload(receiverData), 63), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0)
 | 
					 | 
				
			||||||
            // `cdEnd` is the end of the calldata for `token.safeTransferFrom`.
 | 
					 | 
				
			||||||
            let cdEnd := add(cdStart, add(132, dataAreaLength))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /////// Setup Header Area ///////
 | 
					 | 
				
			||||||
            // This area holds the 4-byte `transferFromSelector`.
 | 
					 | 
				
			||||||
            // Any trailing data in transferFromSelector will be
 | 
					 | 
				
			||||||
            // overwritten in the next `mstore` call.
 | 
					 | 
				
			||||||
            mstore(cdStart, safeTransferFromSelector)
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            /////// 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).
 | 
					 | 
				
			||||||
            mstore(add(cdStart, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
 | 
					 | 
				
			||||||
            mstore(add(cdStart, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
 | 
					 | 
				
			||||||
            mstore(add(cdStart, 68), tokenId)
 | 
					 | 
				
			||||||
            mstore(add(cdStart, 100), 128)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /////// Setup Data Area ///////
 | 
					 | 
				
			||||||
            // This area holds `receiverData`.
 | 
					 | 
				
			||||||
            let dataArea := add(cdStart, 132)
 | 
					 | 
				
			||||||
            for {} lt(dataArea, cdEnd) {} {
 | 
					 | 
				
			||||||
                mstore(dataArea, mload(receiverData))
 | 
					 | 
				
			||||||
                dataArea := add(dataArea, 32)
 | 
					 | 
				
			||||||
                receiverData := add(receiverData, 32)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            /////// Call `token.safeTransferFrom` using the calldata ///////
 | 
					 | 
				
			||||||
            success := call(
 | 
					 | 
				
			||||||
                gas,                    // forward all gas
 | 
					 | 
				
			||||||
                token,                  // call address of token contract
 | 
					 | 
				
			||||||
                0,                      // don't send any ETH
 | 
					 | 
				
			||||||
                cdStart,                // pointer to start of input
 | 
					 | 
				
			||||||
                sub(cdEnd, cdStart),    // length of input
 | 
					 | 
				
			||||||
                cdStart,                // write output over input
 | 
					 | 
				
			||||||
                0                       // output size is 0 bytes
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        require(
 | 
					 | 
				
			||||||
            success,
 | 
					 | 
				
			||||||
            TRANSFER_FAILED
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// @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 (
 | 
					 | 
				
			||||||
            address token,
 | 
					 | 
				
			||||||
            uint256 tokenId,
 | 
					 | 
				
			||||||
            bytes memory receiverData
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // Decode asset data.
 | 
					 | 
				
			||||||
        token = assetData.readAddress(16);
 | 
					 | 
				
			||||||
        tokenId = assetData.readUint256(36);
 | 
					 | 
				
			||||||
        receiverData = assetData.readBytesWithLength(100);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return (
 | 
					 | 
				
			||||||
            token,
 | 
					 | 
				
			||||||
            tokenId,
 | 
					 | 
				
			||||||
            receiverData
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -38,19 +38,6 @@ contract IAssetProxy is
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
        external;
 | 
					        external;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    /// @dev Makes multiple transfers of assets. Either succeeds or throws.
 | 
					 | 
				
			||||||
    /// @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 assetData,
 | 
					 | 
				
			||||||
        address[] memory from,
 | 
					 | 
				
			||||||
        address[] memory to,
 | 
					 | 
				
			||||||
        uint256[] memory amounts
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
        public;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// @dev Gets the proxy id associated with the proxy address.
 | 
					    /// @dev Gets the proxy id associated with the proxy address.
 | 
				
			||||||
    /// @return Proxy id.
 | 
					    /// @return Proxy id.
 | 
				
			||||||
    function getProxyId()
 | 
					    function getProxyId()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,9 +23,14 @@ pragma solidity ^0.4.24;
 | 
				
			|||||||
contract LibAssetProxyErrors {
 | 
					contract LibAssetProxyErrors {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Authorizable errors ///
 | 
					    /// Authorizable errors ///
 | 
				
			||||||
    string constant SENDER_NOT_AUTHORIZED = "SENDER_NOT_AUTHORIZED";              // Sender not authorized to call this method.
 | 
					    string constant SENDER_NOT_AUTHORIZED = "SENDER_NOT_AUTHORIZED";                        // Sender not authorized to call this method.
 | 
				
			||||||
    string constant TARGET_NOT_AUTHORIZED = "TARGET_NOT_AUTHORIZED";              // Target address not authorized to call this method.
 | 
					    string constant TARGET_NOT_AUTHORIZED = "TARGET_NOT_AUTHORIZED";                        // Target address not authorized to call this method.
 | 
				
			||||||
    string constant TARGET_ALREADY_AUTHORIZED = "TARGET_ALREADY_AUTHORIZED";      // Target address must not already be authorized.
 | 
					    string constant TARGET_ALREADY_AUTHORIZED = "TARGET_ALREADY_AUTHORIZED";                // Target address must not already be authorized.
 | 
				
			||||||
    string constant INDEX_OUT_OF_BOUNDS = "INDEX_OUT_OF_BOUNDS";                  // Specified array index is out of bounds.
 | 
					    string constant INDEX_OUT_OF_BOUNDS = "INDEX_OUT_OF_BOUNDS";                            // Specified array index is out of bounds.
 | 
				
			||||||
    string constant AUTHORIZED_ADDRESS_MISMATCH = "AUTHORIZED_ADDRESS_MISMATCH";  // Address at index does not match given target address.
 | 
					    string constant AUTHORIZED_ADDRESS_MISMATCH = "AUTHORIZED_ADDRESS_MISMATCH";            // Address at index does not match given target address.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Transfer errors ///
 | 
				
			||||||
 | 
					    string constant INVALID_AMOUNT = "INVALID_AMOUNT";                                      // Transfer amount must equal 1.
 | 
				
			||||||
 | 
					    string constant TRANSFER_FAILED = "TRANSFER_FAILED";                                    // Transfer failed.
 | 
				
			||||||
 | 
					    string constant LENGTH_GREATER_THAN_131_REQUIRED = "LENGTH_GREATER_THAN_131_REQUIRED";  // Byte array must have a length greater than 0.
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,29 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// @dev This contract documents the revert reasons used in the `transferFrom` methods of different AssetProxy contracts.
 | 
					 | 
				
			||||||
/// This contract is intended to serve as a reference, but is not actually used for efficiency reasons.
 | 
					 | 
				
			||||||
contract LibTransferErrors {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Transfer errors ///
 | 
					 | 
				
			||||||
    string constant INVALID_AMOUNT = "INVALID_AMOUNT";                            // Transfer amount must equal 1.
 | 
					 | 
				
			||||||
    string constant TRANSFER_FAILED = "TRANSFER_FAILED";                          // Transfer failed.
 | 
					 | 
				
			||||||
    string constant ASSET_DATA_TO_SHORT = "ASSET_DATA_TO_SHORT";                      // Asset data to short
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,40 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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 "../interfaces/IAssetProxy.sol";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
contract MAssetProxy is
 | 
					 | 
				
			||||||
    IAssetProxy
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// @dev Internal version of `transferFrom`.
 | 
					 | 
				
			||||||
    /// @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 assetData,
 | 
					 | 
				
			||||||
        address from,
 | 
					 | 
				
			||||||
        address to,
 | 
					 | 
				
			||||||
        uint256 amount
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
        internal;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -135,7 +135,6 @@ contract MixinAssetProxyDispatcher is
 | 
				
			|||||||
            // |          | 132    | 32      | assetData Length                            |
 | 
					            // |          | 132    | 32      | assetData Length                            |
 | 
				
			||||||
            // |          | 164    | **      | assetData Contents                          |
 | 
					            // |          | 164    | **      | assetData Contents                          |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            bytes4 transferFromSelector = IAssetProxy(assetProxy).transferFrom.selector;
 | 
					 | 
				
			||||||
            bool success;
 | 
					            bool success;
 | 
				
			||||||
            assembly {
 | 
					            assembly {
 | 
				
			||||||
                /////// Setup State ///////
 | 
					                /////// Setup State ///////
 | 
				
			||||||
@@ -151,7 +150,8 @@ contract MixinAssetProxyDispatcher is
 | 
				
			|||||||
                
 | 
					                
 | 
				
			||||||
                /////// Setup Header Area ///////
 | 
					                /////// Setup Header Area ///////
 | 
				
			||||||
                // This area holds the 4-byte `transferFromSelector`.
 | 
					                // This area holds the 4-byte `transferFromSelector`.
 | 
				
			||||||
                mstore(cdStart, transferFromSelector)
 | 
					                // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
 | 
				
			||||||
 | 
					                mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000)
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
                /////// Setup Params Area ///////
 | 
					                /////// Setup Params Area ///////
 | 
				
			||||||
                // Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
 | 
					                // Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,56 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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
 | 
					 | 
				
			||||||
    ERC721Proxy
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /// @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 (
 | 
					 | 
				
			||||||
            address token,
 | 
					 | 
				
			||||||
            uint256 tokenId,
 | 
					 | 
				
			||||||
            bytes memory receiverData
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        (
 | 
					 | 
				
			||||||
            token,
 | 
					 | 
				
			||||||
            tokenId,
 | 
					 | 
				
			||||||
            receiverData
 | 
					 | 
				
			||||||
        ) = decodeERC721AssetData(assetData);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return (
 | 
					 | 
				
			||||||
            token,
 | 
					 | 
				
			||||||
            tokenId,
 | 
					 | 
				
			||||||
            receiverData
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -11,7 +11,6 @@ import * as ExchangeWrapper from '../artifacts/ExchangeWrapper.json';
 | 
				
			|||||||
import * as MixinAuthorizable from '../artifacts/MixinAuthorizable.json';
 | 
					import * as MixinAuthorizable from '../artifacts/MixinAuthorizable.json';
 | 
				
			||||||
import * as MultiSigWallet from '../artifacts/MultiSigWallet.json';
 | 
					import * as MultiSigWallet from '../artifacts/MultiSigWallet.json';
 | 
				
			||||||
import * as MultiSigWalletWithTimeLock from '../artifacts/MultiSigWalletWithTimeLock.json';
 | 
					import * as MultiSigWalletWithTimeLock from '../artifacts/MultiSigWalletWithTimeLock.json';
 | 
				
			||||||
import * as TestAssetDataDecoders from '../artifacts/TestAssetDataDecoders.json';
 | 
					 | 
				
			||||||
import * as TestAssetProxyDispatcher from '../artifacts/TestAssetProxyDispatcher.json';
 | 
					import * as TestAssetProxyDispatcher from '../artifacts/TestAssetProxyDispatcher.json';
 | 
				
			||||||
import * as TestAssetProxyOwner from '../artifacts/TestAssetProxyOwner.json';
 | 
					import * as TestAssetProxyOwner from '../artifacts/TestAssetProxyOwner.json';
 | 
				
			||||||
import * as TestLibBytes from '../artifacts/TestLibBytes.json';
 | 
					import * as TestLibBytes from '../artifacts/TestLibBytes.json';
 | 
				
			||||||
@@ -39,7 +38,6 @@ export const artifacts = {
 | 
				
			|||||||
    MultiSigWalletWithTimeLock: (MultiSigWalletWithTimeLock as any) as ContractArtifact,
 | 
					    MultiSigWalletWithTimeLock: (MultiSigWalletWithTimeLock as any) as ContractArtifact,
 | 
				
			||||||
    TestAssetProxyOwner: (TestAssetProxyOwner as any) as ContractArtifact,
 | 
					    TestAssetProxyOwner: (TestAssetProxyOwner as any) as ContractArtifact,
 | 
				
			||||||
    TestAssetProxyDispatcher: (TestAssetProxyDispatcher as any) as ContractArtifact,
 | 
					    TestAssetProxyDispatcher: (TestAssetProxyDispatcher as any) as ContractArtifact,
 | 
				
			||||||
    TestAssetDataDecoders: (TestAssetDataDecoders as any) as ContractArtifact,
 | 
					 | 
				
			||||||
    TestLibBytes: (TestLibBytes as any) as ContractArtifact,
 | 
					    TestLibBytes: (TestLibBytes as any) as ContractArtifact,
 | 
				
			||||||
    TestLibs: (TestLibs as any) as ContractArtifact,
 | 
					    TestLibs: (TestLibs as any) as ContractArtifact,
 | 
				
			||||||
    TestSignatureValidator: (TestSignatureValidator as any) as ContractArtifact,
 | 
					    TestSignatureValidator: (TestSignatureValidator as any) as ContractArtifact,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,84 +0,0 @@
 | 
				
			|||||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
 | 
					 | 
				
			||||||
import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils';
 | 
					 | 
				
			||||||
import { BigNumber } from '@0xproject/utils';
 | 
					 | 
				
			||||||
import * as chai from 'chai';
 | 
					 | 
				
			||||||
import ethUtil = require('ethereumjs-util');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { TestAssetDataDecodersContract } from '../../src/generated_contract_wrappers/test_asset_data_decoders';
 | 
					 | 
				
			||||||
import { artifacts } from '../../src/utils/artifacts';
 | 
					 | 
				
			||||||
import { chaiSetup } from '../../src/utils/chai_setup';
 | 
					 | 
				
			||||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
chaiSetup.configure();
 | 
					 | 
				
			||||||
const expect = chai.expect;
 | 
					 | 
				
			||||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
describe('TestAssetDataDecoders', () => {
 | 
					 | 
				
			||||||
    let testAssetProxyDecoder: TestAssetDataDecodersContract;
 | 
					 | 
				
			||||||
    let testAddress: string;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    before(async () => {
 | 
					 | 
				
			||||||
        await blockchainLifecycle.startAsync();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    after(async () => {
 | 
					 | 
				
			||||||
        await blockchainLifecycle.revertAsync();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    before(async () => {
 | 
					 | 
				
			||||||
        // Setup accounts & addresses
 | 
					 | 
				
			||||||
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
 | 
					 | 
				
			||||||
        testAddress = accounts[0];
 | 
					 | 
				
			||||||
        testAssetProxyDecoder = await TestAssetDataDecodersContract.deployFrom0xArtifactAsync(
 | 
					 | 
				
			||||||
            artifacts.TestAssetDataDecoders,
 | 
					 | 
				
			||||||
            provider,
 | 
					 | 
				
			||||||
            txDefaults,
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    beforeEach(async () => {
 | 
					 | 
				
			||||||
        await blockchainLifecycle.startAsync();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    afterEach(async () => {
 | 
					 | 
				
			||||||
        await blockchainLifecycle.revertAsync();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    describe('Asset Data Decoders', () => {
 | 
					 | 
				
			||||||
        it('should correctly decode ERC721 asset data', async () => {
 | 
					 | 
				
			||||||
            const tokenId = generatePseudoRandomSalt();
 | 
					 | 
				
			||||||
            const encodedAssetData = assetProxyUtils.encodeERC721AssetData(testAddress, tokenId);
 | 
					 | 
				
			||||||
            const expectedDecodedAssetData = assetProxyUtils.decodeERC721AssetData(encodedAssetData);
 | 
					 | 
				
			||||||
            let decodedTokenAddress: string;
 | 
					 | 
				
			||||||
            let decodedTokenId: BigNumber;
 | 
					 | 
				
			||||||
            let decodedData: string;
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                decodedTokenAddress,
 | 
					 | 
				
			||||||
                decodedTokenId,
 | 
					 | 
				
			||||||
                decodedData,
 | 
					 | 
				
			||||||
            ] = await testAssetProxyDecoder.publicDecodeERC721Data.callAsync(encodedAssetData);
 | 
					 | 
				
			||||||
            expect(decodedTokenAddress).to.be.equal(expectedDecodedAssetData.tokenAddress);
 | 
					 | 
				
			||||||
            expect(decodedTokenId).to.be.bignumber.equal(expectedDecodedAssetData.tokenId);
 | 
					 | 
				
			||||||
            expect(decodedData).to.be.equal(expectedDecodedAssetData.receiverData);
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it('should correctly decode ERC721 asset data with receiver data', async () => {
 | 
					 | 
				
			||||||
            const tokenId = generatePseudoRandomSalt();
 | 
					 | 
				
			||||||
            const receiverDataFirst32Bytes = ethUtil.bufferToHex(
 | 
					 | 
				
			||||||
                assetProxyUtils.encodeUint256(generatePseudoRandomSalt()),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            const receiverDataExtraBytes = 'FFFF';
 | 
					 | 
				
			||||||
            // We add extra bytes to generate a value that doesn't fit perfectly into one word
 | 
					 | 
				
			||||||
            const receiverData = receiverDataFirst32Bytes + receiverDataExtraBytes;
 | 
					 | 
				
			||||||
            const encodedAssetData = assetProxyUtils.encodeERC721AssetData(testAddress, tokenId, receiverData);
 | 
					 | 
				
			||||||
            const expectedDecodedAssetData = assetProxyUtils.decodeERC721AssetData(encodedAssetData);
 | 
					 | 
				
			||||||
            let decodedTokenAddress: string;
 | 
					 | 
				
			||||||
            let decodedTokenId: BigNumber;
 | 
					 | 
				
			||||||
            let decodedReceiverData: string;
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                decodedTokenAddress,
 | 
					 | 
				
			||||||
                decodedTokenId,
 | 
					 | 
				
			||||||
                decodedReceiverData,
 | 
					 | 
				
			||||||
            ] = await testAssetProxyDecoder.publicDecodeERC721Data.callAsync(encodedAssetData);
 | 
					 | 
				
			||||||
            expect(decodedTokenAddress).to.be.equal(expectedDecodedAssetData.tokenAddress);
 | 
					 | 
				
			||||||
            expect(decodedTokenId).to.be.bignumber.equal(expectedDecodedAssetData.tokenId);
 | 
					 | 
				
			||||||
            expect(decodedReceiverData).to.be.equal(expectedDecodedAssetData.receiverData);
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
@@ -5,7 +5,6 @@ import { BigNumber } from '@0xproject/utils';
 | 
				
			|||||||
import * as chai from 'chai';
 | 
					import * as chai from 'chai';
 | 
				
			||||||
import { LogWithDecodedArgs } from 'ethereum-types';
 | 
					import { LogWithDecodedArgs } from 'ethereum-types';
 | 
				
			||||||
import ethUtil = require('ethereumjs-util');
 | 
					import ethUtil = require('ethereumjs-util');
 | 
				
			||||||
import * as _ from 'lodash';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token';
 | 
					import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@@ -189,58 +188,6 @@ describe('Asset Transfer Proxies', () => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        describe('batchTransferFrom', () => {
 | 
					 | 
				
			||||||
            it('should succesfully make multiple token transfers', async () => {
 | 
					 | 
				
			||||||
                const erc20Balances = await erc20Wrapper.getBalancesAsync();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
 | 
					 | 
				
			||||||
                const amount = new BigNumber(10);
 | 
					 | 
				
			||||||
                const numTransfers = 2;
 | 
					 | 
				
			||||||
                const assetData = _.times(numTransfers, () => encodedAssetData);
 | 
					 | 
				
			||||||
                const fromAddresses = _.times(numTransfers, () => makerAddress);
 | 
					 | 
				
			||||||
                const toAddresses = _.times(numTransfers, () => takerAddress);
 | 
					 | 
				
			||||||
                const amounts = _.times(numTransfers, () => amount);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                const txHash = await erc20Proxy.batchTransferFrom.sendTransactionAsync(
 | 
					 | 
				
			||||||
                    assetData,
 | 
					 | 
				
			||||||
                    fromAddresses,
 | 
					 | 
				
			||||||
                    toAddresses,
 | 
					 | 
				
			||||||
                    amounts,
 | 
					 | 
				
			||||||
                    { from: exchangeAddress },
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                const res = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
					 | 
				
			||||||
                    txHash,
 | 
					 | 
				
			||||||
                    constants.AWAIT_TRANSACTION_MINED_MS,
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                const newBalances = await erc20Wrapper.getBalancesAsync();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                expect(res.logs.length).to.equal(numTransfers);
 | 
					 | 
				
			||||||
                expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal(
 | 
					 | 
				
			||||||
                    erc20Balances[makerAddress][zrxToken.address].minus(amount.times(numTransfers)),
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal(
 | 
					 | 
				
			||||||
                    erc20Balances[takerAddress][zrxToken.address].add(amount.times(numTransfers)),
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            it('should throw if not called by an authorized address', async () => {
 | 
					 | 
				
			||||||
                const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
 | 
					 | 
				
			||||||
                const amount = new BigNumber(10);
 | 
					 | 
				
			||||||
                const numTransfers = 2;
 | 
					 | 
				
			||||||
                const assetData = _.times(numTransfers, () => encodedAssetData);
 | 
					 | 
				
			||||||
                const fromAddresses = _.times(numTransfers, () => makerAddress);
 | 
					 | 
				
			||||||
                const toAddresses = _.times(numTransfers, () => takerAddress);
 | 
					 | 
				
			||||||
                const amounts = _.times(numTransfers, () => amount);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return expectRevertReasonOrAlwaysFailingTransactionAsync(
 | 
					 | 
				
			||||||
                    erc20Proxy.batchTransferFrom.sendTransactionAsync(assetData, fromAddresses, toAddresses, amounts, {
 | 
					 | 
				
			||||||
                        from: notAuthorized,
 | 
					 | 
				
			||||||
                    }),
 | 
					 | 
				
			||||||
                    RevertReason.SenderNotAuthorized,
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it('should have an id of 0xf47261b0', async () => {
 | 
					        it('should have an id of 0xf47261b0', async () => {
 | 
				
			||||||
            const proxyId = await erc20Proxy.getProxyId.callAsync();
 | 
					            const proxyId = await erc20Proxy.getProxyId.callAsync();
 | 
				
			||||||
            const expectedProxyId = '0xf47261b0';
 | 
					            const expectedProxyId = '0xf47261b0';
 | 
				
			||||||
@@ -440,61 +387,6 @@ describe('Asset Transfer Proxies', () => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        describe('batchTransferFrom', () => {
 | 
					 | 
				
			||||||
            it('should succesfully make multiple token transfers', async () => {
 | 
					 | 
				
			||||||
                const erc721TokensById = await erc721Wrapper.getBalancesAsync();
 | 
					 | 
				
			||||||
                const [makerTokenIdA, makerTokenIdB] = erc721TokensById[makerAddress][erc721Token.address];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                const numTransfers = 2;
 | 
					 | 
				
			||||||
                const assetData = [
 | 
					 | 
				
			||||||
                    assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdA),
 | 
					 | 
				
			||||||
                    assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdB),
 | 
					 | 
				
			||||||
                ];
 | 
					 | 
				
			||||||
                const fromAddresses = _.times(numTransfers, () => makerAddress);
 | 
					 | 
				
			||||||
                const toAddresses = _.times(numTransfers, () => takerAddress);
 | 
					 | 
				
			||||||
                const amounts = _.times(numTransfers, () => new BigNumber(1));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                const txHash = await erc721Proxy.batchTransferFrom.sendTransactionAsync(
 | 
					 | 
				
			||||||
                    assetData,
 | 
					 | 
				
			||||||
                    fromAddresses,
 | 
					 | 
				
			||||||
                    toAddresses,
 | 
					 | 
				
			||||||
                    amounts,
 | 
					 | 
				
			||||||
                    { from: exchangeAddress },
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                const res = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
					 | 
				
			||||||
                    txHash,
 | 
					 | 
				
			||||||
                    constants.AWAIT_TRANSACTION_MINED_MS,
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                expect(res.logs.length).to.equal(numTransfers);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                const newOwnerMakerAssetA = await erc721Token.ownerOf.callAsync(makerTokenIdA);
 | 
					 | 
				
			||||||
                const newOwnerMakerAssetB = await erc721Token.ownerOf.callAsync(makerTokenIdB);
 | 
					 | 
				
			||||||
                expect(newOwnerMakerAssetA).to.be.bignumber.equal(takerAddress);
 | 
					 | 
				
			||||||
                expect(newOwnerMakerAssetB).to.be.bignumber.equal(takerAddress);
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            it('should throw if not called by an authorized address', async () => {
 | 
					 | 
				
			||||||
                const erc721TokensById = await erc721Wrapper.getBalancesAsync();
 | 
					 | 
				
			||||||
                const [makerTokenIdA, makerTokenIdB] = erc721TokensById[makerAddress][erc721Token.address];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                const numTransfers = 2;
 | 
					 | 
				
			||||||
                const assetData = [
 | 
					 | 
				
			||||||
                    assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdA).slice(0, -2),
 | 
					 | 
				
			||||||
                    assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdB).slice(0, -2),
 | 
					 | 
				
			||||||
                ];
 | 
					 | 
				
			||||||
                const fromAddresses = _.times(numTransfers, () => makerAddress);
 | 
					 | 
				
			||||||
                const toAddresses = _.times(numTransfers, () => takerAddress);
 | 
					 | 
				
			||||||
                const amounts = _.times(numTransfers, () => new BigNumber(1));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return expectRevertReasonOrAlwaysFailingTransactionAsync(
 | 
					 | 
				
			||||||
                    erc721Proxy.batchTransferFrom.sendTransactionAsync(assetData, fromAddresses, toAddresses, amounts, {
 | 
					 | 
				
			||||||
                        from: notAuthorized,
 | 
					 | 
				
			||||||
                    }),
 | 
					 | 
				
			||||||
                    RevertReason.SenderNotAuthorized,
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it('should have an id of 0x08e937fa', async () => {
 | 
					        it('should have an id of 0x08e937fa', async () => {
 | 
				
			||||||
            const proxyId = await erc721Proxy.getProxyId.callAsync();
 | 
					            const proxyId = await erc721Proxy.getProxyId.callAsync();
 | 
				
			||||||
            const expectedProxyId = '0x08e937fa';
 | 
					            const expectedProxyId = '0x08e937fa';
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user