ETH Price: $2,027.83 (+1.64%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
XDaiForeignBridge

Compiler Version
v0.4.24+commit.e67f0147

Optimization Enabled:
Yes with 10 runs

Other Settings:
constantinople EvmVersion
pragma solidity 0.4.24;

import "./ForeignBridgeErcToNative.sol";
import "./SavingsDaiConnector.sol";
import "../GSNForeignERC20Bridge.sol";
import "../../interfaces/IDaiUsds.sol";

contract XDaiForeignBridge is ForeignBridgeErcToNative, SavingsDaiConnector, GSNForeignERC20Bridge {
    address public constant DAI_USDS = 0x3225737a9Bbb6473CB4a45b7244ACa2BeFdB276A;
    address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
    address public constant USDS = 0xdC035D45d973E3EC169d2276DDab16f1e407384F;

    function initialize(
        address _validatorContract,
        address _erc20token,
        uint256 _requiredBlockConfirmations,
        uint256 _gasPrice,
        uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
        uint256[2] _homeDailyLimitHomeMaxPerTxArray, //[ 0 = _homeDailyLimit, 1 = _homeMaxPerTx ]
        address _owner,
        int256 _decimalShift,
        address _bridgeOnOtherSide
    ) external onlyRelevantSender returns (bool) {
        require(!isInitialized());
        require(AddressUtils.isContract(_validatorContract));
        require(_erc20token == address(daiToken()));
        require(_decimalShift == 0);

        addressStorage[VALIDATOR_CONTRACT] = _validatorContract;
        uintStorage[DEPLOYED_AT_BLOCK] = block.number;
        _setRequiredBlockConfirmations(_requiredBlockConfirmations);
        _setGasPrice(_gasPrice);
        _setLimits(_dailyLimitMaxPerTxMinPerTxArray);
        _setExecutionLimits(_homeDailyLimitHomeMaxPerTxArray);
        _setOwner(_owner);
        _setBridgeContractOnOtherSide(_bridgeOnOtherSide);
        setInitialize();

        return isInitialized();
    }

    /**
     * @dev return the address of USDS
     */
    function erc20token() public view returns (ERC20) {
        return ERC20(USDS);
    }

    /**
     * @dev one time function to be called during bridge upgrade
     */
    function swapSDAIToUSDS() public {
        bytes32 isUSDSBridgeUpgrade = keccak256("upgrade_DAI_to_USDS");
        require(!boolStorage[isUSDSBridgeUpgrade], "USDS bridge ugprade completed");

        address sDAI = 0x83F20F44975D03b1b09e64809B757c47f942BEeA;

        // withdraw all sDAI into DAI
        uint256 maxWithdrawable = ISavingsDai(sDAI).maxWithdraw(address(this));
        ISavingsDai(sDAI).withdraw(maxWithdrawable, address(this), address(this));
        // disableInterest for DAI
        _setInvestedAmount(DAI, 0);
        _setInterestEnabled(DAI, false);
        _setMinCashThreshold(DAI, 0);
        _setMinInterestPaid(DAI, 0);

        // swap DAI -> USDS
        uint256 remainDAI = ERC20(DAI).balanceOf(address(this));
        ERC20(DAI).approve(DAI_USDS, remainDAI);
        IDaiUsds(DAI_USDS).daiToUsds(address(this), remainDAI);
        boolStorage[isUSDSBridgeUpgrade] = true;
    }

    /**
     * @dev Withdraws USDS from sUSDS vault to the bridge up to min cash threshold
     */
    function refillBridge() external {
        uint256 currentBalance = ERC20(USDS).balanceOf(address(this));
        uint256 minThreshold = minCashThreshold(USDS);
        require(currentBalance < minThreshold, "Bridge is Filled");
        uint256 withdrawAmount = minThreshold - currentBalance;
        _withdraw(USDS, withdrawAmount);
    }

    /**
     * @dev Invests the USDS into the sUSDS Vault.
     */
    function investDai() external {
        invest(USDS);
    }

    /**
     * @dev Withdraws the erc20 tokens or native coins from this contract.
     * @param _token address of the claimed token or address(0) for native coins.
     * @param _to address of the tokens/coins receiver.
     */
    function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
        // Since bridged tokens are locked at this contract, it is not allowed to claim them with the use of claimTokens function
        address bridgedToken = USDS;
        address sUSDS = 0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD;
        require(_token != bridgedToken, "Can't claim USDS");
        require(_token != sUSDS || !isInterestEnabled(bridgedToken), "Can't claim sUSDS");
        claimValues(_token, _to);
    }

    /**
     * @dev Withdraws the USDS tokens if they are mistakenly sent to this contract after the Hashi integration, as the Transfer event will no longer be supported.
     * @param _to address of the tokens/coins receiver.
     */
    function recoverLegacyTransfer(address _to, uint256 recoverAmount) external onlyIfUpgradeabilityOwner {
        uint256 currentBalance = ERC20(USDS).balanceOf(this);
        uint256 minThreshold = minCashThreshold(USDS);
        require(recoverAmount < currentBalance, "invalid withdraw balance");
        if (currentBalance - recoverAmount < minThreshold) {
            // need to fill the bridge to ensure enough USDS for withdrawal
            uint256 withdrawAmount = minThreshold + recoverAmount - currentBalance;
            _withdraw(USDS, withdrawAmount);
        }
        ERC20(USDS).transfer(_to, recoverAmount);
    }

    /// @dev this function returns DAI/USDS based on _tokenAddress
    function onExecuteMessage(address _recipient, uint256 _amount, bytes32, /*_nonce*/ address _tokenAddress)
        internal
        returns (bool)
    {
        addTotalExecutedPerDay(getCurrentDay(), _amount);

        ERC20 token = ERC20(USDS);
        ensureEnoughTokens(token, _amount);

        if (_tokenAddress == DAI) {
            token.approve(DAI_USDS, _amount);
            IDaiUsds(DAI_USDS).usdsToDai(address(this), _amount);
            return ERC20(DAI).transfer(_recipient, _amount);
        } else if (_tokenAddress == USDS) {
            return token.transfer(_recipient, _amount);
        } else {
            revert();
        }
    }

    function onExecuteMessageGSN(address recipient, uint256 amount, uint256 fee) internal returns (bool) {
        ensureEnoughTokens(ERC20(USDS), amount);

        return super.onExecuteMessageGSN(recipient, amount, fee);
    }

    function ensureEnoughTokens(ERC20 token, uint256 amount) internal {
        uint256 currentBalance = token.balanceOf(address(this));

        if (currentBalance < amount) {
            uint256 withdrawAmount = (amount - currentBalance).add(minCashThreshold(address(token)));
            _withdraw(address(token), withdrawAmount);
        }
    }
}

pragma solidity 0.4.24;

import "../ERC20Bridge.sol";
import "../OtherSideBridgeStorage.sol";

contract ForeignBridgeErcToNative is ERC20Bridge, OtherSideBridgeStorage {
    function initialize(
        address _validatorContract,
        address _erc20token,
        uint256 _requiredBlockConfirmations,
        uint256 _gasPrice,
        uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
        uint256[2] _homeDailyLimitHomeMaxPerTxArray, //[ 0 = _homeDailyLimit, 1 = _homeMaxPerTx ]
        address _owner,
        int256 _decimalShift,
        address _bridgeOnOtherSide
    ) external onlyRelevantSender returns (bool) {
        require(!isInitialized());
        require(AddressUtils.isContract(_validatorContract));

        addressStorage[VALIDATOR_CONTRACT] = _validatorContract;
        setErc20token(_erc20token);
        uintStorage[DEPLOYED_AT_BLOCK] = block.number;
        _setRequiredBlockConfirmations(_requiredBlockConfirmations);
        _setGasPrice(_gasPrice);
        _setLimits(_dailyLimitMaxPerTxMinPerTxArray);
        _setExecutionLimits(_homeDailyLimitHomeMaxPerTxArray);
        _setDecimalShift(_decimalShift);
        _setOwner(_owner);
        _setBridgeContractOnOtherSide(_bridgeOnOtherSide);
        setInitialize();

        return isInitialized();
    }

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

    /**
     * @dev Withdraws the erc20 tokens or native coins from this contract.
     * @param _token address of the claimed token or address(0) for native coins.
     * @param _to address of the tokens/coins receiver.
     */
    function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
        // Since bridged tokens are locked at this contract, it is not allowed to claim them with the use of claimTokens function
        require(_token != address(erc20token()), "Bridged Token is disallowed");
        claimValues(_token, _to);
    }

    function onExecuteMessage(
        address _recipient,
        uint256 _amount,
        bytes32, /*_nonce*/
        address _tokenAddress
    ) internal returns (bool) {
        require(_tokenAddress == address(erc20token()));
        addTotalExecutedPerDay(getCurrentDay(), _amount);
        return erc20token().transfer(_recipient, _unshiftValue(_amount));
    }

    function onFailedMessage(address, uint256, bytes32) internal {
        revert();
    }

    function relayTokens(address _receiver, uint256 _amount) public {
        require(_receiver != bridgeContractOnOtherSide(), "Relayed to Bridge address");
        require(_receiver != address(0), "Relayed to Null address");
        require(_receiver != address(this), "Relayed to this address");
        require(_amount > 0, "Relayed zero funds");
        require(withinLimit(_amount), "Exceeds bridge daily limit");
        addTotalSpentPerDay(getCurrentDay(), _amount);
        erc20token().transferFrom(msg.sender, address(this), _amount);
        _emitUserRequestForAffirmationIncreaseNonceAndMaybeSendDataWithHashi(_receiver, _amount);
    }
}

pragma solidity 0.4.24;

import "./InterestConnector.sol";
import "../../interfaces/ISavingsDai.sol";

/**
 * @title SavingsDaiConnector
 * @dev After the usds upgrade, this contract deposit locked USDS into Sky's SSR.
 * @dev The contract and functions name in this contract remains unchanged but the value of daiToken() and sDaiToken() are changed to Usds and sUsds address respectively.
 * @dev https://forum.gnosis.io/t/gip-118-should-sdai-be-replaced-by-susds-in-the-bridge/9354
 * @dev This must never be deployed standalone and only as an interface to interact with the sUSDS from the InterestConnector
 */
contract SavingsDaiConnector is InterestConnector {
    /**
     * @dev After the usds upgrade, this function returns the address of the USDS token in the Ethereum Mainnet instead of DAI token address.
     * @dev To minimize the changes on the bridge contract itself, the same function name is used but the address is changed. One should be aware when interacting with the contract.
     */
    function daiToken() public pure returns (ERC20) {
        return ERC20(0xdC035D45d973E3EC169d2276DDab16f1e407384F);
    }

    /**
     * @dev After the usds upgrade, this function returns the address of the sUSDS token in the Ethereum Mainnet instead of sDAI token address.
     * @dev To minimize the changes on the bridge contract itself, the same function name is used but the address is changed. One should be aware when interacting with the contract.
     */
    function sDaiToken() public pure returns (ISavingsDai) {
        return ISavingsDai(0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD);
    }

    /**
     * @dev Tells the current earned interest amount.
     * @param _token address of the underlying token contract.
     * @return total amount of interest that can be withdrawn now.
     */
    function interestAmount(address _token) public view returns (uint256) {
        require(_token == 0xdC035D45d973E3EC169d2276DDab16f1e407384F, "Not USDS");
        uint256 underlyingBalance = ISavingsDai(0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD).maxWithdraw(address(this));
        // 1 DAI is reserved for possible truncation/round errors
        uint256 invested = investedAmount(_token) + 1 ether;
        return underlyingBalance > invested ? underlyingBalance - invested : 0;
    }

    /**
     * @dev Tells if interest earning is supported for the specific token contract.
     * @param _token address of the token contract.
     * @return true, if interest earning is supported.
     */
    function _isInterestSupported(address _token) internal pure returns (bool) {
        return _token == 0xdC035D45d973E3EC169d2276DDab16f1e407384F;
    }

    /**
     * @dev Invests the given amount of DAI to the sDAI Vault.
     * Deposits _amount of _token into the sDAI vault.
     * @param _token address of the token contract.
     * @param _amount amount of tokens to invest.
     */
    function _invest(address _token, uint256 _amount) internal {
        require(_token == 0xdC035D45d973E3EC169d2276DDab16f1e407384F, "not USDS");
        ERC20(0xdC035D45d973E3EC169d2276DDab16f1e407384F).approve(0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD, _amount);
        require(
            ISavingsDai(0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD).deposit(_amount, address(this)) > 0,
            "Failed to deposit"
        );
    }

    /**
     * @dev Withdraws at least the given amount of USDS from the sUSDS vault contract.
     * Withdraws the _amount of _token from the sUSDS vault.
     * @param _token address of the token contract.
     * @param _amount minimal amount of tokens to withdraw.
     */
    function _withdrawTokens(address _token, uint256 _amount) internal {
        require(_token == 0xdC035D45d973E3EC169d2276DDab16f1e407384F, "not USDS");
        require(
            ISavingsDai(0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD).withdraw(_amount, address(this), address(this)) > 0,
            "Failed to withdraw"
        );
    }

    /**
     * @dev Previews a withdraw of the given amount of DAI from the sDAI vault contract.
     * Previews withdrawing the _amount of _token from the sDAI vault.
     * @param _token address of the token contract.
     * @param _amount minimal amount of tokens to withdraw.
     */
    function previewWithdraw(address _token, uint256 _amount) public view returns (uint256) {
        require(_token == 0xdC035D45d973E3EC169d2276DDab16f1e407384F, "not USDS");
        return ISavingsDai(0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD).previewWithdraw(_amount);
    }
}

pragma solidity 0.4.24;

import "./BasicForeignBridge.sol";
import "./ERC20Bridge.sol";
import "../gsn/BaseRelayRecipient.sol";
import "../gsn/interfaces/IKnowForwarderAddress.sol";

contract GSNForeignERC20Bridge is BasicForeignBridge, ERC20Bridge, BaseRelayRecipient, IKnowForwarderAddress {
    bytes32 internal constant PAYMASTER = 0xfefcc139ed357999ed60c6a013947328d52e7d9751e93fd0274a2bfae5cbcb12; // keccak256(abi.encodePacked("paymaster"))
    bytes32 internal constant TRUSTED_FORWARDER = 0x222cb212229f0f9bcd249029717af6845ea3d3a84f22b54e5744ac25ef224c92; // keccak256(abi.encodePacked("trustedForwarder"))

    function versionRecipient() external view returns (string memory) {
        return "1.0.1";
    }

    function getTrustedForwarder() external view returns (address) {
        return addressStorage[TRUSTED_FORWARDER];
    }

    function setTrustedForwarder(address _trustedForwarder) public onlyOwner {
        addressStorage[TRUSTED_FORWARDER] = _trustedForwarder;
    }

    function isTrustedForwarder(address forwarder) public view returns (bool) {
        return forwarder == addressStorage[TRUSTED_FORWARDER];
    }

    function setPayMaster(address _paymaster) public onlyOwner {
        addressStorage[PAYMASTER] = _paymaster;
    }

    /**
    * @param message same as in `executeSignatures`
    * @param signatures same as in `executeSignatures`
    * @param maxTokensFee maximum amount of foreign tokens that user allows to take
    * as a commission
    */
    function executeSignaturesGSN(bytes message, bytes signatures, uint256 maxTokensFee) external {
        // Allow only forwarder calls
        require(isTrustedForwarder(msg.sender), "invalid forwarder");
        Message.hasEnoughValidSignatures(message, signatures, validatorContract(), false);

        address recipient;
        uint256 amount;
        bytes32 txHash;
        address contractAddress;
        address tokenAddress;
        (recipient, amount, txHash, contractAddress, tokenAddress) = Message.parseMessage(message);
        require(tokenAddress == address(erc20token()));
        if (withinExecutionLimit(amount)) {
            require(maxTokensFee <= amount);
            require(contractAddress == address(this));
            require(!relayedMessages(txHash));
            setRelayedMessages(txHash, true);
            require(onExecuteMessageGSN(recipient, amount, maxTokensFee));
            emit RelayedMessage(recipient, amount, txHash);
        } else {
            onFailedMessage(recipient, amount, txHash);
        }
    }

    function onExecuteMessageGSN(address recipient, uint256 amount, uint256 fee) internal returns (bool) {
        addTotalExecutedPerDay(getCurrentDay(), amount);
        // Send maxTokensFee to paymaster
        ERC20 token = erc20token();
        bool first = token.transfer(addressStorage[PAYMASTER], fee);
        bool second = token.transfer(recipient, amount - fee);

        return first && second;
    }
}

// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.4.24;

interface IDaiUsds {
    event DaiToUsds(address indexed caller, address indexed usr, uint256 wad);
    event UsdsToDai(address indexed caller, address indexed usr, uint256 wad);

    function daiToUsds(address usr, uint256 wad) external;

    function usdsToDai(address usr, uint256 wad) external;

    function dai() external view returns (address);
    function usds() external view returns (address);
}

pragma solidity 0.4.24;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
import "./BasicForeignBridge.sol";

contract ERC20Bridge is BasicForeignBridge {
    bytes32 internal constant ERC20_TOKEN = 0x15d63b18dbc21bf4438b7972d80076747e1d93c4f87552fe498c90cbde51665e; // keccak256(abi.encodePacked("erc20token"))

    function erc20token() public view returns (ERC20) {
        return ERC20(addressStorage[ERC20_TOKEN]);
    }

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

    function relayTokens(address _receiver, uint256 _amount) public {
        require(_receiver != address(0), "Receiver can't be Null");
        require(_receiver != address(this), "Receiver can't be the Bridge");
        require(_amount > 0, "Relayed zero tokens");
        require(withinLimit(_amount), "Relayed above limit");
        addTotalSpentPerDay(getCurrentDay(), _amount);
        erc20token().transferFrom(msg.sender, address(this), _amount);
        _emitUserRequestForAffirmationIncreaseNonceAndMaybeSendDataWithHashi(_receiver, _amount);
    }

    function _relayInterest(address _receiver, uint256 _amount) internal {
        require(_receiver != address(0), "Receiver can't be Null");
        require(_receiver != address(this), "Receiver can't be the Bridge");
        require(_amount > 0, "Relayed zero tokens");
        require(withinLimit(_amount), "Relayed above limit");
        addTotalSpentPerDay(getCurrentDay(), _amount);
        _emitUserRequestForAffirmationIncreaseNonceAndMaybeSendDataWithHashi(_receiver, _amount);
    }
}

