Contract 0x714b49640c2a545B672e8bbD53cC8935725C6a14

 
Txn Hash Method
Block
From
To
Value
0x73647497a7eb4ebe9d210e57c11338e379109d0daaffe8c00695eb53bde4322fInitialize131802832021-09-07 18:33:0011 days 22 hrs ago0xc8e0b91a47b66cec16be2528fab2a36ec7db38f8 IN 0x714b49640c2a545b672e8bbd53cc8935725c6a140 Ether0.047834399813 178.380736106
0xbe4091fcd7cdf219d0737f64c93b6cba0554f730661fecbc10c15fa2d900841e0x60806040130925192021-08-25 4:58:3025 days 11 hrs ago0x7c6c6ea036e56efad829af5070c8fb59dc163d88 IN  Create: BridgeBank0 Ether0.46429307199
[ Download CSV Export 
View more zero value Internal Transactions in Advanced View mode
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BridgeBank

Compiler Version
v0.5.16+commit.9c3226ce

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 30 : BridgeBank.sol
pragma solidity 0.5.16;

import "./CosmosBank.sol";
import "./EthereumBank.sol";
import "./EthereumWhitelist.sol";
import "./CosmosWhiteList.sol";
import "../Oracle.sol";
import "../CosmosBridge.sol";
import "./BankStorage.sol";
import "./Pausable.sol";

/*
 * @title BridgeBank
 * @dev Bank contract which coordinates asset-related functionality.
 *      CosmosBank manages the minting and burning of tokens which
 *      represent Cosmos based assets, while EthereumBank manages
 *      the locking and unlocking of Ethereum and ERC20 token assets
 *      based on Ethereum. WhiteList records the ERC20 token address 
 *      list that can be locked.
 **/

contract BridgeBank is BankStorage,
    CosmosBank,
    EthereumBank,
    EthereumWhiteList,
    CosmosWhiteList,
    Pausable {

    bool private _initialized;

    using SafeMath for uint256;

    /*
     * @dev: Initializer, sets operator
     */
    function initialize(
        address _operatorAddress,
        address _cosmosBridgeAddress,
        address _owner,
        address _pauser
    ) public {
        require(!_initialized, "Init");

        EthereumWhiteList.initialize();
        CosmosWhiteList.initialize();
        Pausable.initialize(_pauser);

        operator = _operatorAddress;
        cosmosBridge = _cosmosBridgeAddress;
        owner = _owner;
        _initialized = true;

        // hardcode since this is the first token
        lowerToUpperTokens["erowan"] = "erowan";
        lowerToUpperTokens["eth"] = "eth";
    }

    /*
     * @dev: Modifier to restrict access to operator
     */
    modifier onlyOperator() {
        require(msg.sender == operator, "!operator");
        _;
    }

    /*
     * @dev: Modifier to restrict access to operator
     */
    modifier onlyOwner() {
        require(msg.sender == owner, "!owner");
        _;
    }

    /*
     * @dev: Modifier to restrict access to the cosmos bridge
     */
    modifier onlyCosmosBridge() {
        require(
            msg.sender == cosmosBridge,
            "!cosmosbridge"
        );
        _;
    }

    /*
     * @dev: Modifier to only allow valid sif addresses
     */
    modifier validSifAddress(bytes memory _sifAddress) {
        require(_sifAddress.length == 42, "Invalid len");
        require(verifySifPrefix(_sifAddress) == true, "Invalid sif address");
        _;
    }

    function changeOwner(address _newOwner) public onlyOwner {
        require(_newOwner != address(0), "invalid address");
        owner = _newOwner;
    }

    function changeOperator(address _newOperator) public onlyOperator {
        require(_newOperator != address(0), "invalid address");
        operator = _newOperator;
    }

    /*
     * @dev: function to validate if a sif address has a correct prefix
     */
    function verifySifPrefix(bytes memory _sifAddress) public pure returns (bool) {
        bytes3 sifInHex = 0x736966;

        for (uint256 i = 0; i < sifInHex.length; i++) {
            if (sifInHex[i] != _sifAddress[i]) {
                return false;
            }
        }
        return true;
    }

    /*
     * @dev: Creates a new BridgeToken
     *
     * @param _symbol: The new BridgeToken's symbol
     * @return: The new BridgeToken contract's address
     */
    function createNewBridgeToken(string memory _symbol)
        public
        onlyCosmosBridge
        returns (address)
    {
        address newTokenAddress = deployNewBridgeToken(_symbol);
        setTokenInCosmosWhiteList(newTokenAddress, true);
        return newTokenAddress;
    }

    /*
     * @dev: Creates a new BridgeToken
     *
     * @param _symbol: The new BridgeToken's symbol
     * @return: The new BridgeToken contract's address
     */
    function addExistingBridgeToken(
        address _contractAddress
    ) public onlyOwner returns (address) {
        setTokenInCosmosWhiteList(_contractAddress, true);

        return useExistingBridgeToken(_contractAddress);
    }

    /*
     * @dev: Set the token address in whitelist
     *
     * @param _token: ERC 20's address
     * @param _inList: set the _token in list or not
     * @return: new value of if _token in whitelist
     */
    function updateEthWhiteList(address _token, bool _inList)
        public
        onlyOperator
        returns (bool)
    {
        string memory symbol = BridgeToken(_token).symbol();
        address listAddress = lockedTokenList[symbol];
        
        // Do not allow a token with the same symbol to be whitelisted
        if (_inList) {
            // if we want to add it to the whitelist, make sure that the address
            // is 0, meaning we have not seen that symbol in the whitelist before
            require(listAddress == address(0), "whitelisted");
        } else {
            // if we want to de-whitelist it, make sure that the symbol is 
            // in fact stored in our locked token list before we set to false
            require(uint256(listAddress) > 0, "!whitelisted");
        }
        lowerToUpperTokens[toLower(symbol)] = symbol;
        return setTokenInEthWhiteList(_token, _inList);
    }

    function bulkWhitelistUpdateLimits(address[] calldata tokenAddresses)
        external
        onlyOperator
        returns (bool)
    {
        for (uint256 i = 0; i < tokenAddresses.length; i++) {
            setTokenInEthWhiteList(tokenAddresses[i], true);
            string memory symbol = BridgeToken(tokenAddresses[i]).symbol();
            lowerToUpperTokens[toLower(symbol)] = symbol;
        }
        return true;
    }

    /*
     * @dev: Mints new BankTokens
     *
     * @param _cosmosSender: The sender's Cosmos address in bytes.
     * @param _ethereumRecipient: The intended recipient's Ethereum address.
     * @param _cosmosTokenAddress: The currency type
     * @param _symbol: comsos token symbol
     * @param _amount: number of comsos tokens to be minted
     */
    function mintBridgeTokens(
        address payable _intendedRecipient,
        string memory _symbol,
        uint256 _amount
    ) public onlyCosmosBridge whenNotPaused {
        string memory symbol = safeLowerToUpperTokens(_symbol);
        address tokenAddress = controlledBridgeTokens[symbol];
        return
            mintNewBridgeTokens(
                _intendedRecipient,
                tokenAddress,
                symbol,
                _amount
            );
    }

    /*
     * @dev: Burns BridgeTokens representing native Cosmos assets.
     *
     * @param _recipient: bytes representation of destination address.
     * @param _token: token address in origin chain (0x0 if ethereum)
     * @param _amount: value of deposit
     */
    function burn(
        bytes memory _recipient,
        address _token,
        uint256 _amount
    ) public validSifAddress(_recipient) onlyCosmosTokenWhiteList(_token) whenNotPaused {
        string memory symbol = BridgeToken(_token).symbol();

        BridgeToken(_token).burnFrom(msg.sender, _amount);
        burnFunds(msg.sender, _recipient, _token, symbol, _amount);
    }

    /*
     * @dev: Locks received Ethereum/ERC20 funds.
     *
     * @param _recipient: bytes representation of destination address.
     * @param _token: token address in origin chain (0x0 if ethereum)
     * @param _amount: value of deposit
     */
    function lock(
        bytes memory _recipient,
        address _token,
        uint256 _amount
    ) public payable onlyEthTokenWhiteList(_token) validSifAddress(_recipient) whenNotPaused {
        string memory symbol;

        // Ethereum deposit
        if (msg.value > 0) {
            require(
                _token == address(0),
                "!address(0)"
            );
            require(
                msg.value == _amount,
                "incorrect eth amount"
            );
            symbol = "eth";
            // ERC20 deposit
        } else {
            IERC20 tokenToTransfer = IERC20(_token);
            tokenToTransfer.safeTransferFrom(
                msg.sender,
                address(this),
                _amount
            );
            symbol = BridgeToken(_token).symbol();
        }

        lockFunds(msg.sender, _recipient, _token, symbol, _amount);
    }

    /*
     * @dev: Unlocks Ethereum and ERC20 tokens held on the contract.
     *
     * @param _recipient: recipient's Ethereum address
     * @param _token: token contract address
     * @param _symbol: token symbol
     * @param _amount: wei amount or ERC20 token count
     */
    function unlock(
        address payable _recipient,
        string memory _symbol,
        uint256 _amount
    ) public onlyCosmosBridge whenNotPaused {
        string memory symbol = safeLowerToUpperTokens(_symbol);

        // Confirm that the bank holds sufficient balances to complete the unlock
        address tokenAddress = lockedTokenList[symbol];
        unlockFunds(_recipient, tokenAddress, symbol, _amount);
    }

    /*
    * @dev fallback function for ERC223 tokens so that we can receive these tokens in our contract
    * Don't need to do anything to handle these tokens
    */
    function tokenFallback(address _from, uint _value, bytes memory _data) public {}
}

File 2 of 30 : CosmosBank.sol
pragma solidity 0.5.16;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./BridgeToken.sol";
import "./CosmosBankStorage.sol";
import "./ToLower.sol";

/**
 * @title CosmosBank
 * @dev Manages the deployment and minting of ERC20 compatible BridgeTokens
 *      which represent assets based on the Cosmos blockchain.
 **/

contract CosmosBank is CosmosBankStorage, ToLower {
    using SafeMath for uint256;

    /*
     * @dev: Event declarations
     */
    event LogNewBridgeToken(address _token, string _symbol);

    event LogBridgeTokenMint(
        address _token,
        string _symbol,
        uint256 _amount,
        address _beneficiary
    );

    /*
     * @dev: Get a token symbol's corresponding bridge token address.
     *
     * @param _symbol: The token's symbol/denom without 'e' prefix.
     * @return: Address associated with the given symbol. Returns address(0) if none is found.
     */
    function getBridgeToken(string memory _symbol)
        public
        view
        returns (address)
    {
        return (controlledBridgeTokens[_symbol]);
    }

    function safeLowerToUpperTokens(string memory _symbol)
        public
        view
        returns (string memory)
    {
        string memory retrievedSymbol = lowerToUpperTokens[_symbol];
        return keccak256(abi.encodePacked(retrievedSymbol)) == keccak256("") ? _symbol : retrievedSymbol;
    }

    /*
     * @dev: Deploys a new BridgeToken contract
     *
     * @param _symbol: The BridgeToken's symbol
     */
    function deployNewBridgeToken(string memory _symbol)
        internal
        returns (address)
    {
        bridgeTokenCount = bridgeTokenCount.add(1);

        // Deploy new bridge token contract
        BridgeToken newBridgeToken = (new BridgeToken)(_symbol);

        // Set address in tokens mapping
        address newBridgeTokenAddress = address(newBridgeToken);
        controlledBridgeTokens[_symbol] = newBridgeTokenAddress;
        lowerToUpperTokens[toLower(_symbol)] = _symbol;

        emit LogNewBridgeToken(newBridgeTokenAddress, _symbol);
        return newBridgeTokenAddress;
    }

    /*
     * @dev: Deploys a new BridgeToken contract
     *
     * @param _symbol: The BridgeToken's symbol
     *
     * @note the Rowan token symbol needs to be "Rowan" so that it integrates correctly with the cosmos bridge 
     */
    function useExistingBridgeToken(address _contractAddress)
        internal
        returns (address)
    {
        bridgeTokenCount = bridgeTokenCount.add(1);

        string memory _symbol = BridgeToken(_contractAddress).symbol();
        // Set address in tokens mapping
        address newBridgeTokenAddress = _contractAddress;
        controlledBridgeTokens[_symbol] = newBridgeTokenAddress;
        lowerToUpperTokens[toLower(_symbol)] = _symbol;

        emit LogNewBridgeToken(newBridgeTokenAddress, _symbol);
        return newBridgeTokenAddress;
    }

    /*
     * @dev: Mints new cosmos tokens
     *
     * @param _cosmosSender: The sender's Cosmos address in bytes.
     * @param _ethereumRecipient: The intended recipient's Ethereum address.
     * @param _cosmosTokenAddress: The currency type
     * @param _symbol: comsos token symbol
     * @param _amount: number of comsos tokens to be minted
     */
    function mintNewBridgeTokens(
        address payable _intendedRecipient,
        address _bridgeTokenAddress,
        string memory _symbol,
        uint256 _amount
    ) internal {
        require(
            controlledBridgeTokens[_symbol] == _bridgeTokenAddress,
            "Token must be a controlled bridge token"
        );

        // Mint bridge tokens
        require(
            BridgeToken(_bridgeTokenAddress).mint(_intendedRecipient, _amount),
            "Attempted mint of bridge tokens failed"
        );

        emit LogBridgeTokenMint(
            _bridgeTokenAddress,
            _symbol,
            _amount,
            _intendedRecipient
        );
    }
}

File 3 of 30 : EthereumBank.sol
pragma solidity 0.5.16;

import "./BridgeToken.sol";
import "./EthereumBankStorage.sol";
import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol";
/*
 *  @title: EthereumBank
 *  @dev: Ethereum bank which locks Ethereum/ERC20 token deposits, and unlocks
 *        Ethereum/ERC20 tokens once the prophecy has been successfully processed.
 */
contract EthereumBank is EthereumBankStorage {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    /*
     * @dev: Event declarations
     */
    event LogBurn(
        address _from,
        bytes _to,
        address _token,
        string _symbol,
        uint256 _value,
        uint256 _nonce
    );

    event LogLock(
        address _from,
        bytes _to,
        address _token,
        string _symbol,
        uint256 _value,
        uint256 _nonce
    );

    event LogUnlock(
        address _to,
        address _token,
        string _symbol,
        uint256 _value
    );

    /*
     * @dev: Gets the contract address of locked tokens by symbol.
     *
     * @param _symbol: The asset's symbol.
     */
    function getLockedTokenAddress(string memory _symbol)
        public
        view
        returns (address)
    {
        return lockedTokenList[_symbol];
    }

    /*
     * @dev: Gets the amount of locked tokens by symbol.
     *
     * @param _symbol: The asset's symbol.
     */
    function getLockedFunds(string memory _symbol)
        public
        view
        returns (uint256)
    {
        return lockedFunds[lockedTokenList[_symbol]];
    }

    /*
     * @dev: Creates a new Ethereum deposit with a unique id.
     *
     * @param _sender: The sender's ethereum address.
     * @param _recipient: The intended recipient's cosmos address.
     * @param _token: The currency type, either erc20 or ethereum.
     * @param _amount: The amount of erc20 tokens/ ethereum (in wei) to be itemized.
     */
    function burnFunds(
        address payable _sender,
        bytes memory _recipient,
        address _token,
        string memory _symbol,
        uint256 _amount
    ) internal {
        lockBurnNonce = lockBurnNonce.add(1);
        emit LogBurn(_sender, _recipient, _token, _symbol, _amount, lockBurnNonce);
    }

    /*
     * @dev: Creates a new Ethereum deposit with a unique id.
     *
     * @param _sender: The sender's ethereum address.
     * @param _recipient: The intended recipient's cosmos address.
     * @param _token: The currency type, either erc20 or ethereum.
     * @param _amount: The amount of erc20 tokens/ ethereum (in wei) to be itemized.
     */
    function lockFunds(
        address payable _sender,
        bytes memory _recipient,
        address _token,
        string memory _symbol,
        uint256 _amount
    ) internal {
        lockBurnNonce = lockBurnNonce.add(1);

        // Increment locked funds by the amount of tokens to be locked
        lockedTokenList[_symbol] = _token;

        emit LogLock(_sender, _recipient, _token, _symbol, _amount, lockBurnNonce);
    }

    /*
     * @dev: Unlocks funds held on contract and sends them to the
     *       intended recipient
     *
     * @param _recipient: recipient's Ethereum address
     * @param _token: token contract address
     * @param _symbol: token symbol
     * @param _amount: wei amount or ERC20 token count
     */
    function unlockFunds(
        address payable _recipient,
        address _token,
        string memory _symbol,
        uint256 _amount
    ) internal {
        // Transfer funds to intended recipient
        if (_token == address(0)) {
            (bool success,) = _recipient.call.value(_amount).gas(60000)("");
            require(success, "error sending ether");
        } else {
            IERC20 tokenToTransfer = IERC20(_token);
            tokenToTransfer.safeTransfer(_recipient, _amount);
        }

        emit LogUnlock(_recipient, _token, _symbol, _amount);
    }
}

File 4 of 30 : EthereumWhitelist.sol
pragma solidity 0.5.16;

/**
 * @title WhiteList
 * @dev WhiteList contract records the ERC 20 list that can be locked in BridgeBank.
 **/

contract EthereumWhiteList {
    bool private _initialized;

    /**
    * @notice mapping to keep track of whitelisted tokens
    */
    mapping(address => bool) private _ethereumTokenWhiteList;

    /**
    * @notice gap of storage for future upgrades
    */
    uint256[100] private ____gap;
    /*
     * @dev: Event declarations
     */
    event LogWhiteListUpdate(address _token, bool _value);

    function initialize() public {
        require(!_initialized, "Initialized");
        _ethereumTokenWhiteList[address(0)] = true;
        _initialized = true;
    }

    /*
     * @dev: Modifier to restrict erc20 can be locked
     */
    modifier onlyEthTokenWhiteList(address _token) {
        require(
            getTokenInEthWhiteList(_token),
            "Only token in whitelist can be transferred to cosmos"
        );
        _;
    }

    /*
     * @dev: Set the token address in whitelist
     *
     * @param _token: ERC 20's address
     * @param _inList: set the _token in list or not
     * @return: new value of if _token in whitelist
     */
    function setTokenInEthWhiteList(address _token, bool _inList)
        internal
        returns (bool)
    {
        _ethereumTokenWhiteList[_token] = _inList;
        emit LogWhiteListUpdate(_token, _inList);
        return _inList;
    }

    /*
     * @dev: Get if the token in whitelist
     *
     * @param _token: ERC 20's address
     * @return: if _token in whitelist
     */
    function getTokenInEthWhiteList(address _token) public view returns (bool) {
        return _ethereumTokenWhiteList[_token];
    }
}

File 5 of 30 : CosmosWhiteList.sol
pragma solidity 0.5.16;

import "./CosmosWhiteListStorage.sol";

/**
 * @title WhiteList
 * @dev WhiteList contract records the ERC 20 list that can be locked in BridgeBank.
 **/

contract CosmosWhiteList is CosmosWhiteListStorage {
    bool private _initialized;

    /*
     * @dev: Event declarations
     */
    event LogWhiteListUpdate(address _token, bool _value);

    function initialize() public {
        require(!_initialized, "Initialized");
        _cosmosTokenWhiteList[address(0)] = true;
        _initialized = true;
    }

    /*
     * @dev: Modifier to restrict erc20 can be locked
     */
    modifier onlyCosmosTokenWhiteList(address _token) {
        require(
            getCosmosTokenInWhiteList(_token),
            "Only token in whitelist can be transferred to cosmos"
        );
        _;
    }

    /*
     * @dev: Set the token address in whitelist
     *
     * @param _token: ERC 20's address
     * @param _inList: set the _token in list or not
     * @return: new value of if _token in whitelist
     */
    function setTokenInCosmosWhiteList(address _token, bool _inList)
        internal
        returns (bool)
    {
        _cosmosTokenWhiteList[_token] = _inList;
        emit LogWhiteListUpdate(_token, _inList);
        return _inList;
    }

    /*
     * @dev: Get if the token in whitelist
     *
     * @param _token: ERC 20's address
     * @return: if _token in whitelist
     */
    function getCosmosTokenInWhiteList(address _token) public view returns (bool) {
        return _cosmosTokenWhiteList[_token];
    }
}

File 6 of 30 : Oracle.sol
pragma solidity 0.5.16;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./Valset.sol";
import "./OracleStorage.sol";
import "./Valset.sol";


contract Oracle is OracleStorage, Valset {
    using SafeMath for uint256;

    bool private _initialized;

    /*
     * @dev: Event declarations
     */
    event LogNewOracleClaim(
        uint256 _prophecyID,
        address _validatorAddress
    );

    event LogProphecyProcessed(
        uint256 _prophecyID,
        uint256 _prophecyPowerCurrent,
        uint256 _prophecyPowerThreshold,
        address _submitter
    );

    /*
     * @dev: Modifier to restrict access to the operator.
     */
    modifier onlyOperator() {
        require(msg.sender == operator, "Must be the operator.");
        _;
    }

    /*
     * @dev: Initialize Function
     */
    function _initialize(
        address _operator,
        uint256 _consensusThreshold,
        address[] memory _initValidators,
        uint256[] memory _initPowers
    ) internal {
        require(!_initialized, "Initialized");
        require(
            _consensusThreshold > 0,
            "Consensus threshold must be positive."
        );
        require(
            _consensusThreshold <= 100,
            "Invalid consensus threshold."
        );
        operator = _operator;
        consensusThreshold = _consensusThreshold;
        _initialized = true;

        Valset._initialize(_operator, _initValidators, _initPowers);
    }

    /*
     * @dev: newOracleClaim
     *       Allows validators to make new OracleClaims on an existing Prophecy
     */
    function newOracleClaim(
        uint256 _prophecyID,
        address validatorAddress
    ) internal
        returns (bool)
    {
        // Confirm that this address has not already made an oracle claim on this prophecy
        require(
            !hasMadeClaim[_prophecyID][validatorAddress],
            "Cannot make duplicate oracle claims from the same address."
        );

        hasMadeClaim[_prophecyID][validatorAddress] = true;
        // oracleClaimValidators[_prophecyID].push(validatorAddress);
        oracleClaimValidators[_prophecyID] = oracleClaimValidators[_prophecyID].add(
            getValidatorPower(validatorAddress)
        );
        emit LogNewOracleClaim(
            _prophecyID,
            validatorAddress
        );

        // Process the prophecy
        (bool valid, , ) = getProphecyThreshold(_prophecyID);

        return valid;
    }

    /*
     * @dev: processProphecy
     *       Calculates the status of a prophecy. The claim is considered valid if the
     *       combined active signatory validator powers pass the consensus threshold.
     *       The threshold is x% of Total power, where x is the consensusThreshold param.
     */
    function getProphecyThreshold(uint256 _prophecyID)
        public
        view
        returns (bool, uint256, uint256)
    {
        uint256 signedPower = 0;
        uint256 totalPower = totalPower;

        signedPower = oracleClaimValidators[_prophecyID];

        // Prophecy must reach total signed power % threshold in order to pass consensus
        uint256 prophecyPowerThreshold = totalPower.mul(consensusThreshold);
        // consensusThreshold is a decimal multiplied by 100, so signedPower must also be multiplied by 100
        uint256 prophecyPowerCurrent = signedPower.mul(100);
        bool hasReachedThreshold = prophecyPowerCurrent >=
            prophecyPowerThreshold;

        return (
            hasReachedThreshold,
            prophecyPowerCurrent,
            prophecyPowerThreshold
        );
    }
}

File 7 of 30 : CosmosBridge.sol
pragma solidity 0.5.16;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./Valset.sol";
import "./Oracle.sol";
import "./BridgeBank/BridgeBank.sol";
import "./CosmosBridgeStorage.sol";


contract CosmosBridge is CosmosBridgeStorage, Oracle {
    using SafeMath for uint256;
    
    bool private _initialized;
    uint256[100] private ___gap;

    /*
     * @dev: Event declarations
     */

    event LogOracleSet(address _oracle);

    event LogBridgeBankSet(address _bridgeBank);

    event LogNewProphecyClaim(
        uint256 _prophecyID,
        ClaimType _claimType,
        address payable _ethereumReceiver,
        string _symbol,
        uint256 _amount
    );

    event LogProphecyCompleted(uint256 _prophecyID, ClaimType _claimType);

    /*
     * @dev: Modifier to restrict access to the operator.
     */
    modifier onlyOperator() {
        require(msg.sender == operator, "Must be the operator.");
        _;
    }

    /*
     * @dev: Modifier to restrict access to current ValSet validators
     */
    modifier onlyValidator() {
        require(
            isActiveValidator(msg.sender),
            "Must be an active validator"
        );
        _;
    }

    /*
     * @dev: Constructor
     */
    function initialize(
        address _operator,
        uint256 _consensusThreshold,
        address[] memory _initValidators,
        uint256[] memory _initPowers
    ) public {
        require(!_initialized, "Initialized");

        COSMOS_NATIVE_ASSET_PREFIX = "e";
        operator = _operator;
        hasBridgeBank = false;
        _initialized = true;
        Oracle._initialize(
            _operator,
            _consensusThreshold,
            _initValidators,
            _initPowers
        );
    }

    function changeOperator(address _newOperator) public onlyOperator {
        require(_newOperator != address(0), "invalid address");
        operator = _newOperator;
    }

    /*
     * @dev: setBridgeBank
     */
    function setBridgeBank(address payable _bridgeBank) public onlyOperator {
        require(
            !hasBridgeBank,
            "The Bridge Bank cannot be updated once it has been set"
        );

        hasBridgeBank = true;
        bridgeBank = _bridgeBank;

        emit LogBridgeBankSet(bridgeBank);
    }

    function getProphecyID(
        ClaimType _claimType,
        bytes calldata _cosmosSender,
        uint256 _cosmosSenderSequence,
        address payable _ethereumReceiver,
        string calldata _symbol,
        uint256 _amount
    ) external pure returns (uint256) {
        return uint256(keccak256(abi.encodePacked(_claimType, _cosmosSender, _cosmosSenderSequence, _ethereumReceiver, _symbol, _amount)));
    }

    /*
     * @dev: newProphecyClaim
     *       Creates a new burn or lock prophecy claim, adding it to the prophecyClaims mapping.
     *       Burn claims require that there are enough locked Ethereum assets to complete the prophecy.
     *       Lock claims have a new token contract deployed or use an existing contract based on symbol.
     */
    function newProphecyClaim(
        ClaimType _claimType,
        bytes memory _cosmosSender,
        uint256 _cosmosSenderSequence,
        address payable _ethereumReceiver,
        string memory _symbol,
        uint256 _amount
    ) public onlyValidator {
        uint256 _prophecyID = uint256(keccak256(abi.encodePacked(_claimType, _cosmosSender, _cosmosSenderSequence, _ethereumReceiver, _symbol, _amount)));
        (bool prophecyCompleted, , ) = getProphecyThreshold(_prophecyID);
        require(!prophecyCompleted, "prophecyCompleted");

        if (oracleClaimValidators[_prophecyID] == 0) {
            string memory symbol = BridgeBank(bridgeBank).safeLowerToUpperTokens(_symbol);

            if (_claimType == ClaimType.Burn) {
                address tokenAddress = BridgeBank(bridgeBank).getLockedTokenAddress(symbol);
                if (tokenAddress == address(0) && uint256(keccak256(abi.encodePacked(symbol))) != uint256(keccak256("eth"))) {
                    revert("Invalid token address");
                }
            } else if (_claimType == ClaimType.Lock) {
                address bridgeTokenAddress = BridgeBank(bridgeBank).getBridgeToken(symbol);
                if (bridgeTokenAddress == address(0)) {
                    // First lock of this asset, deploy new contract and get new symbol/token address
                    BridgeBank(bridgeBank).createNewBridgeToken(symbol);
                }
            } else {
                revert("Invalid claim type, only burn and lock are supported.");
            }

            emit LogNewProphecyClaim(
                _prophecyID,
                _claimType,
                _ethereumReceiver,
                symbol,
                _amount
            );
        }

        bool claimComplete = newOracleClaim(_prophecyID, msg.sender);

        if (claimComplete) {
            completeProphecyClaim(
                _prophecyID,
                _claimType,
                _ethereumReceiver,
                _symbol,
                _amount
            );
        }
    }

    /*
     * @dev: completeProphecyClaim
     *       Allows for the completion of ProphecyClaims once processed by the Oracle.
     *       Burn claims unlock tokens stored by BridgeBank.
     *       Lock claims mint BridgeTokens on BridgeBank's token whitelist.
     */
    function completeProphecyClaim(
        uint256 _prophecyID,
        ClaimType claimType,
        address payable ethereumReceiver,
        string memory symbol,
        uint256 amount
    ) internal {

        if (claimType == ClaimType.Burn) {
            unlockTokens(ethereumReceiver, symbol, amount);
        } else {
            issueBridgeTokens(ethereumReceiver, symbol, amount);
        }

        emit LogProphecyCompleted(_prophecyID, claimType);
    }

    /*
     * @dev: issueBridgeTokens
     *       Issues a request for the BridgeBank to mint new BridgeTokens
     */
    function issueBridgeTokens(
        address payable ethereumReceiver,
        string memory symbol,
        uint256 amount
    ) internal {
        BridgeBank(bridgeBank).mintBridgeTokens(
            ethereumReceiver,
            symbol,
            amount
        );
    }

    /*
     * @dev: unlockTokens
     *       Issues a request for the BridgeBank to unlock funds held on contract
     */
    function unlockTokens(
        address payable ethereumReceiver,
        string memory symbol,
        uint256 amount
    ) internal {
        BridgeBank(bridgeBank).unlock(
            ethereumReceiver,
            symbol,
            amount
        );
    }
}

File 8 of 30 : BankStorage.sol
pragma solidity 0.5.16;

import "./CosmosBankStorage.sol";
import "./EthereumBankStorage.sol";
import "./CosmosWhiteListStorage.sol";

contract BankStorage is 
    CosmosBankStorage,
    EthereumBankStorage,
    CosmosWhiteListStorage {

    /**
    * @notice operator address that can update the smart contract
    */
    address public operator;

    /**
    * @notice address of the Oracle smart contract
    */
    address public oracle;

    /**
    * @notice address of the Cosmos Bridge smart contract
    */
    address public cosmosBridge;

    /**
    * @notice owner address that can use the admin API
    */
    address public owner;

    mapping (string => uint256) public maxTokenAmount;

    /**
    * @notice gap of storage for future upgrades
    */
    uint256[100] private ____gap;
}

File 9 of 30 : Pausable.sol
pragma solidity 0.5.16;

import "./PauserRole.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
contract Pausable is PauserRole {
    /**
     * @dev Emitted when the pause is triggered by a pauser (`account`).
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by a pauser (`account`).
     */
    event Unpaused(address account);

    bool private _paused;


    function initialize (address _user) internal {
        _addPauser(_user);
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     */
    modifier whenNotPaused() {
        require(!_paused, "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     */
    modifier whenPaused() {
        require(_paused, "Pausable: not paused");
        _;
    }

    /**
     * @dev Called by a owner to toggle pause
     */
    function togglePause() private {
        _paused = !_paused;
    }

    /**
     * @dev Called by a pauser to pause contract
     */
    function pause() external onlyPauser whenNotPaused {
        togglePause();
        emit Paused(msg.sender);
    }

    /**
     * @dev Called by a pauser to unpause contract
     */
    function unpause() external onlyPauser whenPaused {
        togglePause();
        emit Unpaused(msg.sender);
    }
}

File 10 of 30 : SafeMath.sol
pragma solidity ^0.5.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 11 of 30 : BridgeToken.sol
pragma solidity 0.5.16;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20Burnable.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";


/**
 * @title BridgeToken
 * @dev Mintable, ERC20Burnable, ERC20 compatible BankToken for use by BridgeBank
 **/

contract BridgeToken is ERC20Mintable, ERC20Burnable, ERC20Detailed {
    constructor(string memory _symbol)
        public
        ERC20Detailed(_symbol, _symbol, 18)
    {
        // Intentionally left blank
    }
}

File 12 of 30 : CosmosBankStorage.sol
pragma solidity 0.5.16;

contract CosmosBankStorage {

    /**
    * @notice Cosmos deposit struct
    */
    struct CosmosDeposit {
        bytes cosmosSender;
        address payable ethereumRecipient;
        address bridgeTokenAddress;
        uint256 amount;
        bool locked;
    }

    /**
    * @notice number of bridge tokens
    */
    uint256 public bridgeTokenCount;

    /**
    * @notice cosmos deposit nonce
    */
    uint256 public cosmosDepositNonce;
    
    /**
    * @notice mapping of symbols to token addresses
    */
    mapping(string => address) controlledBridgeTokens;
    
    /**
    * @notice mapping of lowercase symbols to properly capitalized tokens
    */
    mapping(string => string) public lowerToUpperTokens;

    /**
    * @notice gap of storage for future upgrades
    */
    uint256[100] private ____gap;
}

File 13 of 30 : ToLower.sol
pragma solidity 0.5.16;

contract ToLower {

    function toLower(string memory str) public pure returns (string memory) {
		bytes memory bStr = bytes(str);
		bytes memory bLower = new bytes(bStr.length);
		for (uint i = 0; i < bStr.length; i++) {
			// Uppercase character...
			if ((bStr[i] >= bytes1(uint8(65))) && (bStr[i] <= bytes1(uint8(90)))) {
				// So we add 32 to make it lowercase
				bLower[i] = bytes1(uint8(bStr[i]) + 32);
			} else {
				bLower[i] = bStr[i];
			}
		}
		return string(bLower);
	}
}

File 14 of 30 : ERC20Mintable.sol
pragma solidity ^0.5.0;

import "./ERC20.sol";
import "../../access/roles/MinterRole.sol";

/**
 * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole},
 * which have permission to mint (create) new tokens as they see fit.
 *
 * At construction, the deployer of the contract is the only minter.
 */
contract ERC20Mintable is ERC20, MinterRole {
    /**
     * @dev See {ERC20-_mint}.
     *
     * Requirements:
     *
     * - the caller must have the {MinterRole}.
     */
    function mint(address account, uint256 amount) public onlyMinter returns (bool) {
        _mint(account, amount);
        return true;
    }
}

File 15 of 30 : ERC20Burnable.sol
pragma solidity ^0.5.0;

import "../../GSN/Context.sol";
import "./ERC20.sol";

/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
contract ERC20Burnable is Context, ERC20 {
    /**
     * @dev Destroys `amount` tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 amount) public {
        _burn(_msgSender(), amount);
    }

    /**
     * @dev See {ERC20-_burnFrom}.
     */
    function burnFrom(address account, uint256 amount) public {
        _burnFrom(account, amount);
    }
}

File 16 of 30 : ERC20Detailed.sol
pragma solidity ^0.5.0;

import "./IERC20.sol";

/**
 * @dev Optional functions from the ERC20 standard.
 */
contract ERC20Detailed is IERC20 {
    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
     * these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name, string memory symbol, uint8 decimals) public {
        _name = name;
        _symbol = symbol;
        _decimals = decimals;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }
}

File 17 of 30 : ERC20.sol
pragma solidity ^0.5.0;

import "../../GSN/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20Mintable}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20};
     *
     * Requirements:
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for `sender`'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal {
        require(account != address(0), "ERC20: mint to the zero address");

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal {
        require(account != address(0), "ERC20: burn from the zero address");

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
     *
     * This is internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
     * from the caller's allowance.
     *
     * See {_burn} and {_approve}.
     */
    function _burnFrom(address account, uint256 amount) internal {
        _burn(account, amount);
        _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
    }
}

File 18 of 30 : MinterRole.sol
pragma solidity ^0.5.0;

import "../../GSN/Context.sol";
import "../Roles.sol";

contract MinterRole is Context {
    using Roles for Roles.Role;

    event MinterAdded(address indexed account);
    event MinterRemoved(address indexed account);

    Roles.Role private _minters;

    constructor () internal {
        _addMinter(_msgSender());
    }

    modifier onlyMinter() {
        require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role");
        _;
    }

    function isMinter(address account) public view returns (bool) {
        return _minters.has(account);
    }

    function addMinter(address account) public onlyMinter {
        _addMinter(account);
    }

    function renounceMinter() public {
        _removeMinter(_msgSender());
    }

    function _addMinter(address account) internal {
        _minters.add(account);
        emit MinterAdded(account);
    }

    function _removeMinter(address account) internal {
        _minters.remove(account);
        emit MinterRemoved(account);
    }
}

File 19 of 30 : Context.sol
pragma solidity ^0.5.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, which should be used via inheritance.
    constructor () internal { }
    // solhint-disable-previous-line no-empty-blocks

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 20 of 30 : IERC20.sol
pragma solidity ^0.5.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see {ERC20Detailed}.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 21 of 30 : Roles.sol
pragma solidity ^0.5.0;

/**
 * @title Roles
 * @dev Library for managing addresses assigned to a Role.
 */
library Roles {
    struct Role {
        mapping (address => bool) bearer;
    }

    /**
     * @dev Give an account access to this role.
     */
    function add(Role storage role, address account) internal {
        require(!has(role, account), "Roles: account already has role");
        role.bearer[account] = true;
    }

    /**
     * @dev Remove an account's access to this role.
     */
    function remove(Role storage role, address account) internal {
        require(has(role, account), "Roles: account does not have role");
        role.bearer[account] = false;
    }

    /**
     * @dev Check if an account has this role.
     * @return bool
     */
    function has(Role storage role, address account) internal view returns (bool) {
        require(account != address(0), "Roles: account is the zero address");
        return role.bearer[account];
    }
}

File 22 of 30 : EthereumBankStorage.sol
pragma solidity 0.5.16;

contract EthereumBankStorage {

    /**
    * @notice current lock and or burn nonce
    */
    uint256 public lockBurnNonce;

    /**
    * @notice how much funds we have stored of a certain token
    */
    mapping(address => uint256) public lockedFunds;

    /**
    * @notice map the token symbol to the token address
    */
    mapping(string => address) public lockedTokenList;

    /**
    * @notice gap of storage for future upgrades
    */
    uint256[100] private ____gap;
}

File 23 of 30 : SafeERC20.sol
pragma solidity ^0.5.0;

import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves.

        // A Solidity high level call has three parts:
        //  1. The target address is checked to verify it contains contract code
        //  2. The call itself is made, and success asserted
        //  3. The return value is decoded, which in turn checks the size of the returned data.
        // solhint-disable-next-line max-line-length
        require(address(token).isContract(), "SafeERC20: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "SafeERC20: low-level call failed");

        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 24 of 30 : Address.sol
pragma solidity ^0.5.5;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following 
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Converts an `address` into `address payable`. Note that this is
     * simply a type cast: the actual underlying value is not changed.
     *
     * _Available since v2.4.0._
     */
    function toPayable(address account) internal pure returns (address payable) {
        return address(uint160(account));
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     *
     * _Available since v2.4.0._
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-call-value
        (bool success, ) = recipient.call.value(amount)("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}

File 25 of 30 : CosmosWhiteListStorage.sol
pragma solidity 0.5.16;

contract CosmosWhiteListStorage {

    /**
    * @notice mapping to keep track of whitelisted tokens
    */
    mapping(address => bool) internal _cosmosTokenWhiteList;

    /**
    * @notice gap of storage for future upgrades
    */
    uint256[100] private ____gap;
}

File 26 of 30 : Valset.sol
pragma solidity 0.5.16;

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

contract Valset is ValsetStorage {
    using SafeMath for uint256;

    bool private _initialized;

    /*
     * @dev: Event declarations
     */
    event LogValidatorAdded(
        address _validator,
        uint256 _power,
        uint256 _currentValsetVersion,
        uint256 _validatorCount,
        uint256 _totalPower
    );

    event LogValidatorPowerUpdated(
        address _validator,
        uint256 _power,
        uint256 _currentValsetVersion,
        uint256 _validatorCount,
        uint256 _totalPower
    );

    event LogValidatorRemoved(
        address _validator,
        uint256 _power,
        uint256 _currentValsetVersion,
        uint256 _validatorCount,
        uint256 _totalPower
    );

    event LogValsetReset(
        uint256 _newValsetVersion,
        uint256 _validatorCount,
        uint256 _totalPower
    );

    event LogValsetUpdated(
        uint256 _newValsetVersion,
        uint256 _validatorCount,
        uint256 _totalPower
    );

    /*
     * @dev: Modifier which restricts access to the operator.
     */
    modifier onlyOperator() {
        require(msg.sender == operator, "Must be the operator.");
        _;
    }

    /*
     * @dev: Constructor
     */
    function _initialize(
        address _operator,
        address[] memory _initValidators,
        uint256[] memory _initPowers
    ) internal {
        require(!_initialized, "Initialized");

        operator = _operator;
        currentValsetVersion = 0;
        _initialized = true;

        require(
            _initValidators.length == _initPowers.length,
            "Every validator must have a corresponding power"
        );

        resetValset();

        for (uint256 i = 0; i < _initValidators.length; i++) {
            addValidatorInternal(_initValidators[i], _initPowers[i]);
        }

        emit LogValsetUpdated(currentValsetVersion, validatorCount, totalPower);
    }

    /*
     * @dev: addValidator
     */
    function addValidator(address _validatorAddress, uint256 _validatorPower)
        public
        onlyOperator
    {
        addValidatorInternal(_validatorAddress, _validatorPower);
    }

    /*
     * @dev: updateValidatorPower
     */
    function updateValidatorPower(
        address _validatorAddress,
        uint256 _newValidatorPower
    ) public onlyOperator {

        require(
            validators[_validatorAddress][currentValsetVersion],
            "Can only update the power of active valdiators"
        );

        // Adjust total power by new validator power
        uint256 priorPower = powers[_validatorAddress][currentValsetVersion];
        totalPower = totalPower.sub(priorPower);
        totalPower = totalPower.add(_newValidatorPower);

        // Set validator's new power
        powers[_validatorAddress][currentValsetVersion] = _newValidatorPower;

        emit LogValidatorPowerUpdated(
            _validatorAddress,
            _newValidatorPower,
            currentValsetVersion,
            validatorCount,
            totalPower
        );
    }

    /*
     * @dev: removeValidator
     */
    function removeValidator(address _validatorAddress) public onlyOperator {
        require(validators[_validatorAddress][currentValsetVersion], "Can only remove active validators");

        // Update validator count and total power
        validatorCount = validatorCount.sub(1);
        totalPower = totalPower.sub(powers[_validatorAddress][currentValsetVersion]);

        // Delete validator and power
        delete validators[_validatorAddress][currentValsetVersion];
        delete powers[_validatorAddress][currentValsetVersion];

        emit LogValidatorRemoved(
            _validatorAddress,
            0,
            currentValsetVersion,
            validatorCount,
            totalPower
        );
    }

    /*
     * @dev: updateValset
     */
    function updateValset(
        address[] memory _validators,
        uint256[] memory _powers
    ) public onlyOperator {
        require(
            _validators.length == _powers.length,
            "Every validator must have a corresponding power"
        );

        resetValset();

        for (uint256 i = 0; i < _validators.length; i++) {
            addValidatorInternal(_validators[i], _powers[i]);
        }

        emit LogValsetUpdated(currentValsetVersion, validatorCount, totalPower);
    }

    /*
     * @dev: isActiveValidator
     */
    function isActiveValidator(address _validatorAddress)
        public
        view
        returns (bool)
    {
        // Return bool indicating if this address is an active validator
        return validators[_validatorAddress][currentValsetVersion];
    }

    /*
     * @dev: getValidatorPower
     */
    function getValidatorPower(address _validatorAddress)
        public
        view
        returns (uint256)
    {
        return powers[_validatorAddress][currentValsetVersion];
    }

    /*
     * @dev: recoverGas
     */
    function recoverGas(uint256 _valsetVersion, address _validatorAddress)
        external
        onlyOperator
    {
        require(
            _valsetVersion < currentValsetVersion,
            "Gas recovery only allowed for previous validator sets"
        );
        // Delete from mappings and recover gas
        delete (validators[_validatorAddress][currentValsetVersion]);
        delete (powers[_validatorAddress][currentValsetVersion]);
    }

    /*
     * @dev: addValidatorInternal
     */
    function addValidatorInternal(
        address _validatorAddress,
        uint256 _validatorPower
    ) internal {
        validatorCount = validatorCount.add(1);
        totalPower = totalPower.add(_validatorPower);

        // Set validator as active and set their power
        validators[_validatorAddress][currentValsetVersion] = true;
        powers[_validatorAddress][currentValsetVersion] = _validatorPower;

        emit LogValidatorAdded(
            _validatorAddress,
            _validatorPower,
            currentValsetVersion,
            validatorCount,
            totalPower
        );
    }

    /*
     * @dev: resetValset
     */
    function resetValset() internal {
        currentValsetVersion = currentValsetVersion.add(1);
        validatorCount = 0;
        totalPower = 0;

        emit LogValsetReset(currentValsetVersion, validatorCount, totalPower);
    }
}

File 27 of 30 : OracleStorage.sol
pragma solidity 0.5.16;

contract OracleStorage {
    /*
     * @dev: Public variable declarations
     */
    address public cosmosBridge;

    /**
    * @notice Tracks the number of OracleClaims made on an individual BridgeClaim
    */
    address public operator;

    /**
    * @notice Tracks the number of OracleClaims made on an individual BridgeClaim
    */
    uint256 public consensusThreshold; // e.g. 75 = 75%

    /**
    * @notice Tracks the number of OracleClaims made on an individual BridgeClaim
    */
    mapping(uint256 => uint256) public oracleClaimValidators;

    /**
    * @notice mapping of prophecyid to validator address to boolean
    */
    mapping(uint256 => mapping(address => bool)) public hasMadeClaim;

    /**
    * @notice gap of storage for future upgrades
    */
    uint256[100] private ____gap;
}

File 28 of 30 : ValsetStorage.sol
pragma solidity 0.5.16;

contract ValsetStorage {

    /**
     * @dev: Total power of all validators
     */
    uint256 public totalPower;

    /**
     * @dev: Current valset version
     */
    uint256 public currentValsetVersion;

    /**
     * @dev: validator count
     */
    uint256 public validatorCount;

    /**
     * @dev: Keep track of active validator
     */
    mapping(address => mapping(uint256 => bool)) public validators;

    /**
     * @dev: operator address
     */
    address public operator;

    /**
     * @dev: validator address + uint then hashed equals key mapped to powers
     */
    mapping(address => mapping(uint256 => uint256)) public powers;

    /**
    * @notice gap of storage for future upgrades
    */
    uint256[100] private ____gap;
}

File 29 of 30 : CosmosBridgeStorage.sol
pragma solidity 0.5.16;

import "./BridgeBank/CosmosBankStorage.sol";
import "./BridgeBank/EthereumBankStorage.sol";

contract CosmosBridgeStorage {
    /**
    * @notice gap of storage for future upgrades
    */
    string COSMOS_NATIVE_ASSET_PREFIX;

    /*
     * @dev: Public variable declarations
     */
    address public operator;
    
    /**
    * @notice gap of storage for future upgrades
    */
    address payable public valset;
    
    /**
    * @notice gap of storage for future upgrades
    */
    address payable public oracle;
    
    /**
    * @notice gap of storage for future upgrades
    */
    address payable public bridgeBank;
    
    /**
    * @notice gap of storage for future upgrades
    */
    bool public hasBridgeBank;

    /**
    * @notice gap of storage for future upgrades
    */
    mapping(uint256 => ProphecyClaim) public prophecyClaims;

    /**
    * @notice prophecy status enum
    */
    enum Status {Null, Pending, Success, Failed}

    /**
    * @notice claim type enum
    */
    enum ClaimType {Unsupported, Burn, Lock}

    /**
    * @notice Prophecy claim struct
    */
    struct ProphecyClaim {
        address payable ethereumReceiver;
        string symbol;
        uint256 amount;
    }

    /**
    * @notice gap of storage for future upgrades
    */
    uint256[100] private ____gap;
}

File 30 of 30 : PauserRole.sol
pragma solidity 0.5.16;

contract PauserRole {

    mapping (address => bool) public pausers;

    modifier onlyPauser() {
        require(pausers[msg.sender], "PauserRole: caller does not have the Pauser role");
        _;
    }

    function addPauser(address account) public onlyPauser {
        _addPauser(account);
    }

    function renouncePauser() public {
        _removePauser(msg.sender);
    }

    function _addPauser(address account) internal {
        pausers[account] = true;
    }

    function _removePauser(address account) internal {
        pausers[account] = false;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_beneficiary","type":"address"}],"name":"LogBridgeTokenMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"bytes","name":"_to","type":"bytes"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"LogBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"bytes","name":"_to","type":"bytes"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"LogLock","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"}],"name":"LogNewBridgeToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"LogUnlock","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"bool","name":"_value","type":"bool"}],"name":"LogWhiteListUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"constant":false,"inputs":[{"internalType":"address","name":"_contractAddress","type":"address"}],"name":"addExistingBridgeToken","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addPauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"bridgeTokenCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"tokenAddresses","type":"address[]"}],"name":"bulkWhitelistUpdateLimits","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"_recipient","type":"bytes"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_newOperator","type":"address"}],"name":"changeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"changeOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"cosmosBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cosmosDepositNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"createNewBridgeToken","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"getBridgeToken","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getCosmosTokenInWhiteList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"getLockedFunds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"getLockedTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getTokenInEthWhiteList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_operatorAddress","type":"address"},{"internalType":"address","name":"_cosmosBridgeAddress","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_pauser","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"_recipient","type":"bytes"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"lock","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"lockBurnNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lockedFunds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"lockedTokenList","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"lowerToUpperTokens","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"maxTokenAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"_intendedRecipient","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mintBridgeTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oracle","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pausers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renouncePauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"safeLowerToUpperTokens","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"toLower","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"tokenFallback","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"_recipient","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unlock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"bool","name":"_inList","type":"bool"}],"name":"updateEthWhiteList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"_sifAddress","type":"bytes"}],"name":"verifySifPrefix","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"}]

