Contract Address Details

0x1DC04BDc205A70d99773812c865d3301b61869d1

Contract Name
HomeBridgeErcToErc
Creator
0xd42726–40d954 at 0xd002e0–ce6227
Balance
0 VLX
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
69799772
Contract name:
HomeBridgeErcToErc




Optimization enabled
true
Compiler version
v0.4.24+commit.e67f0147




Optimization runs
200
EVM Version
byzantium




Verified at
2021-09-03T20:17:00.790652Z

Contract source code

// File: contracts/interfaces/IBridgeValidators.sol

pragma solidity 0.4.24;

interface IBridgeValidators {
    function isValidator(address _validator) external view returns (bool);
    function requiredSignatures() external view returns (uint256);
    function owner() external view returns (address);
}

// File: contracts/libraries/Message.sol

pragma solidity 0.4.24;


library Message {
    function addressArrayContains(address[] array, address value) internal pure returns (bool) {
        for (uint256 i = 0; i < array.length; i++) {
            if (array[i] == value) {
                return true;
            }
        }
        return false;
    }
    // layout of message :: bytes:
    // offset  0: 32 bytes :: uint256 - message length
    // offset 32: 20 bytes :: address - recipient address
    // offset 52: 32 bytes :: uint256 - value
    // offset 84: 32 bytes :: bytes32 - transaction hash
    // offset 104: 20 bytes :: address - contract address to prevent double spending

    // mload always reads 32 bytes.
    // so we can and have to start reading recipient at offset 20 instead of 32.
    // if we were to read at 32 the address would contain part of value and be corrupted.
    // when reading from offset 20 mload will read 12 bytes (most of them zeros) followed
    // by the 20 recipient address bytes and correctly convert it into an address.
    // this saves some storage/gas over the alternative solution
    // which is padding address to 32 bytes and reading recipient at offset 32.
    // for more details see discussion in:
    // https://github.com/paritytech/parity-bridge/issues/61
    function parseMessage(bytes message)
        internal
        pure
        returns (address recipient, uint256 amount, bytes32 txHash, address contractAddress)
    {
        require(isMessageValid(message));
        assembly {
            recipient := mload(add(message, 20))
            amount := mload(add(message, 52))
            txHash := mload(add(message, 84))
            contractAddress := mload(add(message, 104))
        }
    }

    function isMessageValid(bytes _msg) internal pure returns (bool) {
        return _msg.length == requiredMessageLength();
    }

    function requiredMessageLength() internal pure returns (uint256) {
        return 104;
    }

    function recoverAddressFromSignedMessage(bytes signature, bytes message, bool isAMBMessage)
        internal
        pure
        returns (address)
    {
        require(signature.length == 65);
        bytes32 r;
        bytes32 s;
        bytes1 v;

        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := mload(add(signature, 0x60))
        }
        require(uint8(v) == 27 || uint8(v) == 28);
        require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0);

        return ecrecover(hashMessage(message, isAMBMessage), uint8(v), r, s);
    }

    function hashMessage(bytes message, bool isAMBMessage) internal pure returns (bytes32) {
        bytes memory prefix = "\x19Ethereum Signed Message:\n";
        if (isAMBMessage) {
            return keccak256(abi.encodePacked(prefix, uintToString(message.length), message));
        } else {
            string memory msgLength = "104";
            return keccak256(abi.encodePacked(prefix, msgLength, message));
        }
    }

    /**
    * @dev Validates provided signatures, only first requiredSignatures() number
    * of signatures are going to be validated, these signatures should be from different validators.
    * @param _message bytes message used to generate signatures
    * @param _signatures bytes blob with signatures to be validated.
    * First byte X is a number of signatures in a blob,
    * next X bytes are v components of signatures,
    * next 32 * X bytes are r components of signatures,
    * next 32 * X bytes are s components of signatures.
    * @param _validatorContract contract, which conforms to the IBridgeValidators interface,
    * where info about current validators and required signatures is stored.
    * @param isAMBMessage true if _message is an AMB message with arbitrary length.
    */
    function hasEnoughValidSignatures(
        bytes _message,
        bytes _signatures,
        IBridgeValidators _validatorContract,
        bool isAMBMessage
    ) internal view {
        require(isAMBMessage || isMessageValid(_message));
        uint256 requiredSignatures = _validatorContract.requiredSignatures();
        uint256 amount;
        assembly {
            amount := and(mload(add(_signatures, 1)), 0xff)
        }
        require(amount >= requiredSignatures);
        bytes32 hash = hashMessage(_message, isAMBMessage);
        address[] memory encounteredAddresses = new address[](requiredSignatures);

        for (uint256 i = 0; i < requiredSignatures; i++) {
            uint8 v;
            bytes32 r;
            bytes32 s;
            uint256 posr = 33 + amount + 32 * i;
            uint256 poss = posr + 32 * amount;
            assembly {
                v := mload(add(_signatures, add(2, i)))
                r := mload(add(_signatures, posr))
                s := mload(add(_signatures, poss))
            }

            address recoveredAddress = ecrecover(hash, v, r, s);
            require(_validatorContract.isValidator(recoveredAddress));
            require(!addressArrayContains(encounteredAddresses, recoveredAddress));
            encounteredAddresses[i] = recoveredAddress;
        }
    }

    function uintToString(uint256 i) internal pure returns (string) {
        if (i == 0) return "0";
        uint256 j = i;
        uint256 length;
        while (j != 0) {
            length++;
            j /= 10;
        }
        bytes memory bstr = new bytes(length);
        uint256 k = length - 1;
        while (i != 0) {
            bstr[k--] = bytes1(48 + (i % 10));
            i /= 10;
        }
        return string(bstr);
    }
}

// File: contracts/upgradeability/EternalStorage.sol

pragma solidity 0.4.24;

/**
 * @title EternalStorage
 * @dev This contract holds all the necessary state variables to carry out the storage of any contract.
 */
contract EternalStorage {
    mapping(bytes32 => uint256) internal uintStorage;
    mapping(bytes32 => string) internal stringStorage;
    mapping(bytes32 => address) internal addressStorage;
    mapping(bytes32 => bytes) internal bytesStorage;
    mapping(bytes32 => bool) internal boolStorage;
    mapping(bytes32 => int256) internal intStorage;

}

// File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol

pragma solidity ^0.4.24;


/**
 * @title ERC20Basic
 * @dev Simpler version of ERC20 interface
 * See https://github.com/ethereum/EIPs/issues/179
 */
contract ERC20Basic {
  function totalSupply() public view returns (uint256);
  function balanceOf(address _who) public view returns (uint256);
  function transfer(address _to, uint256 _value) public returns (bool);
  event Transfer(address indexed from, address indexed to, uint256 value);
}

// File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol

pragma solidity ^0.4.24;



/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
contract ERC20 is ERC20Basic {
  function allowance(address _owner, address _spender)
    public view returns (uint256);

  function transferFrom(address _from, address _to, uint256 _value)
    public returns (bool);

  function approve(address _spender, uint256 _value) public returns (bool);
  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 value
  );
}

// File: contracts/interfaces/ERC677.sol

pragma solidity 0.4.24;


contract ERC677 is ERC20 {
    event Transfer(address indexed from, address indexed to, uint256 value, bytes data);

    function transferAndCall(address, uint256, bytes) external returns (bool);

    function increaseAllowance(address spender, uint256 addedValue) public returns (bool);
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool);
}

contract LegacyERC20 {
    function transfer(address _spender, uint256 _value) public; // returns (bool);
    function transferFrom(address _owner, address _spender, uint256 _value) public; // returns (bool);
}

// File: contracts/interfaces/IBurnableMintableERC677Token.sol

pragma solidity 0.4.24;


contract IBurnableMintableERC677Token is ERC677 {
    function mint(address _to, uint256 _amount) public returns (bool);
    function burn(uint256 _value) public;
    function claimTokens(address _token, address _to) external;
}

// File: openzeppelin-solidity/contracts/math/SafeMath.sol

pragma solidity ^0.4.24;


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

  /**
  * @dev Multiplies two numbers, throws on overflow.
  */
  function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
    // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
    // benefit is lost if 'b' is also tested.
    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
    if (_a == 0) {
      return 0;
    }

    c = _a * _b;
    assert(c / _a == _b);
    return c;
  }

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

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

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

// File: contracts/upgradeable_contracts/ValidatorStorage.sol

pragma solidity 0.4.24;

contract ValidatorStorage {
    bytes32 internal constant VALIDATOR_CONTRACT = 0x5a74bb7e202fb8e4bf311841c7d64ec19df195fee77d7e7ae749b27921b6ddfe; // keccak256(abi.encodePacked("validatorContract"))
}

// File: contracts/upgradeable_contracts/Validatable.sol

pragma solidity 0.4.24;




contract Validatable is EternalStorage, ValidatorStorage {
    function validatorContract() public view returns (IBridgeValidators) {
        return IBridgeValidators(addressStorage[VALIDATOR_CONTRACT]);
    }

    modifier onlyValidator() {
        require(validatorContract().isValidator(msg.sender));
        /* solcov ignore next */
        _;
    }

    function requiredSignatures() public view returns (uint256) {
        return validatorContract().requiredSignatures();
    }

}

// File: contracts/interfaces/IUpgradeabilityOwnerStorage.sol

pragma solidity 0.4.24;

interface IUpgradeabilityOwnerStorage {
    function upgradeabilityOwner() external view returns (address);
}

// File: contracts/upgradeable_contracts/Upgradeable.sol

pragma solidity 0.4.24;


contract Upgradeable {
    // Avoid using onlyUpgradeabilityOwner name to prevent issues with implementation from proxy contract
    modifier onlyIfUpgradeabilityOwner() {
        require(msg.sender == IUpgradeabilityOwnerStorage(this).upgradeabilityOwner());
        /* solcov ignore next */
        _;
    }
}

// File: contracts/upgradeable_contracts/Initializable.sol

pragma solidity 0.4.24;


contract Initializable is EternalStorage {
    bytes32 internal constant INITIALIZED = 0x0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba; // keccak256(abi.encodePacked("isInitialized"))

    function setInitialize() internal {
        boolStorage[INITIALIZED] = true;
    }

    function isInitialized() public view returns (bool) {
        return boolStorage[INITIALIZED];
    }
}

// File: contracts/upgradeable_contracts/InitializableBridge.sol

pragma solidity 0.4.24;


contract InitializableBridge is Initializable {
    bytes32 internal constant DEPLOYED_AT_BLOCK = 0xb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b0; // keccak256(abi.encodePacked("deployedAtBlock"))

    function deployedAtBlock() external view returns (uint256) {
        return uintStorage[DEPLOYED_AT_BLOCK];
    }
}

// File: openzeppelin-solidity/contracts/AddressUtils.sol

pragma solidity ^0.4.24;


/**
 * Utility library of inline functions on addresses
 */
library AddressUtils {

  /**
   * Returns whether the target address is a contract
   * @dev This function will return false if invoked during the constructor of a contract,
   * as the code is not actually created until after the constructor finishes.
   * @param _addr address to check
   * @return whether the target address is a contract
   */
  function isContract(address _addr) internal view returns (bool) {
    uint256 size;
    // XXX Currently there is no better way to check if there is a contract in an address
    // than to check the size of the code at that address.
    // See https://ethereum.stackexchange.com/a/14016/36603
    // for more details about how this works.
    // TODO Check this again before the Serenity release, because all addresses will be
    // contracts then.
    // solium-disable-next-line security/no-inline-assembly
    assembly { size := extcodesize(_addr) }
    return size > 0;
  }

}

// File: contracts/upgradeable_contracts/Ownable.sol

pragma solidity 0.4.24;



/**
 * @title Ownable
 * @dev This contract has an owner address providing basic authorization control
 */
contract Ownable is EternalStorage {
    bytes4 internal constant UPGRADEABILITY_OWNER = 0x6fde8202; // upgradeabilityOwner()

    /**
    * @dev Event to show ownership has been transferred
    * @param previousOwner representing the address of the previous owner
    * @param newOwner representing the address of the new owner
    */
    event OwnershipTransferred(address previousOwner, address newOwner);

    /**
    * @dev Throws if called by any account other than the owner.
    */
    modifier onlyOwner() {
        require(msg.sender == owner());
        /* solcov ignore next */
        _;
    }

    /**
    * @dev Throws if called by any account other than contract itself or owner.
    */
    modifier onlyRelevantSender() {
        // proxy owner if used through proxy, address(0) otherwise
        require(
            !address(this).call(abi.encodeWithSelector(UPGRADEABILITY_OWNER)) || // covers usage without calling through storage proxy
                msg.sender == IUpgradeabilityOwnerStorage(this).upgradeabilityOwner() || // covers usage through regular proxy calls
                msg.sender == address(this) // covers calls through upgradeAndCall proxy method
        );
        /* solcov ignore next */
        _;
    }

    bytes32 internal constant OWNER = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0; // keccak256(abi.encodePacked("owner"))

    /**
    * @dev Tells the address of the owner
    * @return the address of the owner
    */
    function owner() public view returns (address) {
        return addressStorage[OWNER];
    }

    /**
    * @dev Allows the current owner to transfer control of the contract to a newOwner.
    * @param newOwner the address to transfer ownership to.
    */
    function transferOwnership(address newOwner) external onlyOwner {
        _setOwner(newOwner);
    }

    /**
    * @dev Sets a new owner address
    */
    function _setOwner(address newOwner) internal {
        require(newOwner != address(0));
        emit OwnershipTransferred(owner(), newOwner);
        addressStorage[OWNER] = newOwner;
    }
}