pragma solidity 0.4.24;

import "../upgradeability/EternalStorage.sol";

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];
    }
}

pragma solidity 0.4.24;

import "../Ownable.sol";
import "../ERC20Bridge.sol";
import "../../interfaces/IInterestReceiver.sol";

/**
 * @title InterestConnector
 * @dev This contract gives an abstract way of receiving interest on locked tokens.
 */
contract InterestConnector is Ownable, ERC20Bridge {
    event PaidInterest(address indexed token, address to, uint256 value);

    /**
     * @dev Throws if interest is bearing not enabled.
     * @param token address, for which interest should be enabled.
     */
    modifier interestEnabled(address token) {
        require(isInterestEnabled(token), "Interest not Enabled");
        /* solcov ignore next */
        _;
    }

    /**
     * @dev Ensures that caller is an EOA.
     * Functions with such modifier cannot be called from other contract (as well as from GSN-like approaches)
     */
    modifier onlyEOA() {
        // solhint-disable-next-line avoid-tx-origin
        require(msg.sender == tx.origin, "Not EOA");
        /* solcov ignore next */
        _;
    }

    /**
     * @dev Tells if interest earning was enabled for particular token.
     * @return true, if interest bearing  is enabled.
     */
    function isInterestEnabled(address _token) public view returns (bool) {
        return boolStorage[keccak256(abi.encodePacked("interestEnabled", _token))];
    }

    /**
     * @dev Initializes interest receiving functionality.
     * Only owner can call this method.
     * @param _token address of the token for interest earning.
     * @param _minCashThreshold minimum amount of underlying tokens that are not invested.
     * @param _minInterestPaid minimum amount of interest that can be paid in a single call.
     */
    function initializeInterest(
        address _token,
        uint256 _minCashThreshold,
        uint256 _minInterestPaid,
        address _interestReceiver
    ) external onlyOwner {
        require(_isInterestSupported(_token), "Token not supported");
        require(!isInterestEnabled(_token), "Interest already enabled");

        _setInterestEnabled(_token, true);
        _setMinCashThreshold(_token, _minCashThreshold);
        _setMinInterestPaid(_token, _minInterestPaid);
        _setInterestReceiver(_token, _interestReceiver);
    }

    /**
     * @dev Sets minimum amount of tokens that cannot be invested.
     * Only owner can call this method.
     * @param _token address of the token contract.
     * @param _minCashThreshold minimum amount of underlying tokens that are not invested.
     */
    function setMinCashThreshold(address _token, uint256 _minCashThreshold) external onlyOwner {
        _setMinCashThreshold(_token, _minCashThreshold);
    }

    /**
     * @dev Tells minimum amount of tokens that are not being invested.
     * @param _token address of the invested token contract.
     * @return amount of tokens.
     */
    function minCashThreshold(address _token) public view returns (uint256) {
        return uintStorage[keccak256(abi.encodePacked("minCashThreshold", _token))];
    }

    /**
     * @dev Sets lower limit for the paid interest amount.
     * Only owner can call this method.
     * @param _token address of the token contract.
     * @param _minInterestPaid minimum amount of interest paid in a single call.
     */
    function setMinInterestPaid(address _token, uint256 _minInterestPaid) external onlyOwner {
        _setMinInterestPaid(_token, _minInterestPaid);
    }

    /**
     * @dev Tells minimum amount of paid interest in a single call.
     * @param _token address of the invested token contract.
     * @return paid interest minimum limit.
     */
    function minInterestPaid(address _token) public view returns (uint256) {
        return uintStorage[keccak256(abi.encodePacked("minInterestPaid", _token))];
    }

    /**
     * @dev Internal function that disables interest for locked funds.
     * Only owner can call this method.
     * @param _token of token to disable interest for.
     */
    function disableInterest(address _token) external onlyOwner {
        _withdraw(_token, uint256(-1));
        _setInterestEnabled(_token, false);
    }

    /**
     * @dev Tells configured address of the interest receiver.
     * @param _token address of the invested token contract.
     * @return address of the interest receiver.
     */
    function interestReceiver(address _token) public view returns (address) {
        return addressStorage[keccak256(abi.encodePacked("interestReceiver", _token))];
    }

    /**
     * Updates the interest receiver address.
     * Only owner can call this method.
     * @param _token address of the invested token contract.
     * @param _receiver new receiver address.
     */
    function setInterestReceiver(address _token, address _receiver) external onlyOwner {
        _setInterestReceiver(_token, _receiver);
    }

    /**
     * @dev Pays collected interest for the specific underlying token to _reveicer contract on Gnosis Chain 
     *      and reinvests amount claimed.
     * Requires interest for the given token to be enabled.
     * @param _token address of the token contract.
     */
    function payInterest(address _token, uint256 _amount) external interestEnabled(_token) {
        require(_token == address(erc20token()), "Not bridge Token");
        uint256 claimable = interestAmount(_token);
        uint256 interest = (_amount < claimable) ? _amount : claimable;
        require(interest >= minInterestPaid(_token), "Collectable interest too low");

        _setInvestedAmount(_token, investedAmount(_token).add(interest));
        address receiver = interestReceiver(_token);
        _relayInterest(receiver, interest);
        emit PaidInterest(_token, receiver, interest);
    }

    /**
     * @dev Tells the amount of underlying tokens that are currently invested.
     * @param _token address of the token contract.
     * @return amount of underlying tokens.
     */
    function investedAmount(address _token) public view returns (uint256) {
        return uintStorage[keccak256(abi.encodePacked("investedAmount", _token))];
    }

    /**
     * @dev Invests all excess tokens.
     * Requires interest for the given token to be enabled.
     * @param _token address of the token contract considered.
     */
    function invest(address _token) public interestEnabled(_token) {
        uint256 balance = _selfBalance(_token);
        uint256 minCash = minCashThreshold(_token);

        require(balance > minCash, "Balance too Low");
        uint256 amount = balance - minCash;

        _setInvestedAmount(_token, investedAmount(_token).add(amount));

        _invest(_token, amount);
    }

    /**
     * @dev Internal function for transferring interest. Deprecated 
     * Calls a callback on the receiver, if it is a contract.
     * @param _token address of the underlying token contract.
     * @param _amount amount of collected tokens that should be sent.
     */
    function _transferInterest(address _token, uint256 _amount) internal {
        address receiver = interestReceiver(_token);
        require(receiver != address(0), "Receiver can't be Null");

        ERC20(_token).transfer(receiver, _amount);

        if (AddressUtils.isContract(receiver)) {
            IInterestReceiver(receiver).onInterestReceived(_token);
        }

        emit PaidInterest(_token, receiver, _amount);
    }

    /**
     * @dev Internal function for setting interest enabled flag for some token.
     * @param _token address of the token contract.
     * @param _enabled true to enable interest earning, false to disable.
     */
    function _setInterestEnabled(address _token, bool _enabled) internal {
        boolStorage[keccak256(abi.encodePacked("interestEnabled", _token))] = _enabled;
    }

    /**
     * @dev Internal function for setting the amount of underlying tokens that are currently invested.
     * @param _token address of the token contract.
     * @param _amount new amount of invested tokens.
     */
    function _setInvestedAmount(address _token, uint256 _amount) internal {
        uintStorage[keccak256(abi.encodePacked("investedAmount", _token))] = _amount;
    }

    /**
     * @dev Internal function for withdrawing some amount of the invested tokens.
     * Reverts if given amount cannot be withdrawn.
     * @param _token address of the token contract withdrawn.
     * @param _amount amount of requested tokens to be withdrawn.
     */
    function _withdraw(address _token, uint256 _amount) internal {
        uint256 invested = investedAmount(_token);
        uint256 withdrawal = _amount > invested ? invested : _amount;
        if (withdrawal == 0) return;
        uint256 redeemed = _safeWithdrawTokens(_token, withdrawal);

        _setInvestedAmount(_token, invested > redeemed ? invested - redeemed : 0);
    }

    /**
     * @dev Internal function for safe withdrawal of invested tokens.
     * Reverts if given amount cannot be withdrawn.
     * Additionally verifies that at least _amount of tokens were withdrawn.
     * @param _token address of the token contract withdrawn.
     * @param _amount amount of requested tokens to be withdrawn.
     */
    function _safeWithdrawTokens(address _token, uint256 _amount) private returns (uint256) {
        uint256 balance = _selfBalance(_token);

        _withdrawTokens(_token, _amount);

        uint256 redeemed = _selfBalance(_token) - balance;

        require(redeemed >= _amount, "Withdrawn less than Amount");

        return redeemed;
    }

    /**
     * @dev Internal function for setting minimum amount of tokens that cannot be invested.
     * @param _token address of the token contract.
     * @param _minCashThreshold minimum amount of underlying tokens that are not invested.
     */
    function _setMinCashThreshold(address _token, uint256 _minCashThreshold) internal {
        uintStorage[keccak256(abi.encodePacked("minCashThreshold", _token))] = _minCashThreshold;
    }

    /**
     * @dev Internal function for setting lower limit for paid interest amount. Must be lower than DAILY_LIMIT and MAX_PER_TX
     * @param _token address of the token contract.
     * @param _minInterestPaid minimum amount of interest paid in a single call.
     */
    function _setMinInterestPaid(address _token, uint256 _minInterestPaid) internal {
        uintStorage[keccak256(abi.encodePacked("minInterestPaid", _token))] = _minInterestPaid;
    }

    /**
     * @dev Internal function for setting interest receiver address.
     * @param _token address of the invested token contract.
     * @param _receiver address of the interest receiver.
     */
    function _setInterestReceiver(address _token, address _receiver) internal {
        require(_receiver != address(this), "Receiver can't be the Bridge");
        addressStorage[keccak256(abi.encodePacked("interestReceiver", _token))] = _receiver;
    }

    /**
     * @dev Tells this contract balance of some specific token contract
     * @param _token address of the token contract.
     * @return contract balance.
     */
    function _selfBalance(address _token) internal view returns (uint256) {
        return ERC20(_token).balanceOf(address(this));
    }

    function _isInterestSupported(address _token) internal pure returns (bool);

    function _invest(address _token, uint256 _amount) internal;

    function _withdrawTokens(address _token, uint256 _amount) internal;

    function previewWithdraw(address _token, uint256 _amount) public view returns (uint256);

    function interestAmount(address _token) public view returns (uint256);
}

File 9 of 40 : ISavingsDai.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

// Copyright (C) 2021-2022 Dai Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity 0.4.24;

interface ISavingsDai {
    function totalSupply() external view returns (uint256);
    function balanceOf(address) external view returns (uint256);
    function allowance(address, address) external view returns (uint256);
    function approve(address, uint256) external returns (bool);
    function transfer(address, uint256) external returns (bool);
    function transferFrom(address, address, uint256) external returns (bool);
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function version() external view returns (string memory);
    function decimals() external view returns (uint8);
    function deploymentChainId() external view returns (uint256);
    function PERMIT_TYPEHASH() external view returns (bytes32);
    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function nonces(address) external view returns (uint256);
    function vat() external view returns (address);
    function daiJoin() external view returns (address);
    function dai() external view returns (address);
    function pot() external view returns (address);
    function increaseAllowance(address, uint256) external returns (bool);
    function decreaseAllowance(address, uint256) external returns (bool);
    function asset() external view returns (address);
    function totalAssets() external view returns (uint256);
    function convertToShares(uint256) external view returns (uint256);
    function convertToAssets(uint256) external view returns (uint256);
    function maxDeposit(address) external view returns (uint256);
    function previewDeposit(uint256) external view returns (uint256);
    function deposit(uint256, address) external returns (uint256);
    function deposit(uint256, address, uint16) external returns (uint256);
    function maxMint(address) external view returns (uint256);
    function previewMint(uint256) external view returns (uint256);
    function mint(uint256, address) external returns (uint256);
    function mint(uint256, address, uint16) external returns (uint256);
    function maxWithdraw(address) external view returns (uint256);
    function previewWithdraw(uint256) external view returns (uint256);
    function withdraw(uint256, address, address) external returns (uint256);
    function maxRedeem(address) external view returns (uint256);
    function previewRedeem(uint256) external view returns (uint256);
    function redeem(uint256, address, address) external returns (uint256);
    function permit(address, address, uint256, uint256, bytes) external;
    function permit(address, address, uint256, uint256, uint8, bytes32, bytes32) external;
}

pragma solidity 0.4.24;

import "../upgradeability/EternalStorage.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "./Validatable.sol";
import "../libraries/Message.sol";
import "./MessageRelay.sol";
import "./BasicBridge.sol";
import "./BasicTokenBridge.sol";
import "./MessageRelay.sol";

