ETH Price: $2,491.62 (+3.07%)

Contract

0x740f8B58f5562C8379F2A8c2230C9be5C03Ac3Fc
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Process Trade Fo...118688762021-02-16 16:15:391328 days ago1613492139IN
Nuo Network: MKernel
0 ETH0.05672727146
Process Trade Fo...118688762021-02-16 16:15:391328 days ago1613492139IN
Nuo Network: MKernel
0 ETH0.13643383146.5
Process Trade Fo...118631532021-02-15 19:05:111329 days ago1613415911IN
Nuo Network: MKernel
0 ETH0.0090639150
Process Trade Fo...118630642021-02-15 18:41:411329 days ago1613414501IN
Nuo Network: MKernel
0 ETH0.00817138133
Process Trade Fo...118630642021-02-15 18:41:411329 days ago1613414501IN
Nuo Network: MKernel
0 ETH0.00871123133
Process Trade Fo...118630572021-02-15 18:40:361329 days ago1613414436IN
Nuo Network: MKernel
0 ETH0.00750159133
Process Trade Fo...118630132021-02-15 18:31:401329 days ago1613413900IN
Nuo Network: MKernel
0 ETH0.00829426135
Process Trade Fo...118630132021-02-15 18:31:401329 days ago1613413900IN
Nuo Network: MKernel
0 ETH0.00884223135
Process Trade Fo...118630082021-02-15 18:31:061329 days ago1613413866IN
Nuo Network: MKernel
0 ETH0.0075862134.5
Process Trade Fo...108852772020-09-18 9:19:271479 days ago1600420767IN
Nuo Network: MKernel
0 ETH0.00983808280
Process Trade Fo...108845312020-09-18 6:25:211480 days ago1600410321IN
Nuo Network: MKernel
0 ETH0.00983808280
Process Trade Fo...108845312020-09-18 6:25:211480 days ago1600410321IN
Nuo Network: MKernel
0 ETH0.39328744280
Process Trade Fo...108610562020-09-14 15:55:391483 days ago1600098939IN
Nuo Network: MKernel
0 ETH0.01041572280
Process Trade Fo...108610232020-09-14 15:47:571483 days ago1600098477IN
Nuo Network: MKernel
0 ETH0.01041908280
Process Trade Fo...108609632020-09-14 15:37:021483 days ago1600097822IN
Nuo Network: MKernel
0 ETH0.01041908280
Liquidate Order108450212020-09-12 4:46:511486 days ago1599886011IN
Nuo Network: MKernel
0 ETH0.0072901792
Process Trade Fo...108132342020-09-07 7:49:281490 days ago1599464968IN
Nuo Network: MKernel
0 ETH0.38459671100.5
Process Trade Fo...108132182020-09-07 7:44:571490 days ago1599464697IN
Nuo Network: MKernel
0 ETH0.3649637895
Process Trade Fo...108131982020-09-07 7:41:191490 days ago1599464479IN
Nuo Network: MKernel
0 ETH0.34982695
Process Trade Fo...108131732020-09-07 7:35:081490 days ago1599464108IN
Nuo Network: MKernel
0 ETH0.38018733101
Process Trade Fo...108128882020-09-07 6:31:261491 days ago1599460286IN
Nuo Network: MKernel
0 ETH0.3659035594
Process Trade Fo...108128862020-09-07 6:31:001491 days ago1599460260IN
Nuo Network: MKernel
0 ETH0.3645149894
Process Trade Fo...108128792020-09-07 6:29:211491 days ago1599460161IN
Nuo Network: MKernel
0 ETH0.3673124294
Process Trade Fo...108036022020-09-05 20:28:271492 days ago1599337707IN
Nuo Network: MKernel
0 ETH1.05101332280
Process Trade Fo...108013822020-09-05 12:24:261492 days ago1599308666IN
Nuo Network: MKernel
0 ETH0.01757868280
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MKernel

Compiler Version
v0.4.24+commit.e67f0147

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2019-04-18
*/

pragma solidity 0.4.24;

contract DSAuthority {
    function canCall(address src, address dst, bytes4 sig) public view returns (bool);
}


contract DSAuthEvents {
    event LogSetAuthority (address indexed authority);
    event LogSetOwner     (address indexed owner);
}


contract DSAuth is DSAuthEvents {
    DSAuthority  public  authority;
    address      public  owner;

    constructor() public {
        owner = msg.sender;
        emit LogSetOwner(msg.sender);
    }

    function setOwner(address owner_)
        public
        auth
    {
        owner = owner_;
        emit LogSetOwner(owner);
    }

    function setAuthority(DSAuthority authority_)
        public
        auth
    {
        authority = authority_;
        emit LogSetAuthority(authority);
    }

    modifier auth {
        require(isAuthorized(msg.sender, msg.sig), "DSAuth::_ SENDER_NOT_AUTHORIZED");
        _;
    }

    function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
        if (src == address(this)) {
            return true;
        } else if (src == owner) {
            return true;
        } else if (authority == DSAuthority(0)) {
            return false;
        } else {
            return authority.canCall(src, this, sig);
        }
    }
}


contract Proxy {

    // masterCopy always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated.
    address masterCopy;

    /// @dev Constructor function sets address of master copy contract.
    /// @param _masterCopy Master copy address.
    constructor(address _masterCopy)
        public
    {
        require(_masterCopy != 0, "Invalid master copy address provided");
        masterCopy = _masterCopy;
    }

    /// @dev Fallback function forwards all transactions and returns all received return data.
    function ()
        external
        payable
    {
        // solium-disable-next-line security/no-inline-assembly
        assembly {
            let masterCopy := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
            calldatacopy(0, 0, calldatasize())
            let success := delegatecall(gas, masterCopy, 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            if eq(success, 0) { revert(0, returndatasize()) }
            return(0, returndatasize())
        }
    }

    function implementation()
        public
        view
        returns (address)
    {
        return masterCopy;
    }

    function proxyType()
        public
        pure
        returns (uint256)
    {
        return 2;
    }
}


contract ErrorUtils {

    event LogError(string methodSig, string errMsg);
    event LogErrorWithHintBytes32(bytes32 indexed bytes32Value, string methodSig, string errMsg);
    event LogErrorWithHintAddress(address indexed addressValue, string methodSig, string errMsg);

}


contract DSMath {
    function add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x);
    }
    function sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x);
    }
    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x);
    }

    // custom : not in original DSMath, putting it here for consistency, copied from SafeMath
    function div(uint x, uint y) internal pure returns (uint z) {
        z = x / y;
    }

    function min(uint x, uint y) internal pure returns (uint z) {
        return x <= y ? x : y;
    }
    function max(uint x, uint y) internal pure returns (uint z) {
        return x >= y ? x : y;
    }
    function imin(int x, int y) internal pure returns (int z) {
        return x <= y ? x : y;
    }
    function imax(int x, int y) internal pure returns (int z) {
        return x >= y ? x : y;
    }

    uint constant WAD = 10 ** 18;
    uint constant RAY = 10 ** 27;

    function wmul(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, y), WAD / 2) / WAD;
    }
    function rmul(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, y), RAY / 2) / RAY;
    }
    function wdiv(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, WAD), y / 2) / y;
    }
    function rdiv(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, RAY), y / 2) / y;
    }

    // This famous algorithm is called "exponentiation by squaring"
    // and calculates x^n with x as fixed-point and n as regular unsigned.
    //
    // It's O(log n), instead of O(n) for naive repeated multiplication.
    //
    // These facts are why it works:
    //
    //  If n is even, then x^n = (x^2)^(n/2).
    //  If n is odd,  then x^n = x * x^(n-1),
    //   and applying the equation for even x gives
    //    x^n = x * (x^2)^((n-1) / 2).
    //
    //  Also, EVM division is flooring and
    //    floor[(n-1) / 2] = floor[n / 2].
    //
    function rpow(uint x, uint n) internal pure returns (uint z) {
        z = n % 2 != 0 ? x : RAY;

        for (n /= 2; n != 0; n /= 2) {
            x = rmul(x, x);

            if (n % 2 != 0) {
                z = rmul(z, x);
            }
        }
    }
}


contract SelfAuthorized {
    modifier authorized() {
        require(msg.sender == address(this), "Method can only be called from this contract");
        _;
    }
}


contract DSNote {
    event LogNote(
        bytes4   indexed  sig,
        address  indexed  guy,
        bytes32  indexed  foo,
        bytes32  indexed  bar,
        uint              wad,
        bytes             fax
    ) anonymous;

    modifier note {
        bytes32 foo;
        bytes32 bar;

        assembly {
            foo := calldataload(4)
            bar := calldataload(36)
        }

        emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);

        _;
    }
}


contract Utils {

    modifier addressValid(address _address) {
        require(_address != address(0), "Utils::_ INVALID_ADDRESS");
        _;
    }

}


contract WETH9 {
    string public name     = "Wrapped Ether";
    string public symbol   = "WETH";
    uint8  public decimals = 18;

    event  Approval(address indexed _owner, address indexed _spender, uint _value);
    event  Transfer(address indexed _from, address indexed _to, uint _value);
    event  Deposit(address indexed _owner, uint _value);
    event  Withdrawal(address indexed _owner, uint _value);

    mapping (address => uint)                       public  balanceOf;
    mapping (address => mapping (address => uint))  public  allowance;

    function() public payable {
        deposit();
    }

    function deposit() public payable {
        balanceOf[msg.sender] += msg.value;
        Deposit(msg.sender, msg.value);
    }

    function withdraw(uint wad) public {
        require(balanceOf[msg.sender] >= wad);
        balanceOf[msg.sender] -= wad;
        msg.sender.transfer(wad);
        Withdrawal(msg.sender, wad);
    }

    function totalSupply() public view returns (uint) {
        return this.balance;
    }

    function approve(address guy, uint wad) public returns (bool) {
        allowance[msg.sender][guy] = wad;
        Approval(msg.sender, guy, wad);
        return true;
    }

    function transfer(address dst, uint wad) public returns (bool) {
        return transferFrom(msg.sender, dst, wad);
    }

    function transferFrom(address src, address dst, uint wad)
        public
        returns (bool)
    {
        require(balanceOf[src] >= wad);

        if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
            require(allowance[src][msg.sender] >= wad);
            allowance[src][msg.sender] -= wad;
        }

        balanceOf[src] -= wad;
        balanceOf[dst] += wad;

        Transfer(src, dst, wad);

        return true;
    }
}


contract DateTime {
    /*
        *  Date and Time utilities for ethereum contracts
        *
        */
    struct _DateTime {
        uint16 year;
        uint8 month;
        uint8 day;
        uint8 hour;
        uint8 minute;
        uint8 second;
        uint8 weekday;
    }

    uint constant DAY_IN_SECONDS = 86400;
    uint constant YEAR_IN_SECONDS = 31536000;
    uint constant LEAP_YEAR_IN_SECONDS = 31622400;

    uint constant HOUR_IN_SECONDS = 3600;
    uint constant MINUTE_IN_SECONDS = 60;

    uint16 constant ORIGIN_YEAR = 1970;

    function isLeapYear(uint16 year) public pure returns (bool) {
        if (year % 4 != 0) {
            return false;
        }
        if (year % 100 != 0) {
            return true;
        }
        if (year % 400 != 0) {
            return false;
        }
        return true;
    }

    function leapYearsBefore(uint year) public pure returns (uint) {
        year -= 1;
        return year / 4 - year / 100 + year / 400;
    }

    function getDaysInMonth(uint8 month, uint16 year) public pure returns (uint8) {
        if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
            return 31;
        }
        else if (month == 4 || month == 6 || month == 9 || month == 11) {
            return 30;
        }
        else if (isLeapYear(year)) {
            return 29;
        }
        else {
            return 28;
        }
    }

    function parseTimestamp(uint timestamp) internal pure returns (_DateTime dt) {
        uint secondsAccountedFor = 0;
        uint buf;
        uint8 i;

        // Year
        dt.year = getYear(timestamp);
        buf = leapYearsBefore(dt.year) - leapYearsBefore(ORIGIN_YEAR);

        secondsAccountedFor += LEAP_YEAR_IN_SECONDS * buf;
        secondsAccountedFor += YEAR_IN_SECONDS * (dt.year - ORIGIN_YEAR - buf);

        // Month
        uint secondsInMonth;
        for (i = 1; i <= 12; i++) {
            secondsInMonth = DAY_IN_SECONDS * getDaysInMonth(i, dt.year);
            if (secondsInMonth + secondsAccountedFor > timestamp) {
                dt.month = i;
                break;
            }
            secondsAccountedFor += secondsInMonth;
        }

        // Day
        for (i = 1; i <= getDaysInMonth(dt.month, dt.year); i++) {
            if (DAY_IN_SECONDS + secondsAccountedFor > timestamp) {
                dt.day = i;
                break;
            }
            secondsAccountedFor += DAY_IN_SECONDS;
        }

        // Hour
        dt.hour = getHour(timestamp);

        // Minute
        dt.minute = getMinute(timestamp);

        // Second
        dt.second = getSecond(timestamp);

        // Day of week.
        dt.weekday = getWeekday(timestamp);
    }

    function getYear(uint timestamp) public pure returns (uint16) {
        uint secondsAccountedFor = 0;
        uint16 year;
        uint numLeapYears;

        // Year
        year = uint16(ORIGIN_YEAR + timestamp / YEAR_IN_SECONDS);
        numLeapYears = leapYearsBefore(year) - leapYearsBefore(ORIGIN_YEAR);

        secondsAccountedFor += LEAP_YEAR_IN_SECONDS * numLeapYears;
        secondsAccountedFor += YEAR_IN_SECONDS * (year - ORIGIN_YEAR - numLeapYears);

        while (secondsAccountedFor > timestamp) {
            if (isLeapYear(uint16(year - 1))) {
                secondsAccountedFor -= LEAP_YEAR_IN_SECONDS;
            }
            else {
                secondsAccountedFor -= YEAR_IN_SECONDS;
            }
            year -= 1;
        }
        return year;
    }

    function getMonth(uint timestamp) public pure returns (uint8) {
        return parseTimestamp(timestamp).month;
    }

    function getDay(uint timestamp) public pure returns (uint8) {
        return parseTimestamp(timestamp).day;
    }

    function getHour(uint timestamp) public pure returns (uint8) {
        return uint8((timestamp / 60 / 60) % 24);
    }

    function getMinute(uint timestamp) public pure returns (uint8) {
        return uint8((timestamp / 60) % 60);
    }

    function getSecond(uint timestamp) public pure returns (uint8) {
        return uint8(timestamp % 60);
    }

    function getWeekday(uint timestamp) public pure returns (uint8) {
        return uint8((timestamp / DAY_IN_SECONDS + 4) % 7);
    }

    function toTimestamp(uint16 year, uint8 month, uint8 day) public pure returns (uint timestamp) {
        return toTimestamp(year, month, day, 0, 0, 0);
    }

    function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour) public pure returns (uint timestamp) {
        return toTimestamp(year, month, day, hour, 0, 0);
    }

    function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute) public pure returns (uint timestamp) {
        return toTimestamp(year, month, day, hour, minute, 0);
    }

    function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute, uint8 second) public pure returns (uint timestamp) {
        uint16 i;

        // Year
        for (i = ORIGIN_YEAR; i < year; i++) {
            if (isLeapYear(i)) {
                timestamp += LEAP_YEAR_IN_SECONDS;
            }
            else {
                timestamp += YEAR_IN_SECONDS;
            }
        }

        // Month
        uint8[12] memory monthDayCounts;
        monthDayCounts[0] = 31;
        if (isLeapYear(year)) {
            monthDayCounts[1] = 29;
        }
        else {
            monthDayCounts[1] = 28;
        }
        monthDayCounts[2] = 31;
        monthDayCounts[3] = 30;
        monthDayCounts[4] = 31;
        monthDayCounts[5] = 30;
        monthDayCounts[6] = 31;
        monthDayCounts[7] = 31;
        monthDayCounts[8] = 30;
        monthDayCounts[9] = 31;
        monthDayCounts[10] = 30;
        monthDayCounts[11] = 31;

        for (i = 1; i < month; i++) {
            timestamp += DAY_IN_SECONDS * monthDayCounts[i - 1];
        }

        // Day
        timestamp += DAY_IN_SECONDS * (day - 1);

        // Hour
        timestamp += HOUR_IN_SECONDS * (hour);

        // Minute
        timestamp += MINUTE_IN_SECONDS * (minute);

        // Second
        timestamp += second;

        return timestamp;
    }
}


interface ERC20 {

    function name() external view returns(string);
    function symbol() external view returns(string);
    function decimals() external view returns(uint8);
    function totalSupply() external view returns (uint);

    function balanceOf(address tokenOwner) external view returns (uint balance);
    function allowance(address tokenOwner, address spender) external view returns (uint remaining);
    function transfer(address to, uint tokens) external returns (bool success);
    function approve(address spender, uint tokens) external returns (bool success);
    function transferFrom(address from, address to, uint tokens) external returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}


contract MasterCopy is SelfAuthorized {
  // masterCopy always needs to be first declared variable, to ensure that it is at the same location as in the Proxy contract.
  // It should also always be ensured that the address is stored alone (uses a full word)
    address masterCopy;

  /// @dev Allows to upgrade the contract. This can only be done via a Safe transaction.
  /// @param _masterCopy New contract address.
    function changeMasterCopy(address _masterCopy)
        public
        authorized
    {
        // Master copy address cannot be null.
        require(_masterCopy != 0, "Invalid master copy address provided");
        masterCopy = _masterCopy;
    }
}


contract Config is DSNote, DSAuth, Utils {

    WETH9 public weth9;
    mapping (address => bool) public isAccountHandler;
    mapping (address => bool) public isAdmin;
    address[] public admins;
    bool public disableAdminControl = false;
    
    event LogAdminAdded(address indexed _admin, address _by);
    event LogAdminRemoved(address indexed _admin, address _by);

    constructor() public {
        admins.push(msg.sender);
        isAdmin[msg.sender] = true;
    }

    modifier onlyAdmin(){
        require(isAdmin[msg.sender], "Config::_ SENDER_NOT_AUTHORIZED");
        _;
    }

    function setWETH9
    (
        address _weth9
    ) 
        public
        auth
        note
        addressValid(_weth9) 
    {
        weth9 = WETH9(_weth9);
    }

    function setAccountHandler
    (
        address _accountHandler,
        bool _isAccountHandler
    )
        public
        auth
        note
        addressValid(_accountHandler)
    {
        isAccountHandler[_accountHandler] = _isAccountHandler;
    }

    function toggleAdminsControl() 
        public
        auth
        note
    {
        disableAdminControl = !disableAdminControl;
    }

    function isAdminValid(address _admin)
        public
        view
        returns (bool)
    {
        if(disableAdminControl) {
            return true;
        } else {
            return isAdmin[_admin];
        }
    }

    function getAllAdmins()
        public
        view
        returns(address[])
    {
        return admins;
    }

    function addAdmin
    (
        address _admin
    )
        external
        note
        onlyAdmin
        addressValid(_admin)
    {   
        require(!isAdmin[_admin], "Config::addAdmin ADMIN_ALREADY_EXISTS");

        admins.push(_admin);
        isAdmin[_admin] = true;

        emit LogAdminAdded(_admin, msg.sender);
    }

    function removeAdmin
    (
        address _admin
    ) 
        external
        note
        onlyAdmin
        addressValid(_admin)
    {   
        require(isAdmin[_admin], "Config::removeAdmin ADMIN_DOES_NOT_EXIST");
        require(msg.sender != _admin, "Config::removeAdmin ADMIN_NOT_AUTHORIZED");

        isAdmin[_admin] = false;

        for (uint i = 0; i < admins.length - 1; i++) {
            if (admins[i] == _admin) {
                admins[i] = admins[admins.length - 1];
                admins.length -= 1;
                break;
            }
        }

        emit LogAdminRemoved(_admin, msg.sender);
    }
}


