Latest 25 transactions from a total of 381 transactions

TxHash Age From To Value [TxFee]
0xf577ba0e022d41bc2f67c0f631ca3c10c7f0f0ca1bec1cf5d8dec08cad2c29f998 days 4 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.004465247
0xfbe2b6908154f0a426bb05c3d4e0f27d61a0348be512c17fed89423a8af83a0d98 days 5 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.40056116 Ether0.0031250792
0x0990ab1cfd7dd5c69c869defa2ab39577ad6dbe7cb5af71058bdec52c058472e99 days 37 mins ago0xd2ed0cce635ce28c27808e50faff595992687656  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30 Ether0.00242275
0xefa36c504c0b2034d895417fad91ea434c6afdac7578f3ce92768f74c61b9b5a99 days 5 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30 Ether0.004405
0xccfac3e2b5717ca513ee5e137b0949451bbd773771fbb06a56bb9ba54bc45f5499 days 20 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.004618908
0x59f09284365dada094ce94532125efc3af0eb8079a43f4e5bdda3d24b851d72f99 days 20 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.000219948
0xb473fa5918ebf13e7a7424cc4495f89b2d54ae7c1a3153839ff4ca2aa003a91999 days 21 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.004618908
0xd255f113152cd61044d679158f76e7417077ed5cc21a0c8c01a8a586eda0f80899 days 22 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.004838856
0x13181248d8974dfcf0ce37bc36b5ea68fb445b45d54907676baf93f130d4662799 days 22 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.0045529236
0x63ea7fb16f70acf9a6d4227ab9d71eaac130705edc6f8843399abe58308ff720100 days 1 hr ago0x504fd11ff211b01537a6406f11239b08e3c104ab  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30 Ether0.000330464
0xf73403d1fded8e44272d95e84ec91694c9fd453e09240975b8fad3d004cb967b100 days 7 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.1 Ether0.00440024
0xbc626da87c8702cba8d5da3ac994468104bbf3e93b1004729a4da24483efe611100 days 7 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.01 Ether0.004618908
0x0e40aca5b14f456f930685b9831701af4430976dbc6fb2a701c6a2ac6fed5bd2100 days 19 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.1 Ether0.003960216
0xd510ad0334c06d37a73567d152a885df5a95571ec6e3382f45810ac88171d8fe100 days 19 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30 Ether0.003524
0x418fdbf9834b08d3adee63106aaa2eb0ad637dd569b31d5b56475ca107b2c0d9100 days 22 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30 Ether0.004405
0xa8a3466b9816deeed7f9b713f81dd02ab1893afc5ef1a4571caa7d4ad4a0cc57100 days 22 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30 Ether0.004405
0x727a31916543f8ef269614c4f21f0cc1c48d9d812540733015caea6a34f04080100 days 22 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30 Ether0.00022025
0x9f550751fd9a5b8bd4f95f702fb67ee1f779187081ff229664a01f433f20b874101 days 2 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.00219948
0x7ba7ac42be6a0e367067afcec1aba7905a64c7141dd3b2357a4ad903d4d4d633101 days 2 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.00219948
0x6f333fd0d1c7595f39941d77e63599df4251d8e13c7eca946da027abc5d3cb44101 days 21 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.00439896
0xbc64f9300d5c2139380f374d81e5a66aa222a7bd5cc13801441867592015ff05102 days 2 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.0022654644
0xa411c6de9297c18e0cbd04d2e987901c525b4485340184b211fc8acdc69a8221102 days 3 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.0021554904
0x628957dc9a033ed39364bae7a09a33627e4c3f0bb04696b2364480f38dc959f3102 days 3 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.00219948
0x67a571ef56820ac46112171fdf3ffcf22a89c2be436f9b06bad07d43116ad83f102 days 3 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.0023754384
0x81fbd0c5b1f78d57f63c45b891e5f360a00a1373cc8a9877a6602bd3067366bc102 days 3 hrs ago0xfac6a008e1ad0a0bcb261b10206fe928e76a7b06  IN   0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30.03 Ether0.0028373292
[ Download CSV Export  ] 
 Internal Transactions as a result of Contract Execution
 Latest 25 Internal Txns, Click here To View More View All
ParentTxHash Block Age From To Value
0xf577ba0e022d41bc2f67c0f631ca3c10c7f0f0ca1bec1cf5d8dec08cad2c29f9335366798 days 4 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70.03 Ether
0xfbe2b6908154f0a426bb05c3d4e0f27d61a0348be512c17fed89423a8af83a0d335330298 days 5 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70.40056116 Ether
0x0990ab1cfd7dd5c69c869defa2ab39577ad6dbe7cb5af71058bdec52c058472e334876599 days 37 mins ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70 Ether
0x0990ab1cfd7dd5c69c869defa2ab39577ad6dbe7cb5af71058bdec52c058472e334876599 days 37 mins ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x34a54511e2e5706e3cdd28b02cd81fdb70673f8b0 Ether
0x0990ab1cfd7dd5c69c869defa2ab39577ad6dbe7cb5af71058bdec52c058472e334876599 days 37 mins ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x34a54511e2e5706e3cdd28b02cd81fdb70673f8b0 Ether
0xefa36c504c0b2034d895417fad91ea434c6afdac7578f3ce92768f74c61b9b5a334756899 days 5 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70 Ether
0xefa36c504c0b2034d895417fad91ea434c6afdac7578f3ce92768f74c61b9b5a334756899 days 5 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x34a54511e2e5706e3cdd28b02cd81fdb70673f8b0 Ether
0xefa36c504c0b2034d895417fad91ea434c6afdac7578f3ce92768f74c61b9b5a334756899 days 5 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x34a54511e2e5706e3cdd28b02cd81fdb70673f8b0 Ether
0xccfac3e2b5717ca513ee5e137b0949451bbd773771fbb06a56bb9ba54bc45f54334393799 days 20 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70.03 Ether
0x59f09284365dada094ce94532125efc3af0eb8079a43f4e5bdda3d24b851d72f334391699 days 20 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70.03 Ether
0xb473fa5918ebf13e7a7424cc4495f89b2d54ae7c1a3153839ff4ca2aa003a919334363899 days 21 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70.03 Ether
0xd255f113152cd61044d679158f76e7417077ed5cc21a0c8c01a8a586eda0f808334362799 days 22 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70.03 Ether
0x13181248d8974dfcf0ce37bc36b5ea68fb445b45d54907676baf93f130d46627334350399 days 22 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70.03 Ether
0x63ea7fb16f70acf9a6d4227ab9d71eaac130705edc6f8843399abe58308ff7203342713100 days 1 hr ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70 Ether
0x63ea7fb16f70acf9a6d4227ab9d71eaac130705edc6f8843399abe58308ff7203342713100 days 1 hr ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30xe7140be5064f9ea9798242db256bbcd8ed77bcf50 Ether
0x63ea7fb16f70acf9a6d4227ab9d71eaac130705edc6f8843399abe58308ff7203342713100 days 1 hr ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30xe7140be5064f9ea9798242db256bbcd8ed77bcf50 Ether
0xf73403d1fded8e44272d95e84ec91694c9fd453e09240975b8fad3d004cb967b3341372100 days 7 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70.1 Ether
0xbc626da87c8702cba8d5da3ac994468104bbf3e93b1004729a4da24483efe6113341317100 days 7 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70.01 Ether
0x0e40aca5b14f456f930685b9831701af4430976dbc6fb2a701c6a2ac6fed5bd23338534100 days 19 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70.1 Ether
0xd510ad0334c06d37a73567d152a885df5a95571ec6e3382f45810ac88171d8fe3338362100 days 19 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70 Ether
0xd510ad0334c06d37a73567d152a885df5a95571ec6e3382f45810ac88171d8fe3338362100 days 19 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x34a54511e2e5706e3cdd28b02cd81fdb70673f8b0 Ether
0xd510ad0334c06d37a73567d152a885df5a95571ec6e3382f45810ac88171d8fe3338362100 days 19 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x34a54511e2e5706e3cdd28b02cd81fdb70673f8b0 Ether
0x418fdbf9834b08d3adee63106aaa2eb0ad637dd569b31d5b56475ca107b2c0d93337849100 days 22 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x77e27eb38fd430a382dc63fdf0b37d3da96ff6b70 Ether
0x418fdbf9834b08d3adee63106aaa2eb0ad637dd569b31d5b56475ca107b2c0d93337849100 days 22 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x34a54511e2e5706e3cdd28b02cd81fdb70673f8b0 Ether
0x418fdbf9834b08d3adee63106aaa2eb0ad637dd569b31d5b56475ca107b2c0d93337849100 days 22 hrs ago0x04071ac5e2b3d9ace141715b641cdf2d3166d0d30x34a54511e2e5706e3cdd28b02cd81fdb70673f8b0 Ether
[ Download CSV Export  ] 
Warning: The Compiled Contract might be susceptible to ExpExponentCleanup (medium/high-severity), EventStructWrongData (very low-severity) SolidityCompiler Bugs.

Contract Source Code Verified (Exact Match)
Contract Name: ThorNetworkProxy
Compiler Version: v0.4.24+commit.e67f0147
Optimization Enabled: Yes
Runs (Optimiser):  200



  Contract Source Code   Find Similiar Contracts

pragma solidity ^0.4.24;


/**
* @title ThorNetwork
* @author Leo
* @dev Exchange two ERC20 tokens including ETH
*/

/**
 * @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 {
    uint ownerIndex = 0;                        //Owner index, the current owner number
    uint constant OWNERNUMBER = 3;              //Owner number up to 5
    address[OWNERNUMBER] owners;                //All owners
    bool public paused = false;                 //When paused = true, the contract triggers stopped state
    
    address[] operators;
    mapping(address => bool) isOperator;

    mapping (string => address) authorizedFuncOwner;    //The authorization that the owner has achieved to implement the function

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event AddOwner(address indexed newOwner);
    event RemoveOwner(address indexed oldOwner);
    event AuthorizeOwner(string func, address operatingOwner);
    

    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
     * account.
     */
    constructor() public {
        owners[0] = msg.sender;
        operators.push(msg.sender);
        isOperator[msg.sender] = true;
        ownerIndex++;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        bool isOwner = false;
        for (uint i = 0; i < OWNERNUMBER; i++) {
            if (owners[i] == msg.sender){
                isOwner = true;
                break;
            }
        }
        require(isOwner);
        _;
    }

    modifier onlyOwnerAuthorized(string func) {
        if(1 < ownerIndex){
            require(authorizedFuncOwner[func] == msg.sender);
            authorizedFuncOwner[func] = address(0);
            _;            
        }else{
            _;
        }

    }

    modifier onlyOperator() {
        require(isOperator[msg.sender]);
        _;
    }

    modifier whenNotPaused() {
        require(!paused);
        _;
    }

    modifier whenPaused() {
        require(paused);
        _;
    }

    /**
     * @dev called by the owner to pause, triggers stopped state
     */
    function pause() public onlyOwner onlyOwnerAuthorized("pause") whenNotPaused {
        paused = true;
    }

    /**
     * @dev called by the owner to unpause, returns to normal state
     */
    function unpause() public onlyOwner onlyOwnerAuthorized("unpause") whenPaused{
        paused = false;
    }

    /**
     * @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) public onlyOwner onlyOwnerAuthorized("transferOwnership") {
        require(newOwner != address(0));
        for (uint i = 0; i < ownerIndex; i++) {
            if(msg.sender == owners[i]) {
                owners[i] = newOwner;
                break;
            }
        }
        emit OwnershipTransferred(msg.sender, newOwner);
    }

    /**
     * @dev Add a new owner with ownership.
     * @param newOwner The address to ownership added
     */
    function addOwner(address newOwner) public onlyOwner onlyOwnerAuthorized("addOwner") returns(bool) {
        require(OWNERNUMBER > ownerIndex);
        require(newOwner != address(0));
        owners[ownerIndex] = newOwner;
        ownerIndex++;

        if(!isOperator[newOwner]) {
            operators.push(newOwner);
            isOperator[newOwner] = true;
        }

        emit AddOwner(newOwner);
        return true;
    }

    /**
     * @dev Remove an owner from Owners
     * @param oldOwner The owner will be removed
     */
    function removeOwner(address oldOwner) public onlyOwner onlyOwnerAuthorized("removeOwner") returns(bool) {
        require(ownerIndex >= 3);               //An owner could be removed only when there are 3 owners
        require(oldOwner != msg.sender);
        for (uint i = 0; i < ownerIndex; i++) {
            if(oldOwner != owners[i]){
                continue;
            }else {
                owners[i] = owners[ownerIndex-1];
                owners[ownerIndex-1] = address(0);
                break;
            }
        }
        ownerIndex--;

        emit RemoveOwner(oldOwner);
        return true;
    }

    /**
     * @dev Return authorizedFunc result
     * @param func Function will be carried out
     * @return Number of authorizations
     */
    function retAuthorizedFunc(string func) public view onlyOwner returns(address) {
        return authorizedFuncOwner[func];
    }

    /**
     * @dev An owner authorizes another owner to operate functions
     * @param func Function will be implemented
     * @param operatingOwner Owner who will implement the function
     * @return true
     */
    function authorizeOwner(string func, address operatingOwner) public onlyOwner returns(bool) {
        require(operatingOwner != msg.sender);               // An owner cannot authorize to himself
        require(address(0) != msg.sender);
        for(uint i = 0; i < ownerIndex; i++){                //The operatingOwner must belong to owners
            if(owners[i] == operatingOwner)
                break;
            if(i == ownerIndex-1)
                return false;
        }
        authorizedFuncOwner[func] = operatingOwner;

        emit AuthorizeOwner(func, operatingOwner);
        return true;
    }

    /**
     * @dev return a owner's address
     * @param _ownerIndex < OWNERNUMBER
     */
    function retOwners(uint _ownerIndex) onlyOwner public view returns(address) {
        require((OWNERNUMBER > _ownerIndex) && ( 0 <= _ownerIndex));
        return owners[_ownerIndex];
    }

    function addOperator(address _newOperator) public onlyOwner returns(bool) {
        require(_newOperator != address(0));
        require(!isOperator[_newOperator]);

        operators.push(_newOperator);
        isOperator[_newOperator] = true;
        return true;
    }

    function delOperator(address _oldOperator) public onlyOwner returns(bool) {
        require(isOperator[_oldOperator]);
        uint operatorNum = operators.length;
        for (uint i = 0; i < operatorNum; i++) {
            if(_oldOperator != operators[i]){
                continue;
            }else {
                operators[i] = operators[operatorNum-1];
                operators[operatorNum-1] = address(0);
                break;
            }
        }
        isOperator[_oldOperator] = false;
        operators.length--;
        return true;
    }

    function retOperators() public view onlyOwner returns(address[]) {
        return operators;
    }
}


