false
false
0
The new Blockscout UI is now open source! Learn how to deploy it here
- We're indexing this chain right now. Some of the counts may be inaccurate.

Contract Address Details

0x1363aa6d41719736AbF5F12EE850A01659B3Ea08

Contract Name
Controller
Creator
0x44a448–b88f4c at 0x436b9c–9df320
Balance
0 ETH
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
1660060
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
Controller




Optimization enabled
true
Compiler version
v0.8.13+commit.abaa5c0e




Optimization runs
999999
EVM Version
default




Verified at
2024-10-23T11:38:15.910430Z

Constructor Arguments

0x000000000000000000000000cb246b3719fa7f37ab2696ecdcbb7a9b5dd816da

Arg [0] (address) : 0xcb246b3719fa7f37ab2696ecdcbb7a9b5dd816da

              

contracts/bridge/Controller.sol

// SPDX-License-Identifier: GPL-3.0-only
// Sources flattened with hardhat v2.22.4 https://hardhat.org


// File contracts/common/Constants.sol

pragma solidity 0.8.13;

address constant ETH_ADDRESS = address(
    0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
);

bytes32 constant NORMAL_CONTROLLER = keccak256("NORMAL_CONTROLLER");
bytes32 constant FIAT_TOKEN_CONTROLLER = keccak256("FIAT_TOKEN_CONTROLLER");

bytes32 constant LIMIT_HOOK = keccak256("LIMIT_HOOK");
bytes32 constant LIMIT_EXECUTION_HOOK = keccak256("LIMIT_EXECUTION_HOOK");
bytes32 constant LIMIT_EXECUTION_YIELD_HOOK = keccak256(
    "LIMIT_EXECUTION_YIELD_HOOK"
);
bytes32 constant LIMIT_EXECUTION_YIELD_TOKEN_HOOK = keccak256(
    "LIMIT_EXECUTION_YIELD_TOKEN_HOOK"
);

bytes32 constant ERC20_VAULT = keccak256("ERC20_VAULT");
bytes32 constant NATIVE_VAULT = keccak256("NATIVE_VAULT");


// File contracts/common/Errors.sol

pragma solidity 0.8.13;

error SiblingNotSupported();
error NotAuthorized();
error NotBridge();
error NotSocket();
error ConnectorUnavailable();
error InvalidPoolId();
error CannotTransferOrExecuteOnBridgeContracts();
error NoPendingData();
error MessageIdMisMatched();
error NotMessageBridge();
error InvalidSiblingChainSlug();
error InvalidTokenContract();
error InvalidExchangeRateContract();
error InvalidConnector();
error InvalidConnectorPoolId();
error ZeroAddressReceiver();
error ZeroAddress();
error ZeroAmount();
error DebtRatioTooHigh();
error NotEnoughAssets();
error VaultShutdown();
error InsufficientFunds();
error PermitDeadlineExpired();
error InvalidSigner();
error InsufficientMsgValue();
error InvalidOptionsLength();


// File contracts/interfaces/IBridge.sol

pragma solidity ^0.8.3;

interface IBridge {
    function bridge(
        address receiver_,
        uint256 amount_,
        uint256 msgGasLimit_,
        address connector_,
        bytes calldata extraData_,
        bytes calldata options_
    ) external payable;

    function receiveInbound(
        uint32 siblingChainSlug_,
        bytes memory payload_
    ) external payable;

    function retry(address connector_, bytes32 messageId_) external;
}


// File contracts/interfaces/IConnector.sol

pragma solidity ^0.8.13;

interface IConnector {
    function outbound(
        uint256 msgGasLimit_,
        bytes memory payload_,
        bytes memory options_
    ) external payable returns (bytes32 messageId_);

    function siblingChainSlug() external view returns (uint32);

    function getMinFees(
        uint256 msgGasLimit_,
        uint256 payloadSize_
    ) external view returns (uint256 totalFees);

    function getMessageId() external view returns (bytes32);
}


// File contracts/common/Structs.sol

pragma solidity 0.8.13;

struct UpdateLimitParams {
    bool isMint;
    address connector;
    uint256 maxLimit;
    uint256 ratePerSecond;
}

struct SrcPreHookCallParams {
    address connector;
    address msgSender;
    TransferInfo transferInfo;
}

struct SrcPostHookCallParams {
    address connector;
    bytes options;
    bytes postHookData;
    TransferInfo transferInfo;
}

struct DstPreHookCallParams {
    address connector;
    bytes connectorCache;
    TransferInfo transferInfo;
}

struct DstPostHookCallParams {
    address connector;
    bytes32 messageId;
    bytes connectorCache;
    bytes postHookData;
    TransferInfo transferInfo;
}

struct PreRetryHookCallParams {
    address connector;
    CacheData cacheData;
}

struct PostRetryHookCallParams {
    address connector;
    bytes32 messageId;
    bytes postHookData;
    CacheData cacheData;
}

struct TransferInfo {
    address receiver;
    uint256 amount;
    bytes extraData;
}

struct CacheData {
    bytes identifierCache;
    bytes connectorCache;
}

struct LimitParams {
    uint256 lastUpdateTimestamp;
    uint256 ratePerSecond;
    uint256 maxLimit;
    uint256 lastUpdateLimit;
}


// File contracts/interfaces/IHook.sol

pragma solidity ^0.8.3;

interface IHook {
    /**
     * @notice Executes pre-hook call for source underlyingAsset.
     * @dev This function is used to execute a pre-hook call for the source underlyingAsset before initiating a transfer.
     * @param params_ Parameters for the pre-hook call.
     * @return transferInfo Information about the transfer.
     * @return postHookData returned from the pre-hook call.
     */
    function srcPreHookCall(
        SrcPreHookCallParams calldata params_
    )
        external
        returns (TransferInfo memory transferInfo, bytes memory postHookData);

    function srcPostHookCall(
        SrcPostHookCallParams calldata params_
    ) external returns (TransferInfo memory transferInfo);

    /**
     * @notice Executes pre-hook call for destination underlyingAsset.
     * @dev This function is used to execute a pre-hook call for the destination underlyingAsset before initiating a transfer.
     * @param params_ Parameters for the pre-hook call.
     */
    function dstPreHookCall(
        DstPreHookCallParams calldata params_
    )
        external
        returns (bytes memory postHookData, TransferInfo memory transferInfo);

    /**
     * @notice Executes post-hook call for destination underlyingAsset.
     * @dev This function is used to execute a post-hook call for the destination underlyingAsset after completing a transfer.
     * @param params_ Parameters for the post-hook call.
     * @return cacheData Cached data for the post-hook call.
     */
    function dstPostHookCall(
        DstPostHookCallParams calldata params_
    ) external returns (CacheData memory cacheData);

    /**
     * @notice Executes a pre-retry hook for a failed transaction.
     * @dev This function is used to execute a pre-retry hook for a failed transaction.
     * @param params_ Parameters for the pre-retry hook.
     * @return postHookData Data from the post-retry hook.
     * @return transferInfo Information about the transfer.
     */
    function preRetryHook(
        PreRetryHookCallParams calldata params_
    )
        external
        returns (bytes memory postHookData, TransferInfo memory transferInfo);

    /**
     * @notice Executes a post-retry hook for a failed transaction.
     * @dev This function is used to execute a post-retry hook for a failed transaction.
     * @param params_ Parameters for the post-retry hook.
     * @return cacheData Cached data for the post-retry hook.
     */
    function postRetryHook(
        PostRetryHookCallParams calldata params_
    ) external returns (CacheData memory cacheData);
}


// File contracts/interfaces/IMintableERC20.sol

pragma solidity 0.8.13;

interface IMintableERC20 {
    function mint(address receiver_, uint256 amount_) external;

    function burn(address burner_, uint256 amount_) external;
}


// File lib/solmate/src/tokens/ERC20.sol

pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}


// File lib/solmate/src/utils/SafeTransferLib.sol

pragma solidity >=0.8.0;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}


// File contracts/libraries/RescueFundsLib.sol

pragma solidity 0.8.13;




/**
 * @title RescueFundsLib
 * @dev A library that provides a function to rescue funds from a contract.
 */

library RescueFundsLib {
    /**
     * @dev thrown when the given token address don't have any code
     */
    error InvalidTokenAddress();

    /**
     * @dev Rescues funds from a contract.
     * @param token_ The address of the token contract.
     * @param rescueTo_ The address of the user.
     * @param amount_ The amount of tokens to be rescued.
     */
    function rescueFunds(
        address token_,
        address rescueTo_,
        uint256 amount_
    ) internal {
        if (rescueTo_ == address(0)) revert ZeroAddress();

        if (token_ == ETH_ADDRESS) {
            SafeTransferLib.safeTransferETH(rescueTo_, amount_);
        } else {
            if (token_.code.length == 0) revert InvalidTokenAddress();
            SafeTransferLib.safeTransfer(ERC20(token_), rescueTo_, amount_);
        }
    }
}


// File contracts/utils/Ownable.sol

pragma solidity 0.8.13;