library ECRecovery {

    function recover(bytes32 _hash, bytes _sig)
        internal
        pure
    returns (address)
    {
        bytes32 r;
        bytes32 s;
        uint8 v;

        if (_sig.length != 65) {
            return (address(0));
        }

        assembly {
            r := mload(add(_sig, 32))
            s := mload(add(_sig, 64))
            v := byte(0, mload(add(_sig, 96)))
        }

        if (v < 27) {
            v += 27;
        }

        if (v != 27 && v != 28) {
            return (address(0));
        } else {
            return ecrecover(_hash, v, r, s);
        }
    }

    function toEthSignedMessageHash(bytes32 _hash)
        internal
        pure
    returns (bytes32)
    {
        return keccak256(
            abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)
        );
    }
}


contract Utils2 {
    using ECRecovery for bytes32;
    
    function _recoverSigner(bytes32 _hash, bytes _signature) 
        internal
        pure
        returns(address _signer)
    {
        return _hash.toEthSignedMessageHash().recover(_signature);
    }

}


contract DSThing is DSNote, DSAuth, DSMath {

    function S(string s) internal pure returns (bytes4) {
        return bytes4(keccak256(s));
    }

}


contract DSStop is DSNote, DSAuth {

    bool public stopped = false;

    modifier whenNotStopped {
        require(!stopped, "DSStop::_ FEATURE_STOPPED");
        _;
    }

    modifier whenStopped {
        require(stopped, "DSStop::_ FEATURE_NOT_STOPPED");
        _;
    }

    function stop() public auth note {
        stopped = true;
    }
    function start() public auth note {
        stopped = false;
    }

}


contract Account is MasterCopy, DSNote, Utils, Utils2, ErrorUtils {

    address[] public users;
    mapping (address => bool) public isUser;
    mapping (bytes32 => bool) public actionCompleted;

    WETH9 public weth9;
    Config public config;
    bool public isInitialized = false;

    event LogTransferBySystem(address indexed token, address indexed to, uint value, address by);
    event LogTransferByUser(address indexed token, address indexed to, uint value, address by);
    event LogUserAdded(address indexed user, address by);
    event LogUserRemoved(address indexed user, address by);
    event LogImplChanged(address indexed newImpl, address indexed oldImpl);

    modifier initialized() {
        require(isInitialized, "Account::_ ACCOUNT_NOT_INITIALIZED");
        _;
    }

    modifier notInitialized() {
        require(!isInitialized, "Account::_ ACCOUNT_ALREADY_INITIALIZED");
        _;
    }

    modifier userExists(address _user) {
        require(isUser[_user], "Account::_ INVALID_USER");
        _;
    }

    modifier userDoesNotExist(address _user) {
        require(!isUser[_user], "Account::_ USER_DOES_NOT_EXISTS");
        _;
    }

    modifier onlyAdmin() {
        require(config.isAdminValid(msg.sender), "Account::_ INVALID_ADMIN_ACCOUNT");
        _;
    }

    modifier onlyHandler(){
        require(config.isAccountHandler(msg.sender), "Account::_ INVALID_ACC_HANDLER");
        _;
    }

    function init(address _user, address _config)
        public 
        notInitialized
    {
        users.push(_user);
        isUser[_user] = true;
        config = Config(_config);
        weth9 = config.weth9();
        isInitialized = true;
    }
    
    function getAllUsers() public view returns (address[]) {
        return users;
    }

    function balanceFor(address _token) public view returns (uint _balance){
        _balance = ERC20(_token).balanceOf(this);
    }
    
    function transferBySystem
    (   
        address _token,
        address _to,
        uint _value
    ) 
        external 
        onlyHandler
        note 
        initialized
    {
        require(ERC20(_token).balanceOf(this) >= _value, "Account::transferBySystem INSUFFICIENT_BALANCE_IN_ACCOUNT");
        ERC20(_token).transfer(_to, _value);

        emit LogTransferBySystem(_token, _to, _value, msg.sender);
    }
    
    function transferByUser
    (   
        address _token,
        address _to,
        uint _value,
        uint _salt,
        bytes _signature
    )
        external
        addressValid(_to)
        note
        initialized
        onlyAdmin
    {
        bytes32 actionHash = _getTransferActionHash(_token, _to, _value, _salt);

        if(actionCompleted[actionHash]) {
            emit LogError("Account::transferByUser", "ACTION_ALREADY_PERFORMED");
            return;
        }

        if(ERC20(_token).balanceOf(this) < _value){
            emit LogError("Account::transferByUser", "INSUFFICIENT_BALANCE_IN_ACCOUNT");
            return;
        }

        address signer = _recoverSigner(actionHash, _signature);

        if(!isUser[signer]) {
            emit LogError("Account::transferByUser", "SIGNER_NOT_AUTHORIZED_WITH_ACCOUNT");
            return;
        }

        actionCompleted[actionHash] = true;
        
        if (_token == address(weth9)) {
            weth9.withdraw(_value);
            _to.transfer(_value);
        } else {
            require(ERC20(_token).transfer(_to, _value), "Account::transferByUser TOKEN_TRANSFER_FAILED");
        }

        emit LogTransferByUser(_token, _to, _value, signer);
    }

    function addUser
    (
        address _user,
        uint _salt,
        bytes _signature
    )
        external 
        note 
        addressValid(_user)
        userDoesNotExist(_user)
        initialized
        onlyAdmin
    {   
        bytes32 actionHash = _getUserActionHash(_user, "ADD_USER", _salt);
        if(actionCompleted[actionHash])
        {
            emit LogError("Account::addUser", "ACTION_ALREADY_PERFORMED");
            return;
        }

        address signer = _recoverSigner(actionHash, _signature);

        if(!isUser[signer]) {
            emit LogError("Account::addUser", "SIGNER_NOT_AUTHORIZED_WITH_ACCOUNT");
            return;
        }

        actionCompleted[actionHash] = true;

        users.push(_user);
        isUser[_user] = true;

        emit LogUserAdded(_user, signer);
    }

    function removeUser
    (
        address _user,
        uint _salt,
        bytes _signature
    ) 
        external
        note
        userExists(_user) 
        initialized
        onlyAdmin
    {   
        bytes32 actionHash = _getUserActionHash(_user, "REMOVE_USER", _salt);

        if(actionCompleted[actionHash]) {
            emit LogError("Account::removeUser", "ACTION_ALREADY_PERFORMED");
            return;
        }

        address signer = _recoverSigner(actionHash, _signature);
        
        if(users.length == 1){
            emit LogError("Account::removeUser",  "ACC_SHOULD_HAVE_ATLEAST_ONE_USER");
            return;
        }
        
        if(!isUser[signer]){
            emit LogError("Account::removeUser", "SIGNER_NOT_AUTHORIZED_WITH_ACCOUNT");
            return;
        }
        
        actionCompleted[actionHash] = true;

        // should delete value from isUser map? delete isUser[_user]?
        isUser[_user] = false;
        for (uint i = 0; i < users.length - 1; i++) {
            if (users[i] == _user) {
                users[i] = users[users.length - 1];
                users.length -= 1;
                break;
            }
        }

        emit LogUserRemoved(_user, signer);
    }

    function _getTransferActionHash
    ( 
        address _token,
        address _to,
        uint _value,
        uint _salt
    ) 
        internal
        view
        returns (bytes32)
    {
        return keccak256(
            abi.encodePacked(
                address(this),
                _token,
                _to,
                _value,
                _salt
            )
        );
    }

    function _getUserActionHash
    ( 
        address _user,
        string _action,
        uint _salt
    ) 
        internal
        view
        returns (bytes32)
    {
        return keccak256(
            abi.encodePacked(
                address(this),
                _user,
                _action,
                _salt
            )
        );
    }

    // to directly send ether to contract
    function() external payable {
        require(msg.data.length == 0 && msg.value > 0, "Account::fallback INVALID_ETHER_TRANSFER");

        if(msg.sender != address(weth9)){
            weth9.deposit.value(msg.value)();
        }
    }

    function changeImpl
    (
        address _to,
        uint _salt,
        bytes _signature
    )
        external 
        note 
        addressValid(_to)
        initialized
        onlyAdmin
    {   
        bytes32 actionHash = _getUserActionHash(_to, "CHANGE_ACCOUNT_IMPLEMENTATION", _salt);
        if(actionCompleted[actionHash])
        {
            emit LogError("Account::changeImpl", "ACTION_ALREADY_PERFORMED");
            return;
        }

        address signer = _recoverSigner(actionHash, _signature);

        if(!isUser[signer]) {
            emit LogError("Account::changeImpl", "SIGNER_NOT_AUTHORIZED_WITH_ACCOUNT");
            return;
        }

        actionCompleted[actionHash] = true;

        address oldImpl = masterCopy;
        this.changeMasterCopy(_to);
        
        emit LogImplChanged(_to, oldImpl);
    }

}


contract AccountFactory is DSStop, Utils {
    Config public config;
    mapping (address => bool) public isAccount;
    mapping (address => address[]) public userToAccounts;
    address[] public accounts;

    address public accountMaster;

    constructor
    (
        Config _config, 
        address _accountMaster
    ) 
    public 
    {
        config = _config;
        accountMaster = _accountMaster;
    }

    event LogAccountCreated(address indexed user, address indexed account, address by);

    modifier onlyAdmin() {
        require(config.isAdminValid(msg.sender), "AccountFactory::_ INVALID_ADMIN_ACCOUNT");
        _;
    }

    function setConfig(Config _config) external note auth addressValid(_config) {
        config = _config;
    }

    function setAccountMaster(address _accountMaster) external note auth addressValid(_accountMaster) {
        accountMaster = _accountMaster;
    }

    function newAccount(address _user)
        public
        note
        onlyAdmin
        addressValid(config)
        addressValid(accountMaster)
        whenNotStopped
        returns 
        (
            Account _account
        ) 
    {
        address proxy = new Proxy(accountMaster);
        _account = Account(proxy);
        _account.init(_user, config);

        accounts.push(_account);
        userToAccounts[_user].push(_account);
        isAccount[_account] = true;

        emit LogAccountCreated(_user, _account, msg.sender);
    }
    
    function batchNewAccount(address[] _users) public note onlyAdmin {
        for (uint i = 0; i < _users.length; i++) {
            newAccount(_users[i]);
        }
    }

    function getAllAccounts() public view returns (address[]) {
        return accounts;
    }

    function getAccountsForUser(address _user) public view returns (address[]) {
        return userToAccounts[_user];
    }

}


contract Escrow is DSNote, DSAuth {

    event LogTransfer(address indexed token, address indexed to, uint value);
    event LogTransferFromAccount(address indexed account, address indexed token, address indexed to, uint value);

    function transfer
    (
        address _token,
        address _to,
        uint _value
    )
        public
        note
        auth
    {
        require(ERC20(_token).transfer(_to, _value), "Escrow::transfer TOKEN_TRANSFER_FAILED");
        emit LogTransfer(_token, _to, _value);
    }

    function transferFromAccount
    (
        address _account,
        address _token,
        address _to,
        uint _value
    )
        public
        note
        auth
    {   
        Account(_account).transferBySystem(_token, _to, _value);
        emit LogTransferFromAccount(_account, _token, _to, _value);
    }

}

// issue with deploying multiple instances of same type in truffle, hence the following two contracts
contract KernelEscrow is Escrow {

}

contract ReserveEscrow is Escrow {
    
}