// File: contracts/upgradeable_contracts/Sacrifice.sol

pragma solidity 0.4.24;

contract Sacrifice {
    constructor(address _recipient) public payable {
        selfdestruct(_recipient);
    }
}

// File: contracts/libraries/Address.sol

pragma solidity 0.4.24;


/**
 * @title Address
 * @dev Helper methods for Address type.
 */
library Address {
    /**
    * @dev Try to send native tokens to the address. If it fails, it will force the transfer by creating a selfdestruct contract
    * @param _receiver address that will receive the native tokens
    * @param _value the amount of native tokens to send
    */
    function safeSendValue(address _receiver, uint256 _value) internal {
        if (!_receiver.send(_value)) {
            (new Sacrifice).value(_value)(_receiver);
        }
    }
}

// File: contracts/libraries/SafeERC20.sol

pragma solidity 0.4.24;



/**
 * @title SafeERC20
 * @dev Helper methods for safe token transfers.
 * Functions perform additional checks to be sure that token transfer really happened.
 */
library SafeERC20 {
    using SafeMath for uint256;

    /**
    * @dev Same as ERC20.transfer(address,uint256) but with extra consistency checks.
    * @param _token address of the token contract
    * @param _to address of the receiver
    * @param _value amount of tokens to send
    */
    function safeTransfer(address _token, address _to, uint256 _value) internal {
        LegacyERC20(_token).transfer(_to, _value);
        assembly {
            if returndatasize {
                returndatacopy(0, 0, 32)
                if iszero(mload(0)) {
                    revert(0, 0)
                }
            }
        }
    }

    /**
    * @dev Same as ERC20.transferFrom(address,address,uint256) but with extra consistency checks.
    * @param _token address of the token contract
    * @param _from address of the sender
    * @param _value amount of tokens to send
    */
    function safeTransferFrom(address _token, address _from, uint256 _value) internal {
        LegacyERC20(_token).transferFrom(_from, address(this), _value);
        assembly {
            if returndatasize {
                returndatacopy(0, 0, 32)
                if iszero(mload(0)) {
                    revert(0, 0)
                }
            }
        }
    }
}

// File: contracts/upgradeable_contracts/Claimable.sol

pragma solidity 0.4.24;



/**
 * @title Claimable
 * @dev Implementation of the claiming utils that can be useful for withdrawing accidentally sent tokens that are not used in bridge operations.
 */
contract Claimable {
    using SafeERC20 for address;

    /**
     * Throws if a given address is equal to address(0)
     */
    modifier validAddress(address _to) {
        require(_to != address(0));
        /* solcov ignore next */
        _;
    }

    /**
     * @dev Withdraws the erc20 tokens or native coins from this contract.
     * Caller should additionally check that the claimed token is not a part of bridge operations (i.e. that token != erc20token()).
     * @param _token address of the claimed token or address(0) for native coins.
     * @param _to address of the tokens/coins receiver.
     */
    function claimValues(address _token, address _to) internal validAddress(_to) {
        if (_token == address(0)) {
            claimNativeCoins(_to);
        } else {
            claimErc20Tokens(_token, _to);
        }
    }

    /**
     * @dev Internal function for withdrawing all native coins from the contract.
     * @param _to address of the coins receiver.
     */
    function claimNativeCoins(address _to) internal {
        uint256 value = address(this).balance;
        Address.safeSendValue(_to, value);
    }

    /**
     * @dev Internal function for withdrawing all tokens of ssome particular ERC20 contract from this contract.
     * @param _token address of the claimed ERC20 token.
     * @param _to address of the tokens receiver.
     */
    function claimErc20Tokens(address _token, address _to) internal {
        ERC20Basic token = ERC20Basic(_token);
        uint256 balance = token.balanceOf(this);
        _token.safeTransfer(_to, balance);
    }
}

// File: contracts/upgradeable_contracts/VersionableBridge.sol

pragma solidity 0.4.24;

contract VersionableBridge {
    function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
        return (5, 2, 0);
    }

    /* solcov ignore next */
    function getBridgeMode() external pure returns (bytes4);
}

// File: contracts/upgradeable_contracts/DecimalShiftBridge.sol

pragma solidity 0.4.24;



contract DecimalShiftBridge is EternalStorage {
    using SafeMath for uint256;

    bytes32 internal constant DECIMAL_SHIFT = 0x1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee5; // keccak256(abi.encodePacked("decimalShift"))

    /**
    * @dev Internal function for setting the decimal shift for bridge operations.
    * Decimal shift can be positive, negative, or equal to zero.
    * It has the following meaning: N tokens in the foreign chain are equivalent to N * pow(10, shift) tokens on the home side.
    * @param _shift new value of decimal shift.
    */
    function _setDecimalShift(int256 _shift) internal {
        // since 1 wei * 10**77 > 2**255, it does not make any sense to use higher values
        require(_shift > -77 && _shift < 77);
        uintStorage[DECIMAL_SHIFT] = uint256(_shift);
    }

    /**
    * @dev Returns the value of foreign-to-home decimal shift.
    * @return decimal shift.
    */
    function decimalShift() public view returns (int256) {
        return int256(uintStorage[DECIMAL_SHIFT]);
    }

    /**
    * @dev Converts the amount of home tokens into the equivalent amount of foreign tokens.
    * @param _value amount of home tokens.
    * @return equivalent amount of foreign tokens.
    */
    function _unshiftValue(uint256 _value) internal view returns (uint256) {
        return _shiftUint(_value, -decimalShift());
    }

    /**
    * @dev Converts the amount of foreign tokens into the equivalent amount of home tokens.
    * @param _value amount of foreign tokens.
    * @return equivalent amount of home tokens.
    */
    function _shiftValue(uint256 _value) internal view returns (uint256) {
        return _shiftUint(_value, decimalShift());
    }

    /**
    * @dev Calculates _value * pow(10, _shift).
    * @param _value amount of tokens.
    * @param _shift decimal shift to apply.
    * @return shifted value.
    */
    function _shiftUint(uint256 _value, int256 _shift) private pure returns (uint256) {
        if (_shift == 0) {
            return _value;
        }
        if (_shift > 0) {
            return _value.mul(10**uint256(_shift));
        }
        return _value.div(10**uint256(-_shift));
    }
}

// File: contracts/upgradeable_contracts/BasicBridge.sol

pragma solidity 0.4.24;









contract BasicBridge is
    InitializableBridge,
    Validatable,
    Ownable,
    Upgradeable,
    Claimable,
    VersionableBridge,
    DecimalShiftBridge
{
    event GasPriceChanged(uint256 gasPrice);
    event RequiredBlockConfirmationChanged(uint256 requiredBlockConfirmations);

    bytes32 internal constant GAS_PRICE = 0x55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b; // keccak256(abi.encodePacked("gasPrice"))
    bytes32 internal constant REQUIRED_BLOCK_CONFIRMATIONS = 0x916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d79407230071; // keccak256(abi.encodePacked("requiredBlockConfirmations"))

    /**
    * @dev Public setter for fallback gas price value. Only bridge owner can call this method.
    * @param _gasPrice new value for the gas price.
    */
    function setGasPrice(uint256 _gasPrice) external onlyOwner {
        _setGasPrice(_gasPrice);
    }

    function gasPrice() external view returns (uint256) {
        return uintStorage[GAS_PRICE];
    }

    function setRequiredBlockConfirmations(uint256 _blockConfirmations) external onlyOwner {
        _setRequiredBlockConfirmations(_blockConfirmations);
    }

    function _setRequiredBlockConfirmations(uint256 _blockConfirmations) internal {
        require(_blockConfirmations > 0);
        uintStorage[REQUIRED_BLOCK_CONFIRMATIONS] = _blockConfirmations;
        emit RequiredBlockConfirmationChanged(_blockConfirmations);
    }

    function requiredBlockConfirmations() external view returns (uint256) {
        return uintStorage[REQUIRED_BLOCK_CONFIRMATIONS];
    }

    /**
    * @dev Internal function for updating fallback gas price value.
    * @param _gasPrice new value for the gas price, zero gas price is allowed.
    */
    function _setGasPrice(uint256 _gasPrice) internal {
        uintStorage[GAS_PRICE] = _gasPrice;
        emit GasPriceChanged(_gasPrice);
    }
}

// File: contracts/upgradeable_contracts/BasicTokenBridge.sol

pragma solidity 0.4.24;





contract BasicTokenBridge is EternalStorage, Ownable, DecimalShiftBridge {
    using SafeMath for uint256;

    event DailyLimitChanged(uint256 newLimit);
    event ExecutionDailyLimitChanged(uint256 newLimit);

    bytes32 internal constant MIN_PER_TX = 0xbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d1; // keccak256(abi.encodePacked("minPerTx"))
    bytes32 internal constant MAX_PER_TX = 0x0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c; // keccak256(abi.encodePacked("maxPerTx"))
    bytes32 internal constant DAILY_LIMIT = 0x4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a5; // keccak256(abi.encodePacked("dailyLimit"))
    bytes32 internal constant EXECUTION_MAX_PER_TX = 0xc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d5; // keccak256(abi.encodePacked("executionMaxPerTx"))
    bytes32 internal constant EXECUTION_DAILY_LIMIT = 0x21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d237; // keccak256(abi.encodePacked("executionDailyLimit"))

    function totalSpentPerDay(uint256 _day) public view returns (uint256) {
        return uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _day))];
    }

    function totalExecutedPerDay(uint256 _day) public view returns (uint256) {
        return uintStorage[keccak256(abi.encodePacked("totalExecutedPerDay", _day))];
    }

    function dailyLimit() public view returns (uint256) {
        return uintStorage[DAILY_LIMIT];
    }

    function executionDailyLimit() public view returns (uint256) {
        return uintStorage[EXECUTION_DAILY_LIMIT];
    }

    function maxPerTx() public view returns (uint256) {
        return uintStorage[MAX_PER_TX];
    }

    function executionMaxPerTx() public view returns (uint256) {
        return uintStorage[EXECUTION_MAX_PER_TX];
    }

    function minPerTx() public view returns (uint256) {
        return uintStorage[MIN_PER_TX];
    }

    function withinLimit(uint256 _amount) public view returns (bool) {
        uint256 nextLimit = totalSpentPerDay(getCurrentDay()).add(_amount);
        return dailyLimit() >= nextLimit && _amount <= maxPerTx() && _amount >= minPerTx();
    }

    function withinExecutionLimit(uint256 _amount) public view returns (bool) {
        uint256 nextLimit = totalExecutedPerDay(getCurrentDay()).add(_amount);
        return executionDailyLimit() >= nextLimit && _amount <= executionMaxPerTx();
    }

    function getCurrentDay() public view returns (uint256) {
        // solhint-disable-next-line not-rely-on-time
        return now / 1 days;
    }

    function addTotalSpentPerDay(uint256 _day, uint256 _value) internal {
        uintStorage[keccak256(abi.encodePacked("totalSpentPerDay", _day))] = totalSpentPerDay(_day).add(_value);
    }

    function addTotalExecutedPerDay(uint256 _day, uint256 _value) internal {
        uintStorage[keccak256(abi.encodePacked("totalExecutedPerDay", _day))] = totalExecutedPerDay(_day).add(_value);
    }

    function setDailyLimit(uint256 _dailyLimit) external onlyOwner {
        require(_dailyLimit > maxPerTx() || _dailyLimit == 0);
        uintStorage[DAILY_LIMIT] = _dailyLimit;
        emit DailyLimitChanged(_dailyLimit);
    }

    function setExecutionDailyLimit(uint256 _dailyLimit) external onlyOwner {
        require(_dailyLimit > executionMaxPerTx() || _dailyLimit == 0);
        uintStorage[EXECUTION_DAILY_LIMIT] = _dailyLimit;
        emit ExecutionDailyLimitChanged(_dailyLimit);
    }

    function setExecutionMaxPerTx(uint256 _maxPerTx) external onlyOwner {
        require(_maxPerTx < executionDailyLimit());
        uintStorage[EXECUTION_MAX_PER_TX] = _maxPerTx;
    }

    function setMaxPerTx(uint256 _maxPerTx) external onlyOwner {
        require(_maxPerTx == 0 || (_maxPerTx > minPerTx() && _maxPerTx < dailyLimit()));
        uintStorage[MAX_PER_TX] = _maxPerTx;
    }

    function setMinPerTx(uint256 _minPerTx) external onlyOwner {
        require(_minPerTx > 0 && _minPerTx < dailyLimit() && _minPerTx < maxPerTx());
        uintStorage[MIN_PER_TX] = _minPerTx;
    }

    /**
    * @dev Retrieves maximum available bridge amount per one transaction taking into account maxPerTx() and dailyLimit() parameters.
    * @return minimum of maxPerTx parameter and remaining daily quota.
    */
    function maxAvailablePerTx() public view returns (uint256) {
        uint256 _maxPerTx = maxPerTx();
        uint256 _dailyLimit = dailyLimit();
        uint256 _spent = totalSpentPerDay(getCurrentDay());
        uint256 _remainingOutOfDaily = _dailyLimit > _spent ? _dailyLimit - _spent : 0;
        return _maxPerTx < _remainingOutOfDaily ? _maxPerTx : _remainingOutOfDaily;
    }

    function _setLimits(uint256[3] _limits) internal {
        require(
            _limits[2] > 0 && // minPerTx > 0
                _limits[1] > _limits[2] && // maxPerTx > minPerTx
                _limits[0] > _limits[1] // dailyLimit > maxPerTx
        );

        uintStorage[DAILY_LIMIT] = _limits[0];
        uintStorage[MAX_PER_TX] = _limits[1];
        uintStorage[MIN_PER_TX] = _limits[2];

        emit DailyLimitChanged(_limits[0]);
    }

    function _setExecutionLimits(uint256[2] _limits) internal {
        require(_limits[1] < _limits[0]); // foreignMaxPerTx < foreignDailyLimit

        uintStorage[EXECUTION_DAILY_LIMIT] = _limits[0];
        uintStorage[EXECUTION_MAX_PER_TX] = _limits[1];

        emit ExecutionDailyLimitChanged(_limits[0]);
    }
}