/**
 * @title Ownable
 * @dev The Ownable contract provides a simple way to manage ownership of a contract
 * and allows for ownership to be transferred to a nominated address.
 */
abstract contract Ownable {
    address private _owner;
    address private _nominee;

    event OwnerNominated(address indexed nominee);
    event OwnerClaimed(address indexed claimer);

    error OnlyOwner();
    error OnlyNominee();

    /**
     * @dev Sets the contract's owner to the address that is passed to the constructor.
     */
    constructor(address owner_) {
        _claimOwner(owner_);
    }

    /**
     * @dev Modifier that restricts access to only the contract's owner.
     * Throws an error if the caller is not the owner.
     */
    modifier onlyOwner() {
        if (msg.sender != _owner) revert OnlyOwner();
        _;
    }

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

    /**
     * @dev Returns the current nominee for ownership of the contract.
     */
    function nominee() external view returns (address) {
        return _nominee;
    }

    /**
     * @dev Allows the current owner to nominate a new owner for the contract.
     * Throws an error if the caller is not the owner.
     * Emits an `OwnerNominated` event with the address of the nominee.
     */
    function nominateOwner(address nominee_) external {
        if (msg.sender != _owner) revert OnlyOwner();
        _nominee = nominee_;
        emit OwnerNominated(_nominee);
    }

    /**
     * @dev Allows the nominated owner to claim ownership of the contract.
     * Throws an error if the caller is not the nominee.
     * Sets the nominated owner as the new owner of the contract.
     * Emits an `OwnerClaimed` event with the address of the new owner.
     */
    function claimOwner() external {
        if (msg.sender != _nominee) revert OnlyNominee();
        _claimOwner(msg.sender);
    }

    /**
     * @dev Internal function that sets the owner of the contract to the specified address
     * and sets the nominee to address(0).
     */
    function _claimOwner(address claimer_) internal {
        _owner = claimer_;
        _nominee = address(0);
        emit OwnerClaimed(claimer_);
    }
}


// File contracts/utils/AccessControl.sol

pragma solidity 0.8.13;

/**
 * @title AccessControl
 * @dev This abstract contract implements access control mechanism based on roles.
 * Each role can have one or more addresses associated with it, which are granted
 * permission to execute functions with the onlyRole modifier.
 */
abstract contract AccessControl is Ownable {
    /**
     * @dev A mapping of roles to a mapping of addresses to boolean values indicating whether or not they have the role.
     */
    mapping(bytes32 => mapping(address => bool)) private _permits;

    /**
     * @dev Emitted when a role is granted to an address.
     */
    event RoleGranted(bytes32 indexed role, address indexed grantee);

    /**
     * @dev Emitted when a role is revoked from an address.
     */
    event RoleRevoked(bytes32 indexed role, address indexed revokee);

    /**
     * @dev Error message thrown when an address does not have permission to execute a function with onlyRole modifier.
     */
    error NoPermit(bytes32 role);

    /**
     * @dev Constructor that sets the owner of the contract.
     */
    constructor(address owner_) Ownable(owner_) {}

    /**
     * @dev Modifier that restricts access to addresses having roles
     * Throws an error if the caller do not have permit
     */
    modifier onlyRole(bytes32 role) {
        if (!_permits[role][msg.sender]) revert NoPermit(role);
        _;
    }

    /**
     * @dev Checks and reverts if an address do not have a specific role.
     * @param role_ The role to check.
     * @param address_ The address to check.
     */
    function _checkRole(bytes32 role_, address address_) internal virtual {
        if (!_hasRole(role_, address_)) revert NoPermit(role_);
    }

    /**
     * @dev Grants a role to a given address.
     * @param role_ The role to grant.
     * @param grantee_ The address to grant the role to.
     * Emits a RoleGranted event.
     * Can only be called by the owner of the contract.
     */
    function grantRole(
        bytes32 role_,
        address grantee_
    ) external virtual onlyOwner {
        _grantRole(role_, grantee_);
    }

    /**
     * @dev Revokes a role from a given address.
     * @param role_ The role to revoke.
     * @param revokee_ The address to revoke the role from.
     * Emits a RoleRevoked event.
     * Can only be called by the owner of the contract.
     */
    function revokeRole(
        bytes32 role_,
        address revokee_
    ) external virtual onlyOwner {
        _revokeRole(role_, revokee_);
    }

    /**
     * @dev Internal function to grant a role to a given address.
     * @param role_ The role to grant.
     * @param grantee_ The address to grant the role to.
     * Emits a RoleGranted event.
     */
    function _grantRole(bytes32 role_, address grantee_) internal {
        _permits[role_][grantee_] = true;
        emit RoleGranted(role_, grantee_);
    }

    /**
     * @dev Internal function to revoke a role from a given address.
     * @param role_ The role to revoke.
     * @param revokee_ The address to revoke the role from.
     * Emits a RoleRevoked event.
     */
    function _revokeRole(bytes32 role_, address revokee_) internal {
        _permits[role_][revokee_] = false;
        emit RoleRevoked(role_, revokee_);
    }

    /**
     * @dev Checks whether an address has a specific role.
     * @param role_ The role to check.
     * @param address_ The address to check.
     * @return A boolean value indicating whether or not the address has the role.
     */
    function hasRole(
        bytes32 role_,
        address address_
    ) external view returns (bool) {
        return _hasRole(role_, address_);
    }

    function _hasRole(
        bytes32 role_,
        address address_
    ) internal view returns (bool) {
        return _permits[role_][address_];
    }
}


// File contracts/utils/RescueBase.sol

pragma solidity 0.8.13;


/**
 * @title Base contract for super token and vault
 * @notice It contains relevant execution payload storages.
 * @dev This contract implements Socket's IPlug to enable message bridging and IMessageBridge
 * to support any type of message bridge.
 */
abstract contract RescueBase is AccessControl {
    bytes32 constant RESCUE_ROLE = keccak256("RESCUE_ROLE");

    /**
     * @notice Rescues funds from the contract if they are locked by mistake.
     * @param token_ The address of the token contract.
     * @param rescueTo_ The address where rescued tokens need to be sent.
     * @param amount_ The amount of tokens to be rescued.
     */
    function rescueFunds(
        address token_,
        address rescueTo_,
        uint256 amount_
    ) external onlyRole(RESCUE_ROLE) {
        RescueFundsLib.rescueFunds(token_, rescueTo_, amount_);
    }
}


// File lib/solmate/src/utils/ReentrancyGuard.sol

pragma solidity >=0.8.0;

/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
    uint256 private locked = 1;

    modifier nonReentrant() virtual {
        require(locked == 1, "REENTRANCY");

        locked = 2;

        _;

        locked = 1;
    }
}


// File contracts/bridge/Base.sol

pragma solidity 0.8.13;