contract Reserve is DSStop, DSThing, Utils, Utils2, ErrorUtils {

    Escrow public escrow;
    AccountFactory public accountFactory;
    DateTime public dateTime;
    Config public config;
    uint public deployTimestamp;

    string constant public VERSION = "1.0.0";

    uint public TIME_INTERVAL = 1 days;
    //uint public TIME_INTERVAL = 1 hours;
    
    constructor
    (
        Escrow _escrow,
        AccountFactory _accountFactory,
        DateTime _dateTime,
        Config _config
    ) 
    public 
    {
        escrow = _escrow;
        accountFactory = _accountFactory;
        dateTime = _dateTime;
        config = _config;
        deployTimestamp = now - (4 * TIME_INTERVAL);
    }

    function setEscrow(Escrow _escrow) 
        public 
        note 
        auth
        addressValid(_escrow)
    {
        escrow = _escrow;
    }

    function setAccountFactory(AccountFactory _accountFactory) 
        public 
        note 
        auth
        addressValid(_accountFactory)
    {
        accountFactory = _accountFactory;
    }

    function setDateTime(DateTime _dateTime) 
        public 
        note 
        auth
        addressValid(_dateTime)
    {
        dateTime = _dateTime;
    }

    function setConfig(Config _config) 
        public 
        note 
        auth
        addressValid(_config)
    {
        config = _config;
    }

    struct Order {
        address account;
        address token;
        address byUser;
        uint value;
        uint duration;
        uint expirationTimestamp;
        uint salt;
        uint createdTimestamp;
        bytes32 orderHash;
    }

    bytes32[] public orders;
    mapping (bytes32 => Order) public hashToOrder;
    mapping (bytes32 => bool) public isOrder;
    mapping (address => bytes32[]) public accountToOrders;
    mapping (bytes32 => bool) public cancelledOrders;

    // per day
    mapping (uint => mapping(address => uint)) public deposits;
    mapping (uint => mapping(address => uint)) public withdrawals;
    mapping (uint => mapping(address => uint)) public profits;
    mapping (uint => mapping(address => uint)) public losses;

    mapping (uint => mapping(address => uint)) public reserves;
    mapping (address => uint) public lastReserveRuns;

    mapping (address => mapping(address => uint)) public surplus;

    mapping (bytes32 => CumulativeRun) public orderToCumulative;

    struct CumulativeRun {
        uint timestamp;
        uint value;
    }

    modifier onlyAdmin() {
        require(config.isAdminValid(msg.sender), "Reserve::_ INVALID_ADMIN_ACCOUNT");
        _;
    }

    event LogOrderCreated(
        bytes32 indexed orderHash,
        address indexed account,
        address indexed token,
        address byUser,
        uint value,
        uint expirationTimestamp
    );

    event LogOrderCancelled(
        bytes32 indexed orderHash,
        address indexed by
    );

    event LogReserveValuesUpdated(
        address indexed token, 
        uint indexed updatedTill,
        uint reserve,
        uint profit,
        uint loss
    );

    event LogOrderCumulativeUpdated(
        bytes32 indexed orderHash,
        uint updatedTill,
        uint value
    );

    event LogRelease(
        address indexed token,
        address indexed to,
        uint value,
        address by
    );

    event LogLock(
        address indexed token,
        address indexed from,
        uint value,
        uint profit,
        uint loss,
        address by
    );

    event LogLockSurplus(
        address indexed forToken, 
        address indexed token,
        address from,
        uint value
    );

    event LogTransferSurplus(
        address indexed forToken,
        address indexed token,
        address to, 
        uint value
    );
    
    function createOrder
    (
        address[3] _orderAddresses,
        uint[3] _orderValues,
        bytes _signature
    ) 
        public
        note
        onlyAdmin
        whenNotStopped
    {
        Order memory order = _composeOrder(_orderAddresses, _orderValues);
        address signer = _recoverSigner(order.orderHash, _signature);

        if(signer != order.byUser){
            emit LogErrorWithHintBytes32(order.orderHash, "Reserve::createOrder", "SIGNER_NOT_ORDER_CREATOR");
            return;
        }
        
        if(isOrder[order.orderHash]){
            emit LogErrorWithHintBytes32(order.orderHash, "Reserve::createOrder", "ORDER_ALREADY_EXISTS");
            return;
        }

        if(!accountFactory.isAccount(order.account)){
            emit LogErrorWithHintBytes32(order.orderHash, "Reserve::createOrder", "INVALID_ORDER_ACCOUNT");
            return;
        }

        if(!Account(order.account).isUser(signer)){
            emit LogErrorWithHintBytes32(order.orderHash, "Reserve::createOrder", "SIGNER_NOT_AUTHORIZED_WITH_ACCOUNT");
            return;
        }
                
        if(!_isOrderValid(order)) {
            emit LogErrorWithHintBytes32(order.orderHash, "Reserve::createOrder", "INVALID_ORDER_PARAMETERS");
            return;
        }

        if(ERC20(order.token).balanceOf(order.account) < order.value){
            emit LogErrorWithHintBytes32(order.orderHash, "Reserve::createOrder", "INSUFFICIENT_BALANCE_IN_ACCOUNT");
            return;
        }

        escrow.transferFromAccount(order.account, order.token, address(escrow), order.value);
        
        orders.push(order.orderHash);
        hashToOrder[order.orderHash] = order;
        isOrder[order.orderHash] = true;
        accountToOrders[order.account].push(order.orderHash);

        uint dateTimestamp = _getDateTimestamp(now);

        deposits[dateTimestamp][order.token] = add(deposits[dateTimestamp][order.token], order.value);
        
        orderToCumulative[order.orderHash].timestamp = _getDateTimestamp(order.createdTimestamp);
        orderToCumulative[order.orderHash].value = order.value;

        emit LogOrderCreated(
            order.orderHash,
            order.account,
            order.token,
            order.byUser,
            order.value,
            order.expirationTimestamp
        );
    }

    function cancelOrder
    (
        bytes32 _orderHash,
        bytes _signature
    )
        external
        note
        onlyAdmin
    {   
        if(!isOrder[_orderHash]) {
            emit LogErrorWithHintBytes32(_orderHash,"Reserve::createOrder", "ORDER_DOES_NOT_EXIST");
            return;
        }

        if(cancelledOrders[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash,"Reserve::createOrder", "ORDER_ALREADY_CANCELLED");
            return;
        }

        Order memory order = hashToOrder[_orderHash];

        bytes32 cancelOrderHash = _generateActionOrderHash(_orderHash, "CANCEL_RESERVE_ORDER");
        address signer = _recoverSigner(cancelOrderHash, _signature);
        
        if(!Account(order.account).isUser(signer)){
            emit LogErrorWithHintBytes32(_orderHash,"Reserve::createOrder", "SIGNER_NOT_AUTHORIZED_WITH_ACCOUNT");
            return;
        }
        
        doCancelOrder(order);
    }
    
    function processOrder
    (
        bytes32 _orderHash
    ) 
        external 
        note
        onlyAdmin
    {
        if(!isOrder[_orderHash]) {
            emit LogErrorWithHintBytes32(_orderHash,"Reserve::processOrder", "ORDER_DOES_NOT_EXIST");
            return;
        }

        if(cancelledOrders[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash,"Reserve::processOrder", "ORDER_ALREADY_CANCELLED");
            return;
        }

        Order memory order = hashToOrder[_orderHash];

        if(now > _getDateTimestamp(order.expirationTimestamp)) {
            doCancelOrder(order);
        } else {
            emit LogErrorWithHintBytes32(order.orderHash, "Reserve::processOrder", "ORDER_NOT_EXPIRED");
        }
    }

    function doCancelOrder(Order _order) 
        internal
    {   
        uint valueToTransfer = orderToCumulative[_order.orderHash].value;

        if(ERC20(_order.token).balanceOf(escrow) < valueToTransfer){
            emit LogErrorWithHintBytes32(_order.orderHash, "Reserve::doCancel", "INSUFFICIENT_BALANCE_IN_ESCROW");
            return;
        }

        uint nowDateTimestamp = _getDateTimestamp(now);
        cancelledOrders[_order.orderHash] = true;
        withdrawals[nowDateTimestamp][_order.token] = add(withdrawals[nowDateTimestamp][_order.token], valueToTransfer);

        escrow.transfer(_order.token, _order.account, valueToTransfer);
        emit LogOrderCancelled(_order.orderHash, msg.sender);
    }

    function release(address _token, address _to, uint _value) 
        external
        note
        auth
    {   
        require(ERC20(_token).balanceOf(escrow) >= _value, "Reserve::release INSUFFICIENT_BALANCE_IN_ESCROW");
        escrow.transfer(_token, _to, _value);
        emit LogRelease(_token, _to, _value, msg.sender);
    }

    // _value includes profit/loss as well
    function lock(address _token, address _from, uint _value, uint _profit, uint _loss)
        external
        note
        auth
    {   
        require(!(_profit == 0 && _loss == 0), "Reserve::lock INVALID_PROFIT_LOSS_VALUES");
        require(ERC20(_token).balanceOf(_from) >= _value, "Reserve::lock INSUFFICIENT_BALANCE");
            
        if(accountFactory.isAccount(_from)) {
            escrow.transferFromAccount(_from, _token, address(escrow), _value);
        } else {
            Escrow(_from).transfer(_token, address(escrow), _value);
        }
        
        uint dateTimestamp = _getDateTimestamp(now);

        if (_profit > 0){
            profits[dateTimestamp][_token] = add(profits[dateTimestamp][_token], _profit);
        } else if (_loss > 0) {
            losses[dateTimestamp][_token] = add(losses[dateTimestamp][_token], _loss);
        }

        emit LogLock(_token, _from, _value, _profit, _loss, msg.sender);
    }

    // to lock collateral if cannot be liquidated e.g. not enough reserves in kyber
    function lockSurplus(address _from, address _forToken, address _token, uint _value) 
        external
        note
        auth
    {
        require(ERC20(_token).balanceOf(_from) >= _value, "Reserve::lockSurplus INSUFFICIENT_BALANCE_IN_ESCROW");

        Escrow(_from).transfer(_token, address(escrow), _value);
        surplus[_forToken][_token] = add(surplus[_forToken][_token], _value);

        emit LogLockSurplus(_forToken, _token, _from, _value);
    }

    // to transfer surplus collateral out of the system to trade on other platforms and put back in terms of 
    // principal to reserve manually using an account or surplus escrow
    // should work in tandem with lock method when transferring back principal
    function transferSurplus(address _to, address _forToken, address _token, uint _value) 
        external
        note
        auth
    {
        require(ERC20(_token).balanceOf(escrow) >= _value, "Reserve::transferSurplus INSUFFICIENT_BALANCE_IN_ESCROW");
        require(surplus[_forToken][_token] >= _value, "Reserve::transferSurplus INSUFFICIENT_SURPLUS");

        surplus[_forToken][_token] = sub(surplus[_forToken][_token], _value);
        escrow.transfer(_token, _to, _value);

        emit LogTransferSurplus(_forToken, _token, _to, _value);
    }

    function updateReserveValues(address _token, uint _forDays)
        public
        note
        onlyAdmin
    {   
        uint lastReserveRun = lastReserveRuns[_token];

        if (lastReserveRun == 0) {
            lastReserveRun = _getDateTimestamp(deployTimestamp) - TIME_INTERVAL;
        }

        uint nowDateTimestamp = _getDateTimestamp(now);
        uint updatesLeft = ((nowDateTimestamp - TIME_INTERVAL) - lastReserveRun) / TIME_INTERVAL;

        if(updatesLeft == 0) {
            emit LogErrorWithHintAddress(_token, "Reserve::updateReserveValues", "RESERVE_VALUES_UP_TO_DATE");
            return;
        }

        uint counter = updatesLeft;

        if(updatesLeft > _forDays && _forDays > 0) {
            counter = _forDays;
        }

        for (uint i = 0; i < counter; i++) {
            reserves[lastReserveRun + TIME_INTERVAL][_token] = sub(
                sub(
                    add(
                        add(
                            reserves[lastReserveRun][_token],
                            deposits[lastReserveRun + TIME_INTERVAL][_token]
                        ),
                        profits[lastReserveRun + TIME_INTERVAL][_token]
                    ),
                    losses[lastReserveRun + TIME_INTERVAL][_token]
                ),
                withdrawals[lastReserveRun + TIME_INTERVAL][_token]
            );
            lastReserveRuns[_token] = lastReserveRun + TIME_INTERVAL;
            lastReserveRun = lastReserveRuns[_token];
            
            emit LogReserveValuesUpdated(
                _token,
                lastReserveRun,
                reserves[lastReserveRun][_token],
                profits[lastReserveRun][_token],
                losses[lastReserveRun][_token]
            );
            
        }
    }

    function updateOrderCumulativeValueBatch(bytes32[] _orderHashes, uint[] _forDays) 
        public
        note
        onlyAdmin
    {   
        if(_orderHashes.length != _forDays.length) {
            emit LogError("Reserve::updateOrderCumulativeValueBatch", "ARGS_ARRAYLENGTH_MISMATCH");
            return;
        }

        for(uint i = 0; i < _orderHashes.length; i++) {
            updateOrderCumulativeValue(_orderHashes[i], _forDays[i]);
        }
    }

    function updateOrderCumulativeValue
    (
        bytes32 _orderHash, 
        uint _forDays
    ) 
        public
        note
        onlyAdmin 
    {
        if(!isOrder[_orderHash]) {
            emit LogErrorWithHintBytes32(_orderHash, "Reserve::updateOrderCumulativeValue", "ORDER_DOES_NOT_EXIST");
            return;
        }

        if(cancelledOrders[_orderHash]) {
            emit LogErrorWithHintBytes32(_orderHash, "Reserve::updateOrderCumulativeValue", "ORDER_ALREADY_CANCELLED");
            return;
        }
        
        Order memory order = hashToOrder[_orderHash];
        CumulativeRun storage cumulativeRun = orderToCumulative[_orderHash];
        
        uint profitsAccrued = 0;
        uint lossesAccrued = 0;
        uint cumulativeValue = 0;
        uint counter = 0;

        uint lastOrderRun = cumulativeRun.timestamp;
        uint nowDateTimestamp = _getDateTimestamp(now);

        uint updatesLeft = ((nowDateTimestamp - TIME_INTERVAL) - lastOrderRun) / TIME_INTERVAL;

        if(updatesLeft == 0) {
            emit LogErrorWithHintBytes32(_orderHash, "Reserve::updateOrderCumulativeValue", "ORDER_VALUES_UP_TO_DATE");
            return;
        }

        counter = updatesLeft;

        if(updatesLeft > _forDays && _forDays > 0) {
            counter = _forDays;
        }

        for (uint i = 0; i < counter; i++){
            cumulativeValue = cumulativeRun.value;
            lastOrderRun = cumulativeRun.timestamp;

            if(lastReserveRuns[order.token] < lastOrderRun) {
                emit LogErrorWithHintBytes32(_orderHash, "Reserve::updateOrderCumulativeValue", "RESERVE_VALUES_NOT_UPDATED");
                emit LogOrderCumulativeUpdated(_orderHash, cumulativeRun.timestamp, cumulativeRun.value);
                return;
            }

            profitsAccrued = div(
                mul(profits[lastOrderRun + TIME_INTERVAL][order.token], cumulativeValue),
                reserves[lastOrderRun][order.token]
            );
                
            lossesAccrued = div(
                mul(losses[lastOrderRun + TIME_INTERVAL][order.token], cumulativeValue),
                reserves[lastOrderRun][order.token]
            );

            cumulativeValue = sub(add(cumulativeValue, profitsAccrued), lossesAccrued);

            cumulativeRun.timestamp = lastOrderRun + TIME_INTERVAL;
            cumulativeRun.value = cumulativeValue;
        }
        
        emit LogOrderCumulativeUpdated(_orderHash, cumulativeRun.timestamp, cumulativeRun.value);
    }

    function getAllOrders() 
        public
        view 
        returns 
        (
            bytes32[]
        ) 
    {
        return orders;
    }

    function getOrdersForAccount(address _account) 
        public
        view 
        returns 
        (
            bytes32[]
        )
    {
        return accountToOrders[_account];
    }

    function getOrder(bytes32 _orderHash)
        public 
        view 
        returns 
        (
            address _account,
            address _token,
            address _byUser,
            uint _value,
            uint _expirationTimestamp,
            uint _salt,
            uint _createdTimestamp
        )
    {   
        Order memory order = hashToOrder[_orderHash];
        return (
            order.account,
            order.token,
            order.byUser,
            order.value,
            order.expirationTimestamp,
            order.salt,
            order.createdTimestamp
        );
    }

    function _isOrderValid(Order _order)
        internal
        view
        returns (bool)
    {
        if(_order.account == address(0) || _order.byUser == address(0)
         || _order.value <= 0
         || _order.expirationTimestamp <= _order.createdTimestamp || _order.salt <= 0) {
            return false;
        }

        if(isOrder[_order.orderHash]) {
            return false;
        }

        if(cancelledOrders[_order.orderHash]) {
            return false;
        }

        return true;
    }

    function _composeOrder(address[3] _orderAddresses, uint[3] _orderValues)
        internal
        view
        returns (Order _order)
    {
        Order memory order = Order({
            account: _orderAddresses[0],
            token: _orderAddresses[1],
            byUser: _orderAddresses[2],
            value: _orderValues[0],
            createdTimestamp: now,
            duration: _orderValues[1],
            expirationTimestamp: add(now, _orderValues[1]),
            salt: _orderValues[2],
            orderHash: bytes32(0)
        });

        order.orderHash = _generateCreateOrderHash(order);

        return order;
    }

    function _generateCreateOrderHash(Order _order)
        internal
        pure //view
        returns (bytes32 _orderHash)
    {
        return keccak256(
            abi.encodePacked(
 //              address(this),
                _order.account,
                _order.token,
                _order.value,
                _order.duration,
                _order.salt
            )
        );
    }

    function _generateActionOrderHash
    (
        bytes32 _orderHash,
        string _action
    )
        internal
        pure //view
        returns (bytes32 _repayOrderHash)
    {
        return keccak256(
            abi.encodePacked(
//                address(this),
                _orderHash,
                _action
            )
        );
    }

    function _getDateTimestamp(uint _timestamp) 
        internal
        view
        returns (uint)
    {
        // 1 day
        return dateTime.toTimestamp(dateTime.getYear(_timestamp), dateTime.getMonth(_timestamp), dateTime.getDay(_timestamp));
        // 1 hour
        //return dateTime.toTimestamp(dateTime.getYear(_timestamp), dateTime.getMonth(_timestamp), dateTime.getDay(_timestamp), dateTime.getHour(_timestamp));
    } 

}
interface ExchangeConnector {

    function tradeWithInputFixed
    (   
        Escrow _escrow,
        address _srcToken,
        address _destToken,
        uint _srcTokenValue
    )
        external
        returns (uint _destTokenValue, uint _srcTokenValueLeft);

    function tradeWithOutputFixed
    (   
        Escrow _escrow,
        address _srcToken,
        address _destToken,
        uint _srcTokenValue,
        uint _maxDestTokenValue
    )
        external
        returns (uint _destTokenValue, uint _srcTokenValueLeft);
    

    function getExpectedRate(address _srcToken, address _destToken, uint _srcTokenValue) 
        external
        view
        returns(uint _expectedRate, uint _slippageRate);
    
    function isTradeFeasible(address _srcToken, address _destToken, uint _srcTokenValue) 
        external
        view
        returns(bool);

}