/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

    /**
     * @dev Multiplies two numbers, throws on overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        if (a == 0) {
            return 0;
        }
        c = a * b;
        assert(c / a == b);
        return c;
    }

    /**
     * @dev Integer division of two numbers, truncating the quotient.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // assert(b > 0); // Solidity automatically throws when dividing by 0
        // uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return a / b;
    }

    /**
     * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    /**
     * @dev Adds two numbers, throws on overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = a + b;
        assert(c >= a);
        return c;
    }

}


/**
 * @title Standard ERC20 token
 *
 * @dev Implementation of the basic standard token.
 * @dev https://github.com/ethereum/EIPs/issues/20
 * @dev Based on code by OpenZeppelin: https://github.com/OpenZeppelin/openzeppelin-solidity
 */
contract StandardToken is Ownable{

    using SafeMath for uint256;

    mapping (address => mapping (address => uint256)) internal allowed;

    mapping(address => uint256) public balances;

    uint256 public totalSupply;

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    event Burn(address indexed _from, uint256 _value);

    /**
     * @dev Fix for the ERC20 short address attack.
     */
    modifier onlyPayloadSize(uint size) {
        require(!(msg.data.length < size + 4));
        _;
    }

    /**
     * @dev total number of tokens in existence
     */
    function totalSupply() public view returns (uint256) {
        return totalSupply;
    }

    /**
     * @dev Gets the balance of the specified address.
     * @param _owner The address to query the the balance of.
     * @return An uint256 representing the amount owned by the passed address.
     */
    function balanceOf(address _owner) public view whenNotPaused returns (uint256) {
        return balances[_owner];
    }

    /**
     * @dev transfer token for a specified address
     * @param _to The address to transfer to.
     * @param _value The amount to be transferred.
     */
    function transfer(address _to, uint256 _value) public onlyPayloadSize(2 * 32) whenNotPaused returns (bool) {
        require(_to != address(0));
        require(_value <= balances[msg.sender]);

        balances[msg.sender] = balances[msg.sender].sub(_value);
        balances[_to] = balances[_to].add(_value);
        emit Transfer(msg.sender, _to, _value);
        return true;
    }

    /**
     * @dev Transfer tokens from one address to another
     * @param _from address The address which you want to send tokens from
     * @param _to address The address which you want to transfer to
     * @param _value uint256 the amount of tokens to be transferred
     */
    function transferFrom(address _from, address _to, uint256 _value) public onlyPayloadSize (2 * 32) whenNotPaused returns (bool) {
        require(_to != address(0));
        require(_value <= balances[_from]);
        require(_value <= allowed[_from][msg.sender]);

        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(_value);
        allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
        emit Transfer(_from, _to, _value);
        return true;
    }

    /**
     * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
     *
     * Beware that changing an allowance with this method brings the risk that someone may use both the old
     * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
     * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     * @param _spender The address which will spend the funds.
     * @param _value The amount of tokens to be spent.
     */
    function approve(address _spender, uint256 _value) public whenNotPaused returns (bool) {
        allowed[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    /**
     * @dev Function to check the amount of tokens that an owner allowed to a spender.
     * @param _owner address The address which owns the funds.
     * @param _spender address The address which will spend the funds.
     * @return A uint256 specifying the amount of tokens still available for the spender.
     */
    function allowance(address _owner, address _spender) public view returns (uint256) {
        return allowed[_owner][_spender];
    }

    /**
     * @dev Burns a specific amount of tokens.
     * @param _value The amount of token to be burned.
     */
    function burn(uint256 _value) public whenNotPaused {
        _burn(msg.sender, _value);
    }

    /**
     * @dev Burns a specific amount of tokens from the target address and decrements allowance
     * @param _from address The address which you want to send tokens from
     * @param _value uint256 The amount of token to be burned
     */
    function burnFrom(address _from, uint256 _value) public whenNotPaused {
        require(_value <= allowed[_from][msg.sender]);
        // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
        // this function needs to emit an event with the updated approval.
        allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
        _burn(_from, _value);
    }

    function _burn(address _from, uint256 _value) internal {
        require(_value <= balances[_from]);
        // no need to require value <= totalSupply, since that would imply the
        // sender's balance is greater than the totalSupply, which *should* be an assertion failure
        balances[_from] = balances[_from].sub(_value);
        totalSupply = totalSupply.sub(_value);
        emit Burn(_from, _value);
        emit Transfer(_from, address(0), _value);
    }

    /**
     * @dev Increase the amount of tokens that an owner allowed to a spender.
     *
     * approve should be called when allowed[_spender] == 0. To increment
     * allowed value is better to use this function to avoid 2 calls (and wait until
     * the first transaction is mined)
     * From MonolithDAO Token.sol
     * @param _spender The address which will spend the funds.
     * @param _addedValue The amount of tokens to increase the allowance by.
     */
    function increaseApproval(address _spender, uint _addedValue) public  whenNotPaused returns (bool) {
        allowed[msg.sender][_spender] = (allowed[msg.sender][_spender].add(_addedValue));
        emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
        return true;
    }

    /**
     * @dev Decrease the amount of tokens that an owner allowed to a spender.
     *
     * approve should be called when allowed[_spender] == 0. To decrement
     * allowed value is better to use this function to avoid 2 calls (and wait until
     * the first transaction is mined)
     * From MonolithDAO Token.sol
     * @param _spender The address which will spend the funds.
     * @param _subtractedValue The amount of tokens to decrease the allowance by.
     */
    function decreaseApproval(address _spender, uint _subtractedValue) public whenNotPaused returns (bool) {
        uint oldValue = allowed[msg.sender][_spender];
        if (_subtractedValue > oldValue) {
            allowed[msg.sender][_spender] = 0;
        } else {
            allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
        }
        emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
        return true;
    }

}


// https://github.com/ethereum/EIPs/issues/20
interface Token {
    function totalSupply() external view returns (uint supply);
    function balanceOf(address _owner) external view returns (uint balance);
    function transfer(address _to, uint _value) external returns (bool success);
    function transferFrom(address _from, address _to, uint _value) external returns (bool success);
    function approve(address _spender, uint _value) external returns (bool success);
    function allowance(address _owner, address _spender) external view returns (uint remaining);
    function decimals() external view returns(uint digits);
    event Approval(address indexed _owner, address indexed _spender, uint _value);
}

contract Utils {
    Token constant internal TOKEN_ETH_ADDRESS = Token(0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);
    uint constant internal ETH_DECIMALS = 18;
    uint constant internal MAX_DECIMALS = 18;

    uint constant internal MAX_PRICE_PRODUCT = 10 ** 16;
    uint constant internal PRICE_PRODUCT = 10 ** 8;

    uint constant internal MAX_VALUE = 2 ** 255 - 1;

    mapping(address => uint) tokenDecimals;

    function setTokenDecimals(Token _token) public {
        if (TOKEN_ETH_ADDRESS == _token) {
            tokenDecimals[_token] = ETH_DECIMALS;
        } else {
            tokenDecimals[_token] = _token.decimals();
        }
    }

    function getTokenDecimals(Token _token) public view returns(uint) {
        if (TOKEN_ETH_ADDRESS == _token) {
            return MAX_DECIMALS;
        } else {
            return _token.decimals();
        }
    }

    function getBalance(Token _token, address _user) public view returns(uint) {
        if(TOKEN_ETH_ADDRESS == _token) {
            return _user.balance;
        } else {
            return _token.balanceOf(_user);
        }
    }
}

/**
 * @title Contracts that should be able to recover tokens or ethers
 * @dev This allows to recover any tokens or Ethers received in a contract.
 */
contract Withdrawable is Ownable {

    event TokenWithdraw(Token _token, uint _amount, address _sendTo);

    /**
     * @dev Withdraw all ERC20 compatible tokens
     * @param _token The address of the token contract
     * @param _amount The amount of token
     * @param _sendTo The address of the token send to
     */
    function withdrawToken(Token _token, uint _amount, address _sendTo) external onlyOwner {
        require(_token.transfer(_sendTo, _amount));
        emit TokenWithdraw(_token, _amount, _sendTo);
    }

    event EtherWithdraw(uint _amount, address _sendTo);

    /**
     * @dev Withdraw Ethers
     * @param _amount The amount of Ethers
     * @param _sendTo The address of the token send to
     */
    function withdrawEther(uint _amount, address _sendTo) external onlyOwner {
        _sendTo.transfer(_amount);
        emit EtherWithdraw(_amount, _sendTo);
    }
}

contract THORToken is StandardToken {
    using SafeMath for uint256;

    string public constant name = "THORToken";   //Token name
    string public constant symbol = "THT";            //Token symbol
    uint8 public decimals = 18;
    uint256 public INITIAL_SUPPLY = 10000000000 * 10 ** uint256(decimals);     //Token initial_supply 10 billion

    event Mint(address indexed _to, uint256 _value);    //Mint tokens

    constructor() public payable{
        totalSupply = INITIAL_SUPPLY;
        balances[msg.sender] = totalSupply;
    }
}

interface ThorNetworkInterface {
    function exchange(Token _fromToken, uint _fromAmount, Token _toToken, address _toAddress, uint minRate, address _walletId) external payable returns(uint);
    function getMaxGasPrice() external view returns(uint);
    function findBestRate(Token _fromToken, Token _toToken, uint _fromAmount, uint _maxAmount, uint _minRate) external view returns(uint, uint);
    function getUserQuota(address _user) external returns(uint);
    function getTokensIncluded() external view returns(address[]);
    function getTokenPairAndPrice(Token _fromToken, Token _toToken) external view returns(uint);
    function calculatePlatformFeeInWei(Token _fromToken, uint _fromAmount) external view returns(uint);
}

contract ThorNetworkProxy is Ownable, Utils, Withdrawable {
    using SafeMath for uint256;
    ThorNetworkInterface public thorNetwork;
    string public contractName;

    constructor() public payable {
        contractName = "ThorNetworkProxy";
    }

    /**
     * @dev makes a trade between src and dest token and send dest token to destAddress
     * @param _fromToken fromToken address
     * @param _fromAmount amount of fromToken
     * @param _toToken toToken address
     * @param _minRate the min rate user coule accept
     * @param _walletId the wallet's address
     * @return uint the actual amount of toToken
     */
    function exchange(Token _fromToken, uint _fromAmount, Token _toToken, uint _minRate, address _walletId) public payable whenNotPaused returns(uint) {
        require(_fromToken != _toToken);
        uint256 fromAmount = _fromAmount.div(10 ** (MAX_DECIMALS - getTokenDecimals(_fromToken)));

        return doExchange(_fromToken, fromAmount, _toToken, msg.sender, _minRate, _walletId);
    }

    event ThorNetworkProxyExchange(address indexed trader, Token src, Token dest, uint actualSrcAmount, uint actualDestAmount);

    /**
     * @dev makes a trade between src and dest token and send dest token to destAddress
     * @param _fromToken fromToken address
     * @param _fromAmount amount of fromToken
     * @param _toToken toToken address
     * @param _destAddress the user's address
     * @param _minRate the min rate user coule accept
     * @param _walletId the wallet's address
     * @return uint the actual amount of toToken
     */
    function doExchange(Token _fromToken, uint _fromAmount, Token _toToken, address _destAddress, uint _minRate, address _walletId) internal returns(uint) {
        require(TOKEN_ETH_ADDRESS == _fromToken || msg.value == 0);

        if(TOKEN_ETH_ADDRESS == _fromToken) {
            require(_fromAmount == msg.value);
        }

        //send tokens to ThorNetwork
        if (TOKEN_ETH_ADDRESS != _fromToken) {
            require(_fromToken.transferFrom(msg.sender, thorNetwork, _fromAmount));
        }

        //send eth(msg.value) to ThorNetwork
        //call thorNetwork.exchage to get tokens(_toToken)
        uint actualAmount = thorNetwork.exchange.value(msg.value)(_fromToken, _fromAmount, _toToken, _destAddress, _minRate, _walletId);

        emit ThorNetworkProxyExchange(msg.sender, _fromToken, _toToken, _fromAmount, actualAmount);

        return actualAmount;
    }

    event SetThorNetworkContract(ThorNetworkInterface _thorNetworkContract);
    /**
     * @dev set the ThorNetwork contract
     * @param _thorNetworkContract the ThorNetwork contract
     * @return address ThorNetwork contract
     */
    function setThorNetworkContract(ThorNetworkInterface _thorNetworkContract) public onlyOwner {
        require(_thorNetworkContract != address(0));
        thorNetwork = _thorNetworkContract;

        emit SetThorNetworkContract(_thorNetworkContract);
    }

    /**
     * @dev return the ThorNetwork contract
     * @return address ThorNetwork contract
     */
    function getThorNetworkContract() public view onlyOwner returns(address) {
        return thorNetwork;
    }

    /**
     * @dev return the max GasPrice
     * @return uint the max GasPrice
     */
    function getMaxGasPrice() public view returns(uint) {
        return thorNetwork.getMaxGasPrice();
    }

    /**
     * @dev find the best reserve
     * @param _fromToken token address
     * @param _toToken token address
     * @param _fromAmount token amount of fromToken
     * @param _minRate the min rate user coule accept
     * @return uint reserveId
     * @return uint actual rate
     */
    function findBestRate(Token _fromToken, Token _toToken, uint _fromAmount, uint _minRate) public view returns(uint, uint) {
        return thorNetwork.findBestRate(_fromToken, _toToken, _fromAmount, MAX_VALUE, _minRate);
    }

    /**
     * @dev calculate platformFee
     * @param _fromToken token address
     * @param _fromAmount token amount of fromToken
     * @return uint
     */
    function calculatePlatformFeeInWei(Token _fromToken, uint _fromAmount) public view returns(uint) {
        return thorNetwork.calculatePlatformFeeInWei(_fromToken, _fromAmount);
    }

    /**
     * @dev return token amount of toToken
     * @param _fromToken token address
     * @param _toToken token address
     * @param _fromAmount token amount of fromToken
     * @return uint
     */
    function calculateToTokenAmount(Token _fromToken, Token _toToken, uint _fromAmount) public view returns(uint) {
        uint actualPrice = getTokenPairAndPrice(_fromToken, _toToken);
        uint toAmount = _fromAmount.mul(actualPrice).div(PRICE_PRODUCT);
        toAmount = toAmount.div(10 ** (MAX_DECIMALS - getTokenDecimals(_toToken)));

        return toAmount;
    }

    /**
     * @dev return two tokens price
     * @param _fromToken token address
     * @param _toToken token address
     * @return uint
     */
    function getTokenPairAndPrice(Token _fromToken, Token _toToken) public view returns(uint) {
        return thorNetwork.getTokenPairAndPrice(_fromToken, _toToken);
    }

    /**
     * @dev return a user's quota
     * @param _user a user
     * @return uint
     */
    function getUserQuota(address _user) public returns(uint) {
        return thorNetwork.getUserQuota(_user);
    }

    /**
     * @dev return all tokens in ThorSwap
     * @return address[], a list of tokens
     */
    function getTokensIncluded() public view returns(address[]) {
        return thorNetwork.getTokensIncluded();
    }
}

interface ThorReserveInterface {
    function exchange(Token _fromToken, Token _toToken, address _to, uint _actualAmount, uint _actualRate) external payable returns(bool);
    function getExchangeRate(Token _fromToken, Token _toToken, uint _toAmount) external view returns(uint);
    function getTokensIncluded() external view returns(address[]);
}

interface ThorUserInfoInterface {
    function getUserQuota(address _user) external view returns(uint);
}

interface ThorFeeInterface {
    function handleFee(uint _platformFee, address _walletId) external payable returns(bool);
}

interface ThorPriceInterface {
    function addTokenPairAndPrice(Token _fromToken, Token _toToken, uint _rate) external returns(bool);
    function modifyTokenPairPrice(Token _fromToken, Token _toToken, uint _rate) external returns(bool);
    function setTokenPairsPrice(Token[] _fromTokens, Token[] _toTokens, uint[] _rates) external returns(bool);
    function getTokenPairAndPrice(Token _fromToken, Token _toToken) external view returns(uint);
    function getTokenTransactionPrice(Token _token) external view returns(uint, uint);
}

contract ThorNetwork is Ownable, Utils, Withdrawable {
    using SafeMath for uint256;

    string public contractName;

    uint internal numTransaction = 0;
    uint internal numTokenToToken = 0;
    uint internal numTokenToETH = 0;
    uint internal numETHToToken = 0;

    address public thorNetworkProxy;

    address[] tokensIncluded;
    mapping(address => bool) internal isTokenIncluded;       // when two tokens could be exchanged, true
    
    address[] internal tokensToExchange;
    mapping(address => bool) internal isTokenToExchange;     // tokens included in ThorNetwork, true

    uint public maxGasPrice = 50 * 1000 * 1000 * 1000; // 50 gwei

    uint internal feeRateDenominator = 1000;
    uint internal feeRateMolecular = 1;

    uint internal minTransactionAmount = 10 ** 15;
    uint internal maxTransactionAmount = 10 ** 19;

    uint internal minRate = 9500;
    uint internal standardRate = 10000;
    uint internal maxRate = 10500;

    ThorPriceInterface internal thorPrice;
    ThorUserInfoInterface internal thorUserInfo;
    ThorFeeInterface internal thorFee;
    ThorReserveInterface[] internal thorReserves;
    ThorReserveInterface internal thorReserve1;
    ThorReserveInterface internal thorReserve2;
    mapping(address => bool) isReserve;

    struct BestRateResult {
        uint reserveId1;
        uint reserveId2;
        uint reserveRate1;
        uint reserveRate2;
        uint actualAmount1;
        uint actualAmount2;
        uint actualRate;
    }

    constructor () public {
        contractName = "ThorNetwork";
    }

    event EtherReceival(address indexed sender, uint amount);

    /* solhint-disable no-complex-fallback */
    // Only reserve contract could send Ether to network contract directly.
    function() public payable {
        require(isReserve[msg.sender]);
        emit EtherReceival(msg.sender, msg.value);
    }
    /* solhint-enable no-complex-fallback */

    /**
     * @dev makes a trade between src and dest token and send dest token to toAddress
     * @param _fromToken fromToken address
     * @param _fromAmount amount of fromToken
     * @param _toToken toToken address
     * @param _toAddress the user's address
     * @param _minRate the min rate user coule accept
     * @param _walletId the wallet's address
     * @return uint the actual amount of toToken
     */
    function exchange(Token _fromToken, uint _fromAmount, Token _toToken, address _toAddress, uint _minRate, address _walletId)
        public
        payable
        whenNotPaused
        returns(uint)
    {
        require(msg.sender == address(thorNetworkProxy));
        require(tx.gasprice <= maxGasPrice);
        require(isTokenToExchange[_fromToken] && isTokenToExchange[_toToken]);
        require(isTokenIncluded[_fromToken] && isTokenIncluded[_toToken]);

        if(TOKEN_ETH_ADDRESS == _fromToken) {
            require(minTransactionAmount <= _fromAmount && _fromAmount <= maxTransactionAmount);
        } else {
            uint amountInEth = calculateToTokenAmount(_fromToken, TOKEN_ETH_ADDRESS, _fromAmount);
            require(minTransactionAmount <= amountInEth && amountInEth <= maxTransactionAmount);
        }

        uint maxAmount = calculateToTokenAmount(_fromToken, _toToken, _fromAmount);

        uint actualAmount = doExchange(_fromToken, _fromAmount, _toToken, _toAddress, maxAmount, _minRate, _walletId);
        require(actualAmount >= maxAmount.mul(_minRate).div(standardRate));
        require(actualAmount <= maxAmount.mul(maxRate).div(standardRate));

        return actualAmount;
    }

    event ThorNetworkExchange(Token _fromToken, uint _fromAmount, Token _toToken, uint _actualAmount, address _toAddress, uint _actualRate, address _walletId);

    /**
     * @dev makes a trade between src and dest token and send dest token to toAddress
     * @param _fromToken fromToken address
     * @param _fromAmount amount of fromToken
     * @param _toToken toToken address
     * @param _toAddress the user's address
     * @param _maxAmount the max amount of toToken
     * @param _minRate the min rate user coule accept
     * @param _walletId the wallet's address
     * @return uint the actual amount of toToken
     */
    function doExchange(Token _fromToken, uint _fromAmount, Token _toToken, address _toAddress, uint _maxAmount, uint _minRate, address _walletId)
        internal
        returns(uint)
    {
        BestRateResult memory bestRateResult;
        (bestRateResult.reserveId1, bestRateResult.reserveId2, bestRateResult.reserveRate1, bestRateResult.reserveRate2, bestRateResult.actualRate) = findBestRate(_fromToken, _toToken, _fromAmount, _maxAmount, _minRate);
        thorReserve1 = thorReserves[bestRateResult.reserveId1];
        thorReserve2 = thorReserves[bestRateResult.reserveId2];
        uint actualRate = bestRateResult.actualRate;
        uint actualAmount1 = 0;
        uint actualAmount2 = 0;

        require(_minRate <= actualRate && actualRate <= maxRate);

        if(_fromToken != TOKEN_ETH_ADDRESS) {
            if(_toToken != TOKEN_ETH_ADDRESS) {                                                                 // ERC20 <=> ETH <=> ERC20
                numTokenToToken++;
                actualAmount1 = reserveExchange(_fromToken, _fromAmount, TOKEN_ETH_ADDRESS, this, bestRateResult.reserveRate1, thorReserve1, false, _walletId);
                actualAmount2 = reserveExchange(TOKEN_ETH_ADDRESS, actualAmount1, _toToken, _toAddress, bestRateResult.reserveRate2, thorReserve2, true, _walletId);
            } else {                                                                                            // ERC20 <=> ETH
                numTokenToETH++;
                actualAmount2 = reserveExchange(_fromToken, _fromAmount, TOKEN_ETH_ADDRESS, _toAddress, bestRateResult.reserveRate1, thorReserve1, true, _walletId); 
            }
        } else {                                                                                                // ETH <=> ERC20
            numETHToToken++;
            actualAmount2 = reserveExchange(_fromToken, _fromAmount, _toToken, _toAddress, bestRateResult.reserveRate2, thorReserve2, true, _walletId); 
        }

        numTransaction++;

        emit ThorNetworkExchange(_fromToken, _fromAmount, _toToken, actualAmount2, _toAddress, actualRate, _walletId);

        return actualAmount2;
    }

    event ReserveExchange(Token _fromToken, uint _fromAmount, uint fromAmount, address _toAddress, uint actualAmount, uint _platformFee);

    /**
     * @dev makes a trade between src and dest token and send dest token to toAddress
     * @param _fromToken fromToken address
     * @param _fromAmount amount of fromToken
     * @param _toToken toToken address
     * @param _toAddress the user's address
     * @param _actualRate the actual rate of toToken
     * @param _thorReserve the reserve
     * @param isHandleFee true, handle the platform fee; false, do not handle platform fee
     * @param _walletId wallet address
     * @return uint the actual amount of toToken
     */
    function reserveExchange(
        Token _fromToken,
        uint _fromAmount,
        Token _toToken,
        address _toAddress,
        uint _actualRate,
        ThorReserveInterface _thorReserve,
        bool isHandleFee,
        address _walletId
    )
        internal
        returns(uint)
    {
        uint callValue = 0;
        uint platformFee = 0;
        uint fromAmount = 0;

        if(isHandleFee && TOKEN_ETH_ADDRESS == _fromToken) {
            platformFee = _fromAmount.mul(feeRateMolecular).div(feeRateDenominator);
        }

        fromAmount = _fromAmount.sub(platformFee);

        uint actualAmount = calculateToTokenAmount(_fromToken, _toToken, fromAmount) * _actualRate / standardRate;

        if (TOKEN_ETH_ADDRESS != _fromToken) {
            //network send tokens to reserve
            _fromToken.transfer(_thorReserve, fromAmount);
        } else {
            callValue = fromAmount;
        }

        //network send eth to reserve
        //reserve send tokens/eth to network.
        require(_thorReserve.exchange.value(callValue)(_fromToken, _toToken, this, actualAmount, _actualRate));
        
        if(isHandleFee && TOKEN_ETH_ADDRESS == _toToken) {
            platformFee = actualAmount.mul(feeRateMolecular).div(feeRateDenominator);
            actualAmount = actualAmount.sub(platformFee);
        }

        //network send it to destination
        if(_toAddress != address(this)) {
            if(TOKEN_ETH_ADDRESS == _toToken) {
                _toAddress.transfer(actualAmount);
            } else {
                _toToken.transfer(_toAddress, actualAmount);
            }
        }

        if(isHandleFee) {
            //network send platformFee to ThorFee contract
            require(thorFee.handleFee.value(platformFee)(platformFee, _walletId));
        }

        emit ReserveExchange(_fromToken, _fromAmount, fromAmount, _toAddress, actualAmount, platformFee);

        return actualAmount;
    }

    function findBestRate(Token _fromToken, Token _toToken, uint _fromAmount, uint _maxAmount, uint _minRate) 
        public view returns(uint, uint, uint, uint, uint) 
    {
        BestRateResult memory result;

        uint maxAmount1 = calculateToTokenAmount(_fromToken, TOKEN_ETH_ADDRESS, _fromAmount);
        (result.reserveId1, result.reserveRate1) = findBestRateTokenToToken(_fromToken, TOKEN_ETH_ADDRESS, maxAmount1, _minRate);
        result.actualAmount1 = maxAmount1.mul(result.reserveRate1).div(standardRate);

        uint maxAmount2 = calculateToTokenAmount(TOKEN_ETH_ADDRESS, _toToken, result.actualAmount1);        
        (result.reserveId2, result.reserveRate2) = findBestRateTokenToToken(TOKEN_ETH_ADDRESS, _toToken, maxAmount2, _minRate);
        result.actualAmount2 = maxAmount2.mul(result.reserveRate2).div(standardRate);

        result.actualRate = result.reserveRate1.mul(result.reserveRate2).div(standardRate);
        require(result.actualAmount2 >= _maxAmount * _minRate / standardRate);
        require(_minRate <= result.actualRate);

        return (result.reserveId1, result.reserveId2, result.reserveRate1, result.reserveRate2, result.actualRate);
    }

    /**
     * @dev find the best reserve
     * @param _fromToken token address
     * @param _toToken token address
     * @param _toAmount token amount of toToken
     * @param _minRate the min rate user coule accept
     * @return uint reserveId
     * @return uint actual rate
     */
    function findBestRateTokenToToken(Token _fromToken, Token _toToken, uint _toAmount, uint _minRate) public view returns(uint, uint) {
        if(_fromToken == _toToken) {
            return (0, standardRate);
        }

        uint bestRate = 0;
        uint bestReserve = 0;
        
        uint numberReserve = thorReserves.length;
        uint[] memory rates = new uint[](numberReserve);
        uint[] memory reserveCandiates = new uint[](numberReserve);
        uint reserveCandiateIndex = 0;
        uint random = 0;

        for(uint i = 0; i < numberReserve; i++) {
            rates[i] = thorReserves[i].getExchangeRate(_fromToken, _toToken, _toAmount);

            if(rates[i] > bestRate){
                bestRate = rates[i];
            }
        }
        
        require(_minRate <= bestRate);

        for(i = 0; i < numberReserve; i++) {
            if(rates[i] == bestRate) {
                reserveCandiates[reserveCandiateIndex++] = i;
            }
        }

        if(reserveCandiateIndex > 1) {
            random = uint(keccak256(abi.encodePacked(now, msg.sender))) % reserveCandiateIndex;
        }

        bestReserve = reserveCandiates[random];      

        return (bestReserve, bestRate);
    }

    function getExchangeRate(ThorReserveInterface reserve, Token _fromToken, Token _toToken, uint _toAmount) public view returns(uint) {
        return reserve.getExchangeRate(_fromToken, _toToken, _toAmount);
    }

    event AddTokensToExchange(Token[] tokens, uint length);

    /**
     * @dev add tokens to exchange
     * @param tokens tokens address
     * @param length tokens' length
     */
    function addTokensToExchange(Token[] tokens, uint length) public onlyOwner {
        require(tokens.length == length && length > 0);
        for(uint i = 0; i < length; i++) {
            if(!isTokenToExchange[tokens[i]]) {
                tokensToExchange.push(tokens[i]);
                isTokenToExchange[tokens[i]] = true;
            }
        }

        emit AddTokensToExchange(tokens, length);
    }

    function getTokenToExchangeIsEnable(address _token) public view returns(bool) {
        return isTokenToExchange[_token];
    }

    event SetTokensIncludedEnable(bool);
    /**
     * @dev enable all tokens in ThorSwap 
     * @return address[], a list of tokens
     */
    function setTokensIncludedEnable() public onlyOwner returns(address[]) {
        //isTokenIncluded[TOKEN_ETH_ADDRESS] = true;
        for(uint i = 0; i < thorReserves.length; i++) {
            address[] memory tokensIncludedReserve = thorReserves[i].getTokensIncluded();
            for(uint j = 0; j < tokensIncludedReserve.length; j++) {
                if(!isTokenIncluded[tokensIncludedReserve[j]]) {
                    tokensIncluded.push(tokensIncludedReserve[j]);
                    isTokenIncluded[tokensIncludedReserve[j]] = true;
                }
            }
        }

        emit SetTokensIncludedEnable(true);

        return tokensIncluded;
    }

    /**
     * @dev return all tokens in ThorSwap
     * @return address[], a list of tokens
     */
    function getTokensIncluded() public view returns(address[]) {
        return tokensIncluded;
    }

    event AddReserve(ThorReserveInterface _newReserve);
    /**
     * @dev add a reserve
     * @param _newReserve address of a reserve contract
     * @return bool
     */
    function addReserve(ThorReserveInterface _newReserve) public onlyOwner returns(bool) {
        require(!isReserve[_newReserve]);
        thorReserves.push(_newReserve);
        isReserve[_newReserve] = true;

        emit AddReserve(_newReserve);

        return true;
    }

    event RemoveReserve(ThorReserveInterface _oldReserve);
    /**
     * @dev remove a reserve
     * @param _oldReserve address of a reserve contract
     * @return bool
     */
    function removeReserve(ThorReserveInterface _oldReserve) public onlyOwner {
        require(isReserve[_oldReserve]);
        require(1 <= thorReserves.length);
        for(uint i = 0; i < thorReserves.length; i++){
            if(thorReserves[i] == _oldReserve){
                thorReserves[i] = thorReserves[thorReserves.length - 1];
                thorReserves.length--;
                break;
            }
        }
        isReserve[_oldReserve] = false;

        emit RemoveReserve(_oldReserve);
    }

    /**
     * @dev return two tokens price
     * @param _fromToken token address
     * @param _toToken token address
     * @return uint
     */
    function getTokenPairAndPrice(Token _fromToken, Token _toToken) public view returns(uint) {
        require(_fromToken != _toToken);
        require(isTokenIncluded[_fromToken]);
        require(isTokenIncluded[_toToken]);
        return thorPrice.getTokenPairAndPrice(_fromToken, _toToken);
    }

    function getTokenTransactionPrice(Token _token) public view returns(uint, uint) {
        require(isTokenIncluded[_token]);
        require(isTokenToExchange[_token]);
        return thorPrice.getTokenTransactionPrice(_token);
    }

    function addTokenPairAndPrice(Token _fromToken, Token _toToken, uint _price) public onlyOperator returns(bool) {
        return thorPrice.addTokenPairAndPrice(_fromToken, _toToken, _price);
    }

    function modifyTokenPairPrice(Token _fromToken, Token _toToken, uint _price) public onlyOperator returns(bool) {
        return thorPrice.modifyTokenPairPrice(_fromToken, _toToken, _price);
    }

    function setTokenPairsPrice(Token[] _fromTokens, Token[] _toTokens, uint[] _prices) public onlyOperator returns(bool) {
        return thorPrice.setTokenPairsPrice(_fromTokens, _toTokens, _prices);
    }

    event SetParamsRate(uint _feeRateMolecular, uint _feeRateDenominator, uint _minRate, uint _standardRate, uint _maxRate);
    /**
     * @dev set params including feeRateDenominator, feeRateMolecular, minRate, standardRate and maxRate
     * @param _feeRateMolecular token address
     * @param _feeRateDenominator token amount
     * @return bool
     */
    function setParamsRate(uint _feeRateMolecular, uint _feeRateDenominator, uint _minRate, uint _standardRate, uint _maxRate) public onlyOwner {
        feeRateDenominator = _feeRateDenominator;
        feeRateMolecular = _feeRateMolecular;
        minRate = _minRate;
        standardRate = _standardRate;
        maxRate = _maxRate;

        emit SetParamsRate(_feeRateMolecular, _feeRateDenominator, _minRate, _standardRate, _maxRate);
    }

    function getParamsRate() public view onlyOwner returns(uint, uint, uint, uint, uint) {
        return (feeRateDenominator, feeRateMolecular, minRate, standardRate, maxRate);
    }

    /**
     * @dev return token amount of toToken
     * @param _fromToken token address
     * @param _toToken token address
     * @param _fromAmount token amount of fromToken
     * @return uint
     */
    function calculateToTokenAmount(Token _fromToken, Token _toToken, uint256 _fromAmount) public view returns(uint) {
        if(_fromToken == _toToken) {
            return _fromAmount;
        }
        uint256 actualPrice = getTokenPairAndPrice(_fromToken, _toToken);
        require(actualPrice != 0);
        uint256 toAmount = _fromAmount.mul(actualPrice).div(PRICE_PRODUCT);
        toAmount = toAmount.div(10 ** (MAX_DECIMALS - getTokenDecimals(_toToken)));

        return toAmount;
    }

    /**
     * @dev return platformFee
     * @param _fromToken token address
     * @param _fromAmount token amount of fromToken
     * @return uint
     */
    function calculatePlatformFeeInWei(Token _fromToken, uint _fromAmount) public view returns(uint) {
        return calculateToTokenAmount(_fromToken, TOKEN_ETH_ADDRESS, _fromAmount).mul(feeRateMolecular).div(feeRateDenominator);
    }


    event SetTokenIsEnable(Token _token, bool isEnable);
    /**
     * @dev Set function of two token swap
     * @param _token toToken address
     * @param isEnable true, function normal; false, function stop.
     */
    function setTokenIsEnable(Token _token, bool isEnable) public onlyOwner {
        isTokenIncluded[_token] = isEnable;
        emit SetTokenIsEnable(_token, isEnable);
    }

    /**
     * @dev return function of two token swap
     * @param _token toToken address
     * @return bool
     */
    function getTokenIsEnable(Token _token) public view onlyOwner returns(bool) {
        return isTokenIncluded[_token];
    }

    /**
     * @dev ret ThorReserves contracts
     * @return address[], a list of ThorReserve contracts
     */
    function getThorReserve() public view onlyOwner returns(ThorReserveInterface[]) {
        return thorReserves;
    }

    event SetContracts(address _thorNetworkProxy, ThorPriceInterface _thorPrice, ThorUserInfoInterface _thorUserInfo, ThorFeeInterface _thorFee);
    /**
     * @dev set relative contracts
     * @param _thorNetworkProxy ThorNetworkProxy contract
     * @param _thorPrice ThorPrice contract
     * @param _thorUserInfo ThorUserInfo contract
     * @param _thorFee ThorFee contract
     * @return bool
     */
    function setContracts(address _thorNetworkProxy, ThorPriceInterface _thorPrice, ThorUserInfoInterface _thorUserInfo, ThorFeeInterface _thorFee) 
        public
        onlyOwner
    {
        require(_thorNetworkProxy != address(0));
        require(_thorPrice != address(0));
        require(_thorUserInfo != address(0));
        require(_thorFee != address(0));

        thorNetworkProxy = _thorNetworkProxy;
        thorPrice = _thorPrice;
        thorUserInfo = _thorUserInfo;
        thorFee = _thorFee;

        emit SetContracts(_thorNetworkProxy, _thorPrice, _thorUserInfo, _thorFee);
    }

    /**
     * @dev return relative contracts
     * @return address ThorNetworkProxy contract
     * @return address ThorPrice contract
     * @return address ThorUserInfo contract
     * @return address ThorFee contract
     */
    function getContracts() public view onlyOwner returns(address, address, address, address) {
        return (thorNetworkProxy, thorPrice, thorUserInfo, thorFee);
    }

    event SetMaxGasPrice(uint _maxGasPrice);
    /**
     * @dev set the max GasPrice
     * @param _maxGasPrice the max GasPrice
     * @return uint the max GasPrice
     */
    function setMaxGasPrice(uint _maxGasPrice) public onlyOwner {
        maxGasPrice = _maxGasPrice;
        emit SetMaxGasPrice(_maxGasPrice);
    }

    /**
     * @dev return the max GasPrice
     * @return uint the max GasPrice
     */
    function getMaxGasPrice() public view returns(uint) {
        return maxGasPrice;
    }

    /**
     * @dev get transactions number
     */
    function getTransactionsNumber() public view onlyOwner returns(uint, uint, uint, uint) {
        return (numTransaction, numTokenToToken, numTokenToETH, numETHToToken);
    }

    /**
     * @dev return a user's quota
     * @param _user address of a user
     * @return uint
     */
    function getUserQuota(address _user) public view returns(uint) {
        return thorUserInfo.getUserQuota(_user);
    }
}


interface ThorNetworkReserveInterface {
    function getTokenTransactionPrice(Token _token) external view returns(uint, uint);
    function getTokenToExchangeIsEnable(Token _token) external returns(bool);
}

contract ThorReserve is Ownable, Utils, Withdrawable{
    using SafeMath for uint256;
    string public contractName;

    ThorNetworkReserveInterface public thorNetwork;

    bool public isEnabled = false;

    uint public numTransaction;

    uint constant internal minRate = 9500;
    uint constant internal maxRate = 10500;
    uint constant internal standardRate = 10000;

    uint constant internal targetRatio = 100;

    address[] tokensIncluded;
    mapping(address => bool) isTokenIncluded;

    mapping(bytes32 => bool) isPairToken;       // when two tokens could be exchanged, true

    struct PairTokenRate {
        uint blockNumber;                       // the block when rate was modified
        uint rate;                              // two tokens min rate
    }
    mapping(bytes32 => PairTokenRate) pairTokenRates;

    struct TokenReserveInfo {
        uint targetAmount;
        uint depositRatio;                      //inform reserve to deposit token when ratio < depositRatio
        uint stopRatio;                         //reserve's function pause when current ratio < stopRatio
    }
    mapping(address => TokenReserveInfo) tokenReserveInfos;

    constructor(ThorNetworkReserveInterface _thorNetwork) public {
        contractName = "ThorReserve";
        isEnabled = true;
        thorNetwork = _thorNetwork;
    }

    modifier onlyEnabled() {
        require(isEnabled);
        _;
    }

    event DepositToken(Token token, uint amount);

    function() public payable {
        emit DepositToken(TOKEN_ETH_ADDRESS, msg.value);
    }

    event ThorReserveExchange(Token _fromToken, Token _toToken, address _to, uint _actualAmount, uint _actualRate);
    /**
     * @dev makes a trade between src and dest token and send dest token to toAddress
     * @param _fromToken fromToken address
     * @param _toToken toToken address
     * @param _to the user's address
     * @param _actualAmount the actual amount of toToken
     * @param _actualRate the actual rate of toToken
     * @return bool
     */
    function exchange(Token _fromToken, Token _toToken, address _to, uint _actualAmount, uint _actualRate) public payable returns(bool) {
        require(thorNetwork == msg.sender);

        require(_actualRate == pairTokenRates[keccak256(abi.encodePacked(_fromToken, _toToken))].rate);

        emit ThorReserveExchange(_fromToken, _toToken, _to, _actualAmount, _actualRate);
        return doExchange(_fromToken, _toToken, _to, _actualAmount);
    }

    /**
     * @dev makes a trade between src and dest token and send dest token to toAddress
     * @param _fromToken fromToken address
     * @param _toToken toToken address
     * @param _to the user's address
     * @param _actualAmount the actual amount of toToken
     * @return bool
     */
    function doExchange(Token _fromToken, Token _toToken, address _to, uint _actualAmount) internal returns(bool) {
        numTransaction++;

        require(isPairToken[keccak256(abi.encodePacked(_fromToken, _toToken))]);

        //send tokens/ETH to thorNetwork
        if(TOKEN_ETH_ADDRESS == _toToken) {
            _to.transfer(_actualAmount);
        } else {
            _toToken.transfer(_to, _actualAmount);
        }

        //balance the reserve token
        balanceToken(_toToken);
        return true;
    }

    /**
     * @dev return the reserve rate of two tokens
     * @param _fromToken fromToken address
     * @param _toToken toToken address
     * @param _toAmount the actual amount of toToken
     * @return bool
     */
    function getExchangeRate(Token _fromToken, Token _toToken, uint _toAmount) public view returns(uint)
    {
        bytes32 tokenPair = keccak256(abi.encodePacked(_fromToken, _toToken));
        PairTokenRate memory pairTokenRate = pairTokenRates[tokenPair];
        if(!isEnoughToken(_toToken, _toAmount)) {
            return 0;                                                                   //reserve does not have enough _toToken tokens
        } else {
            return pairTokenRate.rate;
        }
        return 0;
    }

    /**
     * @dev return all tokens in the reserve
     * @return address[], a list of tokens
     */
    function getTokensIncluded() public view returns(address[]) {
        return tokensIncluded;
    }

    /**
     * @dev The reserve has enough tokens
     * @param _targetToken toToken address
     * @param _targetAmount the actual amount of toToken
     * @return bool
     */
    function isEnoughToken(Token _targetToken, uint256 _targetAmount) public view returns(bool) {
        uint tokenAmount = getBalance(_targetToken, address(this));
        uint stopAmount = tokenReserveInfos[_targetToken].stopRatio * tokenReserveInfos[_targetToken].targetAmount / targetRatio;
        //require(tokenAmount >= _targetAmount);
        if(tokenAmount >= _targetAmount && tokenAmount - _targetAmount >= stopAmount) {     // make sure that reserve has enough balance. 
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev add a new pair of token
     * @param _fromToken fromToken address
     * @param _toToken toToken address
     * @param _rate the new rate between two tokens
     * @return bool
     */
    function addTokenPairAndRate(Token _fromToken, Token _toToken, uint _rate) public onlyOwner {
        require(thorNetwork.getTokenToExchangeIsEnable(_fromToken) && thorNetwork.getTokenToExchangeIsEnable(_toToken));
        require(minRate <= _rate && _rate <= maxRate);
        require(TOKEN_ETH_ADDRESS == _fromToken || TOKEN_ETH_ADDRESS == _toToken);
        require(_fromToken != _toToken);
        require(!isTokenIncluded[_fromToken] || !isTokenIncluded[_toToken]);

        if(!isTokenIncluded[_fromToken]) {
            isTokenIncluded[_fromToken] = true;
            tokensIncluded.push(_fromToken);
        }
        
        if(!isTokenIncluded[_toToken]) {
            isTokenIncluded[_toToken] = true;
            tokensIncluded.push(_toToken);
        }

        setTokenPairAndRate(_fromToken, _toToken, _rate);
    }

    /**
     * @dev modify a pair of token
     * @param _fromToken fromToken address
     * @param _toToken toToken address
     * @param _rate the new rate between two tokens
     * @return bool
     */
    function modifyTokenPairRate(Token _fromToken, Token _toToken, uint _rate) public onlyOwner {
        require(minRate <= _rate && _rate <= maxRate);
        require(TOKEN_ETH_ADDRESS == _fromToken || TOKEN_ETH_ADDRESS == _toToken);
        require(_fromToken != _toToken);
        require(isTokenIncluded[_fromToken] && isTokenIncluded[_toToken]);
        setTokenPairAndRate(_fromToken, _toToken, _rate);
    }

    event SetTokenPairAndRate(Token _fromToken, Token _toToken, uint _rate);
    /**
     * @dev set a pair of token
     * @param _fromToken fromToken address
     * @param _toToken toToken address
     * @param _rate the new rate between two tokens
     * @return bool
     */
    function setTokenPairAndRate(Token _fromToken, Token _toToken, uint _rate) internal {
        PairTokenRate memory pairTokenRate = PairTokenRate(block.number, _rate);
        bytes32 tokenPair1 = keccak256(abi.encodePacked(_fromToken, _toToken));
        bytes32 tokenPair2 = keccak256(abi.encodePacked(_toToken, _fromToken));
        pairTokenRates[tokenPair1] = pairTokenRate;
        pairTokenRates[tokenPair2] = pairTokenRate;

        isPairToken[tokenPair1] = true;
        isPairToken[tokenPair2] = true;

        emit SetTokenPairAndRate(_fromToken, _toToken, _rate);
    }

    /**
     * @dev return a pair of token
     * @param _fromToken fromToken address
     * @param _toToken toToken address
     * @return uint The rate between two tokens
     * @return uint The current blockNumber when the rate was set
     * @return uint The current blockNumber
     */
    function getTokenPairAndRate(Token _fromToken, Token _toToken) public view returns(uint, uint, uint) {
        bytes32 tokenPair = keccak256(abi.encodePacked(_fromToken, _toToken));
        require(isPairToken[tokenPair]);
        return (pairTokenRates[tokenPair].rate, pairTokenRates[tokenPair].blockNumber, block.number);
    }

    event SetTokenReserveInfo(Token _token, uint _targetAmount, uint _depositRatio, uint _stopRatio);
    /**
     * @dev set a token's info
     * @param _token toToken address
     * @param _targetAmount Target number of token
     * @param _depositRatio Ratio to deposit
     * @param _stopRatio Ratio to stop
     * @return bool
     */
    function setTokenReserveInfo(Token _token, uint _targetAmount, uint _depositRatio, uint _stopRatio) public onlyOwner {
        require(0 <= _targetAmount);
        require(0 <= _stopRatio && _stopRatio <= _depositRatio);
        require(isTokenIncluded[_token]);
        tokenReserveInfos[_token].targetAmount = _targetAmount;
        tokenReserveInfos[_token].depositRatio = _depositRatio;
        tokenReserveInfos[_token].stopRatio = _stopRatio;

        emit SetTokenReserveInfo(_token, _targetAmount, _depositRatio, _stopRatio);
    }

    /**
     * @dev ret a token's info
     * @param _token toToken address
     * @return _targetAmount Target number of token
     * @return _depositRatio Ratio to deposit
     * @return _stopRatio Ratio to stop
     */
    function getTokenReserveInfo(Token _token) 
        public 
        onlyOwner
        view 
        returns
        (uint marketPrice, uint transactionPrice, uint tokenPairRate, uint decimalsToken, uint currentAmount, uint targetAmount, uint depositRatio, uint stopRatio)
    {
        require(isTokenIncluded[_token]);
        TokenReserveInfo storage tokenReserveInfo = tokenReserveInfos[_token];

        decimalsToken = getTokenDecimals(_token);
        currentAmount = getBalance(_token, address(this));

        if(TOKEN_ETH_ADDRESS == _token) {
            marketPrice = PRICE_PRODUCT;
            transactionPrice = PRICE_PRODUCT;
            tokenPairRate = standardRate;
        } else {
            (marketPrice, transactionPrice) = thorNetwork.getTokenTransactionPrice(_token);
            bytes32 tokenPair = keccak256(abi.encodePacked(TOKEN_ETH_ADDRESS, _token));
            require(isPairToken[tokenPair]);
            tokenPairRate = pairTokenRates[tokenPair].rate;
        }

        targetAmount = tokenReserveInfo.targetAmount;
        depositRatio = tokenReserveInfo.depositRatio;
        stopRatio = tokenReserveInfo.stopRatio;
    }

    event BalanceToken(Token _token, uint _depositAmount);
    /**
     * @dev inform the reserve of the current tokens number 
     * @param _token toToken address
     * @return bool
     */
    function balanceToken(Token _token) internal returns(bool) {
        require(isTokenIncluded[_token]);
        uint depositTokenAmount = tokenReserveInfos[_token].targetAmount.mul(tokenReserveInfos[_token].depositRatio).div(targetRatio);
        uint currentTokenAmount = getBalance(_token, address(this));
        if(currentTokenAmount < depositTokenAmount) {
            uint depositAmount = depositTokenAmount.sub(currentTokenAmount);
            emit BalanceToken(_token, depositAmount);
            return true;
        } else {
            return false;
        }
    }

    event SetTokenPairIsEnable(Token _fromToken, Token _toToken, bool isEnable);
    /**
     * @dev Set function of two token swap
     * @param _toToken toToken address
     * @param _toToken toToken address
     * @param isEnable true, function normal; false, function stop.
     */
    function setTokenPairIsEnable(Token _fromToken, Token _toToken, bool isEnable) public onlyOwner {
        require(isTokenIncluded[_fromToken] && isTokenIncluded[_toToken]);
        bytes32 tokenPair = keccak256(abi.encodePacked(_fromToken, _toToken));
        isPairToken[tokenPair] = isEnable;

        emit SetTokenPairIsEnable(_fromToken, _toToken, isEnable);
    }

    /**
     * @dev return function of two token swap
     * @param _toToken toToken address
     * @param _toToken toToken address
     * @return bool
     */
    function getTokenPairIsEnable(Token _fromToken, Token _toToken) public view onlyOwner returns(bool) {
        require(isTokenIncluded[_fromToken] && isTokenIncluded[_toToken]);
        bytes32 tokenPair = keccak256(abi.encodePacked(_fromToken, _toToken));
        return isPairToken[tokenPair];
    }

    event SetThorNetworkContract(ThorNetworkReserveInterface _thorNetworkContract);
    /**
     * @dev set ThorNetwork contracts
     * @param _thorNetworkContract ThorNetwork contract
     */
    function setThorNetworkContract(ThorNetworkReserveInterface _thorNetworkContract) public onlyOwner {
        require(_thorNetworkContract != address(0));
        thorNetwork = _thorNetworkContract;

        emit SetThorNetworkContract(_thorNetworkContract);
    }

    /**
     * @dev return ThorNetwork contracts
     * @return _thorNetworkContract ThorNetwork contract
     */
    function getThorNetworkContract() public view onlyOwner returns(address) {
        return thorNetwork;
    }
}

contract ThorFee is Ownable, Utils{
    using SafeMath for uint256;

    string public contractName;

    address internal thorWalletAddress = address(0xe2a774bbab574837c9bc178ffd4d4f2e04841f5c);

    address public thorNetwork;

    uint internal walletFeeRatio = 4;
    uint internal thorWalletFeeRatio = 6;

    mapping(address => uint) walletsFee;

    constructor(address _thorNetwork) public {
        contractName = "ThorFee";
        thorNetwork = _thorNetwork;
    }

    event HandleFee(uint platformFee, address walletId);
    /**
     * @dev distribute fees to wallet and ThorNetwork
     * @param _platformFee the total of fee
     * @param _walletId address of wallet
     * @return bool
     */
    function handleFee(uint _platformFee, address _walletId) public payable returns(bool) {
        require(thorNetwork == msg.sender);

        uint walletFee = _platformFee.mul(walletFeeRatio).div(10);
        uint thornetworkFee = _platformFee.mul(thorWalletFeeRatio).div(10);

        walletsFee[_walletId] = walletsFee[_walletId].add(walletFee);
        walletsFee[thorWalletAddress] = walletsFee[thorWalletAddress].add(thornetworkFee);

        emit HandleFee(_platformFee, _walletId);
        return true;
    }

    event EtherFeeWithdraw(uint _amount, address _sendTo);
    /**
     * @dev set wallet address of ThorNetwork
     * @param _sendTo wallet address of ThorNetwork
     * @param _amount wallet address of ThorNetwork
     * @return bool
     */
    function withdrawFee(address _sendTo, uint _amount) public returns(bool) {
        require(walletsFee[msg.sender] != 0);
        require(_sendTo != address(0));

        uint256 actualFeeAmount = walletsFee[msg.sender];
        uint256 sendAmount = _amount;

        if(sendAmount >= actualFeeAmount) {
            sendAmount = actualFeeAmount;
        }

        require(actualFeeAmount >= sendAmount);
        walletsFee[msg.sender] = actualFeeAmount.sub(sendAmount);

        _sendTo.transfer(sendAmount);

        emit EtherFeeWithdraw(sendAmount, _sendTo);

        return true;
    }

    /**
     * @dev return fee of a wallet
     * @param _walletAddress  address of a wallet
     * @return uint
     */
    function getWalletFee(address _walletAddress) public onlyOwner view returns(uint) {
        return walletsFee[_walletAddress];
    }

    function getSelfWalletFee() public view returns(uint) {
        return walletsFee[msg.sender];
    }

    event SetThorWalletAddress(address _thorWalletAddress);
    /**
     * @dev set wallet address of ThorNetwork
     * @param _thorWalletAddress wallet address of ThorNetwork
     * @return bool
     */
    function setThorWalletAddress(address _thorWalletAddress) public onlyOwner {
        require(_thorWalletAddress != address(0));
        thorWalletAddress = _thorWalletAddress;

        emit SetThorWalletAddress(_thorWalletAddress);
    }

    /**
     * @dev ret wallet address of ThorNetwork
     * @return wallet address of ThorNetwork
     */
    function getThorWalletAddress() public view onlyOwner returns(address) {
        return thorWalletAddress;
    }

    event SetThorNetworkContract(address _thorNetworkContract);
    /**
     * @dev set ThorNetwork contracts
     * @param _thorNetworkContract ThorNetwork contract
     */
    function setThorNetworkContract(address _thorNetworkContract) public onlyOwner {
        require(_thorNetworkContract != address(0));
        thorNetwork = _thorNetworkContract;

        emit SetThorNetworkContract(_thorNetworkContract);
    }

    /**
     * @dev return ThorNetwork contracts
     * @return _thorNetworkContract ThorNetwork contract
     */
    function getThorNetworkContract() public view onlyOwner returns(address) {
        return thorNetwork;
    }

    event SetFeeDistributionRatio(uint _walletFeeRatio, uint _thorWalletFeeRatio);
    /**
     * @dev set distribution ratio of wallet and ThorNetwork
     * @param _walletFeeRatio wallet get _walletFeeRatio/10 of fee
     * @param _thorWalletFeeRatio ThorNetwork get _thorWalletFeeRatio/10 of fee
     * @return bool
     */
    function setFeeDistributionRatio(uint _walletFeeRatio, uint _thorWalletFeeRatio) public onlyOwner {
        require((_walletFeeRatio + _thorWalletFeeRatio) == 10);
        walletFeeRatio = _walletFeeRatio;
        thorWalletFeeRatio = _thorWalletFeeRatio;

        emit SetFeeDistributionRatio(_walletFeeRatio, _thorWalletFeeRatio);
    }
}

contract ThorUserInfo is Ownable, Utils, Withdrawable {
    string public contractName;

    address public thorNetwork;

    mapping(address => uint) userQuotas;

    uint256 internal constant QUOTA = 10 ** 18;

    constructor (address _thorNetwork) public {
        contractName = "ThorUserInfo";
        thorNetwork = _thorNetwork;
    }

    event SetUserQuota(address _user, uint256 _quota);
    //0--10ETH, 1--20ETH, 2--30ETH
    /**
     * @dev Set a user's quota
     * @param _user The address of the token contract
     * @param _quota The amount of token
     * @return bool
     */
    function setUserQuota(address _user, uint256 _quota) public onlyOwner {
        userQuotas[_user] = _quota;
        emit SetUserQuota(_user, _quota);
    }

    /**
     * @dev Return a user's quota
     * @param _user The address of the token contract
     * @return uint The quota in wei
     */
    function getUserQuota(address _user) public view returns(uint) {
        require(thorNetwork == msg.sender);

        return 10 * (userQuotas[_user] + 1) * QUOTA;
    }

    event SetThorNetworkContract(address _thorNetworkContract);
    /**
     * @dev set ThorNetwork contracts
     * @param _thorNetworkContract ThorNetwork contract
     */
    function setThorNetworkContract(address _thorNetworkContract) public onlyOwner {
        require(_thorNetworkContract != address(0));
        thorNetwork = _thorNetworkContract;
        emit SetThorNetworkContract(_thorNetworkContract);
    }

    /**
     * @dev return ThorNetwork contracts
     * @return _thorNetworkContract ThorNetwork contract
     */
    function getThorNetworkContract() public view onlyOwner returns(address) {
        return thorNetwork;
    }
}

contract ThorPrice is Ownable, Utils, Withdrawable {
    string public contractName;

    using SafeMath for uint256;

    address public thorNetwork;

    address[] tokensIncluded;
    mapping(address => bool) isTokenIncluded;

    mapping(bytes32 => bool) isPairToken;       // when one ERC20 token could be exchanged with ETH, true

    uint internal moleculePrice = 100;
    uint internal denominatorPrice = 100;

    struct PairTokenPrice {
        uint blockNumber;                       // the block when Price was modified
        uint marketPrice;
        uint transactionPrice;                              // two tokens min Price
    }
    mapping(bytes32 => PairTokenPrice) pairTokenPrices;

    constructor (address _thorNetwork) public {
        contractName = "ThorPrice";
        thorNetwork = _thorNetwork;
    }

    /**
     * @dev return all tokens in the price
     * @return address[], a list of tokens
     */
    function getTokensIncluded() public view returns(address[]) {
        return tokensIncluded;
    }

    event SetPriceRate(uint _moleculePrice, uint _denominatorPrice);
    /**
     * @dev set price rate, actualPrice = price * _moleculePrice / _denominatorPrice
     * @param _moleculePrice actualPrice = price * _moleculePrice / _denominatorPrice
     * @param _denominatorPrice actualPrice = price * _moleculePrice / _denominatorPrice
     */
    function setPriceRate(uint _moleculePrice, uint _denominatorPrice) public onlyOwner {
        require(_denominatorPrice >= _moleculePrice);
        require(_moleculePrice >= 90);
        require(_denominatorPrice <= 100);
        moleculePrice = _moleculePrice;
        denominatorPrice = _denominatorPrice;
        emit SetPriceRate(_moleculePrice, _denominatorPrice);
    }

    function getPriceRate() public view returns(uint, uint) {
        return (moleculePrice, denominatorPrice);
    }

    event AddTokenPairAndPrice(Token _fromToken, Token _toToken, uint _price);
    /**
     * @dev add a price of new token, _price = actualPrice * 10 ** 8
     * @param _fromToken fromToken address
     * @param _toToken toToken address
     * @param _price the new rate between two tokens
     * @return bool
     */
    function addTokenPairAndPrice(Token _fromToken, Token _toToken, uint _price) public onlyOperator {
        require(!isTokenIncluded[_fromToken] || !isTokenIncluded[_toToken]);

        if(!isTokenIncluded[_fromToken]) {
            isTokenIncluded[_fromToken] = true;
            tokensIncluded.push(_fromToken);
        }
        
        if(!isTokenIncluded[_toToken]) {
            isTokenIncluded[_toToken] = true;
            tokensIncluded.push(_toToken);
        }

        setTokenPairAndPrice(_fromToken, _toToken, _price);
        emit AddTokenPairAndPrice(_fromToken, _toToken, _price);
    }

    event AddTokenPairsAndPrice(Token[] _tokens, uint[] _prices);
    /**
     * @dev add a new price of tokens, _price = actualPrice * 10 ** 8
     * @param _tokens fromToken address
     * @param _prices the new rate between two tokens
     * @return bool
     */
    function addTokenPairsAndPrice(Token[] _tokens, uint[] _prices) public onlyOperator {
        require(_tokens.length == _prices.length);
        for (uint i = 0; i < _tokens.length; i++) {
            addTokenPairAndPrice(TOKEN_ETH_ADDRESS, _tokens[i], _prices[i]);
        }
        emit AddTokenPairsAndPrice(_tokens, _prices);
    }

    event ModifyTokenPairPrice(Token _fromToken, Token _toToken, uint _price);
    /**
     * @dev modify a new price of tokens
     * @param _fromToken fromToken address
     * @param _toToken toToken address
     * @param _price the new rate between two tokens
     * @return bool
     */
    function modifyTokenPairPrice(Token _fromToken, Token _toToken, uint _price) public onlyOperator {
        require(isTokenIncluded[_fromToken] && isTokenIncluded[_toToken]);
        setTokenPairAndPrice(_fromToken, _toToken, _price);

        emit ModifyTokenPairPrice(_fromToken, _toToken, _price);
    }

    /**
     * @dev add a new price of token
     * @param _fromToken fromToken address
     * @param _toToken toToken address
     * @param _price the new rate between two tokens
     * @return bool
     */
    function setTokenPairAndPrice(Token _fromToken, Token _toToken, uint _price) internal returns(bool) {
        require(TOKEN_ETH_ADDRESS == _fromToken || TOKEN_ETH_ADDRESS == _toToken);
        require(_fromToken != _toToken);
        uint marketPrice = _price;
        uint marketPriceInverse = MAX_PRICE_PRODUCT.div(marketPrice);

        uint transactionPrice = marketPrice.mul(moleculePrice).div(denominatorPrice);
        uint transactionInversePrice = marketPriceInverse.mul(moleculePrice).div(denominatorPrice);

        PairTokenPrice memory pairTokenPrice1 = PairTokenPrice(block.number, marketPrice, transactionPrice);
        PairTokenPrice memory pairTokenPrice2 = PairTokenPrice(block.number, marketPriceInverse, transactionInversePrice);
        bytes32 tokenPair1 = keccak256(abi.encodePacked(_fromToken, _toToken));
        bytes32 tokenPair2 = keccak256(abi.encodePacked(_toToken, _fromToken));
        pairTokenPrices[tokenPair1] = pairTokenPrice1;
        pairTokenPrices[tokenPair2] = pairTokenPrice2;

        isPairToken[tokenPair1] = true;
        isPairToken[tokenPair2] = true;
    }

    event SetTokenPairsPrice(Token[] _fromTokens, Token[] _toTokens, uint[] _Prices);
    /**
     * @dev set a list of tokens price
     * @param _fromTokens a list fromTokens address
     * @param _toTokens a list of toTokens address
     * @param _Prices a list of prices
     * @return bool
     */
    function setTokenPairsPrice(Token[] _fromTokens, Token[] _toTokens, uint[] _Prices) public onlyOperator returns(bool) {
        require(_fromTokens.length == _toTokens.length);
        require(_fromTokens.length == _Prices.length);
        for(uint i = 0; i < _fromTokens.length; i++){
            require(isTokenIncluded[_fromTokens[i]] && isTokenIncluded[_toTokens[i]]);
            setTokenPairAndPrice(_fromTokens[i], _toTokens[i], _Prices[i]);
        }

        emit SetTokenPairsPrice(_fromTokens, _toTokens, _Prices);
        return true;
    }

    /**
     * @dev return a price of tokens
     * @param _fromToken fromToken address
     * @param _toToken toToken address
     * @return bool
     */
    function getTokenPairAndPrice(Token _fromToken, Token _toToken) public view returns(uint) {
        if(TOKEN_ETH_ADDRESS == _fromToken || TOKEN_ETH_ADDRESS == _toToken) {
            bytes32 tokenPair = keccak256(abi.encodePacked(_fromToken, _toToken));
            require(isPairToken[tokenPair]);
            return pairTokenPrices[tokenPair].transactionPrice;
        } else {
            bytes32 tokenPair1 = keccak256(abi.encodePacked(_fromToken, TOKEN_ETH_ADDRESS));
            bytes32 tokenPair2 = keccak256(abi.encodePacked(TOKEN_ETH_ADDRESS, _toToken));
            require(isPairToken[tokenPair1] && isPairToken[tokenPair2]);
            uint256 tokenPairPrice1 = pairTokenPrices[tokenPair1].transactionPrice;
            uint256 tokenPairPrice2 = pairTokenPrices[tokenPair2].transactionPrice;

            return tokenPairPrice1.mul(tokenPairPrice2).div(PRICE_PRODUCT).mul(denominatorPrice).div(moleculePrice);
        }
    }

    function getTokenTransactionPrice(Token _token) public view returns(uint, uint) {
        require(TOKEN_ETH_ADDRESS != _token);
        bytes32 tokenPair = keccak256(abi.encodePacked(TOKEN_ETH_ADDRESS, _token));
        require(isPairToken[tokenPair]);
        return (pairTokenPrices[tokenPair].marketPrice, pairTokenPrices[tokenPair].transactionPrice);
    }

    event SetTokenPairIsEnable(Token _fromToken, Token _toToken, bool isEnable);
    /**
     * @dev Set function of two token swap
     * @param _toToken toToken address
     * @param _toToken toToken address
     * @param isEnable true, function normal; false, function stop.
     */
    function setTokenPairIsEnable(Token _fromToken, Token _toToken, bool isEnable) public onlyOwner {
        require(isTokenIncluded[_fromToken] && isTokenIncluded[_toToken]);
        bytes32 tokenPair = keccak256(abi.encodePacked(_fromToken, _toToken));
        isPairToken[tokenPair] = isEnable;
        emit SetTokenPairIsEnable(_fromToken, _toToken, isEnable);
    }

    /**
     * @dev return function of two token swap
     * @param _toToken toToken address
     * @param _toToken toToken address
     * @return bool
     */
    function getTokenPairIsEnable(Token _fromToken, Token _toToken) public view onlyOwner returns(bool) {
        require(isTokenIncluded[_fromToken] && isTokenIncluded[_toToken]);
        bytes32 tokenPair = keccak256(abi.encodePacked(_fromToken, _toToken));
        return isPairToken[tokenPair];
    }

    event SetThorNetworkContract(address _thorNetworkContract);
    /**
     * @dev set ThorNetwork contracts
     * @param _thorNetworkContract ThorNetwork contract
     */
    function setThorNetworkContract(address _thorNetworkContract) public onlyOwner {
        require(_thorNetworkContract != address(0));
        thorNetwork = _thorNetworkContract;
        emit SetThorNetworkContract(_thorNetworkContract);
    }

    /**
     * @dev return ThorNetwork contracts
     * @return _thorNetworkContract ThorNetwork contract
     */
    function getThorNetworkContract() public view onlyOwner returns(address) {
        return thorNetwork;
    }

}

    Contract ABI  
[{"constant":false,"inputs":[{"name":"oldOwner","type":"address"}],"name":"removeOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"func","type":"string"}],"name":"retAuthorizedFunc","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_sendTo","type":"address"}],"name":"withdrawToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_thorNetworkContract","type":"address"}],"name":"setThorNetworkContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_oldOperator","type":"address"}],"name":"delOperator","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_fromToken","type":"address"},{"name":"_toToken","type":"address"},{"name":"_fromAmount","type":"uint256"}],"name":"calculateToTokenAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_fromToken","type":"address"},{"name":"_toToken","type":"address"},{"name":"_fromAmount","type":"uint256"},{"name":"_minRate","type":"uint256"}],"name":"findBestRate","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTokensIncluded","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getThorNetworkContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"thorNetwork","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_fromToken","type":"address"},{"name":"_fromAmount","type":"uint256"},{"name":"_toToken","type":"address"},{"name":"_minRate","type":"uint256"},{"name":"_walletId","type":"address"}],"name":"exchange","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"addOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_ownerIndex","type":"uint256"}],"name":"retOwners","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contractName","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"}],"name":"getTokenDecimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"func","type":"string"},{"name":"operatingOwner","type":"address"}],"name":"authorizeOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getMaxGasPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_fromToken","type":"address"},{"name":"_toToken","type":"address"}],"name":"getTokenPairAndPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newOperator","type":"address"}],"name":"addOperator","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_user","type":"address"}],"name":"getUserQuota","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_fromToken","type":"address"},{"name":"_fromAmount","type":"uint256"}],"name":"calculatePlatformFeeInWei","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"setTokenDecimals","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"},{"name":"_sendTo","type":"address"}],"name":"withdrawEther","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"},{"name":"_user","type":"address"}],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"retOperators","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":true,"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"trader","type":"address"},{"indexed":false,"name":"src","type":"address"},{"indexed":false,"name":"dest","type":"address"},{"indexed":false,"name":"actualSrcAmount","type":"uint256"},{"indexed":false,"name":"actualDestAmount","type":"uint256"}],"name":"ThorNetworkProxyExchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_thorNetworkContract","type":"address"}],"name":"SetThorNetworkContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_token","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"},{"indexed":false,"name":"_sendTo","type":"address"}],"name":"TokenWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_amount","type":"uint256"},{"indexed":false,"name":"_sendTo","type":"address"}],"name":"EtherWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"newOwner","type":"address"}],"name":"AddOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"oldOwner","type":"address"}],"name":"RemoveOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"func","type":"string"},{"indexed":false,"name":"operatingOwner","type":"address"}],"name":"AuthorizeOwner","type":"event"}]

  Contract Creation Code Switch To Opcodes View