contract BasicForeignBridge is EternalStorage, Validatable, BasicBridge, BasicTokenBridge, MessageRelay {
    /// triggered when relay of deposit from HomeBridge is complete
    event RelayedMessage(address recipient, uint256 value, bytes32 transactionHash);
    event UserRequestForAffirmation(address recipient, uint256 value, bytes32 nonce);

    /**
     * @dev Validates provided signatures and relays a given message
     * @param message bytes to be relayed
     * @param signatures bytes blob with signatures to be validated
     */
    function executeSignatures(bytes message, bytes signatures) external {
        Message.hasEnoughValidSignatures(message, signatures, validatorContract(), false);

        address recipient;
        uint256 amount;
        bytes32 nonce;
        address contractAddress;
        address tokenAddress;
        (recipient, amount, nonce, contractAddress, tokenAddress) = Message.parseMessage(message);
        if (withinExecutionLimit(amount)) {
            require(contractAddress == address(this));
            require(!relayedMessages(nonce));
            setRelayedMessages(nonce, true);

            bytes32 hashMsg = keccak256(abi.encodePacked(recipient, amount, nonce));
            if (HASHI_IS_ENABLED && HASHI_IS_MANDATORY) require(isApprovedByHashi(hashMsg));

            require(onExecuteMessage(recipient, amount, nonce, tokenAddress));
            emit RelayedMessage(recipient, amount, nonce);
        } else {
            onFailedMessage(recipient, amount, nonce);
        }
    }

    function onMessage(
        uint256, /*messageId*/
        uint256 chainId,
        address sender,
        uint256 threshold,
        address[] adapters,
        bytes data
    ) external returns (bytes) {
        _validateHashiMessage(chainId, threshold, sender, adapters);
        bytes32 hashMsg = keccak256(data);
        require(!isApprovedByHashi(hashMsg));
        _setHashiApprovalForMessage(hashMsg, true);
    }

    function _emitUserRequestForAffirmationIncreaseNonceAndMaybeSendDataWithHashi(address _receiver, uint256 _amount)
        internal
    {
        uint256 currentNonce = nonce();
        setNonce(currentNonce + 1);
        emit UserRequestForAffirmation(_receiver, _amount, bytes32(currentNonce));
        _maybeSendDataWithHashi(abi.encodePacked(_receiver, _amount, bytes32(currentNonce)));
    }

    /**
     * @dev Internal function for updating fallback gas price value.
     * @param _gasPrice new value for the gas price, zero gas price is not allowed.
     */
    function _setGasPrice(uint256 _gasPrice) internal {
        require(_gasPrice > 0);
        super._setGasPrice(_gasPrice);
    }

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

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

// SPDX-License-Identifier:MIT
// solhint-disable no-inline-assembly
pragma solidity 0.4.24;

import "./interfaces/IRelayRecipient.sol";

/**
 * A base contract to be inherited by any contract that want to receive relayed transactions
 * A subclass must use "_msgSender()" instead of "msg.sender"
 */
contract BaseRelayRecipient is IRelayRecipient {
    /**
     * return the sender of this call.
     * if the call came through our trusted forwarder, return the original sender.
     * otherwise, return `msg.sender`.
     * should be used in the contract anywhere instead of msg.sender
     */
    function _msgSender() internal view returns (address ret) {
        if (msg.data.length >= 24 && isTrustedForwarder(msg.sender)) {
            // At this point we know that the sender is a trusted forwarder,
            // so we trust that the last bytes of msg.data are the verified sender address.
            // extract sender address from the end of msg.data
            assembly {
                ret := shr(96, calldataload(sub(calldatasize, 20)))
            }
        } else {
            return msg.sender;
        }
    }

    /**
     * return the msg.data of this call.
     * if the call came through our trusted forwarder, then the real sender was appended as the last 20 bytes
     * of the msg.data - so this method will strip those 20 bytes off.
     * otherwise, return `msg.data`
     * should be used in the contract instead of msg.data, where the difference matters (e.g. when explicitly
     * signing or hashing the
     */
    function _msgData() internal view returns (bytes memory ret) {
        if (msg.data.length >= 24 && isTrustedForwarder(msg.sender)) {
            // At this point we know that the sender is a trusted forwarder,
            // we copy the msg.data , except the last 20 bytes (and update the total length)
            assembly {
                let ptr := mload(0x40)
                // copy only size-20 bytes
                let size := sub(calldatasize, 20)
                // structure RLP data as <offset> <length> <bytes>
                mstore(ptr, 0x20)
                mstore(add(ptr, 32), size)
                calldatacopy(add(ptr, 64), 0, size)
                return(ptr, add(size, 64))
            }
        } else {
            return msg.data;
        }
    }
}

File 12 of 40 : IKnowForwarderAddress.sol
// SPDX-License-Identifier:MIT
pragma solidity 0.4.24;

interface IKnowForwarderAddress {
    /**
     * return the forwarder we trust to forward relayed transactions to us.
     * the forwarder is required to verify the sender's signature, and verify
     * the call is not a replay.
     */
    function getTrustedForwarder() external view returns (address);
}

pragma solidity ^0.4.24;

import "./ERC20Basic.sol";


/**
 * @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
  );
}

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 15 of 40 : 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;

}

pragma solidity 0.4.24;

import "../upgradeability/EternalStorage.sol";
import "../interfaces/IUpgradeabilityOwnerStorage.sol";

/**
 * @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;
    }
}

pragma solidity 0.4.24;

interface IInterestReceiver {
    function onInterestReceived(address _token) external;
}

pragma solidity 0.4.24;

import "../interfaces/IBridgeValidators.sol";
import "../upgradeability/EternalStorage.sol";
import "./ValidatorStorage.sol";

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

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

    function _onlyValidator() internal {
        require(validatorContract().isValidator(msg.sender));
    }

}

pragma solidity 0.4.24;

import "../interfaces/IBridgeValidators.sol";

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 116: 20 bytes :: address - contract address to prevent double spending
    // offset 136: 20 bytes :: address - token address

    // 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 nonce, address contractAddress, address tokenAddress)
    {
        require(isMessageValid(message));

        assembly {
            recipient := mload(add(message, 20))
            amount := mload(add(message, 52))
            nonce := mload(add(message, 84))
            contractAddress := mload(add(message, 104))
            tokenAddress := mload(add(message, 124))
        }

        if (message.length == 104) {
            tokenAddress = 0x6B175474E89094C44Da98b954EedeAC495271d0F; // DAI address
        }
    }

    ///@dev original message length is 104. Message with 124 has appended token address.
    function isMessageValid(bytes _msg) internal pure returns (bool) {
        return _msg.length == 104 || _msg.length == 124; 
    }

    function recoverAddressFromSignedMessage(bytes signature, bytes message, bool isAMBMessage)
        internal
        pure
        returns (address)
    {

        require(isMessageValid(message));
        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;
            if (message.length == 104) {
                msgLength = "104";
            }else if(message.length == 124){
                msgLength = "124";
            }else{
                revert();
            }
            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);
    }
}

pragma solidity 0.4.24;

import "../upgradeability/EternalStorage.sol";

contract MessageRelay is EternalStorage {
    function relayedMessages(bytes32 _nonce) public view returns (bool) {
        return boolStorage[keccak256(abi.encodePacked("relayedMessages", _nonce))];
    }

    function setRelayedMessages(bytes32 _nonce, bool _status) internal {
        boolStorage[keccak256(abi.encodePacked("relayedMessages", _nonce))] = _status;
    }
}

pragma solidity 0.4.24;
import "./Upgradeable.sol";
import "./InitializableBridge.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
import "./Validatable.sol";
import "./Ownable.sol";
import "./Claimable.sol";
import "./VersionableBridge.sol";
import "./DecimalShiftBridge.sol";
import "../interfaces/hashi/IYaho.sol";
import "../interfaces/IHashiManager.sol";

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"))
    bytes32 internal constant HASHI_MANAGER = 0x660d8ed18395a9aa930e304e0bb5e6e51957af1fa215b11db48bfda3dd38d511; // keccak256(abi.encodePacked("hashiManager"))
    bool public constant HASHI_IS_ENABLED = true;
    bool public constant HASHI_IS_MANDATORY = false;

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

    /**
    * @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];
    }

    function hashiManager() public view returns (IHashiManager) {
        return IHashiManager(addressStorage[HASHI_MANAGER]);
    }

    function setHashiManager(address _hashiManager) external onlyOwner {
        addressStorage[HASHI_MANAGER] = _hashiManager;
    }

    /**
    * @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);
    }

    function _setHashiApprovalForMessage(bytes32 hashMsg, bool status) internal {
        boolStorage[keccak256(abi.encodePacked("messagesApprovedByHashi", hashMsg))] = status;
    }

    function resendDataWithHashi(bytes data) external {
        require(boolStorage[keccak256(abi.encodePacked("dataSentWithHashi", data))]);
        _dispatchMessageWithHashi(data);
    }

    function _maybeSendDataWithHashi(bytes data) internal {
        if (HASHI_IS_ENABLED) {
            boolStorage[keccak256(abi.encodePacked("dataSentWithHashi", data))] = true;
            _dispatchMessageWithHashi(data);
        }
    }

    function _dispatchMessageWithHashi(bytes data) internal {
        IHashiManager manager = hashiManager();
        IYaho(manager.yaho()).dispatchMessage(
            manager.targetChainId(),
            manager.threshold(),
            manager.targetAddress(),
            data,
            manager.reporters(),
            manager.adapters()
        );
    }

    function _validateHashiMessage(uint256 chainId, uint256 threshold, address sender, address[] adapters) internal {
        IHashiManager manager = hashiManager();
        require(
            HASHI_IS_ENABLED &&
                msg.sender == manager.yaru() &&
                chainId == manager.targetChainId() &&
                sender == manager.targetAddress() &&
                threshold == manager.expectedThreshold() &&
                keccak256(abi.encodePacked(adapters)) == manager.expectedAdaptersHash()
        );
    }
}

pragma solidity 0.4.24;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "../upgradeability/EternalStorage.sol";
import "./DecimalShiftBridge.sol";
import "./Ownable.sol";

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"))
    bytes32 internal constant TOKEN_BRIDGE_NONCE = 0x8fe4c9f18420598a0f0a5c996b969714f39cc770f1900e60d2697139e137749b; // keccak256(abi.encodePacked("tokenBridgeNonce"))

    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) {
        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]);
    }

    function nonce() public view returns (uint256) {
        return uintStorage[TOKEN_BRIDGE_NONCE];
    }

    function setNonce(uint256 nonce) internal {
        uintStorage[TOKEN_BRIDGE_NONCE] = nonce;
    }
}

// SPDX-License-Identifier:MIT
pragma solidity 0.4.24;

/**
 * a contract must implement this interface in order to support relayed transaction.
 * It is better to inherit the BaseRelayRecipient as its implementation.
 */
contract IRelayRecipient {
    /**
     * return if the forwarder is trusted to forward relayed transactions to us.
     * the forwarder is required to verify the sender's signature, and verify
     * the call is not a replay.
     */
    function isTrustedForwarder(address forwarder) public view returns (bool);

    /**
     * return the sender of this call.
     * if the call came through our trusted forwarder, then the real sender is appended as the last 20 bytes
     * of the msg.data.
     * otherwise, return `msg.sender`
     * should be used in the contract anywhere instead of msg.sender
     */
    function _msgSender() internal view returns (address);

    /**
     * return the msg.data of this call.
     * if the call came through our trusted forwarder, then the real sender was appended as the last 20 bytes
     * of the msg.data - so this method will strip those 20 bytes off.
     * otherwise, return `msg.data`
     * should be used in the contract instead of msg.data, where the difference matters (e.g. when explicitly
     * signing or hashing the
     */
    function _msgData() internal view returns (bytes memory);

    function versionRecipient() external view returns (string memory);
}

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 25 of 40 : IUpgradeabilityOwnerStorage.sol
pragma solidity 0.4.24;

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

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);
    function addValidator(address _validator) external;
    function removeValidator(address _validator) external;
    function setRequiredSignatures(uint256 _requiredSignatures) external;
}

File 27 of 40 : ValidatorStorage.sol
pragma solidity 0.4.24;

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

File 28 of 40 : Upgradeable.sol
pragma solidity 0.4.24;

import "../interfaces/IUpgradeabilityOwnerStorage.sol";

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 */
        _;
    }
}

pragma solidity 0.4.24;

import "./Initializable.sol";

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];
    }
}

pragma solidity 0.4.24;

import "../libraries/Address.sol";
import "../libraries/SafeERC20.sol";