contract MKernel is DSStop, DSThing, Utils, Utils2, ErrorUtils {
    
    Escrow public escrow;
    AccountFactory public accountFactory;
    Reserve public reserve;
    address public feeWallet;
    Config public config;
    
    constructor
    (
        Escrow _escrow,
        AccountFactory _accountFactory,
        Reserve _reserve,
        address _feeWallet,
        Config _config
    ) 
    public 
    {
        escrow = _escrow;
        accountFactory = _accountFactory;
        reserve = _reserve;
        feeWallet = _feeWallet;
        config = _config;
    }

    function setEscrow(Escrow _escrow) 
        public 
        note 
        auth
        addressValid(_escrow)
    {
        escrow = _escrow;
    }

    function setAccountFactory(AccountFactory _accountFactory)
        public 
        note 
        auth
        addressValid(_accountFactory)
    {
        accountFactory = _accountFactory;
    }

    function setReserve(Reserve _reserve)
        public 
        note 
        auth
        addressValid(_reserve)
    {
        reserve = _reserve;
    }

    function setConfig(Config _config)
        public 
        note 
        auth
        addressValid(_config)
    {
        config = _config;
    }

    function setFeeWallet(address _feeWallet)
        public 
        note 
        auth
        addressValid(_feeWallet)
    {
        feeWallet = _feeWallet;
    }
    
    event LogOrderCreated(
        bytes32 indexed orderHash,
        uint tradeAmount,
        uint expirationTimestamp
    );

    event LogOrderLiquidatedByUser(
        bytes32 indexed orderHash
    );

    event LogOrderStoppedAtProfit(
        bytes32 indexed orderHash
    );

    event LogOrderDefaulted(
        bytes32 indexed orderHash,
        string reason
    );

    event LogNoActionPerformed(
        bytes32 indexed orderHash
    );

    event LogOrderSettlement(
        bytes32 indexed orderHash,
        uint valueRepaid,
        uint reserveProfit,
        uint reserveLoss,
        uint collateralLeft,
        uint userProfit,
        uint fee
    );

    struct Order {
        address account;
        address byUser;
        address principalToken; 
        address collateralToken;
        Trade trade;
        uint principalAmount;
        uint collateralAmount;
        uint premium;
        uint expirationTimestamp;
        uint duration;
        uint salt;
        uint fee;
        uint createdTimestamp;
        bytes32 orderHash;
    }

    struct Trade {
        address tradeToken;
        address closingToken;
        address exchangeConnector; //stores initial and then just used to pass around params
        uint stopProfit;
        uint stopLoss;
    }

    bytes32[] public orders;
    mapping (bytes32 => Order) public hashToOrder;
    mapping (bytes32 => bool) public isOrder;
    mapping (address => bytes32[]) public accountToOrders;

    mapping (bytes32 => uint) public initialTradeAmount;
    mapping (bytes32 => bool) public isLiquidated;
    mapping (bytes32 => bool) public isDefaulted;

    modifier onlyAdmin() {
        require(config.isAdminValid(msg.sender), "MKernel::_ INVALID_ADMIN_ACCOUNT");
        _;
    }


    function createOrder
    (
        address[6] _orderAddresses,
        uint[8] _orderValues,
        address _exchangeConnector,
        bytes _signature
    )    
        external
        note
        onlyAdmin
        whenNotStopped
        addressValid(_exchangeConnector)
    {
        Order memory order = _composeOrder(_orderAddresses, _orderValues);
        address signer = _recoverSigner(order.orderHash, _signature);
        order.trade.exchangeConnector = _exchangeConnector;

        if(signer != order.byUser) {
            emit LogErrorWithHintBytes32(order.orderHash, "MKernel::createOrder","SIGNER_NOT_ORDER_CREATOR");
            return;
        }

        if(isOrder[order.orderHash]){
            emit LogErrorWithHintBytes32(order.orderHash, "MKernel::createOrder","ORDER_ALREADY_EXISTS");
            return;
        }

        if(!accountFactory.isAccount(order.account)){
            emit LogErrorWithHintBytes32(order.orderHash, "MKernel::createOrder","INVALID_ORDER_ACCOUNT");
            return;
        }

        if(!Account(order.account).isUser(signer)) {
            emit LogErrorWithHintBytes32(order.orderHash, "MKernel::createOrder","SIGNER_NOT_AUTHORIZED_WITH_ACCOUNT");
            return;
        }

        if(!_isOrderValid(order)){
            emit LogErrorWithHintBytes32(order.orderHash, "MKernel::createOrder","INVALID_ORDER_PARAMETERS");
            return;
        }

        if(ERC20(order.collateralToken).balanceOf(order.account) < order.collateralAmount){
            emit LogErrorWithHintBytes32(order.orderHash, "MKernel::createOrder","INSUFFICIENT_COLLATERAL_IN_ACCOUNT");
            return;
        }

        if(ERC20(order.principalToken).balanceOf(reserve.escrow()) < order.principalAmount){
            emit LogErrorWithHintBytes32(order.orderHash, "MKernel::createOrder","INSUFFICIENT_FUNDS_IN_RESERVE");
            return;
        }

        if(!_isTradeFeasible(order, order.principalToken, order.trade.tradeToken, order.principalAmount))
        {
            emit LogErrorWithHintBytes32(order.orderHash, "MKernel::createOrder","TRADE_NOT_FEASIBLE");
            return;
        }        

        
        orders.push(order.orderHash);
        hashToOrder[order.orderHash] = order;
        isOrder[order.orderHash] = true;
        accountToOrders[order.account].push(order.orderHash);

        escrow.transferFromAccount(order.account, order.collateralToken, address(escrow), order.collateralAmount);
        reserve.release(order.principalToken, address(escrow), order.principalAmount);
    
        (initialTradeAmount[order.orderHash],) = _tradeWithFixedInput(
            order,
            ERC20(order.principalToken),
            ERC20(order.trade.tradeToken),
            order.principalAmount
        );

        emit LogOrderCreated(
            order.orderHash,
            initialTradeAmount[order.orderHash],
            order.expirationTimestamp
        );
        

    }

    function liquidateOrder
    (
        bytes32 _orderHash,
        address _exchangeConnector,
        bytes _signature
    ) 
        external
        note
        onlyAdmin
        addressValid(_exchangeConnector)
    {
        if(!isOrder[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::liquidateOrder","ORDER_DOES_NOT_EXIST");
            return;
        }
        
        if(isLiquidated[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::liquidateOrder","ORDER_ALREADY_LIQUIDATED");
            return;
        }

        if(isDefaulted[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::liquidateOrder","ORDER_ALREADY_DEFAULTED");
            return;
        }

        bytes32 liquidateOrderHash = _generateLiquidateOrderHash(_orderHash);
        address signer = _recoverSigner(liquidateOrderHash, _signature);

        Order memory order = hashToOrder[_orderHash];
        order.trade.exchangeConnector = _exchangeConnector;
        
        if(!Account(order.account).isUser(signer)){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::liquidateOrder", "SIGNER_NOT_AUTHORIZED_WITH_ACCOUNT");
            return;
        }

        if(ERC20(order.trade.tradeToken).balanceOf(address(escrow)) < initialTradeAmount[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::liquidateOrder", "INSUFFICIENT_TRADE_BALANCE_IN_ESCROW");
            return;
        }

        if(ERC20(order.collateralToken).balanceOf(address(escrow)) < order.collateralAmount){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::liquidateOrder", "INSUFFICIENT_COLLATERAL_BALANCE_IN_ESCROW");
            return;
        }

        isLiquidated[order.orderHash] = true;
        _performOrderLiquidation(order);

        emit LogOrderLiquidatedByUser(_orderHash);
    }

    function processTradeForExpiry
    (
        bytes32 _orderHash,
        address _exchangeConnector
    )
        external
        note
        onlyAdmin
        addressValid(_exchangeConnector)
    {
        if(!isOrder[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForExpiry","ORDER_DOES_NOT_EXIST");
            return;
        }

        if(isLiquidated[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForExpiry","ORDER_ALREADY_LIQUIDATED");
            return;
        }

        if(isDefaulted[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForExpiry","ORDER_ALREADY_DEFAULTED");
            return;
        }
        

        Order memory order = hashToOrder[_orderHash];
        order.trade.exchangeConnector = _exchangeConnector;

        if(ERC20(order.trade.tradeToken).balanceOf(address(escrow)) < initialTradeAmount[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForExpiry", "INSUFFICIENT_TRADE_BALANCE_IN_ESCROW");
            return;
        }

        if(ERC20(order.collateralToken).balanceOf(address(escrow)) < order.collateralAmount){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForExpiry", "INSUFFICIENT_COLLATERAL_BALANCE_IN_ESCROW");
            return;
        }

        if(now > order.expirationTimestamp) {
            isDefaulted[order.orderHash] = true;
            _performOrderLiquidation(order);
            emit LogOrderDefaulted(order.orderHash, "MKERNEL_DUE_DATE_PASSED");
            return;
        }

        emit LogErrorWithHintBytes32(order.orderHash, "MKernel::processTradeForExpiry", "NO_ACTION_PERFORMED");
    }


    function processTradeForStopLoss
    (
        bytes32 _orderHash,
        address _exchangeConnector,
        uint[2] _tokenPrices,
        uint _bufferInPrincipal
    )
        external
        note
        onlyAdmin
        addressValid(_exchangeConnector)
    {   
        if(!isOrder[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForStopLoss","ORDER_DOES_NOT_EXIST");
            return;
        }

        if(isLiquidated[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForStopLoss","ORDER_ALREADY_LIQUIDATED");
            return;
        }

        if(isDefaulted[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForStopLoss","ORDER_ALREADY_DEFAULTED");
            return;
        }

        Order memory order = hashToOrder[_orderHash];
        order.trade.exchangeConnector = _exchangeConnector;

        if(ERC20(order.trade.tradeToken).balanceOf(address(escrow)) < initialTradeAmount[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForStopLoss", "INSUFFICIENT_TRADE_BALANCE_IN_ESCROW");
            return;
        }

        if(ERC20(order.collateralToken).balanceOf(address(escrow)) < order.collateralAmount){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForStopLoss", "INSUFFICIENT_COLLATERAL_BALANCE_IN_ESCROW");
            return;
        }

        if(!_isPositionAboveStopLoss(order, _tokenPrices, _bufferInPrincipal)) {
            isDefaulted[order.orderHash] = true;
            _performOrderLiquidation(order);
            emit LogOrderDefaulted(order.orderHash, "MKERNEL_ORDER_UNSAFE");
            return;
        }

        emit LogErrorWithHintBytes32(order.orderHash, "MKernel::processTradeForStopLoss", "NO_ACTION_PERFORMED");
    }

    function processTradeForStopProfit
    (
        bytes32 _orderHash,
        address _exchangeConnector,
        uint[2] _tokenPrices,
        uint _bufferInPrincipal
    )
        external
        note
        onlyAdmin
        addressValid(_exchangeConnector)
    {   
        if(!isOrder[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForStopProfit","ORDER_DOES_NOT_EXIST");
            return;
        }

        if(isLiquidated[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForStopProfit","ORDER_ALREADY_LIQUIDATED");
            return;
        }

        if(isDefaulted[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForStopProfit","ORDER_ALREADY_DEFAULTED");
            return;
        }

        Order memory order = hashToOrder[_orderHash];
        order.trade.exchangeConnector = _exchangeConnector;

        if(ERC20(order.trade.tradeToken).balanceOf(address(escrow)) < initialTradeAmount[_orderHash]){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForStopProfit", "INSUFFICIENT_TRADE_BALANCE_IN_ESCROW");
            return;
        }

        if(ERC20(order.collateralToken).balanceOf(address(escrow)) < order.collateralAmount){
            emit LogErrorWithHintBytes32(_orderHash, "MKernel::processTradeForStopProfit", "INSUFFICIENT_COLLATERAL_BALANCE_IN_ESCROW");
            return;
        }
        
        if(_isPositionAboveStopProfit(order, _tokenPrices, _bufferInPrincipal)) {
            isLiquidated[order.orderHash] = true;
            _performOrderLiquidation(order);
            emit LogOrderStoppedAtProfit(order.orderHash);
            return;
        }

        emit LogErrorWithHintBytes32(order.orderHash, "MKernel::processTradeForStopProfit", "NO_ACTION_PERFORMED");
    }

    function _performOrderLiquidation(Order _order) 
        internal
    {   
        uint tradeAmount = initialTradeAmount[_order.orderHash];
        uint valueToRepay = add(_order.principalAmount, _order.premium);
        uint valueToRepayWithFee = add(valueToRepay, _order.fee);
    
        uint principalFromTrade = 0;
        uint principalFromCollateral = 0;
        uint principalNeededFromCollateral = 0;
        uint collateralLeft = 0;
        uint userProfit = 0;
        uint totalPrincipalAcquired = 0;
        uint orderFee = 0;
        

        
            (principalFromTrade,) = _tradeWithFixedInput(_order, _order.trade.tradeToken, _order.principalToken, tradeAmount);

            if(principalFromTrade >= valueToRepayWithFee) {
                userProfit = sub(principalFromTrade, valueToRepayWithFee);
                orderFee = _order.fee;
                _performSettlement(_order, valueToRepay, _order.premium, 0, _order.collateralAmount, userProfit, orderFee);
            } else {

                principalNeededFromCollateral = sub(valueToRepayWithFee, principalFromTrade);

                if (_order.collateralToken == _order.principalToken) {
                    principalFromCollateral = principalNeededFromCollateral;

                    if(_order.collateralAmount >= principalNeededFromCollateral) {
                        collateralLeft = sub(_order.collateralAmount, principalNeededFromCollateral);
                    }

                } else {
                    (principalFromCollateral, collateralLeft) = _tradeWithFixedOutput(_order, _order.collateralToken, _order.principalToken, _order.collateralAmount, principalNeededFromCollateral);    
                }

                if(principalFromCollateral >= principalNeededFromCollateral) {
                    orderFee = _order.fee;
                    _performSettlement(_order, valueToRepay, _order.premium, 0, collateralLeft, 0, orderFee);
                } else {
                    totalPrincipalAcquired = add(principalFromTrade, principalFromCollateral);
                    _performSettlementAfterAllPossibleLiquidations(_order, totalPrincipalAcquired);
                }
            }
                       
    }

    function _tradeWithFixedInput(Order _order, address _srcToken, address _destToken, uint _srcTokenValue)
        internal
        returns (uint _destTokenValue, uint _srcTokenValueLeft)
    {
        ExchangeConnector exchangeConnector = ExchangeConnector(_order.trade.exchangeConnector);
        return exchangeConnector.tradeWithInputFixed(
                    escrow,
                    _srcToken,
                    _destToken,
                    _srcTokenValue
        );
    }

    function _tradeWithFixedOutput(Order _order, address _srcToken, address _destToken, uint _srcTokenValue, uint _maxDestTokenValue)
        internal
        returns (uint _destTokenValue, uint _srcTokenValueLeft)
    {
        ExchangeConnector exchangeConnector = ExchangeConnector(_order.trade.exchangeConnector);
        return exchangeConnector.tradeWithOutputFixed(
                    escrow,
                    _srcToken,
                    _destToken,
                    _srcTokenValue,
                    _maxDestTokenValue
        );
    }

    function _isTradeFeasible(Order _order, address _srcToken, address _destToken, uint _srcTokenValue)
        internal
        view
        returns (bool)
    {   
        ExchangeConnector exchangeConnector = ExchangeConnector(_order.trade.exchangeConnector);
        return exchangeConnector.isTradeFeasible(_srcToken, _destToken, _srcTokenValue);
    }

    function _performSettlementAfterAllPossibleLiquidations
    (
        Order _order,
        uint _totalPrincipalAcquired
    )
        internal
    {
        uint valueToRepay = add(_order.principalAmount, _order.premium);

        if(_totalPrincipalAcquired >= valueToRepay) {
            _performSettlement(_order, valueToRepay, _order.premium, 0, 0, 0, sub(_totalPrincipalAcquired, valueToRepay));
        } else if((_totalPrincipalAcquired < valueToRepay) && (_totalPrincipalAcquired >= _order.principalAmount)) {
            _performSettlement(_order, _totalPrincipalAcquired, sub(_totalPrincipalAcquired, _order.principalAmount), 0, 0, 0, 0);
        } else {
            _performSettlement(_order, _totalPrincipalAcquired, 0, sub(_order.principalAmount, _totalPrincipalAcquired), 0, 0, 0);
        }

    }

    function _performSettlement
    (
        Order _order,
        uint _valueRepaid,
        uint _reserveProfit,
        uint _reserveLoss,
        uint _collateralLeft,
        uint _userProfit,
        uint _fee
    ) 
        internal 
    {
        uint closingFromPrincipal = 0;
        uint userEarnings = _userProfit;

        if(_fee > 0){
            escrow.transfer(_order.principalToken, feeWallet, _fee);
        }
        
        reserve.lock(_order.principalToken, escrow, _valueRepaid, _reserveProfit, _reserveLoss);
        
        if(_collateralLeft > 0) {
            escrow.transfer(_order.collateralToken, _order.account, _collateralLeft);    
        }

        if(_userProfit > 0) {
            if(_order.trade.closingToken == _order.principalToken || !_isTradeFeasible(_order, _order.principalToken, _order.trade.closingToken, _userProfit)) {
                escrow.transfer(_order.principalToken, _order.account, _userProfit);
            } else {
                (closingFromPrincipal,) = _tradeWithFixedInput(_order, _order.principalToken, _order.trade.closingToken, _userProfit);
                escrow.transfer(_order.trade.closingToken, _order.account, closingFromPrincipal);
                userEarnings = closingFromPrincipal;
            }
        }

        emit LogOrderSettlement(_order.orderHash, _valueRepaid, _reserveProfit, _reserveLoss, _collateralLeft, userEarnings, _fee);
    }

    function _isPositionAboveStopLoss(Order _order, uint[2] _tokenPrices, uint _bufferInPrincipal)
        internal 
        view
        returns (bool)
    {
        uint principalPerCollateral = _tokenPrices[0]; 
        uint principalPerTrade = _tokenPrices[1];
        uint tradeAmount = initialTradeAmount[_order.orderHash];

        uint valueToRepayWithFee = add(add(_order.principalAmount, _order.premium), _order.fee);
        uint totalCollateralValueInPrincipal = div(mul(_order.collateralAmount, principalPerCollateral), WAD);
        uint totalTradeValueInPrincipal = div(mul(tradeAmount, principalPerTrade), WAD);

        uint bufferValue = div(mul(_order.principalAmount, _bufferInPrincipal), WAD);
        uint minValueReq = div(mul(_order.trade.stopLoss, totalCollateralValueInPrincipal), WAD);

        if(add(valueToRepayWithFee, bufferValue) >= totalTradeValueInPrincipal && 
            sub(add(valueToRepayWithFee, bufferValue), totalTradeValueInPrincipal) >= minValueReq) 
        {
            return false;
        }

        return true;
    }

    function _isPositionAboveStopProfit(Order _order, uint[2] _tokenPrices, uint _bufferInPrincipal)
        internal 
        view
        returns (bool)
    {       
        if(_order.trade.stopProfit == 0) {
            return false;
        } else {
            uint principalPerTrade = _tokenPrices[1];
            uint tradeAmount = initialTradeAmount[_order.orderHash];

            uint valueToRepayWithFee = add(add(_order.principalAmount, _order.premium), _order.fee);
            uint totalTradeValueInPrincipal = div(mul(tradeAmount, principalPerTrade), WAD);

            uint stopProfitValue = div(mul(_order.principalAmount, _order.trade.stopProfit), WAD);
            uint bufferValue = div(mul(_order.principalAmount, _bufferInPrincipal), WAD);

            if(totalTradeValueInPrincipal >= add(add(valueToRepayWithFee, stopProfitValue), bufferValue)) {
                return true;
            }

            return false;
        }
    }

    function _generateLiquidateOrderHash
    (
        bytes32 _orderHash
    )
        internal
        view
        returns (bytes32 _liquidateOrderHash)
    {
        return keccak256(
            abi.encodePacked(
                address(this),
                _orderHash,
                "CANCEL_MKERNEL_ORDER"
            )
        );
    }

    function _isOrderValid(Order _order)
        internal
        pure
        returns (bool)
    {
        if(_order.account == address(0) || _order.byUser == address(0)
         || _order.principalToken == address(0) || _order.collateralToken == address(0)
         || _order.trade.closingToken == address(0)
         || _order.trade.tradeToken == address(0)
         || (_order.trade.tradeToken == _order.principalToken) || _order.trade.exchangeConnector == address(0)
         || _order.principalAmount == 0 || _order.collateralAmount == 0
         || _order.premium == 0
         || _order.expirationTimestamp <= _order.createdTimestamp || _order.salt == 0) {
            return false;
        }

        return true;
    }

    function _composeOrder
    (
        address[6] _orderAddresses,
        uint[8] _orderValues
    )
        internal
        view
        returns (Order _order)
    {   
        Trade memory trade = _composeTrade(_orderAddresses[4], _orderAddresses[5], _orderValues[6], _orderValues[7]);

        Order memory order = Order({
            account: _orderAddresses[0],
            byUser: _orderAddresses[1],
            principalToken: _orderAddresses[2],
            collateralToken: _orderAddresses[3],
            principalAmount: _orderValues[0],
            collateralAmount: _orderValues[1],
            premium: _orderValues[2],
            duration: _orderValues[3],
            expirationTimestamp: add(now, _orderValues[3]),
            salt: _orderValues[4],
            fee: _orderValues[5],
            createdTimestamp: now,
            orderHash: bytes32(0),
            trade: trade
        });

        order.orderHash = _generateOrderHash(order);
    
        return order;
    }

    function _composeTrade
    (
        address _tradeToken,
        address _closingToken,
        uint _stopProfit,
        uint _stopLoss
    )
        internal 
        pure
        returns (Trade _trade)
    {
        _trade = Trade({
            tradeToken: _tradeToken,
            closingToken: _closingToken,
            stopProfit: _stopProfit,
            stopLoss: _stopLoss,
            exchangeConnector: address(0)
        });
    }

    function _generateOrderHash(Order _order)
        internal
        view
        returns (bytes32 _orderHash)
    {
        return keccak256(
            abi.encodePacked(
                address(this),
                _generateOrderHash1(_order),
                _generateOrderHash2(_order)
            )
        );
    }

    function _generateOrderHash1(Order _order)
        internal
        view
        returns (bytes32 _orderHash1) 
    {
        return keccak256(
            abi.encodePacked(
                address(this),
                _order.account,
                _order.principalToken,
                _order.collateralToken,
                _order.principalAmount,
                _order.collateralAmount,
                _order.premium,
                _order.duration,
                _order.salt,
                _order.fee
            )
        );
    }

    function _generateOrderHash2(Order _order)
        internal
        view
        returns (bytes32 _orderHash2)
    {
        return keccak256(
            abi.encodePacked(
                address(this),
                _order.trade.tradeToken,
                _order.trade.closingToken,
                _order.trade.stopProfit,
                _order.trade.stopLoss,
                _order.salt
            )
        );
    }

    function getAllOrders()
        public 
        view 
        returns 
        (
            bytes32[]
        )
    {
        return orders;
    }

    
    function getOrder(bytes32 _orderHash)
        public 
        view 
        returns 
        (
            address _account,
            address _byUser,
            address _principalToken,
            address _collateralToken,
            uint _principalAmount,
            uint _collateralAmount,
            uint _premium,
            uint _expirationTimestamp,
            uint _salt,
            uint _fee,
            uint _createdTimestamp
        )
    {   
        Order memory order = hashToOrder[_orderHash];
        return (
            order.account,
            order.byUser,
            order.principalToken,
            order.collateralToken,
            order.principalAmount,
            order.collateralAmount,
            order.premium,
            order.expirationTimestamp,
            order.salt,
            order.fee,
            order.createdTimestamp
        );
    }

    function getTrade(bytes32 _orderHash)
        public 
        view 
        returns 
        (
            address _tradeToken,
            address _closingToken,
            address _initExchangeConnector,
            uint _stopProfit,
            uint _stopLoss
        )
    {   
        Order memory order = hashToOrder[_orderHash];
        return (
            order.trade.tradeToken,
            order.trade.closingToken,
            order.trade.exchangeConnector,
            order.trade.stopProfit,
            order.trade.stopLoss
        );
    }

    function getOrdersForAccount(address _account) 
        public
        view 
        returns 
        (
            bytes32[]
        )
    {
        return accountToOrders[_account];
    }

}

Contract Security Audit

Contract ABI

[{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"initialTradeAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_config","type":"address"}],"name":"setConfig","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"isDefaulted","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"getOrdersForAccount","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"isLiquidated","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orderHash","type":"bytes32"},{"name":"_exchangeConnector","type":"address"}],"name":"processTradeForExpiry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_orderHash","type":"bytes32"}],"name":"getOrder","outputs":[{"name":"_account","type":"address"},{"name":"_byUser","type":"address"},{"name":"_principalToken","type":"address"},{"name":"_collateralToken","type":"address"},{"name":"_principalAmount","type":"uint256"},{"name":"_collateralAmount","type":"uint256"},{"name":"_premium","type":"uint256"},{"name":"_expirationTimestamp","type":"uint256"},{"name":"_salt","type":"uint256"},{"name":"_fee","type":"uint256"},{"name":"_createdTimestamp","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orderAddresses","type":"address[6]"},{"name":"_orderValues","type":"uint256[8]"},{"name":"_exchangeConnector","type":"address"},{"name":"_signature","type":"bytes"}],"name":"createOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"accountFactory","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"accountToOrders","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"stopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"config","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orderHash","type":"bytes32"},{"name":"_exchangeConnector","type":"address"},{"name":"_tokenPrices","type":"uint256[2]"},{"name":"_bufferInPrincipal","type":"uint256"}],"name":"processTradeForStopLoss","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getAllOrders","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"isOrder","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_feeWallet","type":"address"}],"name":"setFeeWallet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_reserve","type":"address"}],"name":"setReserve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_orderHash","type":"bytes32"}],"name":"getTrade","outputs":[{"name":"_tradeToken","type":"address"},{"name":"_closingToken","type":"address"},{"name":"_initExchangeConnector","type":"address"},{"name":"_stopProfit","type":"uint256"},{"name":"_stopLoss","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"orders","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_accountFactory","type":"address"}],"name":"setAccountFactory","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"start","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"authority","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orderHash","type":"bytes32"},{"name":"_exchangeConnector","type":"address"},{"name":"_tokenPrices","type":"uint256[2]"},{"name":"_bufferInPrincipal","type":"uint256"}],"name":"processTradeForStopProfit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_escrow","type":"address"}],"name":"setEscrow","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"hashToOrder","outputs":[{"name":"account","type":"address"},{"name":"byUser","type":"address"},{"name":"principalToken","type":"address"},{"name":"collateralToken","type":"address"},{"components":[{"name":"tradeToken","type":"address"},{"name":"closingToken","type":"address"},{"name":"exchangeConnector","type":"address"},{"name":"stopProfit","type":"uint256"},{"name":"stopLoss","type":"uint256"}],"name":"trade","type":"tuple"},{"name":"principalAmount","type":"uint256"},{"name":"collateralAmount","type":"uint256"},{"name":"premium","type":"uint256"},{"name":"expirationTimestamp","type":"uint256"},{"name":"duration","type":"uint256"},{"name":"salt","type":"uint256"},{"name":"fee","type":"uint256"},{"name":"createdTimestamp","type":"uint256"},{"name":"orderHash","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"reserve","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"escrow","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orderHash","type":"bytes32"},{"name":"_exchangeConnector","type":"address"},{"name":"_signature","type":"bytes"}],"name":"liquidateOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"feeWallet","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_escrow","type":"address"},{"name":"_accountFactory","type":"address"},{"name":"_reserve","type":"address"},{"name":"_feeWallet","type":"address"},{"name":"_config","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"orderHash","type":"bytes32"},{"indexed":false,"name":"tradeAmount","type":"uint256"},{"indexed":false,"name":"expirationTimestamp","type":"uint256"}],"name":"LogOrderCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"orderHash","type":"bytes32"}],"name":"LogOrderLiquidatedByUser","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"orderHash","type":"bytes32"}],"name":"LogOrderStoppedAtProfit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"orderHash","type":"bytes32"},{"indexed":false,"name":"reason","type":"string"}],"name":"LogOrderDefaulted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"orderHash","type":"bytes32"}],"name":"LogNoActionPerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"orderHash","type":"bytes32"},{"indexed":false,"name":"valueRepaid","type":"uint256"},{"indexed":false,"name":"reserveProfit","type":"uint256"},{"indexed":false,"name":"reserveLoss","type":"uint256"},{"indexed":false,"name":"collateralLeft","type":"uint256"},{"indexed":false,"name":"userProfit","type":"uint256"},{"indexed":false,"name":"fee","type":"uint256"}],"name":"LogOrderSettlement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"methodSig","type":"string"},{"indexed":false,"name":"errMsg","type":"string"}],"name":"LogError","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"bytes32Value","type":"bytes32"},{"indexed":false,"name":"methodSig","type":"string"},{"indexed":false,"name":"errMsg","type":"string"}],"name":"LogErrorWithHintBytes32","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"addressValue","type":"address"},{"indexed":false,"name":"methodSig","type":"string"},{"indexed":false,"name":"errMsg","type":"string"}],"name":"LogErrorWithHintAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"},{"anonymous":true,"inputs":[{"indexed":true,"name":"sig","type":"bytes4"},{"indexed":true,"name":"guy","type":"address"},{"indexed":true,"name":"foo","type":"bytes32"},{"indexed":true,"name":"bar","type":"bytes32"},{"indexed":false,"name":"wad","type":"uint256"},{"indexed":false,"name":"fax","type":"bytes"}],"name":"LogNote","type":"event"}]