608060405234801561001057600080fd5b506153fa806100206000396000f3fe6080604052600436106200025a5760003560e01c80638456cb59116200013f578063be6b721e11620000bb578063e05988a41162000079578063e05988a41462000f52578063ebb73ca9146200101c578063f24a590a14620010d4578063f8c8765e146200118c578063fcf9cf6e14620011db576200025a565b8063be6b721e1462000c46578063c0ee0b8a1462000cfe578063d185e1bb1462000dcb578063dc9ae17d1462000e0a578063ddf75bca1462000ed0576200025a565b806396e5c356116200010957806396e5c3561462000ad15780639df2a3851462000b08578063a6f9dae11462000bc0578063b0e9ef711462000bf7578063b86247d71462000c0f576200025a565b80638456cb591462000931578063867910d314620009495780638da5cb5b1462000a015780639416b4231462000a19576200025a565b80635acba65511620001db5780637b38c6d411620001995780637b38c6d4146200085c5780637dc0d1d0146200089357806380f51c1214620008ab5780638129fc1c14620008e257806382dc1ec414620008fa576200025a565b80635acba65514620005665780635c975abb146200061e57806361750471146200064a5780636ef8d66d146200071457806373d88665146200072c576200025a565b8063328470ab1162000229578063328470ab146200044e5780633f4ba83a1462000466578063416d3227146200047e57806350b06e4d1462000496578063570ca735146200054e576200025a565b806306394c9b146200025f5780630a1f9b66146200029857806311cf03cb146200036c5780631deed3bb1462000436575b600080fd5b3480156200026c57600080fd5b5062000296600480360360208110156200028557600080fd5b50356001600160a01b031662001212565b005b348015620002a557600080fd5b506200035060048036036020811015620002be57600080fd5b810190602081018135600160201b811115620002d957600080fd5b820183602082011115620002ec57600080fd5b803590602001918460018302840111600160201b831117156200030e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550620012d0945050505050565b604080516001600160a01b039092168252519081900360200190f35b3480156200037957600080fd5b5062000424600480360360208110156200039257600080fd5b810190602081018135600160201b811115620003ad57600080fd5b820183602082011115620003c057600080fd5b803590602001918460018302840111600160201b83111715620003e257600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955062001345945050505050565b60408051918252519081900360200190f35b3480156200044357600080fd5b506200042462001363565b3480156200045b57600080fd5b506200042462001369565b3480156200047357600080fd5b50620002966200136f565b3480156200048b57600080fd5b50620004246200144f565b348015620004a357600080fd5b506200035060048036036020811015620004bc57600080fd5b810190602081018135600160201b811115620004d757600080fd5b820183602082011115620004ea57600080fd5b803590602001918460018302840111600160201b831117156200050c57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955062001455945050505050565b3480156200055b57600080fd5b5062000350620014cc565b3480156200057357600080fd5b5062000424600480360360208110156200058c57600080fd5b810190602081018135600160201b811115620005a757600080fd5b820183602082011115620005ba57600080fd5b803590602001918460018302840111600160201b83111715620005dc57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550620014dc945050505050565b3480156200062b57600080fd5b506200063662001562565b604080519115158252519081900360200190f35b3480156200065757600080fd5b5062000296600480360360608110156200067057600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156200069b57600080fd5b820183602082011115620006ae57600080fd5b803590602001918460018302840111600160201b83111715620006d057600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050913592506200156d915050565b3480156200072157600080fd5b5062000296620016a1565b3480156200073957600080fd5b50620007e4600480360360208110156200075257600080fd5b810190602081018135600160201b8111156200076d57600080fd5b8201836020820111156200078057600080fd5b803590602001918460018302840111600160201b83111715620007a257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550620016ae945050505050565b6040805160208082528351818301528351919283929083019185019080838360005b838110156200082057818101518382015260200162000806565b50505050905090810190601f1680156200084e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156200086957600080fd5b5062000636600480360360208110156200088257600080fd5b50356001600160a01b031662001850565b348015620008a057600080fd5b50620003506200186f565b348015620008b857600080fd5b506200063660048036036020811015620008d157600080fd5b50356001600160a01b03166200187f565b348015620008ef57600080fd5b506200029662001895565b3480156200090757600080fd5b5062000296600480360360208110156200092057600080fd5b50356001600160a01b031662001925565b3480156200093e57600080fd5b506200029662001984565b3480156200095657600080fd5b50620007e4600480360360208110156200096f57600080fd5b810190602081018135600160201b8111156200098a57600080fd5b8201836020820111156200099d57600080fd5b803590602001918460018302840111600160201b83111715620009bf57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955062001a61945050505050565b34801562000a0e57600080fd5b506200035062001b0c565b34801562000a2657600080fd5b50620007e46004803603602081101562000a3f57600080fd5b810190602081018135600160201b81111562000a5a57600080fd5b82018360208201111562000a6d57600080fd5b803590602001918460018302840111600160201b8311171562000a8f57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955062001b1c945050505050565b34801562000ade57600080fd5b50620006366004803603602081101562000af757600080fd5b50356001600160a01b031662001c55565b620002966004803603606081101562000b2057600080fd5b810190602081018135600160201b81111562000b3b57600080fd5b82018360208201111562000b4e57600080fd5b803590602001918460018302840111600160201b8311171562000b7057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550506001600160a01b03833516935050506020013562001c73565b34801562000bcd57600080fd5b50620002966004803603602081101562000be657600080fd5b50356001600160a01b031662001fce565b34801562000c0457600080fd5b506200035062002089565b34801562000c1c57600080fd5b50620004246004803603602081101562000c3557600080fd5b50356001600160a01b031662002099565b34801562000c5357600080fd5b50620006366004803603602081101562000c6c57600080fd5b810190602081018135600160201b81111562000c8757600080fd5b82018360208201111562000c9a57600080fd5b803590602001918460018302840111600160201b8311171562000cbc57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550620020ab945050505050565b34801562000d0b57600080fd5b50620002966004803603606081101562000d2457600080fd5b6001600160a01b0382351691602081013591810190606081016040820135600160201b81111562000d5457600080fd5b82018360208201111562000d6757600080fd5b803590602001918460018302840111600160201b8311171562000d8957600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506200169c945050505050565b34801562000dd857600080fd5b50620006366004803603604081101562000df157600080fd5b506001600160a01b03813516906020013515156200211c565b34801562000e1757600080fd5b50620002966004803603606081101562000e3057600080fd5b810190602081018135600160201b81111562000e4b57600080fd5b82018360208201111562000e5e57600080fd5b803590602001918460018302840111600160201b8311171562000e8057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550506001600160a01b0383351693505050602001356200244b565b34801562000edd57600080fd5b50620006366004803603602081101562000ef657600080fd5b810190602081018135600160201b81111562000f1157600080fd5b82018360208201111562000f2457600080fd5b803590602001918460208302840111600160201b8311171562000f4657600080fd5b50909250905062002725565b34801562000f5f57600080fd5b50620002966004803603606081101562000f7857600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111562000fa357600080fd5b82018360208201111562000fb657600080fd5b803590602001918460018302840111600160201b8311171562000fd857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550509135925062002985915050565b3480156200102957600080fd5b5062000350600480360360208110156200104257600080fd5b810190602081018135600160201b8111156200105d57600080fd5b8201836020820111156200107057600080fd5b803590602001918460018302840111600160201b831117156200109257600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955062002ab1945050505050565b348015620010e157600080fd5b506200035060048036036020811015620010fa57600080fd5b810190602081018135600160201b8111156200111557600080fd5b8201836020820111156200112857600080fd5b803590602001918460018302840111600160201b831117156200114a57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955062002ae6945050505050565b3480156200119957600080fd5b506200029660048036036080811015620011b257600080fd5b506001600160a01b03813581169160208101358216916040820135811691606001351662002b0c565b348015620011e857600080fd5b5062000350600480360360208110156200120157600080fd5b50356001600160a01b031662002c4d565b610134546001600160a01b031633146200125f576040805162461bcd60e51b815260206004820152600960248201526810b7b832b930ba37b960b91b604482015290519081900360640190fd5b6001600160a01b038116620012ad576040805162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b604482015290519081900360640190fd5b61013480546001600160a01b0319166001600160a01b0392909216919091179055565b6000606a826040518082805190602001908083835b60208310620013065780518252601f199092019160209182019101620012e5565b51815160209384036101000a60001901801990921691161790529201948552506040519384900301909220546001600160a01b0316925050505b919050565b80516020818301810180516101388252928201919093012091525481565b60685481565b60005481565b336000908152610204602052604090205460ff16620013c05760405162461bcd60e51b8152600401808060200182810382526030815260200180620052eb6030913960400191505060405180910390fd5b6102055460ff1662001410576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b6200141a62002cb9565b6040805133815290517f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa9181900360200190a1565b60015481565b610136546000906001600160a01b03163314620014a9576040805162461bcd60e51b815260206004820152600d60248201526c21636f736d6f7362726964676560981b604482015290519081900360640190fd5b6000620014b68362002cce565b9050620014c581600162002f4c565b5092915050565b610134546001600160a01b031681565b600060696000606a846040518082805190602001908083835b60208310620015165780518252601f199092019160209182019101620014f5565b51815160209384036101000a600019018019909216911617905292019485525060408051948590038201909420546001600160a01b031685528401949094525001600020549392505050565b6102055460ff165b90565b610136546001600160a01b03163314620015be576040805162461bcd60e51b815260206004820152600d60248201526c21636f736d6f7362726964676560981b604482015290519081900360640190fd5b6102055460ff16156200160b576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60606200161883620016ae565b905060006002826040518082805190602001908083835b60208310620016505780518252601f1990920191602091820191016200162f565b51815160209384036101000a60001901801990921691161790529201948552506040519384900301909220546001600160a01b0316925062001699915086905082848662002fb7565b50505b505050565b620016ac3362003219565b565b6060806003836040518082805190602001908083835b60208310620016e55780518252601f199092019160209182019101620016c4565b518151600019602094850361010090810a820192831692199390931691909117909252949092019687526040805197889003820188208054601f60026001831615909802909501169590950492830182900482028801820190528187529294509250508301828280156200179d5780601f1062001771576101008083540402835291602001916200179d565b820191906000526020600020905b8154815290600101906020018083116200177f57829003601f168201915b505060405184519495507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709486945060209182019350839250908401908083835b60208310620017ff5780518252601f199092019160209182019101620017de565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052805190602001201462001847578062001849565b825b9392505050565b6001600160a01b0316600090815261019e602052604090205460ff1690565b610135546001600160a01b031681565b6102046020526000908152604090205460ff1681565b6102035460ff1615620018dd576040805162461bcd60e51b815260206004820152600b60248201526a125b9a5d1a585b1a5e995960aa1b604482015290519081900360640190fd5b6000805260cf6020527fe02c59459e6ae69bba35526a32783b104c6119df0d640a9ac4990ec2f8d493a98054600160ff19918216811790925561020380549091169091179055565b336000908152610204602052604090205460ff16620019765760405162461bcd60e51b8152600401808060200182810382526030815260200180620052eb6030913960400191505060405180910390fd5b62001981816200323b565b50565b336000908152610204602052604090205460ff16620019d55760405162461bcd60e51b8152600401808060200182810382526030815260200180620052eb6030913960400191505060405180910390fd5b6102055460ff161562001a22576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b62001a2c62002cb9565b6040805133815290517f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589181900360200190a1565b805160208183018101805160038252928201938201939093209190925280546040805160026001841615610100026000190190931692909204601f8101859004850283018501909152808252909283018282801562001b045780601f1062001ad85761010080835404028352916020019162001b04565b820191906000526020600020905b81548152906001019060200180831162001ae657829003601f168201915b505050505081565b610137546001600160a01b031681565b606080829050606081516040519080825280601f01601f19166020018201604052801562001b51576020820181803883390190505b50905060005b825181101562001c4d578251604160f81b9084908390811062001b7657fe5b01602001516001600160f81b0319161080159062001bb657508251602d60f91b9084908390811062001ba457fe5b01602001516001600160f81b03191611155b1562001c075782818151811062001bc957fe5b602001015160f81c60f81b60f81c60200160f81b82828151811062001bea57fe5b60200101906001600160f81b031916908160001a90535062001c44565b82818151811062001c1457fe5b602001015160f81c60f81b82828151811062001c2c57fe5b60200101906001600160f81b031916908160001a9053505b60010162001b57565b509392505050565b6001600160a01b0316600090815260cf602052604090205460ff1690565b8162001c7f8162001850565b62001cbc5760405162461bcd60e51b8152600401808060200182810382526034815260200180620053686034913960400191505060405180910390fd5b838051602a1462001d02576040805162461bcd60e51b815260206004820152600b60248201526a24b73b30b634b2103632b760a91b604482015290519081900360640190fd5b62001d0d81620020ab565b151560011462001d5a576040805162461bcd60e51b8152602060048201526013602482015272496e76616c696420736966206164647265737360681b604482015290519081900360640190fd5b6102055460ff161562001da7576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6060341562001e68576001600160a01b0385161562001dfb576040805162461bcd60e51b815260206004820152600b60248201526a216164647265737328302960a81b604482015290519081900360640190fd5b83341462001e47576040805162461bcd60e51b81526020600482015260146024820152731a5b98dbdc9c9958dd08195d1a08185b5bdd5b9d60621b604482015290519081900360640190fd5b506040805180820190915260038152620cae8d60eb1b602082015262001fb7565b8462001e866001600160a01b03821633308863ffffffff6200326016565b856001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801562001ec057600080fd5b505afa15801562001ed5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101562001eff57600080fd5b8101908080516040519392919084600160201b82111562001f1f57600080fd5b90830190602082018581111562001f3557600080fd5b8251600160201b81118282018810171562001f4f57600080fd5b82525081516020918201929091019080838360005b8381101562001f7e57818101518382015260200162001f64565b50505050905090810190601f16801562001fac5780820380516001836020036101000a031916815260200191505b506040525050509150505b62001fc63387878488620032c2565b505050505050565b610137546001600160a01b0316331462002018576040805162461bcd60e51b815260206004820152600660248201526510b7bbb732b960d11b604482015290519081900360640190fd5b6001600160a01b03811662002066576040805162461bcd60e51b815260206004820152600f60248201526e696e76616c6964206164647265737360881b604482015290519081900360640190fd5b61013780546001600160a01b0319166001600160a01b0392909216919091179055565b610136546001600160a01b031681565b60696020526000908152604090205481565b60006239b4b360e91b815b60038110156200211257838181518110620020cd57fe5b01602001516001600160f81b031916828260038110620020e957fe5b1a60f81b6001600160f81b03191614620021095760009250505062001340565b600101620020b6565b5060019392505050565b610134546000906001600160a01b031633146200216c576040805162461bcd60e51b815260206004820152600960248201526810b7b832b930ba37b960b91b604482015290519081900360640190fd5b6060836001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015620021a857600080fd5b505afa158015620021bd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015620021e757600080fd5b8101908080516040519392919084600160201b8211156200220757600080fd5b9083019060208201858111156200221d57600080fd5b8251600160201b8111828201881017156200223757600080fd5b82525081516020918201929091019080838360005b83811015620022665781810151838201526020016200224c565b50505050905090810190601f168015620022945780820380516001836020036101000a031916815260200191505b5060405250505090506000606a826040518082805190602001908083835b60208310620022d35780518252601f199092019160209182019101620022b2565b51815160209384036101000a60001901801990921691161790529201948552506040519384900301909220546001600160a01b03169250508415905062002365576001600160a01b038116156200235f576040805162461bcd60e51b815260206004820152600b60248201526a1dda1a5d195b1a5cdd195960aa1b604482015290519081900360640190fd5b620023b3565b6000816001600160a01b031611620023b3576040805162461bcd60e51b815260206004820152600c60248201526b085dda1a5d195b1a5cdd195960a21b604482015290519081900360640190fd5b816003620023c18462001b1c565b6040518082805190602001908083835b60208310620023f25780518252601f199092019160209182019101620023d1565b51815160209384036101000a6000190180199092169116179052920194855250604051938490038101909320845162002435959194919091019250905062003d61565b5062002442858562003495565b95945050505050565b828051602a1462002491576040805162461bcd60e51b815260206004820152600b60248201526a24b73b30b634b2103632b760a91b604482015290519081900360640190fd5b6200249c81620020ab565b1515600114620024e9576040805162461bcd60e51b8152602060048201526013602482015272496e76616c696420736966206164647265737360681b604482015290519081900360640190fd5b82620024f58162001c55565b620025325760405162461bcd60e51b8152600401808060200182810382526034815260200180620053686034913960400191505060405180910390fd5b6102055460ff16156200257f576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6060846001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015620025bb57600080fd5b505afa158015620025d0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015620025fa57600080fd5b8101908080516040519392919084600160201b8211156200261a57600080fd5b9083019060208201858111156200263057600080fd5b8251600160201b8111828201881017156200264a57600080fd5b82525081516020918201929091019080838360005b83811015620026795781810151838201526020016200265f565b50505050905090810190601f168015620026a75780820380516001836020036101000a031916815260200191505b50604081815263079cc67960e41b8252336004830152602482018a9052519495506001600160a01b038a16946379cc679094506044808301945060009350909182900301818387803b158015620026fd57600080fd5b505af115801562002712573d6000803e3d6000fd5b5050505062001fc6338787848862003501565b610134546000906001600160a01b0316331462002775576040805162461bcd60e51b815260206004820152600960248201526810b7b832b930ba37b960b91b604482015290519081900360640190fd5b60005b828110156200211257620027aa8484838181106200279257fe5b905060200201356001600160a01b0316600162003495565b506060848483818110620027ba57fe5b905060200201356001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156200280357600080fd5b505afa15801562002818573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156200284257600080fd5b8101908080516040519392919084600160201b8211156200286257600080fd5b9083019060208201858111156200287857600080fd5b8251600160201b8111828201881017156200289257600080fd5b82525081516020918201929091019080838360005b83811015620028c1578181015183820152602001620028a7565b50505050905090810190601f168015620028ef5780820380516001836020036101000a031916815260200191505b506040525050509050806003620029068362001b1c565b6040518082805190602001908083835b60208310620029375780518252601f19909201916020918201910162002916565b51815160209384036101000a600019018019909216911617905292019485525060405193849003810190932084516200297a959194919091019250905062003d61565b505060010162002778565b610136546001600160a01b03163314620029d6576040805162461bcd60e51b815260206004820152600d60248201526c21636f736d6f7362726964676560981b604482015290519081900360640190fd5b6102055460ff161562002a23576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b606062002a3083620016ae565b90506000606a826040518082805190602001908083835b6020831062002a685780518252601f19909201916020918201910162002a47565b51815160209384036101000a60001901801990921691161790529201948552506040519384900301909220546001600160a01b03169250620016999150869050828486620035c4565b600060028260405180828051906020019080838360208310620013065780518252601f199092019160209182019101620012e5565b8051602081830181018051606a825292820191909301209152546001600160a01b031681565b61020554610100900460ff161562002b54576040805162461bcd60e51b81526020600480830191909152602482015263125b9a5d60e21b604482015290519081900360640190fd5b62002b5e62003736565b62002b6862001895565b62002b7381620037c7565b61013480546001600160a01b038087166001600160a01b0319928316179092556101368054868416908316179055610137805492851692909116919091179055610205805461ff00191661010017905560408051808201825260068082526532b937bbb0b760d11b602083018181528451918252600392820192909252925192839003602601909220905162002c0a929062003d61565b506040805180820182526003808252620cae8d60eb1b60208301818152845191825281830192909252925192839003602301909220905162001699929062003d61565b610137546000906001600160a01b0316331462002c9a576040805162461bcd60e51b815260206004820152600660248201526510b7bbb732b960d11b604482015290519081900360640190fd5b62002ca782600162002f4c565b5062002cb382620037e0565b92915050565b610205805460ff19811660ff90911615179055565b6000805462002ce590600163ffffffff62003ab116565b6000908155604051839062002cfa9062003de6565b60208082528251818301528251829160408301919085019080838360005b8381101562002d3257818101518382015260200162002d18565b50505050905090810190601f16801562002d605780820380516001836020036101000a031916815260200191505b5092505050604051809103906000f08015801562002d82573d6000803e3d6000fd5b5090506000819050806002856040518082805190602001908083835b6020831062002dbf5780518252601f19909201916020918201910162002d9e565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922080546001600160a01b0319166001600160a01b03949094169390931790925550849050600362002e1a8262001b1c565b6040518082805190602001908083835b6020831062002e4b5780518252601f19909201916020918201910162002e2a565b51815160209384036101000a6000190180199092169116179052920194855250604051938490038101909320845162002e8e959194919091019250905062003d61565b507f0ec4ab372af15f8db6003eb14d91402a44b20dff79fbac33b4ee0df68fafe9c0818560405180836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b8381101562002f0957818101518382015260200162002eef565b50505050905090810190601f16801562002f375780820380516001836020036101000a031916815260200191505b50935050505060405180910390a19392505050565b6001600160a01b038216600081815260cf60209081526040808320805460ff1916861515908117909155815194855291840191909152805191927fbabeec6613676f4972214f70ddf47c77eb8360e09b54278f21d6f999faf7c15c929081900390910190a150919050565b826001600160a01b03166002836040518082805190602001908083835b6020831062002ff55780518252601f19909201916020918201910162002fd4565b51815160209384036101000a60001901801990921691161790529201948552506040519384900301909220546001600160a01b03169290921491506200306f90505760405162461bcd60e51b8152600401808060200182810382526027815260200180620053416027913960400191505060405180910390fd5b826001600160a01b03166340c10f1985836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015620030d057600080fd5b505af1158015620030e5573d6000803e3d6000fd5b505050506040513d6020811015620030fc57600080fd5b50516200313b5760405162461bcd60e51b81526004018080602001828103825260268152602001806200531b6026913960400191505060405180910390fd5b7f262f97360779b7c2bb05fd24ef49f22d51435f78d3abd1ab35c323b22064cd4d8383838760405180856001600160a01b03166001600160a01b0316815260200180602001848152602001836001600160a01b03166001600160a01b03168152602001828103825285818151815260200191508051906020019080838360005b83811015620031d5578181015183820152602001620031bb565b50505050905090810190601f168015620032035780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a150505050565b6001600160a01b0316600090815261020460205260409020805460ff19169055565b6001600160a01b0316600090815261020460205260409020805460ff19166001179055565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052620032bc90859062003b0c565b50505050565b606854620032d890600163ffffffff62003ab116565b60688190555082606a836040518082805190602001908083835b60208310620033135780518252601f199092019160209182019101620032f2565b51815160209384036101000a600019018019909216911617905292019485525060408051948590038201852080546001600160a01b0319166001600160a01b039788161790556068548b87168652958916908501526080840186905260a0840185905260c08482018181528a519186019190915289517f374449c83a37309524754bbdfc5b8306d3694b5d14609b8fbb1b50cc5c0319a7968c968c96508b95508a948a949293919291606084019160e0850191908a019080838360005b83811015620033ea578181015183820152602001620033d0565b50505050905090810190601f168015620034185780820380516001836020036101000a031916815260200191505b50838103825286518152865160209182019188019080838360005b838110156200344d57818101518382015260200162003433565b50505050905090810190601f1680156200347b5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390a15050505050565b6001600160a01b038216600081815261019e60209081526040808320805460ff1916861515908117909155815194855291840191909152805191927fbabeec6613676f4972214f70ddf47c77eb8360e09b54278f21d6f999faf7c15c929081900390910190a150919050565b6068546200351790600163ffffffff62003ab116565b6068819055507fcff57df3b42f67919a9300d211bb7fe56104ca34949da91116a8f82ff51bb777858585858560685460405180876001600160a01b03166001600160a01b0316815260200180602001866001600160a01b03166001600160a01b03168152602001806020018581526020018481526020018381038352888181518152602001915080519060200190808383600083811015620033ea578181015183820152602001620033d0565b6001600160a01b0383166200367e576040516000906001600160a01b0386169061ea6090849084818181858888f193505050503d806000811462003625576040519150601f19603f3d011682016040523d82523d6000602084013e6200362a565b606091505b505090508062003677576040805162461bcd60e51b815260206004820152601360248201527232b93937b91039b2b73234b7339032ba3432b960691b604482015290519081900360640190fd5b506200369d565b826200369b6001600160a01b038216868463ffffffff62003cd016565b505b7f802cd873de701272ec903860b690986bd460b5bcd57e30ac1fdfdeece10528ac8484848460405180856001600160a01b03166001600160a01b03168152602001846001600160a01b03166001600160a01b03168152602001806020018381526020018281038252848181518152602001915080519060200190808383600083811015620031d5578181015183820152602001620031bb565b61019d5460ff16156200377e576040805162461bcd60e51b815260206004820152600b60248201526a125b9a5d1a585b1a5e995960aa1b604482015290519081900360640190fd5b6000805261019e6020527f5b1e587894c781c322714baac11bfa7b0da2aeb4590a6dcb5f31ea08c486311b8054600160ff19918216811790925561019d80549091169091179055565b620037d2816200323b565b50610205805460ff19169055565b60008054620037f790600163ffffffff62003ab116565b6000819055506060826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156200383957600080fd5b505afa1580156200384e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156200387857600080fd5b8101908080516040519392919084600160201b8211156200389857600080fd5b908301906020820185811115620038ae57600080fd5b8251600160201b811182820188101715620038c857600080fd5b82525081516020918201929091019080838360005b83811015620038f7578181015183820152602001620038dd565b50505050905090810190601f168015620039255780820380516001836020036101000a031916815260200191505b5060405250505090506000839050806002836040518082805190602001908083835b60208310620039685780518252601f19909201916020918201910162003947565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922080546001600160a01b0319166001600160a01b039490941693909317909255508290506003620039c38262001b1c565b6040518082805190602001908083835b60208310620039f45780518252601f199092019160209182019101620039d3565b51815160209384036101000a6000190180199092169116179052920194855250604051938490038101909320845162003a37959194919091019250905062003d61565b507f0ec4ab372af15f8db6003eb14d91402a44b20dff79fbac33b4ee0df68fafe9c0818360405180836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360008381101562002f0957818101518382015260200162002eef565b60008282018381101562001849576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b62003b20826001600160a01b031662003d24565b62003b72576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b6020831062003bb25780518252601f19909201916020918201910162003b91565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811462003c16576040519150601f19603f3d011682016040523d82523d6000602084013e62003c1b565b606091505b50915091508162003c73576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115620032bc5780806020019051602081101562003c9157600080fd5b5051620032bc5760405162461bcd60e51b815260040180806020018281038252602a8152602001806200539c602a913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526200169c90849062003b0c565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159062003d5957508115155b949350505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1062003da457805160ff191683800117855562003dd4565b8280016001018555821562003dd4579182015b8281111562003dd457825182559160200191906001019062003db7565b5062003de292915062003df4565b5090565b6114d98062003e1283390190565b6200156a91905b8082111562003de2576000815560010162003dfb56fe60806040523480156200001157600080fd5b50604051620014d9380380620014d9833981810160405260208110156200003757600080fd5b81019080805160405193929190846401000000008211156200005857600080fd5b9083019060208201858111156200006e57600080fd5b82516401000000008111828201881017156200008957600080fd5b82525081516020918201929091019080838360005b83811015620000b85781810151838201526020016200009e565b50505050905090810190601f168015620000e65780820380516001836020036101000a031916815260200191505b506040525050508081601262000114620001056200015e60201b60201c565b6001600160e01b036200016316565b825162000129906004906020860190620002ab565b5081516200013f906005906020850190620002ab565b506006805460ff191660ff92909216919091179055506200034d915050565b335b90565b6200017e816003620001b560201b62000e621790919060201c565b6040516001600160a01b038216907f6ae172837ea30b801fbfcdd4108aa1d5bf8ff775444fd70256b44e6bf3dfc3f690600090a250565b620001ca82826001600160e01b036200024216565b156200021d576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b60006001600160a01b0382166200028b5760405162461bcd60e51b8152600401808060200182810382526022815260200180620014b76022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620002ee57805160ff19168380011785556200031e565b828001600101855582156200031e579182015b828111156200031e57825182559160200191906001019062000301565b506200032c92915062000330565b5090565b6200016091905b808211156200032c576000815560010162000337565b61115a806200035d6000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c806370a08231116100a257806398650275116100715780639865027514610332578063a457c2d71461033a578063a9059cbb14610366578063aa271e1a14610392578063dd62ed3e146103b85761010b565b806370a08231146102b257806379cc6790146102d857806395d89b4114610304578063983b2d561461030c5761010b565b8063313ce567116100de578063313ce5671461021d578063395093511461023b57806340c10f191461026757806342966c68146102935761010b565b806306fdde0314610110578063095ea7b31461018d57806318160ddd146101cd57806323b872dd146101e7575b600080fd5b6101186103e6565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561015257818101518382015260200161013a565b50505050905090810190601f16801561017f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101b9600480360360408110156101a357600080fd5b506001600160a01b03813516906020013561047c565b604080519115158252519081900360200190f35b6101d5610499565b60408051918252519081900360200190f35b6101b9600480360360608110156101fd57600080fd5b506001600160a01b0381358116916020810135909116906040013561049f565b61022561052c565b6040805160ff9092168252519081900360200190f35b6101b96004803603604081101561025157600080fd5b506001600160a01b038135169060200135610535565b6101b96004803603604081101561027d57600080fd5b506001600160a01b038135169060200135610589565b6102b0600480360360208110156102a957600080fd5b50356105e0565b005b6101d5600480360360208110156102c857600080fd5b50356001600160a01b03166105f4565b6102b0600480360360408110156102ee57600080fd5b506001600160a01b03813516906020013561060f565b61011861061d565b6102b06004803603602081101561032257600080fd5b50356001600160a01b031661067e565b6102b06106cd565b6101b96004803603604081101561035057600080fd5b506001600160a01b0381351690602001356106df565b6101b96004803603604081101561037c57600080fd5b506001600160a01b03813516906020013561074d565b6101b9600480360360208110156103a857600080fd5b50356001600160a01b0316610761565b6101d5600480360360408110156103ce57600080fd5b506001600160a01b038135811691602001351661077a565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104725780601f1061044757610100808354040283529160200191610472565b820191906000526020600020905b81548152906001019060200180831161045557829003601f168201915b5050505050905090565b60006104906104896107a5565b84846107a9565b50600192915050565b60025490565b60006104ac848484610895565b610522846104b86107a5565b61051d85604051806060016040528060288152602001611029602891396001600160a01b038a166000908152600160205260408120906104f66107a5565b6001600160a01b03168152602081019190915260400160002054919063ffffffff6109f116565b6107a9565b5060019392505050565b60065460ff1690565b60006104906105426107a5565b8461051d85600160006105536107a5565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff610a8816565b600061059b6105966107a5565b610761565b6105d65760405162461bcd60e51b8152600401808060200182810382526030815260200180610fd86030913960400191505060405180910390fd5b6104908383610ae9565b6105f16105eb6107a5565b82610bd9565b50565b6001600160a01b031660009081526020819052604090205490565b6106198282610cd5565b5050565b60058054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104725780601f1061044757610100808354040283529160200191610472565b6106896105966107a5565b6106c45760405162461bcd60e51b8152600401808060200182810382526030815260200180610fd86030913960400191505060405180910390fd5b6105f181610d29565b6106dd6106d86107a5565b610d71565b565b60006104906106ec6107a5565b8461051d8560405180606001604052806025815260200161110160259139600160006107166107a5565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff6109f116565b600061049061075a6107a5565b8484610895565b600061077460038363ffffffff610db916565b92915050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b3390565b6001600160a01b0383166107ee5760405162461bcd60e51b81526004018080602001828103825260248152602001806110dd6024913960400191505060405180910390fd5b6001600160a01b0382166108335760405162461bcd60e51b8152600401808060200182810382526022815260200180610f906022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b0383166108da5760405162461bcd60e51b81526004018080602001828103825260258152602001806110b86025913960400191505060405180910390fd5b6001600160a01b03821661091f5760405162461bcd60e51b8152600401808060200182810382526023815260200180610f4b6023913960400191505060405180910390fd5b61096281604051806060016040528060268152602001610fb2602691396001600160a01b038616600090815260208190526040902054919063ffffffff6109f116565b6001600160a01b038085166000908152602081905260408082209390935590841681522054610997908263ffffffff610a8816565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b60008184841115610a805760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610a45578181015183820152602001610a2d565b50505050905090810190601f168015610a725780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600082820183811015610ae2576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6001600160a01b038216610b44576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b600254610b57908263ffffffff610a8816565b6002556001600160a01b038216600090815260208190526040902054610b83908263ffffffff610a8816565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b038216610c1e5760405162461bcd60e51b81526004018080602001828103825260218152602001806110976021913960400191505060405180910390fd5b610c6181604051806060016040528060228152602001610f6e602291396001600160a01b038516600090815260208190526040902054919063ffffffff6109f116565b6001600160a01b038316600090815260208190526040902055600254610c8d908263ffffffff610e2016565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b610cdf8282610bd9565b61061982610ceb6107a5565b61051d84604051806060016040528060248152602001611073602491396001600160a01b0388166000908152600160205260408120906104f66107a5565b610d3a60038263ffffffff610e6216565b6040516001600160a01b038216907f6ae172837ea30b801fbfcdd4108aa1d5bf8ff775444fd70256b44e6bf3dfc3f690600090a250565b610d8260038263ffffffff610ee316565b6040516001600160a01b038216907fe94479a9f7e1952cc78f2d6baab678adc1b772d936c6583def489e524cb6669290600090a250565b60006001600160a01b038216610e005760405162461bcd60e51b81526004018080602001828103825260228152602001806110516022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b6000610ae283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506109f1565b610e6c8282610db9565b15610ebe576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b610eed8282610db9565b610f285760405162461bcd60e51b81526004018080602001828103825260218152602001806110086021913960400191505060405180910390fd5b6001600160a01b0316600090815260209190915260409020805460ff1916905556fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63654d696e746572526f6c653a2063616c6c657220646f6573206e6f74206861766520746865204d696e74657220726f6c65526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c6545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365526f6c65733a206163636f756e7420697320746865207a65726f206164647265737345524332303a206275726e20616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a7231582092a82a5926e2b0a68d208f27474bb084e81c7bb0f3c7838645f5e1759d608e0664736f6c63430005100032526f6c65733a206163636f756e7420697320746865207a65726f2061646472657373506175736572526f6c653a2063616c6c657220646f6573206e6f742068617665207468652050617573657220726f6c65417474656d70746564206d696e74206f662062726964676520746f6b656e73206661696c6564546f6b656e206d757374206265206120636f6e74726f6c6c65642062726964676520746f6b656e4f6e6c7920746f6b656e20696e2077686974656c6973742063616e206265207472616e7366657272656420746f20636f736d6f735361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a265627a7a7231582033f44a07a5d35b13d659ddf8724618f7d12e90672afe1fd11c256e9ab9a540f064736f6c63430005100032

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