Address Details
contract

0x8ba9Ce201Fe7808cd7952617af868eBb5740e9E9

Contract Name
Federation
Creator
0x9f08bf–5824ad at 0x360f5e–05c179
Balance
0 CELO ( )
Tokens
Fetching tokens...
Transactions
453 Transactions
Transfers
0 Transfers
Gas Used
77,996,202
Last Balance Update
17419260
This contract has been partially verified via Sourcify. View contract in Sourcify repository
Contract name:
Federation




Optimization enabled
false
Compiler version
v0.5.17+commit.d19bba13




EVM Version
istanbul




Verified at
2022-11-03T12:37:45.595045Z

Federation.sol

// File: contracts/zeppelin/token/ERC20/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: contracts/zeppelin/token/ERC20/ERC20Detailed.sol

pragma solidity ^0.5.0;


/**
 * @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: contracts/IBridge.sol

pragma solidity ^0.5.0;


interface IBridge {
    function version() external pure returns (string memory);

    function getFeePercentage() external view returns(uint);

    function calcMaxWithdraw() external view returns (uint);

    /**
     * ERC-20 tokens approve and transferFrom pattern
     * See https://eips.ethereum.org/EIPS/eip-20#transferfrom
     */
    function receiveTokens(address tokenToUse, uint256 amount) external returns(bool);

    /**
     * ERC-777 tokensReceived hook allows to send tokens to a contract and notify it in a single transaction
     * See https://eips.ethereum.org/EIPS/eip-777#motivation for details
     */
    function tokensReceived (
        address operator,
        address from,
        address to,
        uint amount,
        bytes calldata userData,
        bytes calldata operatorData
    ) external;

    /**
     * Accepts the transaction from the other chain that was voted and sent by the federation contract
     */
    function acceptTransfer(
        address originalTokenAddress,
        address receiver,
        uint256 amount,
        string calldata symbol,
        bytes32 blockHash,
        bytes32 transactionHash,
        uint32 logIndex,
        uint8 decimals,
        uint256 granularity
    ) external returns(bool);

    event Cross(address indexed _tokenAddress, address indexed _to, uint256 _amount, string _symbol, bytes _userData,
        uint8 _decimals, uint256 _granularity);
    event NewSideToken(address indexed _newSideTokenAddress, address indexed _originalTokenAddress, string _newSymbol, uint256 _granularity);
    event AcceptedCrossTransfer(address indexed _tokenAddress, address indexed _to, uint256 _amount, uint8 _decimals, uint256 _granularity,
        uint256 _formattedAmount, uint8 _calculatedDecimals, uint256 _calculatedGranularity);
    event FeePercentageChanged(uint256 _amount);
}

// File: contracts/zeppelin/GSN/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: contracts/zeppelin/ownership/Ownable.sol