// File: contracts/upgradeable_contracts/BasicHomeBridge.sol

pragma solidity 0.4.24;








/**
 * @title BasicHomeBridge
 * @dev This contract implements common functionality for all vanilla bridge modes on the Home side.
 */
contract BasicHomeBridge is EternalStorage, Validatable, BasicBridge, BasicTokenBridge {
    using SafeMath for uint256;

    event UserRequestForSignature(address recipient, uint256 value);
    event AffirmationCompleted(address recipient, uint256 value, bytes32 transactionHash);
    event SignedForUserRequest(address indexed signer, bytes32 messageHash);
    event SignedForAffirmation(address indexed signer, bytes32 transactionHash);
    event CollectedSignatures(
        address authorityResponsibleForRelay,
        bytes32 messageHash,
        uint256 NumberOfCollectedSignatures
    );

    /**
     * @dev Executes a message affirmation for some Foreign side event.
     * Can be called only by a current bridge validator.
     * @param recipient tokens/coins of receiver address, where the assets should be unlocked/minted.
     * @param value amount of assets to unlock/mint.
     * @param transactionHash reference event transaction hash on the Foreign side of the bridge.
     */
    function executeAffirmation(address recipient, uint256 value, bytes32 transactionHash) external onlyValidator {
        bytes32 hashMsg = keccak256(abi.encodePacked(recipient, value, transactionHash));
        if (withinExecutionLimit(value)) {
            bytes32 hashSender = keccak256(abi.encodePacked(msg.sender, hashMsg));
            // Duplicated affirmations
            require(!affirmationsSigned(hashSender));
            setAffirmationsSigned(hashSender, true);

            uint256 signed = numAffirmationsSigned(hashMsg);
            require(!isAlreadyProcessed(signed));
            // the check above assumes that the case when the value could be overflew will not happen in the addition operation below
            signed = signed + 1;

            setNumAffirmationsSigned(hashMsg, signed);

            emit SignedForAffirmation(msg.sender, transactionHash);

            if (signed >= requiredSignatures()) {
                // If the bridge contract does not own enough tokens to transfer
                // it will couse funds lock on the home side of the bridge
                setNumAffirmationsSigned(hashMsg, markAsProcessed(signed));
                if (value > 0) {
                    require(onExecuteAffirmation(recipient, value, transactionHash, hashMsg));
                }
                emit AffirmationCompleted(recipient, value, transactionHash);
            }
        } else {
            onFailedAffirmation(recipient, value, transactionHash, hashMsg);
        }
    }

    function submitSignature(bytes signature, bytes message) external onlyValidator {
        // ensure that `signature` is really `message` signed by `msg.sender`
        require(Message.isMessageValid(message));
        require(msg.sender == Message.recoverAddressFromSignedMessage(signature, message, false));
        bytes32 hashMsg = keccak256(abi.encodePacked(message));
        bytes32 hashSender = keccak256(abi.encodePacked(msg.sender, hashMsg));

        uint256 signed = numMessagesSigned(hashMsg);
        require(!isAlreadyProcessed(signed));
        // the check above assumes that the case when the value could be overflew will not happen in the addition operation below
        signed = signed + 1;
        if (signed > 1) {
            // Duplicated signatures
            require(!messagesSigned(hashSender));
        } else {
            setMessages(hashMsg, message);
        }
        setMessagesSigned(hashSender, true);

        bytes32 signIdx = keccak256(abi.encodePacked(hashMsg, (signed - 1)));
        setSignatures(signIdx, signature);

        setNumMessagesSigned(hashMsg, signed);

        emit SignedForUserRequest(msg.sender, hashMsg);

        uint256 reqSigs = requiredSignatures();
        if (signed >= reqSigs) {
            setNumMessagesSigned(hashMsg, markAsProcessed(signed));
            emit CollectedSignatures(msg.sender, hashMsg, reqSigs);

            onSignaturesCollected(message);
        }
    }

    function setMessagesSigned(bytes32 _hash, bool _status) internal {
        boolStorage[keccak256(abi.encodePacked("messagesSigned", _hash))] = _status;
    }

    /* solcov ignore next */
    function onExecuteAffirmation(address, uint256, bytes32, bytes32) internal returns (bool);

    /* solcov ignore next */
    function onFailedAffirmation(address, uint256, bytes32, bytes32) internal;

    /* solcov ignore next */
    function onSignaturesCollected(bytes) internal;

    function numAffirmationsSigned(bytes32 _withdrawal) public view returns (uint256) {
        return uintStorage[keccak256(abi.encodePacked("numAffirmationsSigned", _withdrawal))];
    }

    function setAffirmationsSigned(bytes32 _withdrawal, bool _status) internal {
        boolStorage[keccak256(abi.encodePacked("affirmationsSigned", _withdrawal))] = _status;
    }

    function setNumAffirmationsSigned(bytes32 _withdrawal, uint256 _number) internal {
        uintStorage[keccak256(abi.encodePacked("numAffirmationsSigned", _withdrawal))] = _number;
    }

    function affirmationsSigned(bytes32 _withdrawal) public view returns (bool) {
        return boolStorage[keccak256(abi.encodePacked("affirmationsSigned", _withdrawal))];
    }

    function signature(bytes32 _hash, uint256 _index) external view returns (bytes) {
        bytes32 signIdx = keccak256(abi.encodePacked(_hash, _index));
        return bytesStorage[keccak256(abi.encodePacked("signatures", signIdx))];
    }

    function messagesSigned(bytes32 _message) public view returns (bool) {
        return boolStorage[keccak256(abi.encodePacked("messagesSigned", _message))];
    }

    function setSignatures(bytes32 _hash, bytes _signature) internal {
        bytesStorage[keccak256(abi.encodePacked("signatures", _hash))] = _signature;
    }

    function setMessages(bytes32 _hash, bytes _message) internal {
        bytesStorage[keccak256(abi.encodePacked("messages", _hash))] = _message;
    }

    function message(bytes32 _hash) external view returns (bytes) {
        return bytesStorage[keccak256(abi.encodePacked("messages", _hash))];
    }

    function setNumMessagesSigned(bytes32 _message, uint256 _number) internal {
        uintStorage[keccak256(abi.encodePacked("numMessagesSigned", _message))] = _number;
    }

    function markAsProcessed(uint256 _v) internal pure returns (uint256) {
        return _v | (2**255);
    }

    function isAlreadyProcessed(uint256 _number) public pure returns (bool) {
        return _number & (2**255) == 2**255;
    }

    function numMessagesSigned(bytes32 _message) public view returns (uint256) {
        return uintStorage[keccak256(abi.encodePacked("numMessagesSigned", _message))];
    }

    function requiredMessageLength() public pure returns (uint256) {
        return Message.requiredMessageLength();
    }
}

// File: contracts/upgradeable_contracts/FeeTypes.sol

pragma solidity 0.4.24;

contract FeeTypes {
    bytes32 internal constant HOME_FEE = 0x89d93e5e92f7e37e490c25f0e50f7f4aad7cc94b308a566553280967be38bcf1; // keccak256(abi.encodePacked("home-fee"))
    bytes32 internal constant FOREIGN_FEE = 0xdeb7f3adca07d6d1f708c1774389db532a2b2f18fd05a62b957e4089f4696ed5; // keccak256(abi.encodePacked("foreign-fee"))

    /**
    * @dev Throws if given fee type is unknown.
    */
    modifier validFeeType(bytes32 _feeType) {
        require(_feeType == HOME_FEE || _feeType == FOREIGN_FEE);
        /* solcov ignore next */
        _;
    }
}

// File: contracts/upgradeable_contracts/RewardableBridge.sol

pragma solidity 0.4.24;




/**
 * @title RewardableBridge
 * @dev Common functionality for fee management logic delegation to the separate fee management contract.
 */
contract RewardableBridge is Ownable, FeeTypes {
    event FeeDistributedFromAffirmation(uint256 feeAmount, bytes32 indexed transactionHash);
    event FeeDistributedFromSignatures(uint256 feeAmount, bytes32 indexed transactionHash);

    bytes32 internal constant FEE_MANAGER_CONTRACT = 0x779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e5; // keccak256(abi.encodePacked("feeManagerContract"))
    bytes4 internal constant GET_HOME_FEE = 0x94da17cd; // getHomeFee()
    bytes4 internal constant GET_FOREIGN_FEE = 0xffd66196; // getForeignFee()
    bytes4 internal constant GET_FEE_MANAGER_MODE = 0xf2ba9561; // getFeeManagerMode()
    bytes4 internal constant SET_HOME_FEE = 0x34a9e148; // setHomeFee(uint256)
    bytes4 internal constant SET_FOREIGN_FEE = 0x286c4066; // setForeignFee(uint256)
    bytes4 internal constant CALCULATE_FEE = 0x9862f26f; // calculateFee(uint256,bool,bytes32)
    bytes4 internal constant DISTRIBUTE_FEE_FROM_SIGNATURES = 0x59d78464; // distributeFeeFromSignatures(uint256)
    bytes4 internal constant DISTRIBUTE_FEE_FROM_AFFIRMATION = 0x054d46ec; // distributeFeeFromAffirmation(uint256)

    /**
     * @dev Internal function for reading the fee value from the fee manager.
     * @param _feeType type of the fee, should be either HOME_FEE of FOREIGN_FEE.
     * @return retrieved fee percentage.
     */
    function _getFee(bytes32 _feeType) internal view validFeeType(_feeType) returns (uint256 fee) {
        address feeManager = feeManagerContract();
        bytes4 method = _feeType == HOME_FEE ? GET_HOME_FEE : GET_FOREIGN_FEE;
        bytes memory callData = abi.encodeWithSelector(method);

        assembly {
            let result := callcode(gas, feeManager, 0x0, add(callData, 0x20), mload(callData), 0, 32)

            if and(eq(returndatasize, 32), result) {
                fee := mload(0)
            }
        }
    }

    /**
     * @dev Retrieves the mode of the used fee manager.
     * @return manager mode identifier, or zero bytes otherwise.
     */
    function getFeeManagerMode() external view returns (bytes4 mode) {
        bytes memory callData = abi.encodeWithSelector(GET_FEE_MANAGER_MODE);
        address feeManager = feeManagerContract();
        assembly {
            let result := callcode(gas, feeManager, 0x0, add(callData, 0x20), mload(callData), 0, 4)

            if and(eq(returndatasize, 32), result) {
                mode := mload(0)
            }
        }
    }

    /**
     * @dev Retrieves the address of the fee manager contract used.
     * @return address of the fee manager contract.
     */
    function feeManagerContract() public view returns (address) {
        return addressStorage[FEE_MANAGER_CONTRACT];
    }

    /**
     * @dev Updates the address of the used fee manager contract.
     * Only contract owner can call this method.
     * If during this operation, home fee is changed, it is highly recommended to stop the bridge operations first.
     * Otherwise, pending signature requests can become a reason for imbalance between two bridge sides.
     * @param _feeManager address of the new fee manager contract, or zero address to disable fee collection.
     */
    function setFeeManagerContract(address _feeManager) external onlyOwner {
        require(_feeManager == address(0) || AddressUtils.isContract(_feeManager));
        addressStorage[FEE_MANAGER_CONTRACT] = _feeManager;
    }

    /**
     * @dev Internal function for setting the fee value by using the fee manager.
     * @param _feeManager address of the fee manager contract.
     * @param _fee new value for fee percentage amount.
     * @param _feeType type of the fee, should be either HOME_FEE of FOREIGN_FEE.
     */
    function _setFee(address _feeManager, uint256 _fee, bytes32 _feeType) internal validFeeType(_feeType) {
        bytes4 method = _feeType == HOME_FEE ? SET_HOME_FEE : SET_FOREIGN_FEE;
        require(_feeManager.delegatecall(abi.encodeWithSelector(method, _fee)));
    }

    /**
     * @dev Calculates the exact fee amount by using the fee manager.
     * @param _value transferred value for which fee should be calculated.
     * @param _recover true, if the fee was already subtracted from the given _value and needs to be restored.
     * @param _impl address of the fee manager contract.
     * @param _feeType type of the fee, should be either HOME_FEE of FOREIGN_FEE.
     * @return calculated fee amount.
     */
    function calculateFee(uint256 _value, bool _recover, address _impl, bytes32 _feeType)
        internal
        view
        returns (uint256 fee)
    {
        bytes memory callData = abi.encodeWithSelector(CALCULATE_FEE, _value, _recover, _feeType);
        assembly {
            let result := callcode(gas, _impl, 0x0, add(callData, 0x20), mload(callData), 0, 32)

            switch and(eq(returndatasize, 32), result)
                case 1 {
                    fee := mload(0)
                }
                default {
                    revert(0, 0)
                }
        }
    }

    /**
     * @dev Internal function for distributing the fee for collecting sufficient amount of signatures.
     * @param _fee amount of fee to distribute.
     * @param _feeManager address of the fee manager contract.
     * @param _txHash reference transaction hash where the original bridge request happened.
     */
    function distributeFeeFromSignatures(uint256 _fee, address _feeManager, bytes32 _txHash) internal {
        if (_fee > 0) {
            require(_feeManager.delegatecall(abi.encodeWithSelector(DISTRIBUTE_FEE_FROM_SIGNATURES, _fee)));
            emit FeeDistributedFromSignatures(_fee, _txHash);
        }
    }

    /**
     * @dev Internal function for distributing the fee for collecting sufficient amount of affirmations.
     * @param _fee amount of fee to distribute.
     * @param _feeManager address of the fee manager contract.
     * @param _txHash reference transaction hash where the original bridge request happened.
     */
    function distributeFeeFromAffirmation(uint256 _fee, address _feeManager, bytes32 _txHash) internal {
        if (_fee > 0) {
            require(_feeManager.delegatecall(abi.encodeWithSelector(DISTRIBUTE_FEE_FROM_AFFIRMATION, _fee)));
            emit FeeDistributedFromAffirmation(_fee, _txHash);
        }
    }
}