60806040526001805460a060020a60ff021916905534801561002057600080fd5b5060405160a08062005b488339810160408181528251602084015191840151606085015160809095015160018054600160a060020a031916339081179091559295939491939290917fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9490600090a260028054600160a060020a0319908116600160a060020a03978816179091556003805482169587169590951790945560048054851693861693909317909255600580548416918516919091179055600680549092169216919091179055615a4d80620000fb6000396000f3006080604052600436106101875763ffffffff60e060020a60003504166307da68f5811461018c57806313af4035146101a3578063162cfaac146101c457806320e3dbd4146101ee5780632fcdb8dd1461020f578063359abaed1461023b578063431025e1146102ac5780634459c9a3146102c45780635778472a146102e85780636722232614610368578063687cd9c11461039a5780636dec3260146103cb57806375f12b21146103ef57806379502c55146104045780637959f20a146104195780637a9e5e4b146104425780637bea0d1c146104635780638723555e146104785780638da5cb5b1461049057806390d49b9d146104a55780639cecc80a146104c6578063a3b13799146104e7578063a85c38ef14610539578063addc1a7614610551578063be9a655514610572578063bf7e214f14610587578063c046229e1461059c578063c10c3546146105c5578063c559f686146105e6578063cd3293de146106bf578063e2fdcc17146106d4578063ebac0bd9146106e9578063f25f4b561461071a575b600080fd5b34801561019857600080fd5b506101a161072f565b005b3480156101af57600080fd5b506101a1600160a060020a0360043516610813565b3480156101d057600080fd5b506101dc6004356108bd565b60408051918252519081900360200190f35b3480156101fa57600080fd5b506101a1600160a060020a03600435166108cf565b34801561021b57600080fd5b506102276004356109ef565b604080519115158252519081900360200190f35b34801561024757600080fd5b5061025c600160a060020a0360043516610a04565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610298578181015183820152602001610280565b505050509050019250505060405180910390f35b3480156102b857600080fd5b50610227600435610a72565b3480156102d057600080fd5b506101a1600435600160a060020a0360243516610a87565b3480156102f457600080fd5b50610300600435611185565b60408051600160a060020a039c8d1681529a8c1660208c0152988b168a8a0152969099166060890152608088019490945260a087019290925260c086015260e08501526101008401526101208301939093526101408201929092529051908190036101600190f35b34801561037457600080fd5b506101a1600460c46101c435600160a060020a03166101e43560248101908401356113fd565b3480156103a657600080fd5b506103af612294565b60408051600160a060020a039092168252519081900360200190f35b3480156103d757600080fd5b506101dc600160a060020a03600435166024356122a3565b3480156103fb57600080fd5b506102276122d3565b34801561041057600080fd5b506103af6122f4565b34801561042557600080fd5b506101a1600435600160a060020a03602435166044608435612303565b34801561044e57600080fd5b506101a1600160a060020a0360043516612b91565b34801561046f57600080fd5b5061025c612c37565b34801561048457600080fd5b50610227600435612c90565b34801561049c57600080fd5b506103af612ca5565b3480156104b157600080fd5b506101a1600160a060020a0360043516612cb4565b3480156104d257600080fd5b506101a1600160a060020a0360043516612dd4565b3480156104f357600080fd5b506104ff600435612ef4565b60408051600160a060020a039687168152948616602086015292909416838301526060830152608082019290925290519081900360a00190f35b34801561054557600080fd5b506101dc60043561301a565b34801561055d57600080fd5b506101a1600160a060020a0360043516613039565b34801561057e57600080fd5b506101a1613159565b34801561059357600080fd5b506103af613226565b3480156105a857600080fd5b506101a1600435600160a060020a03602435166044608435613235565b3480156105d157600080fd5b506101a1600160a060020a0360043516613ada565b3480156105f257600080fd5b506105fe600435613bfa565b604051808f600160a060020a0316600160a060020a031681526020018e600160a060020a0316600160a060020a031681526020018d600160a060020a0316600160a060020a031681526020018c600160a060020a0316600160a060020a031681526020018b81526020018a815260200189815260200188815260200187815260200186815260200185815260200184815260200183815260200182600019166000191681526020019e50505050505050505050505050505060405180910390f35b3480156106cb57600080fd5b506103af613cb8565b3480156106e057600080fd5b506103af613cc7565b3480156106f557600080fd5b506101a1600480359060248035600160a060020a031691604435918201910135613cd6565b34801561072657600080fd5b506103af6145c3565b61074533600035600160e060020a0319166145d2565b1515610789576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a450506001805474ff0000000000000000000000000000000000000000191674010000000000000000000000000000000000000000179055565b61082933600035600160e060020a0319166145d2565b151561086d576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b60018054600160a060020a031916600160a060020a0383811691909117918290556040519116907fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9490600090a250565b600b6020526000908152604090205481565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a461093633600035600160e060020a0319166145d2565b151561097a576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b82600160a060020a03811615156109c9576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b505060068054600160a060020a031916600160a060020a03939093169290921790915550565b600d6020526000908152604090205460ff1681565b600160a060020a0381166000908152600a6020908152604091829020805483518184028101840190945280845260609392830182828015610a6557602002820191906000526020600020905b81548152600190910190602001808311610a50575b505050505090505b919050565b600c6020526000908152604090205460ff1681565b610a8f61579a565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a46006546040805160e060020a639c14ee290281523360048201529051600160a060020a0390921691639c14ee29916024808201926020929091908290030181600087803b158015610b3057600080fd5b505af1158015610b44573d6000803e3d6000fd5b505050506040513d6020811015610b5a57600080fd5b50511515610ba0576040805160e560020a62461bcd02815260206004820181905260248201526000805160206159e2833981519152604482015290519081900360640190fd5b83600160a060020a0381161515610bef576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b60008681526009602052604090205460ff161515610c6d5760408051818152601e818301526000805160206158e2833981519152606082015260806020820181905260149082015260008051602061598283398151915260a0820152905187916000805160206158a2833981519152919081900360c00190a261117d565b6000868152600c602052604090205460ff1615610cea5760408051818152601e818301526000805160206158e2833981519152606082015260806020820181905260189082015260008051602061584283398151915260a0820152905187916000805160206158a2833981519152919081900360c00190a261117d565b6000868152600d602052604090205460ff1615610d675760408051818152601e818301526000805160206158e2833981519152606082015260806020820181905260179082015260008051602061588283398151915260a0820152905187916000805160206158a2833981519152919081900360c00190a261117d565b600086815260086020818152604080842081516101c0810183528154600160a060020a039081168252600183015481168286015260028084015482168386015260038401548216606080850191909152855160a081810188526004808801548616835260058801548616838b0152600788015493830193909352988601546080828101919091528501818152600987015499860199909952600a86015460c0860152600b8087015460e0870152600c870154610100870152600d870154610120870152600e870154610140870152600f87015461016087015260108701546101808701526011909601546101a08601528e8416908701528e8952938652848820549651519054855160e060020a6370a08231028152908316948101949094529351919a50949592909416936370a082319360248084019491938390030190829087803b158015610eb657600080fd5b505af1158015610eca573d6000803e3d6000fd5b505050506040513d6020811015610ee057600080fd5b50511015610f5e5760408051818152601e818301526000805160206158e2833981519152606082015260806020820181905260249082015260008051602061594283398151915260a082015260e060020a6343524f570260c0820152905187916000805160206158a2833981519152919081900360e00190a261117d565b60c084015160608501516002546040805160e060020a6370a08231028152600160a060020a039283166004820152905191909216916370a082319160248083019260209291908290030181600087803b158015610fba57600080fd5b505af1158015610fce573d6000803e3d6000fd5b505050506040513d6020811015610fe457600080fd5b505110156110665760408051818152601e818301526000805160206158e2833981519152606082015260806020820181905260299082015260008051602061596283398151915260a0820152600080516020615a0283398151915260c0820152905187916000805160206158a2833981519152919081900360e00190a261117d565b836101000151421115611106576101a08401516000908152600d60205260409020805460ff1916600117905561109b846146db565b6101a08401516040805160208082526017908201527f4d4b45524e454c5f4455455f444154455f5041535345440000000000000000008183015290517f98e393d0760ecfe8e3907134d357e8a4fa5b37e364c3baeb0b059a98317638c49181900360600190a261117d565b6101a084015160408051818152601e818301526000805160206158e283398151915260608201526080602082018190526013908201527f4e4f5f414354494f4e5f504552464f524d45440000000000000000000000000060a082015290516000805160206158a28339815191529181900360c00190a25b505050505050565b600080600080600080600080600080600061119e61579a565b600860008e600019166000191681526020019081526020016000206101c060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016003820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016004820160a060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a0316815260200160038201548152602001600482015481525050815260200160098201548152602001600a8201548152602001600b8201548152602001600c8201548152602001600d8201548152602001600e8201548152602001600f8201548152602001601082015481526020016011820154600019166000191681525050905080600001518160200151826040015183606001518460a001518560c001518660e001518761010001518861014001518961016001518a61018001519b509b509b509b509b509b509b509b509b509b509b505091939597999b90929496989a50565b61140561579a565b604080513480825260208201838152369383018490526000936004359360243593849386933393600160e060020a03198a351693928a929190606082018484808284376040519201829003965090945050505050a46006546040805160e060020a639c14ee290281523360048201529051600160a060020a0390921691639c14ee29916024808201926020929091908290030181600087803b1580156114aa57600080fd5b505af11580156114be573d6000803e3d6000fd5b505050506040513d60208110156114d457600080fd5b5051151561151a576040805160e560020a62461bcd02815260206004820181905260248201526000805160206159e2833981519152604482015290519081900360640190fd5b60015474010000000000000000000000000000000000000000900460ff161561158d576040805160e560020a62461bcd02815260206004820152601960248201527f445353746f703a3a5f20464541545552455f53544f5050454400000000000000604482015290519081900360640190fd5b86600160a060020a03811615156115dc576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b6040805160c0818101909252611624918c90600690839083908082843750506040805161010081810190925293508e92506008915083908390808284375061485b9350505050565b9450611665856101a0015188888080601f01602080910402602001604051908101604052809392919081815260200183838082843750614950945050505050565b6080860151600160a060020a03808b16604090920191909152602087015191955080861691161461170b576101a0850151604080518181526014818301526000805160206159a283398151915260608201526080602082018190526018908201527f5349474e45525f4e4f545f4f524445525f43524541544f52000000000000000060a082015290516000805160206158a28339815191529181900360c00190a2612288565b6101a085015160009081526009602052604090205460ff16156117a2576101a08501516040805181815260148183018190526000805160206159a283398151915260608301526080602083018190528201527f4f524445525f414c52454144595f45584953545300000000000000000000000060a082015290516000805160206158a28339815191529181900360c00190a2612288565b6003548551604080517f25ca4c9c000000000000000000000000000000000000000000000000000000008152600160a060020a039283166004820152905191909216916325ca4c9c9160248083019260209291908290030181600087803b15801561180c57600080fd5b505af1158015611820573d6000803e3d6000fd5b505050506040513d602081101561183657600080fd5b505115156118b9576101a0850151604080518181526014818301526000805160206159a283398151915260608201526080602082018190526015908201527f494e56414c49445f4f524445525f4143434f554e54000000000000000000000060a082015290516000805160206158a28339815191529181900360c00190a2612288565b8460000151600160a060020a0316634209fff1856040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561191857600080fd5b505af115801561192c573d6000803e3d6000fd5b505050506040513d602081101561194257600080fd5b505115156119eb576101a0850151604080518181526014818301526000805160206159a283398151915260608201526080602082018190526022908201527f5349474e45525f4e4f545f415554484f52495a45445f574954485f4143434f5560a08201527f4e5400000000000000000000000000000000000000000000000000000000000060c082015290516000805160206158a28339815191529181900360e00190a2612288565b6119f485614972565b1515611a75576101a0850151604080518181526014818301526000805160206159a283398151915260608201526080602082018190526018908201527f494e56414c49445f4f524445525f504152414d4554455253000000000000000060a082015290516000805160206158a28339815191529181900360c00190a2612288565b8460c001518560600151600160a060020a03166370a0823187600001516040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b158015611add57600080fd5b505af1158015611af1573d6000803e3d6000fd5b505050506040513d6020811015611b0757600080fd5b50511015611bb0576101a0850151604080518181526014818301526000805160206159a283398151915260608201526080602082018190526022908201527f494e53554646494349454e545f434f4c4c41544552414c5f494e5f4143434f5560a08201527f4e5400000000000000000000000000000000000000000000000000000000000060c082015290516000805160206158a28339815191529181900360e00190a2612288565b8460a001518560400151600160a060020a03166370a08231600460009054906101000a9004600160a060020a0316600160a060020a031663e2fdcc176040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015611c1b57600080fd5b505af1158015611c2f573d6000803e3d6000fd5b505050506040513d6020811015611c4557600080fd5b50516040805160e060020a63ffffffff8516028152600160a060020a0390921660048301525160248083019260209291908290030181600087803b158015611c8c57600080fd5b505af1158015611ca0573d6000803e3d6000fd5b505050506040513d6020811015611cb657600080fd5b50511015611d39576101a0850151604080518181526014818301526000805160206159a28339815191526060820152608060208201819052601d908201527f494e53554646494349454e545f46554e44535f494e5f5245534552564500000060a082015290516000805160206158a28339815191529181900360c00190a2612288565b611d558586604001518760800151600001518860a00151614a95565b1515611dd6576101a0850151604080518181526014818301526000805160206159a283398151915260608201526080602082018190526012908201527f54524144455f4e4f545f4645415349424c45000000000000000000000000000060a082015290516000805160206158a28339815191529181900360c00190a2612288565b6007856101a0015190806001815401808255809150509060018203906000526020600020016000909192909190915090600019169055508460086000876101a001516000191660001916815260200190815260200160002060008201518160000160006101000a815481600160a060020a030219169083600160a060020a0316021790555060208201518160010160006101000a815481600160a060020a030219169083600160a060020a0316021790555060408201518160020160006101000a815481600160a060020a030219169083600160a060020a0316021790555060608201518160030160006101000a815481600160a060020a030219169083600160a060020a0316021790555060808201518160040160008201518160000160006101000a815481600160a060020a030219169083600160a060020a0316021790555060208201518160010160006101000a815481600160a060020a030219169083600160a060020a0316021790555060408201518160020160006101000a815481600160a060020a030219169083600160a060020a031602179055506060820151816003015560808201518160040155505060a0820151816009015560c082015181600a015560e082015181600b015561010082015181600c015561012082015181600d015561014082015181600e015561016082015181600f015561018082015181601001556101a08201518160110190600019169055905050600160096000876101a001516000191660001916815260200190815260200160002060006101000a81548160ff021916908315150217905550600a60008660000151600160a060020a0316600160a060020a03168152602001908152602001600020856101a001519080600181540180825580915050906001820390600052602060002001600090919290919091509060001916905550600260009054906101000a9004600160a060020a0316600160a060020a0316635e61e1c886600001518760600151600260009054906101000a9004600160a060020a03168960c001516040518563ffffffff1660e060020a0281526004018085600160a060020a0316600160a060020a0316815260200184600160a060020a0316600160a060020a0316815260200183600160a060020a0316600160a060020a03168152602001828152602001945050505050600060405180830381600087803b15801561215557600080fd5b505af1158015612169573d6000803e3d6000fd5b5050600480546040808a015160025460a08c015183517f8bfb07c9000000000000000000000000000000000000000000000000000000008152600160a060020a039384169681019690965290821660248601526044850152905191169350638bfb07c99250606480830192600092919082900301818387803b1580156121ee57600080fd5b505af1158015612202573d6000803e3d6000fd5b505050506122228586604001518760800151600001518860a00151614b48565b506101a0860180516000908152600b602090815260408083209490945591518082529083902054610100890151845191825292810192909252825190927fea0bf587ab60e35e1551a895f638f97223b5471e71aef9e3102dfe8ceb87dc01928290030190a25b50505050505050505050565b600354600160a060020a031681565b600a602052816000526040600020818154811015156122be57fe5b90600052602060002001600091509150505481565b60015474010000000000000000000000000000000000000000900460ff1681565b600654600160a060020a031681565b61230b61579a565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a46006546040805160e060020a639c14ee290281523360048201529051600160a060020a0390921691639c14ee29916024808201926020929091908290030181600087803b1580156123ac57600080fd5b505af11580156123c0573d6000803e3d6000fd5b505050506040513d60208110156123d657600080fd5b5051151561241c576040805160e560020a62461bcd02815260206004820181905260248201526000805160206159e2833981519152604482015290519081900360640190fd5b85600160a060020a038116151561246b576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b60008881526009602052604090205460ff1615156124ea576040805181815260208183018190526000805160206159228339815191526060830152608090820181905260149082015260008051602061598283398151915260a0820152905189916000805160206158a2833981519152919081900360c00190a2612b87565b6000888152600c602052604090205460ff1615612568576040805181815260208183018190526000805160206159228339815191526060830152608090820181905260189082015260008051602061584283398151915260a0820152905189916000805160206158a2833981519152919081900360c00190a2612b87565b6000888152600d602052604090205460ff16156125e6576040805181815260208183018190526000805160206159228339815191526060830152608090820181905260179082015260008051602061588283398151915260a0820152905189916000805160206158a2833981519152919081900360c00190a2612b87565b6008600089600019166000191681526020019081526020016000206101c060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016003820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016004820160a060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a0316815260200160038201548152602001600482015481525050815260200160098201548152602001600a8201548152602001600b8201548152602001600c8201548152602001600d8201548152602001600e8201548152602001600f8201548152602001601082015481526020016011820154600019166000191681525050935086846080015160400190600160a060020a03169081600160a060020a031681525050600b6000896000191660001916815260200190815260200160002054846080015160000151600160a060020a03166370a08231600260009054906101000a9004600160a060020a03166040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561289a57600080fd5b505af11580156128ae573d6000803e3d6000fd5b505050506040513d60208110156128c457600080fd5b50511015612943576040805181815260208183018190526000805160206159228339815191526060830152608090820181905260249082015260008051602061594283398151915260a082015260e060020a6343524f570260c0820152905189916000805160206158a2833981519152919081900360e00190a2612b87565b60c084015160608501516002546040805160e060020a6370a08231028152600160a060020a039283166004820152905191909216916370a082319160248083019260209291908290030181600087803b15801561299f57600080fd5b505af11580156129b3573d6000803e3d6000fd5b505050506040513d60208110156129c957600080fd5b50511015612a4c576040805181815260208183018190526000805160206159228339815191526060830152608090820181905260299082015260008051602061596283398151915260a0820152600080516020615a0283398151915260c0820152905189916000805160206158a2833981519152919081900360e00190a2612b87565b604080518082018252612a769186919089906002908390839080828437508b9350614c1092505050565b1515612b0f576101a08401516000908152600d60205260409020805460ff19166001179055612aa4846146db565b6101a08401516040805160208082526014908201527f4d4b45524e454c5f4f524445525f554e534146450000000000000000000000008183015290517f98e393d0760ecfe8e3907134d357e8a4fa5b37e364c3baeb0b059a98317638c49181900360600190a2612b87565b6101a0840151604080518181526020818301819052600080516020615922833981519152606083015260809082018190526013908201527f4e4f5f414354494f4e5f504552464f524d45440000000000000000000000000060a082015290516000805160206158a28339815191529181900360c00190a25b5050505050505050565b612ba733600035600160e060020a0319166145d2565b1515612beb576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b60008054600160a060020a031916600160a060020a03838116919091178083556040519116917f1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada491a250565b60606007805480602002602001604051908101604052809291908181526020018280548015612c8657602002820191906000526020600020905b81548152600190910190602001808311612c71575b5050505050905090565b60096020526000908152604090205460ff1681565b600154600160a060020a031681565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a4612d1b33600035600160e060020a0319166145d2565b1515612d5f576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b82600160a060020a0381161515612dae576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b505060058054600160a060020a031916600160a060020a03939093169290921790915550565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a4612e3b33600035600160e060020a0319166145d2565b1515612e7f576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b82600160a060020a0381161515612ece576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b505060048054600160a060020a031916600160a060020a03939093169290921790915550565b6000806000806000612f0461579a565b505050600093845250506008602081815260409384902084516101c0810186528154600160a060020a0390811682526001830154811682850152600283015481168288015260038301548116606080840191909152875160a08082018a5260048601548416825260058601548416968201968752600686015490931698810198895260078501549181019182529584015460808088019182528401879052600985015492840192909252600a84015460c0840152600b84015460e0840152600c840154610100840152600d840154610120840152600e840154610140840152600f84015461016084015260108401546101808401526011909301546101a090920191909152925191519451905192519195909350565b600780548290811061302857fe5b600091825260209091200154905081565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a46130a033600035600160e060020a0319166145d2565b15156130e4576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b82600160a060020a0381161515613133576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b505060038054600160a060020a031916600160a060020a03939093169290921790915550565b61316f33600035600160e060020a0319166145d2565b15156131b3576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a450506001805474ff000000000000000000000000000000000000000019169055565b600054600160a060020a031681565b61323d61579a565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a46006546040805160e060020a639c14ee290281523360048201529051600160a060020a0390921691639c14ee29916024808201926020929091908290030181600087803b1580156132de57600080fd5b505af11580156132f2573d6000803e3d6000fd5b505050506040513d602081101561330857600080fd5b5051151561334e576040805160e560020a62461bcd02815260206004820181905260248201526000805160206159e2833981519152604482015290519081900360640190fd5b85600160a060020a038116151561339d576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b60008881526009602052604090205460ff1615156134295760408051818152602281830152600080516020615902833981519152606082015260f260020a611a5d02608082015260a06020820181905260149082015260008051602061598283398151915260c0820152905189916000805160206158a2833981519152919081900360e00190a2612b87565b6000888152600c602052604090205460ff16156134b45760408051818152602281830152600080516020615902833981519152606082015260f260020a611a5d02608082015260a06020820181905260189082015260008051602061584283398151915260c0820152905189916000805160206158a2833981519152919081900360e00190a2612b87565b6000888152600d602052604090205460ff161561353f5760408051818152602281830152600080516020615902833981519152606082015260f260020a611a5d02608082015260a06020820181905260179082015260008051602061588283398151915260c0820152905189916000805160206158a2833981519152919081900360e00190a2612b87565b6008600089600019166000191681526020019081526020016000206101c060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016003820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016004820160a060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a0316815260200160038201548152602001600482015481525050815260200160098201548152602001600a8201548152602001600b8201548152602001600c8201548152602001600d8201548152602001600e8201548152602001600f8201548152602001601082015481526020016011820154600019166000191681525050935086846080015160400190600160a060020a03169081600160a060020a031681525050600b6000896000191660001916815260200190815260200160002054846080015160000151600160a060020a03166370a08231600260009054906101000a9004600160a060020a03166040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b1580156137f357600080fd5b505af1158015613807573d6000803e3d6000fd5b505050506040513d602081101561381d57600080fd5b505110156138aa5760408051818152602281830152600080516020615902833981519152606082015260f260020a611a5d02608082015260a06020820181905260249082015260008051602061594283398151915260c082015260e060020a6343524f570260e0820152905189916000805160206158a283398151915291908190036101000190a2612b87565b60c084015160608501516002546040805160e060020a6370a08231028152600160a060020a039283166004820152905191909216916370a082319160248083019260209291908290030181600087803b15801561390657600080fd5b505af115801561391a573d6000803e3d6000fd5b505050506040513d602081101561393057600080fd5b505110156139c15760408051818152602281830152600080516020615902833981519152606082015260f260020a611a5d02608082015260a06020820181905260299082015260008051602061596283398151915260c0820152600080516020615a0283398151915260e0820152905189916000805160206158a283398151915291908190036101000190a2612b87565b6040805180820182526139eb9186919089906002908390839080828437508b9350614d0692505050565b15613a4c576101a08401516000908152600c60205260409020805460ff19166001179055613a18846146db565b6101a08401516040517fc614d231c29c73ae067f16cd5460d0050c98401008b3cce99b3abb37302e548590600090a2612b87565b6101a084015160408051818152602281830152600080516020615902833981519152606082015260f260020a611a5d02608082015260a0602082018190526013908201527f4e4f5f414354494f4e5f504552464f524d45440000000000000000000000000060c082015290516000805160206158a28339815191529181900360e00190a25050505050505050565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a4613b4133600035600160e060020a0319166145d2565b1515613b85576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b82600160a060020a0381161515613bd4576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b505060028054600160a060020a031916600160a060020a03939093169290921790915550565b6008602081815260009283526040928390208054600182015460028301546003840154875160a0810189526004860154600160a060020a03908116825260058701548116978201979097526006860154871698810198909852600785015460608901529584015460808801526009840154600a850154600b860154600c870154600d880154600e890154600f8a015460108b01546011909b0154998c169d988c169c978c169b9097169997989597949693959294919390929091908e565b600454600160a060020a031681565b600254600160a060020a031681565b600080613ce161579a565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a46006546040805160e060020a639c14ee290281523360048201529051600160a060020a0390921691639c14ee29916024808201926020929091908290030181600087803b158015613d8257600080fd5b505af1158015613d96573d6000803e3d6000fd5b505050506040513d6020811015613dac57600080fd5b50511515613df2576040805160e560020a62461bcd02815260206004820181905260248201526000805160206159e2833981519152604482015290519081900360640190fd5b87600160a060020a0381161515613e41576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b60008a81526009602052604090205460ff161515613ebf57604080518181526017818301526000805160206158c2833981519152606082015260806020820181905260149082015260008051602061598283398151915260a082015290518b916000805160206158a2833981519152919081900360c00190a2612288565b60008a8152600c602052604090205460ff1615613f3c57604080518181526017818301526000805160206158c2833981519152606082015260806020820181905260189082015260008051602061584283398151915260a082015290518b916000805160206158a2833981519152919081900360c00190a2612288565b60008a8152600d602052604090205460ff1615613fb8576040805181815260178183018190526000805160206158c2833981519152606083015260806020830181905282015260008051602061588283398151915260a082015290518b916000805160206158a2833981519152919081900360c00190a2612288565b613fc18a614de3565b9550613ffd8689898080601f01602080910402602001604051908101604052809392919081815260200183838082843750614950945050505050565b9450600860008b600019166000191681526020019081526020016000206101c060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016003820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016004820160a060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a0316815260200160038201548152602001600482015481525050815260200160098201548152602001600a8201548152602001600b8201548152602001600c8201548152602001600d8201548152602001600e8201548152602001600f8201548152602001601082015481526020016011820154600019166000191681525050935088846080015160400190600160a060020a03169081600160a060020a0316815250508360000151600160a060020a0316634209fff1866040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561427e57600080fd5b505af1158015614292573d6000803e3d6000fd5b505050506040513d60208110156142a857600080fd5b5051151561434e57604080518181526017818301526000805160206158c283398151915260608201526080602082018190526022908201527f5349474e45525f4e4f545f415554484f52495a45445f574954485f4143434f5560a08201527f4e5400000000000000000000000000000000000000000000000000000000000060c082015290518b916000805160206158a2833981519152919081900360e00190a2612288565b60008a8152600b6020908152604080832054608088015151600254835160e060020a6370a08231028152600160a060020a039182166004820152935192959116936370a08231936024808201949293918390030190829087803b1580156143b457600080fd5b505af11580156143c8573d6000803e3d6000fd5b505050506040513d60208110156143de57600080fd5b5051101561445c57604080518181526017818301526000805160206158c2833981519152606082015260806020820181905260249082015260008051602061594283398151915260a082015260e060020a6343524f570260c082015290518b916000805160206158a2833981519152919081900360e00190a2612288565b60c084015160608501516002546040805160e060020a6370a08231028152600160a060020a039283166004820152905191909216916370a082319160248083019260209291908290030181600087803b1580156144b857600080fd5b505af11580156144cc573d6000803e3d6000fd5b505050506040513d60208110156144e257600080fd5b5051101561456457604080518181526017818301526000805160206158c2833981519152606082015260806020820181905260299082015260008051602061596283398151915260a0820152600080516020615a0283398151915260c082015290518b916000805160206158a2833981519152919081900360e00190a2612288565b6101a08401516000908152600c60205260409020805460ff1916600117905561458c846146db565b6040518a907f6cc69d7894fbf109ad278f7e331e91f734cd486332ee4e1eb3625bb2538eea4990600090a250505050505050505050565b600554600160a060020a031681565b6000600160a060020a0383163014156145ed575060016146d5565b600154600160a060020a038481169116141561460b575060016146d5565b600054600160a060020a03161515614625575060006146d5565b60008054604080517fb7009613000000000000000000000000000000000000000000000000000000008152600160a060020a038781166004830152306024830152600160e060020a0319871660448301529151919092169263b700961392606480820193602093909283900390910190829087803b1580156146a657600080fd5b505af11580156146ba573d6000803e3d6000fd5b505050506040513d60208110156146d057600080fd5b505190505b92915050565b600080600080600080600080600080600b60008c6101a001516000191660001916815260200190815260200160002054995061471f8b60a001518c60e00151614ea1565b9850614730898c6101600151614ea1565b9750600096506000955060009450600093506000925060009150600090506147668b8c60800151600001518d604001518d614b48565b5096508787106147a15761477a8789614eb1565b92508a6101600151905061479c8b8a8d60e0015160008f60c001518887614ec1565b61484e565b6147ab8888614eb1565b94508a60400151600160a060020a03168b60600151600160a060020a031614156147f557849550848b60c001511015156147f0576147ed8b60c0015186614eb1565b93505b614814565b61480e8b8c606001518d604001518e60c001518961524e565b90965093505b848610614838578a6101600151905061479c8b8a8d60e00151600088600087614ec1565b6148428787614ea1565b915061484e8b8361531e565b5050505050505050505050565b61486361579a565b61486b615813565b61487361579a565b608085015160a086015160c086015160e0870151614893939291906153b8565b604080516101c0810182528751600160a060020a0390811682526020808a0151821681840152898401518216838501526060808b01519092168284015260808301859052885160a084015288015160c08301529187015160e08201529086015191935090610100820190614908904290614ea1565b81526060808701516020830152608080880151604084015260a08089015192840192909252429083015260009101529050614942816153fa565b6101a0820152949350505050565b600061496b8261495f8561548a565b9063ffffffff61550116565b9392505050565b8051600090600160a060020a0316158061499757506020820151600160a060020a0316155b806149ad57506040820151600160a060020a0316155b806149c357506060820151600160a060020a0316155b806149dd5750608082015160200151600160a060020a0316155b806149f45750608082015151600160a060020a0316155b80614a1c57508160400151600160a060020a0316826080015160000151600160a060020a0316145b80614a365750608082015160400151600160a060020a0316155b80614a43575060a0820151155b80614a50575060c0820151155b80614a5d575060e0820151155b80614a72575081610180015182610100015111155b80614a805750610140820151155b15614a8d57506000610a6d565b506001919050565b608084015160409081015181517f5d0b4e5c000000000000000000000000000000000000000000000000000000008152600160a060020a0386811660048301528581166024830152604482018590529251600093831691635d0b4e5c91606480830192602092919082900301818887803b158015614b1257600080fd5b505af1158015614b26573d6000803e3d6000fd5b505050506040513d6020811015614b3c57600080fd5b50519695505050505050565b608084015160409081015160025482517f17fd9cc5000000000000000000000000000000000000000000000000000000008152600160a060020a039182166004820152868216602482015285821660448201526064810185905283516000948594938416926317fd9cc5926084808301939282900301818887803b158015614bcf57600080fd5b505af1158015614be3573d6000803e3d6000fd5b505050506040513d6040811015614bf957600080fd5b508051602090910151909890975095505050505050565b81516020808401516101a08601516000908152600b909252604082205460a087015160e088015193949385918291829182918291614c5d91614c529190614ea1565b8d6101600151614ea1565b9450614c7e614c708d60c001518a6155d6565b670de0b6b3a76400006155fe565b9350614c8d614c7087896155d6565b9250614ca0614c708d60a001518c6155d6565b9150614cb7614c708d6080015160800151866155d6565b905082614cc48684614ea1565b10158015614ce4575080614ce1614cdb8785614ea1565b85614eb1565b10155b15614cf25760009850614cf7565b600198505b50505050505050509392505050565b600080600080600080600089608001516060015160001415614d2b5760009650614dd6565b6020808a01516101a08c01516000908152600b90925260409091205460a08c015160e08d0151929850909650614d7091614d659190614ea1565b8b6101600151614ea1565b9350614d7f614c7086886155d6565b9250614d9a614c708b60a001518c60800151606001516155d6565b9150614dad614c708b60a001518a6155d6565b9050614dc2614dbc8584614ea1565b82614ea1565b8310614dd15760019650614dd6565b600096505b5050505050509392505050565b604080516c010000000000000000000000003002602080830191909152603482018490527f43414e43454c5f4d4b45524e454c5f4f524445520000000000000000000000006054830152825160488184030181526068909201928390528151600093918291908401908083835b60208310614e6f5780518252601f199092019160209182019101614e50565b5181516020939093036101000a6000190180199091169216919091179052604051920182900390912095945050505050565b808201828110156146d557600080fd5b808203828111156146d557600080fd5b60008281831115614f4b576002546040808b0151600554825160e360020a6317d57599028152600160a060020a039283166004820152908216602482015260448101879052915192169163beabacc89160648082019260009290919082900301818387803b158015614f3257600080fd5b505af1158015614f46573d6000803e3d6000fd5b505050505b600480546040808c015160025482517f106689a5000000000000000000000000000000000000000000000000000000008152600160a060020a039283169581019590955281166024850152604484018c9052606484018b9052608484018a9052905191169163106689a59160a480830192600092919082900301818387803b158015614fd657600080fd5b505af1158015614fea573d6000803e3d6000fd5b5050505060008511156150765760025460608a01518a516040805160e360020a6317d57599028152600160a060020a03938416600482015291831660248301526044820189905251919092169163beabacc891606480830192600092919082900301818387803b15801561505d57600080fd5b505af1158015615071573d6000803e3d6000fd5b505050505b60008411156151e8578860400151600160a060020a0316896080015160200151600160a060020a031614806150c057506150be898a604001518b608001516020015187614a95565b155b15615147576002546040808b01518b51825160e360020a6317d57599028152600160a060020a039283166004820152908216602482015260448101889052915192169163beabacc89160648082019260009290919082900301818387803b15801561512a57600080fd5b505af115801561513e573d6000803e3d6000fd5b505050506151e8565b61515f898a604001518b608001516020015187614b48565b5060025460808b0151602001518b516040805160e360020a6317d57599028152600160a060020a0393841660048201529183166024830152604482018590525193955091169163beabacc89160648082019260009290919082900301818387803b1580156151cc57600080fd5b505af11580156151e0573d6000803e3d6000fd5b505050508190505b6101a0890151604080518a8152602081018a9052808201899052606081018890526080810184905260a0810186905290517fd5620126c5a9c2d177d7302570339d14ed881b5f6d3fdb8f63bd6fa00601bc6b9181900360c00190a2505050505050505050565b608085015160409081015160025482517fc83ec89d000000000000000000000000000000000000000000000000000000008152600160a060020a039182166004820152878216602482015286821660448201526064810186905260848101859052835160009485949384169263c83ec89d9260a4808301939282900301818887803b1580156152dc57600080fd5b505af11580156152f0573d6000803e3d6000fd5b505050506040513d604081101561530657600080fd5b50805160209091015190999098509650505050505050565b60006153328360a001518460e00151614ea1565b905080821061535e5761535983828560e0015160008060006153548989614eb1565b614ec1565b6153b3565b808210801561537157508260a001518210155b15615394576153598383615389858760a00151614eb1565b600080600080614ec1565b6153b3838360006153a98760a0015187614eb1565b6000806000614ec1565b505050565b6153c0615813565b506040805160a081018252600160a060020a0395861681529390941660208401526000938301939093526060820152608081019190915290565b60003061540683615613565b61540f846156ef565b604080516c01000000000000000000000000600160a060020a0390951694909402602080860191909152603485019390935260548085019290925280518085039092018252607490930192839052805190929182919084019080838360208310614e6f5780518252601f199092019160209182019101614e50565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c80830185905283518084039091018152605c9092019283905281516000939182919084019080838360208310614e6f5780518252601f199092019160209182019101614e50565b6000806000808451604114151561551b57600093506155cd565b50505060208201516040830151606084015160001a601b60ff8216101561554057601b015b8060ff16601b1415801561555857508060ff16601c14155b1561556657600093506155cd565b60408051600080825260208083018085528a905260ff8516838501526060830187905260808301869052925160019360a0808501949193601f19840193928390039091019190865af11580156155c0573d6000803e3d6000fd5b5050506020604051035193505b50505092915050565b60008115806155f35750508082028282828115156155f057fe5b04145b15156146d557600080fd5b6000818381151561560b57fe5b049392505050565b8051604080830151606084015160a085015160c086015160e08701516101208801516101408901516101608a015188516c01000000000000000000000000308102602080840191909152600160a060020a039c8d1682026034840152998c16810260488301529a909716909902605c8701526070860194909452609085019290925260b084015260d083015260f0820152610110808201949094528251808203909401845261013001918290528251600093929182919084019080838360208310614e6f5780518252601f199092019160209182019101614e50565b608080820151805160208083015160608401519390940151610140860151604080516c0100000000000000000000000030810282870152600160a060020a0396871681026034830152959097169094026048870152605c860194909452607c850152609c808501939093528151808503909301835260bc90930190819052815160009382919084019080838360208310614e6f5780518252601f199092019160209182019101614e50565b60408051610240810182526000808252602082018190529181018290526060810191909152608081016157cb615813565b81526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600080191681525090565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091529056004f524445525f414c52454144595f4c49515549444154454400000000000000004453417574683a3a5f2053454e4445525f4e4f545f415554484f52495a4544004f524445525f414c52454144595f44454641554c544544000000000000000000db0b341562703a7cbd47efa0b024b1ed2e3c68e2d313e46d276db9a46d8a6f804d4b65726e656c3a3a6c69717569646174654f726465720000000000000000004d4b65726e656c3a3a70726f636573735472616465466f7245787069727900004d4b65726e656c3a3a70726f636573735472616465466f7253746f7050726f664d4b65726e656c3a3a70726f636573735472616465466f7253746f704c6f7373494e53554646494349454e545f54524144455f42414c414e43455f494e5f4553494e53554646494349454e545f434f4c4c41544552414c5f42414c414e43455f4f524445525f444f45535f4e4f545f45584953540000000000000000000000004d4b65726e656c3a3a6372656174654f726465720000000000000000000000005574696c733a3a5f20494e56414c49445f4144445245535300000000000000004d4b65726e656c3a3a5f20494e56414c49445f41444d494e5f4143434f554e54494e5f455343524f570000000000000000000000000000000000000000000000a165627a7a72305820b978523cfaf0225ad9aaac828feaa290019983b18ae0961590f65ff6838948120029000000000000000000000000af38668f4719ecf9452dc0300be3f6c83cbf37210000000000000000000000004e9d7f37eadc6fef64b5f5dccc4deb622466767700000000000000000000000064d14595152b430cf6940da15c6e39545c7c5b7e0000000000000000000000003e990e787a88cd4426fb3af9b90dd1d951e2cb87000000000000000000000000431f429035a1e3059d5c6a9a83208c6d3143d925