pragma solidity ^0.5.0;

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        _owner = _msgSender();
        emit OwnershipTransferred(address(0), _owner);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(isOwner(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Returns true if the caller is the current owner.
     */
    function isOwner() public view returns (bool) {
        return _msgSender() == _owner;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

// File: contracts/Federation.sol

pragma solidity ^0.5.0;



contract Federation is Ownable {
    uint constant public MAX_MEMBER_COUNT = 50;
    address constant private NULL_ADDRESS = address(0);

    IBridge public bridge;
    address[] public members;
    uint public required;

    mapping (address => bool) public isMember;
    mapping (bytes32 => mapping (address => bool)) public votes;
    mapping(bytes32 => bool) public processed;
    // solium-disable-next-line max-len
    event Voted(address indexed sender, bytes32 indexed transactionId, address originalTokenAddress, address receiver, uint256 amount, string symbol, bytes32 blockHash, bytes32 indexed transactionHash, uint32 logIndex, uint8 decimals, uint256 granularity);
    event Executed(bytes32 indexed transactionId);
    event MemberAddition(address indexed member);
    event MemberRemoval(address indexed member);
    event RequirementChange(uint required);
    event BridgeChanged(address bridge);

    modifier onlyMember() {
        require(isMember[_msgSender()], "Federation: Caller not a Federator");
        _;
    }

    modifier validRequirement(uint membersCount, uint _required) {
        // solium-disable-next-line max-len
        require(_required <= membersCount && _required != 0 && membersCount != 0, "Federation: Invalid requirements");
        _;
    }

    constructor(address[] memory _members, uint _required) public validRequirement(_members.length, _required) {
        require(_members.length <= MAX_MEMBER_COUNT, "Federation: Members larger than max allowed");
        members = _members;
        for (uint i = 0; i < _members.length; i++) {
            require(!isMember[_members[i]] && _members[i] != NULL_ADDRESS, "Federation: Invalid members");
            isMember[_members[i]] = true;
            emit MemberAddition(_members[i]);
        }
        required = _required;
        emit RequirementChange(required);
    }

    function setBridge(address _bridge) external onlyOwner {
        require(_bridge != NULL_ADDRESS, "Federation: Empty bridge");
        bridge = IBridge(_bridge);
        emit BridgeChanged(_bridge);
    }

    function voteTransaction(
        address originalTokenAddress,
        address receiver,
        uint256 amount,
        string calldata symbol,
        bytes32 blockHash,
        bytes32 transactionHash,
        uint32 logIndex,
        uint8 decimals,
        uint256 granularity)
    external onlyMember returns(bool)
    {
        // solium-disable-next-line max-len
        bytes32 transactionId = getTransactionId(originalTokenAddress, receiver, amount, symbol, blockHash, transactionHash, logIndex, decimals, granularity);
        if (processed[transactionId])
            return true;

        if (votes[transactionId][_msgSender()])
            return true;

        votes[transactionId][_msgSender()] = true;
        // solium-disable-next-line max-len
        emit Voted(_msgSender(), transactionId, originalTokenAddress, receiver, amount, symbol, blockHash, transactionHash, logIndex, decimals, granularity);

        uint transactionCount = getTransactionCount(transactionId);
        if (transactionCount >= required && transactionCount >= members.length / 2 + 1) {
            processed[transactionId] = true;
            bool acceptTransfer = bridge.acceptTransfer(originalTokenAddress, receiver, amount, symbol, blockHash, transactionHash, logIndex, decimals, granularity);
            require(acceptTransfer, "Federation: Bridge acceptTransfer error");
            emit Executed(transactionId);
            return true;
        }

        return true;
    }

    function getTransactionCount(bytes32 transactionId) public view returns(uint) {
        uint count = 0;
        for (uint i = 0; i < members.length; i++) {
            if (votes[transactionId][members[i]])
                count += 1;
        }
        return count;
    }

    function hasVoted(bytes32 transactionId) external view returns(bool)
    {
        return votes[transactionId][_msgSender()];
    }

    function transactionWasProcessed(bytes32 transactionId) external view returns(bool)
    {
        return processed[transactionId];
    }

    function getTransactionId(
        address originalTokenAddress,
        address receiver,
        uint256 amount,
        string memory symbol,
        bytes32 blockHash,
        bytes32 transactionHash,
        uint32 logIndex,
        uint8 decimals,
        uint256 granularity)
    public pure returns(bytes32)
    {
        // solium-disable-next-line max-len
        return keccak256(abi.encodePacked(originalTokenAddress, receiver, amount, symbol, blockHash, transactionHash, logIndex, decimals, granularity));
    }

    function addMember(address _newMember) external onlyOwner
    {
        require(_newMember != NULL_ADDRESS, "Federation: Empty member");
        require(!isMember[_newMember], "Federation: Member already exists");
        require(members.length < MAX_MEMBER_COUNT, "Federation: Max members reached");

        isMember[_newMember] = true;
        members.push(_newMember);
        emit MemberAddition(_newMember);
    }

    function removeMember(address _oldMember) external onlyOwner
    {
        require(_oldMember != NULL_ADDRESS, "Federation: Empty member");
        require(isMember[_oldMember], "Federation: Member doesn't exists");
        require(members.length > 1, "Federation: Can't remove all the members");
        require(members.length - 1 >= required, "Federation: Can't have less than required members");

        isMember[_oldMember] = false;
        for (uint i = 0; i < members.length - 1; i++) {
            if (members[i] == _oldMember) {
                members[i] = members[members.length - 1];
                break;
            }
        }
        members.length -= 1;
        emit MemberRemoval(_oldMember);
    }

    function getMembers() external view returns (address[] memory)
    {
        return members;
    }

    function changeRequirement(uint _required) external onlyOwner validRequirement(members.length, _required)
    {
        require(_required >= 2, "Federation: Requires at least 2");
        required = _required;
        emit RequirementChange(_required);
    }

}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[{"type":"address[]","name":"_members","internalType":"address[]"},{"type":"uint256","name":"_required","internalType":"uint256"}]},{"type":"event","name":"BridgeChanged","inputs":[{"type":"address","name":"bridge","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Executed","inputs":[{"type":"bytes32","name":"transactionId","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"event","name":"MemberAddition","inputs":[{"type":"address","name":"member","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"MemberRemoval","inputs":[{"type":"address","name":"member","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RequirementChange","inputs":[{"type":"uint256","name":"required","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Voted","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":true},{"type":"bytes32","name":"transactionId","internalType":"bytes32","indexed":true},{"type":"address","name":"originalTokenAddress","internalType":"address","indexed":false},{"type":"address","name":"receiver","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"string","name":"symbol","internalType":"string","indexed":false},{"type":"bytes32","name":"blockHash","internalType":"bytes32","indexed":false},{"type":"bytes32","name":"transactionHash","internalType":"bytes32","indexed":true},{"type":"uint32","name":"logIndex","internalType":"uint32","indexed":false},{"type":"uint8","name":"decimals","internalType":"uint8","indexed":false},{"type":"uint256","name":"granularity","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_MEMBER_COUNT","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addMember","inputs":[{"type":"address","name":"_newMember","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"contract IBridge"}],"name":"bridge","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"changeRequirement","inputs":[{"type":"uint256","name":"_required","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getMembers","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTransactionCount","inputs":[{"type":"bytes32","name":"transactionId","internalType":"bytes32"}],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getTransactionId","inputs":[{"type":"address","name":"originalTokenAddress","internalType":"address"},{"type":"address","name":"receiver","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"string","name":"symbol","internalType":"string"},{"type":"bytes32","name":"blockHash","internalType":"bytes32"},{"type":"bytes32","name":"transactionHash","internalType":"bytes32"},{"type":"uint32","name":"logIndex","internalType":"uint32"},{"type":"uint8","name":"decimals","internalType":"uint8"},{"type":"uint256","name":"granularity","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasVoted","inputs":[{"type":"bytes32","name":"transactionId","internalType":"bytes32"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isMember","inputs":[{"type":"address","name":"","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isOwner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"members","inputs":[{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"processed","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeMember","inputs":[{"type":"address","name":"_oldMember","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"renounceOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"required","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setBridge","inputs":[{"type":"address","name":"_bridge","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transactionWasProcessed","inputs":[{"type":"bytes32","name":"transactionId","internalType":"bytes32"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"voteTransaction","inputs":[{"type":"address","name":"originalTokenAddress","internalType":"address"},{"type":"address","name":"receiver","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"string","name":"symbol","internalType":"string"},{"type":"bytes32","name":"blockHash","internalType":"bytes32"},{"type":"bytes32","name":"transactionHash","internalType":"bytes32"},{"type":"uint32","name":"logIndex","internalType":"uint32"},{"type":"uint8","name":"decimals","internalType":"uint8"},{"type":"uint256","name":"granularity","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"votes","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"},{"type":"address","name":"","internalType":"address"}],"constant":true}]
            

Deployed ByteCode

Verify & Publish
0x608060405234801561001057600080fd5b50600436106101375760003560e01c80639eab5253116100b8578063c1f0808a1161007c578063c1f0808a14610638578063ca6d56dc1461067e578063d03e1ee9146106c2578063dc8452cd146107d9578063e78cea92146107f7578063f2fde38b1461084157610137565b80639eab5253146104c7578063a1fb4acb14610526578063a230c52414610568578063a93585f0146105c4578063ba51a6df1461060a57610137565b8063715018a6116100ff578063715018a6146103a75780638da5cb5b146103b15780638dd14802146103fb5780638f32d59b1461043f5780639386775a1461046157610137565b8063099160571461013c5780630b1ca49a146102915780631b4613cb146102d55780635daf08ca1461031b578063681fc92114610389575b600080fd5b61027b600480360361012081101561015357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156101ba57600080fd5b8201836020820111156101cc57600080fd5b803590602001918460018302840111640100000000831117156101ee57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019092919080359060200190929190803563ffffffff169060200190929190803560ff16906020019092919080359060200190929190505050610885565b6040518082815260200191505060405180910390f35b6102d3600480360360208110156102a757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506109be565b005b610301600480360360208110156102eb57600080fd5b8101908080359060200190929190505050610e1e565b604051808215151515815260200191505060405180910390f35b6103476004803603602081101561033157600080fd5b8101908080359060200190929190505050610e8c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610391610ec8565b6040518082815260200191505060405180910390f35b6103af610ecd565b005b6103b9611006565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61043d6004803603602081101561041157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061102f565b005b6104476111f3565b604051808215151515815260200191505060405180910390f35b6104ad6004803603604081101561047757600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611251565b604051808215151515815260200191505060405180910390f35b6104cf611280565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156105125780820151818401526020810190506104f7565b505050509050019250505060405180910390f35b6105526004803603602081101561053c57600080fd5b810190808035906020019092919050505061130e565b6040518082815260200191505060405180910390f35b6105aa6004803603602081101561057e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506113e0565b604051808215151515815260200191505060405180910390f35b6105f0600480360360208110156105da57600080fd5b8101908080359060200190929190505050611400565b604051808215151515815260200191505060405180910390f35b6106366004803603602081101561062057600080fd5b810190808035906020019092919050505061142a565b005b6106646004803603602081101561064e57600080fd5b81019080803590602001909291905050506115f5565b604051808215151515815260200191505060405180910390f35b6106c06004803603602081101561069457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611615565b005b6107bf60048036036101208110156106d957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561074057600080fd5b82018360208201111561075257600080fd5b8035906020019184600183028401116401000000008311171561077457600080fd5b90919293919293908035906020019092919080359060200190929190803563ffffffff169060200190929190803560ff16906020019092919080359060200190929190505050611954565b604051808215151515815260200191505060405180910390f35b6107e1611f20565b6040518082815260200191505060405180910390f35b6107ff611f26565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6108836004803603602081101561085757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611f4c565b005b6000898989898989898989604051602001808a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140188815260200187805190602001908083835b602083106109365780518252602082019150602081019050602083039250610913565b6001836020036101000a0380198251168184511680821785525050505050509050018681526020018581526020018463ffffffff1663ffffffff1660e01b81526004018360ff1660ff1660f81b815260010182815260200199505050505050505050506040516020818303038152906040528051906020012090509998505050505050505050565b6109c66111f3565b610a38576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610adb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f46656465726174696f6e3a20456d707479206d656d626572000000000000000081525060200191505060405180910390fd5b600460008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610b7d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806121df6021913960400191505060405180910390fd5b600160028054905011610bdb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260288152602001806122526028913960400191505060405180910390fd5b6003546001600280549050031015610c3e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260318152602001806122216031913960400191505060405180910390fd5b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060008090505b600160028054905003811015610dbe578173ffffffffffffffffffffffffffffffffffffffff1660028281548110610cd057fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610db157600260016002805490500381548110610d2c57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660028281548110610d6457fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610dbe565b8080600101915050610c9c565b506001600281818054905003915081610dd7919061211e565b508073ffffffffffffffffffffffffffffffffffffffff167f270bfc616dd36d5cb6b35aac93e6ef22b089c34e6f6ad6f0892797424840897b60405160405180910390a250565b6000600560008381526020019081526020016000206000610e3d611fd2565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b60028181548110610e9957fe5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b603281565b610ed56111f3565b610f47576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6110376111f3565b6110a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561114c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f46656465726174696f6e3a20456d70747920627269646765000000000000000081525060200191505060405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f9775531310b2880b61484ed85cbb0b491c8fde3a07f289c63b9255178279449781604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16611235611fd2565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60056020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b6060600280548060200260200160405190810160405280929190818152602001828054801561130457602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116112ba575b5050505050905090565b6000806000905060008090505b6002805490508110156113d6576005600085815260200190815260200160002060006002838154811061134a57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156113c9576001820191505b808060010191505061131b565b5080915050919050565b60046020528060005260406000206000915054906101000a900460ff1681565b60006006600083815260200190815260200160002060009054906101000a900460ff169050919050565b6114326111f3565b6114a4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600280549050818181111580156114bc575060008114155b80156114c9575060008214155b61153b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f46656465726174696f6e3a20496e76616c696420726571756972656d656e747381525060200191505060405180910390fd5b60028310156115b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f46656465726174696f6e3a205265717569726573206174206c6561737420320081525060200191505060405180910390fd5b826003819055507fa3f1ee9126a074d9326c682f561767f710e927faa811f7a99829d49dc421797a836040518082815260200191505060405180910390a1505050565b60066020528060005260406000206000915054906101000a900460ff1681565b61161d6111f3565b61168f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611732576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f46656465726174696f6e3a20456d707479206d656d626572000000000000000081525060200191505060405180910390fd5b600460008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156117d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806122006021913960400191505060405180910390fd5b603260028054905010611850576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f46656465726174696f6e3a204d6178206d656d6265727320726561636865640081525060200191505060405180910390fd5b6001600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060028190806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508073ffffffffffffffffffffffffffffffffffffffff167f72114e270de66b9d2710ecf140403e5e99b1574767d6a8197bdc8d807a46e7c760405160405180910390a250565b600060046000611962611fd2565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff166119ff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806121706022913960400191505060405180910390fd5b6000611a568c8c8c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8b8b8b610885565b90506006600082815260200190815260200160002060009054906101000a900460ff1615611a88576001915050611f12565b600560008281526020019081526020016000206000611aa5611fd2565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611afc576001915050611f12565b6001600560008381526020019081526020016000206000611b1b611fd2565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508581611b76611fd2565b73ffffffffffffffffffffffffffffffffffffffff167f4237ab39e8496b350fbe760f4402abe992fc5d7e175824b087182422d347cf8a8f8f8f8f8f8f8e8e8e604051808a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001888152602001806020018681526020018563ffffffff1663ffffffff1681526020018460ff1660ff1681526020018381526020018281038252888882818152602001925080828437600081840152601f19601f8201169050808301925050509a505050505050505050505060405180910390a46000611c9c8261130e565b90506003548110158015611cc1575060016002808054905081611cbb57fe5b04018110155b15611f0b5760016006600084815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630e6ec7798f8f8f8f8f8f8f8f8f8f6040518b63ffffffff1660e01b8152600401808b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001898152602001806020018781526020018681526020018563ffffffff1663ffffffff1681526020018460ff1660ff1681526020018381526020018281038252898982818152602001925080828437600081840152601f19601f8201169050808301925050509b505050505050505050505050602060405180830381600087803b158015611e3f57600080fd5b505af1158015611e53573d6000803e3d6000fd5b505050506040513d6020811015611e6957600080fd5b8101908080519060200190929190505050905080611ed2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806121b86027913960400191505060405180910390fd5b827fa74c8847d513feba22a0f0cb38d53081abf97562cdb293926ba243689e7c41ca60405160405180910390a260019350505050611f12565b6001925050505b9a9950505050505050505050565b60035481565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b611f546111f3565b611fc6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b611fcf81611fda565b50565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612060576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806121926026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b81548183558181111561214557818360005260206000209182019101612144919061214a565b5b505050565b61216c91905b80821115612168576000816000905550600101612150565b5090565b9056fe46656465726174696f6e3a2043616c6c6572206e6f74206120466564657261746f724f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737346656465726174696f6e3a20427269646765206163636570745472616e73666572206572726f7246656465726174696f6e3a204d656d62657220646f65736e27742065786973747346656465726174696f6e3a204d656d62657220616c72656164792065786973747346656465726174696f6e3a2043616e27742068617665206c657373207468616e207265717569726564206d656d6265727346656465726174696f6e3a2043616e27742072656d6f766520616c6c20746865206d656d62657273a265627a7a72315820c37c2bee430146389ebe6dfe94ef99b727365e08cd30f8d05ad44d561f947ed564736f6c63430005110032