// File: contracts/upgradeable_contracts/BaseOverdrawManagement.sol

pragma solidity 0.4.24;


/**
 * @title BaseOverdrawManagement
 * @dev This contract implements basic functionality for tracking execution bridge operations that are out of limits.
 */
contract BaseOverdrawManagement is EternalStorage {
    event MediatorAmountLimitExceeded(address recipient, uint256 value, bytes32 indexed messageId);
    event AmountLimitExceeded(address recipient, uint256 value, bytes32 indexed transactionHash, bytes32 messageId);
    event AssetAboveLimitsFixed(bytes32 indexed messageId, uint256 value, uint256 remaining);

    bytes32 internal constant OUT_OF_LIMIT_AMOUNT = 0x145286dc85799b6fb9fe322391ba2d95683077b2adf34dd576dedc437e537ba7; // keccak256(abi.encodePacked("outOfLimitAmount"))

    /**
     * @dev Total amount coins/tokens that were bridged from the other side and are out of execution limits.
     * @return total amount of all bridge operations above limits.
     */
    function outOfLimitAmount() public view returns (uint256) {
        return uintStorage[OUT_OF_LIMIT_AMOUNT];
    }

    /**
     * @dev Internal function for updating a total amount that is out of execution limits.
     * @param _value new value for the total amount of bridge operations above limits.
     */
    function setOutOfLimitAmount(uint256 _value) internal {
        uintStorage[OUT_OF_LIMIT_AMOUNT] = _value;
    }

    /**
     * @dev Internal function for retrieving information about out-of-limits bridge operation.
     * @param _messageId id of the message that cause above-limits error.
     * @return (address of the receiver, amount of coins/tokens in the bridge operation)
     */
    function txAboveLimits(bytes32 _messageId) internal view returns (address recipient, uint256 value) {
        recipient = addressStorage[keccak256(abi.encodePacked("txOutOfLimitRecipient", _messageId))];
        value = uintStorage[keccak256(abi.encodePacked("txOutOfLimitValue", _messageId))];
    }

    /**
     * @dev Internal function for updating information about tbe out-of-limits bridge operation.
     * @param _recipient receiver specified in the bridge operation.
     * @param _value amount of coins/tokens inside the bridge operation.
     * @param _messageId id of the message that cause above-limits error.
     */
    function setTxAboveLimits(address _recipient, uint256 _value, bytes32 _messageId) internal {
        addressStorage[keccak256(abi.encodePacked("txOutOfLimitRecipient", _messageId))] = _recipient;
        setTxAboveLimitsValue(_value, _messageId);
    }

    /**
     * @dev Internal function for updating information about the remaining value of out-of-limits bridge operation.
     * @param _value amount of coins/tokens inside the bridge operation.
     * @param _messageId id of the message that cause above-limits error.
     */
    function setTxAboveLimitsValue(uint256 _value, bytes32 _messageId) internal {
        uintStorage[keccak256(abi.encodePacked("txOutOfLimitValue", _messageId))] = _value;
    }

    /* solcov ignore next */
    function fixAssetsAboveLimits(bytes32 messageId, bool unlockOnForeign, uint256 valueToUnlock) external;
}

// File: contracts/upgradeable_contracts/HomeOverdrawManagement.sol

pragma solidity 0.4.24;






/**
 * @title HomeOverdrawManagement
 * @dev This contract implements functionality for recovering from out-of-limits executions in Home side vanilla bridges.
 */
contract HomeOverdrawManagement is BaseOverdrawManagement, RewardableBridge, Upgradeable, BasicHomeBridge {
    using SafeMath for uint256;

    /**
    * @dev Fixes locked tokens, that were out of execution limits during the call to executeAffirmation.
    * @param hashMsg reference for bridge operation that was out of execution limits.
    * @param unlockOnForeign true if fixed tokens should be unlocked to the other side of the bridge.
    * @param valueToUnlock unlocked amount of tokens, should be less than txAboveLimitsValue.
    * Should be less than maxPerTx(), if tokens need to be unlocked on the other side.
    */
    function fixAssetsAboveLimits(bytes32 hashMsg, bool unlockOnForeign, uint256 valueToUnlock)
        external
        onlyIfUpgradeabilityOwner
    {
        uint256 signed = numAffirmationsSigned(hashMsg);
        require(!isAlreadyProcessed(signed));
        (address recipient, uint256 value) = txAboveLimits(hashMsg);
        require(recipient != address(0) && value > 0 && value >= valueToUnlock);
        setOutOfLimitAmount(outOfLimitAmount().sub(valueToUnlock));
        uint256 pendingValue = value.sub(valueToUnlock);
        setTxAboveLimitsValue(pendingValue, hashMsg);
        emit AssetAboveLimitsFixed(hashMsg, valueToUnlock, pendingValue);
        if (unlockOnForeign) {
            require(valueToUnlock <= maxPerTx());
            address feeManager = feeManagerContract();
            uint256 eventValue = valueToUnlock;
            if (feeManager != address(0)) {
                uint256 fee = calculateFee(valueToUnlock, false, feeManager, HOME_FEE);
                eventValue = valueToUnlock.sub(fee);
            }
            emit UserRequestForSignature(recipient, eventValue);
        }
    }

    /**
     * @dev Internal function for clearing above limits markers for some failed transfer.
     * Useful when transfer is being reprocessed on a new day or after limits were updated.
     * It is required that fixAssetsAboveLimits was not called on the failed transfer before prior to this function.
     * @param _hashMsg hash of the message, works as a unique indentifier.
     * @param _value transferred amount of tokens/coins in the fixed message.
     */
    function _clearAboveLimitsMarker(bytes32 _hashMsg, uint256 _value) internal {
        (address aboveLimitsRecipient, uint256 aboveLimitsValue) = txAboveLimits(_hashMsg);
        // check if transfer was marked as out of limits
        if (aboveLimitsRecipient != address(0)) {
            // revert if a given transaction hash was already processed by the call to fixAssetsAboveLimits
            require(aboveLimitsValue == _value);
            setTxAboveLimits(address(0), 0, _hashMsg);
            setOutOfLimitAmount(outOfLimitAmount().sub(_value));
        }
    }
}

// File: contracts/upgradeable_contracts/erc20_to_erc20/RewardableHomeBridgeErcToErc.sol

pragma solidity 0.4.24;


contract RewardableHomeBridgeErcToErc is RewardableBridge {
    /**
     * @dev Updates the fee percentage for home->foreign bridge operations.
     * Only owner is allowed to call this method.
     * If during this operation, home fee is changed, it is highly recommended to stop the bridge operations first.
     * Otherwise, pending signature requests can become a reason for imbalance between two bridge sides.
     * @param _fee new value for fee percentage.
     */
    function setHomeFee(uint256 _fee) external onlyOwner {
        _setFee(feeManagerContract(), _fee, HOME_FEE);
    }

    /**
     * @dev Updates the fee percentage for foreign->home bridge operations.
     * Only owner is allowed to call this method.
     * @param _fee new value for fee percentage.
     */
    function setForeignFee(uint256 _fee) external onlyOwner {
        _setFee(feeManagerContract(), _fee, FOREIGN_FEE);
    }

    function getHomeFee() public view returns (uint256) {
        return _getFee(HOME_FEE);
    }

    function getForeignFee() public view returns (uint256) {
        return _getFee(FOREIGN_FEE);
    }
}

// File: contracts/interfaces/ERC677Receiver.sol

pragma solidity 0.4.24;

contract ERC677Receiver {
    function onTokenTransfer(address _from, uint256 _value, bytes _data) external returns (bool);
}

// File: contracts/upgradeable_contracts/ERC677Storage.sol

pragma solidity 0.4.24;

contract ERC677Storage {
    bytes32 internal constant ERC677_TOKEN = 0xa8b0ade3e2b734f043ce298aca4cc8d19d74270223f34531d0988b7d00cba21d; // keccak256(abi.encodePacked("erc677token"))
}

// File: contracts/libraries/Bytes.sol

pragma solidity 0.4.24;

/**
 * @title Bytes
 * @dev Helper methods to transform bytes to other solidity types.
 */
library Bytes {
    /**
    * @dev Converts bytes array to bytes32.
    * Truncates bytes array if its size is more than 32 bytes.
    * NOTE: This function does not perform any checks on the received parameter.
    * Make sure that the _bytes argument has a correct length, not less than 32 bytes.
    * A case when _bytes has length less than 32 will lead to the undefined behaviour,
    * since assembly will read data from memory that is not related to the _bytes argument.
    * @param _bytes to be converted to bytes32 type
    * @return bytes32 type of the firsts 32 bytes array in parameter.
    */
    function bytesToBytes32(bytes _bytes) internal pure returns (bytes32 result) {
        assembly {
            result := mload(add(_bytes, 32))
        }
    }

    /**
    * @dev Truncate bytes array if its size is more than 20 bytes.
    * NOTE: Similar to the bytesToBytes32 function, make sure that _bytes is not shorter than 20 bytes.
    * @param _bytes to be converted to address type
    * @return address included in the firsts 20 bytes of the bytes array in parameter.
    */
    function bytesToAddress(bytes _bytes) internal pure returns (address addr) {
        assembly {
            addr := mload(add(_bytes, 20))
        }
    }
}

// File: contracts/upgradeable_contracts/ChooseReceiverHelper.sol

pragma solidity 0.4.24;


contract ChooseReceiverHelper {
    /**
    * @dev Helper function for alternative receiver feature. Chooses the actual receiver out of sender and passed data.
    * @param _from address of tokens sender.
    * @param _data passed data in the transfer message.
    * @return address of the receiver on the other side.
    */
    function chooseReceiver(address _from, bytes _data) internal view returns (address recipient) {
        recipient = _from;
        if (_data.length > 0) {
            require(_data.length == 20);
            recipient = Bytes.bytesToAddress(_data);
            require(recipient != address(0));
            require(recipient != bridgeContractOnOtherSide());
        }
    }

    /* solcov ignore next */
    function bridgeContractOnOtherSide() internal view returns (address);
}