Deployed Bytecode

0x6080604052600436106101875763ffffffff60e060020a60003504166307da68f5811461018c57806313af4035146101a3578063162cfaac146101c457806320e3dbd4146101ee5780632fcdb8dd1461020f578063359abaed1461023b578063431025e1146102ac5780634459c9a3146102c45780635778472a146102e85780636722232614610368578063687cd9c11461039a5780636dec3260146103cb57806375f12b21146103ef57806379502c55146104045780637959f20a146104195780637a9e5e4b146104425780637bea0d1c146104635780638723555e146104785780638da5cb5b1461049057806390d49b9d146104a55780639cecc80a146104c6578063a3b13799146104e7578063a85c38ef14610539578063addc1a7614610551578063be9a655514610572578063bf7e214f14610587578063c046229e1461059c578063c10c3546146105c5578063c559f686146105e6578063cd3293de146106bf578063e2fdcc17146106d4578063ebac0bd9146106e9578063f25f4b561461071a575b600080fd5b34801561019857600080fd5b506101a161072f565b005b3480156101af57600080fd5b506101a1600160a060020a0360043516610813565b3480156101d057600080fd5b506101dc6004356108bd565b60408051918252519081900360200190f35b3480156101fa57600080fd5b506101a1600160a060020a03600435166108cf565b34801561021b57600080fd5b506102276004356109ef565b604080519115158252519081900360200190f35b34801561024757600080fd5b5061025c600160a060020a0360043516610a04565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610298578181015183820152602001610280565b505050509050019250505060405180910390f35b3480156102b857600080fd5b50610227600435610a72565b3480156102d057600080fd5b506101a1600435600160a060020a0360243516610a87565b3480156102f457600080fd5b50610300600435611185565b60408051600160a060020a039c8d1681529a8c1660208c0152988b168a8a0152969099166060890152608088019490945260a087019290925260c086015260e08501526101008401526101208301939093526101408201929092529051908190036101600190f35b34801561037457600080fd5b506101a1600460c46101c435600160a060020a03166101e43560248101908401356113fd565b3480156103a657600080fd5b506103af612294565b60408051600160a060020a039092168252519081900360200190f35b3480156103d757600080fd5b506101dc600160a060020a03600435166024356122a3565b3480156103fb57600080fd5b506102276122d3565b34801561041057600080fd5b506103af6122f4565b34801561042557600080fd5b506101a1600435600160a060020a03602435166044608435612303565b34801561044e57600080fd5b506101a1600160a060020a0360043516612b91565b34801561046f57600080fd5b5061025c612c37565b34801561048457600080fd5b50610227600435612c90565b34801561049c57600080fd5b506103af612ca5565b3480156104b157600080fd5b506101a1600160a060020a0360043516612cb4565b3480156104d257600080fd5b506101a1600160a060020a0360043516612dd4565b3480156104f357600080fd5b506104ff600435612ef4565b60408051600160a060020a039687168152948616602086015292909416838301526060830152608082019290925290519081900360a00190f35b34801561054557600080fd5b506101dc60043561301a565b34801561055d57600080fd5b506101a1600160a060020a0360043516613039565b34801561057e57600080fd5b506101a1613159565b34801561059357600080fd5b506103af613226565b3480156105a857600080fd5b506101a1600435600160a060020a03602435166044608435613235565b3480156105d157600080fd5b506101a1600160a060020a0360043516613ada565b3480156105f257600080fd5b506105fe600435613bfa565b604051808f600160a060020a0316600160a060020a031681526020018e600160a060020a0316600160a060020a031681526020018d600160a060020a0316600160a060020a031681526020018c600160a060020a0316600160a060020a031681526020018b81526020018a815260200189815260200188815260200187815260200186815260200185815260200184815260200183815260200182600019166000191681526020019e50505050505050505050505050505060405180910390f35b3480156106cb57600080fd5b506103af613cb8565b3480156106e057600080fd5b506103af613cc7565b3480156106f557600080fd5b506101a1600480359060248035600160a060020a031691604435918201910135613cd6565b34801561072657600080fd5b506103af6145c3565b61074533600035600160e060020a0319166145d2565b1515610789576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a450506001805474ff0000000000000000000000000000000000000000191674010000000000000000000000000000000000000000179055565b61082933600035600160e060020a0319166145d2565b151561086d576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b60018054600160a060020a031916600160a060020a0383811691909117918290556040519116907fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9490600090a250565b600b6020526000908152604090205481565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a461093633600035600160e060020a0319166145d2565b151561097a576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b82600160a060020a03811615156109c9576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b505060068054600160a060020a031916600160a060020a03939093169290921790915550565b600d6020526000908152604090205460ff1681565b600160a060020a0381166000908152600a6020908152604091829020805483518184028101840190945280845260609392830182828015610a6557602002820191906000526020600020905b81548152600190910190602001808311610a50575b505050505090505b919050565b600c6020526000908152604090205460ff1681565b610a8f61579a565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a46006546040805160e060020a639c14ee290281523360048201529051600160a060020a0390921691639c14ee29916024808201926020929091908290030181600087803b158015610b3057600080fd5b505af1158015610b44573d6000803e3d6000fd5b505050506040513d6020811015610b5a57600080fd5b50511515610ba0576040805160e560020a62461bcd02815260206004820181905260248201526000805160206159e2833981519152604482015290519081900360640190fd5b83600160a060020a0381161515610bef576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b60008681526009602052604090205460ff161515610c6d5760408051818152601e818301526000805160206158e2833981519152606082015260806020820181905260149082015260008051602061598283398151915260a0820152905187916000805160206158a2833981519152919081900360c00190a261117d565b6000868152600c602052604090205460ff1615610cea5760408051818152601e818301526000805160206158e2833981519152606082015260806020820181905260189082015260008051602061584283398151915260a0820152905187916000805160206158a2833981519152919081900360c00190a261117d565b6000868152600d602052604090205460ff1615610d675760408051818152601e818301526000805160206158e2833981519152606082015260806020820181905260179082015260008051602061588283398151915260a0820152905187916000805160206158a2833981519152919081900360c00190a261117d565b600086815260086020818152604080842081516101c0810183528154600160a060020a039081168252600183015481168286015260028084015482168386015260038401548216606080850191909152855160a081810188526004808801548616835260058801548616838b0152600788015493830193909352988601546080828101919091528501818152600987015499860199909952600a86015460c0860152600b8087015460e0870152600c870154610100870152600d870154610120870152600e870154610140870152600f87015461016087015260108701546101808701526011909601546101a08601528e8416908701528e8952938652848820549651519054855160e060020a6370a08231028152908316948101949094529351919a50949592909416936370a082319360248084019491938390030190829087803b158015610eb657600080fd5b505af1158015610eca573d6000803e3d6000fd5b505050506040513d6020811015610ee057600080fd5b50511015610f5e5760408051818152601e818301526000805160206158e2833981519152606082015260806020820181905260249082015260008051602061594283398151915260a082015260e060020a6343524f570260c0820152905187916000805160206158a2833981519152919081900360e00190a261117d565b60c084015160608501516002546040805160e060020a6370a08231028152600160a060020a039283166004820152905191909216916370a082319160248083019260209291908290030181600087803b158015610fba57600080fd5b505af1158015610fce573d6000803e3d6000fd5b505050506040513d6020811015610fe457600080fd5b505110156110665760408051818152601e818301526000805160206158e2833981519152606082015260806020820181905260299082015260008051602061596283398151915260a0820152600080516020615a0283398151915260c0820152905187916000805160206158a2833981519152919081900360e00190a261117d565b836101000151421115611106576101a08401516000908152600d60205260409020805460ff1916600117905561109b846146db565b6101a08401516040805160208082526017908201527f4d4b45524e454c5f4455455f444154455f5041535345440000000000000000008183015290517f98e393d0760ecfe8e3907134d357e8a4fa5b37e364c3baeb0b059a98317638c49181900360600190a261117d565b6101a084015160408051818152601e818301526000805160206158e283398151915260608201526080602082018190526013908201527f4e4f5f414354494f4e5f504552464f524d45440000000000000000000000000060a082015290516000805160206158a28339815191529181900360c00190a25b505050505050565b600080600080600080600080600080600061119e61579a565b600860008e600019166000191681526020019081526020016000206101c060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016003820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016004820160a060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a0316815260200160038201548152602001600482015481525050815260200160098201548152602001600a8201548152602001600b8201548152602001600c8201548152602001600d8201548152602001600e8201548152602001600f8201548152602001601082015481526020016011820154600019166000191681525050905080600001518160200151826040015183606001518460a001518560c001518660e001518761010001518861014001518961016001518a61018001519b509b509b509b509b509b509b509b509b509b509b505091939597999b90929496989a50565b61140561579a565b604080513480825260208201838152369383018490526000936004359360243593849386933393600160e060020a03198a351693928a929190606082018484808284376040519201829003965090945050505050a46006546040805160e060020a639c14ee290281523360048201529051600160a060020a0390921691639c14ee29916024808201926020929091908290030181600087803b1580156114aa57600080fd5b505af11580156114be573d6000803e3d6000fd5b505050506040513d60208110156114d457600080fd5b5051151561151a576040805160e560020a62461bcd02815260206004820181905260248201526000805160206159e2833981519152604482015290519081900360640190fd5b60015474010000000000000000000000000000000000000000900460ff161561158d576040805160e560020a62461bcd02815260206004820152601960248201527f445353746f703a3a5f20464541545552455f53544f5050454400000000000000604482015290519081900360640190fd5b86600160a060020a03811615156115dc576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b6040805160c0818101909252611624918c90600690839083908082843750506040805161010081810190925293508e92506008915083908390808284375061485b9350505050565b9450611665856101a0015188888080601f01602080910402602001604051908101604052809392919081815260200183838082843750614950945050505050565b6080860151600160a060020a03808b16604090920191909152602087015191955080861691161461170b576101a0850151604080518181526014818301526000805160206159a283398151915260608201526080602082018190526018908201527f5349474e45525f4e4f545f4f524445525f43524541544f52000000000000000060a082015290516000805160206158a28339815191529181900360c00190a2612288565b6101a085015160009081526009602052604090205460ff16156117a2576101a08501516040805181815260148183018190526000805160206159a283398151915260608301526080602083018190528201527f4f524445525f414c52454144595f45584953545300000000000000000000000060a082015290516000805160206158a28339815191529181900360c00190a2612288565b6003548551604080517f25ca4c9c000000000000000000000000000000000000000000000000000000008152600160a060020a039283166004820152905191909216916325ca4c9c9160248083019260209291908290030181600087803b15801561180c57600080fd5b505af1158015611820573d6000803e3d6000fd5b505050506040513d602081101561183657600080fd5b505115156118b9576101a0850151604080518181526014818301526000805160206159a283398151915260608201526080602082018190526015908201527f494e56414c49445f4f524445525f4143434f554e54000000000000000000000060a082015290516000805160206158a28339815191529181900360c00190a2612288565b8460000151600160a060020a0316634209fff1856040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561191857600080fd5b505af115801561192c573d6000803e3d6000fd5b505050506040513d602081101561194257600080fd5b505115156119eb576101a0850151604080518181526014818301526000805160206159a283398151915260608201526080602082018190526022908201527f5349474e45525f4e4f545f415554484f52495a45445f574954485f4143434f5560a08201527f4e5400000000000000000000000000000000000000000000000000000000000060c082015290516000805160206158a28339815191529181900360e00190a2612288565b6119f485614972565b1515611a75576101a0850151604080518181526014818301526000805160206159a283398151915260608201526080602082018190526018908201527f494e56414c49445f4f524445525f504152414d4554455253000000000000000060a082015290516000805160206158a28339815191529181900360c00190a2612288565b8460c001518560600151600160a060020a03166370a0823187600001516040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b158015611add57600080fd5b505af1158015611af1573d6000803e3d6000fd5b505050506040513d6020811015611b0757600080fd5b50511015611bb0576101a0850151604080518181526014818301526000805160206159a283398151915260608201526080602082018190526022908201527f494e53554646494349454e545f434f4c4c41544552414c5f494e5f4143434f5560a08201527f4e5400000000000000000000000000000000000000000000000000000000000060c082015290516000805160206158a28339815191529181900360e00190a2612288565b8460a001518560400151600160a060020a03166370a08231600460009054906101000a9004600160a060020a0316600160a060020a031663e2fdcc176040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015611c1b57600080fd5b505af1158015611c2f573d6000803e3d6000fd5b505050506040513d6020811015611c4557600080fd5b50516040805160e060020a63ffffffff8516028152600160a060020a0390921660048301525160248083019260209291908290030181600087803b158015611c8c57600080fd5b505af1158015611ca0573d6000803e3d6000fd5b505050506040513d6020811015611cb657600080fd5b50511015611d39576101a0850151604080518181526014818301526000805160206159a28339815191526060820152608060208201819052601d908201527f494e53554646494349454e545f46554e44535f494e5f5245534552564500000060a082015290516000805160206158a28339815191529181900360c00190a2612288565b611d558586604001518760800151600001518860a00151614a95565b1515611dd6576101a0850151604080518181526014818301526000805160206159a283398151915260608201526080602082018190526012908201527f54524144455f4e4f545f4645415349424c45000000000000000000000000000060a082015290516000805160206158a28339815191529181900360c00190a2612288565b6007856101a0015190806001815401808255809150509060018203906000526020600020016000909192909190915090600019169055508460086000876101a001516000191660001916815260200190815260200160002060008201518160000160006101000a815481600160a060020a030219169083600160a060020a0316021790555060208201518160010160006101000a815481600160a060020a030219169083600160a060020a0316021790555060408201518160020160006101000a815481600160a060020a030219169083600160a060020a0316021790555060608201518160030160006101000a815481600160a060020a030219169083600160a060020a0316021790555060808201518160040160008201518160000160006101000a815481600160a060020a030219169083600160a060020a0316021790555060208201518160010160006101000a815481600160a060020a030219169083600160a060020a0316021790555060408201518160020160006101000a815481600160a060020a030219169083600160a060020a031602179055506060820151816003015560808201518160040155505060a0820151816009015560c082015181600a015560e082015181600b015561010082015181600c015561012082015181600d015561014082015181600e015561016082015181600f015561018082015181601001556101a08201518160110190600019169055905050600160096000876101a001516000191660001916815260200190815260200160002060006101000a81548160ff021916908315150217905550600a60008660000151600160a060020a0316600160a060020a03168152602001908152602001600020856101a001519080600181540180825580915050906001820390600052602060002001600090919290919091509060001916905550600260009054906101000a9004600160a060020a0316600160a060020a0316635e61e1c886600001518760600151600260009054906101000a9004600160a060020a03168960c001516040518563ffffffff1660e060020a0281526004018085600160a060020a0316600160a060020a0316815260200184600160a060020a0316600160a060020a0316815260200183600160a060020a0316600160a060020a03168152602001828152602001945050505050600060405180830381600087803b15801561215557600080fd5b505af1158015612169573d6000803e3d6000fd5b5050600480546040808a015160025460a08c015183517f8bfb07c9000000000000000000000000000000000000000000000000000000008152600160a060020a039384169681019690965290821660248601526044850152905191169350638bfb07c99250606480830192600092919082900301818387803b1580156121ee57600080fd5b505af1158015612202573d6000803e3d6000fd5b505050506122228586604001518760800151600001518860a00151614b48565b506101a0860180516000908152600b602090815260408083209490945591518082529083902054610100890151845191825292810192909252825190927fea0bf587ab60e35e1551a895f638f97223b5471e71aef9e3102dfe8ceb87dc01928290030190a25b50505050505050505050565b600354600160a060020a031681565b600a602052816000526040600020818154811015156122be57fe5b90600052602060002001600091509150505481565b60015474010000000000000000000000000000000000000000900460ff1681565b600654600160a060020a031681565b61230b61579a565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a46006546040805160e060020a639c14ee290281523360048201529051600160a060020a0390921691639c14ee29916024808201926020929091908290030181600087803b1580156123ac57600080fd5b505af11580156123c0573d6000803e3d6000fd5b505050506040513d60208110156123d657600080fd5b5051151561241c576040805160e560020a62461bcd02815260206004820181905260248201526000805160206159e2833981519152604482015290519081900360640190fd5b85600160a060020a038116151561246b576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b60008881526009602052604090205460ff1615156124ea576040805181815260208183018190526000805160206159228339815191526060830152608090820181905260149082015260008051602061598283398151915260a0820152905189916000805160206158a2833981519152919081900360c00190a2612b87565b6000888152600c602052604090205460ff1615612568576040805181815260208183018190526000805160206159228339815191526060830152608090820181905260189082015260008051602061584283398151915260a0820152905189916000805160206158a2833981519152919081900360c00190a2612b87565b6000888152600d602052604090205460ff16156125e6576040805181815260208183018190526000805160206159228339815191526060830152608090820181905260179082015260008051602061588283398151915260a0820152905189916000805160206158a2833981519152919081900360c00190a2612b87565b6008600089600019166000191681526020019081526020016000206101c060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016003820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016004820160a060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a0316815260200160038201548152602001600482015481525050815260200160098201548152602001600a8201548152602001600b8201548152602001600c8201548152602001600d8201548152602001600e8201548152602001600f8201548152602001601082015481526020016011820154600019166000191681525050935086846080015160400190600160a060020a03169081600160a060020a031681525050600b6000896000191660001916815260200190815260200160002054846080015160000151600160a060020a03166370a08231600260009054906101000a9004600160a060020a03166040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561289a57600080fd5b505af11580156128ae573d6000803e3d6000fd5b505050506040513d60208110156128c457600080fd5b50511015612943576040805181815260208183018190526000805160206159228339815191526060830152608090820181905260249082015260008051602061594283398151915260a082015260e060020a6343524f570260c0820152905189916000805160206158a2833981519152919081900360e00190a2612b87565b60c084015160608501516002546040805160e060020a6370a08231028152600160a060020a039283166004820152905191909216916370a082319160248083019260209291908290030181600087803b15801561299f57600080fd5b505af11580156129b3573d6000803e3d6000fd5b505050506040513d60208110156129c957600080fd5b50511015612a4c576040805181815260208183018190526000805160206159228339815191526060830152608090820181905260299082015260008051602061596283398151915260a0820152600080516020615a0283398151915260c0820152905189916000805160206158a2833981519152919081900360e00190a2612b87565b604080518082018252612a769186919089906002908390839080828437508b9350614c1092505050565b1515612b0f576101a08401516000908152600d60205260409020805460ff19166001179055612aa4846146db565b6101a08401516040805160208082526014908201527f4d4b45524e454c5f4f524445525f554e534146450000000000000000000000008183015290517f98e393d0760ecfe8e3907134d357e8a4fa5b37e364c3baeb0b059a98317638c49181900360600190a2612b87565b6101a0840151604080518181526020818301819052600080516020615922833981519152606083015260809082018190526013908201527f4e4f5f414354494f4e5f504552464f524d45440000000000000000000000000060a082015290516000805160206158a28339815191529181900360c00190a25b5050505050505050565b612ba733600035600160e060020a0319166145d2565b1515612beb576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b60008054600160a060020a031916600160a060020a03838116919091178083556040519116917f1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada491a250565b60606007805480602002602001604051908101604052809291908181526020018280548015612c8657602002820191906000526020600020905b81548152600190910190602001808311612c71575b5050505050905090565b60096020526000908152604090205460ff1681565b600154600160a060020a031681565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a4612d1b33600035600160e060020a0319166145d2565b1515612d5f576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b82600160a060020a0381161515612dae576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b505060058054600160a060020a031916600160a060020a03939093169290921790915550565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a4612e3b33600035600160e060020a0319166145d2565b1515612e7f576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b82600160a060020a0381161515612ece576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b505060048054600160a060020a031916600160a060020a03939093169290921790915550565b6000806000806000612f0461579a565b505050600093845250506008602081815260409384902084516101c0810186528154600160a060020a0390811682526001830154811682850152600283015481168288015260038301548116606080840191909152875160a08082018a5260048601548416825260058601548416968201968752600686015490931698810198895260078501549181019182529584015460808088019182528401879052600985015492840192909252600a84015460c0840152600b84015460e0840152600c840154610100840152600d840154610120840152600e840154610140840152600f84015461016084015260108401546101808401526011909301546101a090920191909152925191519451905192519195909350565b600780548290811061302857fe5b600091825260209091200154905081565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a46130a033600035600160e060020a0319166145d2565b15156130e4576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b82600160a060020a0381161515613133576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b505060038054600160a060020a031916600160a060020a03939093169290921790915550565b61316f33600035600160e060020a0319166145d2565b15156131b3576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a450506001805474ff000000000000000000000000000000000000000019169055565b600054600160a060020a031681565b61323d61579a565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a46006546040805160e060020a639c14ee290281523360048201529051600160a060020a0390921691639c14ee29916024808201926020929091908290030181600087803b1580156132de57600080fd5b505af11580156132f2573d6000803e3d6000fd5b505050506040513d602081101561330857600080fd5b5051151561334e576040805160e560020a62461bcd02815260206004820181905260248201526000805160206159e2833981519152604482015290519081900360640190fd5b85600160a060020a038116151561339d576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b60008881526009602052604090205460ff1615156134295760408051818152602281830152600080516020615902833981519152606082015260f260020a611a5d02608082015260a06020820181905260149082015260008051602061598283398151915260c0820152905189916000805160206158a2833981519152919081900360e00190a2612b87565b6000888152600c602052604090205460ff16156134b45760408051818152602281830152600080516020615902833981519152606082015260f260020a611a5d02608082015260a06020820181905260189082015260008051602061584283398151915260c0820152905189916000805160206158a2833981519152919081900360e00190a2612b87565b6000888152600d602052604090205460ff161561353f5760408051818152602281830152600080516020615902833981519152606082015260f260020a611a5d02608082015260a06020820181905260179082015260008051602061588283398151915260c0820152905189916000805160206158a2833981519152919081900360e00190a2612b87565b6008600089600019166000191681526020019081526020016000206101c060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016003820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016004820160a060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a0316815260200160038201548152602001600482015481525050815260200160098201548152602001600a8201548152602001600b8201548152602001600c8201548152602001600d8201548152602001600e8201548152602001600f8201548152602001601082015481526020016011820154600019166000191681525050935086846080015160400190600160a060020a03169081600160a060020a031681525050600b6000896000191660001916815260200190815260200160002054846080015160000151600160a060020a03166370a08231600260009054906101000a9004600160a060020a03166040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b1580156137f357600080fd5b505af1158015613807573d6000803e3d6000fd5b505050506040513d602081101561381d57600080fd5b505110156138aa5760408051818152602281830152600080516020615902833981519152606082015260f260020a611a5d02608082015260a06020820181905260249082015260008051602061594283398151915260c082015260e060020a6343524f570260e0820152905189916000805160206158a283398151915291908190036101000190a2612b87565b60c084015160608501516002546040805160e060020a6370a08231028152600160a060020a039283166004820152905191909216916370a082319160248083019260209291908290030181600087803b15801561390657600080fd5b505af115801561391a573d6000803e3d6000fd5b505050506040513d602081101561393057600080fd5b505110156139c15760408051818152602281830152600080516020615902833981519152606082015260f260020a611a5d02608082015260a06020820181905260299082015260008051602061596283398151915260c0820152600080516020615a0283398151915260e0820152905189916000805160206158a283398151915291908190036101000190a2612b87565b6040805180820182526139eb9186919089906002908390839080828437508b9350614d0692505050565b15613a4c576101a08401516000908152600c60205260409020805460ff19166001179055613a18846146db565b6101a08401516040517fc614d231c29c73ae067f16cd5460d0050c98401008b3cce99b3abb37302e548590600090a2612b87565b6101a084015160408051818152602281830152600080516020615902833981519152606082015260f260020a611a5d02608082015260a0602082018190526013908201527f4e4f5f414354494f4e5f504552464f524d45440000000000000000000000000060c082015290516000805160206158a28339815191529181900360e00190a25050505050505050565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a4613b4133600035600160e060020a0319166145d2565b1515613b85576040805160e560020a62461bcd02815260206004820152601f6024820152600080516020615862833981519152604482015290519081900360640190fd5b82600160a060020a0381161515613bd4576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b505060028054600160a060020a031916600160a060020a03939093169290921790915550565b6008602081815260009283526040928390208054600182015460028301546003840154875160a0810189526004860154600160a060020a03908116825260058701548116978201979097526006860154871698810198909852600785015460608901529584015460808801526009840154600a850154600b860154600c870154600d880154600e890154600f8a015460108b01546011909b0154998c169d988c169c978c169b9097169997989597949693959294919390929091908e565b600454600160a060020a031681565b600254600160a060020a031681565b600080613ce161579a565b60408051348082526020820183815236938301849052600435936024359384938693339360008035600160e060020a031916949092606082018484808284376040519201829003965090945050505050a46006546040805160e060020a639c14ee290281523360048201529051600160a060020a0390921691639c14ee29916024808201926020929091908290030181600087803b158015613d8257600080fd5b505af1158015613d96573d6000803e3d6000fd5b505050506040513d6020811015613dac57600080fd5b50511515613df2576040805160e560020a62461bcd02815260206004820181905260248201526000805160206159e2833981519152604482015290519081900360640190fd5b87600160a060020a0381161515613e41576040805160e560020a62461bcd02815260206004820152601860248201526000805160206159c2833981519152604482015290519081900360640190fd5b60008a81526009602052604090205460ff161515613ebf57604080518181526017818301526000805160206158c2833981519152606082015260806020820181905260149082015260008051602061598283398151915260a082015290518b916000805160206158a2833981519152919081900360c00190a2612288565b60008a8152600c602052604090205460ff1615613f3c57604080518181526017818301526000805160206158c2833981519152606082015260806020820181905260189082015260008051602061584283398151915260a082015290518b916000805160206158a2833981519152919081900360c00190a2612288565b60008a8152600d602052604090205460ff1615613fb8576040805181815260178183018190526000805160206158c2833981519152606083015260806020830181905282015260008051602061588283398151915260a082015290518b916000805160206158a2833981519152919081900360c00190a2612288565b613fc18a614de3565b9550613ffd8689898080601f01602080910402602001604051908101604052809392919081815260200183838082843750614950945050505050565b9450600860008b600019166000191681526020019081526020016000206101c060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016003820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016004820160a060405190810160405290816000820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016001820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a031681526020016002820160009054906101000a9004600160a060020a0316600160a060020a0316600160a060020a0316815260200160038201548152602001600482015481525050815260200160098201548152602001600a8201548152602001600b8201548152602001600c8201548152602001600d8201548152602001600e8201548152602001600f8201548152602001601082015481526020016011820154600019166000191681525050935088846080015160400190600160a060020a03169081600160a060020a0316815250508360000151600160a060020a0316634209fff1866040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561427e57600080fd5b505af1158015614292573d6000803e3d6000fd5b505050506040513d60208110156142a857600080fd5b5051151561434e57604080518181526017818301526000805160206158c283398151915260608201526080602082018190526022908201527f5349474e45525f4e4f545f415554484f52495a45445f574954485f4143434f5560a08201527f4e5400000000000000000000000000000000000000000000000000000000000060c082015290518b916000805160206158a2833981519152919081900360e00190a2612288565b60008a8152600b6020908152604080832054608088015151600254835160e060020a6370a08231028152600160a060020a039182166004820152935192959116936370a08231936024808201949293918390030190829087803b1580156143b457600080fd5b505af11580156143c8573d6000803e3d6000fd5b505050506040513d60208110156143de57600080fd5b5051101561445c57604080518181526017818301526000805160206158c2833981519152606082015260806020820181905260249082015260008051602061594283398151915260a082015260e060020a6343524f570260c082015290518b916000805160206158a2833981519152919081900360e00190a2612288565b60c084015160608501516002546040805160e060020a6370a08231028152600160a060020a039283166004820152905191909216916370a082319160248083019260209291908290030181600087803b1580156144b857600080fd5b505af11580156144cc573d6000803e3d6000fd5b505050506040513d60208110156144e257600080fd5b5051101561456457604080518181526017818301526000805160206158c2833981519152606082015260806020820181905260299082015260008051602061596283398151915260a0820152600080516020615a0283398151915260c082015290518b916000805160206158a2833981519152919081900360e00190a2612288565b6101a08401516000908152600c60205260409020805460ff1916600117905561458c846146db565b6040518a907f6cc69d7894fbf109ad278f7e331e91f734cd486332ee4e1eb3625bb2538eea4990600090a250505050505050505050565b600554600160a060020a031681565b6000600160a060020a0383163014156145ed575060016146d5565b600154600160a060020a038481169116141561460b575060016146d5565b600054600160a060020a03161515614625575060006146d5565b60008054604080517fb7009613000000000000000000000000000000000000000000000000000000008152600160a060020a038781166004830152306024830152600160e060020a0319871660448301529151919092169263b700961392606480820193602093909283900390910190829087803b1580156146a657600080fd5b505af11580156146ba573d6000803e3d6000fd5b505050506040513d60208110156146d057600080fd5b505190505b92915050565b600080600080600080600080600080600b60008c6101a001516000191660001916815260200190815260200160002054995061471f8b60a001518c60e00151614ea1565b9850614730898c6101600151614ea1565b9750600096506000955060009450600093506000925060009150600090506147668b8c60800151600001518d604001518d614b48565b5096508787106147a15761477a8789614eb1565b92508a6101600151905061479c8b8a8d60e0015160008f60c001518887614ec1565b61484e565b6147ab8888614eb1565b94508a60400151600160a060020a03168b60600151600160a060020a031614156147f557849550848b60c001511015156147f0576147ed8b60c0015186614eb1565b93505b614814565b61480e8b8c606001518d604001518e60c001518961524e565b90965093505b848610614838578a6101600151905061479c8b8a8d60e00151600088600087614ec1565b6148428787614ea1565b915061484e8b8361531e565b5050505050505050505050565b61486361579a565b61486b615813565b61487361579a565b608085015160a086015160c086015160e0870151614893939291906153b8565b604080516101c0810182528751600160a060020a0390811682526020808a0151821681840152898401518216838501526060808b01519092168284015260808301859052885160a084015288015160c08301529187015160e08201529086015191935090610100820190614908904290614ea1565b81526060808701516020830152608080880151604084015260a08089015192840192909252429083015260009101529050614942816153fa565b6101a0820152949350505050565b600061496b8261495f8561548a565b9063ffffffff61550116565b9392505050565b8051600090600160a060020a0316158061499757506020820151600160a060020a0316155b806149ad57506040820151600160a060020a0316155b806149c357506060820151600160a060020a0316155b806149dd5750608082015160200151600160a060020a0316155b806149f45750608082015151600160a060020a0316155b80614a1c57508160400151600160a060020a0316826080015160000151600160a060020a0316145b80614a365750608082015160400151600160a060020a0316155b80614a43575060a0820151155b80614a50575060c0820151155b80614a5d575060e0820151155b80614a72575081610180015182610100015111155b80614a805750610140820151155b15614a8d57506000610a6d565b506001919050565b608084015160409081015181517f5d0b4e5c000000000000000000000000000000000000000000000000000000008152600160a060020a0386811660048301528581166024830152604482018590529251600093831691635d0b4e5c91606480830192602092919082900301818887803b158015614b1257600080fd5b505af1158015614b26573d6000803e3d6000fd5b505050506040513d6020811015614b3c57600080fd5b50519695505050505050565b608084015160409081015160025482517f17fd9cc5000000000000000000000000000000000000000000000000000000008152600160a060020a039182166004820152868216602482015285821660448201526064810185905283516000948594938416926317fd9cc5926084808301939282900301818887803b158015614bcf57600080fd5b505af1158015614be3573d6000803e3d6000fd5b505050506040513d6040811015614bf957600080fd5b508051602090910151909890975095505050505050565b81516020808401516101a08601516000908152600b909252604082205460a087015160e088015193949385918291829182918291614c5d91614c529190614ea1565b8d6101600151614ea1565b9450614c7e614c708d60c001518a6155d6565b670de0b6b3a76400006155fe565b9350614c8d614c7087896155d6565b9250614ca0614c708d60a001518c6155d6565b9150614cb7614c708d6080015160800151866155d6565b905082614cc48684614ea1565b10158015614ce4575080614ce1614cdb8785614ea1565b85614eb1565b10155b15614cf25760009850614cf7565b600198505b50505050505050509392505050565b600080600080600080600089608001516060015160001415614d2b5760009650614dd6565b6020808a01516101a08c01516000908152600b90925260409091205460a08c015160e08d0151929850909650614d7091614d659190614ea1565b8b6101600151614ea1565b9350614d7f614c7086886155d6565b9250614d9a614c708b60a001518c60800151606001516155d6565b9150614dad614c708b60a001518a6155d6565b9050614dc2614dbc8584614ea1565b82614ea1565b8310614dd15760019650614dd6565b600096505b5050505050509392505050565b604080516c010000000000000000000000003002602080830191909152603482018490527f43414e43454c5f4d4b45524e454c5f4f524445520000000000000000000000006054830152825160488184030181526068909201928390528151600093918291908401908083835b60208310614e6f5780518252601f199092019160209182019101614e50565b5181516020939093036101000a6000190180199091169216919091179052604051920182900390912095945050505050565b808201828110156146d557600080fd5b808203828111156146d557600080fd5b60008281831115614f4b576002546040808b0151600554825160e360020a6317d57599028152600160a060020a039283166004820152908216602482015260448101879052915192169163beabacc89160648082019260009290919082900301818387803b158015614f3257600080fd5b505af1158015614f46573d6000803e3d6000fd5b505050505b600480546040808c015160025482517f106689a5000000000000000000000000000000000000000000000000000000008152600160a060020a039283169581019590955281166024850152604484018c9052606484018b9052608484018a9052905191169163106689a59160a480830192600092919082900301818387803b158015614fd657600080fd5b505af1158015614fea573d6000803e3d6000fd5b5050505060008511156150765760025460608a01518a516040805160e360020a6317d57599028152600160a060020a03938416600482015291831660248301526044820189905251919092169163beabacc891606480830192600092919082900301818387803b15801561505d57600080fd5b505af1158015615071573d6000803e3d6000fd5b505050505b60008411156151e8578860400151600160a060020a0316896080015160200151600160a060020a031614806150c057506150be898a604001518b608001516020015187614a95565b155b15615147576002546040808b01518b51825160e360020a6317d57599028152600160a060020a039283166004820152908216602482015260448101889052915192169163beabacc89160648082019260009290919082900301818387803b15801561512a57600080fd5b505af115801561513e573d6000803e3d6000fd5b505050506151e8565b61515f898a604001518b608001516020015187614b48565b5060025460808b0151602001518b516040805160e360020a6317d57599028152600160a060020a0393841660048201529183166024830152604482018590525193955091169163beabacc89160648082019260009290919082900301818387803b1580156151cc57600080fd5b505af11580156151e0573d6000803e3d6000fd5b505050508190505b6101a0890151604080518a8152602081018a9052808201899052606081018890526080810184905260a0810186905290517fd5620126c5a9c2d177d7302570339d14ed881b5f6d3fdb8f63bd6fa00601bc6b9181900360c00190a2505050505050505050565b608085015160409081015160025482517fc83ec89d000000000000000000000000000000000000000000000000000000008152600160a060020a039182166004820152878216602482015286821660448201526064810186905260848101859052835160009485949384169263c83ec89d9260a4808301939282900301818887803b1580156152dc57600080fd5b505af11580156152f0573d6000803e3d6000fd5b505050506040513d604081101561530657600080fd5b50805160209091015190999098509650505050505050565b60006153328360a001518460e00151614ea1565b905080821061535e5761535983828560e0015160008060006153548989614eb1565b614ec1565b6153b3565b808210801561537157508260a001518210155b15615394576153598383615389858760a00151614eb1565b600080600080614ec1565b6153b3838360006153a98760a0015187614eb1565b6000806000614ec1565b505050565b6153c0615813565b506040805160a081018252600160a060020a0395861681529390941660208401526000938301939093526060820152608081019190915290565b60003061540683615613565b61540f846156ef565b604080516c01000000000000000000000000600160a060020a0390951694909402602080860191909152603485019390935260548085019290925280518085039092018252607490930192839052805190929182919084019080838360208310614e6f5780518252601f199092019160209182019101614e50565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c80830185905283518084039091018152605c9092019283905281516000939182919084019080838360208310614e6f5780518252601f199092019160209182019101614e50565b6000806000808451604114151561551b57600093506155cd565b50505060208201516040830151606084015160001a601b60ff8216101561554057601b015b8060ff16601b1415801561555857508060ff16601c14155b1561556657600093506155cd565b60408051600080825260208083018085528a905260ff8516838501526060830187905260808301869052925160019360a0808501949193601f19840193928390039091019190865af11580156155c0573d6000803e3d6000fd5b5050506020604051035193505b50505092915050565b60008115806155f35750508082028282828115156155f057fe5b04145b15156146d557600080fd5b6000818381151561560b57fe5b049392505050565b8051604080830151606084015160a085015160c086015160e08701516101208801516101408901516101608a015188516c01000000000000000000000000308102602080840191909152600160a060020a039c8d1682026034840152998c16810260488301529a909716909902605c8701526070860194909452609085019290925260b084015260d083015260f0820152610110808201949094528251808203909401845261013001918290528251600093929182919084019080838360208310614e6f5780518252601f199092019160209182019101614e50565b608080820151805160208083015160608401519390940151610140860151604080516c0100000000000000000000000030810282870152600160a060020a0396871681026034830152959097169094026048870152605c860194909452607c850152609c808501939093528151808503909301835260bc90930190819052815160009382919084019080838360208310614e6f5780518252601f199092019160209182019101614e50565b60408051610240810182526000808252602082018190529181018290526060810191909152608081016157cb615813565b81526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600080191681525090565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091529056004f524445525f414c52454144595f4c49515549444154454400000000000000004453417574683a3a5f2053454e4445525f4e4f545f415554484f52495a4544004f524445525f414c52454144595f44454641554c544544000000000000000000db0b341562703a7cbd47efa0b024b1ed2e3c68e2d313e46d276db9a46d8a6f804d4b65726e656c3a3a6c69717569646174654f726465720000000000000000004d4b65726e656c3a3a70726f636573735472616465466f7245787069727900004d4b65726e656c3a3a70726f636573735472616465466f7253746f7050726f664d4b65726e656c3a3a70726f636573735472616465466f7253746f704c6f7373494e53554646494349454e545f54524144455f42414c414e43455f494e5f4553494e53554646494349454e545f434f4c4c41544552414c5f42414c414e43455f4f524445525f444f45535f4e4f545f45584953540000000000000000000000004d4b65726e656c3a3a6372656174654f726465720000000000000000000000005574696c733a3a5f20494e56414c49445f4144445245535300000000000000004d4b65726e656c3a3a5f20494e56414c49445f41444d494e5f4143434f554e54494e5f455343524f570000000000000000000000000000000000000000000000a165627a7a72305820b978523cfaf0225ad9aaac828feaa290019983b18ae0961590f65ff6838948120029

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

