Contract 0x03E0F73A93993E5101362656Af1162eD80FB54F2

 
 
Txn Hash
Method
Block
From
To
Value
0xb65da665c13bb7e4f3b678cc8f1204d9249770c905c7e150bd8aad3776779f32Set Cutoff52533282018-03-14 10:35:501721 days 21 hrs ago0xfa244e7689ce25bc7775c277e1765222a720fd31 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.0009276521
0x5c753c6ee9c129c1835dba29354ca128793f5796173217719d04e5dca8420195Cancel Order52480592018-03-13 13:06:391722 days 19 hrs ago0xf4271df1e744200a1356d191afef60b9a8e74f13 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.001285221
0x70e01fb768eb26456791600ec1f797e6a59e124e0f3a5da2b397fbf05e88a830Cancel Order52085822018-03-06 20:08:191729 days 12 hrs ago0x1ed46acd498fade39a5eaaf59011c92587664e2e IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.0009648221
0x9e05858591b487e6557f48631435e28419d2d218228adaef59620096c2a971daSet Cutoff50711452018-02-11 13:27:301752 days 18 hrs ago0x335187ce3f862b89bb1f44c55eeda5405015a234 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.0009276521
0xebeed94277a1b0c0012c380c64d292f63e6c393886d4db4293e4a40e4e9ccdaeSet Cutoff50552572018-02-08 21:42:091755 days 10 hrs ago0x1ed46acd498fade39a5eaaf59011c92587664e2e IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.0009276521
0x0a3d3fd4172e28ea232290e9947af6d729f21af4aa432c26f02c85c77e9b39b7Cancel Order50552382018-02-08 21:37:521755 days 10 hrs ago0x1ed46acd498fade39a5eaaf59011c92587664e2e IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.0012798221
0x1ebb3909555ff5ad2a9910a30512540343c5a86663fbaa511a6568e3fa1e8fc4Submit Ring50296262018-02-04 14:16:591759 days 17 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.000132791.5
0x026d7c54e7c36ccadae8113a1044b6ab729dbbe026004299e24f306665753518Submit Ring50296192018-02-04 14:14:381759 days 17 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.00013261.5
0x01c51743c153127324a72821aadc8df61e21b1a15f71bbc0846328092d5b615eSubmit Ring50296072018-02-04 14:11:321759 days 17 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.00013251.5
0x102bb756e3c6ba53c0840a91465c5195aec60c951f999cada1f952a6f901bd40Submit Ring50296042018-02-04 14:10:381759 days 18 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.000132881.5
0xc5c0f122e6bd54e91c8a11693fc9450dcda3a037d872d72c25c4c5b2f82b235fSubmit Ring50296042018-02-04 14:10:381759 days 18 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.000133171.5
0x2951954d650fbc8795646766d95a4d16fc65ef440349d2906f25bcb22207ec46Submit Ring50257332018-02-03 22:45:551760 days 9 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.000133361.5
0xabe2c8a66df511a1adbdfca9d7f946bb179efbf8df82dfab01f7c21209038389Set Cutoff50158402018-02-02 6:51:221762 days 1 hr ago0x7e90a0c92ff1cf8098309b5d626f65a6c64fdac3 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.0006126521
0x180393b24881e259bd33677e3daddd6c5e3d5c494b6618ec8313d0e096665ba5Set Cutoff50138362018-02-01 22:31:361762 days 9 hrs ago0xd3af8ded8547102d29533d05b66bf2c8ef155127 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.0009276521
0x89a2edb53d254d8f1be2aefe8f29657249e83ed9716bdcc717a25f27583ae596Cancel Order50138142018-02-01 22:24:351762 days 9 hrs ago0xd3af8ded8547102d29533d05b66bf2c8ef155127 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.0009769221
0x79a42a1f73d255561b68f285a1d772b27517831f16bf18ab36f857cb297d6ba9Cancel Order50083082018-01-31 23:35:591763 days 8 hrs ago0x7e90a0c92ff1cf8098309b5d626f65a6c64fdac3 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.0012932621
0xf2f5b18ad0a014ae627455cc6ca7b356ea7484251dcf7ecbf078c22fa645f9caCancel Order50083062018-01-31 23:35:411763 days 8 hrs ago0x7e90a0c92ff1cf8098309b5d626f65a6c64fdac3 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.0009769221
0x3a1e459617d619680a9abc8d0f752743a0a74b967abae1cd08fef9e960360647Set Cutoff50082682018-01-31 23:26:451763 days 8 hrs ago0x7e90a0c92ff1cf8098309b5d626f65a6c64fdac3 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.0006126521
0xf188316222856aaa3b3449fbd3dfb5467125a989478d7c89fad6bf4cbfd667aaSubmit Ring50055942018-01-31 12:13:211763 days 19 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.000400271.5
0xdfb46b4326ee5f713bff2ea4fc677734d9ff54171b63cd54f5b3d8f6f74671abSubmit Ring50055942018-01-31 12:13:211763 days 19 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.000400121.5
0x9346d918b019e394cc4711fd3c7291c3c8865e129541d60ce692c98d1a4a18ffSubmit Ring50052982018-01-31 11:05:031763 days 21 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.000392111.5
0xd64b99b2c1191c9e15b196bdae32d881648a6b8cd5c9519f6507fb5b676a3cdaSubmit Ring50052972018-01-31 11:04:541763 days 21 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.000392111.5
0xce55bb57b25c80b8c9dbfeb3902b74edbc526cb4f1cb5510a7cb901b0cd74d8fSubmit Ring50052962018-01-31 11:04:481763 days 21 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.000392111.5
0x9e828ec31cf7867b22e60530f11b1903403e7bc94b84769a1f9f2b083ef1fc47Submit Ring50052952018-01-31 11:04:141763 days 21 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.00039221.5
0x000b2695a6734b2ab964ef94915640938abe6384c7a56097c23f1ed82b926e7bSubmit Ring50052932018-01-31 11:04:081763 days 21 hrs ago0x3acdf3e3d8ec52a768083f718e763727b0210650 IN  0x03e0f73a93993e5101362656af1162ed80fb54f20 Ether0.000400051.5
[ Download CSV Export 
View more zero value Internal Transactions in Advanced View mode
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LoopringProtocolImpl

Compiler Version
v0.4.18+commit.9cf6e910

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2017-12-12
*/

/*
  Copyright 2017 Loopring Project Ltd (Loopring Foundation).
  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.18;
/// @title Utility Functions for uint
/// @author Daniel Wang - <[email protected]>
library MathUint {
    function mul(uint a, uint b) internal pure returns (uint c) {
        c = a * b;
        require(a == 0 || c / a == b);
    }
    function sub(uint a, uint b) internal pure returns (uint) {
        require(b <= a);
        return a - b;
    }
    function add(uint a, uint b) internal pure returns (uint c) {
        c = a + b;
        require(c >= a);
    }
    function tolerantSub(uint a, uint b) internal pure returns (uint c) {
        return (a >= b) ? a - b : 0;
    }
    /// @dev calculate the square of Coefficient of Variation (CV)
    /// https://en.wikipedia.org/wiki/Coefficient_of_variation
    function cvsquare(
        uint[] arr,
        uint scale
        )
        internal
        pure
        returns (uint)
    {
        uint len = arr.length;
        require(len > 1);
        require(scale > 0);
        uint avg = 0;
        for (uint i = 0; i < len; i++) {
            avg += arr[i];
        }
        avg = avg / len;
        if (avg == 0) {
            return 0;
        }
        uint cvs = 0;
        uint s;
        uint item;
        for (i = 0; i < len; i++) {
            item = arr[i];
            s = item > avg ? item - avg : avg - item;
            cvs += mul(s, s);
        }
        return ((mul(mul(cvs, scale), scale) / avg) / avg) / (len - 1);
    }
}
/*
  Copyright 2017 Loopring Project Ltd (Loopring Foundation).
  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.
*/
/*
  Copyright 2017 Loopring Project Ltd (Loopring Foundation).
  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.
*/
/// @title ERC20 Token Interface
/// @dev see https://github.com/ethereum/EIPs/issues/20
/// @author Daniel Wang - <[email protected]>
contract ERC20 {
    uint public totalSupply;
	
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    function balanceOf(address who) view public returns (uint256);
    function allowance(address owner, address spender) view public returns (uint256);
    function transfer(address to, uint256 value) public returns (bool);
    function transferFrom(address from, address to, uint256 value) public returns (bool);
    function approve(address spender, uint256 value) public returns (bool);
}
/*
  Copyright 2017 Loopring Project Ltd (Loopring Foundation).
  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.
*/
/// @title Loopring Token Exchange Protocol Contract Interface
/// @author Daniel Wang - <[email protected]>
/// @author Kongliang Zhong - <[email protected]>
contract LoopringProtocol {
    ////////////////////////////////////////////////////////////////////////////
    /// Constants                                                            ///
    ////////////////////////////////////////////////////////////////////////////
    uint8   public constant FEE_SELECT_LRC               = 0;
    uint8   public constant FEE_SELECT_MARGIN_SPLIT      = 1;
    uint8   public constant FEE_SELECT_MAX_VALUE         = 1;
    uint8   public constant MARGIN_SPLIT_PERCENTAGE_BASE = 100;
    ////////////////////////////////////////////////////////////////////////////
    /// Events                                                               ///
    ////////////////////////////////////////////////////////////////////////////
    /// @dev Event to emit if a ring is successfully mined.
    /// _amountsList is an array of:
    /// [_amountS, _amountB, _lrcReward, _lrcFee, splitS, splitB].
    event RingMined(
        uint                _ringIndex,
        bytes32     indexed _ringhash,
        address             _miner,
        address             _feeRecipient,
        bool                _isRinghashReserved,
        bytes32[]           _orderHashList,
        uint[6][]           _amountsList
    );
    event OrderCancelled(
        bytes32     indexed _orderHash,
        uint                _amountCancelled
    );
    event CutoffTimestampChanged(
        address     indexed _address,
        uint                _cutoff
    );
    ////////////////////////////////////////////////////////////////////////////
    /// Functions                                                            ///
    ////////////////////////////////////////////////////////////////////////////
    /// @dev Submit a order-ring for validation and settlement.
    /// @param addressList  List of each order's owner and tokenS. Note that next
    ///                     order's `tokenS` equals this order's `tokenB`.
    /// @param uintArgsList List of uint-type arguments in this order:
    ///                     amountS, amountB, timestamp, ttl, salt, lrcFee,
    ///                     rateAmountS.
    /// @param uint8ArgsList -
    ///                     List of unit8-type arguments, in this order:
    ///                     marginSplitPercentageList, feeSelectionList.
    /// @param buyNoMoreThanAmountBList -
    ///                     This indicates when a order should be considered
    ///                     as 'completely filled'.
    /// @param vList        List of v for each order. This list is 1-larger than
    ///                     the previous lists, with the last element being the
    ///                     v value of the ring signature.
    /// @param rList        List of r for each order. This list is 1-larger than
    ///                     the previous lists, with the last element being the
    ///                     r value of the ring signature.
    /// @param sList        List of s for each order. This list is 1-larger than
    ///                     the previous lists, with the last element being the
    ///                     s value of the ring signature.
    /// @param ringminer    The address that signed this tx.
    /// @param feeRecepient The recepient address for fee collection. If this is
    ///                     '0x0', all fees will be paid to the address who had
    ///                     signed this transaction, not `msg.sender`. Noted if
    ///                     LRC need to be paid back to order owner as the result
    ///                     of fee selection model, LRC will also be sent from
    ///                     this address.
    function submitRing(
        address[2][]    addressList,
        uint[7][]       uintArgsList,
        uint8[2][]      uint8ArgsList,
        bool[]          buyNoMoreThanAmountBList,
        uint8[]         vList,
        bytes32[]       rList,
        bytes32[]       sList,
        address         ringminer,
        address         feeRecepient
        ) public;
    /// @dev Cancel a order. cancel amount(amountS or amountB) can be specified
    ///      in orderValues.
    /// @param addresses          owner, tokenS, tokenB
    /// @param orderValues        amountS, amountB, timestamp, ttl, salt, lrcFee,
    ///                           cancelAmountS, and cancelAmountB.
    /// @param buyNoMoreThanAmountB -
    ///                           This indicates when a order should be considered
    ///                           as 'completely filled'.
    /// @param marginSplitPercentage -
    ///                           Percentage of margin split to share with miner.
    /// @param v                  Order ECDSA signature parameter v.
    /// @param r                  Order ECDSA signature parameters r.
    /// @param s                  Order ECDSA signature parameters s.
    function cancelOrder(
        address[3] addresses,
        uint[7]    orderValues,
        bool       buyNoMoreThanAmountB,
        uint8      marginSplitPercentage,
        uint8      v,
        bytes32    r,
        bytes32    s
        ) external;
    /// @dev   Set a cutoff timestamp to invalidate all orders whose timestamp
    ///        is smaller than or equal to the new value of the address's cutoff
    ///        timestamp.
    /// @param cutoff The cutoff timestamp, will default to `block.timestamp`
    ///        if it is 0.
    function setCutoff(uint cutoff) external;
}
/*
  Copyright 2017 Loopring Project Ltd (Loopring Foundation).
  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.
*/
/*
  Copyright 2017 Loopring Project Ltd (Loopring Foundation).
  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.
*/
/// @title Utility Functions for byte32
/// @author Kongliang Zhong - <[email protected]>,
/// @author Daniel Wang - <[email protected]>.
library MathBytes32 {
    function xorReduce(
        bytes32[]   arr,
        uint        len
        )
        internal
        pure
        returns (bytes32 res)
    {
        res = arr[0];
        for (uint i = 1; i < len; i++) {
            res ^= arr[i];
        }
    }
}
/*
  Copyright 2017 Loopring Project Ltd (Loopring Foundation).
  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.
*/
/// @title Utility Functions for uint8
/// @author Kongliang Zhong - <[email protected]>,
/// @author Daniel Wang - <[email protected]>.
library MathUint8 {
    function xorReduce(
        uint8[] arr,
        uint    len
        )
        internal
        pure
        returns (uint8 res)
    {
        res = arr[0];
        for (uint i = 1; i < len; i++) {
            res ^= arr[i];
        }
    }
}
/// @title Ring Hash Registry Contract
/// @dev This contracts help reserve ringhashes for miners.
/// @author Kongliang Zhong - <[email protected]>,
/// @author Daniel Wang - <[email protected]>.
contract RinghashRegistry {
    using MathBytes32   for bytes32[];
    using MathUint8     for uint8[];
    uint public blocksToLive;
    struct Submission {
        address ringminer;
        uint block;
    }
    mapping (bytes32 => Submission) submissions;
    ////////////////////////////////////////////////////////////////////////////
    /// Events                                                               ///
    ////////////////////////////////////////////////////////////////////////////
    event RinghashSubmitted(
        address indexed _ringminer,
        bytes32 indexed _ringhash
    );
    ////////////////////////////////////////////////////////////////////////////
    /// Constructor                                                          ///
    ////////////////////////////////////////////////////////////////////////////
    function RinghashRegistry(uint _blocksToLive)
        public
    {
        require(_blocksToLive > 0);
        blocksToLive = _blocksToLive;
    }
    ////////////////////////////////////////////////////////////////////////////
    /// Public Functions                                                     ///
    ////////////////////////////////////////////////////////////////////////////
    /// @dev Disable default function.
    function () payable public {
        revert();
    }
    function submitRinghash(
        address     ringminer,
        bytes32     ringhash
        )
        public
    {
        require(canSubmit(ringhash, ringminer)); //, "Ringhash submitted");
        submissions[ringhash] = Submission(ringminer, block.number);
        RinghashSubmitted(ringminer, ringhash);
    }
    function batchSubmitRinghash(
        address[]     ringminerList,
        bytes32[]     ringhashList
        )
        external
    {
        uint size = ringminerList.length;
        require(size > 0);
        require(size == ringhashList.length);
        for (uint i = 0; i < size; i++) {
            submitRinghash(ringminerList[i], ringhashList[i]);
        }
    }
    /// @dev Calculate the hash of a ring.
    function calculateRinghash(
        uint        ringSize,
        uint8[]     vList,
        bytes32[]   rList,
        bytes32[]   sList
        )
        private
        pure
        returns (bytes32)
    {
        require(
            ringSize == vList.length - 1 && (
            ringSize == rList.length - 1 && (
            ringSize == sList.length - 1))
        ); //, "invalid ring data");
        return keccak256(
            vList.xorReduce(ringSize),
            rList.xorReduce(ringSize),
            sList.xorReduce(ringSize)
        );
    }
     /// return value attributes[2] contains the following values in this order:
     /// canSubmit, isReserved.
    function computeAndGetRinghashInfo(
        uint        ringSize,
        address     ringminer,
        uint8[]     vList,
        bytes32[]   rList,
        bytes32[]   sList
        )
        external
        view
        returns (bytes32 ringhash, bool[2] attributes)
    {
        ringhash = calculateRinghash(
            ringSize,
            vList,
            rList,
            sList
        );
        attributes[0] = canSubmit(ringhash, ringminer);
        attributes[1] = isReserved(ringhash, ringminer);
    }
    /// @return true if a ring's hash can be submitted;
    /// false otherwise.
    function canSubmit(
        bytes32 ringhash,
        address ringminer)
        public
        view
        returns (bool)
    {
        require(ringminer != 0x0);
        Submission memory submission = submissions[ringhash];
        address miner = submission.ringminer;
        return (
            miner == 0x0 || (
            submission.block + blocksToLive < block.number) || (
            miner == ringminer)
        );
    }
    /// @return true if a ring's hash was submitted and still valid;
    /// false otherwise.
    function isReserved(
        bytes32 ringhash,
        address ringminer)
        public
        view
        returns (bool)
    {
        Submission memory submission = submissions[ringhash];
        return (
            submission.block + blocksToLive >= block.number && (
            submission.ringminer == ringminer)
        );
    }
}
/*
  Copyright 2017 Loopring Project Ltd (Loopring Foundation).
  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.
*/
/*
  Copyright 2017 Loopring Project Ltd (Loopring Foundation).
  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.
*/
/*
  Copyright 2017 Loopring Project Ltd (Loopring Foundation).
  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.
*/
/// @title Ownable
/// @dev The Ownable contract has an owner address, and provides basic
///      authorization control functions, this simplifies the implementation of
///      "user permissions".
contract Ownable {
    address public owner;
    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );
    /// @dev The Ownable constructor sets the original `owner` of the contract
    ///      to the sender.
    function Ownable() public {
        owner = msg.sender;
    }
    /// @dev Throws if called by any account other than the owner.
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }
    /// @dev Allows the current owner to transfer control of the contract to a
    ///      newOwner.
    /// @param newOwner The address to transfer ownership to.
    function transferOwnership(address newOwner) onlyOwner public {
        require(newOwner != 0x0);
        OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }
}
/// @title Claimable
/// @dev Extension for the Ownable contract, where the ownership needs
///      to be claimed. This allows the new owner to accept the transfer.
contract Claimable is Ownable {
    address public pendingOwner;
    /// @dev Modifier throws if called by any account other than the pendingOwner.
    modifier onlyPendingOwner() {
        require(msg.sender == pendingOwner);
        _;
    }
    /// @dev Allows the current owner to set the pendingOwner address.
    /// @param newOwner The address to transfer ownership to.
    function transferOwnership(address newOwner) onlyOwner public {
        require(newOwner != 0x0 && newOwner != owner);
        pendingOwner = newOwner;
    }
    /// @dev Allows the pendingOwner address to finalize the transfer.
    function claimOwnership() onlyPendingOwner public {
        OwnershipTransferred(owner, pendingOwner);
        owner = pendingOwner;
        pendingOwner = 0x0;
    }
}
/// @title Token Register Contract
/// @dev This contract maintains a list of tokens the Protocol supports.
/// @author Kongliang Zhong - <[email protected]>,
/// @author Daniel Wang - <[email protected]>.
contract TokenRegistry is Claimable {
    address[] public addresses;
    mapping (address => TokenInfo) addressMap;
    mapping (string => address) symbolMap;
    
    uint8 public constant TOKEN_STANDARD_ERC20   = 0;
    uint8 public constant TOKEN_STANDARD_ERC223  = 1;
    
    ////////////////////////////////////////////////////////////////////////////
    /// Structs                                                              ///
    ////////////////////////////////////////////////////////////////////////////
    struct TokenInfo {
        uint   pos;      // 0 mens unregistered; if > 0, pos + 1 is the
                         // token's position in `addresses`.
        uint8  standard; // ERC20 or ERC223
        string symbol;   // Symbol of the token
    }
    
    ////////////////////////////////////////////////////////////////////////////
    /// Events                                                               ///
    ////////////////////////////////////////////////////////////////////////////
    event TokenRegistered(address addr, string symbol);
    event TokenUnregistered(address addr, string symbol);
    
    ////////////////////////////////////////////////////////////////////////////
    /// Public Functions                                                     ///
    ////////////////////////////////////////////////////////////////////////////
    /// @dev Disable default function.
    function () payable public {
        revert();
    }
    function registerToken(
        address addr,
        string  symbol
        )
        external
        onlyOwner
    {
        registerStandardToken(addr, symbol, TOKEN_STANDARD_ERC20);    
    }
    function registerStandardToken(
        address addr,
        string  symbol,
        uint8   standard
        )
        public
        onlyOwner
    {
        require(0x0 != addr);
        require(bytes(symbol).length > 0);
        require(0x0 == symbolMap[symbol]);
        require(0 == addressMap[addr].pos);
        require(standard <= TOKEN_STANDARD_ERC223);
        addresses.push(addr);
        symbolMap[symbol] = addr;
        addressMap[addr] = TokenInfo(addresses.length, standard, symbol);
        TokenRegistered(addr, symbol);      
    }
    function unregisterToken(
        address addr,
        string  symbol
        )
        external
        onlyOwner
    {
        require(addr != 0x0);
        require(symbolMap[symbol] == addr);
        delete symbolMap[symbol];
        
        uint pos = addressMap[addr].pos;
        require(pos != 0);
        delete addressMap[addr];
        
        // We will replace the token we need to unregister with the last token
        // Only the pos of the last token will need to be updated
        address lastToken = addresses[addresses.length - 1];
        
        // Don't do anything if the last token is the one we want to delete
        if (addr != lastToken) {
            // Swap with the last token and update the pos
            addresses[pos - 1] = lastToken;
            addressMap[lastToken].pos = pos;
        }
        addresses.length--;
        TokenUnregistered(addr, symbol);
    }
    function isTokenRegisteredBySymbol(string symbol)
        public
        view
        returns (bool)
    {
        return symbolMap[symbol] != 0x0;
    }
    function isTokenRegistered(address addr)
        public
        view
        returns (bool)
    {
        return addressMap[addr].pos != 0;
    }
    function areAllTokensRegistered(address[] addressList)
        external
        view
        returns (bool)
    {
        for (uint i = 0; i < addressList.length; i++) {
            if (addressMap[addressList[i]].pos == 0) {
                return false;
            }
        }
        return true;
    }
    
    function getTokenStandard(address addr)
        public
        view
        returns (uint8)
    {
        TokenInfo memory info = addressMap[addr];
        require(info.pos != 0);
        return info.standard;
    }
    function getAddressBySymbol(string symbol)
        external
        view
        returns (address)
    {
        return symbolMap[symbol];
    }
    
    function getTokens(
        uint start,
        uint count
        )
        public
        view
        returns (address[] addressList)
    {
        uint num = addresses.length;
        
        if (start >= num) {
            return;
        }
        
        uint end = start + count;
        if (end > num) {
            end = num;
        }
        if (start == num) {
            return;
        }
        
        addressList = new address[](end - start);
        for (uint i = start; i < end; i++) {
            addressList[i - start] = addresses[i];
        }
    }
}
/*
  Copyright 2017 Loopring Project Ltd (Loopring Foundation).
  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.
*/
/// @title TokenTransferDelegate
/// @dev Acts as a middle man to transfer ERC20 tokens on behalf of different
/// versions of Loopring protocol to avoid ERC20 re-authorization.
/// @author Daniel Wang - <[email protected]>.
contract TokenTransferDelegate is Claimable {
    using MathUint for uint;
    ////////////////////////////////////////////////////////////////////////////
    /// Variables                                                            ///
    ////////////////////////////////////////////////////////////////////////////
    mapping(address => AddressInfo) private addressInfos;
    address public latestAddress;
    ////////////////////////////////////////////////////////////////////////////
    /// Structs                                                              ///
    ////////////////////////////////////////////////////////////////////////////
    struct AddressInfo {
        address previous;
        uint32  index;
        bool    authorized;
    }
    ////////////////////////////////////////////////////////////////////////////
    /// Modifiers                                                            ///
    ////////////////////////////////////////////////////////////////////////////
    modifier onlyAuthorized() {
        require(addressInfos[msg.sender].authorized);
        _;
    }
    ////////////////////////////////////////////////////////////////////////////
    /// Events                                                               ///
    ////////////////////////////////////////////////////////////////////////////
    event AddressAuthorized(address indexed addr, uint32 number);
    event AddressDeauthorized(address indexed addr, uint32 number);
    ////////////////////////////////////////////////////////////////////////////
    /// Public Functions                                                     ///
    ////////////////////////////////////////////////////////////////////////////
    /// @dev Disable default function.
    function () payable public {
        revert();
    }
    /// @dev Add a Loopring protocol address.
    /// @param addr A loopring protocol address.
    function authorizeAddress(address addr)
        onlyOwner
        external
    {
        AddressInfo storage addrInfo = addressInfos[addr];
        if (addrInfo.index != 0) { // existing
            if (addrInfo.authorized == false) { // re-authorize
                addrInfo.authorized = true;
                AddressAuthorized(addr, addrInfo.index);
            }
        } else {
            address prev = latestAddress;
            if (prev == 0x0) {
                addrInfo.index = 1;
                addrInfo.authorized = true;
            } else {
                addrInfo.previous = prev;
                addrInfo.index = addressInfos[prev].index + 1;
            }
            addrInfo.authorized = true;
            latestAddress = addr;
            AddressAuthorized(addr, addrInfo.index);
        }
    }
    /// @dev Remove a Loopring protocol address.
    /// @param addr A loopring protocol address.
    function deauthorizeAddress(address addr)
        onlyOwner
        external
    {
        uint32 index = addressInfos[addr].index;
        if (index != 0) {
            addressInfos[addr].authorized = false;
            AddressDeauthorized(addr, index);
        }
    }
    function isAddressAuthorized(address addr)
        public
        view
        returns (bool)
    {
        return addressInfos[addr].authorized;
    }
    function getLatestAuthorizedAddresses(uint max)
        external
        view
        returns (address[] addresses)
    {
        addresses = new address[](max);
        address addr = latestAddress;
        AddressInfo memory addrInfo;
        uint count = 0;
        while (addr != 0x0 && count < max) {
            addrInfo = addressInfos[addr];
            if (addrInfo.index == 0) {
                break;
            }
            addresses[count++] = addr;
            addr = addrInfo.previous;
        }
    }
    /// @dev Invoke ERC20 transferFrom method.
    /// @param token Address of token to transfer.
    /// @param from Address to transfer token from.
    /// @param to Address to transfer token to.
    /// @param value Amount of token to transfer.
    function transferToken(
        address token,
        address from,
        address to,
        uint    value)
        onlyAuthorized
        external
    {
        if (value > 0 && from != to) {
            require(
                ERC20(token).transferFrom(from, to, value)
            );
        }
    }
    function batchTransferToken(
        address lrcTokenAddress,
        address feeRecipient,
        bytes32[] batch)
        onlyAuthorized
        external
    {
        uint len = batch.length;
        require(len % 6 == 0);
        ERC20 lrc = ERC20(lrcTokenAddress);
        for (uint i = 0; i < len; i += 6) {
            address owner = address(batch[i]);
            address prevOwner = address(batch[(i + len - 6) % len]);
            // Pay token to previous order, or to miner as previous order's
            // margin split or/and this order's margin split.
            ERC20 token = ERC20(address(batch[i + 1]));
            // Here batch[i+2] has been checked not to be 0.
            if (owner != prevOwner) {
                require(
                    token.transferFrom(owner, prevOwner, uint(batch[i + 2]))
                );
            }
            if (owner != feeRecipient) {
                bytes32 item = batch[i + 3];
                if (item != 0) {
                    require(
                        token.transferFrom(owner, feeRecipient, uint(item))
                    );
                }
                item = batch[i + 4];
                if (item != 0) {
                    require(
                        lrc.transferFrom(feeRecipient, owner, uint(item))
                    );
                }
                item = batch[i + 5];
                if (item != 0) {
                    require(
                        lrc.transferFrom(owner, feeRecipient, uint(item))
                    );
                }
            }
        }
    }
}
/// @title Loopring Token Exchange Protocol Implementation Contract v1
/// @author Daniel Wang - <[email protected]>,
/// @author Kongliang Zhong - <[email protected]>
///
/// Recognized contributing developers from the community:
///     https://github.com/Brechtpd
///     https://github.com/rainydio
///     https://github.com/BenjaminPrice
///     https://github.com/jonasshen
contract LoopringProtocolImpl is LoopringProtocol {
    using MathUint for uint;
    ////////////////////////////////////////////////////////////////////////////
    /// Variables                                                            ///
    ////////////////////////////////////////////////////////////////////////////
    address public  lrcTokenAddress             = 0x0;
    address public  tokenRegistryAddress        = 0x0;
    address public  ringhashRegistryAddress     = 0x0;
    address public  delegateAddress             = 0x0;
    uint    public  maxRingSize                 = 0;
    uint64  public  ringIndex                   = 0;
    // Exchange rate (rate) is the amount to sell or sold divided by the amount
    // to buy or bought.
    //
    // Rate ratio is the ratio between executed rate and an order's original
    // rate.
    //
    // To require all orders' rate ratios to have coefficient ofvariation (CV)
    // smaller than 2.5%, for an example , rateRatioCVSThreshold should be:
    //     `(0.025 * RATE_RATIO_SCALE)^2` or 62500.
    uint    public  rateRatioCVSThreshold       = 0;
    uint    public constant RATE_RATIO_SCALE    = 10000;
    uint64  public constant ENTERED_MASK        = 1 << 63;
    // The following map is used to keep trace of order fill and cancellation
    // history.
    mapping (bytes32 => uint) public cancelledOrFilled;
    // A map from address to its cutoff timestamp.
    mapping (address => uint) public cutoffs;
    ////////////////////////////////////////////////////////////////////////////
    /// Structs                                                              ///
    ////////////////////////////////////////////////////////////////////////////
    struct Rate {
        uint amountS;
        uint amountB;
    }
    /// @param tokenS       Token to sell.
    /// @param tokenB       Token to buy.
    /// @param amountS      Maximum amount of tokenS to sell.
    /// @param amountB      Minimum amount of tokenB to buy if all amountS sold.
    /// @param timestamp    Indicating when this order is created/signed.
    /// @param ttl          Indicating after how many seconds from `timestamp`
    ///                     this order will expire.
    /// @param salt         A random number to make this order's hash unique.
    /// @param lrcFee       Max amount of LRC to pay for miner. The real amount
    ///                     to pay is proportional to fill amount.
    /// @param buyNoMoreThanAmountB -
    ///                     If true, this order does not accept buying more
    ///                     than `amountB`.
    /// @param marginSplitPercentage -
    ///                     The percentage of margin paid to miner.
    /// @param v            ECDSA signature parameter v.
    /// @param r            ECDSA signature parameters r.
    /// @param s            ECDSA signature parameters s.
    struct Order {
        address owner;
        address tokenS;
        address tokenB;
        uint    amountS;
        uint    amountB;
        uint    lrcFee;
        bool    buyNoMoreThanAmountB;
        uint8   marginSplitPercentage;
    }
    /// @param order        The original order
    /// @param orderHash    The order's hash
    /// @param feeSelection -
    ///                     A miner-supplied value indicating if LRC (value = 0)
    ///                     or margin split is choosen by the miner (value = 1).
    ///                     We may support more fee model in the future.
    /// @param rate         Exchange rate provided by miner.
    /// @param fillAmountS  Amount of tokenS to sell, calculated by protocol.
    /// @param lrcReward    The amount of LRC paid by miner to order owner in
    ///                     exchange for margin split.
    /// @param lrcFee       The amount of LR paid by order owner to miner.
    /// @param splitS      TokenS paid to miner.
    /// @param splitB      TokenB paid to miner.
    struct OrderState {
        Order   order;
        bytes32 orderHash;
        uint8   feeSelection;
        Rate    rate;
        uint    fillAmountS;
        uint    lrcReward;
        uint    lrcFee;
        uint    splitS;
        uint    splitB;
    }
    ////////////////////////////////////////////////////////////////////////////
    /// Constructor                                                          ///
    ////////////////////////////////////////////////////////////////////////////
    function LoopringProtocolImpl(
        address _lrcTokenAddress,
        address _tokenRegistryAddress,
        address _ringhashRegistryAddress,
        address _delegateAddress,
        uint    _maxRingSize,
        uint    _rateRatioCVSThreshold
        )
        public
    {
        require(0x0 != _lrcTokenAddress);
        require(0x0 != _tokenRegistryAddress);
        require(0x0 != _ringhashRegistryAddress);
        require(0x0 != _delegateAddress);
        require(_maxRingSize > 1);
        require(_rateRatioCVSThreshold > 0);
        lrcTokenAddress = _lrcTokenAddress;
        tokenRegistryAddress = _tokenRegistryAddress;
        ringhashRegistryAddress = _ringhashRegistryAddress;
        delegateAddress = _delegateAddress;
        maxRingSize = _maxRingSize;
        rateRatioCVSThreshold = _rateRatioCVSThreshold;
    }
    ////////////////////////////////////////////////////////////////////////////
    /// Public Functions                                                     ///
    ////////////////////////////////////////////////////////////////////////////
    /// @dev Disable default function.
    function () payable public {
        revert();
    }
    /// @dev Submit a order-ring for validation and settlement.
    /// @param addressList  List of each order's tokenS. Note that next order's
    ///                     `tokenS` equals this order's `tokenB`.
    /// @param uintArgsList List of uint-type arguments in this order:
    ///                     amountS, amountB, timestamp, ttl, salt, lrcFee,
    ///                     rateAmountS.
    /// @param uint8ArgsList -
    ///                     List of unit8-type arguments, in this order:
    ///                     marginSplitPercentageList,feeSelectionList.
    /// @param buyNoMoreThanAmountBList -
    ///                     This indicates when a order should be considered
    ///                     as 'completely filled'.
    /// @param vList        List of v for each order. This list is 1-larger than
    ///                     the previous lists, with the last element being the
    ///                     v value of the ring signature.
    /// @param rList        List of r for each order. This list is 1-larger than
    ///                     the previous lists, with the last element being the
    ///                     r value of the ring signature.
    /// @param sList        List of s for each order. This list is 1-larger than
    ///                     the previous lists, with the last element being the
    ///                     s value of the ring signature.
    /// @param ringminer    The address that signed this tx.
    /// @param feeRecipient The Recipient address for fee collection. If this is
    ///                     '0x0', all fees will be paid to the address who had
    ///                     signed this transaction, not `msg.sender`. Noted if
    ///                     LRC need to be paid back to order owner as the result
    ///                     of fee selection model, LRC will also be sent from
    ///                     this address.
    function submitRing(
        address[2][]  addressList,
        uint[7][]     uintArgsList,
        uint8[2][]    uint8ArgsList,
        bool[]        buyNoMoreThanAmountBList,
        uint8[]       vList,
        bytes32[]     rList,
        bytes32[]     sList,
        address       ringminer,
        address       feeRecipient
        )
        public
    {
        // Check if the highest bit of ringIndex is '1'.
        require(ringIndex & ENTERED_MASK != ENTERED_MASK); // "attempted to re-ent submitRing function");
        // Set the highest bit of ringIndex to '1'.
        ringIndex |= ENTERED_MASK;
        //Check ring size
        uint ringSize = addressList.length;
        require(ringSize > 1 && ringSize <= maxRingSize); // "invalid ring size");
        verifyInputDataIntegrity(
            ringSize,
            addressList,
            uintArgsList,
            uint8ArgsList,
            buyNoMoreThanAmountBList,
            vList,
            rList,
            sList
        );
        verifyTokensRegistered(ringSize, addressList);
        var (ringhash, ringhashAttributes) = RinghashRegistry(
            ringhashRegistryAddress
        ).computeAndGetRinghashInfo(
            ringSize,
            ringminer,
            vList,
            rList,
            sList
        );
        //Check if we can submit this ringhash.
        require(ringhashAttributes[0]); // "Ring claimed by others");
        verifySignature(
            ringminer,
            ringhash,
            vList[ringSize],
            rList[ringSize],
            sList[ringSize]
        );
        //Assemble input data into structs so we can pass them to other functions.
        OrderState[] memory orders = assembleOrders(
            addressList,
            uintArgsList,
            uint8ArgsList,
            buyNoMoreThanAmountBList,
            vList,
            rList,
            sList
        );
        if (feeRecipient == 0x0) {
            feeRecipient = ringminer;
        }
        handleRing(
            ringSize,
            ringhash,
            orders,
            ringminer,
            feeRecipient,
            ringhashAttributes[1]
        );
        ringIndex = (ringIndex ^ ENTERED_MASK) + 1;
    }
    /// @dev Cancel a order. cancel amount(amountS or amountB) can be specified
    ///      in orderValues.
    /// @param addresses          owner, tokenS, tokenB
    /// @param orderValues        amountS, amountB, timestamp, ttl, salt, lrcFee,
    ///                           cancelAmountS, and cancelAmountB.
    /// @param buyNoMoreThanAmountB -
    ///                           This indicates when a order should be considered
    ///                           as 'completely filled'.
    /// @param marginSplitPercentage -
    ///                           Percentage of margin split to share with miner.
    /// @param v                  Order ECDSA signature parameter v.
    /// @param r                  Order ECDSA signature parameters r.
    /// @param s                  Order ECDSA signature parameters s.
    function cancelOrder(
        address[3] addresses,
        uint[7]    orderValues,
        bool       buyNoMoreThanAmountB,
        uint8      marginSplitPercentage,
        uint8      v,
        bytes32    r,
        bytes32    s
        )
        external
    {
        uint cancelAmount = orderValues[6];
        require(cancelAmount > 0); // "amount to cancel is zero");
        Order memory order = Order(
            addresses[0],
            addresses[1],
            addresses[2],
            orderValues[0],
            orderValues[1],
            orderValues[5],
            buyNoMoreThanAmountB,
            marginSplitPercentage
        );
        require(msg.sender == order.owner); // "cancelOrder not submitted by order owner");
        bytes32 orderHash = calculateOrderHash(
            order,
            orderValues[2], // timestamp
            orderValues[3], // ttl
            orderValues[4]  // salt
        );
        verifySignature(
            order.owner,
            orderHash,
            v,
            r,
            s
        );
        cancelledOrFilled[orderHash] = cancelledOrFilled[orderHash].add(cancelAmount);
        OrderCancelled(orderHash, cancelAmount);
    }
    /// @dev   Set a cutoff timestamp to invalidate all orders whose timestamp
    ///        is smaller than or equal to the new value of the address's cutoff
    ///        timestamp.
    /// @param cutoff The cutoff timestamp, will default to `block.timestamp`
    ///        if it is 0.
    function setCutoff(uint cutoff)
        external
    {
        uint t = (cutoff == 0 || cutoff >= block.timestamp) ? block.timestamp : cutoff;
        require(cutoffs[msg.sender] < t); // "attempted to set cutoff to a smaller value"
        cutoffs[msg.sender] = t;
        CutoffTimestampChanged(msg.sender, t);
    }
    ////////////////////////////////////////////////////////////////////////////
    /// Internal & Private Functions                                         ///
    ////////////////////////////////////////////////////////////////////////////
    /// @dev Validate a ring.
    function verifyRingHasNoSubRing(
        uint          ringSize,
        OrderState[]  orders
        )
        private
        pure
    {
        // Check the ring has no sub-ring.
        for (uint i = 0; i < ringSize - 1; i++) {
            address tokenS = orders[i].order.tokenS;
            for (uint j = i + 1; j < ringSize; j++) {
                require(tokenS != orders[j].order.tokenS); // "found sub-ring");
            }
        }
    }
    function verifyTokensRegistered(
        uint          ringSize,
        address[2][]  addressList
        )
        private
        view
    {
        // Extract the token addresses
        address[] memory tokens = new address[](ringSize);
        for (uint i = 0; i < ringSize; i++) {
            tokens[i] = addressList[i][1];
        }
        // Test all token addresses at once
        require(
            TokenRegistry(tokenRegistryAddress).areAllTokensRegistered(tokens)
        ); // "token not registered");
    }
    function handleRing(
        uint          ringSize,
        bytes32       ringhash,
        OrderState[]  orders,
        address       miner,
        address       feeRecipient,
        bool          isRinghashReserved
        )
        private
    {
        uint64 _ringIndex = ringIndex ^ ENTERED_MASK;
        address _lrcTokenAddress = lrcTokenAddress;
        TokenTransferDelegate delegate = TokenTransferDelegate(delegateAddress);
        // Do the hard work.
        verifyRingHasNoSubRing(ringSize, orders);
        // Exchange rates calculation are performed by ring-miners as solidity
        // cannot get power-of-1/n operation, therefore we have to verify
        // these rates are correct.
        verifyMinerSuppliedFillRates(ringSize, orders);
        // Scale down each order independently by substracting amount-filled and
        // amount-cancelled. Order owner's current balance and allowance are
        // not taken into consideration in these operations.
        scaleRingBasedOnHistoricalRecords(delegate, ringSize, orders);
        // Based on the already verified exchange rate provided by ring-miners,
        // we can furthur scale down orders based on token balance and allowance,
        // then find the smallest order of the ring, then calculate each order's
        // `fillAmountS`.
        calculateRingFillAmount(ringSize, orders);
        // Calculate each order's `lrcFee` and `lrcRewrard` and splict how much
        // of `fillAmountS` shall be paid to matching order or miner as margin
        // split.
        calculateRingFees(
            delegate,
            ringSize,
            orders,
            feeRecipient,
            _lrcTokenAddress
        );
        /// Make transfers.
        var (orderHashList, amountsList) = settleRing(
            delegate,
            ringSize,
            orders,
            feeRecipient,
            _lrcTokenAddress
        );
        RingMined(
            _ringIndex,
            ringhash,
            miner,
            feeRecipient,
            isRinghashReserved,
            orderHashList,
            amountsList
        );
    }
    function settleRing(
        TokenTransferDelegate delegate,
        uint          ringSize,
        OrderState[]  orders,
        address       feeRecipient,
        address       _lrcTokenAddress
        )
        private
        returns(
        bytes32[] memory orderHashList,
        uint[6][] memory amountsList)
    {
        bytes32[] memory batch = new bytes32[](ringSize * 6); // ringSize * (owner + tokenS + 4 amounts)
        orderHashList = new bytes32[](ringSize);
        amountsList = new uint[6][](ringSize);
        uint p = 0;
        for (uint i = 0; i < ringSize; i++) {
            OrderState memory state = orders[i];
            Order memory order = state.order;
            uint prevSplitB = orders[(i + ringSize - 1) % ringSize].splitB;
            uint nextFillAmountS = orders[(i + 1) % ringSize].fillAmountS;
            // Store owner and tokenS of every order
            batch[p] = bytes32(order.owner);
            batch[p+1] = bytes32(order.tokenS);
            // Store all amounts
            batch[p+2] = bytes32(state.fillAmountS - prevSplitB);
            batch[p+3] = bytes32(prevSplitB + state.splitS);
            batch[p+4] = bytes32(state.lrcReward);
            batch[p+5] = bytes32(state.lrcFee);
            p += 6;
            // Update fill records
            if (order.buyNoMoreThanAmountB) {
                cancelledOrFilled[state.orderHash] += nextFillAmountS;
            } else {
                cancelledOrFilled[state.orderHash] += state.fillAmountS;
            }
            orderHashList[i] = state.orderHash;
            amountsList[i][0] = state.fillAmountS + state.splitS;
            amountsList[i][1] = nextFillAmountS - state.splitB;
            amountsList[i][2] = state.lrcReward;
            amountsList[i][3] = state.lrcFee;
            amountsList[i][4] = state.splitS;
            amountsList[i][5] = state.splitB;
        }
        // Do all transactions
        delegate.batchTransferToken(_lrcTokenAddress, feeRecipient, batch);
    }
    /// @dev Verify miner has calculte the rates correctly.
    function verifyMinerSuppliedFillRates(
        uint          ringSize,
        OrderState[]  orders
        )
        private
        view
    {
        uint[] memory rateRatios = new uint[](ringSize);
        uint _rateRatioScale = RATE_RATIO_SCALE;
        for (uint i = 0; i < ringSize; i++) {
            uint s1b0 = orders[i].rate.amountS.mul(orders[i].order.amountB);
            uint s0b1 = orders[i].order.amountS.mul(orders[i].rate.amountB);
            require(s1b0 <= s0b1); // "miner supplied exchange rate provides invalid discount");
            rateRatios[i] = _rateRatioScale.mul(s1b0) / s0b1;
        }
        uint cvs = MathUint.cvsquare(rateRatios, _rateRatioScale);
        require(cvs <= rateRatioCVSThreshold); // "miner supplied exchange rate is not evenly discounted");
    }
    /// @dev Calculate each order's fee or LRC reward.
    function calculateRingFees(
        TokenTransferDelegate delegate,
        uint            ringSize,
        OrderState[]    orders,
        address         feeRecipient,
        address         _lrcTokenAddress
        )
        private
        view
    {
        bool checkedMinerLrcSpendable = false;
        uint minerLrcSpendable = 0;
        uint8 _marginSplitPercentageBase = MARGIN_SPLIT_PERCENTAGE_BASE;
        uint nextFillAmountS;
        for (uint i = 0; i < ringSize; i++) {
            OrderState memory state = orders[i];
            uint lrcReceiable = 0;
            if (state.lrcFee == 0) {
                // When an order's LRC fee is 0 or smaller than the specified fee,
                // we help miner automatically select margin-split.
                state.feeSelection = FEE_SELECT_MARGIN_SPLIT;
                state.order.marginSplitPercentage = _marginSplitPercentageBase;
            } else {
                uint lrcSpendable = getSpendable(
                    delegate,
                    _lrcTokenAddress,
                    state.order.owner
                );
                // If the order is selling LRC, we need to calculate how much LRC
                // is left that can be used as fee.
                if (state.order.tokenS == _lrcTokenAddress) {
                    lrcSpendable -= state.fillAmountS;
                }
                // If the order is buyign LRC, it will has more to pay as fee.
                if (state.order.tokenB == _lrcTokenAddress) {
                    nextFillAmountS = orders[(i + 1) % ringSize].fillAmountS;
                    lrcReceiable = nextFillAmountS;
                }
                uint lrcTotal = lrcSpendable + lrcReceiable;
                // If order doesn't have enough LRC, set margin split to 100%.
                if (lrcTotal < state.lrcFee) {
                    state.lrcFee = lrcTotal;
                    state.order.marginSplitPercentage = _marginSplitPercentageBase;
                }
                if (state.lrcFee == 0) {
                    state.feeSelection = FEE_SELECT_MARGIN_SPLIT;
                }
            }
            if (state.feeSelection == FEE_SELECT_LRC) {
                if (lrcReceiable > 0) {
                    if (lrcReceiable >= state.lrcFee) {
                        state.splitB = state.lrcFee;
                        state.lrcFee = 0;
                    } else {
                        state.splitB = lrcReceiable;
                        state.lrcFee -= lrcReceiable;
                    }
                }
            } else if (state.feeSelection == FEE_SELECT_MARGIN_SPLIT) {
                // Only check the available miner balance when absolutely needed
                if (!checkedMinerLrcSpendable && minerLrcSpendable < state.lrcFee) {
                    checkedMinerLrcSpendable = true;
                    minerLrcSpendable = getSpendable(delegate, _lrcTokenAddress, feeRecipient);
                }
                // Only calculate split when miner has enough LRC;
                // otherwise all splits are 0.
                if (minerLrcSpendable >= state.lrcFee) {
                    nextFillAmountS = orders[(i + 1) % ringSize].fillAmountS;
                    uint split;
                    if (state.order.buyNoMoreThanAmountB) {
                        split = (nextFillAmountS.mul(
                            state.order.amountS
                        ) / state.order.amountB).sub(
                            state.fillAmountS
                        );
                    } else {
                        split = nextFillAmountS.sub(
                            state.fillAmountS.mul(
                                state.order.amountB
                            ) / state.order.amountS
                        );
                    }
                    if (state.order.marginSplitPercentage != _marginSplitPercentageBase) {
                        split = split.mul(
                            state.order.marginSplitPercentage
                        ) / _marginSplitPercentageBase;
                    }
                    if (state.order.buyNoMoreThanAmountB) {
                        state.splitS = split;
                    } else {
                        state.splitB = split;
                    }
                    // This implicits order with smaller index in the ring will
                    // be paid LRC reward first, so the orders in the ring does
                    // mater.
                    if (split > 0) {
                        minerLrcSpendable -= state.lrcFee;
                        state.lrcReward = state.lrcFee;
                    }
                }
                state.lrcFee = 0;
            } else {
                revert(); // "unsupported fee selection value");
            }
        }
    }
    /// @dev Calculate each order's fill amount.
    function calculateRingFillAmount(
        uint          ringSize,
        OrderState[]  orders
        )
        private
        pure
    {
        uint smallestIdx = 0;
        uint i;
        uint j;
        for (i = 0; i < ringSize; i++) {
            j = (i + 1) % ringSize;
            smallestIdx = calculateOrderFillAmount(
                orders[i],
                orders[j],
                i,
                j,
                smallestIdx
            );
        }
        for (i = 0; i < smallestIdx; i++) {
            calculateOrderFillAmount(
                orders[i],
                orders[(i + 1) % ringSize],
                0,               // Not needed
                0,               // Not needed
                0                // Not needed
            );
        }
    }
    /// @return The smallest order's index.
    function calculateOrderFillAmount(
        OrderState        state,
        OrderState        next,
        uint              i,
        uint              j,
        uint              smallestIdx
        )
        private
        pure
        returns (uint newSmallestIdx)
    {
        // Default to the same smallest index
        newSmallestIdx = smallestIdx;
        uint fillAmountB = state.fillAmountS.mul(
            state.rate.amountB
        ) / state.rate.amountS;
        if (state.order.buyNoMoreThanAmountB) {
            if (fillAmountB > state.order.amountB) {
                fillAmountB = state.order.amountB;
                state.fillAmountS = fillAmountB.mul(
                    state.rate.amountS
                ) / state.rate.amountB;
                newSmallestIdx = i;
            }
            state.lrcFee = state.order.lrcFee.mul(
                fillAmountB
            ) / state.order.amountB;
        } else {
            state.lrcFee = state.order.lrcFee.mul(
                state.fillAmountS
            ) / state.order.amountS;
        }
        if (fillAmountB <= next.fillAmountS) {
            next.fillAmountS = fillAmountB;
        } else {
            newSmallestIdx = j;
        }
    }
    /// @dev Scale down all orders based on historical fill or cancellation
    ///      stats but key the order's original exchange rate.
    function scaleRingBasedOnHistoricalRecords(
        TokenTransferDelegate delegate,
        uint ringSize,
        OrderState[] orders
        )
        private
        view
    {
        for (uint i = 0; i < ringSize; i++) {
            OrderState memory state = orders[i];
            Order memory order = state.order;
            uint amount;
            if (order.buyNoMoreThanAmountB) {
                amount = order.amountB.tolerantSub(
                    cancelledOrFilled[state.orderHash]
                );
                order.amountS = amount.mul(order.amountS) / order.amountB;
                order.lrcFee = amount.mul(order.lrcFee) / order.amountB;
                order.amountB = amount;
            } else {
                amount = order.amountS.tolerantSub(
                    cancelledOrFilled[state.orderHash]
                );
                order.amountB = amount.mul(order.amountB) / order.amountS;
                order.lrcFee = amount.mul(order.lrcFee) / order.amountS;
                order.amountS = amount;
            }
            require(order.amountS > 0); // "amountS is zero");
            require(order.amountB > 0); // "amountB is zero");
            uint availableAmountS = getSpendable(delegate, order.tokenS, order.owner);
            require(availableAmountS > 0); // "order spendable amountS is zero");
            state.fillAmountS = (
                order.amountS < availableAmountS ?
                order.amountS : availableAmountS
            );
        }
    }
    /// @return Amount of ERC20 token that can be spent by this contract.
    function getSpendable(
        TokenTransferDelegate delegate,
        address tokenAddress,
        address tokenOwner
        )
        private
        view
        returns (uint)
    {
        ERC20 token = ERC20(tokenAddress);
        uint allowance = token.allowance(
            tokenOwner,
            address(delegate)
        );
        uint balance = token.balanceOf(tokenOwner);
        return (allowance < balance ? allowance : balance);
    }
    /// @dev verify input data's basic integrity.
    function verifyInputDataIntegrity(
        uint          ringSize,
        address[2][]  addressList,
        uint[7][]     uintArgsList,
        uint8[2][]    uint8ArgsList,
        bool[]        buyNoMoreThanAmountBList,
        uint8[]       vList,
        bytes32[]     rList,
        bytes32[]     sList
        )
        private
        pure
    {
        require(ringSize == addressList.length); // "ring data is inconsistent - addressList");
        require(ringSize == uintArgsList.length); // "ring data is inconsistent - uintArgsList");
        require(ringSize == uint8ArgsList.length); // "ring data is inconsistent - uint8ArgsList");
        require(ringSize == buyNoMoreThanAmountBList.length); // "ring data is inconsistent - buyNoMoreThanAmountBList");
        require(ringSize + 1 == vList.length); // "ring data is inconsistent - vList");
        require(ringSize + 1 == rList.length); // "ring data is inconsistent - rList");
        require(ringSize + 1 == sList.length); // "ring data is inconsistent - sList");
        // Validate ring-mining related arguments.
        for (uint i = 0; i < ringSize; i++) {
            require(uintArgsList[i][6] > 0); // "order rateAmountS is zero");
            require(uint8ArgsList[i][1] <= FEE_SELECT_MAX_VALUE); // "invalid order fee selection");
        }
    }
    /// @dev        assmble order parameters into Order struct.
    /// @return     A list of orders.
    function assembleOrders(
        address[2][]    addressList,
        uint[7][]       uintArgsList,
        uint8[2][]      uint8ArgsList,
        bool[]          buyNoMoreThanAmountBList,
        uint8[]         vList,
        bytes32[]       rList,
        bytes32[]       sList
        )
        private
        view
        returns (OrderState[] memory orders)
    {
        uint ringSize = addressList.length;
        orders = new OrderState[](ringSize);
        for (uint i = 0; i < ringSize; i++) {
            uint[7] memory uintArgs = uintArgsList[i];
            Order memory order = Order(
                addressList[i][0],
                addressList[i][1],
                addressList[(i + 1) % ringSize][1],
                uintArgs[0],
                uintArgs[1],
                uintArgs[5],
                buyNoMoreThanAmountBList[i],
                uint8ArgsList[i][0]
            );
            bytes32 orderHash = calculateOrderHash(
                order,
                uintArgs[2], // timestamp
                uintArgs[3], // ttl
                uintArgs[4]  // salt
            );
            verifySignature(
                order.owner,
                orderHash,
                vList[i],
                rList[i],
                sList[i]
            );
            validateOrder(
                order,
                uintArgs[2], // timestamp
                uintArgs[3], // ttl
                uintArgs[4]  // salt
            );
            orders[i] = OrderState(
                order,
                orderHash,
                uint8ArgsList[i][1],  // feeSelection
                Rate(uintArgs[6], order.amountB),
                0,   // fillAmountS
                0,   // lrcReward
                0,   // lrcFee
                0,   // splitS
                0    // splitB
            );
        }
    }
    /// @dev validate order's parameters are OK.
    function validateOrder(
        Order        order,
        uint         timestamp,
        uint         ttl,
        uint         salt
        )
        private
        view
    {
        require(order.owner != 0x0); // "invalid order owner");
        require(order.tokenS != 0x0); // "invalid order tokenS");
        require(order.tokenB != 0x0); // "invalid order tokenB");
        require(order.amountS != 0); // "invalid order amountS");
        require(order.amountB != 0); // "invalid order amountB");
        require(timestamp <= block.timestamp); // "order is too early to match");
        require(timestamp > cutoffs[order.owner]); // "order is cut off");
        require(ttl != 0); // "order ttl is 0");
        require(timestamp + ttl > block.timestamp); // "order is expired");
        require(salt != 0); // "invalid order salt");
        require(order.marginSplitPercentage <= MARGIN_SPLIT_PERCENTAGE_BASE); // "invalid order marginSplitPercentage");
    }
    /// @dev Get the Keccak-256 hash of order with specified parameters.
    function calculateOrderHash(
        Order        order,
        uint         timestamp,
        uint         ttl,
        uint         salt
        )
        private
        view
        returns (bytes32)
    {
        return keccak256(
            address(this),
            order.owner,
            order.tokenS,
            order.tokenB,
            order.amountS,
            order.amountB,
            timestamp,
            ttl,
            salt,
            order.lrcFee,
            order.buyNoMoreThanAmountB,
            order.marginSplitPercentage
        );
    }
    /// @dev Verify signer's signature.
    function verifySignature(
        address signer,
        bytes32 hash,
        uint8   v,
        bytes32 r,
        bytes32 s
        )
        private
        pure
    {
        require(
            signer == ecrecover(
                keccak256("\x19Ethereum Signed Message:\n32", hash),
                v,
                r,
                s
            )
        ); // "invalid signature");
    }
}