// File: contracts/upgradeable_contracts/BaseERC677Bridge.sol

pragma solidity 0.4.24;







contract BaseERC677Bridge is BasicTokenBridge, ERC677Receiver, ERC677Storage, ChooseReceiverHelper {
    function _erc677token() internal view returns (ERC677) {
        return ERC677(addressStorage[ERC677_TOKEN]);
    }

    function setErc677token(address _token) internal {
        require(AddressUtils.isContract(_token));
        addressStorage[ERC677_TOKEN] = _token;
    }

    function onTokenTransfer(address _from, uint256 _value, bytes _data) external returns (bool) {
        ERC677 token = _erc677token();
        require(msg.sender == address(token));
        require(withinLimit(_value));
        addTotalSpentPerDay(getCurrentDay(), _value);
        bridgeSpecificActionsOnTokenTransfer(token, _from, _value, _data);
        return true;
    }

    /* solcov ignore next */
    function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value, bytes _data) internal;
}

// File: contracts/upgradeable_contracts/OtherSideBridgeStorage.sol

pragma solidity 0.4.24;


contract OtherSideBridgeStorage is EternalStorage {
    bytes32 internal constant BRIDGE_CONTRACT = 0x71483949fe7a14d16644d63320f24d10cf1d60abecc30cc677a340e82b699dd2; // keccak256(abi.encodePacked("bridgeOnOtherSide"))

    function _setBridgeContractOnOtherSide(address _bridgeContract) internal {
        require(_bridgeContract != address(0));
        addressStorage[BRIDGE_CONTRACT] = _bridgeContract;
    }

    function bridgeContractOnOtherSide() internal view returns (address) {
        return addressStorage[BRIDGE_CONTRACT];
    }
}

// File: contracts/upgradeable_contracts/ERC677Bridge.sol

pragma solidity 0.4.24;



contract ERC677Bridge is BaseERC677Bridge, OtherSideBridgeStorage {
    function erc677token() public view returns (ERC677) {
        return _erc677token();
    }

    function bridgeSpecificActionsOnTokenTransfer(
        ERC677, /*_token*/
        address _from,
        uint256 _value,
        bytes _data
    ) internal {
        fireEventOnTokenTransfer(chooseReceiver(_from, _data), _value);
    }

    /* solcov ignore next */
    function fireEventOnTokenTransfer(address _from, uint256 _value) internal;
}

// File: contracts/upgradeable_contracts/ERC677BridgeForBurnableMintableToken.sol

pragma solidity 0.4.24;



contract ERC677BridgeForBurnableMintableToken is ERC677Bridge {
    function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value, bytes _data) internal {
        IBurnableMintableERC677Token(_token).burn(_value);
        fireEventOnTokenTransfer(chooseReceiver(_from, _data), _value);
    }
}

// File: contracts/upgradeable_contracts/erc20_to_erc20/HomeBridgeErcToErc.sol

pragma solidity 0.4.24;








/**
 * @title HomeBridgeErcToErc
 * @dev This contract Home side logic for the erc-to-erc vanilla bridge mode.
 * It is designed to be used as an implementation contract of EternalStorageProxy contract.
 */
contract HomeBridgeErcToErc is
    EternalStorage,
    BasicHomeBridge,
    ERC677BridgeForBurnableMintableToken,
    HomeOverdrawManagement,
    RewardableHomeBridgeErcToErc
{
    function initialize(
        address _validatorContract,
        uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
        uint256 _homeGasPrice,
        uint256 _requiredBlockConfirmations,
        address _erc677token,
        uint256[2] _foreignDailyLimitForeignMaxPerTxArray, // [ 0 = _foreignDailyLimit, 1 = _foreignMaxPerTx ]
        address _owner,
        int256 _decimalShift
    ) external onlyRelevantSender returns (bool) {
        _initialize(
            _validatorContract,
            _dailyLimitMaxPerTxMinPerTxArray,
            _homeGasPrice,
            _requiredBlockConfirmations,
            _erc677token,
            _foreignDailyLimitForeignMaxPerTxArray,
            _owner,
            _decimalShift
        );
        setInitialize();

        return isInitialized();
    }

    function rewardableInitialize(
        address _validatorContract,
        uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
        uint256 _homeGasPrice,
        uint256 _requiredBlockConfirmations,
        address _erc677token,
        uint256[2] _foreignDailyLimitForeignMaxPerTxArray, // [ 0 = _foreignDailyLimit, 1 = _foreignMaxPerTx ]
        address _owner,
        address _feeManager,
        uint256[2] _homeFeeForeignFeeArray, // [ 0 = _homeFee, 1 = _foreignFee ]
        int256 _decimalShift
    ) external onlyRelevantSender returns (bool) {
        _rewardableInitialize(
            _validatorContract,
            _dailyLimitMaxPerTxMinPerTxArray,
            _homeGasPrice,
            _requiredBlockConfirmations,
            _erc677token,
            _foreignDailyLimitForeignMaxPerTxArray,
            _owner,
            _feeManager,
            _homeFeeForeignFeeArray,
            _decimalShift
        );
        setInitialize();

        return isInitialized();
    }

    function _rewardableInitialize(
        address _validatorContract,
        uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
        uint256 _homeGasPrice,
        uint256 _requiredBlockConfirmations,
        address _erc677token,
        uint256[2] _foreignDailyLimitForeignMaxPerTxArray, // [ 0 = _foreignDailyLimit, 1 = _foreignMaxPerTx ]
        address _owner,
        address _feeManager,
        uint256[2] _homeFeeForeignFeeArray, // [ 0 = _homeFee, 1 = _foreignFee ]
        int256 _decimalShift
    ) internal {
        _initialize(
            _validatorContract,
            _dailyLimitMaxPerTxMinPerTxArray,
            _homeGasPrice,
            _requiredBlockConfirmations,
            _erc677token,
            _foreignDailyLimitForeignMaxPerTxArray,
            _owner,
            _decimalShift
        );
        require(AddressUtils.isContract(_feeManager));
        addressStorage[FEE_MANAGER_CONTRACT] = _feeManager;
        _setFee(_feeManager, _homeFeeForeignFeeArray[0], HOME_FEE);
        _setFee(_feeManager, _homeFeeForeignFeeArray[1], FOREIGN_FEE);
    }

    function _initialize(
        address _validatorContract,
        uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
        uint256 _homeGasPrice,
        uint256 _requiredBlockConfirmations,
        address _erc677token,
        uint256[2] _foreignDailyLimitForeignMaxPerTxArray, // [ 0 = _foreignDailyLimit, 1 = _foreignMaxPerTx ]
        address _owner,
        int256 _decimalShift
    ) internal {
        require(!isInitialized());
        require(AddressUtils.isContract(_validatorContract));

        addressStorage[VALIDATOR_CONTRACT] = _validatorContract;
        uintStorage[DEPLOYED_AT_BLOCK] = block.number;
        _setLimits(_dailyLimitMaxPerTxMinPerTxArray);
        _setGasPrice(_homeGasPrice);
        _setRequiredBlockConfirmations(_requiredBlockConfirmations);
        _setExecutionLimits(_foreignDailyLimitForeignMaxPerTxArray);
        _setDecimalShift(_decimalShift);
        _setOwner(_owner);
        setErc677token(_erc677token);
    }

    /**
     * @dev Withdraws erc20 tokens or native coins from the token contract. It is required since the bridge contract is the owner of the token contract.
     * @param _token address of the claimed token or address(0) for native coins.
     * @param _to address of the tokens/coins receiver.
     */
    function claimTokensFromErc677(address _token, address _to) external onlyIfUpgradeabilityOwner {
        IBurnableMintableERC677Token(erc677token()).claimTokens(_token, _to);
    }

    function getBridgeMode() external pure returns (bytes4 _data) {
        return 0xba4690f5; // bytes4(keccak256(abi.encodePacked("erc-to-erc-core")))
    }

    /**
     * @dev Internal callback to be called on successfull message execution.
     * Should be called only after enough affirmations from the validators are already collected.
     * @param _recipient address of the receiver where the new tokens should be minted.
     * @param _value amount of tokens to mint.
     * @param _txHash reference transaction hash on the Foreign side of the bridge which cause this operation.
     * @param _hashMsg unique identifier of the particular bridge operation.
     * @return true, if execution completed successfully.
     */
    function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 _txHash, bytes32 _hashMsg)
        internal
        returns (bool)
    {
        _clearAboveLimitsMarker(_hashMsg, _value);
        addTotalExecutedPerDay(getCurrentDay(), _value);
        uint256 valueToMint = _shiftValue(_value);
        address feeManager = feeManagerContract();
        if (feeManager != address(0)) {
            uint256 fee = calculateFee(valueToMint, false, feeManager, FOREIGN_FEE);
            distributeFeeFromAffirmation(fee, feeManager, _txHash);
            valueToMint = valueToMint.sub(fee);
        }
        return IBurnableMintableERC677Token(erc677token()).mint(_recipient, valueToMint);
    }

    function fireEventOnTokenTransfer(address _from, uint256 _value) internal {
        uint256 valueToTransfer = _value;
        address feeManager = feeManagerContract();
        if (feeManager != address(0)) {
            uint256 fee = calculateFee(valueToTransfer, false, feeManager, HOME_FEE);
            valueToTransfer = valueToTransfer.sub(fee);
        }
        emit UserRequestForSignature(_from, valueToTransfer);
    }

    /**
     * @dev Internal function to be called when enough signatures are collected.
     * Distributed the fee for collecting signatures.
     * @param _message encoded message signed by the validators.
     */
    function onSignaturesCollected(bytes _message) internal {
        address feeManager = feeManagerContract();
        if (feeManager != address(0)) {
            (, uint256 amount, bytes32 txHash, ) = Message.parseMessage(_message);
            uint256 fee = calculateFee(amount, true, feeManager, HOME_FEE);
            distributeFeeFromSignatures(fee, feeManager, txHash);
        }
    }

    /**
     * @dev Internal callback to be called on failed message execution due to the out-of-limits error.
     * This function saves the bridge operation information for further processing.
     * @param _recipient address of the receiver where the new tokens should be minted.
     * @param _value amount of tokens to mint.
     * @param _txHash reference transaction hash on the Foreign side of the bridge which cause this operation.
     * @param _hashMsg unique identifier of the particular bridge operation.
     */
    function onFailedAffirmation(address _recipient, uint256 _value, bytes32 _txHash, bytes32 _hashMsg) internal {
        (address recipient, uint256 value) = txAboveLimits(_hashMsg);
        require(recipient == address(0) && value == 0);
        setOutOfLimitAmount(outOfLimitAmount().add(_value));
        setTxAboveLimits(_recipient, _value, _hashMsg);
        emit AmountLimitExceeded(_recipient, _value, _txHash, _hashMsg);
    }
}
        

Contract ABI