60008080556004805460ff199081169091556001805433600160a060020a031991821681178355600580548085019091557f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db001805490921681179091558352600660205260408084208054909316821790925582540190915560c09052601060808190527f54686f724e6574776f726b50726f78790000000000000000000000000000000060a0908152620000b891600a9190620000bf565b5062000164565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200010257805160ff191683800117855562000132565b8280016001018555821562000132579182015b828111156200013257825182559160200191906001019062000115565b506200014092915062000144565b5090565b6200016191905b808211156200014057600081556001016200014b565b90565b6128bb80620001746000396000f30060806040526004361061015b5763ffffffff60e060020a600035041663173825d981146101605780633107d505146101955780633ccdbb281461020a5780633da53f9c146102375780633e30838d146102585780633f089405146102795780633f4ba83a146102b557806346dc4e06146102ca57806357c188ce146103105780635c975abb1461037557806361a281e21461038a57806366802c6d1461039f57806369516ad7146103b45780637065cb48146103dc57806374fb4ef2146103fd57806375d0c0dc14610415578063785c7cf61461049f5780638456cb59146104c057806386e28552146104d557806389c98c061461053957806392e3926f1461054e5780639870d7fe1461057557806398a299e514610596578063bfbc0b77146105b7578063c57b3beb146105db578063ce56c454146105fc578063d4fac45d14610620578063e780a2aa14610647578063f2fde38b1461065c575b600080fd5b34801561016c57600080fd5b50610181600160a060020a036004351661067d565b604080519115158252519081900360200190f35b3480156101a157600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526101ee943694929360249392840191908190840183828082843750949750610a6a9650505050505050565b60408051600160a060020a039092168252519081900360200190f35b34801561021657600080fd5b50610235600160a060020a036004358116906024359060443516610b25565b005b34801561024357600080fd5b50610235600160a060020a0360043516610c59565b34801561026457600080fd5b50610181600160a060020a0360043516610d0d565b34801561028557600080fd5b506102a3600160a060020a0360043581169060243516604435610eb4565b60408051918252519081900360200190f35b3480156102c157600080fd5b50610235610f14565b3480156102d657600080fd5b506102f7600160a060020a03600435811690602435166044356064356110df565b6040805192835260208301919091528051918290030190f35b34801561031c57600080fd5b506103256111c2565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610361578181015183820152602001610349565b505050509050019250505060405180910390f35b34801561038157600080fd5b506101816112b2565b34801561039657600080fd5b506101ee6112bb565b3480156103ab57600080fd5b506101ee611318565b6102a3600160a060020a03600435811690602435906044358116906064359060843516611327565b3480156103e857600080fd5b50610181600160a060020a036004351661138f565b34801561040957600080fd5b506101ee600435611744565b34801561042157600080fd5b5061042a6117ca565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561046457818101518382015260200161044c565b50505050905090810190601f1680156104915780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156104ab57600080fd5b506102a3600160a060020a0360043516611858565b3480156104cc57600080fd5b506102356118f9565b3480156104e157600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261018194369492936024939284019190819084018382808284375094975050509235600160a060020a03169350611ac792505050565b34801561054557600080fd5b506102a3611cba565b34801561055a57600080fd5b506102a3600160a060020a0360043581169060243516611d4a565b34801561058157600080fd5b50610181600160a060020a0360043516611df2565b3480156105a257600080fd5b506102a3600160a060020a0360043516611ee1565b3480156105c357600080fd5b506102a3600160a060020a0360043516602435611f4c565b3480156105e757600080fd5b50610235600160a060020a0360043516611fbe565b34801561060857600080fd5b50610235600435600160a060020a036024351661208b565b34801561062c57600080fd5b506102a3600160a060020a0360043581169060243516612154565b34801561065357600080fd5b5061032561221a565b34801561066857600080fd5b50610235600160a060020a03600435166122c7565b60008080805b60038110156106bc57336001826003811061069a57fe5b0154600160a060020a031614156106b457600191506106bc565b600101610683565b8115156106c857600080fd5b60408051808201909152600b81527f72656d6f76654f776e65720000000000000000000000000000000000000000006020820152600054600110156109375733600160a060020a03166007826040518082805190602001908083835b602083106107435780518252601f199092019160209182019101610724565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a0316929092149150610789905057600080fd5b60006007826040518082805190602001908083835b602083106107bd5780518252601f19909201916020918201910161079e565b51815160209384036101000a600019018019909216911617905292019485525060405193849003019092208054600160a060020a031916600160a060020a03949094169390931790925550506000546003111561081957600080fd5b600160a060020a03861633141561082f57600080fd5b600093505b6000548410156108f3576001846003811061084b57fe5b0154600160a060020a03878116911614610864576108e8565b600054600190600019016003811061087857fe5b0154600160a060020a03166001856003811061089057fe5b018054600160a060020a031916600160a060020a03929092169190911790556000805460019060001901600381106108c457fe5b018054600160a060020a031916600160a060020a03929092169190911790556108f3565b600190930192610834565b60008054600019018155604051600160a060020a038816917fac6e8398676cf37429d530b81144d7079e99f4fe9d28b0d88c4a749ceccbe8cd91a260019450610a61565b6000546003111561094757600080fd5b600160a060020a03861633141561095d57600080fd5b600093505b600054841015610a21576001846003811061097957fe5b0154600160a060020a0387811691161461099257610a16565b60005460019060001901600381106109a657fe5b0154600160a060020a0316600185600381106109be57fe5b018054600160a060020a031916600160a060020a03929092169190911790556000805460019060001901600381106109f257fe5b018054600160a060020a031916600160a060020a0392909216919091179055610a21565b600190930192610962565b60008054600019018155604051600160a060020a038816917fac6e8398676cf37429d530b81144d7079e99f4fe9d28b0d88c4a749ceccbe8cd91a2600194505b50505050919050565b600080805b6003811015610aa8573360018260038110610a8657fe5b0154600160a060020a03161415610aa05760019150610aa8565b600101610a6f565b811515610ab457600080fd5b6007846040518082805190602001908083835b60208310610ae65780518252601f199092019160209182019101610ac7565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a03169695505050505050565b6000805b6003811015610b62573360018260038110610b4057fe5b0154600160a060020a03161415610b5a5760019150610b62565b600101610b29565b811515610b6e57600080fd5b84600160a060020a031663a9059cbb84866040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b158015610bd157600080fd5b505af1158015610be5573d6000803e3d6000fd5b505050506040513d6020811015610bfb57600080fd5b50511515610c0857600080fd5b60408051600160a060020a0380881682526020820187905285168183015290517f72cb8a894ddb372ceec3d2a7648d86f17d5a15caae0e986c53109b8a9a9385e69181900360600190a15050505050565b6000805b6003811015610c96573360018260038110610c7457fe5b0154600160a060020a03161415610c8e5760019150610c96565b600101610c5d565b811515610ca257600080fd5b600160a060020a0383161515610cb757600080fd5b60098054600160a060020a038516600160a060020a0319909116811790915560408051918252517fa290c18be4400eb4f583b32fbe432f8e184b6ed55db534b310ab995755c5f9f49181900360200190a1505050565b6000808080805b6003811015610d4d573360018260038110610d2b57fe5b0154600160a060020a03161415610d455760019150610d4d565b600101610d14565b811515610d5957600080fd5b600160a060020a03861660009081526006602052604090205460ff161515610d8057600080fd5b6005549350600092505b83831015610e74576005805484908110610da057fe5b600091825260209091200154600160a060020a03878116911614610dc357610e69565b600580546000198601908110610dd557fe5b60009182526020909120015460058054600160a060020a039092169185908110610dfb57fe5b600091825260208220018054600160a060020a031916600160a060020a039390931692909217909155600580546000198701908110610e3657fe5b9060005260206000200160006101000a815481600160a060020a030219169083600160a060020a03160217905550610e74565b600190920191610d8a565b600160a060020a0386166000908152600660205260409020805460ff191690556005805490610ea7906000198301612852565b5060019695505050505050565b6000806000610ec38686611d4a565b9150610ee96305f5e100610edd868563ffffffff6125be16565b9063ffffffff6125e716565b9050610f0a610ef786611858565b8290601203600a0a63ffffffff6125e716565b9695505050505050565b6000805b6003811015610f51573360018260038110610f2f57fe5b0154600160a060020a03161415610f495760019150610f51565b600101610f18565b811515610f5d57600080fd5b60408051808201909152600781527f756e7061757365000000000000000000000000000000000000000000000000006020820152600054600110156110be5733600160a060020a03166007826040518082805190602001908083835b60208310610fd85780518252601f199092019160209182019101610fb9565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a031692909214915061101e905057600080fd5b60006007826040518082805190602001908083835b602083106110525780518252601f199092019160209182019101611033565b51815160209384036101000a600019018019909216911617905292019485525060405193849003019092208054600160a060020a031916600160a060020a039490941693909317909255505060045460ff1615156110af57600080fd5b6004805460ff191690556110da565b60045460ff1615156110cf57600080fd5b6004805460ff191690555b505050565b600954604080517fcab1e847000000000000000000000000000000000000000000000000000000008152600160a060020a0387811660048301528681166024830152604482018690527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6064830152608482018590528251600094859492169263cab1e8479260a480830193919282900301818787803b15801561118257600080fd5b505af1158015611196573d6000803e3d6000fd5b505050506040513d60408110156111ac57600080fd5b5080516020909101519097909650945050505050565b600954604080517f57c188ce0000000000000000000000000000000000000000000000000000000081529051606092600160a060020a0316916357c188ce91600480830192600092919082900301818387803b15801561122157600080fd5b505af1158015611235573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561125e57600080fd5b81019080805164010000000081111561127657600080fd5b8201602081018481111561128957600080fd5b81518560208202830111640100000000821117156112a657600080fd5b50909450505050505b90565b60045460ff1681565b600080805b60038110156112f95733600182600381106112d757fe5b0154600160a060020a031614156112f157600191506112f9565b6001016112c0565b81151561130557600080fd5b600954600160a060020a03169250505090565b600954600160a060020a031681565b600454600090819060ff161561133c57600080fd5b600160a060020a03878116908616141561135557600080fd5b61137461136188611858565b8790601203600a0a63ffffffff6125e716565b90506113848782873388886125fc565b979650505050505050565b600080805b60038110156113cd5733600182600381106113ab57fe5b0154600160a060020a031614156113c557600191506113cd565b600101611394565b8115156113d957600080fd5b60408051808201909152600881527f6164644f776e657200000000000000000000000000000000000000000000000060208201526000546001101561162d5733600160a060020a03166007826040518082805190602001908083835b602083106114545780518252601f199092019160209182019101611435565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a031692909214915061149a905057600080fd5b60006007826040518082805190602001908083835b602083106114ce5780518252601f1990920191602091820191016114af565b51815160209384036101000a600019018019909216911617905292019485525060405193849003019092208054600160a060020a031916600160a060020a039490941693909317909255505060005460031161152957600080fd5b600160a060020a038516151561153e57600080fd5b84600160005460038110151561155057fe5b018054600160a060020a031916600160a060020a0392831617905560008054600101815590861681526006602052604090205460ff1615156115f0576005805460018082019092557f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0018054600160a060020a031916600160a060020a0388169081179091556000908152600660205260409020805460ff191690911790555b604051600160a060020a038616907fac1e9ef41b54c676ccf449d83ae6f2624bcdce8f5b93a6b48ce95874c332693d90600090a26001935061173c565b60005460031161163c57600080fd5b600160a060020a038516151561165157600080fd5b84600160005460038110151561166357fe5b018054600160a060020a031916600160a060020a0392831617905560008054600101815590861681526006602052604090205460ff161515611703576005805460018082019092557f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0018054600160a060020a031916600160a060020a0388169081179091556000908152600660205260409020805460ff191690911790555b604051600160a060020a038616907fac1e9ef41b54c676ccf449d83ae6f2624bcdce8f5b93a6b48ce95874c332693d90600090a2600193505b505050919050565b600080805b600381101561178257336001826003811061176057fe5b0154600160a060020a0316141561177a5760019150611782565b600101611749565b81151561178e57600080fd5b83600311801561179f575083600011155b15156117aa57600080fd5b600184600381106117b757fe5b0154600160a060020a0316949350505050565b600a805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156118505780601f1061182557610100808354040283529160200191611850565b820191906000526020600020905b81548152906001019060200180831161183357829003601f168201915b505050505081565b600073aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa600160a060020a0383161415611887575060126118f4565b81600160a060020a031663313ce5676040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156118c557600080fd5b505af11580156118d9573d6000803e3d6000fd5b505050506040513d60208110156118ef57600080fd5b505190505b919050565b6000805b600381101561193657336001826003811061191457fe5b0154600160a060020a0316141561192e5760019150611936565b6001016118fd565b81151561194257600080fd5b60408051808201909152600581527f7061757365000000000000000000000000000000000000000000000000000000602082015260005460011015611aa55733600160a060020a03166007826040518082805190602001908083835b602083106119bd5780518252601f19909201916020918201910161199e565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a0316929092149150611a03905057600080fd5b60006007826040518082805190602001908083835b60208310611a375780518252601f199092019160209182019101611a18565b51815160209384036101000a600019018019909216911617905292019485525060405193849003019092208054600160a060020a031916600160a060020a039490941693909317909255505060045460ff1615611a9357600080fd5b6004805460ff191660011790556110da565b60045460ff1615611ab557600080fd5b6004805460ff19166001179055505050565b60008080805b6003811015611b06573360018260038110611ae457fe5b0154600160a060020a03161415611afe5760019150611b06565b600101611acd565b811515611b1257600080fd5b600160a060020a038516331415611b2857600080fd5b331515611b3457600080fd5b600092505b600054831015611b9157600160a060020a03851660018460038110611b5a57fe5b0154600160a060020a03161415611b7057611b91565b600160005403831415611b865760009350611cb1565b600190920191611b39565b846007876040518082805190602001908083835b60208310611bc45780518252601f199092019160209182019101611ba5565b51815160209384036101000a60001901801990921691161790529201948552506040805194859003820185208054600160a060020a031916600160a060020a03978816179055948a16848201528484528a5194840194909452505087517f3f148c7394cc08823ea429f9301b7a26493e1b18cedbb73459bcb712b46fc82c928992899290918291606083019186019080838360005b83811015611c71578181015183820152602001611c59565b50505050905090810190601f168015611c9e5780820380516001836020036101000a031916815260200191505b50935050505060405180910390a1600193505b50505092915050565b600954604080517f89c98c060000000000000000000000000000000000000000000000000000000081529051600092600160a060020a0316916389c98c0691600480830192602092919082900301818787803b158015611d1957600080fd5b505af1158015611d2d573d6000803e3d6000fd5b505050506040513d6020811015611d4357600080fd5b5051905090565b600954604080517f92e3926f000000000000000000000000000000000000000000000000000000008152600160a060020a0385811660048301528481166024830152915160009392909216916392e3926f9160448082019260209290919082900301818787803b158015611dbd57600080fd5b505af1158015611dd1573d6000803e3d6000fd5b505050506040513d6020811015611de757600080fd5b505190505b92915050565b600080805b6003811015611e30573360018260038110611e0e57fe5b0154600160a060020a03161415611e285760019150611e30565b600101611df7565b811515611e3c57600080fd5b600160a060020a0384161515611e5157600080fd5b600160a060020a03841660009081526006602052604090205460ff1615611e7757600080fd5b50506005805460018082019092557f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0018054600160a060020a031916600160a060020a03949094169384179055600092835260066020526040909220805460ff1916831790555090565b600954604080517f98a299e5000000000000000000000000000000000000000000000000000000008152600160a060020a038481166004830152915160009392909216916398a299e59160248082019260209290919082900301818787803b1580156118c557600080fd5b600954604080517fbfbc0b77000000000000000000000000000000000000000000000000000000008152600160a060020a038581166004830152602482018590529151600093929092169163bfbc0b779160448082019260209290919082900301818787803b158015611dbd57600080fd5b73aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa600160a060020a038216141561200457600160a060020a038116600090815260086020526040902060129055612088565b80600160a060020a031663313ce5676040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561204257600080fd5b505af1158015612056573d6000803e3d6000fd5b505050506040513d602081101561206c57600080fd5b5051600160a060020a0382166000908152600860205260409020555b50565b6000805b60038110156120c85733600182600381106120a657fe5b0154600160a060020a031614156120c057600191506120c8565b60010161208f565b8115156120d457600080fd5b604051600160a060020a0384169085156108fc029086906000818181858888f1935050505015801561210a573d6000803e3d6000fd5b5060408051858152600160a060020a038516602082015281517fec47e7ed86c86774d1a72c19f35c639911393fe7c1a34031fdbd260890da90de929181900390910190a150505050565b600073aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa600160a060020a038416141561218c5750600160a060020a03811631611dec565b82600160a060020a03166370a08231836040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b1580156121e757600080fd5b505af11580156121fb573d6000803e3d6000fd5b505050506040513d602081101561221157600080fd5b50519050611dec565b60606000805b600381101561225957336001826003811061223757fe5b0154600160a060020a031614156122515760019150612259565b600101612220565b81151561226557600080fd5b60058054806020026020016040519081016040528092919081815260200182805480156122bb57602002820191906000526020600020905b8154600160a060020a0316815260019091019060200180831161229d575b50505050509250505090565b600080805b60038110156123055733600182600381106122e357fe5b0154600160a060020a031614156122fd5760019150612305565b6001016122cc565b81151561231157600080fd5b60408051808201909152601181527f7472616e736665724f776e6572736869700000000000000000000000000000006020820152600054600110156125005733600160a060020a03166007826040518082805190602001908083835b6020831061238c5780518252601f19909201916020918201910161236d565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a03169290921491506123d2905057600080fd5b60006007826040518082805190602001908083835b602083106124065780518252601f1990920191602091820191016123e7565b51815160209384036101000a600019018019909216911617905292019485525060405193849003019092208054600160a060020a031916600160a060020a0394851617905550508516151561245a57600080fd5b600093505b6000548410156124c5576001846003811061247657fe5b0154600160a060020a03163314156124ba57846001856003811061249657fe5b018054600160a060020a031916600160a060020a03929092169190911790556124c5565b60019093019261245f565b604051600160a060020a0386169033907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a36125b7565b600160a060020a038516151561251557600080fd5b600093505b600054841015612580576001846003811061253157fe5b0154600160a060020a031633141561257557846001856003811061255157fe5b018054600160a060020a031916600160a060020a0392909216919091179055612580565b60019093019261251a565b604051600160a060020a0386169033907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35b5050505050565b60008215156125cf57506000611dec565b508181028183828115156125df57fe5b0414611dec57fe5b600081838115156125f457fe5b049392505050565b60008073aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa600160a060020a0389161480612628575034155b151561263357600080fd5b73aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa600160a060020a03891614156126645734871461266457600080fd5b73aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa600160a060020a0389161461273457600954604080517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152600160a060020a039283166024820152604481018a90529051918a16916323b872dd916064808201926020929091908290030181600087803b1580156126fd57600080fd5b505af1158015612711573d6000803e3d6000fd5b505050506040513d602081101561272757600080fd5b5051151561273457600080fd5b600954604080517fa7cff222000000000000000000000000000000000000000000000000000000008152600160a060020a038b81166004830152602482018b9052898116604483015288811660648301526084820188905286811660a48301529151919092169163a7cff22291349160c48082019260209290919082900301818588803b1580156127c457600080fd5b505af11580156127d8573d6000803e3d6000fd5b50505050506040513d60208110156127ef57600080fd5b505160408051600160a060020a038b81168252891660208201528082018a905260608101839052905191925033917f2ae30e1257e5ac2b6d5cfe7f99d7b87eaead5533d01dcbbf00acc62a49dbe5209181900360800190a2979650505050505050565b8154818355818111156110da576000838152602090206110da9181019083016112af91905b8082111561288b5760008155600101612877565b50905600a165627a7a723058207b893cbe9f65abe744349e35c9ec0442bc7680d5ac11364c5006ab3262f1efc00029

   Swarm Source:
bzzr://7b893cbe9f65abe744349e35c9ec0442bc7680d5ac11364c5006ab3262f1efc0

 

View All
Block Age transaction Difficulty GasUsed Reward
View All
Block Age UncleNumber Difficulty GasUsed Reward