Contract Security Audit

Contract ABI

[{"constant":true,"inputs":[],"name":"ENTERED_MASK","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FEE_SELECT_MAX_VALUE","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MARGIN_SPLIT_PERCENTAGE_BASE","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ringIndex","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"addresses","type":"address[3]"},{"name":"orderValues","type":"uint256[7]"},{"name":"buyNoMoreThanAmountB","type":"bool"},{"name":"marginSplitPercentage","type":"uint8"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"cancelOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"RATE_RATIO_SCALE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lrcTokenAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"cancelledOrFilled","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenRegistryAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"delegateAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"addressList","type":"address[2][]"},{"name":"uintArgsList","type":"uint256[7][]"},{"name":"uint8ArgsList","type":"uint8[2][]"},{"name":"buyNoMoreThanAmountBList","type":"bool[]"},{"name":"vList","type":"uint8[]"},{"name":"rList","type":"bytes32[]"},{"name":"sList","type":"bytes32[]"},{"name":"ringminer","type":"address"},{"name":"feeRecipient","type":"address"}],"name":"submitRing","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"maxRingSize","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ringhashRegistryAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"cutoff","type":"uint256"}],"name":"setCutoff","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"FEE_SELECT_LRC","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"cutoffs","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"rateRatioCVSThreshold","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FEE_SELECT_MARGIN_SPLIT","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_lrcTokenAddress","type":"address"},{"name":"_tokenRegistryAddress","type":"address"},{"name":"_ringhashRegistryAddress","type":"address"},{"name":"_delegateAddress","type":"address"},{"name":"_maxRingSize","type":"uint256"},{"name":"_rateRatioCVSThreshold","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_ringIndex","type":"uint256"},{"indexed":true,"name":"_ringhash","type":"bytes32"},{"indexed":false,"name":"_miner","type":"address"},{"indexed":false,"name":"_feeRecipient","type":"address"},{"indexed":false,"name":"_isRinghashReserved","type":"bool"},{"indexed":false,"name":"_orderHashList","type":"bytes32[]"},{"indexed":false,"name":"_amountsList","type":"uint256[6][]"}],"name":"RingMined","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_orderHash","type":"bytes32"},{"indexed":false,"name":"_amountCancelled","type":"uint256"}],"name":"OrderCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_address","type":"address"},{"indexed":false,"name":"_cutoff","type":"uint256"}],"name":"CutoffTimestampChanged","type":"event"}]