000000000000000000000000af38668f4719ecf9452dc0300be3f6c83cbf37210000000000000000000000004e9d7f37eadc6fef64b5f5dccc4deb622466767700000000000000000000000064d14595152b430cf6940da15c6e39545c7c5b7e0000000000000000000000003e990e787a88cd4426fb3af9b90dd1d951e2cb87000000000000000000000000431f429035a1e3059d5c6a9a83208c6d3143d925

-----Decoded View---------------
Arg [0] : _escrow (address): 0xaf38668F4719Ecf9452DC0300BE3f6c83Cbf3721
Arg [1] : _accountFactory (address): 0x4E9D7f37EADc6fef64B5F5DCcC4deB6224667677
Arg [2] : _reserve (address): 0x64d14595152B430CF6940Da15C6e39545c7c5B7e
Arg [3] : _feeWallet (address): 0x3E990e787a88cD4426fB3AF9B90DD1D951E2cb87
Arg [4] : _config (address): 0x431F429035a1e3059d5c6a9a83208c6D3143D925

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000af38668f4719ecf9452dc0300be3f6c83cbf3721
Arg [1] : 0000000000000000000000004e9d7f37eadc6fef64b5f5dccc4deb6224667677
Arg [2] : 00000000000000000000000064d14595152b430cf6940da15c6e39545c7c5b7e
Arg [3] : 0000000000000000000000003e990e787a88cd4426fb3af9b90dd1d951e2cb87
Arg [4] : 000000000000000000000000431f429035a1e3059d5c6a9a83208c6d3143d925


Swarm Source

bzzr://b978523cfaf0225ad9aaac828feaa290019983b18ae0961590f65ff683894812

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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