abstract contract Base is ReentrancyGuard, IBridge, RescueBase {
    address public immutable token;
    bytes32 public bridgeType;
    IHook public hook__;
    // message identifier => cache
    mapping(bytes32 => bytes) public identifierCache;

    // connector => cache
    mapping(address => bytes) public connectorCache;

    mapping(address => bool) public validConnectors;

    event ConnectorStatusUpdated(address connector, bool status);

    event HookUpdated(address newHook);

    event BridgingTokens(
        address connector,
        address sender,
        address receiver,
        uint256 amount,
        bytes32 messageId
    );
    event TokensBridged(
        address connecter,
        address receiver,
        uint256 amount,
        bytes32 messageId
    );

    constructor(address token_) AccessControl(msg.sender) {
        if (token_ != ETH_ADDRESS && token_.code.length == 0)
            revert InvalidTokenContract();
        token = token_;
        _grantRole(RESCUE_ROLE, msg.sender);
    }

    /**
     * @notice this function is used to update hook
     * @dev it can only be updated by owner
     * @dev should be carefully migrated as it can risk user funds
     * @param hook_ new hook address
     */
    function updateHook(
        address hook_,
        bool approve_
    ) external virtual onlyOwner {
        // remove the approval from the old hook
        if (token != ETH_ADDRESS) {
            if (ERC20(token).allowance(address(this), address(hook__)) > 0) {
                SafeTransferLib.safeApprove(ERC20(token), address(hook__), 0);
            }
            if (approve_) {
                SafeTransferLib.safeApprove(
                    ERC20(token),
                    hook_,
                    type(uint256).max
                );
            }
        }
        hook__ = IHook(hook_);

        emit HookUpdated(hook_);
    }

    function updateConnectorStatus(
        address[] calldata connectors,
        bool[] calldata statuses
    ) external onlyOwner {
        uint256 length = connectors.length;
        for (uint256 i; i < length; i++) {
            validConnectors[connectors[i]] = statuses[i];
            emit ConnectorStatusUpdated(connectors[i], statuses[i]);
        }
    }

    /**
     * @notice Executes pre-bridge operations before initiating a token bridge transfer.
     * @dev This internal function is called before initiating a token bridge transfer.
     * It validates the receiver address and the connector, and if a pre-hook contract is defined,
     * it executes the source pre-hook call.
     * @param connector_ The address of the connector responsible for the transfer.
     * @param transferInfo_ Information about the transfer.
     * @return transferInfo Information about the transfer after pre-bridge operations.
     * @return postHookData Data returned from the pre-hook call.
     * @dev Reverts with `ZeroAddressReceiver` if the receiver address is zero.
     * Reverts with `InvalidConnector` if the connector address is not valid.
     */
    function _beforeBridge(
        address connector_,
        TransferInfo memory transferInfo_
    )
        internal
        returns (TransferInfo memory transferInfo, bytes memory postHookData)
    {
        if (transferInfo_.receiver == address(0)) revert ZeroAddressReceiver();
        if (!validConnectors[connector_]) revert InvalidConnector();
        if (token == ETH_ADDRESS && msg.value < transferInfo_.amount)
            revert InsufficientMsgValue();

        if (address(hook__) != address(0)) {
            (transferInfo, postHookData) = hook__.srcPreHookCall(
                SrcPreHookCallParams(connector_, msg.sender, transferInfo_)
            );
        } else {
            transferInfo = transferInfo_;
        }
    }

    /**
     * @notice Executes post-bridge operations after completing a token bridge transfer.
     * @dev This internal function is called after completing a token bridge transfer.
     * It executes the source post-hook call if a hook contract is defined, calculates fees,
     * calls the outbound function of the connector, and emits an event for tokens withdrawn.
     * @param msgGasLimit_ The gas limit for the outbound call.
     * @param connector_ The address of the connector responsible for the transfer.
     * @param options_ Additional options for the outbound call.
     * @param postHookData_ Data returned from the source post-hook call.
     * @param transferInfo_ Information about the transfer.
     * @dev Reverts with `MessageIdMisMatched` if the returned message ID does not match the expected message ID.
     */
    function _afterBridge(
        uint256 msgGasLimit_,
        address connector_,
        bytes memory options_,
        bytes memory postHookData_,
        TransferInfo memory transferInfo_
    ) internal {
        TransferInfo memory transferInfo = transferInfo_;
        if (address(hook__) != address(0)) {
            transferInfo = hook__.srcPostHookCall(
                SrcPostHookCallParams(
                    connector_,
                    options_,
                    postHookData_,
                    transferInfo_
                )
            );
        }

        uint256 fees = token == ETH_ADDRESS
            ? msg.value - transferInfo.amount
            : msg.value;

        bytes32 messageId = IConnector(connector_).getMessageId();
        bytes32 returnedMessageId = IConnector(connector_).outbound{
            value: fees
        }(
            msgGasLimit_,
            abi.encode(
                transferInfo.receiver,
                transferInfo.amount,
                messageId,
                transferInfo.extraData
            ),
            options_
        );
        if (returnedMessageId != messageId) revert MessageIdMisMatched();

        emit BridgingTokens(
            connector_,
            msg.sender,
            transferInfo.receiver,
            transferInfo.amount,
            messageId
        );
    }

    /**
     * @notice Executes pre-mint operations before minting tokens.
     * @dev This internal function is called before minting tokens.
     * It validates the caller as a valid connector, checks if the receiver is not this contract, the bridge contract,
     * or the token contract, and executes the destination pre-hook call if a hook contract is defined.
     * @param transferInfo_ Information about the transfer.
     * @return postHookData Data returned from the destination pre-hook call.
     * @return transferInfo Information about the transfer after pre-mint operations.
     * @dev Reverts with `InvalidConnector` if the caller is not a valid connector.
     * Reverts with `CannotTransferOrExecuteOnBridgeContracts` if the receiver is this contract, the bridge contract,
     * or the token contract.
     */
    function _beforeMint(
        uint32,
        TransferInfo memory transferInfo_
    )
        internal
        returns (bytes memory postHookData, TransferInfo memory transferInfo)
    {
        if (!validConnectors[msg.sender]) revert InvalidConnector();

        // no need of source check here, as if invalid caller, will revert with InvalidPoolId
        if (
            transferInfo_.receiver == address(this) ||
            // transferInfo_.receiver == address(bridge__) ||
            transferInfo_.receiver == token
        ) revert CannotTransferOrExecuteOnBridgeContracts();

        if (address(hook__) != address(0)) {
            (postHookData, transferInfo) = hook__.dstPreHookCall(
                DstPreHookCallParams(
                    msg.sender,
                    connectorCache[msg.sender],
                    transferInfo_
                )
            );
        } else {
            transferInfo = transferInfo_;
        }
    }

    /**
     * @notice Executes post-mint operations after minting tokens.
     * @dev This internal function is called after minting tokens.
     * It executes the destination post-hook call if a hook contract is defined and updates cache data.
     * @param messageId_ The unique identifier for the mint transaction.
     * @param postHookData_ Data returned from the destination pre-hook call.
     * @param transferInfo_ Information about the mint transaction.
     */
    function _afterMint(
        uint256,
        bytes32 messageId_,
        bytes memory postHookData_,
        TransferInfo memory transferInfo_
    ) internal {
        if (address(hook__) != address(0)) {
            CacheData memory cacheData = hook__.dstPostHookCall(
                DstPostHookCallParams(
                    msg.sender,
                    messageId_,
                    connectorCache[msg.sender],
                    postHookData_,
                    transferInfo_
                )
            );

            identifierCache[messageId_] = cacheData.identifierCache;
            connectorCache[msg.sender] = cacheData.connectorCache;
        }

        emit TokensBridged(
            msg.sender,
            transferInfo_.receiver,
            transferInfo_.amount,
            messageId_
        );
    }

    /**
     * @notice Executes pre-retry operations before retrying a failed transaction.
     * @dev This internal function is called before retrying a failed transaction.
     * It validates the connector, retrieves cache data for the given message ID,
     * and executes the pre-retry hook if defined.
     * @param connector_ The address of the connector responsible for the failed transaction.
     * @param messageId_ The unique identifier for the failed transaction.
     * @return postHookData Data returned from the pre-retry hook call.
     * @return transferInfo Information about the transfer.
     * @dev Reverts with `InvalidConnector` if the connector is not valid.
     * Reverts with `NoPendingData` if there is no pending data for the given message ID.
     */
    function _beforeRetry(
        address connector_,
        bytes32 messageId_
    )
        internal
        returns (bytes memory postHookData, TransferInfo memory transferInfo)
    {
        if (!validConnectors[connector_]) revert InvalidConnector();

        CacheData memory cacheData = CacheData(
            identifierCache[messageId_],
            connectorCache[connector_]
        );

        if (cacheData.identifierCache.length == 0) revert NoPendingData();
        (postHookData, transferInfo) = hook__.preRetryHook(
            PreRetryHookCallParams(connector_, cacheData)
        );
    }

    /**
     * @notice Executes post-retry operations after retrying a failed transaction.
     * @dev This internal function is called after retrying a failed transaction.
     * It retrieves cache data for the given message ID, executes the post-retry hook if defined,
     * and updates cache data.
     * @param connector_ The address of the connector responsible for the failed transaction.
     * @param messageId_ The unique identifier for the failed transaction.
     * @param postHookData Data returned from the pre-retry hook call.
     */
    function _afterRetry(
        address connector_,
        bytes32 messageId_,
        bytes memory postHookData
    ) internal {
        CacheData memory cacheData = CacheData(
            identifierCache[messageId_],
            connectorCache[connector_]
        );

        (cacheData) = hook__.postRetryHook(
            PostRetryHookCallParams(
                connector_,
                messageId_,
                postHookData,
                cacheData
            )
        );
        identifierCache[messageId_] = cacheData.identifierCache;
        connectorCache[connector_] = cacheData.connectorCache;
    }

    /**
     * @notice Retrieves the minimum fees required for a transaction from a connector.
     * @dev This function returns the minimum fees required for a transaction from the specified connector,
     * based on the provided message gas limit and payload size.
     * @param connector_ The address of the connector.
     * @param msgGasLimit_ The gas limit for the transaction.
     * @param payloadSize_ The size of the payload for the transaction.
     * @return totalFees The total minimum fees required for the transaction.
     */
    function getMinFees(
        address connector_,
        uint256 msgGasLimit_,
        uint256 payloadSize_
    ) external view returns (uint256 totalFees) {
        return IConnector(connector_).getMinFees(msgGasLimit_, payloadSize_);
    }
}


// File contracts/bridge/Controller.sol

pragma solidity 0.8.13;