606060405260008054600160a060020a031990811682556001805482169055600280548216905560038054909116905560048190556005805467ffffffffffffffff1916905560065534156200005457600080fd5b60405160c080620024d7833981016040528080519190602001805191906020018051919060200180519190602001805191906020018051915050600160a060020a0386161515620000a457600080fd5b600160a060020a0385161515620000ba57600080fd5b600160a060020a0384161515620000d057600080fd5b600160a060020a0383161515620000e657600080fd5b60018211620000f457600080fd5b600081116200010257600080fd5b60008054600160a060020a03978816600160a060020a031991821617909155600180549688169682169690961790955560028054948716948616949094179093556003805492909516919093161790925560045560065561236e80620001696000396000f3006060604052600436106100e25763ffffffff60e060020a6000350416631879749981146100e757806326ea9268146101175780632db237bb1461014057806341ffbc1f1461015357806347a99e43146101665780634a63864b1461019b5780634c0a6532146101c05780635511f319146101ef5780635be2aca0146102055780636d96a2aa14610218578063ca35947d1461022b578063cbc12d13146104a5578063d21b96ab146104b8578063d7bf9110146104cb578063db71d8b6146104e1578063de794c1e146104f4578063df565ca214610513578063e95d716c14610117575b600080fd5b34156100f257600080fd5b6100fa610526565b60405167ffffffffffffffff909116815260200160405180910390f35b341561012257600080fd5b61012a610532565b60405160ff909116815260200160405180910390f35b341561014b57600080fd5b61012a610537565b341561015e57600080fd5b6100fa61053c565b341561017157600080fd5b6101996004606461014435151560ff6101643581169061018435166101a4356101c43561054c565b005b34156101a657600080fd5b6101ae61068a565b60405190815260200160405180910390f35b34156101cb57600080fd5b6101d3610690565b604051600160a060020a03909116815260200160405180910390f35b34156101fa57600080fd5b6101ae60043561069f565b341561021057600080fd5b6101d36106b1565b341561022357600080fd5b6101d36106c0565b341561023657600080fd5b61019960046024813581810190830135806020818102016040519081016040528181529291906000602085015b828210156102a2576040808302860190600290805190810160405280929190826002602002808284375050509183525050600190910190602001610263565b505050505091908035906020019082018035906020019080806020026020016040519081016040528181529291906000602085015b828210156103135760e08083028601906007906040519081016040529190828260e08082843750505091835250506001909101906020016102d7565b505050505091908035906020019082018035906020019080806020026020016040519081016040528181529291906000602085015b82821015610387576040808302860190600290805190810160405280929190826002602002808284375050509183525050600190910190602001610348565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284375094965050600160a060020a038535811695602001351693506106cf92505050565b34156104b057600080fd5b6101ae610995565b34156104c357600080fd5b6101d361099b565b34156104d657600080fd5b6101996004356109aa565b34156104ec57600080fd5b61012a610a41565b34156104ff57600080fd5b6101ae600160a060020a0360043516610a46565b341561051e57600080fd5b6101ae610a58565b67800000000000000081565b600181565b606481565b60055467ffffffffffffffff1681565b6000610556612214565b60c08801359150600080831161056b57600080fd5b6101006040519081016040908152600160a060020a038c35811683526020808e01358216818501528d830135909116918301919091528a3560608301528a0135608082015260a0808b01359082015288151560c082015260ff881660e082015291508151600160a060020a031633600160a060020a03161415156105ee57600080fd5b6106068260408b013560608c013560808d0135610a5e565b9050610616825182888888610b40565b600081815260076020526040902054610635908463ffffffff610c0516565b600082815260076020526040908190209190915581907f3e1003227205ab9eb9b1652e25b2f6fc548ff55e94bf76a42aca90501c6c4e359085905190815260200160405180910390a250505050505050505050565b61271081565b600054600160a060020a031681565b60076020526000908152604090205481565b600154600160a060020a031681565b600354600160a060020a031681565b6000806106da612258565b6106e261227f565b60055467800000000000000090811614156106fc57600080fd5b6005805467ffffffffffffffff808216678000000000000000171667ffffffffffffffff199091161790558c51935060018411801561073d57506004548411155b151561074857600080fd5b610758848e8e8e8e8e8e8e610c1b565b610762848e610cf0565b600254600160a060020a03166393d9bf3085888c8c8c6000604051606001526040518663ffffffff1660e060020a0281526004018086815260200185600160a060020a0316600160a060020a03168152602001806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156107f95780820151838201526020016107e1565b50505050905001848103835286818151815260200191508051906020019060200280838360005b83811015610838578082015183820152602001610820565b50505050905001848103825285818151815260200191508051906020019060200280838360005b8381101561087757808201518382015260200161085f565b5050505090500198505050505050505050606060405180830381600087803b15156108a157600080fd5b6102c65a03f115156108b257600080fd5b50505060405180516060820160405293506020019150815115156108d557600080fd5b61092186848b87815181106108e657fe5b906020019060200201518b88815181106108fc57fe5b906020019060200201518b898151811061091257fe5b90602001906020020151610b40565b6109308d8d8d8d8d8d8d610e2a565b9050600160a060020a0385161515610946578594505b61095884848389896020880151611094565b50506005805467ffffffffffffffff808216678000000000000000186001011667ffffffffffffffff199091161790555050505050505050505050565b60045481565b600254600160a060020a031681565b60008115806109b95750428210155b6109c357816109c5565b425b600160a060020a0333166000908152600860205260409020549091508190106109ed57600080fd5b600160a060020a033316600081815260086020526040908190208390557f6153a6969dac97e9622b2006c92f14fe5d5399d661739d1518b0cafd1e767bed9083905190815260200160405180910390a25050565b600081565b60086020526000908152604090205481565b60065481565b600030855186602001518760400151886060015189608001518989898d60a001518e60c001518f60e001516040516c01000000000000000000000000600160a060020a039d8e16810282529b8d168c026014820152998c168b0260288b015297909a16909802603c88015260508701949094526070860192909252609085015260b084015260d083015260f08201929092527f0100000000000000000000000000000000000000000000000000000000000000921515830261011082015260ff9091169091026101118201526101120160405180910390209050949350505050565b6001846040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0160405180910390208484846040516000815260200160405260006040516020015260405193845260ff90921660208085019190915260408085019290925260608401929092526080909201915160208103908084039060008661646e5a03f11515610bde57600080fd5b505060206040510351600160a060020a03868116911614610bfe57600080fd5b5050505050565b81810182811015610c1557600080fd5b92915050565b600087518914610c2a57600080fd5b86518914610c3757600080fd5b85518914610c4457600080fd5b84518914610c5157600080fd5b835160018a0114610c6157600080fd5b825160018a0114610c7157600080fd5b815160018a0114610c8157600080fd5b5060005b88811015610ce5576000878281518110610c9b57fe5b9060200190602002015160c0015111610cb357600080fd5b6001868281518110610cc157fe5b906020019060200201516020015160ff161115610cdd57600080fd5b600101610c85565b505050505050505050565b610cf861227f565b600083604051805910610d085750595b90808252806020026020018201604052509150600090505b83811015610d6d57828181518110610d3457fe5b9060200190602002015160200151828281518110610d4e57fe5b600160a060020a03909216602092830290910190910152600101610d20565b600154600160a060020a03166316066e69836000604051602001526040518263ffffffff1660e060020a0281526004018080602001828103825283818151815260200191508051906020019060200280838360005b83811015610dda578082015183820152602001610dc2565b5050505090500192505050602060405180830381600087803b1515610dfe57600080fd5b6102c65a03f11515610e0f57600080fd5b505050604051805190501515610e2457600080fd5b50505050565b610e3261227f565b600080610e3d612291565b610e45612214565b60008c51945084604051805910610e595750595b908082528060200260200182016040528015610e8f57816020015b610e7c6122b8565b815260200190600190039081610e745790505b509550600093505b84841015611084578b8481518110610eab57fe5b906020019060200201519250610100604051908101604052808e8681518110610ed057fe5b9060200190602002015151600160a060020a031681526020018e8681518110610ef557fe5b9060200190602002015160200151600160a060020a031681526020018e8787600101811515610f2057fe5b0681518110610f2b57fe5b9060200190602002015160200151600160a060020a03168152602001845181526020018460016020020151815260200160a085015181526020018b8681518110610f7157fe5b90602001906020020151151581526020018c8681518110610f8e57fe5b906020019060200201515160ff1690529150610fb882604085015160608601516080870151610a5e565b9050610fcc8251828b87815181106108e657fe5b610fe48260408501516060860151608087015161123f565b61012060405190810160409081528382526020820183905281018c868151811061100a57fe5b906020019060200201516020015160ff168152602001604080519081016040528060c087015181526020018560800151815250815260200160008152602001600081526020016000815260200160008152602001600081525086858151811061106f57fe5b60209081029091010152600190930192610e97565b5050505050979650505050505050565b60008060006110a161227f565b6110a961227f565b60055460005460035467ffffffffffffffff909216678000000000000000189650600160a060020a0390811695501692506110e48b8a61131a565b6110ee8b8a61139b565b6110f9838c8b6114de565b6111038b8a6116a6565b611110838c8b8a88611768565b61111d838c8b8a88611a82565b9092509050897f1b8337f5092681bc841e8399eb24528eb0cf3a3ea0eaaf1615afd56f61b0ea28868a8a8a878760405167ffffffffffffffff87168152600160a060020a03808716602083015285166040820152831515606082015260c0608082018181529060a0830190830185818151815260200191508051906020019060200280838360005b838110156111bd5780820151838201526020016111a5565b505050509050018381038252848181518152602001915080516000925b8184101561121c5760208085028401015160c080838360005b8381101561120b5780820151838201526020016111f3565b5050505090500192600101926111da565b925050509850505050505050505060405180910390a25050505050505050505050565b8351600160a060020a0316151561125557600080fd5b8360200151600160a060020a0316151561126e57600080fd5b8360400151600160a060020a0316151561128757600080fd5b8360600151151561129757600080fd5b836080015115156112a757600080fd5b428311156112b457600080fd5b600860008551600160a060020a0316815260208101919091526040016000205483116112df57600080fd5b8115156112eb57600080fd5b42838301116112f957600080fd5b80151561130557600080fd5b606460e085015160ff161115610e2457600080fd5b600080805b60018503831015610bfe5783838151811061133657fe5b906020019060200201515160200151915050600182015b848110156113905783818151811061136157fe5b906020019060200201515160200151600160a060020a038381169116141561138857600080fd5b60010161134d565b60019092019161131f565b6113a361227f565b6000806000806000876040518059106113b95750595b908082528060200260200182016040525095506127109450600093505b878410156114b8576114238785815181106113ed57fe5b90602001906020020151516080015188868151811061140857fe5b9060200190602002015160600151519063ffffffff611e9516565b925061146d87858151811061143457fe5b90602001906020020151606001516020015188868151811061145257fe5b9060200190602002015151606001519063ffffffff611e9516565b91508183111561147c57600080fd5b8161148d868563ffffffff611e9516565b81151561149657fe5b048685815181106114a357fe5b602090810290910101526001909301926113d6565b6114c28686611eba565b6006549091508111156114d457600080fd5b5050505050505050565b60006114e86122b8565b6114f0612214565b600080600094505b868510156114d45785858151811061150c57fe5b906020019060200201519350835192508260c00151156115b457611554600760008660200151815260208101919091526040016000205460808501519063ffffffff611fd416565b915082608001516115708460600151849063ffffffff611e9516565b81151561157957fe5b04606084015260808301516115998460a00151849063ffffffff611e9516565b8115156115a257fe5b0460a08401526080830182905261163e565b6115e2600760008660200151815260208101919091526040016000205460608501519063ffffffff611fd416565b915082606001516115fe8460800151849063ffffffff611e9516565b81151561160757fe5b04608084015260608301516116278460a00151849063ffffffff611e9516565b81151561163057fe5b0460a0840152606083018290525b600083606001511161164f57600080fd5b600083608001511161166057600080fd5b6116708884602001518551611ff0565b90506000811161167f57600080fd5b808360600151106116905780611696565b82606001515b60808501526001909401936114f8565b600080805b848210156117085784826001018115156116c157fe5b0690506116fb8483815181106116d357fe5b906020019060200201518583815181106116e957fe5b906020019060200201518484876120fc565b92506001909101906116ab565b600091505b82821015610bfe5761175c84838151811061172457fe5b9060200190602002015185878560010181151561173d57fe5b068151811061174857fe5b9060200190602002015160008060006120fc565b5060019091019061170d565b60008060008060006117786122b8565b600080600080600099506000985060649750600095505b8d861015611a71578c86815181106117a357fe5b906020019060200201519450600093508460c0015115156117d9576001604086015287855160ff90911660e09190910152611899565b6117e68f8c875151611ff0565b9250600160a060020a038b16855160200151600160a060020a03161415611811578460800151830392505b600160a060020a038b16855160400151600160a060020a0316141561185e578c8e8760010181151561183f57fe5b068151811061184a57fe5b906020019060200201516080015196508693505b83830191508460c001518210156118865760c0850182905287855160ff90911660e091909101525b8460c00151151561189957600160408601525b6000604086015160ff1614156118ee5760008411156118e9578460c0015184106118d4578460c00151610100860152600060c08601526118e9565b61010085018490528360c08601818151039052505b611a66565b6001604086015160ff1614156100e2578915801561190f57508460c0015189105b1561192657600199506119238f8c8e611ff0565b98505b8460c001518910611a5e578c8e8760010181151561194057fe5b068151811061194b57fe5b90602001906020020151608001519650845160c00151156119a7576119a0856080015186516080015161198a8851606001518b9063ffffffff611e9516565b81151561199357fe5b049063ffffffff61220516565b90506119e5565b6119e28551606001516119ca87516080015188608001519063ffffffff611e9516565b8115156119d357fe5b8991900463ffffffff61220516565b90505b60ff8816855160e0015160ff1614611a215760ff8816611a14865160e00151839060ff1663ffffffff611e9516565b811515611a1d57fe5b0490505b845160c0015115611a385760e08501819052611a41565b61010085018190525b6000811115611a5e578460c00151890398508460c0015160a08601525b600060c08601525b60019095019461178f565b505050505050505050505050505050565b611a8a61227f565b611a9261227f565b611a9a61227f565b600080611aa56122b8565b611aad612214565b6000808c600602604051805910611ac15750595b908082528060200260200182016040525096508c604051805910611ae25750595b908082528060200260200182016040525098508c604051805910611b035750595b908082528060200260200182016040528015611b3957816020015b611b26612311565b815260200190600190039081611b1e5790505b50975060009550600094505b8c851015611dcb578b8581518110611b5957fe5b906020019060200201519350835192508b8d60018f880103811515611b7a57fe5b0681518110611b8557fe5b90602001906020020151610100015191508b8d86600101811515611ba557fe5b0681518110611bb057fe5b906020019060200201516080015190508251600160a060020a0316878781518110611bd757fe5b6020908102909101810191909152830151600160a060020a0316876001880181518110611c0057fe5b6020908102909101015281608085015103876002880181518110611c2057fe5b6020908102909101015260e08401518201876003880181518110611c4057fe5b6020908102909101015260a0840151876004880181518110611c5e57fe5b6020908102909101015260c0840151876005880181518110611c7c57fe5b602090810290910101526006959095019460c083015115611cbd57806007600086602001518152602081019190915260400160002080549091019055611ce3565b836080015160076000866020015181526020810191909152604001600020805490910190555b8360200151898681518110611cf457fe5b6020908102909101015260e0840151846080015101888681518110611d1557fe5b90602001906020020151526101008401518103888681518110611d3457fe5b906020019060200201516020015260a0840151888681518110611d5357fe5b906020019060200201516040015260c0840151888681518110611d7257fe5b906020019060200201516060015260e0840151888681518110611d9157fe5b9060200190602002015160800152610100840151888681518110611db157fe5b9060200190602002015160a0015260019490940193611b45565b8d600160a060020a0316638a8bf82a8b8d8a60405160e060020a63ffffffff8616028152600160a060020a03808516600483019081529084166024830152606060448301908152909160640183818151815260200191508051906020019060200280838360005b83811015611e4a578082015183820152602001611e32565b50505050905001945050505050600060405180830381600087803b1515611e7057600080fd5b6102c65a03f11515611e8157600080fd5b505050505050505050509550959350505050565b818102821580611eaf5750818382811515611eac57fe5b04145b1515610c1557600080fd5b60008060008060008060008851955060018611611ed657600080fd5b60008811611ee357600080fd5b60009450600093505b85841015611f1957888481518110611f0057fe5b9060200190602002015190940193600190930192611eec565b8585811515611f2457fe5b049450841515611f375760009650611fc8565b60009250600093505b85841015611f8e57888481518110611f5457fe5b906020019060200201519050848111611f6f57808503611f73565b8481035b9150611f7f8283611e95565b60019094019390920191611f40565b600186038586611fa7611fa1878d611e95565b8c611e95565b811515611fb057fe5b04811515611fba57fe5b04811515611fc457fe5b0496505b50505050505092915050565b600081831015611fe5576000611fe9565b8183035b9392505050565b6000828180600160a060020a03831663dd62ed3e8689846040516020015260405160e060020a63ffffffff8516028152600160a060020a03928316600482015291166024820152604401602060405180830381600087803b151561205357600080fd5b6102c65a03f1151561206457600080fd5b5050506040518051925050600160a060020a0383166370a082318660006040516020015260405160e060020a63ffffffff8416028152600160a060020a039091166004820152602401602060405180830381600087803b15156120c657600080fd5b6102c65a03f115156120d757600080fd5b50505060405180519150508082106120ef57806120f1565b815b979650505050505050565b80600060608701515161212288606001516020015189608001519063ffffffff611e9516565b81151561212b57fe5b049050865160c00151156121b05786516080015181111561218057865160800151905086606001516020015161216d886060015151839063ffffffff611e9516565b81151561217657fe5b0460808801528491505b86516080015161219c82895160a001519063ffffffff611e9516565b8115156121a557fe5b0460c08801526121e0565b8651606001516121d08860800151895160a001519063ffffffff611e9516565b8115156121d957fe5b0460c08801525b856080015181116121f757608086018190526121fb565b8391505b5095945050505050565b600082821115611fe557600080fd5b6101006040519081016040908152600080835260208301819052908201819052606082018190526080820181905260a0820181905260c0820181905260e082015290565b604080519081016040526002815b6000815260001990910190602001816122665790505090565b60206040519081016040526000815290565b60e06040519081016040526007815b60008152602001906001900390816122a05790505090565b610220604051908101604052806122cd612214565b815260006020820181905260408201526060016122e861232b565b815260200160008152602001600081526020016000815260200160008152602001600081525090565b60c0604051908101604052600081526005602082016122a0565b6040805190810160405260008082526020820152905600a165627a7a723058209e6fc5ee2d5c5d144af1c7cabd0b3248a935dc14fca0462be990b0e5b2ba66ab0029000000000000000000000000ef68e7c694f40c8202821edf525de3782458639f000000000000000000000000974e1e639b5a3c5f44909e1959ab786af21b7086000000000000000000000000ee445e921f481c04a5d254a7f8f013f48a6f0947000000000000000000000000450d10a0c61f2b007384128b626f28b757a75e490000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000f424

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000ef68e7c694f40c8202821edf525de3782458639f000000000000000000000000974e1e639b5a3c5f44909e1959ab786af21b7086000000000000000000000000ee445e921f481c04a5d254a7f8f013f48a6f0947000000000000000000000000450d10a0c61f2b007384128b626f28b757a75e490000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000f424

-----Decoded View---------------
Arg [0] : _lrcTokenAddress (address): 0xEF68e7C694F40c8202821eDF525dE3782458639f
Arg [1] : _tokenRegistryAddress (address): 0x974e1e639b5a3c5f44909E1959Ab786AF21B7086
Arg [2] : _ringhashRegistryAddress (address): 0xeE445e921F481c04A5d254A7F8f013F48A6f0947
Arg [3] : _delegateAddress (address): 0x450D10A0C61f2b007384128B626F28b757A75e49
Arg [4] : _maxRingSize (uint256): 5
Arg [5] : _rateRatioCVSThreshold (uint256): 62500

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000ef68e7c694f40c8202821edf525de3782458639f
Arg [1] : 000000000000000000000000974e1e639b5a3c5f44909e1959ab786af21b7086
Arg [2] : 000000000000000000000000ee445e921f481c04a5d254a7f8f013f48a6f0947
Arg [3] : 000000000000000000000000450d10a0c61f2b007384128b626f28b757a75e49
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [5] : 000000000000000000000000000000000000000000000000000000000000f424


Swarm Source

bzzr://9e6fc5ee2d5c5d144af1c7cabd0b3248a935dc14fca0462be990b0e5b2ba66ab
Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.