aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts/contracts/extensions/CompliantForwarder/CompliantForwarder.sol
blob: f34ee699d48e9df6d78ceb626fa4a808eb49ebe2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*

  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/Exchange/interfaces/IExchange.sol";
import "../../tokens/ERC721Token/IERC721Token.sol";
import "../../utils/LibBytes/LibBytes.sol";

contract CompliantForwarder {

    using LibBytes for bytes;

    bytes4 constant internal EXCHANGE_FILL_ORDER_SELECTOR = bytes4(keccak256("fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"));
    IExchange internal EXCHANGE;
    IERC721Token internal COMPLIANCE_TOKEN;

    constructor(address exchange, address complianceToken)
        public
    {
        EXCHANGE = IExchange(exchange);
        COMPLIANCE_TOKEN = IERC721Token(complianceToken);
    }

    function fillOrder(
        uint256 salt,
        address signerAddress,
        bytes signedFillOrderTransaction,
        bytes signature
    ) 
        public
    {
        // Validate `signedFillOrderTransaction`
        bytes4 selector = signedFillOrderTransaction.readBytes4(0);
        if (selector != EXCHANGE_FILL_ORDER_SELECTOR) {
            revert("EXCHANGE_TRANSACTION_NOT_FILL_ORDER");
        }
        
        // Taker must be compliant
        require(
            COMPLIANCE_TOKEN.balanceOf(signerAddress) > 0,
            "TAKER_UNVERIFIED"
        );

        // Extract maker address from fill order transaction and ensure maker is compliant
        // Below is the table of calldata offsets into a fillOrder transaction.
        /**
                    ### parameters 
            0x00      ptr<order>                                                                      
            0x20      takerAssetFillAmount                                                            
            0x40      ptr<signature>                                                                  
                    ### order                                                                           
            0x60      makerAddress                                                                    
            0x80      takerAddress                                                                    
            0xa0      feeRecipientAddress                                                             
            0xc0      senderAddress                                                                   
            0xe0      makerAssetAmount                                                                
            0x100     takerAssetAmount                                                                
            0x120     makerFee                                                                        
            0x140     takerFee                                                                        
            0x160     expirationTimeSeconds                                                           
            0x180     salt                                                                            
            0x1a0     ptr<makerAssetData>                                                             
            0x1c0     ptr<takerAssetData>                                                             
            0x1e0     makerAssetData                                                                  
            *         takerAssetData                                                                  
            *         signature
            ------------------------------
            * Context-dependent offsets; unknown at compile time.
        */
        // Add 0x4 to a given offset to account for the fillOrder selector prepended to `signedFillOrderTransaction`.
        // Add 0xc to the makerAddress since abi-encoded addresses are left padded with 12 bytes.
        // Putting this together: makerAddress = 0x60 + 0x4 + 0xc = 0x70
        address makerAddress = signedFillOrderTransaction.readAddress(0x70);
        require(
            COMPLIANCE_TOKEN.balanceOf(makerAddress) > 0, 
            "MAKER_UNVERIFIED"
        );
        
        // All entities are verified. Execute fillOrder.
        EXCHANGE.executeTransaction(
            salt,
            signerAddress,
            signedFillOrderTransaction,
            signature
        );
    }
}