contract Controller is Base {
    uint256 public totalMinted;

    constructor(address token_) Base(token_) {
        bridgeType = NORMAL_CONTROLLER;
    }

    /**
     * @notice Bridges tokens between chains.
     * @dev This function allows bridging tokens between different chains.
     * @param receiver_ The address to receive the bridged tokens.
     * @param amount_ The amount of tokens to bridge.
     * @param msgGasLimit_ The gas limit for the execution of the bridging process.
     * @param connector_ The address of the connector contract responsible for the bridge.
     * @param extraData_ The extra data passed to hook functions.
     * @param options_ Additional options for the bridging process.
     */
    function bridge(
        address receiver_,
        uint256 amount_,
        uint256 msgGasLimit_,
        address connector_,
        bytes calldata extraData_,
        bytes calldata options_
    ) external payable nonReentrant {
        (
            TransferInfo memory transferInfo,
            bytes memory postHookData
        ) = _beforeBridge(
                connector_,
                TransferInfo(receiver_, amount_, extraData_)
            );

        // to maintain socket dl specific accounting for super token
        // re check this logic for mint and mint use cases and if other minter involved
        totalMinted -= transferInfo.amount;
        _burn(msg.sender, transferInfo.amount);
        _afterBridge(
            msgGasLimit_,
            connector_,
            options_,
            postHookData,
            transferInfo
        );
    }

    /**
     * @notice Receives inbound tokens from another chain.
     * @dev This function is used to receive tokens from another chain.
     * @param siblingChainSlug_ The identifier of the sibling chain.
     * @param payload_ The payload containing the inbound tokens.
     */
    function receiveInbound(
        uint32 siblingChainSlug_,
        bytes memory payload_
    ) external payable override nonReentrant {
        (
            address receiver,
            uint256 lockAmount,
            bytes32 messageId,
            bytes memory extraData
        ) = abi.decode(payload_, (address, uint256, bytes32, bytes));

        // convert to shares
        TransferInfo memory transferInfo = TransferInfo(
            receiver,
            lockAmount,
            extraData
        );
        bytes memory postHookData;
        (postHookData, transferInfo) = _beforeMint(
            siblingChainSlug_,
            transferInfo
        );

        _mint(transferInfo.receiver, transferInfo.amount);
        totalMinted += transferInfo.amount;

        _afterMint(lockAmount, messageId, postHookData, transferInfo);
    }

    /**
     * @notice Retry a failed transaction.
     * @dev This function allows retrying a failed transaction sent through a connector.
     * @param connector_ The address of the connector contract responsible for the failed transaction.
     * @param messageId_ The unique identifier of the failed transaction.
     */
    function retry(
        address connector_,
        bytes32 messageId_
    ) external nonReentrant {
        (
            bytes memory postHookData,
            TransferInfo memory transferInfo
        ) = _beforeRetry(connector_, messageId_);
        _mint(transferInfo.receiver, transferInfo.amount);
        totalMinted += transferInfo.amount;

        _afterRetry(connector_, messageId_, postHookData);
    }

    function _burn(address user_, uint256 burnAmount_) internal virtual {
        IMintableERC20(token).burn(user_, burnAmount_);
    }

    function _mint(address user_, uint256 mintAmount_) internal virtual {
        if (mintAmount_ == 0) return;
        IMintableERC20(token).mint(user_, mintAmount_);
    }
}
        

Compiler Settings