/**
 * @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);
    }
}

pragma solidity 0.4.24;

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

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

pragma solidity 0.4.24;

import "../upgradeability/EternalStorage.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";

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));
    }
}

pragma solidity 0.4.24;

interface IYaho {
    function dispatchMessage(
        uint256 targetChainId,
        uint256 threshold,
        address receiver,
        bytes data,
        address[] reporters,
        address[] adapters
    ) external returns (uint256);
}

pragma solidity 0.4.24;

interface IHashiManager {
    function adapters() external view returns (address[]);

    function reporters() external view returns (address[]);

    function expectedAdaptersHash() external view returns (bytes32);

    function expectedThreshold() external view returns (uint256);

    function yaho() external view returns (address);

    function yaru() external view returns (address);

    function targetAddress() external view returns (address);

    function targetChainId() external view returns (uint256);

    function threshold() external view returns (uint256);
}

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;
  }
}

pragma solidity 0.4.24;

import "../upgradeability/EternalStorage.sol";

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];
    }
}

pragma solidity 0.4.24;

import "../upgradeable_contracts/Sacrifice.sol";

/**
 * @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);
        }
    }
}

pragma solidity 0.4.24;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "../interfaces/ERC677.sol";

/**
 * @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 39 of 40 : Sacrifice.sol
pragma solidity 0.4.24;

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

pragma solidity 0.4.24;
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";

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);
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "openzeppelin-solidity/=node_modules/openzeppelin-solidity/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10
  },
  "metadata": {
    "useLiteralContent": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "constantinople"
}

Contract Security Audit

Contract ABI

API
[{"constant":false,"inputs":[{"name":"_receiver","type":"address"},{"name":"_amount","type":"uint256"}],"name":"relayTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"invest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"refillBridge","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"}],"name":"payInterest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"erc20token","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"HASHI_IS_MANDATORY","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"message","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"maxTokensFee","type":"uint256"}],"name":"executeSignaturesGSN","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nonce","type":"bytes32"}],"name":"relayedMessages","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_day","type":"uint256"}],"name":"totalSpentPerDay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"sDaiToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"isInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_dailyLimit","type":"uint256"}],"name":"setExecutionDailyLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentDay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"requiredBlockConfirmations","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"message","type":"bytes"},{"name":"signatures","type":"bytes"}],"name":"executeSignatures","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getBridgeMode","outputs":[{"name":"_data","type":"bytes4"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"executionDailyLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"}],"name":"minInterestPaid","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"versionRecipient","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_day","type":"uint256"}],"name":"totalExecutedPerDay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"}],"name":"minCashThreshold","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"dailyLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_to","type":"address"}],"name":"claimTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_validatorContract","type":"address"},{"name":"_erc20token","type":"address"},{"name":"_requiredBlockConfirmations","type":"uint256"},{"name":"_gasPrice","type":"uint256"},{"name":"_dailyLimitMaxPerTxMinPerTxArray","type":"uint256[3]"},{"name":"_homeDailyLimitHomeMaxPerTxArray","type":"uint256[2]"},{"name":"_owner","type":"address"},{"name":"_decimalShift","type":"int256"},{"name":"_bridgeOnOtherSide","type":"address"}],"name":"initialize","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"investDai","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"data","type":"bytes"}],"name":"resendDataWithHashi","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hashiManager","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_paymaster","type":"address"}],"name":"setPayMaster","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_amount","type":"uint256"}],"name":"withinExecutionLimit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"executionMaxPerTx","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"HASHI_IS_ENABLED","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"requiredSignatures","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"hashMsg","type":"bytes32"}],"name":"isApprovedByHashi","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_receiver","type":"address"}],"name":"setInterestReceiver","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"maxAvailablePerTx","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"validatorContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"deployedAtBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBridgeInterfacesVersion","outputs":[{"name":"major","type":"uint64"},{"name":"minor","type":"uint64"},{"name":"patch","type":"uint64"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_minPerTx","type":"uint256"}],"name":"setMinPerTx","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_minInterestPaid","type":"uint256"}],"name":"setMinInterestPaid","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_minCashThreshold","type":"uint256"}],"name":"setMinCashThreshold","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"}],"name":"interestReceiver","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_blockConfirmations","type":"uint256"}],"name":"setRequiredBlockConfirmations","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_dailyLimit","type":"uint256"}],"name":"setDailyLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"}],"name":"previewWithdraw","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"daiToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_hashiManager","type":"address"}],"name":"setHashiManager","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_gasPrice","type":"uint256"}],"name":"setGasPrice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"recoverAmount","type":"uint256"}],"name":"recoverLegacyTransfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxPerTx","type":"uint256"}],"name":"setMaxPerTx","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"}],"name":"interestAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"USDS","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_minCashThreshold","type":"uint256"},{"name":"_minInterestPaid","type":"uint256"},{"name":"_interestReceiver","type":"address"}],"name":"initializeInterest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTrustedForwarder","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"}],"name":"investedAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"}],"name":"isInterestEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","type":"uint256"},{"name":"chainId","type":"uint256"},{"name":"sender","type":"address"},{"name":"threshold","type":"uint256"},{"name":"adapters","type":"address[]"},{"name":"data","type":"bytes"}],"name":"onMessage","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_trustedForwarder","type":"address"}],"name":"setTrustedForwarder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimalShift","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minPerTx","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DAI","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_amount","type":"uint256"}],"name":"withinLimit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DAI_USDS","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxPerTx","type":"uint256"}],"name":"setExecutionMaxPerTx","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"disableInterest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"maxPerTx","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"swapSDAIToUSDS","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"gasPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"PaidInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"recipient","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"transactionHash","type":"bytes32"}],"name":"RelayedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"recipient","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"nonce","type":"bytes32"}],"name":"UserRequestForAffirmation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newLimit","type":"uint256"}],"name":"DailyLimitChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newLimit","type":"uint256"}],"name":"ExecutionDailyLimitChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"gasPrice","type":"uint256"}],"name":"GasPriceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"requiredBlockConfirmations","type":"uint256"}],"name":"RequiredBlockConfirmationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"previousOwner","type":"address"},{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]

608060405234801561001057600080fd5b50615e6e80620000216000396000f3006080604052600436106103315760003560e01c63ffffffff16806301e4f53a1461033657806303f9c7931461035c5780630fd6d5281461037d5780631b7623be146103925780631dcea427146103b65780631ded8468146103e75780631e86b2911461041057806321d800ec1461043f5780632bd0bb05146104575780633853b7a114610481578063392e53cd146104965780633dd95d1b146104ab5780633e6968b6146104c35780633f0a9f65146104d85780633f7658fd146104ed578063437764df1461051957806343b37dd31461054b5780634774f56314610560578063486ff0cd146105815780634fb3fef71461060b5780635726ff3014610623578063572b6c051461064457806367eeba0c1461066557806369ffa08a1461067a5780636da8b996146106a157806374948c52146106e9578063785b15d5146106fe5780637ea5f8d41461071e57806384fe8ab214610733578063879ce676146107545780638aa1949a1461076c5780638b94e255146107815780638d068043146107965780638da5cb5b146107ab5780638dc8cf87146107c0578063904377ec146107d857806395e54a17146107ff57806399439089146108145780639a454b99146108295780639cb7595a1461083e578063a2a6ca271461087f578063a36b85fd14610897578063a4b4b233146108bb578063a83bb236146108df578063acf5c68914610900578063affed0e014610918578063b20d30a91461092d578063bbc6f1dc14610945578063be22f546146103b6578063bec9fa7c14610969578063bf1fe4201461098a578063c2a2872d146109a2578063c6f6f216146109c6578063c779c1c3146109de578063c8ef95ae146109ff578063cd0fc03314610a14578063ce1b815f14610a43578063cff7744414610a58578063d2ef866014610a79578063d496af2414610a9a578063da74222814610adf578063dae5f0fd14610b00578063df25f3f014610b15578063e0bab4c414610b2a578063ea9f496814610b3f578063ecd9217914610b57578063f20151e114610b6c578063f2fde38b14610b84578063f50dace614610ba5578063f968adbe14610bc6578063fda8babc14610bdb578063fe173b9714610bf0575b600080fd5b34801561034257600080fd5b5061035a600160a060020a0360043516602435610c05565b005b34801561036857600080fd5b5061035a600160a060020a0360043516610e8f565b34801561038957600080fd5b5061035a610f88565b34801561039e57600080fd5b5061035a600160a060020a0360043516602435611094565b3480156103c257600080fd5b506103cb611243565b60408051600160a060020a039092168252519081900360200190f35b3480156103f357600080fd5b506103fc611255565b604080519115158252519081900360200190f35b34801561041c57600080fd5b5061035a602460048035828101929082013591813591820191013560443561125a565b34801561044b57600080fd5b506103fc60043561144a565b34801561046357600080fd5b5061046f600435611508565b60408051918252519081900360200190f35b34801561048d57600080fd5b506103cb6115bb565b3480156104a257600080fd5b506103fc6115cd565b3480156104b757600080fd5b5061035a6004356115fa565b3480156104cf57600080fd5b5061046f611684565b3480156104e457600080fd5b5061046f61168d565b3480156104f957600080fd5b5061035a60246004803582810192908201359181359182019101356116b7565b34801561052557600080fd5b5061052e6118b1565b60408051600160e060020a03199092168252519081900360200190f35b34801561055757600080fd5b5061046f6118bf565b34801561056c57600080fd5b5061046f600160a060020a03600435166118e9565b34801561058d57600080fd5b5061059661196e565b6040805160208082528351818301528351919283929083019185019080838360005b838110156105d05781810151838201526020016105b8565b50505050905090810190601f1680156105fd5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561061757600080fd5b5061046f600435611990565b34801561062f57600080fd5b5061046f600160a060020a0360043516611a04565b34801561065057600080fd5b506103fc600160a060020a0360043516611a8a565b34801561067157600080fd5b5061046f611ac2565b34801561068657600080fd5b5061035a600160a060020a0360043581169060243516611aec565b3480156106ad57600080fd5b506103fc600160a060020a03600435811690602435811690604435906064359060849060e4906101243581169061014435906101643516611c66565b3480156106f557600080fd5b5061035a611ebc565b34801561070a57600080fd5b5061035a6004803560248101910135611ed5565b34801561072a57600080fd5b506103cb611fd2565b34801561073f57600080fd5b5061035a600160a060020a0360043516612005565b34801561076057600080fd5b506103fc600435612067565b34801561077857600080fd5b5061046f6120a5565b34801561078d57600080fd5b506103fc6120cf565b3480156107a257600080fd5b5061046f6120d4565b3480156107b757600080fd5b506103cb612149565b3480156107cc57600080fd5b506103fc60043561217c565b3480156107e457600080fd5b5061035a600160a060020a03600435811690602435166121fd565b34801561080b57600080fd5b5061046f612223565b34801561082057600080fd5b506103cb61227d565b34801561083557600080fd5b5061046f6122c2565b34801561084a57600080fd5b506108536122ec565b6040805167ffffffffffffffff9485168152928416602084015292168183015290519081900360600190f35b34801561088b57600080fd5b5061035a6004356122f7565b3480156108a357600080fd5b5061035a600160a060020a036004351660243561236f565b3480156108c757600080fd5b5061035a600160a060020a0360043516602435612395565b3480156108eb57600080fd5b506103cb600160a060020a03600435166123bb565b34801561090c57600080fd5b5061035a60043561248d565b34801561092457600080fd5b5061046f6124b5565b34801561093957600080fd5b5061035a6004356124df565b34801561095157600080fd5b5061046f600160a060020a0360043516602435612569565b34801561097557600080fd5b5061035a600160a060020a036004351661264e565b34801561099657600080fd5b5061035a6004356126b0565b3480156109ae57600080fd5b5061035a600160a060020a03600435166024356126d5565b3480156109d257600080fd5b5061035a6004356128ff565b3480156109ea57600080fd5b5061046f600160a060020a0360043516612973565b348015610a0b57600080fd5b506103cb612a80565b348015610a2057600080fd5b5061035a600160a060020a03600435811690602435906044359060643516612a92565b348015610a4f57600080fd5b506103cb612b8d565b348015610a6457600080fd5b5061046f600160a060020a0360043516612bc0565b348015610a8557600080fd5b506103fc600160a060020a0360043516612c44565b348015610aa657600080fd5b5061059660048035906024803591600160a060020a0360443516916064359160843580830192908201359160a435918201910135612cca565b348015610aeb57600080fd5b5061035a600160a060020a0360043516612d51565b348015610b0c57600080fd5b5061046f612db3565b348015610b2157600080fd5b5061046f612e01565b348015610b3657600080fd5b506103cb612e2b565b348015610b4b57600080fd5b506103fc600435612e3d565b348015610b6357600080fd5b506103cb612e88565b348015610b7857600080fd5b5061035a600435612e9a565b348015610b9057600080fd5b5061035a600160a060020a0360043516612ef2565b348015610bb157600080fd5b5061035a600160a060020a0360043516612f17565b348015610bd257600080fd5b5061046f612f4a565b348015610be757600080fd5b5061035a612f74565b348015610bfc57600080fd5b5061046f61331c565b610c0d613346565b600160a060020a0383811691161415610c70576040805160e560020a62461bcd02815260206004820152601960248201527f52656c6179656420746f20427269646765206164647265737300000000000000604482015290519081900360640190fd5b600160a060020a0382161515610cd0576040805160e560020a62461bcd02815260206004820152601760248201527f52656c6179656420746f204e756c6c2061646472657373000000000000000000604482015290519081900360640190fd5b600160a060020a038216301415610d31576040805160e560020a62461bcd02815260206004820152601760248201527f52656c6179656420746f20746869732061646472657373000000000000000000604482015290519081900360640190fd5b60008111610d81576040805160e560020a62461bcd0281526020600482015260126024820152607060020a7152656c61796564207a65726f2066756e647302604482015290519081900360640190fd5b610d8a81612e3d565b1515610de0576040805160e560020a62461bcd02815260206004820152601a60248201527f4578636565647320627269646765206461696c79206c696d6974000000000000604482015290519081900360640190fd5b610df1610deb611684565b82613379565b610df9611243565b6040805160e060020a6323b872dd028152336004820152306024820152604481018490529051600160a060020a0392909216916323b872dd916064808201926020929091908290030181600087803b158015610e5457600080fd5b505af1158015610e68573d6000803e3d6000fd5b505050506040513d6020811015610e7e57600080fd5b50610e8b90508282613438565b5050565b600080600083610e9e81612c44565b1515610eee576040805160e560020a62461bcd0281526020600482015260146024820152606260020a73125b9d195c995cdd081b9bdd08115b98589b195902604482015290519081900360640190fd5b610ef7856134e2565b9350610f0285611a04565b9250828411610f50576040805160e560020a62461bcd02815260206004820152600f6024820152608860020a6e42616c616e636520746f6f204c6f7702604482015290519081900360640190fd5b8284039150610f7785610f7284610f6689612bc0565b9063ffffffff61356216565b613575565b610f8185836135f8565b5050505050565b6040805160e060020a6370a08231028152306004820152905160009182918291600080516020615dc3833981519152916370a082319160248082019260209290919082900301818787803b158015610fdf57600080fd5b505af1158015610ff3573d6000803e3d6000fd5b505050506040513d602081101561100957600080fd5b50519250611024600080516020615dc3833981519152611a04565b9150818310611073576040805160e560020a62461bcd0281526020600482015260106024820152608260020a6f109c9a5919d9481a5cc8119a5b1b195902604482015290519081900360640190fd5b5081810361108f600080516020615dc3833981519152826137b7565b505050565b6000806000846110a381612c44565b15156110f3576040805160e560020a62461bcd0281526020600482015260146024820152606260020a73125b9d195c995cdd081b9bdd08115b98589b195902604482015290519081900360640190fd5b6110fb611243565b600160a060020a03878116911614611153576040805160e560020a62461bcd0281526020600482015260106024820152608160020a6f2737ba10313934b233b2902a37b5b2b702604482015290519081900360640190fd5b61115c86612973565b935083851061116b578361116d565b845b9250611178866118e9565b8310156111cf576040805160e560020a62461bcd02815260206004820152601c60248201527f436f6c6c65637461626c6520696e74657265737420746f6f206c6f7700000000604482015290519081900360640190fd5b6111e086610f7285610f668a612bc0565b6111e9866123bb565b91506111f5828461380a565b60408051600160a060020a038481168252602082018690528251908916927f222348fe8b30f078a8a4da2f55f16d24d70bc40d3ec49d295d7ad1d11e666887928290030190a2505050505050565b600080516020615dc383398151915290565b600081565b600080600080600061126b33611a8a565b15156112b8576040805160e560020a62461bcd0281526020600482015260116024820152607960020a7034b73b30b634b2103337b93bb0b93232b902604482015290519081900360640190fd5b61132f8a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505089898080601f01602080910402602001604051908101604052809392919081815260200183838082843750611328945061227d9350505050565b6000613977565b6113688a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843750613bfb945050505050565b93985091965094509250905061137c611243565b600160a060020a0382811691161461139357600080fd5b61139c84612067565b1561143357838611156113ae57600080fd5b600160a060020a03821630146113c357600080fd5b6113cc8361144a565b156113d657600080fd5b6113e1836001613c5e565b6113ec858588613d25565b15156113f757600080fd5b60408051600160a060020a0387168152602081018690528082018590529051600080516020615be38339815191529181900360600190a161143e565b61143e858585610331565b50505050505050505050565b600060046000836040516020018080608860020a6e72656c617965644d6573736167657302815250600f0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106114c45780518252601f1990920191602091820191016114a5565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1695945050505050565b6000806000836040516020018080608060020a6f746f74616c5370656e74506572446179028152506010018281526020019150506040516020818303038152906040526040518082805190602001908083835b6020831061157a5780518252601f19909201916020918201910161155b565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205495945050505050565b6000805160206159e383398151915290565b600080516020615d038339815191526000526004602052600080516020615b638339815191525460ff1690565b611602612149565b600160a060020a0316331461161657600080fd5b61161e6120a5565b811180611629575080155b151561163457600080fd5b600080516020615a4383398151915260009081526020908152600080516020615ca3833981519152829055604080518381529051600080516020615983833981519152929181900390910190a150565b62015180420490565b600080516020615c238339815191526000908152602052600080516020615c838339815191525490565b6000806000806000806117308a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505089898080601f01602080910402602001604051908101604052809392919081815260200183838082843750611328945061227d9350505050565b6117698a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843750613bfb945050505050565b93995091975095509350915061177e85612067565b156118a657600160a060020a038316301461179857600080fd5b6117a18461144a565b156117ab57600080fd5b6117b6846001613c5e565b60408051600160a060020a03881660601b60208083019190915260348201889052605480830188905283518084039091018152607490920192839052815191929182918401908083835b6020831061181f5780518252601f199092019160209182019101611800565b5181516020939093036101000a60001901801990911692169190911790526040519201829003909120935061185392505050565b61185f86868685613d4a565b151561186a57600080fd5b60408051600160a060020a0388168152602081018790528082018690529051600080516020615be38339815191529181900360600190a161143e565b61143e868686610331565b60e160020a630c3b16a30290565b600080516020615a438339815191526000908152602052600080516020615ca38339815191525490565b6000806000836040516020018080608a60020a6e1b5a5b925b9d195c995cdd14185a5902815250600f0182600160a060020a0316600160a060020a031660601b81526014019150506040516020818303038152906040526040518082805190602001908083836020831061157a5780518252601f19909201916020918201910161155b565b604080518082019091526005815260d860020a64312e302e3102602082015290565b6000806000836040516020018080606860020a72746f74616c4578656375746564506572446179028152506013018281526020019150506040516020818303038152906040526040518082805190602001908083836020831061157a5780518252601f19909201916020918201910161155b565b6000806000836040516020018080608260020a6f1b5a5b90d85cda151a1c995cda1bdb190281525060100182600160a060020a0316600160a060020a031660601b81526014019150506040516020818303038152906040526040518082805190602001908083836020831061157a5780518252601f19909201916020918201910161155b565b600080516020615a038339815191526000526002602052600080516020615ba383398151915254600160a060020a0390811691161490565b600080516020615b438339815191526000908152602052600080516020615e238339815191525490565b60008030600160a060020a0316636fde82026040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611b2a57600080fd5b505af1158015611b3e573d6000803e3d6000fd5b505050506040513d6020811015611b5457600080fd5b5051600160a060020a03163314611b6a57600080fd5b50600080516020615dc383398151915290506000805160206159e3833981519152600160a060020a038416821415611be2576040805160e560020a62461bcd0281526020600482015260106024820152608060020a6f43616e277420636c61696d205553445302604482015290519081900360640190fd5b80600160a060020a031684600160a060020a0316141580611c095750611c0782612c44565b155b1515611c56576040805160e560020a62461bcd0281526020600482015260116024820152607860020a7043616e277420636c61696d20735553445302604482015290519081900360640190fd5b611c608484613fac565b50505050565b6040805160048152602481018252602081018051600160e060020a031660e160020a6337ef4101021781529151815160009330939291829190808383895b83811015611cbc578181015183820152602001611ca4565b50505050905090810190601f168015611ce95780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af19150501580611d78575030600160a060020a0316636fde82026040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611d4057600080fd5b505af1158015611d54573d6000803e3d6000fd5b505050506040513d6020811015611d6a57600080fd5b5051600160a060020a031633145b80611d8257503330145b1515611d8d57600080fd5b611d956115cd565b15611d9f57600080fd5b611da88a613fea565b1515611db357600080fd5b611dbb611243565b600160a060020a038a8116911614611dd257600080fd5b8215611ddd57600080fd5b600080516020615b238339815191528054600160a060020a031916600160a060020a038c16179055600080516020615963833981519152600090815260205243600080516020615b0383398151915255611e3688613ff2565b611e3f87614061565b604080516060818101909252611e679188906003908390839080828437506140779350505050565b604080518082018252611e8c9187906002908390839080828437506141569350505050565b611e95846141d1565b611e9e82614277565b611ea66142d2565b611eae6115cd565b9a9950505050505050505050565b611ed3600080516020615dc3833981519152610e8f565b565b6004600083836040516020018080607860020a706461746153656e74576974684861736869028152506011018383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b60208310611f4e5780518252601f199092019160209182019101611f2f565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1615159250611f9991505057600080fd5b610e8b82828080601f01602080910402602001604051908101604052809392919081815260200183838082843750614305945050505050565b600080516020615b838339815191526000526002602052600080516020615a6383398151915254600160a060020a031690565b61200d612149565b600160a060020a0316331461202157600080fd5b600080516020615ae38339815191526000526002602052600080516020615de38339815191528054600160a060020a031916600160a060020a0392909216919091179055565b60008061207e83610f66612079611684565b611990565b9050806120896118bf565b1015801561209e575061209a6120a5565b8311155b9392505050565b600080516020615e0383398151915260009081526020526000805160206159a38339815191525490565b600181565b60006120de61227d565b600160a060020a0316638d0680436040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561211857600080fd5b505af115801561212c573d6000803e3d6000fd5b505050506040513d602081101561214257600080fd5b5051905090565b600080516020615c638339815191526000526002602052600080516020615c4383398151915254600160a060020a031690565b600060046000836040516020018080604860020a766d65737361676573417070726f76656442794861736869028152506017018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106114c45780518252601f1990920191602091820191016114a5565b612205612149565b600160a060020a0316331461221957600080fd5b610e8b82826147d7565b6000806000806000612233612f4a565b935061223d611ac2565b925061224f61224a611684565b611508565b915081831161225f576000612263565b8183035b90508084106122725780612274565b835b94505050505090565b7f5a74bb7e202fb8e4bf311841c7d64ec19df195fee77d7e7ae749b27921b6ddfe6000526002602052600080516020615b2383398151915254600160a060020a031690565b6000805160206159638339815191526000908152602052600080516020615b038339815191525490565b600660016000909192565b6122ff612149565b600160a060020a0316331461231357600080fd5b6000811180156123295750612326611ac2565b81105b801561233b5750612338612f4a565b81105b151561234657600080fd5b600080516020615a838339815191526000908152602052600080516020615d2383398151915255565b612377612149565b600160a060020a0316331461238b57600080fd5b610e8b828261490a565b61239d612149565b600160a060020a031633146123b157600080fd5b610e8b828261498e565b600060026000836040516020018080608160020a6f34b73a32b932b9ba2932b1b2b4bb32b90281525060100182600160a060020a0316600160a060020a031660601b81526014019150506040516020818303038152906040526040518082805190602001908083835b602083106124435780518252601f199092019160209182019101612424565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054600160a060020a031695945050505050565b612495612149565b600160a060020a031633146124a957600080fd5b6124b281613ff2565b50565b600080516020615bc38339815191526000908152602052600080516020615ac38339815191525490565b6124e7612149565b600160a060020a031633146124fb57600080fd5b612503612f4a565b81118061250e575080155b151561251957600080fd5b600080516020615b4383398151915260009081526020908152600080516020615e23833981519152829055604080518381529051600080516020615d83833981519152929181900390910190a150565b6000600080516020615dc3833981519152600160a060020a038416146125c7576040805160e560020a62461bcd028152602060048201526008602482015260c060020a676e6f74205553445302604482015290519081900360640190fd5b6000805160206159e3833981519152600160a060020a0316630a28a477836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561261b57600080fd5b505af115801561262f573d6000803e3d6000fd5b505050506040513d602081101561264557600080fd5b50519392505050565b612656612149565b600160a060020a0316331461266a57600080fd5b600080516020615b838339815191526000526002602052600080516020615a638339815191528054600160a060020a031916600160a060020a0392909216919091179055565b6126b8612149565b600160a060020a031633146126cc57600080fd5b6124b281614061565b600080600030600160a060020a0316636fde82026040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561271557600080fd5b505af1158015612729573d6000803e3d6000fd5b505050506040513d602081101561273f57600080fd5b5051600160a060020a0316331461275557600080fd5b6040805160e060020a6370a082310281523060048201529051600080516020615dc3833981519152916370a082319160248083019260209291908290030181600087803b1580156127a557600080fd5b505af11580156127b9573d6000803e3d6000fd5b505050506040513d60208110156127cf57600080fd5b505192506127ea600080516020615dc3833981519152611a04565b9150828410612843576040805160e560020a62461bcd02815260206004820152601860248201527f696e76616c69642077697468647261772062616c616e63650000000000000000604482015290519081900360640190fd5b81848403101561286c578284830103905061286c600080516020615dc3833981519152826137b7565b6040805160e060020a63a9059cbb028152600160a060020a0387166004820152602481018690529051600080516020615dc38339815191529163a9059cbb9160448083019260209291908290030181600087803b1580156128cc57600080fd5b505af11580156128e0573d6000803e3d6000fd5b505050506040513d60208110156128f657600080fd5b50505050505050565b612907612149565b600160a060020a0316331461291b57600080fd5b80158061293f575061292b612e01565b8111801561293f575061293c611ac2565b81105b151561294a57600080fd5b6000805160206159c38339815191526000908152602052600080516020615ce383398151915255565b60008080600080516020615dc3833981519152600160a060020a038516146129d3576040805160e560020a62461bcd028152602060048201526008602482015260c060020a674e6f74205553445302604482015290519081900360640190fd5b6040805160e060020a63ce96cb7702815230600482015290516000805160206159e38339815191529163ce96cb779160248083019260209291908290030181600087803b158015612a2357600080fd5b505af1158015612a37573d6000803e3d6000fd5b505050506040513d6020811015612a4d57600080fd5b50519150612a5a84612bc0565b670de0b6b3a7640000019050808211612a74576000612a78565b8082035b949350505050565b600080516020615dc383398151915281565b612a9a612149565b600160a060020a03163314612aae57600080fd5b612ab784614a13565b1515612b06576040805160e560020a62461bcd0281526020600482015260136024820152606a60020a72151bdad95b881b9bdd081cdd5c1c1bdc9d195902604482015290519081900360640190fd5b612b0f84612c44565b15612b64576040805160e560020a62461bcd02815260206004820152601860248201527f496e74657265737420616c726561647920656e61626c65640000000000000000604482015290519081900360640190fd5b612b6f846001614a2f565b612b79848461498e565b612b83848361490a565b611c6084826147d7565b600080516020615a038339815191526000526002602052600080516020615ba383398151915254600160a060020a031690565b6000806000836040516020018080609260020a6d1a5b9d995cdd1959105b5bdd5b9d02815250600e0182600160a060020a0316600160a060020a031660601b81526014019150506040516020818303038152906040526040518082805190602001908083836020831061157a5780518252601f19909201916020918201910161155b565b600060046000836040516020018080608a60020a6e1a5b9d195c995cdd115b98589b195902815250600f0182600160a060020a0316600160a060020a031660601b8152601401915050604051602081830303815290604052604051808280519060200190808383602083106114c45780518252601f1990920191602091820191016114a5565b60606000612d0789888a89898080602002602001604051908101604052809392919081815260200183836020028082843750614ab4945050505050565b83836040518083838082843782019150509250505060405180910390209050612d2f8161217c565b15612d3957600080fd5b612d44816001614db7565b5098975050505050505050565b612d59612149565b600160a060020a03163314612d6d57600080fd5b600080516020615a038339815191526000526002602052600080516020615ba38339815191528054600160a060020a031916600160a060020a0392909216919091179055565b7f1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee560009081526020527fd5c78dd9468716ca9bb96be25d56436811b20aab3523a9904b12deef1cab239d5490565b600080516020615a838339815191526000908152602052600080516020615d238339815191525490565b600080516020615aa383398151915281565b600080612e4f83610f6661224a611684565b905080612e5a611ac2565b10158015612e6f5750612e6b612f4a565b8311155b801561209e5750612e7e612e01565b9092101592915050565b600080516020615d4383398151915281565b612ea2612149565b600160a060020a03163314612eb657600080fd5b612ebe6118bf565b8110612ec957600080fd5b600080516020615e0383398151915260009081526020526000805160206159a383398151915255565b612efa612149565b600160a060020a03163314612f0e57600080fd5b6124b2816141d1565b612f1f612149565b600160a060020a03163314612f3357600080fd5b612f3f816000196137b7565b6124b2816000614a2f565b6000805160206159c38339815191526000908152602052600080516020615ce38339815191525490565b60408051606860020a72757067726164655f4441495f746f5f55534453028152815190819003601301902060008181526004602052918220549091908190819060ff161561300c576040805160e560020a62461bcd02815260206004820152601d60248201527f5553445320627269646765207567707261646520636f6d706c65746564000000604482015290519081900360640190fd5b6040805160e060020a63ce96cb7702815230600482015290517383f20f44975d03b1b09e64809b757c47f942beea9450849163ce96cb779160248083019260209291908290030181600087803b15801561306557600080fd5b505af1158015613079573d6000803e3d6000fd5b505050506040513d602081101561308f57600080fd5b50516040805160e260020a632d182be502815260048101839052306024820181905260448201529051919350600160a060020a0385169163b460af94916064808201926020929091908290030181600087803b1580156130ee57600080fd5b505af1158015613102573d6000803e3d6000fd5b505050506040513d602081101561311857600080fd5b506131349050600080516020615aa38339815191526000613575565b61314d600080516020615aa38339815191526000614a2f565b613166600080516020615aa3833981519152600061498e565b61317f600080516020615aa3833981519152600061490a565b6040805160e060020a6370a082310281523060048201529051600080516020615aa3833981519152916370a082319160248083019260209291908290030181600087803b1580156131cf57600080fd5b505af11580156131e3573d6000803e3d6000fd5b505050506040513d60208110156131f957600080fd5b50516040805160e060020a63095ea7b3028152600080516020615d438339815191526004820152602481018390529051919250600080516020615aa38339815191529163095ea7b3916044808201926020929091908290030181600087803b15801561326457600080fd5b505af1158015613278573d6000803e3d6000fd5b505050506040513d602081101561328e57600080fd5b50506040805160e160020a6379603d57028152306004820152602481018390529051600080516020615d438339815191529163f2c07aae91604480830192600092919082900301818387803b1580156132e657600080fd5b505af11580156132fa573d6000803e3d6000fd5b505050600094855250506004602052505060409020805460ff19166001179055565b600080516020615c038339815191526000908152602052600080516020615cc38339815191525490565b600080516020615a238339815191526000526002602052600080516020615d6383398151915254600160a060020a031690565b61338681610f6684611508565b600080846040516020018080608060020a6f746f74616c5370656e74506572446179028152506010018281526020019150506040516020818303038152906040526040518082805190602001908083835b602083106133f65780518252601f1990920191602091820191016133d7565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050565b60006134426124b5565b905061345081600101614e37565b60408051600160a060020a038516815260208101849052600083901b8183015290517ff6968e689b3d8c24f22c10c2a3256bb5ca483a474e11bac08423baa049e38ae89181900360600190a160408051600160a060020a03851660601b602082015260348101849052600083901b60548083019190915282518083039091018152607490910190915261108f90614e60565b6040805160e060020a6370a082310281523060048201529051600091600160a060020a038416916370a082319160248082019260209290919082900301818787803b15801561353057600080fd5b505af1158015613544573d6000803e3d6000fd5b505050506040513d602081101561355a57600080fd5b505192915050565b8181018281101561356f57fe5b92915050565b80600080846040516020018080609260020a6d1a5b9d995cdd1959105b5bdd5b9d02815250600e0182600160a060020a0316600160a060020a031660601b8152601401915050604051602081830303815290604052604051808280519060200190808383602083106133f65780518252601f1990920191602091820191016133d7565b600080516020615dc3833981519152600160a060020a03831614613654576040805160e560020a62461bcd028152602060048201526008602482015260c060020a676e6f74205553445302604482015290519081900360640190fd5b6040805160e060020a63095ea7b30281526000805160206159e38339815191526004820152602481018390529051600080516020615dc38339815191529163095ea7b39160448083019260209291908290030181600087803b1580156136b957600080fd5b505af11580156136cd573d6000803e3d6000fd5b505050506040513d60208110156136e357600080fd5b50506040805160e060020a636e553f650281526004810183905230602482015290516000916000805160206159e383398151915291636e553f659160448082019260209290919082900301818787803b15801561373f57600080fd5b505af1158015613753573d6000803e3d6000fd5b505050506040513d602081101561376957600080fd5b505111610e8b576040805160e560020a62461bcd0281526020600482015260116024820152607a60020a7011985a5b1959081d1bc819195c1bdcda5d02604482015290519081900360640190fd5b60008060006137c585612bc0565b92508284116137d457836137d6565b825b91508115156137e457610f81565b6137ee8583614f70565b9050610f8185828511613802576000610f72565b828503613575565b600160a060020a038216151561386a576040805160e560020a62461bcd02815260206004820152601660248201527f52656365697665722063616e2774206265204e756c6c00000000000000000000604482015290519081900360640190fd5b600160a060020a0382163014156138b9576040805160e560020a62461bcd02815260206004820152601c6024820152600080516020615da3833981519152604482015290519081900360640190fd5b6000811161390a576040805160e560020a62461bcd0281526020600482015260136024820152606860020a7252656c61796564207a65726f20746f6b656e7302604482015290519081900360640190fd5b61391381612e3d565b1515613962576040805160e560020a62461bcd0281526020600482015260136024820152606a60020a7214995b185e59590818589bdd99481b1a5b5a5d02604482015290519081900360640190fd5b61396d610deb611684565b610e8b8282613438565b6000806000606060008060008060008060008b8061399957506139998f614ffb565b15156139a457600080fd5b8c600160a060020a0316638d0680436040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156139df57600080fd5b505af11580156139f3573d6000803e3d6000fd5b505050506040513d6020811015613a0957600080fd5b505160018f0151909b5060ff1699508a8a1015613a2557600080fd5b613a2f8f8d615010565b98508a604051908082528060200260200182016040528015613a5b578160200160208202803883390190505b509750600096505b8a871015613bea57866020028a6021010192508960200283019150866002018e01519550828e01519450818e01519350600189878787604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af1158015613b0a573d6000803e3d6000fd5b5050506020604051035190508c600160a060020a031663facd743b826040518263ffffffff1660e01b81526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b158015613b6e57600080fd5b505af1158015613b82573d6000803e3d6000fd5b505050506040513d6020811015613b9857600080fd5b50511515613ba557600080fd5b613baf8882615240565b15613bb957600080fd5b808888815181101515613bc857fe5b600160a060020a03909216602092830290910190910152600190960195613a63565b505050505050505050505050505050565b6000806000806000613c0c86614ffb565b1515613c1757600080fd5b60148601519450603486015193506054860151925060688601519150607c8601519050855160681415613c555750600080516020615aa38339815191525b91939590929450565b8060046000846040516020018080608860020a6e72656c617965644d6573736167657302815250600f0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310613cd75780518252601f199092019160209182019101613cb8565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff1916941515949094179093555050505050565b6000613d3f600080516020615dc38339815191528461529b565b612a78848484615347565b600080613d5e613d58611684565b866154ae565b50600080516020615dc3833981519152613d78818661529b565b600160a060020a038316600080516020615aa38339815191521415613f24576040805160e060020a63095ea7b3028152600080516020615d438339815191526004820152602481018790529051600160a060020a0383169163095ea7b39160448083019260209291908290030181600087803b158015613df757600080fd5b505af1158015613e0b573d6000803e3d6000fd5b505050506040513d6020811015613e2157600080fd5b50506040805160e460020a63068f3015028152306004820152602481018790529051600080516020615d43833981519152916368f3015091604480830192600092919082900301818387803b158015613e7957600080fd5b505af1158015613e8d573d6000803e3d6000fd5b50506040805160e060020a63a9059cbb028152600160a060020a038a166004820152602481018990529051600080516020615aa3833981519152935063a9059cbb925060448083019260209291908290030181600087803b158015613ef157600080fd5b505af1158015613f05573d6000803e3d6000fd5b505050506040513d6020811015613f1b57600080fd5b50519150613fa3565b600160a060020a038316600080516020615dc383398151915214156103315780600160a060020a031663a9059cbb87876040518363ffffffff1660e01b81526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b158015613ef157600080fd5b50949350505050565b80600160a060020a0381161515613fc257600080fd5b600160a060020a0383161515613fe057613fdb8261552d565b61108f565b61108f8383615539565b6000903b1190565b60008111613fff57600080fd5b600080516020615c2383398151915260009081526020908152600080516020615c838339815191528290556040805183815290517f4fb76205cd57c896b21511d2114137d8e901b4ccd659e1a0f97d6306795264fb929181900390910190a150565b6000811161406e57600080fd5b6124b2816155d0565b60408101516000108015614092575060408101516020820151115b80156140a2575060208101518151115b15156140ad57600080fd5b8051600080516020615b4383398151915260009081526020818152600080516020615e2383398151915292909255908201516000805160206159c38339815191528252600080516020615ce3833981519152556040820151600080516020615a838339815191528252600080516020615d2383398151915255600080516020615d838339815191529082905b60200201516040518082815260200191505060405180910390a150565b805160208201511061416757600080fd5b8051600080516020615a4383398151915260009081526020818152600080516020615ca38339815191529290925590820151600080516020615e0383398151915282526000805160206159a383398151915255600080516020615983833981519152908290614139565b600160a060020a03811615156141e657600080fd5b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e061420f612149565b60408051600160a060020a03928316815291841660208301528051918290030190a1600080516020615c638339815191526000526002602052600080516020615c438339815191528054600160a060020a031916600160a060020a0392909216919091179055565b600160a060020a038116151561428c57600080fd5b600080516020615a238339815191526000526002602052600080516020615d638339815191528054600160a060020a031916600160a060020a0392909216919091179055565b600080516020615d038339815191526000526004602052600080516020615b63833981519152805460ff19166001179055565b600061430f611fd2565b905080600160a060020a031663ee4937ba6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561434c57600080fd5b505af1158015614360573d6000803e3d6000fd5b505050506040513d602081101561437657600080fd5b50516040805160e160020a630a37fd930281529051600160a060020a03928316926339d0bf63929085169163146ffb26916004808201926020929091908290030181600087803b1580156143c957600080fd5b505af11580156143dd573d6000803e3d6000fd5b505050506040513d60208110156143f357600080fd5b50516040805160e360020a630859bc9d0281529051600160a060020a038616916342cde4e89160048083019260209291908290030181600087803b15801561443a57600080fd5b505af115801561444e573d6000803e3d6000fd5b505050506040513d602081101561446457600080fd5b50516040805160e160020a63290875ab0281529051600160a060020a03871691635210eb569160048083019260209291908290030181600087803b1580156144ab57600080fd5b505af11580156144bf573d6000803e3d6000fd5b505050506040513d60208110156144d557600080fd5b50516040805160e160020a6378a26a4302815290518891600160a060020a0389169163f144d4869160048082019260009290919082900301818387803b15801561451e57600080fd5b505af1158015614532573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561455b57600080fd5b810190808051602060020a81111561457257600080fd5b8201602081018481111561458557600080fd5b81518560208202830111602060020a821117156145a157600080fd5b505092919050505087600160a060020a0316636b6e93d56040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156145e457600080fd5b505af11580156145f8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561462157600080fd5b810190808051602060020a81111561463857600080fd5b8201602081018481111561464b57600080fd5b81518560208202830111602060020a8211171561466757600080fd5b505060405163ffffffff8b1660e01b8152600481018a8152602482018a9052600160a060020a038916604483015260c060648301908152885160c484015288519396509094509250608481019160a482019160e40190602089019080838360005b838110156146e05781810151838201526020016146c8565b50505050905090810190601f16801561470d5780820380516001836020036101000a031916815260200191505b508481038352865181528651602091820191808901910280838360005b8381101561474257818101518382015260200161472a565b50505050905001848103825285818151815260200191508051906020019060200280838360005b83811015614781578181015183820152602001614769565b505050509050019950505050505050505050602060405180830381600087803b1580156147ad57600080fd5b505af11580156147c1573d6000803e3d6000fd5b505050506040513d6020811015611c6057600080fd5b600160a060020a038116301415614826576040805160e560020a62461bcd02815260206004820152601c6024820152600080516020615da3833981519152604482015290519081900360640190fd5b8060026000846040516020018080608160020a6f34b73a32b932b9ba2932b1b2b4bb32b90281525060100182600160a060020a0316600160a060020a031660601b81526014019150506040516020818303038152906040526040518082805190602001908083835b602083106148ad5780518252601f19909201916020918201910161488e565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000208054600160a060020a031916600160a060020a0395909516949094179093555050505050565b80600080846040516020018080608a60020a6e1b5a5b925b9d195c995cdd14185a5902815250600f0182600160a060020a0316600160a060020a031660601b8152601401915050604051602081830303815290604052604051808280519060200190808383602083106133f65780518252601f1990920191602091820191016133d7565b80600080846040516020018080608260020a6f1b5a5b90d85cda151a1c995cda1bdb190281525060100182600160a060020a0316600160a060020a031660601b8152601401915050604051602081830303815290604052604051808280519060200190808383602083106133f65780518252601f1990920191602091820191016133d7565b600160a060020a0316600080516020615dc38339815191521490565b8060046000846040516020018080608a60020a6e1a5b9d195c995cdd115b98589b195902815250600f0182600160a060020a0316600160a060020a031660601b815260140191505060405160208183030381529060405260405180828051906020019080838360208310613cd75780518252601f199092019160209182019101613cb8565b6000614abe611fd2565b905080600160a060020a031663789b11d76040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614afb57600080fd5b505af1158015614b0f573d6000803e3d6000fd5b505050506040513d6020811015614b2557600080fd5b5051600160a060020a031633148015614ba3575080600160a060020a031663146ffb266040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614b7457600080fd5b505af1158015614b88573d6000803e3d6000fd5b505050506040513d6020811015614b9e57600080fd5b505185145b8015614c20575080600160a060020a0316635210eb566040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614be557600080fd5b505af1158015614bf9573d6000803e3d6000fd5b505050506040513d6020811015614c0f57600080fd5b5051600160a060020a038481169116145b8015614c91575080600160a060020a0316632690ff8b6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614c6257600080fd5b505af1158015614c76573d6000803e3d6000fd5b505050506040513d6020811015614c8c57600080fd5b505184145b8015614dac575080600160a060020a031663f238ca266040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614cd357600080fd5b505af1158015614ce7573d6000803e3d6000fd5b505050506040513d6020811015614cfd57600080fd5b5051604051835184916020908101918291848101910280838360005b83811015614d31578181015183820152602001614d19565b505050509050019150506040516020818303038152906040526040518082805190602001908083835b60208310614d795780518252601f199092019160209182019101614d5a565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916145b1515610f8157600080fd5b8060046000846040516020018080604860020a766d65737361676573417070726f7665644279486173686902815250601701826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310613cd75780518252601f199092019160209182019101613cb8565b600080516020615bc38339815191526000908152602052600080516020615ac383398151915255565b600160046000836040516020018080607860020a706461746153656e745769746848617368690281525060110182805190602001908083835b60208310614eb85780518252601f199092019160209182019101614e99565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b60208310614f1b5780518252601f199092019160209182019101614efc565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff191694151594909417909355506124b29150829050614305565b6000806000614f7e856134e2565b9150614f8a8585615632565b81614f94866134e2565b03905083811015614fef576040805160e560020a62461bcd02815260206004820152601a60248201527f57697468647261776e206c657373207468616e20416d6f756e74000000000000604482015290519081900360640190fd5b8092505b505092915050565b600081516068148061356f57505051607c1490565b60408051808201909152601a81527f19457468657265756d205369676e6564204d6573736167653a0a0000000000006020820152600090606083156151b6578161505a8651615768565b866040516020018084805190602001908083835b6020831061508d5780518252601f19909201916020918201910161506e565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b602083106150d55780518252601f1990920191602091820191016150b6565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b6020831061511d5780518252601f1990920191602091820191016150fe565b6001836020036101000a03801982511681845116808217855250505050505090500193505050506040516020818303038152906040526040518082805190602001908083835b602083106151825780518252601f199092019160209182019101615163565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250614ff3565b8451606814156151e35750604080518082019091526003815260ea60020a620c4c0d02602082015261520c565b8451607c14156103315750604080518082019091526003815260ea60020a620c4c8d0260208201525b8181866040516020018084805190602001908083836020831061508d5780518252601f19909201916020918201910161506e565b6000805b835181101561528f5782600160a060020a0316848281518110151561526557fe5b90602001906020020151600160a060020a031614156152875760019150615294565b600101615244565b600091505b5092915050565b6040805160e060020a6370a0823102815230600482015290516000918291600160a060020a038616916370a0823191602480830192602092919082900301818787803b1580156152ea57600080fd5b505af11580156152fe573d6000803e3d6000fd5b505050506040513d602081101561531457600080fd5b5051915082821015611c605761533b61532c85611a04565b8385039063ffffffff61356216565b9050611c6084826137b7565b60008060008061535e615358611684565b876154ae565b615366611243565b600080516020615ae3833981519152600090815260026020908152600080516020615de3833981519152546040805160e060020a63a9059cbb028152600160a060020a039283166004820152602481018b905290519497509087169363a9059cbb93604480840194938390030190829087803b1580156153e557600080fd5b505af11580156153f9573d6000803e3d6000fd5b505050506040513d602081101561540f57600080fd5b50516040805160e060020a63a9059cbb028152600160a060020a038a81166004830152888a03602483015291519294509085169163a9059cbb916044808201926020929091908290030181600087803b15801561546b57600080fd5b505af115801561547f573d6000803e3d6000fd5b505050506040513d602081101561549557600080fd5b505190508180156154a35750805b979650505050505050565b6154bb81610f6684611990565b600080846040516020018080606860020a72746f74616c457865637574656450657244617902815250601301828152602001915050604051602081830303815290604052604051808280519060200190808383602083106133f65780518252601f1990920191602091820191016133d7565b3031610e8b828261583f565b6040805160e060020a6370a0823102815230600482015290518391600091600160a060020a038416916370a0823191602480830192602092919082900301818787803b15801561558857600080fd5b505af115801561559c573d6000803e3d6000fd5b505050506040513d60208110156155b257600080fd5b50519050611c60600160a060020a038516848363ffffffff6158a016565b600080516020615c0383398151915260009081526020908152600080516020615cc38339815191528290556040805183815290517f52264b89e0fceafb26e79fd49ef8a366eb6297483bf4035b027f0c99a7ad512e929181900390910190a150565b600080516020615dc3833981519152600160a060020a0383161461568e576040805160e560020a62461bcd028152602060048201526008602482015260c060020a676e6f74205553445302604482015290519081900360640190fd5b6040805160e260020a632d182be5028152600481018390523060248201819052604482015290516000916000805160206159e38339815191529163b460af949160648082019260209290919082900301818787803b1580156156ef57600080fd5b505af1158015615703573d6000803e3d6000fd5b505050506040513d602081101561571957600080fd5b505111610e8b576040805160e560020a62461bcd0281526020600482015260126024820152607060020a714661696c656420746f20776974686472617702604482015290519081900360640190fd5b6060600080828185151561579857604080518082019091526001815260fc60020a60030260208201529450615836565b8593505b83156157b357600190920191600a8404935061579c565b826040519080825280601f01601f1916602001820160405280156157e1578160200160208202803883390190505b5091505060001982015b85156158325781516000198201916030600a89060160f81b91849190811061580f57fe5b906020010190600160f860020a031916908160001a905350600a860495506157eb565b8194505b50505050919050565b604051600160a060020a0383169082156108fc029083906000818181858888f193505050501515610e8b578082615874615932565b600160a060020a039091168152604051908190036020019082f080158015610f81573d6000803e3d6000fd5b82600160a060020a031663a9059cbb83836040518363ffffffff1660e01b81526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050600060405180830381600087803b15801561590057600080fd5b505af1158015615914573d6000803e3d6000fd5b505050503d1561108f5760206000803e600051151561108f57600080fd5b604051602180615942833901905600608060405260405160208060218339810160405251600160a060020a038116ff00b120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b09bebf928b90863f24cc31f726a3a7545efd409f1dcf552301b1ee3710da70d3bf8e983ee86e5e377e9e34c9131b266382c3f04113d20de077f9e12663c7a646b0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c000000000000000000000000a3931d71877c0e7a3148cb7eb4463524fec27fbd222cb212229f0f9bcd249029717af6845ea3d3a84f22b54e5744ac25ef224c9271483949fe7a14d16644d63320f24d10cf1d60abecc30cc677a340e82b699dd221dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d237b1578d368dec034f5de4adb7567061a469e92e7039fd319ab435573139ccbcc6bbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d10000000000000000000000006b175474e89094c44da98b954eedeac495271d0f8ba1484e8bf7939787444e92eb98a67eb881960295fd73460f6d5e6df6d34d1ffefcc139ed357999ed60c6a013947328d52e7d9751e93fd0274a2bfae5cbcb12e66bef0282a446f9848e2903380099bb6e431483ee78778868f33b4a154c818bab54f3fbbe62c59b7876a9bf9bd5e0c22dbae93f4d8ee0438f7ce62b198eb0e04a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a5078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc660d8ed18395a9aa930e304e0bb5e6e51957af1fa215b11db48bfda3dd38d511b3492a958ebdd65bd9a0b8ebca07c67a2ad3af56a28fc2944e214aa69ec9581b8fe4c9f18420598a0f0a5c996b969714f39cc770f1900e60d2697139e137749b4ab7d581336d92edbea22636a613e8e76c99ac7f91137c1523db38dbfb3bf32955b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d79407230071b7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0d2ea0feb732edb0ffe32efd33a6b9d24d46b16eb34a4d07ce256537b6f131e42add938dbd083a16bae12238cd914fca0afc7a30edb55b1cd5c7f1823f1b0e421f7d5eefab3776d7f0450bd0193564bcb4f832ce313ff2836c450fc63a4b944199de0f81379b4d8e60fe509315d071b56e7b732abaf193e74e0d15808b0951d090a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba8df5c48c6b6e11d97548adc824ba0c99103ec09830fa5d53a179984085e6eaa00000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a21ffdf150a5d180f96d98d16f50e7b4dd63e2a067adc8386cf5af55dcecd8dd9ad4123ae17c414d9c6d2fec478b402e6b01856cc250fd01fbfd252fda0089d3c52656365697665722063616e2774206265207468652042726964676500000000000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384ff215aff72f0a1a7d74fcd807336e100b80bbb56cdfb43843ade07ecf211a979fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d51ab29a5cca988aee50edccdd61c5bcaa7ad4b29a03b7ee50f298ceccfe14cc4ea165627a7a723058206d3bf9eb229128196dce5dc14ada05a523133a08c3e79e95a72034085dbc93600029

Deployed Bytecode

0x6080604052600436106103315760003560e01c63ffffffff16806301e4f53a1461033657806303f9c7931461035c5780630fd6d5281461037d5780631b7623be146103925780631dcea427146103b65780631ded8468146103e75780631e86b2911461041057806321d800ec1461043f5780632bd0bb05146104575780633853b7a114610481578063392e53cd146104965780633dd95d1b146104ab5780633e6968b6146104c35780633f0a9f65146104d85780633f7658fd146104ed578063437764df1461051957806343b37dd31461054b5780634774f56314610560578063486ff0cd146105815780634fb3fef71461060b5780635726ff3014610623578063572b6c051461064457806367eeba0c1461066557806369ffa08a1461067a5780636da8b996146106a157806374948c52146106e9578063785b15d5146106fe5780637ea5f8d41461071e57806384fe8ab214610733578063879ce676146107545780638aa1949a1461076c5780638b94e255146107815780638d068043146107965780638da5cb5b146107ab5780638dc8cf87146107c0578063904377ec146107d857806395e54a17146107ff57806399439089146108145780639a454b99146108295780639cb7595a1461083e578063a2a6ca271461087f578063a36b85fd14610897578063a4b4b233146108bb578063a83bb236146108df578063acf5c68914610900578063affed0e014610918578063b20d30a91461092d578063bbc6f1dc14610945578063be22f546146103b6578063bec9fa7c14610969578063bf1fe4201461098a578063c2a2872d146109a2578063c6f6f216146109c6578063c779c1c3146109de578063c8ef95ae146109ff578063cd0fc03314610a14578063ce1b815f14610a43578063cff7744414610a58578063d2ef866014610a79578063d496af2414610a9a578063da74222814610adf578063dae5f0fd14610b00578063df25f3f014610b15578063e0bab4c414610b2a578063ea9f496814610b3f578063ecd9217914610b57578063f20151e114610b6c578063f2fde38b14610b84578063f50dace614610ba5578063f968adbe14610bc6578063fda8babc14610bdb578063fe173b9714610bf0575b600080fd5b34801561034257600080fd5b5061035a600160a060020a0360043516602435610c05565b005b34801561036857600080fd5b5061035a600160a060020a0360043516610e8f565b34801561038957600080fd5b5061035a610f88565b34801561039e57600080fd5b5061035a600160a060020a0360043516602435611094565b3480156103c257600080fd5b506103cb611243565b60408051600160a060020a039092168252519081900360200190f35b3480156103f357600080fd5b506103fc611255565b604080519115158252519081900360200190f35b34801561041c57600080fd5b5061035a602460048035828101929082013591813591820191013560443561125a565b34801561044b57600080fd5b506103fc60043561144a565b34801561046357600080fd5b5061046f600435611508565b60408051918252519081900360200190f35b34801561048d57600080fd5b506103cb6115bb565b3480156104a257600080fd5b506103fc6115cd565b3480156104b757600080fd5b5061035a6004356115fa565b3480156104cf57600080fd5b5061046f611684565b3480156104e457600080fd5b5061046f61168d565b3480156104f957600080fd5b5061035a60246004803582810192908201359181359182019101356116b7565b34801561052557600080fd5b5061052e6118b1565b60408051600160e060020a03199092168252519081900360200190f35b34801561055757600080fd5b5061046f6118bf565b34801561056c57600080fd5b5061046f600160a060020a03600435166118e9565b34801561058d57600080fd5b5061059661196e565b6040805160208082528351818301528351919283929083019185019080838360005b838110156105d05781810151838201526020016105b8565b50505050905090810190601f1680156105fd5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561061757600080fd5b5061046f600435611990565b34801561062f57600080fd5b5061046f600160a060020a0360043516611a04565b34801561065057600080fd5b506103fc600160a060020a0360043516611a8a565b34801561067157600080fd5b5061046f611ac2565b34801561068657600080fd5b5061035a600160a060020a0360043581169060243516611aec565b3480156106ad57600080fd5b506103fc600160a060020a03600435811690602435811690604435906064359060849060e4906101243581169061014435906101643516611c66565b3480156106f557600080fd5b5061035a611ebc565b34801561070a57600080fd5b5061035a6004803560248101910135611ed5565b34801561072a57600080fd5b506103cb611fd2565b34801561073f57600080fd5b5061035a600160a060020a0360043516612005565b34801561076057600080fd5b506103fc600435612067565b34801561077857600080fd5b5061046f6120a5565b34801561078d57600080fd5b506103fc6120cf565b3480156107a257600080fd5b5061046f6120d4565b3480156107b757600080fd5b506103cb612149565b3480156107cc57600080fd5b506103fc60043561217c565b3480156107e457600080fd5b5061035a600160a060020a03600435811690602435166121fd565b34801561080b57600080fd5b5061046f612223565b34801561082057600080fd5b506103cb61227d565b34801561083557600080fd5b5061046f6122c2565b34801561084a57600080fd5b506108536122ec565b6040805167ffffffffffffffff9485168152928416602084015292168183015290519081900360600190f35b34801561088b57600080fd5b5061035a6004356122f7565b3480156108a357600080fd5b5061035a600160a060020a036004351660243561236f565b3480156108c757600080fd5b5061035a600160a060020a0360043516602435612395565b3480156108eb57600080fd5b506103cb600160a060020a03600435166123bb565b34801561090c57600080fd5b5061035a60043561248d565b34801561092457600080fd5b5061046f6124b5565b34801561093957600080fd5b5061035a6004356124df565b34801561095157600080fd5b5061046f600160a060020a0360043516602435612569565b34801561097557600080fd5b5061035a600160a060020a036004351661264e565b34801561099657600080fd5b5061035a6004356126b0565b3480156109ae57600080fd5b5061035a600160a060020a03600435166024356126d5565b3480156109d257600080fd5b5061035a6004356128ff565b3480156109ea57600080fd5b5061046f600160a060020a0360043516612973565b348015610a0b57600080fd5b506103cb612a80565b348015610a2057600080fd5b5061035a600160a060020a03600435811690602435906044359060643516612a92565b348015610a4f57600080fd5b506103cb612b8d565b348015610a6457600080fd5b5061046f600160a060020a0360043516612bc0565b348015610a8557600080fd5b506103fc600160a060020a0360043516612c44565b348015610aa657600080fd5b5061059660048035906024803591600160a060020a0360443516916064359160843580830192908201359160a435918201910135612cca565b348015610aeb57600080fd5b5061035a600160a060020a0360043516612d51565b348015610b0c57600080fd5b5061046f612db3565b348015610b2157600080fd5b5061046f612e01565b348015610b3657600080fd5b506103cb612e2b565b348015610b4b57600080fd5b506103fc600435612e3d565b348015610b6357600080fd5b506103cb612e88565b348015610b7857600080fd5b5061035a600435612e9a565b348015610b9057600080fd5b5061035a600160a060020a0360043516612ef2565b348015610bb157600080fd5b5061035a600160a060020a0360043516612f17565b348015610bd257600080fd5b5061046f612f4a565b348015610be757600080fd5b5061035a612f74565b348015610bfc57600080fd5b5061046f61331c565b610c0d613346565b600160a060020a0383811691161415610c70576040805160e560020a62461bcd02815260206004820152601960248201527f52656c6179656420746f20427269646765206164647265737300000000000000604482015290519081900360640190fd5b600160a060020a0382161515610cd0576040805160e560020a62461bcd02815260206004820152601760248201527f52656c6179656420746f204e756c6c2061646472657373000000000000000000604482015290519081900360640190fd5b600160a060020a038216301415610d31576040805160e560020a62461bcd02815260206004820152601760248201527f52656c6179656420746f20746869732061646472657373000000000000000000604482015290519081900360640190fd5b60008111610d81576040805160e560020a62461bcd0281526020600482015260126024820152607060020a7152656c61796564207a65726f2066756e647302604482015290519081900360640190fd5b610d8a81612e3d565b1515610de0576040805160e560020a62461bcd02815260206004820152601a60248201527f4578636565647320627269646765206461696c79206c696d6974000000000000604482015290519081900360640190fd5b610df1610deb611684565b82613379565b610df9611243565b6040805160e060020a6323b872dd028152336004820152306024820152604481018490529051600160a060020a0392909216916323b872dd916064808201926020929091908290030181600087803b158015610e5457600080fd5b505af1158015610e68573d6000803e3d6000fd5b505050506040513d6020811015610e7e57600080fd5b50610e8b90508282613438565b5050565b600080600083610e9e81612c44565b1515610eee576040805160e560020a62461bcd0281526020600482015260146024820152606260020a73125b9d195c995cdd081b9bdd08115b98589b195902604482015290519081900360640190fd5b610ef7856134e2565b9350610f0285611a04565b9250828411610f50576040805160e560020a62461bcd02815260206004820152600f6024820152608860020a6e42616c616e636520746f6f204c6f7702604482015290519081900360640190fd5b8284039150610f7785610f7284610f6689612bc0565b9063ffffffff61356216565b613575565b610f8185836135f8565b5050505050565b6040805160e060020a6370a08231028152306004820152905160009182918291600080516020615dc3833981519152916370a082319160248082019260209290919082900301818787803b158015610fdf57600080fd5b505af1158015610ff3573d6000803e3d6000fd5b505050506040513d602081101561100957600080fd5b50519250611024600080516020615dc3833981519152611a04565b9150818310611073576040805160e560020a62461bcd0281526020600482015260106024820152608260020a6f109c9a5919d9481a5cc8119a5b1b195902604482015290519081900360640190fd5b5081810361108f600080516020615dc3833981519152826137b7565b505050565b6000806000846110a381612c44565b15156110f3576040805160e560020a62461bcd0281526020600482015260146024820152606260020a73125b9d195c995cdd081b9bdd08115b98589b195902604482015290519081900360640190fd5b6110fb611243565b600160a060020a03878116911614611153576040805160e560020a62461bcd0281526020600482015260106024820152608160020a6f2737ba10313934b233b2902a37b5b2b702604482015290519081900360640190fd5b61115c86612973565b935083851061116b578361116d565b845b9250611178866118e9565b8310156111cf576040805160e560020a62461bcd02815260206004820152601c60248201527f436f6c6c65637461626c6520696e74657265737420746f6f206c6f7700000000604482015290519081900360640190fd5b6111e086610f7285610f668a612bc0565b6111e9866123bb565b91506111f5828461380a565b60408051600160a060020a038481168252602082018690528251908916927f222348fe8b30f078a8a4da2f55f16d24d70bc40d3ec49d295d7ad1d11e666887928290030190a2505050505050565b600080516020615dc383398151915290565b600081565b600080600080600061126b33611a8a565b15156112b8576040805160e560020a62461bcd0281526020600482015260116024820152607960020a7034b73b30b634b2103337b93bb0b93232b902604482015290519081900360640190fd5b61132f8a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505089898080601f01602080910402602001604051908101604052809392919081815260200183838082843750611328945061227d9350505050565b6000613977565b6113688a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843750613bfb945050505050565b93985091965094509250905061137c611243565b600160a060020a0382811691161461139357600080fd5b61139c84612067565b1561143357838611156113ae57600080fd5b600160a060020a03821630146113c357600080fd5b6113cc8361144a565b156113d657600080fd5b6113e1836001613c5e565b6113ec858588613d25565b15156113f757600080fd5b60408051600160a060020a0387168152602081018690528082018590529051600080516020615be38339815191529181900360600190a161143e565b61143e858585610331565b50505050505050505050565b600060046000836040516020018080608860020a6e72656c617965644d6573736167657302815250600f0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b602083106114c45780518252601f1990920191602091820191016114a5565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1695945050505050565b6000806000836040516020018080608060020a6f746f74616c5370656e74506572446179028152506010018281526020019150506040516020818303038152906040526040518082805190602001908083835b6020831061157a5780518252601f19909201916020918201910161155b565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205495945050505050565b6000805160206159e383398151915290565b600080516020615d038339815191526000526004602052600080516020615b638339815191525460ff1690565b611602612149565b600160a060020a0316331461161657600080fd5b61161e6120a5565b811180611629575080155b151561163457600080fd5b600080516020615a4383398151915260009081526020908152600080516020615ca3833981519152829055604080518381529051600080516020615983833981519152929181900390910190a150565b62015180420490565b600080516020615c238339815191526000908152602052600080516020615c838339815191525490565b6000806000806000806117308a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505089898080601f01602080910402602001604051908101604052809392919081815260200183838082843750611328945061227d9350505050565b6117698a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843750613bfb945050505050565b93995091975095509350915061177e85612067565b156118a657600160a060020a038316301461179857600080fd5b6117a18461144a565b156117ab57600080fd5b6117b6846001613c5e565b60408051600160a060020a03881660601b60208083019190915260348201889052605480830188905283518084039091018152607490920192839052815191929182918401908083835b6020831061181f5780518252601f199092019160209182019101611800565b5181516020939093036101000a60001901801990911692169190911790526040519201829003909120935061185392505050565b61185f86868685613d4a565b151561186a57600080fd5b60408051600160a060020a0388168152602081018790528082018690529051600080516020615be38339815191529181900360600190a161143e565b61143e868686610331565b60e160020a630c3b16a30290565b600080516020615a438339815191526000908152602052600080516020615ca38339815191525490565b6000806000836040516020018080608a60020a6e1b5a5b925b9d195c995cdd14185a5902815250600f0182600160a060020a0316600160a060020a031660601b81526014019150506040516020818303038152906040526040518082805190602001908083836020831061157a5780518252601f19909201916020918201910161155b565b604080518082019091526005815260d860020a64312e302e3102602082015290565b6000806000836040516020018080606860020a72746f74616c4578656375746564506572446179028152506013018281526020019150506040516020818303038152906040526040518082805190602001908083836020831061157a5780518252601f19909201916020918201910161155b565b6000806000836040516020018080608260020a6f1b5a5b90d85cda151a1c995cda1bdb190281525060100182600160a060020a0316600160a060020a031660601b81526014019150506040516020818303038152906040526040518082805190602001908083836020831061157a5780518252601f19909201916020918201910161155b565b600080516020615a038339815191526000526002602052600080516020615ba383398151915254600160a060020a0390811691161490565b600080516020615b438339815191526000908152602052600080516020615e238339815191525490565b60008030600160a060020a0316636fde82026040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611b2a57600080fd5b505af1158015611b3e573d6000803e3d6000fd5b505050506040513d6020811015611b5457600080fd5b5051600160a060020a03163314611b6a57600080fd5b50600080516020615dc383398151915290506000805160206159e3833981519152600160a060020a038416821415611be2576040805160e560020a62461bcd0281526020600482015260106024820152608060020a6f43616e277420636c61696d205553445302604482015290519081900360640190fd5b80600160a060020a031684600160a060020a0316141580611c095750611c0782612c44565b155b1515611c56576040805160e560020a62461bcd0281526020600482015260116024820152607860020a7043616e277420636c61696d20735553445302604482015290519081900360640190fd5b611c608484613fac565b50505050565b6040805160048152602481018252602081018051600160e060020a031660e160020a6337ef4101021781529151815160009330939291829190808383895b83811015611cbc578181015183820152602001611ca4565b50505050905090810190601f168015611ce95780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af19150501580611d78575030600160a060020a0316636fde82026040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611d4057600080fd5b505af1158015611d54573d6000803e3d6000fd5b505050506040513d6020811015611d6a57600080fd5b5051600160a060020a031633145b80611d8257503330145b1515611d8d57600080fd5b611d956115cd565b15611d9f57600080fd5b611da88a613fea565b1515611db357600080fd5b611dbb611243565b600160a060020a038a8116911614611dd257600080fd5b8215611ddd57600080fd5b600080516020615b238339815191528054600160a060020a031916600160a060020a038c16179055600080516020615963833981519152600090815260205243600080516020615b0383398151915255611e3688613ff2565b611e3f87614061565b604080516060818101909252611e679188906003908390839080828437506140779350505050565b604080518082018252611e8c9187906002908390839080828437506141569350505050565b611e95846141d1565b611e9e82614277565b611ea66142d2565b611eae6115cd565b9a9950505050505050505050565b611ed3600080516020615dc3833981519152610e8f565b565b6004600083836040516020018080607860020a706461746153656e74576974684861736869028152506011018383808284378201915050925050506040516020818303038152906040526040518082805190602001908083835b60208310611f4e5780518252601f199092019160209182019101611f2f565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1615159250611f9991505057600080fd5b610e8b82828080601f01602080910402602001604051908101604052809392919081815260200183838082843750614305945050505050565b600080516020615b838339815191526000526002602052600080516020615a6383398151915254600160a060020a031690565b61200d612149565b600160a060020a0316331461202157600080fd5b600080516020615ae38339815191526000526002602052600080516020615de38339815191528054600160a060020a031916600160a060020a0392909216919091179055565b60008061207e83610f66612079611684565b611990565b9050806120896118bf565b1015801561209e575061209a6120a5565b8311155b9392505050565b600080516020615e0383398151915260009081526020526000805160206159a38339815191525490565b600181565b60006120de61227d565b600160a060020a0316638d0680436040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561211857600080fd5b505af115801561212c573d6000803e3d6000fd5b505050506040513d602081101561214257600080fd5b5051905090565b600080516020615c638339815191526000526002602052600080516020615c4383398151915254600160a060020a031690565b600060046000836040516020018080604860020a766d65737361676573417070726f76656442794861736869028152506017018260001916600019168152602001915050604051602081830303815290604052604051808280519060200190808383602083106114c45780518252601f1990920191602091820191016114a5565b612205612149565b600160a060020a0316331461221957600080fd5b610e8b82826147d7565b6000806000806000612233612f4a565b935061223d611ac2565b925061224f61224a611684565b611508565b915081831161225f576000612263565b8183035b90508084106122725780612274565b835b94505050505090565b7f5a74bb7e202fb8e4bf311841c7d64ec19df195fee77d7e7ae749b27921b6ddfe6000526002602052600080516020615b2383398151915254600160a060020a031690565b6000805160206159638339815191526000908152602052600080516020615b038339815191525490565b600660016000909192565b6122ff612149565b600160a060020a0316331461231357600080fd5b6000811180156123295750612326611ac2565b81105b801561233b5750612338612f4a565b81105b151561234657600080fd5b600080516020615a838339815191526000908152602052600080516020615d2383398151915255565b612377612149565b600160a060020a0316331461238b57600080fd5b610e8b828261490a565b61239d612149565b600160a060020a031633146123b157600080fd5b610e8b828261498e565b600060026000836040516020018080608160020a6f34b73a32b932b9ba2932b1b2b4bb32b90281525060100182600160a060020a0316600160a060020a031660601b81526014019150506040516020818303038152906040526040518082805190602001908083835b602083106124435780518252601f199092019160209182019101612424565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054600160a060020a031695945050505050565b612495612149565b600160a060020a031633146124a957600080fd5b6124b281613ff2565b50565b600080516020615bc38339815191526000908152602052600080516020615ac38339815191525490565b6124e7612149565b600160a060020a031633146124fb57600080fd5b612503612f4a565b81118061250e575080155b151561251957600080fd5b600080516020615b4383398151915260009081526020908152600080516020615e23833981519152829055604080518381529051600080516020615d83833981519152929181900390910190a150565b6000600080516020615dc3833981519152600160a060020a038416146125c7576040805160e560020a62461bcd028152602060048201526008602482015260c060020a676e6f74205553445302604482015290519081900360640190fd5b6000805160206159e3833981519152600160a060020a0316630a28a477836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561261b57600080fd5b505af115801561262f573d6000803e3d6000fd5b505050506040513d602081101561264557600080fd5b50519392505050565b612656612149565b600160a060020a0316331461266a57600080fd5b600080516020615b838339815191526000526002602052600080516020615a638339815191528054600160a060020a031916600160a060020a0392909216919091179055565b6126b8612149565b600160a060020a031633146126cc57600080fd5b6124b281614061565b600080600030600160a060020a0316636fde82026040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561271557600080fd5b505af1158015612729573d6000803e3d6000fd5b505050506040513d602081101561273f57600080fd5b5051600160a060020a0316331461275557600080fd5b6040805160e060020a6370a082310281523060048201529051600080516020615dc3833981519152916370a082319160248083019260209291908290030181600087803b1580156127a557600080fd5b505af11580156127b9573d6000803e3d6000fd5b505050506040513d60208110156127cf57600080fd5b505192506127ea600080516020615dc3833981519152611a04565b9150828410612843576040805160e560020a62461bcd02815260206004820152601860248201527f696e76616c69642077697468647261772062616c616e63650000000000000000604482015290519081900360640190fd5b81848403101561286c578284830103905061286c600080516020615dc3833981519152826137b7565b6040805160e060020a63a9059cbb028152600160a060020a0387166004820152602481018690529051600080516020615dc38339815191529163a9059cbb9160448083019260209291908290030181600087803b1580156128cc57600080fd5b505af11580156128e0573d6000803e3d6000fd5b505050506040513d60208110156128f657600080fd5b50505050505050565b612907612149565b600160a060020a0316331461291b57600080fd5b80158061293f575061292b612e01565b8111801561293f575061293c611ac2565b81105b151561294a57600080fd5b6000805160206159c38339815191526000908152602052600080516020615ce383398151915255565b60008080600080516020615dc3833981519152600160a060020a038516146129d3576040805160e560020a62461bcd028152602060048201526008602482015260c060020a674e6f74205553445302604482015290519081900360640190fd5b6040805160e060020a63ce96cb7702815230600482015290516000805160206159e38339815191529163ce96cb779160248083019260209291908290030181600087803b158015612a2357600080fd5b505af1158015612a37573d6000803e3d6000fd5b505050506040513d6020811015612a4d57600080fd5b50519150612a5a84612bc0565b670de0b6b3a7640000019050808211612a74576000612a78565b8082035b949350505050565b600080516020615dc383398151915281565b612a9a612149565b600160a060020a03163314612aae57600080fd5b612ab784614a13565b1515612b06576040805160e560020a62461bcd0281526020600482015260136024820152606a60020a72151bdad95b881b9bdd081cdd5c1c1bdc9d195902604482015290519081900360640190fd5b612b0f84612c44565b15612b64576040805160e560020a62461bcd02815260206004820152601860248201527f496e74657265737420616c726561647920656e61626c65640000000000000000604482015290519081900360640190fd5b612b6f846001614a2f565b612b79848461498e565b612b83848361490a565b611c6084826147d7565b600080516020615a038339815191526000526002602052600080516020615ba383398151915254600160a060020a031690565b6000806000836040516020018080609260020a6d1a5b9d995cdd1959105b5bdd5b9d02815250600e0182600160a060020a0316600160a060020a031660601b81526014019150506040516020818303038152906040526040518082805190602001908083836020831061157a5780518252601f19909201916020918201910161155b565b600060046000836040516020018080608a60020a6e1a5b9d195c995cdd115b98589b195902815250600f0182600160a060020a0316600160a060020a031660601b8152601401915050604051602081830303815290604052604051808280519060200190808383602083106114c45780518252601f1990920191602091820191016114a5565b60606000612d0789888a89898080602002602001604051908101604052809392919081815260200183836020028082843750614ab4945050505050565b83836040518083838082843782019150509250505060405180910390209050612d2f8161217c565b15612d3957600080fd5b612d44816001614db7565b5098975050505050505050565b612d59612149565b600160a060020a03163314612d6d57600080fd5b600080516020615a038339815191526000526002602052600080516020615ba38339815191528054600160a060020a031916600160a060020a0392909216919091179055565b7f1e8ecaafaddea96ed9ac6d2642dcdfe1bebe58a930b1085842d8fc122b371ee560009081526020527fd5c78dd9468716ca9bb96be25d56436811b20aab3523a9904b12deef1cab239d5490565b600080516020615a838339815191526000908152602052600080516020615d238339815191525490565b600080516020615aa383398151915281565b600080612e4f83610f6661224a611684565b905080612e5a611ac2565b10158015612e6f5750612e6b612f4a565b8311155b801561209e5750612e7e612e01565b9092101592915050565b600080516020615d4383398151915281565b612ea2612149565b600160a060020a03163314612eb657600080fd5b612ebe6118bf565b8110612ec957600080fd5b600080516020615e0383398151915260009081526020526000805160206159a383398151915255565b612efa612149565b600160a060020a03163314612f0e57600080fd5b6124b2816141d1565b612f1f612149565b600160a060020a03163314612f3357600080fd5b612f3f816000196137b7565b6124b2816000614a2f565b6000805160206159c38339815191526000908152602052600080516020615ce38339815191525490565b60408051606860020a72757067726164655f4441495f746f5f55534453028152815190819003601301902060008181526004602052918220549091908190819060ff161561300c576040805160e560020a62461bcd02815260206004820152601d60248201527f5553445320627269646765207567707261646520636f6d706c65746564000000604482015290519081900360640190fd5b6040805160e060020a63ce96cb7702815230600482015290517383f20f44975d03b1b09e64809b757c47f942beea9450849163ce96cb779160248083019260209291908290030181600087803b15801561306557600080fd5b505af1158015613079573d6000803e3d6000fd5b505050506040513d602081101561308f57600080fd5b50516040805160e260020a632d182be502815260048101839052306024820181905260448201529051919350600160a060020a0385169163b460af94916064808201926020929091908290030181600087803b1580156130ee57600080fd5b505af1158015613102573d6000803e3d6000fd5b505050506040513d602081101561311857600080fd5b506131349050600080516020615aa38339815191526000613575565b61314d600080516020615aa38339815191526000614a2f565b613166600080516020615aa3833981519152600061498e565b61317f600080516020615aa3833981519152600061490a565b6040805160e060020a6370a082310281523060048201529051600080516020615aa3833981519152916370a082319160248083019260209291908290030181600087803b1580156131cf57600080fd5b505af11580156131e3573d6000803e3d6000fd5b505050506040513d60208110156131f957600080fd5b50516040805160e060020a63095ea7b3028152600080516020615d438339815191526004820152602481018390529051919250600080516020615aa38339815191529163095ea7b3916044808201926020929091908290030181600087803b15801561326457600080fd5b505af1158015613278573d6000803e3d6000fd5b505050506040513d602081101561328e57600080fd5b50506040805160e160020a6379603d57028152306004820152602481018390529051600080516020615d438339815191529163f2c07aae91604480830192600092919082900301818387803b1580156132e657600080fd5b505af11580156132fa573d6000803e3d6000fd5b505050600094855250506004602052505060409020805460ff19166001179055565b600080516020615c038339815191526000908152602052600080516020615cc38339815191525490565b600080516020615a238339815191526000526002602052600080516020615d6383398151915254600160a060020a031690565b61338681610f6684611508565b600080846040516020018080608060020a6f746f74616c5370656e74506572446179028152506010018281526020019150506040516020818303038152906040526040518082805190602001908083835b602083106133f65780518252601f1990920191602091820191016133d7565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050565b60006134426124b5565b905061345081600101614e37565b60408051600160a060020a038516815260208101849052600083901b8183015290517ff6968e689b3d8c24f22c10c2a3256bb5ca483a474e11bac08423baa049e38ae89181900360600190a160408051600160a060020a03851660601b602082015260348101849052600083901b60548083019190915282518083039091018152607490910190915261108f90614e60565b6040805160e060020a6370a082310281523060048201529051600091600160a060020a038416916370a082319160248082019260209290919082900301818787803b15801561353057600080fd5b505af1158015613544573d6000803e3d6000fd5b505050506040513d602081101561355a57600080fd5b505192915050565b8181018281101561356f57fe5b92915050565b80600080846040516020018080609260020a6d1a5b9d995cdd1959105b5bdd5b9d02815250600e0182600160a060020a0316600160a060020a031660601b8152601401915050604051602081830303815290604052604051808280519060200190808383602083106133f65780518252601f1990920191602091820191016133d7565b600080516020615dc3833981519152600160a060020a03831614613654576040805160e560020a62461bcd028152602060048201526008602482015260c060020a676e6f74205553445302604482015290519081900360640190fd5b6040805160e060020a63095ea7b30281526000805160206159e38339815191526004820152602481018390529051600080516020615dc38339815191529163095ea7b39160448083019260209291908290030181600087803b1580156136b957600080fd5b505af11580156136cd573d6000803e3d6000fd5b505050506040513d60208110156136e357600080fd5b50506040805160e060020a636e553f650281526004810183905230602482015290516000916000805160206159e383398151915291636e553f659160448082019260209290919082900301818787803b15801561373f57600080fd5b505af1158015613753573d6000803e3d6000fd5b505050506040513d602081101561376957600080fd5b505111610e8b576040805160e560020a62461bcd0281526020600482015260116024820152607a60020a7011985a5b1959081d1bc819195c1bdcda5d02604482015290519081900360640190fd5b60008060006137c585612bc0565b92508284116137d457836137d6565b825b91508115156137e457610f81565b6137ee8583614f70565b9050610f8185828511613802576000610f72565b828503613575565b600160a060020a038216151561386a576040805160e560020a62461bcd02815260206004820152601660248201527f52656365697665722063616e2774206265204e756c6c00000000000000000000604482015290519081900360640190fd5b600160a060020a0382163014156138b9576040805160e560020a62461bcd02815260206004820152601c6024820152600080516020615da3833981519152604482015290519081900360640190fd5b6000811161390a576040805160e560020a62461bcd0281526020600482015260136024820152606860020a7252656c61796564207a65726f20746f6b656e7302604482015290519081900360640190fd5b61391381612e3d565b1515613962576040805160e560020a62461bcd0281526020600482015260136024820152606a60020a7214995b185e59590818589bdd99481b1a5b5a5d02604482015290519081900360640190fd5b61396d610deb611684565b610e8b8282613438565b6000806000606060008060008060008060008b8061399957506139998f614ffb565b15156139a457600080fd5b8c600160a060020a0316638d0680436040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156139df57600080fd5b505af11580156139f3573d6000803e3d6000fd5b505050506040513d6020811015613a0957600080fd5b505160018f0151909b5060ff1699508a8a1015613a2557600080fd5b613a2f8f8d615010565b98508a604051908082528060200260200182016040528015613a5b578160200160208202803883390190505b509750600096505b8a871015613bea57866020028a6021010192508960200283019150866002018e01519550828e01519450818e01519350600189878787604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af1158015613b0a573d6000803e3d6000fd5b5050506020604051035190508c600160a060020a031663facd743b826040518263ffffffff1660e01b81526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b158015613b6e57600080fd5b505af1158015613b82573d6000803e3d6000fd5b505050506040513d6020811015613b9857600080fd5b50511515613ba557600080fd5b613baf8882615240565b15613bb957600080fd5b808888815181101515613bc857fe5b600160a060020a03909216602092830290910190910152600190960195613a63565b505050505050505050505050505050565b6000806000806000613c0c86614ffb565b1515613c1757600080fd5b60148601519450603486015193506054860151925060688601519150607c8601519050855160681415613c555750600080516020615aa38339815191525b91939590929450565b8060046000846040516020018080608860020a6e72656c617965644d6573736167657302815250600f0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310613cd75780518252601f199092019160209182019101613cb8565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff1916941515949094179093555050505050565b6000613d3f600080516020615dc38339815191528461529b565b612a78848484615347565b600080613d5e613d58611684565b866154ae565b50600080516020615dc3833981519152613d78818661529b565b600160a060020a038316600080516020615aa38339815191521415613f24576040805160e060020a63095ea7b3028152600080516020615d438339815191526004820152602481018790529051600160a060020a0383169163095ea7b39160448083019260209291908290030181600087803b158015613df757600080fd5b505af1158015613e0b573d6000803e3d6000fd5b505050506040513d6020811015613e2157600080fd5b50506040805160e460020a63068f3015028152306004820152602481018790529051600080516020615d43833981519152916368f3015091604480830192600092919082900301818387803b158015613e7957600080fd5b505af1158015613e8d573d6000803e3d6000fd5b50506040805160e060020a63a9059cbb028152600160a060020a038a166004820152602481018990529051600080516020615aa3833981519152935063a9059cbb925060448083019260209291908290030181600087803b158015613ef157600080fd5b505af1158015613f05573d6000803e3d6000fd5b505050506040513d6020811015613f1b57600080fd5b50519150613fa3565b600160a060020a038316600080516020615dc383398151915214156103315780600160a060020a031663a9059cbb87876040518363ffffffff1660e01b81526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b158015613ef157600080fd5b50949350505050565b80600160a060020a0381161515613fc257600080fd5b600160a060020a0383161515613fe057613fdb8261552d565b61108f565b61108f8383615539565b6000903b1190565b60008111613fff57600080fd5b600080516020615c2383398151915260009081526020908152600080516020615c838339815191528290556040805183815290517f4fb76205cd57c896b21511d2114137d8e901b4ccd659e1a0f97d6306795264fb929181900390910190a150565b6000811161406e57600080fd5b6124b2816155d0565b60408101516000108015614092575060408101516020820151115b80156140a2575060208101518151115b15156140ad57600080fd5b8051600080516020615b4383398151915260009081526020818152600080516020615e2383398151915292909255908201516000805160206159c38339815191528252600080516020615ce3833981519152556040820151600080516020615a838339815191528252600080516020615d2383398151915255600080516020615d838339815191529082905b60200201516040518082815260200191505060405180910390a150565b805160208201511061416757600080fd5b8051600080516020615a4383398151915260009081526020818152600080516020615ca38339815191529290925590820151600080516020615e0383398151915282526000805160206159a383398151915255600080516020615983833981519152908290614139565b600160a060020a03811615156141e657600080fd5b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e061420f612149565b60408051600160a060020a03928316815291841660208301528051918290030190a1600080516020615c638339815191526000526002602052600080516020615c438339815191528054600160a060020a031916600160a060020a0392909216919091179055565b600160a060020a038116151561428c57600080fd5b600080516020615a238339815191526000526002602052600080516020615d638339815191528054600160a060020a031916600160a060020a0392909216919091179055565b600080516020615d038339815191526000526004602052600080516020615b63833981519152805460ff19166001179055565b600061430f611fd2565b905080600160a060020a031663ee4937ba6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561434c57600080fd5b505af1158015614360573d6000803e3d6000fd5b505050506040513d602081101561437657600080fd5b50516040805160e160020a630a37fd930281529051600160a060020a03928316926339d0bf63929085169163146ffb26916004808201926020929091908290030181600087803b1580156143c957600080fd5b505af11580156143dd573d6000803e3d6000fd5b505050506040513d60208110156143f357600080fd5b50516040805160e360020a630859bc9d0281529051600160a060020a038616916342cde4e89160048083019260209291908290030181600087803b15801561443a57600080fd5b505af115801561444e573d6000803e3d6000fd5b505050506040513d602081101561446457600080fd5b50516040805160e160020a63290875ab0281529051600160a060020a03871691635210eb569160048083019260209291908290030181600087803b1580156144ab57600080fd5b505af11580156144bf573d6000803e3d6000fd5b505050506040513d60208110156144d557600080fd5b50516040805160e160020a6378a26a4302815290518891600160a060020a0389169163f144d4869160048082019260009290919082900301818387803b15801561451e57600080fd5b505af1158015614532573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561455b57600080fd5b810190808051602060020a81111561457257600080fd5b8201602081018481111561458557600080fd5b81518560208202830111602060020a821117156145a157600080fd5b505092919050505087600160a060020a0316636b6e93d56040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156145e457600080fd5b505af11580156145f8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561462157600080fd5b810190808051602060020a81111561463857600080fd5b8201602081018481111561464b57600080fd5b81518560208202830111602060020a8211171561466757600080fd5b505060405163ffffffff8b1660e01b8152600481018a8152602482018a9052600160a060020a038916604483015260c060648301908152885160c484015288519396509094509250608481019160a482019160e40190602089019080838360005b838110156146e05781810151838201526020016146c8565b50505050905090810190601f16801561470d5780820380516001836020036101000a031916815260200191505b508481038352865181528651602091820191808901910280838360005b8381101561474257818101518382015260200161472a565b50505050905001848103825285818151815260200191508051906020019060200280838360005b83811015614781578181015183820152602001614769565b505050509050019950505050505050505050602060405180830381600087803b1580156147ad57600080fd5b505af11580156147c1573d6000803e3d6000fd5b505050506040513d6020811015611c6057600080fd5b600160a060020a038116301415614826576040805160e560020a62461bcd02815260206004820152601c6024820152600080516020615da3833981519152604482015290519081900360640190fd5b8060026000846040516020018080608160020a6f34b73a32b932b9ba2932b1b2b4bb32b90281525060100182600160a060020a0316600160a060020a031660601b81526014019150506040516020818303038152906040526040518082805190602001908083835b602083106148ad5780518252601f19909201916020918201910161488e565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000208054600160a060020a031916600160a060020a0395909516949094179093555050505050565b80600080846040516020018080608a60020a6e1b5a5b925b9d195c995cdd14185a5902815250600f0182600160a060020a0316600160a060020a031660601b8152601401915050604051602081830303815290604052604051808280519060200190808383602083106133f65780518252601f1990920191602091820191016133d7565b80600080846040516020018080608260020a6f1b5a5b90d85cda151a1c995cda1bdb190281525060100182600160a060020a0316600160a060020a031660601b8152601401915050604051602081830303815290604052604051808280519060200190808383602083106133f65780518252601f1990920191602091820191016133d7565b600160a060020a0316600080516020615dc38339815191521490565b8060046000846040516020018080608a60020a6e1a5b9d195c995cdd115b98589b195902815250600f0182600160a060020a0316600160a060020a031660601b815260140191505060405160208183030381529060405260405180828051906020019080838360208310613cd75780518252601f199092019160209182019101613cb8565b6000614abe611fd2565b905080600160a060020a031663789b11d76040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614afb57600080fd5b505af1158015614b0f573d6000803e3d6000fd5b505050506040513d6020811015614b2557600080fd5b5051600160a060020a031633148015614ba3575080600160a060020a031663146ffb266040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614b7457600080fd5b505af1158015614b88573d6000803e3d6000fd5b505050506040513d6020811015614b9e57600080fd5b505185145b8015614c20575080600160a060020a0316635210eb566040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614be557600080fd5b505af1158015614bf9573d6000803e3d6000fd5b505050506040513d6020811015614c0f57600080fd5b5051600160a060020a038481169116145b8015614c91575080600160a060020a0316632690ff8b6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614c6257600080fd5b505af1158015614c76573d6000803e3d6000fd5b505050506040513d6020811015614c8c57600080fd5b505184145b8015614dac575080600160a060020a031663f238ca266040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614cd357600080fd5b505af1158015614ce7573d6000803e3d6000fd5b505050506040513d6020811015614cfd57600080fd5b5051604051835184916020908101918291848101910280838360005b83811015614d31578181015183820152602001614d19565b505050509050019150506040516020818303038152906040526040518082805190602001908083835b60208310614d795780518252601f199092019160209182019101614d5a565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916145b1515610f8157600080fd5b8060046000846040516020018080604860020a766d65737361676573417070726f7665644279486173686902815250601701826000191660001916815260200191505060405160208183030381529060405260405180828051906020019080838360208310613cd75780518252601f199092019160209182019101613cb8565b600080516020615bc38339815191526000908152602052600080516020615ac383398151915255565b600160046000836040516020018080607860020a706461746153656e745769746848617368690281525060110182805190602001908083835b60208310614eb85780518252601f199092019160209182019101614e99565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b60208310614f1b5780518252601f199092019160209182019101614efc565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff191694151594909417909355506124b29150829050614305565b6000806000614f7e856134e2565b9150614f8a8585615632565b81614f94866134e2565b03905083811015614fef576040805160e560020a62461bcd02815260206004820152601a60248201527f57697468647261776e206c657373207468616e20416d6f756e74000000000000604482015290519081900360640190fd5b8092505b505092915050565b600081516068148061356f57505051607c1490565b60408051808201909152601a81527f19457468657265756d205369676e6564204d6573736167653a0a0000000000006020820152600090606083156151b6578161505a8651615768565b866040516020018084805190602001908083835b6020831061508d5780518252601f19909201916020918201910161506e565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b602083106150d55780518252601f1990920191602091820191016150b6565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b6020831061511d5780518252601f1990920191602091820191016150fe565b6001836020036101000a03801982511681845116808217855250505050505090500193505050506040516020818303038152906040526040518082805190602001908083835b602083106151825780518252601f199092019160209182019101615163565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250614ff3565b8451606814156151e35750604080518082019091526003815260ea60020a620c4c0d02602082015261520c565b8451607c14156103315750604080518082019091526003815260ea60020a620c4c8d0260208201525b8181866040516020018084805190602001908083836020831061508d5780518252601f19909201916020918201910161506e565b6000805b835181101561528f5782600160a060020a0316848281518110151561526557fe5b90602001906020020151600160a060020a031614156152875760019150615294565b600101615244565b600091505b5092915050565b6040805160e060020a6370a0823102815230600482015290516000918291600160a060020a038616916370a0823191602480830192602092919082900301818787803b1580156152ea57600080fd5b505af11580156152fe573d6000803e3d6000fd5b505050506040513d602081101561531457600080fd5b5051915082821015611c605761533b61532c85611a04565b8385039063ffffffff61356216565b9050611c6084826137b7565b60008060008061535e615358611684565b876154ae565b615366611243565b600080516020615ae3833981519152600090815260026020908152600080516020615de3833981519152546040805160e060020a63a9059cbb028152600160a060020a039283166004820152602481018b905290519497509087169363a9059cbb93604480840194938390030190829087803b1580156153e557600080fd5b505af11580156153f9573d6000803e3d6000fd5b505050506040513d602081101561540f57600080fd5b50516040805160e060020a63a9059cbb028152600160a060020a038a81166004830152888a03602483015291519294509085169163a9059cbb916044808201926020929091908290030181600087803b15801561546b57600080fd5b505af115801561547f573d6000803e3d6000fd5b505050506040513d602081101561549557600080fd5b505190508180156154a35750805b979650505050505050565b6154bb81610f6684611990565b600080846040516020018080606860020a72746f74616c457865637574656450657244617902815250601301828152602001915050604051602081830303815290604052604051808280519060200190808383602083106133f65780518252601f1990920191602091820191016133d7565b3031610e8b828261583f565b6040805160e060020a6370a0823102815230600482015290518391600091600160a060020a038416916370a0823191602480830192602092919082900301818787803b15801561558857600080fd5b505af115801561559c573d6000803e3d6000fd5b505050506040513d60208110156155b257600080fd5b50519050611c60600160a060020a038516848363ffffffff6158a016565b600080516020615c0383398151915260009081526020908152600080516020615cc38339815191528290556040805183815290517f52264b89e0fceafb26e79fd49ef8a366eb6297483bf4035b027f0c99a7ad512e929181900390910190a150565b600080516020615dc3833981519152600160a060020a0383161461568e576040805160e560020a62461bcd028152602060048201526008602482015260c060020a676e6f74205553445302604482015290519081900360640190fd5b6040805160e260020a632d182be5028152600481018390523060248201819052604482015290516000916000805160206159e38339815191529163b460af949160648082019260209290919082900301818787803b1580156156ef57600080fd5b505af1158015615703573d6000803e3d6000fd5b505050506040513d602081101561571957600080fd5b505111610e8b576040805160e560020a62461bcd0281526020600482015260126024820152607060020a714661696c656420746f20776974686472617702604482015290519081900360640190fd5b6060600080828185151561579857604080518082019091526001815260fc60020a60030260208201529450615836565b8593505b83156157b357600190920191600a8404935061579c565b826040519080825280601f01601f1916602001820160405280156157e1578160200160208202803883390190505b5091505060001982015b85156158325781516000198201916030600a89060160f81b91849190811061580f57fe5b906020010190600160f860020a031916908160001a905350600a860495506157eb565b8194505b50505050919050565b604051600160a060020a0383169082156108fc029083906000818181858888f193505050501515610e8b578082615874615932565b600160a060020a039091168152604051908190036020019082f080158015610f81573d6000803e3d6000fd5b82600160a060020a031663a9059cbb83836040518363ffffffff1660e01b81526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050600060405180830381600087803b15801561590057600080fd5b505af1158015615914573d6000803e3d6000fd5b505050503d1561108f5760206000803e600051151561108f57600080fd5b604051602180615942833901905600608060405260405160208060218339810160405251600160a060020a038116ff00b120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b09bebf928b90863f24cc31f726a3a7545efd409f1dcf552301b1ee3710da70d3bf8e983ee86e5e377e9e34c9131b266382c3f04113d20de077f9e12663c7a646b0f8803acad17c63ee38bf2de71e1888bc7a079a6f73658e274b08018bea4e29c000000000000000000000000a3931d71877c0e7a3148cb7eb4463524fec27fbd222cb212229f0f9bcd249029717af6845ea3d3a84f22b54e5744ac25ef224c9271483949fe7a14d16644d63320f24d10cf1d60abecc30cc677a340e82b699dd221dbcab260e413c20dc13c28b7db95e2b423d1135f42bb8b7d5214a92270d237b1578d368dec034f5de4adb7567061a469e92e7039fd319ab435573139ccbcc6bbb088c505d18e049d114c7c91f11724e69c55ad6c5397e2b929e68b41fa05d10000000000000000000000006b175474e89094c44da98b954eedeac495271d0f8ba1484e8bf7939787444e92eb98a67eb881960295fd73460f6d5e6df6d34d1ffefcc139ed357999ed60c6a013947328d52e7d9751e93fd0274a2bfae5cbcb12e66bef0282a446f9848e2903380099bb6e431483ee78778868f33b4a154c818bab54f3fbbe62c59b7876a9bf9bd5e0c22dbae93f4d8ee0438f7ce62b198eb0e04a6a899679f26b73530d8cf1001e83b6f7702e04b6fdb98f3c62dc7e47e041a5078d888f9b66f3f8bfa10909e31f1e16240db73449f0500afdbbe3a70da457cc660d8ed18395a9aa930e304e0bb5e6e51957af1fa215b11db48bfda3dd38d511b3492a958ebdd65bd9a0b8ebca07c67a2ad3af56a28fc2944e214aa69ec9581b8fe4c9f18420598a0f0a5c996b969714f39cc770f1900e60d2697139e137749b4ab7d581336d92edbea22636a613e8e76c99ac7f91137c1523db38dbfb3bf32955b3774520b5993024893d303890baa4e84b1244a43c60034d1ced2d3cf2b04b916daedf6915000ff68ced2f0b6773fe6f2582237f92c3c95bb4d79407230071b7802e97e87ef2842a6cce7da7ffaeaedaa2f61a6a7870b23d9d01fc9b73712e02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0d2ea0feb732edb0ffe32efd33a6b9d24d46b16eb34a4d07ce256537b6f131e42add938dbd083a16bae12238cd914fca0afc7a30edb55b1cd5c7f1823f1b0e421f7d5eefab3776d7f0450bd0193564bcb4f832ce313ff2836c450fc63a4b944199de0f81379b4d8e60fe509315d071b56e7b732abaf193e74e0d15808b0951d090a6f646cd611241d8073675e00d1a1ff700fbf1b53fcf473de56d1e6e4b714ba8df5c48c6b6e11d97548adc824ba0c99103ec09830fa5d53a179984085e6eaa00000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a21ffdf150a5d180f96d98d16f50e7b4dd63e2a067adc8386cf5af55dcecd8dd9ad4123ae17c414d9c6d2fec478b402e6b01856cc250fd01fbfd252fda0089d3c52656365697665722063616e2774206265207468652042726964676500000000000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384ff215aff72f0a1a7d74fcd807336e100b80bbb56cdfb43843ade07ecf211a979fc0ed44c192c86d1cc1ba51340b032c2766b4a2b0041031de13c46dd7104888d51ab29a5cca988aee50edccdd61c5bcaa7ad4b29a03b7ee50f298ceccfe14cc4ea165627a7a723058206d3bf9eb229128196dce5dc14ada05a523133a08c3e79e95a72034085dbc93600029

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

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