[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"numMessagesSigned","inputs":[{"type":"bytes32","name":"_message"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes","name":""}],"name":"signature","inputs":[{"type":"bytes32","name":"_hash"},{"type":"uint256","name":"_index"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"erc677token","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setForeignFee","inputs":[{"type":"uint256","name":"_fee"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"totalSpentPerDay","inputs":[{"type":"uint256","name":"_day"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setHomeFee","inputs":[{"type":"uint256","name":"_fee"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isInitialized","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setExecutionDailyLimit","inputs":[{"type":"uint256","name":"_dailyLimit"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getCurrentDay","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"requiredBlockConfirmations","inputs":[],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"requiredMessageLength","inputs":[],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"bytes4","name":"_data"}],"name":"getBridgeMode","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"executionDailyLimit","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes","name":""}],"name":"message","inputs":[{"type":"bytes32","name":"_hash"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"totalExecutedPerDay","inputs":[{"type":"uint256","name":"_day"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setFeeManagerContract","inputs":[{"type":"address","name":"_feeManager"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"submitSignature","inputs":[{"type":"bytes","name":"signature"},{"type":"bytes","name":"message"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"dailyLimit","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"numAffirmationsSigned","inputs":[{"type":"bytes32","name":"_withdrawal"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"affirmationsSigned","inputs":[{"type":"bytes32","name":"_withdrawal"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"initialize","inputs":[{"type":"address","name":"_validatorContract"},{"type":"uint256[3]","name":"_dailyLimitMaxPerTxMinPerTxArray"},{"type":"uint256","name":"_homeGasPrice"},{"type":"uint256","name":"_requiredBlockConfirmations"},{"type":"address","name":"_erc677token"},{"type":"uint256[2]","name":"_foreignDailyLimitForeignMaxPerTxArray"},{"type":"address","name":"_owner"},{"type":"int256","name":"_decimalShift"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"withinExecutionLimit","inputs":[{"type":"uint256","name":"_amount"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"executionMaxPerTx","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"requiredSignatures","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"messagesSigned","inputs":[{"type":"bytes32","name":"_message"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"claimTokensFromErc677","inputs":[{"type":"address","name":"_token"},{"type":"address","name":"_to"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getHomeFee","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"maxAvailablePerTx","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"validatorContract","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"executeAffirmation","inputs":[{"type":"address","name":"recipient"},{"type":"uint256","name":"value"},{"type":"bytes32","name":"transactionHash"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"deployedAtBlock","inputs":[],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"uint64","name":"major"},{"type":"uint64","name":"minor"},{"type":"uint64","name":"patch"}],"name":"getBridgeInterfacesVersion","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"outOfLimitAmount","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setMinPerTx","inputs":[{"type":"uint256","name":"_minPerTx"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"onTokenTransfer","inputs":[{"type":"address","name":"_from"},{"type":"uint256","name":"_value"},{"type":"bytes","name":"_data"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"fixAssetsAboveLimits","inputs":[{"type":"bytes32","name":"hashMsg"},{"type":"bool","name":"unlockOnForeign"},{"type":"uint256","name":"valueToUnlock"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setRequiredBlockConfirmations","inputs":[{"type":"uint256","name":"_blockConfirmations"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setDailyLimit","inputs":[{"type":"uint256","name":"_dailyLimit"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setGasPrice","inputs":[{"type":"uint256","name":"_gasPrice"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setMaxPerTx","inputs":[{"type":"uint256","name":"_maxPerTx"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"int256","name":""}],"name":"decimalShift","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"feeManagerContract","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"minPerTx","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"rewardableInitialize","inputs":[{"type":"address","name":"_validatorContract"},{"type":"uint256[3]","name":"_dailyLimitMaxPerTxMinPerTxArray"},{"type":"uint256","name":"_homeGasPrice"},{"type":"uint256","name":"_requiredBlockConfirmations"},{"type":"address","name":"_erc677token"},{"type":"uint256[2]","name":"_foreignDailyLimitForeignMaxPerTxArray"},{"type":"address","name":"_owner"},{"type":"address","name":"_feeManager"},{"type":"uint256[2]","name":"_homeFeeForeignFeeArray"},{"type":"int256","name":"_decimalShift"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"withinLimit","inputs":[{"type":"uint256","name":"_amount"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setExecutionMaxPerTx","inputs":[{"type":"uint256","name":"_maxPerTx"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes4","name":"mode"}],"name":"getFeeManagerMode","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"maxPerTx","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"gasPrice","inputs":[],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isAlreadyProcessed","inputs":[{"type":"uint256","name":"_number"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getForeignFee","inputs":[],"constant":true},{"type":"event","name":"UserRequestForSignature","inputs":[{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"AffirmationCompleted","inputs":[{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"value","indexed":false},{"type":"bytes32","name":"transactionHash","indexed":false}],"anonymous":false},{"type":"event","name":"SignedForUserRequest","inputs":[{"type":"address","name":"signer","indexed":true},{"type":"bytes32","name":"messageHash","indexed":false}],"anonymous":false},{"type":"event","name":"SignedForAffirmation","inputs":[{"type":"address","name":"signer","indexed":true},{"type":"bytes32","name":"transactionHash","indexed":false}],"anonymous":false},{"type":"event","name":"CollectedSignatures","inputs":[{"type":"address","name":"authorityResponsibleForRelay","indexed":false},{"type":"bytes32","name":"messageHash","indexed":false},{"type":"uint256","name":"NumberOfCollectedSignatures","indexed":false}],"anonymous":false},{"type":"event","name":"DailyLimitChanged","inputs":[{"type":"uint256","name":"newLimit","indexed":false}],"anonymous":false},{"type":"event","name":"ExecutionDailyLimitChanged","inputs":[{"type":"uint256","name":"newLimit","indexed":false}],"anonymous":false},{"type":"event","name":"GasPriceChanged","inputs":[{"type":"uint256","name":"gasPrice","indexed":false}],"anonymous":false},{"type":"event","name":"RequiredBlockConfirmationChanged","inputs":[{"type":"uint256","name":"requiredBlockConfirmations","indexed":false}],"anonymous":false},{"type":"event","name":"FeeDistributedFromAffirmation","inputs":[{"type":"uint256","name":"feeAmount","indexed":false},{"type":"bytes32","name":"transactionHash","indexed":true}],"anonymous":false},{"type":"event","name":"FeeDistributedFromSignatures","inputs":[{"type":"uint256","name":"feeAmount","indexed":false},{"type":"bytes32","name":"transactionHash","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":false},{"type":"address","name":"newOwner","indexed":false}],"anonymous":false},{"type":"event","name":"MediatorAmountLimitExceeded","inputs":[{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"value","indexed":false},{"type":"bytes32","name":"messageId","indexed":true}],"anonymous":false},{"type":"event","name":"AmountLimitExceeded","inputs":[{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"value","indexed":false},{"type":"bytes32","name":"transactionHash","indexed":true},{"type":"bytes32","name":"messageId","indexed":false}],"anonymous":false},{"type":"event","name":"AssetAboveLimitsFixed","inputs":[{"type":"bytes32","name":"messageId","indexed":true},{"type":"uint256","name":"value","indexed":false},{"type":"uint256","name":"remaining","indexed":false}],"anonymous":false}]
            

Deployed ByteCode

0x6080604052600436106102635763ffffffff60e060020a6000350416630cbf060181146102685780631812d9961461029257806318d8f9c914610322578063286c4066146103535780632bd0bb051461036d57806334a9e14814610385578063392e53cd1461039d5780633dd95d1b146103c65780633e6968b6146103de5780633f0a9f65146103f3578063408fef2e14610408578063437764df1461041d57806343b37dd314610464578063490a32c6146104795780634fb3fef71461049157806360756f7c146104a9578063630cea8e146104ca57806367eeba0c146104f65780636ae1a9761461050b5780637698da2414610523578063865c80281461053b578063879ce6761461057b5780638aa1949a146105935780638d068043146105a85780638da5cb5b146105bd5780638f4b4b98146105d25780639313dc43146105ea57806394da17cd1461061157806395e54a1714610626578063994390891461063b578063995b2cff146106505780639a454b99146106775780639cb7595a1461068c578063a0189345146106cd578063a2a6ca27146106e2578063a4c0ed36146106fa578063a7444c0d1461072b578063acf5c6891461074b578063b20d30a914610763578063bf1fe4201461077b578063c6f6f21614610793578063dae5f0fd146107ab578063dbe03a8b146107c0578063df25f3f0146107d5578063e13d3c79146107ea578063ea9f496814610834578063f20151e11461084c578063f2ba956114610864578063f2fde38b14610879578063f968adbe1461089a578063fe173b97146108af578063ffd19e8c146108c4578063ffd66196146108dc575b600080fd5b34801561027457600080fd5b506102806004356108f1565b60408051918252519081900360200190f35b34801561029e57600080fd5b506102ad6004356024356109b6565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102e75781810151838201526020016102cf565b50505050905090810190601f1680156103145780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561032e57600080fd5b50610337610b93565b60408051600160a060020a039092168252519081900360200190f35b34801561035f57600080fd5b5061036b600435610ba3565b005b34801561037957600080fd5b50610280600435610be2565b34801561039157600080fd5b5061036b600435610c5d565b3480156103a957600080fd5b506103b2610c99565b604080519115158252519081900360200190f35b3480156103d257600080fd5b5061036b600435610cea565b3480156103ea57600080fd5b50610280610daa565b3480156103ff57600080fd5b50610280610db3565b34801561041457600080fd5b50610280610e01565b34801561042957600080fd5b50610432610e0b565b604080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff199092168252519081900360200190f35b34801561047057600080fd5b50610280610e2f565b34801561048557600080fd5b506102ad600435610e7d565b34801561049d57600080fd5b50610280600435610fe5565b3480156104b557600080fd5b5061036b600160a060020a0360043516611060565b3480156104d657600080fd5b5061036b6024600480358281019290820135918135918201910135611118565b34801561050257600080fd5b506102806115ae565b34801561051757600080fd5b506102806004356115fc565b34801561052f57600080fd5b506103b260043561167f565b34801561054757600080fd5b506103b2600160a060020a036004358116906024906084359060a4359060c43581169060e490610124351661014435611748565b34801561058757600080fd5b506103b26004356118f8565b34801561059f57600080fd5b50610280611942565b3480156105b457600080fd5b50610280611990565b3480156105c957600080fd5b50610337611a08565b3480156105de57600080fd5b506103b2600435611a5f565b3480156105f657600080fd5b5061036b600160a060020a0360043581169060243516611ae3565b34801561061d57600080fd5b50610280611bf2565b34801561063257600080fd5b50610280611c0b565b34801561064757600080fd5b50610337611c65565b34801561065c57600080fd5b5061036b600160a060020a0360043516602435604435611cbc565b34801561068357600080fd5b50610280611fba565b34801561069857600080fd5b506106a1612008565b6040805167ffffffffffffffff9485168152928416602084015292168183015290519081900360600190f35b3480156106d957600080fd5b50610280612013565b3480156106ee57600080fd5b5061036b600435612061565b34801561070657600080fd5b506103b260048035600160a060020a03169060248035916044359182019101356120fd565b34801561073757600080fd5b5061036b600435602435151560443561218c565b34801561075757600080fd5b5061036b60043561239d565b34801561076f57600080fd5b5061036b6004356123c2565b34801561078757600080fd5b5061036b600435612482565b34801561079f57600080fd5b5061036b6004356124a7565b3480156107b757600080fd5b5061028061253f565b3480156107cc57600080fd5b5061033761258d565b3480156107e157600080fd5b506102806125e4565b3480156107f657600080fd5b506103b2600160a060020a036004358116906024906084359060a4359060c43581169060e4906101243581169061014435166101646101a435612632565b34801561084057600080fd5b506103b2600435612811565b34801561085857600080fd5b5061036b60043561285c565b34801561087057600080fd5b506104326128d8565b34801561088557600080fd5b5061036b600160a060020a036004351661294e565b3480156108a657600080fd5b50610280612973565b3480156108bb57600080fd5b506102806129c1565b3480156108d057600080fd5b506103b2600435612a0f565b3480156108e857600080fd5b50610280612a37565b60008060008360405160200180807f6e756d4d657373616765735369676e656400000000000000000000000000000081525060110182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106109755780518252601f199092019160209182019101610956565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205495945050505050565b604080516020808201859052818301849052825180830384018152606092830193849052805192936000939192909182918401908083835b60208310610a0d5780518252601f1990920191602091820191016109ee565b51815160209384036101000a6000190180199092169116179052604080519290940182900382207f7369676e6174757265730000000000000000000000000000000000000000000083830152602a80840182905285518085039091018152604a9093019485905282519097506003965060009550919392508291908401908083835b60208310610aae5780518252601f199092019160209182019101610a8f565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b855780601f10610b5a57610100808354040283529160200191610b85565b820191906000526020600020905b815481529060010190602001808311610b6857829003601f168201915b505050505091505092915050565b6000610b9d612a50565b90505b90565b610bab611a08565b600160a060020a03163314610bbf57600080fd5b610bdf610bca61258d565b82600080516020614986833981519152612aa7565b50565b60008060008360405160200180807f746f74616c5370656e7450657244617900000000000000000000000000000000815250601001828152602001915050604051602081830303815290604052604051808280519060200190808383602083106109755780518252601f199092019160209182019101610956565b610c65611a08565b600160a060020a03163314610c7957600080fd5b610bdf610c8461258d565b826000805160206149a6833981519152612aa7565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc5460ff1690565b610cf2611a08565b600160a060020a03163314610d0657600080fd5b610d0e611942565b811180610d19575080155b1515610d2457600080fd5b7f21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d237600090815260209081527fadd938dbd083a16bae12238cd914fca0afc7a30edb55b1cd5c7f1823f1b0e4218290556040805183815290517f9bebf928b90863f24cc31f726a3a7545efd409f1dcf552301b1ee3710da70d3b929181900390910190a150565b62015180420490565b7f916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d7940723007160009081526020527fd2ea0feb732edb0ffe32efd33a6b9d24d46b16eb34a4d07ce256537b6f131e425490565b6000610b9d612c13565b7fba4690f50000000000000000000000000000000000000000000000000000000090565b7f21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d23760009081526020527fadd938dbd083a16bae12238cd914fca0afc7a30edb55b1cd5c7f1823f1b0e4215490565b6060600360008360405160200180807f6d6573736167657300000000000000000000000000000000000000000000000081525060080182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310610f025780518252601f199092019160209182019101610ee3565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610fd95780601f10610fae57610100808354040283529160200191610fd9565b820191906000526020600020905b815481529060010190602001808311610fbc57829003601f168201915b50505050509050919050565b60008060008360405160200180807f746f74616c457865637574656450657244617900000000000000000000000000815250601301828152602001915050604051602081830303815290604052604051808280519060200190808383602083106109755780518252601f199092019160209182019101610956565b611068611a08565b600160a060020a0316331461107c57600080fd5b600160a060020a0381161580611096575061109681612c18565b15156110a157600080fd5b7f779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e560005260026020527fc155b21a14c4592b97825e495fbe0d2705fb46420018cac5bfa7a09c43fae517805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b6000806000806000611128611c65565b600160a060020a031663facd743b336040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561118257600080fd5b505af1158015611196573d6000803e3d6000fd5b505050506040513d60208110156111ac57600080fd5b505115156111b957600080fd5b6111f287878080601f01602080910402602001604051908101604052809392919081815260200183838082843750612c20945050505050565b15156111fd57600080fd5b61126789898080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f8f018190048102820181019092528d815294508d93508c925082915084018382808284375060009450612c349350505050565b600160a060020a0316331461127b57600080fd5b8686604051602001808383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b602083106112d15780518252601f1990920191602091820191016112b2565b51815160209384036101000a600019018019909216911617905260408051929094018290038220336c0100000000000000000000000002838301526034808401829052855180850390910181526054909301948590528251909b509195509293508392850191508083835b6020831061135b5780518252601f19909201916020918201910161133c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209350611393856108f1565b925061139e83612a0f565b156113a857600080fd5b6001928301928311156113cd576113be84611a5f565b156113c857600080fd5b611407565b6114078588888080601f01602080910402602001604051908101604052809392919081815260200183838082843750612d33945050505050565b611412846001612e0a565b604080516020808201889052600019860182840152825180830384018152606090920192839052815191929182918401908083835b602083106114665780518252601f199092019160209182019101611447565b51815160209384036101000a600019018019909216911617905260408051929094018290038220601f8f018290048202830182019094528d82529296506114c79450869350918d91508c908190840183828082843750612edc945050505050565b6114d18584612f5f565b60408051868152905133917fbf06885f40778f5ccfb64497d3f92ce568ddaedb7e2fb4487f72690418cf8e4c919081900360200190a261150f611990565b90508083106115a35761152a8561152585613024565b612f5f565b604080513381526020810187905280820183905290517f415557404d88a0c0b8e3b16967cafffc511213fd9c465c16832ee17ed57d72379181900360600190a16115a387878080601f01602080910402602001604051908101604052809392919081815260200183838082843750613049945050505050565b505050505050505050565b7f4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a560009081526020527f1ab29a5cca988aee50edccdd61c5bcaa7ad4b29a03b7ee50f298ceccfe14cc4e5490565b60008060008360405160200180807f6e756d41666669726d6174696f6e735369676e656400000000000000000000008152506015018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106109755780518252601f199092019160209182019101610956565b6000600460008360405160200180807f61666669726d6174696f6e735369676e6564000000000000000000000000000081525060120182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106117045780518252601f1990920191602091820191016116e5565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1695945050505050565b6040805160048152602481018252602081018051600160e060020a03167f6fde8202000000000000000000000000000000000000000000000000000000001781529151815160009330939291829190808383895b838110156117b457818101518382015260200161179c565b50505050905090810190601f1680156117e15780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af19150501580611873575030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561183b57600080fd5b505af115801561184f573d6000803e3d6000fd5b505050506040513d602081101561186557600080fd5b5051600160a060020a031633145b8061187d57503330145b151561188857600080fd5b6118db8989600380602002604051908101604052809291908260036020028082843750506040805180820182528e94508d93508c9250908b906002908390839080828437820191505050505089896130a2565b6118e36131a4565b6118eb610c99565b9998505050505050505050565b60008061191b8361190f61190a610daa565b610fe5565b9063ffffffff6131fb16565b905080611926610e2f565b1015801561193b5750611937611942565b8311155b9392505050565b7fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d560009081526020527ff8e983ee86e5e377e9e34c9131b266382c3f04113d20de077f9e12663c7a646b5490565b600061199a611c65565b600160a060020a0316638d0680436040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156119d757600080fd5b505af11580156119eb573d6000803e3d6000fd5b505050506040513d6020811015611a0157600080fd5b5051905090565b7f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e54600160a060020a031690565b6000600460008360405160200180807f6d657373616765735369676e6564000000000000000000000000000000000000815250600e018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106117045780518252601f1990920191602091820191016116e5565b30600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015611b2157600080fd5b505af1158015611b35573d6000803e3d6000fd5b505050506040513d6020811015611b4b57600080fd5b5051600160a060020a03163314611b6157600080fd5b611b69610b93565b604080517f69ffa08a000000000000000000000000000000000000000000000000000000008152600160a060020a0385811660048301528481166024830152915192909116916369ffa08a9160448082019260009290919082900301818387803b158015611bd657600080fd5b505af1158015611bea573d6000803e3d6000fd5b505050505050565b6000610b9d6000805160206149a683398151915261320e565b6000806000806000611c1b612973565b9350611c256115ae565b9250611c37611c32610daa565b610be2565b9150818311611c47576000611c4b565b8183035b9050808410611c5a5780611c5c565b835b94505050505090565b7f5a74bb7e202fb8e4bf311841c7d64ec19df195fee77d7e7ae749b27921b6ddfe60005260026020527fab54f3fbbe62c59b7876a9bf9bd5e0c22dbae93f4d8ee0438f7ce62b198eb0e054600160a060020a031690565b6000806000611cc9611c65565b600160a060020a031663facd743b336040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b158015611d2357600080fd5b505af1158015611d37573d6000803e3d6000fd5b505050506040513d6020811015611d4d57600080fd5b50511515611d5a57600080fd5b604080516c01000000000000000000000000600160a060020a0389160260208083019190915260348201889052605480830188905283518084039091018152607490920192839052815191929182918401908083835b60208310611dcf5780518252601f199092019160209182019101611db0565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250611e07856118f8565b15611fae57604080516c010000000000000000000000003302602080830191909152603480830187905283518084039091018152605490920192839052815191929182918401908083835b60208310611e715780518252601f199092019160209182019101611e52565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209150611ea98261167f565b15611eb357600080fd5b611ebe82600161331d565b611ec7836115fc565b9050611ed281612a0f565b15611edc57600080fd5b600101611ee983826133a0565b60408051858152905133917f5df9cc3eb93d8a9a481857a3b70a8ca966e6b80b25cf0ee2cce180ec5afa80a1919081900360200190a2611f27611990565b8110611fa957611f3f83611f3a83613024565b6133a0565b6000851115611f5f57611f5486868686613422565b1515611f5f57600080fd5b60408051600160a060020a03881681526020810187905280820186905290517f6fc115a803b8703117d9a3956c5a15401cb42401f91630f015eb6b043fa762539181900360600190a15b611bea565b611bea86868686613544565b7fb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b060009081526020527fe66bef0282a446f9848e2903380099bb6e431483ee78778868f33b4a154c818b5490565b600560026000909192565b7f145286dc85799b6fb9fe322391ba2d95683077b2adf34dd576dedc437e537ba760009081526020527fba10c7a68bf463c41368d64adcf7df23c0de931ea3b09f061e2dfec302fef95f5490565b612069611a08565b600160a060020a0316331461207d57600080fd5b60008111801561209357506120906115ae565b81105b80156120a557506120a2612973565b81105b15156120b057600080fd5b7fbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d160009081526020527f8df5c48c6b6e11d97548adc824ba0c99103ec09830fa5d53a179984085e6eaa055565b600080612108612a50565b905033600160a060020a0382161461211f57600080fd5b61212885612811565b151561213357600080fd5b61214461213e610daa565b866135e3565b61218081878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843750613669945050505050565b50600195945050505050565b600080600080600080600030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156121d557600080fd5b505af11580156121e9573d6000803e3d6000fd5b505050506040513d60208110156121ff57600080fd5b5051600160a060020a0316331461221557600080fd5b61221e8a6115fc565b965061222987612a0f565b1561223357600080fd5b61223c8a6136e3565b9096509450600160a060020a038616158015906122595750600085115b80156122655750878510155b151561227057600080fd5b61229061228b8961227f612013565b9063ffffffff61386a16565b61387c565b6122a0858963ffffffff61386a16565b93506122ac848b6138c9565b604080518981526020810186905281518c927f5bcec6564fe8d2cbb4e4eb8237510ceb6b291a5c2ee2e429948d25e9c924c1fa928290030190a28815612391576122f4612973565b88111561230057600080fd5b61230861258d565b9250879150600160a060020a0383161561234c57612337886000856000805160206149a683398151915261394b565b9050612349888263ffffffff61386a16565b91505b60408051600160a060020a03881681526020810184905281517f127650bcfb0ba017401abe4931453a405140a8fd36fece67bae2db174d3fdd63929181900390910190a15b50505050505050505050565b6123a5611a08565b600160a060020a031633146123b957600080fd5b610bdf816139dc565b6123ca611a08565b600160a060020a031633146123de57600080fd5b6123e6612973565b8111806123f1575080155b15156123fc57600080fd5b7f4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a5600090815260209081527f1ab29a5cca988aee50edccdd61c5bcaa7ad4b29a03b7ee50f298ceccfe14cc4e8290556040805183815290517fad4123ae17c414d9c6d2fec478b402e6b01856cc250fd01fbfd252fda0089d3c929181900390910190a150565b61248a611a08565b600160a060020a0316331461249e57600080fd5b610bdf81613a6f565b6124af611a08565b600160a060020a031633146124c357600080fd5b8015806124e757506124d36125e4565b811180156124e757506124e46115ae565b81105b15156124f257600080fd5b7f0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c60009081526020527f9de0f81379b4d8e60fe509315d071b56e7b732abaf193e74e0d15808b0951d0955565b7f1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee560009081526020527fd5c78dd9468716ca9bb96be25d56436811b20aab3523a9904b12deef1cab239d5490565b7f779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e560005260026020527fc155b21a14c4592b97825e495fbe0d2705fb46420018cac5bfa7a09c43fae51754600160a060020a031690565b7fbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d160009081526020527f8df5c48c6b6e11d97548adc824ba0c99103ec09830fa5d53a179984085e6eaa05490565b6040805160048152602481018252602081018051600160e060020a03167f6fde8202000000000000000000000000000000000000000000000000000000001781529151815160009330939291829190808383895b8381101561269e578181015183820152602001612686565b50505050905090810190601f1680156126cb5780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af1915050158061275d575030600160a060020a0316636fde82026040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561272557600080fd5b505af1158015612739573d6000803e3d6000fd5b505050506040513d602081101561274f57600080fd5b5051600160a060020a031633145b8061276757503330145b151561277257600080fd5b6127f28b8b600380602002604051908101604052809291908260036020028082843782019150505050508b8b8b8b600280602002604051908101604052809291908260026020028082843782019150505050508b8b8b6002806020026040519081016040528092919082600260200280828437508f9350613af592505050565b6127fa6131a4565b612802610c99565b9b9a5050505050505050505050565b6000806128238361190f611c32610daa565b90508061282e6115ae565b10158015612843575061283f612973565b8311155b801561193b57506128526125e4565b9092101592915050565b612864611a08565b600160a060020a0316331461287857600080fd5b612880610e2f565b811061288b57600080fd5b7fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d560009081526020527ff8e983ee86e5e377e9e34c9131b266382c3f04113d20de077f9e12663c7a646b55565b604080516004815260248101909152602081018051600160e060020a03167ff2ba9561000000000000000000000000000000000000000000000000000000001790526000908161292661258d565b9050600460008351602085016000855af28060203d1416156129485760005193505b50505090565b612956611a08565b600160a060020a0316331461296a57600080fd5b610bdf81613bc5565b7f0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c60009081526020527f9de0f81379b4d8e60fe509315d071b56e7b732abaf193e74e0d15808b0951d095490565b7f55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b60009081526020527ff7d5eefab3776d7f0450bd0193564bcb4f832ce313ff2836c450fc63a4b944195490565b7f80000000000000000000000000000000000000000000000000000000000000009081161490565b6000610b9d60008051602061498683398151915261320e565b7fa8b0ade3e2b734f043ce298aca4cc8d19d74270223f34531d0988b7d00cba21d60005260026020527f603cd9dcbfa185d5c37504f4c8b3f16117ed744fba48d08b7aad44a162af1c9354600160a060020a031690565b6000816000805160206149a6833981519152811480612ad3575060008051602061498683398151915281145b1515612ade57600080fd5b6000805160206149a68339815191528314612b19577f286c406600000000000000000000000000000000000000000000000000000000612b3b565b7f34a9e148000000000000000000000000000000000000000000000000000000005b6040805160248082018890528251808303909101815260449091018252602081018051600160e060020a03167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19851617815291518151939550600160a060020a038916939192909182919080838360005b83811015612bc1578181015183820152602001612ba9565b50505050905090810190601f168015612bee5780820380516001836020036101000a031916815260200191505b50915050600060405180830381855af49150501515612c0c57600080fd5b5050505050565b606890565b6000903b1190565b6000612c2a612c13565b8251149050919050565b60008060008086516041141515612c4a57600080fd5b505050602084015160408501516060860151601b60ff60f860020a8304161480612c7d5750601c60ff60f860020a830416145b1515612c8857600080fd5b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115612cb557600080fd5b6001612cc18787613c9c565b60408051600080825260208083018085529490945260ff60f860020a870416828401526060820188905260808201879052915160a08083019493601f198301938390039091019190865af1158015612d1d573d6000803e3d6000fd5b5050604051601f19015198975050505050505050565b80600360008460405160200180807f6d6573736167657300000000000000000000000000000000000000000000000081525060080182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612db75780518252601f199092019160209182019101612d98565b51815160001960209485036101000a01908116901991909116179052604080519490920184900390932086528583019690965250929093016000208451612e059591945092019190506148ed565b505050565b80600460008460405160200180807f6d657373616765735369676e6564000000000000000000000000000000000000815250600e0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612e8e5780518252601f199092019160209182019101612e6f565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff1916941515949094179093555050505050565b80600360008460405160200180807f7369676e61747572657300000000000000000000000000000000000000000000815250600a01826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612db75780518252601f199092019160209182019101612d98565b806000808460405160200180807f6e756d4d657373616765735369676e656400000000000000000000000000000081525060110182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310612fe25780518252601f199092019160209182019101612fc3565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050565b7f80000000000000000000000000000000000000000000000000000000000000001790565b60008060008061305761258d565b9350600160a060020a03841615612c0c5761307185613eb6565b509350935050613095836001866000805160206149a683398151915260010261394b565b9050612c0c818584613ef1565b6130aa610c99565b156130b457600080fd5b6130bd88612c18565b15156130c857600080fd5b7fab54f3fbbe62c59b7876a9bf9bd5e0c22dbae93f4d8ee0438f7ce62b198eb0e0805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038a161790557fb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b06000908152602052437fe66bef0282a446f9848e2903380099bb6e431483ee78778868f33b4a154c818b5561316487613fff565b61316d86613a6f565b613176856139dc565b61317f8361415c565b61318881614231565b61319182613bc5565b61319a8461429a565b5050505050505050565b7f0a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba60005260046020527f078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc805460ff19166001179055565b8181018281101561320857fe5b92915050565b600080806060846000805160206149a683398151915281148061323e575060008051602061498683398151915281145b151561324957600080fd5b61325161258d565b93506000805160206149a6833981519152861461328e577fffd66196000000000000000000000000000000000000000000000000000000006132b0565b7f94da17cd000000000000000000000000000000000000000000000000000000005b60408051600481526024810190915260208082018051600160e060020a03167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19851617815282519396509194509160009182885af28060203d1416156133135760005195505b5050505050919050565b80600460008460405160200180807f61666669726d6174696f6e735369676e65640000000000000000000000000000815250601201826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612e8e5780518252601f199092019160209182019101612e6f565b806000808460405160200180807f6e756d41666669726d6174696f6e735369676e65640000000000000000000000815250601501826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612fe25780518252601f199092019160209182019101612fc3565b6000806000806134328588614325565b61344361343d610daa565b8861436c565b61344c876143f2565b925061345661258d565b9150600160a060020a038216156134a2576134828360008460008051602061498683398151915261394b565b905061348f818388614405565b61349f838263ffffffff61386a16565b92505b6134aa610b93565b600160a060020a03166340c10f1989856040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b15801561350c57600080fd5b505af1158015613520573d6000803e3d6000fd5b505050506040513d602081101561353657600080fd5b505198975050505050505050565b600080613550836136e3565b9092509050600160a060020a03821615801561356a575080155b151561357557600080fd5b61358461228b8661190f612013565b61358f868685614513565b60408051600160a060020a038816815260208101879052808201859052905185917f26c0a209907d8e06e55b84dfc43d1429e22a3bab2b4f9cfd49d5f7f447a42c4f919081900360600190a2505050505050565b6135f08161190f84610be2565b6000808460405160200180807f746f74616c5370656e745065724461790000000000000000000000000000000081525060100182815260200191505060405160208183030381529060405260405180828051906020019080838360208310612fe25780518252601f199092019160209182019101612fc3565b83600160a060020a03166342966c68836040518263ffffffff1660e060020a02815260040180828152602001915050600060405180830381600087803b1580156136b257600080fd5b505af11580156136c6573d6000803e3d6000fd5b505050506136dd6136d78483614609565b83614663565b50505050565b600080600260008460405160200180807f74784f75744f664c696d6974526563697069656e74000000000000000000000081525060150182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106137695780518252601f19909201916020918201910161374a565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652858101969096525092830160009081205484517f74784f75744f664c696d697456616c75650000000000000000000000000000008188015260318082018b9052865180830390910181526051909101958690528051600160a060020a0390921698509195869592945091925082918401908083835b602083106138275780518252601f199092019160209182019101613808565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054949694955050505050565b60008282111561387657fe5b50900390565b7f145286dc85799b6fb9fe322391ba2d95683077b2adf34dd576dedc437e537ba760009081526020527fba10c7a68bf463c41368d64adcf7df23c0de931ea3b09f061e2dfec302fef95f55565b816000808360405160200180807f74784f75744f664c696d697456616c7565000000000000000000000000000000815250601101826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310612fe25780518252601f199092019160209182019101612fc3565b60408051602481018690528415156044820152606480820184905282518083039091018152608490910190915260208181018051600160e060020a03167f9862f26f000000000000000000000000000000000000000000000000000000001781528251600093929184919082885af28060203d1416600181146139cd57600080fd5b50506000519695505050505050565b600081116139e957600080fd5b7f916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d79407230071600090815260209081527fd2ea0feb732edb0ffe32efd33a6b9d24d46b16eb34a4d07ce256537b6f131e428290556040805183815290517f4fb76205cd57c896b21511d2114137d8e901b4ccd659e1a0f97d6306795264fb929181900390910190a150565b7f55b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b600090815260209081527ff7d5eefab3776d7f0450bd0193564bcb4f832ce313ff2836c450fc63a4b944198290556040805183815290517f52264b89e0fceafb26e79fd49ef8a366eb6297483bf4035b027f0c99a7ad512e929181900390910190a150565b613b058a8a8a8a8a8a8a886130a2565b613b0e83612c18565b1515613b1957600080fd5b7f779a349c5bee7817f04c960f525ee3e2f2516078c38c68a3149787976ee837e560005260026020527fc155b21a14c4592b97825e495fbe0d2705fb46420018cac5bfa7a09c43fae517805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0385161790558151613ba59084906000805160206149a6833981519152612aa7565b612391838360016020020151600080516020614986833981519152612aa7565b600160a060020a0381161515613bda57600080fd5b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0613c03611a08565b60408051600160a060020a03928316815291841660208301528051918290030190a17f02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c060005260026020527fb7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b60408051808201909152601a81527f19457468657265756d205369676e6564204d6573736167653a0a000000000000602082015260009060608315613e425781613ce686516146fb565b866040516020018084805190602001908083835b60208310613d195780518252601f199092019160209182019101613cfa565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b60208310613d615780518252601f199092019160209182019101613d42565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310613da95780518252601f199092019160209182019101613d8a565b6001836020036101000a03801982511681845116808217855250505050505090500193505050506040516020818303038152906040526040518082805190602001908083835b60208310613e0e5780518252601f199092019160209182019101613def565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250613eae565b6040805190810160405280600381526020017f3130340000000000000000000000000000000000000000000000000000000000815250905081818660405160200180848051906020019080838360208310613d195780518252601f199092019160209182019101613cfa565b505092915050565b600080600080613ec585612c20565b1515613ed057600080fd5b50505050601481015160348201516054830151606890930151919390929190565b6000831115612e05576040805160248082018690528251808303909101815260449091018252602081018051600160e060020a03167f59d784640000000000000000000000000000000000000000000000000000000017815291518151600160a060020a03861693829180838360005b83811015613f79578181015183820152602001613f61565b50505050905090810190601f168015613fa65780820380516001836020036101000a031916815260200191505b50915050600060405180830381855af49150501515613fc457600080fd5b60408051848152905182917f858abdcd5efcaebb936e8e8516f0cfe9a0ef5157ff99d16cdabb6db625be90d0919081900360200190a2505050565b6040810151600010801561401a575060408101516020820151115b801561402a575060208101518151115b151561403557600080fd5b80517f4a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a5600090815260208181527f1ab29a5cca988aee50edccdd61c5bcaa7ad4b29a03b7ee50f298ceccfe14cc4e92909255908201517f0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c82527f9de0f81379b4d8e60fe509315d071b56e7b732abaf193e74e0d15808b0951d095560408201517fbbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d182527f8df5c48c6b6e11d97548adc824ba0c99103ec09830fa5d53a179984085e6eaa0557fad4123ae17c414d9c6d2fec478b402e6b01856cc250fd01fbfd252fda0089d3c9082905b60200201516040518082815260200191505060405180910390a150565b805160208201511061416d57600080fd5b80517f21dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d237600090815260208181527fadd938dbd083a16bae12238cd914fca0afc7a30edb55b1cd5c7f1823f1b0e42192909255908201517fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d582527ff8e983ee86e5e377e9e34c9131b266382c3f04113d20de077f9e12663c7a646b557f9bebf928b90863f24cc31f726a3a7545efd409f1dcf552301b1ee3710da70d3b90829061413f565b604c19811380156142425750604d81125b151561424d57600080fd5b7f1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee560009081526020527fd5c78dd9468716ca9bb96be25d56436811b20aab3523a9904b12deef1cab239d55565b6142a381612c18565b15156142ae57600080fd5b7fa8b0ade3e2b734f043ce298aca4cc8d19d74270223f34531d0988b7d00cba21d60005260026020527f603cd9dcbfa185d5c37504f4c8b3f16117ed744fba48d08b7aad44a162af1c93805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600080614331846136e3565b9092509050600160a060020a038216156136dd5780831461435157600080fd5b61435d60008086614513565b6136dd61228b8461227f612013565b6143798161190f84610fe5565b6000808460405160200180807f746f74616c45786563757465645065724461790000000000000000000000000081525060130182815260200191505060405160208183030381529060405260405180828051906020019080838360208310612fe25780518252601f199092019160209182019101612fc3565b60006132088261440061253f565b614806565b6000831115612e05576040805160248082018690528251808303909101815260449091018252602081018051600160e060020a03167f054d46ec0000000000000000000000000000000000000000000000000000000017815291518151600160a060020a03861693829180838360005b8381101561448d578181015183820152602001614475565b50505050905090810190601f1680156144ba5780820380516001836020036101000a031916815260200191505b50915050600060405180830381855af491505015156144d857600080fd5b60408051848152905182917fa52d3c9cbc541772e4edd92e2e4e2a3865ab73630f25deed8a6c8de41ff0f65c919081900360200190a2505050565b82600260008360405160200180807f74784f75744f664c696d6974526563697069656e74000000000000000000000081525060150182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106145975780518252601f199092019160209182019101614578565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03959095169490941790935550612e059150839050826138c9565b805182906000101561320857815160141461462357600080fd5b61462c82614851565b9050600160a060020a038116151561464357600080fd5b61464b614858565b600160a060020a038281169116141561320857600080fd5b8060008061466f61258d565b9150600160a060020a038216156146b05761469b836000846000805160206149a683398151915261394b565b90506146ad838263ffffffff61386a16565b92505b60408051600160a060020a03871681526020810185905281517f127650bcfb0ba017401abe4931453a405140a8fd36fece67bae2db174d3fdd63929181900390910190a15050505050565b606060008082818515156147445760408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015294506147fd565b8593505b831561475f57600190920191600a84049350614748565b826040519080825280601f01601f19166020018201604052801561478d578160200160208202803883390190505b5091505060001982015b85156147f957815160001982019160f860020a6030600a8a0601029184919081106147be57fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a86049550614797565b8194505b50505050919050565b6000811515614816575081613208565b600082131561483a5761483383600a84900a63ffffffff6148af16565b9050613208565b61193b836000849003600a0a63ffffffff6148d816565b6014015190565b7f71483949fe7a14d16644d63320f24d10cf1d60abecc30cc677a340e82b699dd260005260026020527f21ffdf150a5d180f96d98d16f50e7b4dd63e2a067adc8386cf5af55dcecd8dd954600160a060020a031690565b60008215156148c057506000613208565b508181028183828115156148d057fe5b041461320857fe5b600081838115156148e557fe5b049392505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061492e57805160ff191683800117855561495b565b8280016001018555821561495b579182015b8281111561495b578251825591602001919060010190614940565b5061496792915061496b565b5090565b610ba091905b8082111561496757600081556001016149715600deb7f3adca07d6d1f708c1774389db532a2b2f18fd05a62b957e4089f4696ed589d93e5e92f7e37e490c25f0e50f7f4aad7cc94b308a566553280967be38bcf1a165627a7a723058202d2448c9f186eda736b5ea4043924c1b5b124b1cca5e982428da1cf4bcb725780029