{"outputSelection":{"*":{"*":["*"]}},"optimizer":{"runs":999999,"enabled":true},"libraries":{}}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"token_","internalType":"address"}]},{"type":"error","name":"CannotTransferOrExecuteOnBridgeContracts","inputs":[]},{"type":"error","name":"InsufficientMsgValue","inputs":[]},{"type":"error","name":"InvalidConnector","inputs":[]},{"type":"error","name":"InvalidTokenAddress","inputs":[]},{"type":"error","name":"InvalidTokenContract","inputs":[]},{"type":"error","name":"MessageIdMisMatched","inputs":[]},{"type":"error","name":"NoPendingData","inputs":[]},{"type":"error","name":"NoPermit","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"error","name":"OnlyNominee","inputs":[]},{"type":"error","name":"OnlyOwner","inputs":[]},{"type":"error","name":"ZeroAddress","inputs":[]},{"type":"error","name":"ZeroAddressReceiver","inputs":[]},{"type":"event","name":"BridgingTokens","inputs":[{"type":"address","name":"connector","internalType":"address","indexed":false},{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"address","name":"receiver","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"bytes32","name":"messageId","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"ConnectorStatusUpdated","inputs":[{"type":"address","name":"connector","internalType":"address","indexed":false},{"type":"bool","name":"status","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"HookUpdated","inputs":[{"type":"address","name":"newHook","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"OwnerClaimed","inputs":[{"type":"address","name":"claimer","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnerNominated","inputs":[{"type":"address","name":"nominee","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"grantee","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"revokee","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"TokensBridged","inputs":[{"type":"address","name":"connecter","internalType":"address","indexed":false},{"type":"address","name":"receiver","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"bytes32","name":"messageId","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"payable","outputs":[],"name":"bridge","inputs":[{"type":"address","name":"receiver_","internalType":"address"},{"type":"uint256","name":"amount_","internalType":"uint256"},{"type":"uint256","name":"msgGasLimit_","internalType":"uint256"},{"type":"address","name":"connector_","internalType":"address"},{"type":"bytes","name":"extraData_","internalType":"bytes"},{"type":"bytes","name":"options_","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"bridgeType","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimOwner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"connectorCache","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"totalFees","internalType":"uint256"}],"name":"getMinFees","inputs":[{"type":"address","name":"connector_","internalType":"address"},{"type":"uint256","name":"msgGasLimit_","internalType":"uint256"},{"type":"uint256","name":"payloadSize_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role_","internalType":"bytes32"},{"type":"address","name":"grantee_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role_","internalType":"bytes32"},{"type":"address","name":"address_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IHook"}],"name":"hook__","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"identifierCache","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"nominateOwner","inputs":[{"type":"address","name":"nominee_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"nominee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"receiveInbound","inputs":[{"type":"uint32","name":"siblingChainSlug_","internalType":"uint32"},{"type":"bytes","name":"payload_","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescueFunds","inputs":[{"type":"address","name":"token_","internalType":"address"},{"type":"address","name":"rescueTo_","internalType":"address"},{"type":"uint256","name":"amount_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"retry","inputs":[{"type":"address","name":"connector_","internalType":"address"},{"type":"bytes32","name":"messageId_","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role_","internalType":"bytes32"},{"type":"address","name":"revokee_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"token","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalMinted","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateConnectorStatus","inputs":[{"type":"address[]","name":"connectors","internalType":"address[]"},{"type":"bool[]","name":"statuses","internalType":"bool[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateHook","inputs":[{"type":"address","name":"hook_","internalType":"address"},{"type":"bool","name":"approve_","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"validConnectors","inputs":[{"type":"address","name":"","internalType":"address"}]}]
              

Contract Creation Code

Verify & Publish
0x60a060405260016000553480156200001657600080fd5b506040516200359d3803806200359d8339810160408190526200003991620001b2565b803380620000478162000103565b50506001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015906200007f57506001600160a01b0381163b155b156200009e57604051630a6f7ecd60e21b815260040160405180910390fd5b6001600160a01b038116608052620000d77fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292533362000157565b50507ff429e6a62fa0281dc1be2d92b346977a47bde9521f323f08f996b64bdbabd5f3600455620001e4565b600180546001600160a01b0383166001600160a01b031991821681179092556002805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b60008281526003602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b600060208284031215620001c557600080fd5b81516001600160a01b0381168114620001dd57600080fd5b9392505050565b60805161335e6200023f6000396000818161042e01528181610b0b01528181610bab01528181610c2501528181610c6d015281816111c9015281816113ae0152818161150b015281816118c70152611b23015261335e6000f3fe60806040526004361061016a5760003560e01c80638da5cb5b116100cb578063d547741f1161007f578063f290aafa11610059578063f290aafa146103fc578063fc0c546a1461041c578063fc3a7b981461045057600080fd5b8063d547741f1461038c578063e272ad3f146103ac578063e9ee1eaf146103cc57600080fd5b80639dc7b023116100b05780639dc7b02314610336578063a2309ff814610356578063aad48d801461036c57600080fd5b80638da5cb5b146102db57806391d148541461030657600080fd5b80634b0a8854116101225780636ccae054116101075780636ccae0541461027b57806370bab2c01461029b578063873ea755146102c857600080fd5b80634b0a88541461022e5780635b94db271461025b57600080fd5b80632f2ff15d116101535780632f2ff15d146101e45780633bd1adec14610206578063405e720a1461021b57600080fd5b806320f99c0a1461016f5780632421e155146101c0575b600080fd5b34801561017b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101cc57600080fd5b506101d660045481565b6040519081526020016101b7565b3480156101f057600080fd5b506102046101ff3660046126a5565b610470565b005b34801561021257600080fd5b506102046104cf565b610204610229366004612717565b61052b565b34801561023a57600080fd5b5061024e6102493660046127bf565b61069a565b6040516101b79190612852565b34801561026757600080fd5b506102046102763660046127bf565b610734565b34801561028757600080fd5b50610204610296366004612865565b6107f4565b3480156102a757600080fd5b506005546101969073ffffffffffffffffffffffffffffffffffffffff1681565b6102046102d636600461296a565b610892565b3480156102e757600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610196565b34801561031257600080fd5b506103266103213660046126a5565b6109b7565b60405190151581526020016101b7565b34801561034257600080fd5b50610204610351366004612a06565b6109f2565b34801561036257600080fd5b506101d660095481565b34801561037857600080fd5b50610204610387366004612a47565b610ab8565b34801561039857600080fd5b506102046103a73660046126a5565b610d2d565b3480156103b857600080fd5b506102046103c7366004612ac1565b610d88565b3480156103d857600080fd5b506103266103e73660046127bf565b60086020526000908152604090205460ff1681565b34801561040857600080fd5b5061024e610417366004612b2d565b610f42565b34801561042857600080fd5b506101967f000000000000000000000000000000000000000000000000000000000000000081565b34801561045c57600080fd5b506101d661046b366004612b46565b610f5b565b60015473ffffffffffffffffffffffffffffffffffffffff1633146104c1576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104cb8282610ffc565b5050565b60025473ffffffffffffffffffffffffffffffffffffffff163314610520576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61052933611082565b565b60005460011461059c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e43590000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b60026000819055506000806106158760405180606001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c815260200189898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506110fb565b9150915081602001516009600082825461062f9190612baa565b92505081905550610644338360200151611362565b610689888886868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508792508891506114079050565b505060016000555050505050505050565b600760205260009081526040902080546106b390612bc1565b80601f01602080910402602001604051908101604052809291908181526020018280546106df90612bc1565b801561072c5780601f106107015761010080835404028352916020019161072c565b820191906000526020600020905b81548152906001019060200180831161070f57829003601f168201915b505050505081565b60015473ffffffffffffffffffffffffffffffffffffffff163314610785576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b3360009081527f271b3e2292ab6fd3ff496cd98d6d375af02f11568a701741f48bba7789f13a7060205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff16610881576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610593565b61088c84848461174c565b50505050565b6000546001146108fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152606401610593565b6002600081905550600080600080848060200190518101906109209190612c59565b9350935093509350600060405180606001604052808673ffffffffffffffffffffffffffffffffffffffff16815260200185815260200183815250905060606109698883611841565b805160208201519194509192506109809190611acb565b8160200151600960008282546109969190612cbe565b909155506109a8905085858385611b52565b50506001600055505050505050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b600054600114610a5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152606401610593565b6002600090815580610a708484611d8e565b91509150610a8681600001518260200151611acb565b806020015160096000828254610a9c9190612cbe565b90915550610aad9050848484612096565b505060016000555050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b09576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610cb3576005546040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff91821660248201526000917f0000000000000000000000000000000000000000000000000000000000000000169063dd62ed3e90604401602060405180830381865afa158015610bf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c169190612cd6565b1115610c6257600554610c62907f00000000000000000000000000000000000000000000000000000000000000009073ffffffffffffffffffffffffffffffffffffffff166000612351565b8015610cb357610cb37f0000000000000000000000000000000000000000000000000000000000000000837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612351565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fe816c20840d998c8612f9b624b91687a80510eeb293cb09f7637379f6d73342d9060200160405180910390a15050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610d7e576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104cb8282612420565b60015473ffffffffffffffffffffffffffffffffffffffff163314610dd9576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260005b81811015610f3a57838382818110610df757610df7612cef565b9050602002016020810190610e0c9190612d1e565b60086000888885818110610e2257610e22612cef565b9050602002016020810190610e3791906127bf565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790557f857309f1a328784e9fc9749624be5d32fd8e7afab58e7fe9a218dd613a37f15c868683818110610ebd57610ebd612cef565b9050602002016020810190610ed291906127bf565b858584818110610ee457610ee4612cef565b9050602002016020810190610ef99190612d1e565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835290151560208301520160405180910390a180610f3281612d39565b915050610ddd565b505050505050565b600660205260009081526040902080546106b390612bc1565b6040517f666758ca000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260009073ffffffffffffffffffffffffffffffffffffffff85169063666758ca90604401602060405180830381865afa158015610fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff49190612cd6565b949350505050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092556002805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b60408051606080820183526000808352602083015291810191909152815160609073ffffffffffffffffffffffffffffffffffffffff16611168576040517f96bbcf1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff841660009081526008602052604090205460ff166111c7576040517f5b0a758300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480156112235750826020015134105b1561125a576040517f78f38f7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff1615611357576005546040805160608101825273ffffffffffffffffffffffffffffffffffffffff878116825233602083015281830187905291517ff59ad990000000000000000000000000000000000000000000000000000000008152919092169163f59ad990916112e89190600401612db0565b6000604051808303816000875af1158015611307573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261134d9190810190612e7e565b909250905061135b565b8291505b9250929050565b6040517f9dc29fac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f00000000000000000000000000000000000000000000000000000000000000001690639dc29fac906044015b600060405180830381600087803b1580156113f357600080fd5b505af1158015610f3a573d6000803e3d6000fd5b600554819073ffffffffffffffffffffffffffffffffffffffff1615611507576005546040805160808101825273ffffffffffffffffffffffffffffffffffffffff8881168252602082018890528183018790526060820186905291517f62811bf200000000000000000000000000000000000000000000000000000000815291909216916362811bf29161149f9190600401612ee2565b6000604051808303816000875af11580156114be573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115049190810190612f81565b90505b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611560573461156f565b602082015161156f9034612baa565b905060008673ffffffffffffffffffffffffffffffffffffffff166374fa24a66040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e29190612cd6565b905060008773ffffffffffffffffffffffffffffffffffffffff1663ac0710cb848b87600001518860200151878a604001516040516020016116279493929190612fb6565b6040516020818303038152906040528b6040518563ffffffff1660e01b815260040161165593929190612ffb565b60206040518083038185885af1158015611673573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906116989190612cd6565b90508181146116d3576040517f7b7bbbe000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83516020808601516040805173ffffffffffffffffffffffffffffffffffffffff8d811682523394820194909452929093168284015260608201526080810184905290517fc74a00177d2c63e6eead5ea7936974ad9d0121f86140723b8909f8ec9662cc619181900360a00190a1505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8216611799576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016117e5576117e082826124a3565b505050565b8273ffffffffffffffffffffffffffffffffffffffff163b600003611836576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117e0838383612518565b6040805160608181018352600080835260208301529181018290523360009081526008602052604090205460ff166118a5576040517f5b0a758300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825173ffffffffffffffffffffffffffffffffffffffff1630148061191957507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16145b15611950576040517f285c601600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff1615611ac4576005546040805160608101825233808252600090815260076020908152929020805473ffffffffffffffffffffffffffffffffffffffff9094169363cf36b91793830191906119bc90612bc1565b80601f01602080910402602001604051908101604052809291908181526020018280546119e890612bc1565b8015611a355780601f10611a0a57610100808354040283529160200191611a35565b820191906000526020600020905b815481529060010190602001808311611a1857829003601f168201915b50505050508152602001868152506040518263ffffffff1660e01b8152600401611a5f9190613026565b6000604051808303816000875af1158015611a7e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261134d919081019061309d565b5092909150565b80600003611ad7575050565b6040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f000000000000000000000000000000000000000000000000000000000000000016906340c10f19906044016113d9565b60055473ffffffffffffffffffffffffffffffffffffffff1615611d24576005546040805160a0810182523380825260208083018890526000918252600790528281208054919473ffffffffffffffffffffffffffffffffffffffff169363dd19fe3893929083019190611bc590612bc1565b80601f0160208091040260200160405190810160405280929190818152602001828054611bf190612bc1565b8015611c3e5780601f10611c1357610100808354040283529160200191611c3e565b820191906000526020600020905b815481529060010190602001808311611c2157829003601f168201915b50505050508152602001868152602001858152506040518263ffffffff1660e01b8152600401611c6e91906130f7565b6000604051808303816000875af1158015611c8d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611cd39190810190613197565b805160008681526006602090815260409091208251939450611cfb93909291909101906125e7565b5060208082015133600090815260078352604090208151611d21939192909101906125e7565b50505b80516020808301516040805133815273ffffffffffffffffffffffffffffffffffffffff909416928401929092528282015260608201859052517f9afd47907e25028cdaca89d193518c302bbb128617d5a992c5abd458155265939181900360800190a150505050565b60408051606081810183526000808352602083015291810182905273ffffffffffffffffffffffffffffffffffffffff841660009081526008602052604090205460ff16611e08576040517f5b0a758300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518082018252600085815260066020529182208054829190611e2c90612bc1565b80601f0160208091040260200160405190810160405280929190818152602001828054611e5890612bc1565b8015611ea55780601f10611e7a57610100808354040283529160200191611ea5565b820191906000526020600020905b815481529060010190602001808311611e8857829003601f168201915b50505050508152602001600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054611ef990612bc1565b80601f0160208091040260200160405190810160405280929190818152602001828054611f2590612bc1565b8015611f725780601f10611f4757610100808354040283529160200191611f72565b820191906000526020600020905b815481529060010190602001808311611f5557829003601f168201915b50505050508152509050806000015151600003611fbb576040517fd3d38f6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055460408051808201825273ffffffffffffffffffffffffffffffffffffffff88811682526020820185905291517f7afb99530000000000000000000000000000000000000000000000000000000081529190921691637afb995391612025919060040161326c565b6000604051808303816000875af1158015612044573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261208a919081019061309d565b90969095509350505050565b6040805180820182526000848152600660205291822080548291906120ba90612bc1565b80601f01602080910402602001604051908101604052809291908181526020018280546120e690612bc1565b80156121335780601f1061210857610100808354040283529160200191612133565b820191906000526020600020905b81548152906001019060200180831161211657829003601f168201915b50505050508152602001600760008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805461218790612bc1565b80601f01602080910402602001604051908101604052809291908181526020018280546121b390612bc1565b80156122005780601f106121d557610100808354040283529160200191612200565b820191906000526020600020905b8154815290600101906020018083116121e357829003601f168201915b5050509190925250506005546040805160808101825273ffffffffffffffffffffffffffffffffffffffff8881168252602082018890528183018790526060820185905291517f1306ac3b000000000000000000000000000000000000000000000000000000008152939450911691631306ac3b91612281916004016132a7565b6000604051808303816000875af11580156122a0573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526122e69190810190613197565b80516000858152600660209081526040909120825193945061230e93909291909101906125e7565b5060208082015173ffffffffffffffffffffffffffffffffffffffff861660009081526007835260409020815161234a939192909101906125e7565b5050505050565b60006040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061088c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c45440000000000000000000000000000000000006044820152606401610593565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b600080600080600085875af19050806117e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610593565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061088c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610593565b8280546125f390612bc1565b90600052602060002090601f016020900481019282612615576000855561265b565b82601f1061262e57805160ff191683800117855561265b565b8280016001018555821561265b579182015b8281111561265b578251825591602001919060010190612640565b5061266792915061266b565b5090565b5b80821115612667576000815560010161266c565b73ffffffffffffffffffffffffffffffffffffffff811681146126a257600080fd5b50565b600080604083850312156126b857600080fd5b8235915060208301356126ca81612680565b809150509250929050565b60008083601f8401126126e757600080fd5b50813567ffffffffffffffff8111156126ff57600080fd5b60208301915083602082850101111561135b57600080fd5b60008060008060008060008060c0898b03121561273357600080fd5b883561273e81612680565b97506020890135965060408901359550606089013561275c81612680565b9450608089013567ffffffffffffffff8082111561277957600080fd5b6127858c838d016126d5565b909650945060a08b013591508082111561279e57600080fd5b506127ab8b828c016126d5565b999c989b5096995094979396929594505050565b6000602082840312156127d157600080fd5b81356109eb81612680565b60005b838110156127f75781810151838201526020016127df565b8381111561088c5750506000910152565b600081518084526128208160208601602086016127dc565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109eb6020830184612808565b60008060006060848603121561287a57600080fd5b833561288581612680565b9250602084013561289581612680565b929592945050506040919091013590565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561291c5761291c6128a6565b604052919050565b600067ffffffffffffffff82111561293e5761293e6128a6565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b6000806040838503121561297d57600080fd5b823563ffffffff8116811461299157600080fd5b9150602083013567ffffffffffffffff8111156129ad57600080fd5b8301601f810185136129be57600080fd5b80356129d16129cc82612924565b6128d5565b8181528660208385010111156129e657600080fd5b816020840160208301376000602083830101528093505050509250929050565b60008060408385031215612a1957600080fd5b8235612a2481612680565b946020939093013593505050565b80358015158114612a4257600080fd5b919050565b60008060408385031215612a5a57600080fd5b8235612a6581612680565b9150612a7360208401612a32565b90509250929050565b60008083601f840112612a8e57600080fd5b50813567ffffffffffffffff811115612aa657600080fd5b6020830191508360208260051b850101111561135b57600080fd5b60008060008060408587031215612ad757600080fd5b843567ffffffffffffffff80821115612aef57600080fd5b612afb88838901612a7c565b90965094506020870135915080821115612b1457600080fd5b50612b2187828801612a7c565b95989497509550505050565b600060208284031215612b3f57600080fd5b5035919050565b600080600060608486031215612b5b57600080fd5b8335612b6681612680565b95602085013595506040909401359392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015612bbc57612bbc612b7b565b500390565b600181811c90821680612bd557607f821691505b602082108103612c0e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082601f830112612c2557600080fd5b8151612c336129cc82612924565b818152846020838601011115612c4857600080fd5b610ff48260208301602087016127dc565b60008060008060808587031215612c6f57600080fd5b8451612c7a81612680565b809450506020850151925060408501519150606085015167ffffffffffffffff811115612ca657600080fd5b612cb287828801612c14565b91505092959194509250565b60008219821115612cd157612cd1612b7b565b500190565b600060208284031215612ce857600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215612d3057600080fd5b6109eb82612a32565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612d6a57612d6a612b7b565b5060010190565b73ffffffffffffffffffffffffffffffffffffffff8151168252602081015160208301526000604082015160606040850152610ff46060850182612808565b60208152600073ffffffffffffffffffffffffffffffffffffffff808451166020840152806020850151166040840152506040830151606080840152610ff46080840182612d71565b600060608284031215612e0b57600080fd5b6040516060810167ffffffffffffffff8282108183111715612e2f57612e2f6128a6565b8160405282935084519150612e4382612680565b818352602085015160208401526040850151915080821115612e6457600080fd5b50612e7185828601612c14565b6040830152505092915050565b60008060408385031215612e9157600080fd5b825167ffffffffffffffff80821115612ea957600080fd5b612eb586838701612df9565b93506020850151915080821115612ecb57600080fd5b50612ed885828601612c14565b9150509250929050565b6020815273ffffffffffffffffffffffffffffffffffffffff82511660208201526000602083015160806040840152612f1e60a0840182612808565b905060408401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe080858403016060860152612f5a8383612808565b9250606086015191508085840301608086015250612f788282612d71565b95945050505050565b600060208284031215612f9357600080fd5b815167ffffffffffffffff811115612faa57600080fd5b610ff484828501612df9565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000612ff16080830184612808565b9695505050505050565b8381526060602082015260006130146060830185612808565b8281036040840152612ff18185612808565b6020815273ffffffffffffffffffffffffffffffffffffffff825116602082015260006020830151606060408401526130626080840182612808565b905060408401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016060850152612f788282612d71565b600080604083850312156130b057600080fd5b825167ffffffffffffffff808211156130c857600080fd5b6130d486838701612c14565b935060208501519150808211156130ea57600080fd5b50612ed885828601612df9565b6020815273ffffffffffffffffffffffffffffffffffffffff8251166020820152602082015160408201526000604083015160a0606084015261313d60c0840182612808565b905060608401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0808584030160808601526131798383612808565b925060808601519150808584030160a086015250612f788282612d71565b6000602082840312156131a957600080fd5b815167ffffffffffffffff808211156131c157600080fd5b90830190604082860312156131d557600080fd5b6040516040810181811083821117156131f0576131f06128a6565b60405282518281111561320257600080fd5b61320e87828601612c14565b82525060208301518281111561322357600080fd5b61322f87828601612c14565b60208301525095945050505050565b60008151604084526132536040850182612808565b905060208301518482036020860152612f788282612808565b6020815273ffffffffffffffffffffffffffffffffffffffff825116602082015260006020830151604080840152610ff4606084018261323e565b6020815273ffffffffffffffffffffffffffffffffffffffff82511660208201526020820151604082015260006040830151608060608401526132ed60a0840182612808565b905060608401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016080850152612f78828261323e56fea2646970667358221220a2bbddfad7ed3b856aafedec1c0f90261118eb56cc9bdd1cf6510d2fcbae8be264736f6c634300080d0033000000000000000000000000cb246b3719fa7f37ab2696ecdcbb7a9b5dd816da

Deployed ByteCode

0x60806040526004361061016a5760003560e01c80638da5cb5b116100cb578063d547741f1161007f578063f290aafa11610059578063f290aafa146103fc578063fc0c546a1461041c578063fc3a7b981461045057600080fd5b8063d547741f1461038c578063e272ad3f146103ac578063e9ee1eaf146103cc57600080fd5b80639dc7b023116100b05780639dc7b02314610336578063a2309ff814610356578063aad48d801461036c57600080fd5b80638da5cb5b146102db57806391d148541461030657600080fd5b80634b0a8854116101225780636ccae054116101075780636ccae0541461027b57806370bab2c01461029b578063873ea755146102c857600080fd5b80634b0a88541461022e5780635b94db271461025b57600080fd5b80632f2ff15d116101535780632f2ff15d146101e45780633bd1adec14610206578063405e720a1461021b57600080fd5b806320f99c0a1461016f5780632421e155146101c0575b600080fd5b34801561017b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101cc57600080fd5b506101d660045481565b6040519081526020016101b7565b3480156101f057600080fd5b506102046101ff3660046126a5565b610470565b005b34801561021257600080fd5b506102046104cf565b610204610229366004612717565b61052b565b34801561023a57600080fd5b5061024e6102493660046127bf565b61069a565b6040516101b79190612852565b34801561026757600080fd5b506102046102763660046127bf565b610734565b34801561028757600080fd5b50610204610296366004612865565b6107f4565b3480156102a757600080fd5b506005546101969073ffffffffffffffffffffffffffffffffffffffff1681565b6102046102d636600461296a565b610892565b3480156102e757600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610196565b34801561031257600080fd5b506103266103213660046126a5565b6109b7565b60405190151581526020016101b7565b34801561034257600080fd5b50610204610351366004612a06565b6109f2565b34801561036257600080fd5b506101d660095481565b34801561037857600080fd5b50610204610387366004612a47565b610ab8565b34801561039857600080fd5b506102046103a73660046126a5565b610d2d565b3480156103b857600080fd5b506102046103c7366004612ac1565b610d88565b3480156103d857600080fd5b506103266103e73660046127bf565b60086020526000908152604090205460ff1681565b34801561040857600080fd5b5061024e610417366004612b2d565b610f42565b34801561042857600080fd5b506101967f000000000000000000000000cb246b3719fa7f37ab2696ecdcbb7a9b5dd816da81565b34801561045c57600080fd5b506101d661046b366004612b46565b610f5b565b60015473ffffffffffffffffffffffffffffffffffffffff1633146104c1576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104cb8282610ffc565b5050565b60025473ffffffffffffffffffffffffffffffffffffffff163314610520576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61052933611082565b565b60005460011461059c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e43590000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b60026000819055506000806106158760405180606001604052808d73ffffffffffffffffffffffffffffffffffffffff1681526020018c815260200189898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506110fb565b9150915081602001516009600082825461062f9190612baa565b92505081905550610644338360200151611362565b610689888886868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508792508891506114079050565b505060016000555050505050505050565b600760205260009081526040902080546106b390612bc1565b80601f01602080910402602001604051908101604052809291908181526020018280546106df90612bc1565b801561072c5780601f106107015761010080835404028352916020019161072c565b820191906000526020600020905b81548152906001019060200180831161070f57829003601f168201915b505050505081565b60015473ffffffffffffffffffffffffffffffffffffffff163314610785576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b3360009081527f271b3e2292ab6fd3ff496cd98d6d375af02f11568a701741f48bba7789f13a7060205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff16610881576040517f962f633300000000000000000000000000000000000000000000000000000000815260048101829052602401610593565b61088c84848461174c565b50505050565b6000546001146108fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152606401610593565b6002600081905550600080600080848060200190518101906109209190612c59565b9350935093509350600060405180606001604052808673ffffffffffffffffffffffffffffffffffffffff16815260200185815260200183815250905060606109698883611841565b805160208201519194509192506109809190611acb565b8160200151600960008282546109969190612cbe565b909155506109a8905085858385611b52565b50506001600055505050505050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff165b9392505050565b600054600114610a5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152606401610593565b6002600090815580610a708484611d8e565b91509150610a8681600001518260200151611acb565b806020015160096000828254610a9c9190612cbe565b90915550610aad9050848484612096565b505060016000555050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b09576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000cb246b3719fa7f37ab2696ecdcbb7a9b5dd816da73ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610cb3576005546040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff91821660248201526000917f000000000000000000000000cb246b3719fa7f37ab2696ecdcbb7a9b5dd816da169063dd62ed3e90604401602060405180830381865afa158015610bf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c169190612cd6565b1115610c6257600554610c62907f000000000000000000000000cb246b3719fa7f37ab2696ecdcbb7a9b5dd816da9073ffffffffffffffffffffffffffffffffffffffff166000612351565b8015610cb357610cb37f000000000000000000000000cb246b3719fa7f37ab2696ecdcbb7a9b5dd816da837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612351565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fe816c20840d998c8612f9b624b91687a80510eeb293cb09f7637379f6d73342d9060200160405180910390a15050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610d7e576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104cb8282612420565b60015473ffffffffffffffffffffffffffffffffffffffff163314610dd9576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260005b81811015610f3a57838382818110610df757610df7612cef565b9050602002016020810190610e0c9190612d1e565b60086000888885818110610e2257610e22612cef565b9050602002016020810190610e3791906127bf565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790557f857309f1a328784e9fc9749624be5d32fd8e7afab58e7fe9a218dd613a37f15c868683818110610ebd57610ebd612cef565b9050602002016020810190610ed291906127bf565b858584818110610ee457610ee4612cef565b9050602002016020810190610ef99190612d1e565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835290151560208301520160405180910390a180610f3281612d39565b915050610ddd565b505050505050565b600660205260009081526040902080546106b390612bc1565b6040517f666758ca000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260009073ffffffffffffffffffffffffffffffffffffffff85169063666758ca90604401602060405180830381865afa158015610fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff49190612cd6565b949350505050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092556002805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b60408051606080820183526000808352602083015291810191909152815160609073ffffffffffffffffffffffffffffffffffffffff16611168576040517f96bbcf1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff841660009081526008602052604090205460ff166111c7576040517f5b0a758300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000cb246b3719fa7f37ab2696ecdcbb7a9b5dd816da73ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480156112235750826020015134105b1561125a576040517f78f38f7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff1615611357576005546040805160608101825273ffffffffffffffffffffffffffffffffffffffff878116825233602083015281830187905291517ff59ad990000000000000000000000000000000000000000000000000000000008152919092169163f59ad990916112e89190600401612db0565b6000604051808303816000875af1158015611307573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261134d9190810190612e7e565b909250905061135b565b8291505b9250929050565b6040517f9dc29fac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f000000000000000000000000cb246b3719fa7f37ab2696ecdcbb7a9b5dd816da1690639dc29fac906044015b600060405180830381600087803b1580156113f357600080fd5b505af1158015610f3a573d6000803e3d6000fd5b600554819073ffffffffffffffffffffffffffffffffffffffff1615611507576005546040805160808101825273ffffffffffffffffffffffffffffffffffffffff8881168252602082018890528183018790526060820186905291517f62811bf200000000000000000000000000000000000000000000000000000000815291909216916362811bf29161149f9190600401612ee2565b6000604051808303816000875af11580156114be573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526115049190810190612f81565b90505b60007f000000000000000000000000cb246b3719fa7f37ab2696ecdcbb7a9b5dd816da73ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611560573461156f565b602082015161156f9034612baa565b905060008673ffffffffffffffffffffffffffffffffffffffff166374fa24a66040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e29190612cd6565b905060008773ffffffffffffffffffffffffffffffffffffffff1663ac0710cb848b87600001518860200151878a604001516040516020016116279493929190612fb6565b6040516020818303038152906040528b6040518563ffffffff1660e01b815260040161165593929190612ffb565b60206040518083038185885af1158015611673573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906116989190612cd6565b90508181146116d3576040517f7b7bbbe000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83516020808601516040805173ffffffffffffffffffffffffffffffffffffffff8d811682523394820194909452929093168284015260608201526080810184905290517fc74a00177d2c63e6eead5ea7936974ad9d0121f86140723b8909f8ec9662cc619181900360a00190a1505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8216611799576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016117e5576117e082826124a3565b505050565b8273ffffffffffffffffffffffffffffffffffffffff163b600003611836576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117e0838383612518565b6040805160608181018352600080835260208301529181018290523360009081526008602052604090205460ff166118a5576040517f5b0a758300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825173ffffffffffffffffffffffffffffffffffffffff1630148061191957507f000000000000000000000000cb246b3719fa7f37ab2696ecdcbb7a9b5dd816da73ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16145b15611950576040517f285c601600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff1615611ac4576005546040805160608101825233808252600090815260076020908152929020805473ffffffffffffffffffffffffffffffffffffffff9094169363cf36b91793830191906119bc90612bc1565b80601f01602080910402602001604051908101604052809291908181526020018280546119e890612bc1565b8015611a355780601f10611a0a57610100808354040283529160200191611a35565b820191906000526020600020905b815481529060010190602001808311611a1857829003601f168201915b50505050508152602001868152506040518263ffffffff1660e01b8152600401611a5f9190613026565b6000604051808303816000875af1158015611a7e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261134d919081019061309d565b5092909150565b80600003611ad7575050565b6040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f000000000000000000000000cb246b3719fa7f37ab2696ecdcbb7a9b5dd816da16906340c10f19906044016113d9565b60055473ffffffffffffffffffffffffffffffffffffffff1615611d24576005546040805160a0810182523380825260208083018890526000918252600790528281208054919473ffffffffffffffffffffffffffffffffffffffff169363dd19fe3893929083019190611bc590612bc1565b80601f0160208091040260200160405190810160405280929190818152602001828054611bf190612bc1565b8015611c3e5780601f10611c1357610100808354040283529160200191611c3e565b820191906000526020600020905b815481529060010190602001808311611c2157829003601f168201915b50505050508152602001868152602001858152506040518263ffffffff1660e01b8152600401611c6e91906130f7565b6000604051808303816000875af1158015611c8d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611cd39190810190613197565b805160008681526006602090815260409091208251939450611cfb93909291909101906125e7565b5060208082015133600090815260078352604090208151611d21939192909101906125e7565b50505b80516020808301516040805133815273ffffffffffffffffffffffffffffffffffffffff909416928401929092528282015260608201859052517f9afd47907e25028cdaca89d193518c302bbb128617d5a992c5abd458155265939181900360800190a150505050565b60408051606081810183526000808352602083015291810182905273ffffffffffffffffffffffffffffffffffffffff841660009081526008602052604090205460ff16611e08576040517f5b0a758300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518082018252600085815260066020529182208054829190611e2c90612bc1565b80601f0160208091040260200160405190810160405280929190818152602001828054611e5890612bc1565b8015611ea55780601f10611e7a57610100808354040283529160200191611ea5565b820191906000526020600020905b815481529060010190602001808311611e8857829003601f168201915b50505050508152602001600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054611ef990612bc1565b80601f0160208091040260200160405190810160405280929190818152602001828054611f2590612bc1565b8015611f725780601f10611f4757610100808354040283529160200191611f72565b820191906000526020600020905b815481529060010190602001808311611f5557829003601f168201915b50505050508152509050806000015151600003611fbb576040517fd3d38f6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055460408051808201825273ffffffffffffffffffffffffffffffffffffffff88811682526020820185905291517f7afb99530000000000000000000000000000000000000000000000000000000081529190921691637afb995391612025919060040161326c565b6000604051808303816000875af1158015612044573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261208a919081019061309d565b90969095509350505050565b6040805180820182526000848152600660205291822080548291906120ba90612bc1565b80601f01602080910402602001604051908101604052809291908181526020018280546120e690612bc1565b80156121335780601f1061210857610100808354040283529160200191612133565b820191906000526020600020905b81548152906001019060200180831161211657829003601f168201915b50505050508152602001600760008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805461218790612bc1565b80601f01602080910402602001604051908101604052809291908181526020018280546121b390612bc1565b80156122005780601f106121d557610100808354040283529160200191612200565b820191906000526020600020905b8154815290600101906020018083116121e357829003601f168201915b5050509190925250506005546040805160808101825273ffffffffffffffffffffffffffffffffffffffff8881168252602082018890528183018790526060820185905291517f1306ac3b000000000000000000000000000000000000000000000000000000008152939450911691631306ac3b91612281916004016132a7565b6000604051808303816000875af11580156122a0573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526122e69190810190613197565b80516000858152600660209081526040909120825193945061230e93909291909101906125e7565b5060208082015173ffffffffffffffffffffffffffffffffffffffff861660009081526007835260409020815161234a939192909101906125e7565b5050505050565b60006040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061088c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c45440000000000000000000000000000000000006044820152606401610593565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b600080600080600085875af19050806117e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610593565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061088c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610593565b8280546125f390612bc1565b90600052602060002090601f016020900481019282612615576000855561265b565b82601f1061262e57805160ff191683800117855561265b565b8280016001018555821561265b579182015b8281111561265b578251825591602001919060010190612640565b5061266792915061266b565b5090565b5b80821115612667576000815560010161266c565b73ffffffffffffffffffffffffffffffffffffffff811681146126a257600080fd5b50565b600080604083850312156126b857600080fd5b8235915060208301356126ca81612680565b809150509250929050565b60008083601f8401126126e757600080fd5b50813567ffffffffffffffff8111156126ff57600080fd5b60208301915083602082850101111561135b57600080fd5b60008060008060008060008060c0898b03121561273357600080fd5b883561273e81612680565b97506020890135965060408901359550606089013561275c81612680565b9450608089013567ffffffffffffffff8082111561277957600080fd5b6127858c838d016126d5565b909650945060a08b013591508082111561279e57600080fd5b506127ab8b828c016126d5565b999c989b5096995094979396929594505050565b6000602082840312156127d157600080fd5b81356109eb81612680565b60005b838110156127f75781810151838201526020016127df565b8381111561088c5750506000910152565b600081518084526128208160208601602086016127dc565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109eb6020830184612808565b60008060006060848603121561287a57600080fd5b833561288581612680565b9250602084013561289581612680565b929592945050506040919091013590565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561291c5761291c6128a6565b604052919050565b600067ffffffffffffffff82111561293e5761293e6128a6565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b6000806040838503121561297d57600080fd5b823563ffffffff8116811461299157600080fd5b9150602083013567ffffffffffffffff8111156129ad57600080fd5b8301601f810185136129be57600080fd5b80356129d16129cc82612924565b6128d5565b8181528660208385010111156129e657600080fd5b816020840160208301376000602083830101528093505050509250929050565b60008060408385031215612a1957600080fd5b8235612a2481612680565b946020939093013593505050565b80358015158114612a4257600080fd5b919050565b60008060408385031215612a5a57600080fd5b8235612a6581612680565b9150612a7360208401612a32565b90509250929050565b60008083601f840112612a8e57600080fd5b50813567ffffffffffffffff811115612aa657600080fd5b6020830191508360208260051b850101111561135b57600080fd5b60008060008060408587031215612ad757600080fd5b843567ffffffffffffffff80821115612aef57600080fd5b612afb88838901612a7c565b90965094506020870135915080821115612b1457600080fd5b50612b2187828801612a7c565b95989497509550505050565b600060208284031215612b3f57600080fd5b5035919050565b600080600060608486031215612b5b57600080fd5b8335612b6681612680565b95602085013595506040909401359392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015612bbc57612bbc612b7b565b500390565b600181811c90821680612bd557607f821691505b602082108103612c0e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082601f830112612c2557600080fd5b8151612c336129cc82612924565b818152846020838601011115612c4857600080fd5b610ff48260208301602087016127dc565b60008060008060808587031215612c6f57600080fd5b8451612c7a81612680565b809450506020850151925060408501519150606085015167ffffffffffffffff811115612ca657600080fd5b612cb287828801612c14565b91505092959194509250565b60008219821115612cd157612cd1612b7b565b500190565b600060208284031215612ce857600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215612d3057600080fd5b6109eb82612a32565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612d6a57612d6a612b7b565b5060010190565b73ffffffffffffffffffffffffffffffffffffffff8151168252602081015160208301526000604082015160606040850152610ff46060850182612808565b60208152600073ffffffffffffffffffffffffffffffffffffffff808451166020840152806020850151166040840152506040830151606080840152610ff46080840182612d71565b600060608284031215612e0b57600080fd5b6040516060810167ffffffffffffffff8282108183111715612e2f57612e2f6128a6565b8160405282935084519150612e4382612680565b818352602085015160208401526040850151915080821115612e6457600080fd5b50612e7185828601612c14565b6040830152505092915050565b60008060408385031215612e9157600080fd5b825167ffffffffffffffff80821115612ea957600080fd5b612eb586838701612df9565b93506020850151915080821115612ecb57600080fd5b50612ed885828601612c14565b9150509250929050565b6020815273ffffffffffffffffffffffffffffffffffffffff82511660208201526000602083015160806040840152612f1e60a0840182612808565b905060408401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe080858403016060860152612f5a8383612808565b9250606086015191508085840301608086015250612f788282612d71565b95945050505050565b600060208284031215612f9357600080fd5b815167ffffffffffffffff811115612faa57600080fd5b610ff484828501612df9565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000612ff16080830184612808565b9695505050505050565b8381526060602082015260006130146060830185612808565b8281036040840152612ff18185612808565b6020815273ffffffffffffffffffffffffffffffffffffffff825116602082015260006020830151606060408401526130626080840182612808565b905060408401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016060850152612f788282612d71565b600080604083850312156130b057600080fd5b825167ffffffffffffffff808211156130c857600080fd5b6130d486838701612c14565b935060208501519150808211156130ea57600080fd5b50612ed885828601612df9565b6020815273ffffffffffffffffffffffffffffffffffffffff8251166020820152602082015160408201526000604083015160a0606084015261313d60c0840182612808565b905060608401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0808584030160808601526131798383612808565b925060808601519150808584030160a086015250612f788282612d71565b6000602082840312156131a957600080fd5b815167ffffffffffffffff808211156131c157600080fd5b90830190604082860312156131d557600080fd5b6040516040810181811083821117156131f0576131f06128a6565b60405282518281111561320257600080fd5b61320e87828601612c14565b82525060208301518281111561322357600080fd5b61322f87828601612c14565b60208301525095945050505050565b60008151604084526132536040850182612808565b905060208301518482036020860152612f788282612808565b6020815273ffffffffffffffffffffffffffffffffffffffff825116602082015260006020830151604080840152610ff4606084018261323e565b6020815273ffffffffffffffffffffffffffffffffffffffff82511660208201526020820151604082015260006040830151608060608401526132ed60a0840182612808565b905060608401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016080850152612f78828261323e56fea2646970667358221220a2bbddfad7ed3b856aafedec1c0f90261118eb56cc9bdd1cf6510d2fcbae8be264736f6c634300080d0033