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

0x06F92b5D06D54802601CBAf862fe549e7EaedcF7

Contract Name
LimitHook
Creator
0x44a448–b88f4c at 0xe37a7d–bb2d3d
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:
LimitHook




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




Optimization runs
999999
EVM Version
default




Verified at
2024-10-23T11:16:52.528364Z

Constructor Arguments

0x00000000000000000000000044a44837894b5edc2bde64567fc62599b3b88f4c000000000000000000000000b5b1e1ba18d323a2a7313f970bf4310cf8d60b8d0000000000000000000000000000000000000000000000000000000000000001

Arg [0] (address) : 0x44a44837894b5edc2bde64567fc62599b3b88f4c
Arg [1] (address) : 0xb5b1e1ba18d323a2a7313f970bf4310cf8d60b8d
Arg [2] (bool) : true

              

contracts/hooks/LimitHook.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/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 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/hooks/HookBase.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 HookBase is ReentrancyGuard, IHook, RescueBase {
    address public immutable vaultOrController;
    bytes32 public hookType;

    /**
     * @notice Constructor for creating a new SuperToken.
     */
    constructor(
        address owner_,
        address vaultOrController_
    ) AccessControl(owner_) {
        vaultOrController = vaultOrController_;
        _grantRole(RESCUE_ROLE, owner_);
    }

    modifier isVaultOrController() {
        if (msg.sender != vaultOrController) revert NotAuthorized();
        _;
    }
}


// File contracts/hooks/plugins/ConnectorPoolPlugin.sol

pragma solidity 0.8.13;

abstract contract ConnectorPoolPlugin is HookBase {
    // connectorPoolId => totalLockedAmount
    mapping(uint256 => uint256) public poolLockedAmounts;

    // connector => connectorPoolId
    mapping(address => uint256) public connectorPoolIds;

    event ConnectorPoolIdUpdated(address connector, uint256 poolId);
    event PoolLockedAmountUpdated(uint256 poolId, uint256 amount);

    function updateConnectorPoolId(
        address[] calldata connectors,
        uint256[] calldata poolIds_
    ) external onlyOwner {
        uint256 length = connectors.length;
        for (uint256 i; i < length; i++) {
            if (poolIds_[i] == 0) revert InvalidPoolId();
            connectorPoolIds[connectors[i]] = poolIds_[i];
            emit ConnectorPoolIdUpdated(connectors[i], poolIds_[i]);
        }
    }

    function updatePoolLockedAmounts(
        uint256[] calldata poolIds_,
        uint256[] calldata amounts_
    ) external onlyOwner {
        uint256 length = poolIds_.length;
        for (uint256 i; i < length; i++) {
            if (poolIds_[i] == 0) revert InvalidPoolId();
            poolLockedAmounts[poolIds_[i]] = amounts_[i];
            emit PoolLockedAmountUpdated(poolIds_[i], amounts_[i]);
        }
    }

    function _poolSrcHook(address connector_, uint256 amount_) internal {
        uint256 connectorPoolId = connectorPoolIds[connector_];
        if (connectorPoolId == 0) revert InvalidPoolId();
        if (amount_ > poolLockedAmounts[connectorPoolId])
            revert InsufficientFunds();

        poolLockedAmounts[connectorPoolId] -= amount_;
    }

    function _poolDstHook(
        address connector_,
        uint256 amount_
    ) internal returns (uint256 oldLockedAmount) {
        uint256 connectorPoolId = connectorPoolIds[connector_];
        if (connectorPoolId == 0) revert InvalidPoolId();

        oldLockedAmount = poolLockedAmounts[connectorPoolId];
        poolLockedAmounts[connectorPoolId] += amount_;
    }
}


// File contracts/utils/Gauge.sol

pragma solidity 0.8.13;

abstract contract Gauge {
    error AmountOutsideLimit();

    function _getCurrentLimit(
        LimitParams storage _params
    ) internal view returns (uint256 _limit) {
        uint256 timeElapsed = block.timestamp - _params.lastUpdateTimestamp;
        uint256 limitIncrease = timeElapsed * _params.ratePerSecond;

        if (limitIncrease + _params.lastUpdateLimit > _params.maxLimit) {
            _limit = _params.maxLimit;
        } else {
            _limit = limitIncrease + _params.lastUpdateLimit;
        }
    }

    function _consumePartLimit(
        uint256 amount_,
        LimitParams storage _params
    ) internal returns (uint256 consumedAmount, uint256 pendingAmount) {
        uint256 currentLimit = _getCurrentLimit(_params);
        _params.lastUpdateTimestamp = block.timestamp;
        if (currentLimit >= amount_) {
            _params.lastUpdateLimit = currentLimit - amount_;
            consumedAmount = amount_;
            pendingAmount = 0;
        } else {
            _params.lastUpdateLimit = 0;
            consumedAmount = currentLimit;
            pendingAmount = amount_ - currentLimit;
        }
    }

    function _consumeFullLimit(
        uint256 amount_,
        LimitParams storage _params
    ) internal {
        uint256 currentLimit = _getCurrentLimit(_params);
        if (currentLimit >= amount_) {
            _params.lastUpdateTimestamp = block.timestamp;
            _params.lastUpdateLimit = currentLimit - amount_;
        } else {
            revert AmountOutsideLimit();
        }
    }
}


// File contracts/hooks/plugins/LimitPlugin.sol

pragma solidity 0.8.13;


abstract contract LimitPlugin is Gauge, HookBase {
    bytes32 constant LIMIT_UPDATER_ROLE = keccak256("LIMIT_UPDATER_ROLE");

    // connector => receivingLimitParams
    mapping(address => LimitParams) _receivingLimitParams;

    // connector => sendingLimitParams
    mapping(address => LimitParams) _sendingLimitParams;

    ////////////////////////////////////////////////////////
    ////////////////////// EVENTS //////////////////////////
    ////////////////////////////////////////////////////////

    // Emitted when limit parameters are updated
    event LimitParamsUpdated(UpdateLimitParams[] updates);

    // Emitted when pending tokens are minted to the receiver
    event PendingTokensBridged(
        address connector,
        address receiver,
        uint256 consumedAmount,
        uint256 pendingAmount,
        bytes32 messageId
    );
    // Emitted when the transfer reaches the limit, and the token mint is added to the pending queue
    event TokensPending(
        address connector,
        address receiver,
        uint256 consumedAmount,
        uint256 pendingAmount,
        bytes32 messageId
    );

    /**
     * @notice This function is used to set bridge limits.
     * @dev It can only be updated by the owner.
     * @param updates An array of structs containing update parameters.
     */
    function updateLimitParams(
        UpdateLimitParams[] calldata updates
    ) external onlyRole(LIMIT_UPDATER_ROLE) {
        for (uint256 i = 0; i < updates.length; i++) {
            if (updates[i].isMint) {
                _consumePartLimit(
                    0,
                    _receivingLimitParams[updates[i].connector]
                ); // To keep the current limit in sync
                _receivingLimitParams[updates[i].connector].maxLimit = updates[
                    i
                ].maxLimit;
                _receivingLimitParams[updates[i].connector]
                    .ratePerSecond = updates[i].ratePerSecond;
            } else {
                _consumePartLimit(0, _sendingLimitParams[updates[i].connector]); // To keep the current limit in sync
                _sendingLimitParams[updates[i].connector].maxLimit = updates[i]
                    .maxLimit;
                _sendingLimitParams[updates[i].connector]
                    .ratePerSecond = updates[i].ratePerSecond;
            }
        }

        emit LimitParamsUpdated(updates);
    }

    function getCurrentReceivingLimit(
        address connector_
    ) external view returns (uint256) {
        return _getCurrentLimit(_receivingLimitParams[connector_]);
    }

    function getCurrentSendingLimit(
        address connector_
    ) external view returns (uint256) {
        return _getCurrentLimit(_sendingLimitParams[connector_]);
    }

    function getReceivingLimitParams(
        address connector_
    ) external view returns (LimitParams memory) {
        return _receivingLimitParams[connector_];
    }

    function getSendingLimitParams(
        address connector_
    ) external view returns (LimitParams memory) {
        return _sendingLimitParams[connector_];
    }

    function _limitSrcHook(address connector_, uint256 amount_) internal {
        if (_sendingLimitParams[connector_].maxLimit == 0)
            revert SiblingNotSupported();

        _consumeFullLimit(amount_, _sendingLimitParams[connector_]); // Reverts on limit hit
    }

    function _limitDstHook(
        address connector_,
        uint256 amount_
    ) internal returns (uint256 consumedAmount, uint256 pendingAmount) {
        if (_receivingLimitParams[connector_].maxLimit == 0)
            revert SiblingNotSupported();

        (consumedAmount, pendingAmount) = _consumePartLimit(
            amount_,
            _receivingLimitParams[connector_]
        );
    }

    function _getConnectorPendingAmount(
        bytes memory connectorCache_
    ) internal pure returns (uint256) {
        if (connectorCache_.length > 0) {
            return abi.decode(connectorCache_, (uint256));
        } else return 0;
    }
}


// File contracts/interfaces/IController.sol

pragma solidity ^0.8.13;

interface IController {
    function identifierCache(
        bytes32 messageId_
    ) external payable returns (bytes memory cache);

    function connectorCache(
        address connector_
    ) external payable returns (bytes memory cache);
}


// File contracts/hooks/LimitHook.sol

pragma solidity 0.8.13;



contract LimitHook is LimitPlugin, ConnectorPoolPlugin {
    bool public immutable useControllerPools;

    /**
     * @notice Constructor for creating a new SuperToken.
     * @param owner_ Owner of this contract.
     */
    constructor(
        address owner_,
        address controller_,
        bool useControllerPools_
    ) HookBase(owner_, controller_) {
        useControllerPools = useControllerPools_;
        hookType = LIMIT_HOOK;
        _grantRole(LIMIT_UPDATER_ROLE, owner_);
    }

    function srcPreHookCall(
        SrcPreHookCallParams memory params_
    )
        external
        isVaultOrController
        returns (TransferInfo memory transferInfo, bytes memory postHookData)
    {
        if (useControllerPools)
            _poolSrcHook(params_.connector, params_.transferInfo.amount);

        _limitSrcHook(params_.connector, params_.transferInfo.amount);
        transferInfo = params_.transferInfo;
        postHookData = hex"";
    }

    function srcPostHookCall(
        SrcPostHookCallParams memory params_
    ) external view isVaultOrController returns (TransferInfo memory) {
        return params_.transferInfo;
    }

    function dstPreHookCall(
        DstPreHookCallParams memory params_
    )
        external
        isVaultOrController
        returns (bytes memory postHookData, TransferInfo memory transferInfo)
    {
        if (useControllerPools)
            _poolDstHook(params_.connector, params_.transferInfo.amount);

        (uint256 consumedAmount, uint256 pendingAmount) = _limitDstHook(
            params_.connector,
            params_.transferInfo.amount
        );
        postHookData = abi.encode(consumedAmount, pendingAmount);
        transferInfo = params_.transferInfo;
        transferInfo.amount = consumedAmount;
    }

    function dstPostHookCall(
        DstPostHookCallParams memory params_
    ) external isVaultOrController returns (CacheData memory cacheData) {
        (uint256 consumedAmount, uint256 pendingAmount) = abi.decode(
            params_.postHookData,
            (uint256, uint256)
        );
        uint256 connectorPendingAmount = _getConnectorPendingAmount(
            params_.connectorCache
        );
        if (pendingAmount > 0) {
            cacheData = CacheData(
                abi.encode(
                    params_.transferInfo.receiver,
                    pendingAmount,
                    params_.connector
                ),
                abi.encode(connectorPendingAmount + pendingAmount)
            );

            emit TokensPending(
                params_.connector,
                params_.transferInfo.receiver,
                consumedAmount,
                pendingAmount,
                params_.messageId
            );
        } else {
            cacheData = CacheData(
                bytes(""),
                abi.encode(connectorPendingAmount + pendingAmount)
            );
        }
    }

    function preRetryHook(
        PreRetryHookCallParams memory params_
    )
        external
        nonReentrant
        isVaultOrController
        returns (bytes memory postHookData, TransferInfo memory transferInfo)
    {
        (address receiver, uint256 pendingMint, address connector) = abi.decode(
            params_.cacheData.identifierCache,
            (address, uint256, address)
        );

        if (connector != params_.connector) revert InvalidConnector();

        (uint256 consumedAmount, uint256 pendingAmount) = _limitDstHook(
            params_.connector,
            pendingMint
        );

        postHookData = abi.encode(receiver, consumedAmount, pendingAmount);
        transferInfo = TransferInfo(receiver, consumedAmount, bytes(""));
    }

    function postRetryHook(
        PostRetryHookCallParams calldata params_
    )
        external
        isVaultOrController
        nonReentrant
        returns (CacheData memory cacheData)
    {
        (address receiver, uint256 consumedAmount, uint256 pendingAmount) = abi
            .decode(params_.postHookData, (address, uint256, uint256));

        // code reaches here after minting/unlocking the pending amount
        emit PendingTokensBridged(
            params_.connector,
            receiver,
            consumedAmount,
            pendingAmount,
            params_.messageId
        );

        uint256 connectorPendingAmount = _getConnectorPendingAmount(
            params_.cacheData.connectorCache
        );
        cacheData.connectorCache = abi.encode(
            connectorPendingAmount - consumedAmount
        );
        cacheData.identifierCache = abi.encode(
            receiver,
            pendingAmount,
            params_.connector
        );

        if (pendingAmount == 0) {
            cacheData.identifierCache = new bytes(0);
        }
    }

    function getConnectorPendingAmount(
        address connector_
    ) external returns (uint256) {
        bytes memory cache = IController(vaultOrController).connectorCache(
            connector_
        );
        return _getConnectorPendingAmount(cache);
    }

    function _getIdentifierPendingAmount(
        bytes memory identifierCache_
    ) internal pure returns (uint256) {
        if (identifierCache_.length > 0) {
            (, uint256 pendingAmount, ) = abi.decode(
                identifierCache_,
                (address, uint256, address)
            );
            return pendingAmount;
        } else return 0;
    }

    function getIdentifierPendingAmount(
        bytes32 messageId_
    ) external returns (uint256) {
        bytes memory cache = IController(vaultOrController).identifierCache(
            messageId_
        );
        return _getIdentifierPendingAmount(cache);
    }
}
        

Compiler Settings

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

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"owner_","internalType":"address"},{"type":"address","name":"controller_","internalType":"address"},{"type":"bool","name":"useControllerPools_","internalType":"bool"}]},{"type":"error","name":"AmountOutsideLimit","inputs":[]},{"type":"error","name":"InsufficientFunds","inputs":[]},{"type":"error","name":"InvalidConnector","inputs":[]},{"type":"error","name":"InvalidPoolId","inputs":[]},{"type":"error","name":"InvalidTokenAddress","inputs":[]},{"type":"error","name":"NoPermit","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"error","name":"NotAuthorized","inputs":[]},{"type":"error","name":"OnlyNominee","inputs":[]},{"type":"error","name":"OnlyOwner","inputs":[]},{"type":"error","name":"SiblingNotSupported","inputs":[]},{"type":"error","name":"ZeroAddress","inputs":[]},{"type":"event","name":"ConnectorPoolIdUpdated","inputs":[{"type":"address","name":"connector","internalType":"address","indexed":false},{"type":"uint256","name":"poolId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"LimitParamsUpdated","inputs":[{"type":"tuple[]","name":"updates","internalType":"struct UpdateLimitParams[]","indexed":false,"components":[{"type":"bool","name":"isMint","internalType":"bool"},{"type":"address","name":"connector","internalType":"address"},{"type":"uint256","name":"maxLimit","internalType":"uint256"},{"type":"uint256","name":"ratePerSecond","internalType":"uint256"}]}],"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":"PendingTokensBridged","inputs":[{"type":"address","name":"connector","internalType":"address","indexed":false},{"type":"address","name":"receiver","internalType":"address","indexed":false},{"type":"uint256","name":"consumedAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"pendingAmount","internalType":"uint256","indexed":false},{"type":"bytes32","name":"messageId","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"PoolLockedAmountUpdated","inputs":[{"type":"uint256","name":"poolId","internalType":"uint256","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"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":"TokensPending","inputs":[{"type":"address","name":"connector","internalType":"address","indexed":false},{"type":"address","name":"receiver","internalType":"address","indexed":false},{"type":"uint256","name":"consumedAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"pendingAmount","internalType":"uint256","indexed":false},{"type":"bytes32","name":"messageId","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimOwner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"connectorPoolIds","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"tuple","name":"cacheData","internalType":"struct CacheData","components":[{"type":"bytes","name":"identifierCache","internalType":"bytes"},{"type":"bytes","name":"connectorCache","internalType":"bytes"}]}],"name":"dstPostHookCall","inputs":[{"type":"tuple","name":"params_","internalType":"struct DstPostHookCallParams","components":[{"type":"address","name":"connector","internalType":"address"},{"type":"bytes32","name":"messageId","internalType":"bytes32"},{"type":"bytes","name":"connectorCache","internalType":"bytes"},{"type":"bytes","name":"postHookData","internalType":"bytes"},{"type":"tuple","name":"transferInfo","internalType":"struct TransferInfo","components":[{"type":"address","name":"receiver","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"extraData","internalType":"bytes"}]}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes","name":"postHookData","internalType":"bytes"},{"type":"tuple","name":"transferInfo","internalType":"struct TransferInfo","components":[{"type":"address","name":"receiver","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"extraData","internalType":"bytes"}]}],"name":"dstPreHookCall","inputs":[{"type":"tuple","name":"params_","internalType":"struct DstPreHookCallParams","components":[{"type":"address","name":"connector","internalType":"address"},{"type":"bytes","name":"connectorCache","internalType":"bytes"},{"type":"tuple","name":"transferInfo","internalType":"struct TransferInfo","components":[{"type":"address","name":"receiver","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"extraData","internalType":"bytes"}]}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getConnectorPendingAmount","inputs":[{"type":"address","name":"connector_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCurrentReceivingLimit","inputs":[{"type":"address","name":"connector_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCurrentSendingLimit","inputs":[{"type":"address","name":"connector_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getIdentifierPendingAmount","inputs":[{"type":"bytes32","name":"messageId_","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct LimitParams","components":[{"type":"uint256","name":"lastUpdateTimestamp","internalType":"uint256"},{"type":"uint256","name":"ratePerSecond","internalType":"uint256"},{"type":"uint256","name":"maxLimit","internalType":"uint256"},{"type":"uint256","name":"lastUpdateLimit","internalType":"uint256"}]}],"name":"getReceivingLimitParams","inputs":[{"type":"address","name":"connector_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct LimitParams","components":[{"type":"uint256","name":"lastUpdateTimestamp","internalType":"uint256"},{"type":"uint256","name":"ratePerSecond","internalType":"uint256"},{"type":"uint256","name":"maxLimit","internalType":"uint256"},{"type":"uint256","name":"lastUpdateLimit","internalType":"uint256"}]}],"name":"getSendingLimitParams","inputs":[{"type":"address","name":"connector_","internalType":"address"}]},{"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":"bytes32","name":"","internalType":"bytes32"}],"name":"hookType","inputs":[]},{"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":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"poolLockedAmounts","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"tuple","name":"cacheData","internalType":"struct CacheData","components":[{"type":"bytes","name":"identifierCache","internalType":"bytes"},{"type":"bytes","name":"connectorCache","internalType":"bytes"}]}],"name":"postRetryHook","inputs":[{"type":"tuple","name":"params_","internalType":"struct PostRetryHookCallParams","components":[{"type":"address","name":"connector","internalType":"address"},{"type":"bytes32","name":"messageId","internalType":"bytes32"},{"type":"bytes","name":"postHookData","internalType":"bytes"},{"type":"tuple","name":"cacheData","internalType":"struct CacheData","components":[{"type":"bytes","name":"identifierCache","internalType":"bytes"},{"type":"bytes","name":"connectorCache","internalType":"bytes"}]}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes","name":"postHookData","internalType":"bytes"},{"type":"tuple","name":"transferInfo","internalType":"struct TransferInfo","components":[{"type":"address","name":"receiver","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"extraData","internalType":"bytes"}]}],"name":"preRetryHook","inputs":[{"type":"tuple","name":"params_","internalType":"struct PreRetryHookCallParams","components":[{"type":"address","name":"connector","internalType":"address"},{"type":"tuple","name":"cacheData","internalType":"struct CacheData","components":[{"type":"bytes","name":"identifierCache","internalType":"bytes"},{"type":"bytes","name":"connectorCache","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":"revokeRole","inputs":[{"type":"bytes32","name":"role_","internalType":"bytes32"},{"type":"address","name":"revokee_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct TransferInfo","components":[{"type":"address","name":"receiver","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"extraData","internalType":"bytes"}]}],"name":"srcPostHookCall","inputs":[{"type":"tuple","name":"params_","internalType":"struct SrcPostHookCallParams","components":[{"type":"address","name":"connector","internalType":"address"},{"type":"bytes","name":"options","internalType":"bytes"},{"type":"bytes","name":"postHookData","internalType":"bytes"},{"type":"tuple","name":"transferInfo","internalType":"struct TransferInfo","components":[{"type":"address","name":"receiver","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"extraData","internalType":"bytes"}]}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"tuple","name":"transferInfo","internalType":"struct TransferInfo","components":[{"type":"address","name":"receiver","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"extraData","internalType":"bytes"}]},{"type":"bytes","name":"postHookData","internalType":"bytes"}],"name":"srcPreHookCall","inputs":[{"type":"tuple","name":"params_","internalType":"struct SrcPreHookCallParams","components":[{"type":"address","name":"connector","internalType":"address"},{"type":"address","name":"msgSender","internalType":"address"},{"type":"tuple","name":"transferInfo","internalType":"struct TransferInfo","components":[{"type":"address","name":"receiver","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"extraData","internalType":"bytes"}]}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateConnectorPoolId","inputs":[{"type":"address[]","name":"connectors","internalType":"address[]"},{"type":"uint256[]","name":"poolIds_","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateLimitParams","inputs":[{"type":"tuple[]","name":"updates","internalType":"struct UpdateLimitParams[]","components":[{"type":"bool","name":"isMint","internalType":"bool"},{"type":"address","name":"connector","internalType":"address"},{"type":"uint256","name":"maxLimit","internalType":"uint256"},{"type":"uint256","name":"ratePerSecond","internalType":"uint256"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updatePoolLockedAmounts","inputs":[{"type":"uint256[]","name":"poolIds_","internalType":"uint256[]"},{"type":"uint256[]","name":"amounts_","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"useControllerPools","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"vaultOrController","inputs":[]}]
              

Contract Creation Code

Verify & Publish
0x60c060405260016000553480156200001657600080fd5b50604051620032a1380380620032a18339810160408190526200003991620001b0565b828281806200004881620000e4565b50506001600160a01b038116608052620000837fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292538362000138565b505080151560a0527f3b7129f10106e202769096fb024bf2ffbeba2cd8f6d0fc43430d78dad12acb26600455620000db7f129109734c476f17817fbe7bcf461de566dcce58e4c0cb61b62d1b9af26fe47f8462000138565b50505062000202565b600180546001600160a01b0383166001600160a01b031991821681179092556002805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b60008281526003602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b80516001600160a01b0381168114620001ab57600080fd5b919050565b600080600060608486031215620001c657600080fd5b620001d18462000193565b9250620001e16020850162000193565b915060408401518015158114620001f757600080fd5b809150509250925092565b60805160a0516130336200026e6000396000818161048c015281816116850152611b1f01526000818161034201528181610519015281816105e601528181610fc0015281816113660152818161162c01528181611797015281816119f80152611ab001526130336000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c806374f86ade116100f9578063d4bbfea311610097578063e445e7dd11610071578063e445e7dd1461046b578063e73915c214610474578063f2f09c9614610487578063f59ad990146104ae57600080fd5b8063d4bbfea314610425578063d547741f14610445578063dd19fe381461045857600080fd5b806391d14854116100d357806391d14854146103c9578063af93f83b146103ec578063b5f1e82a146103ff578063cf36b9171461041257600080fd5b806374f86ade146103775780637afb99531461038a5780638da5cb5b146103ab57600080fd5b80633caef0f41161016657806362811bf21161014057806362811bf2146102d7578063629a0393146102f75780636651232a1461033d5780636ccae0541461036457600080fd5b80633caef0f41461029e57806352957178146102b15780635b94db27146102c457600080fd5b80632bc9c08a116101a25780632bc9c08a1461024e5780632f2ff15d1461026357806336cc21b8146102765780633bd1adec1461029657600080fd5b8063093c5eb1146101c95780631306ac3b146101ef57806320f99c0a1461020f575b600080fd5b6101dc6101d7366004612362565b6104cf565b6040519081526020015b60405180910390f35b6102026101fd36600461237f565b6105ba565b6040516101e69190612430565b60025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101e6565b61026161025c366004612490565b61089c565b005b610261610271366004612505565b610c19565b6101dc610284366004612362565b60086020526000908152604090205481565b610261610c78565b6102616102ac366004612581565b610cd4565b6101dc6102bf366004612362565b610e98565b6102616102d2366004612362565b610ecc565b6102ea6102e53660046127fe565b610f8c565b6040516101e6919061290d565b61030a610305366004612362565b611023565b6040516101e691908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b6102297f000000000000000000000000000000000000000000000000000000000000000081565b610261610372366004612920565b6110a9565b610261610385366004612581565b611147565b61039d610398366004612961565b6112c2565b6040516101e6929190612a38565b60015473ffffffffffffffffffffffffffffffffffffffff16610229565b6103dc6103d7366004612505565b61150d565b60405190151581526020016101e6565b61030a6103fa366004612362565b611545565b6101dc61040d366004612362565b6115cb565b61039d610420366004612a5d565b6115f9565b6101dc610433366004612b01565b60076020526000908152604090205481565b610261610453366004612505565b611710565b610202610466366004612b1a565b61176b565b6101dc60045481565b6101dc610482366004612b01565b6119af565b6103dc7f000000000000000000000000000000000000000000000000000000000000000081565b6104c16104bc366004612bea565b611a92565b6040516101e6929190612c62565b6040517f4b0a885400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff828116600483015260009182917f00000000000000000000000000000000000000000000000000000000000000001690634b0a8854906024016000604051808303816000875af1158015610562573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105a89190810190612c87565b90506105b381611b87565b9392505050565b60408051808201909152606080825260208201523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461063d576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000546001146106ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e43590000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6002600090815580806106c46040860186612cf5565b8101906106d19190612d5a565b919450925090507f8b3544fa225539b17e942d41841bf832b900055aa60660631db9559bbdcd8b366107066020870187612362565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291861660208381019190915290820185905260608201849052870135608082015260a00160405180910390a160006107aa6107626060880188612d8f565b610770906020810190612cf5565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b8792505050565b90506107b68382612dfc565b6040516020016107c891815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020868101919091528490839061080f90890189612362565b6040805173ffffffffffffffffffffffffffffffffffffffff9485166020820152908101929092529091166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528552600082900361088d5760408051600081526020810190915285525b50506001600055509092915050565b3360009081527fbd500bc6ab4a9bcd7eb9f453a5938fad0b08d3dbaae22ba7976ac385056bde2960205260409020547f129109734c476f17817fbe7bcf461de566dcce58e4c0cb61b62d1b9af26fe47f9060ff16610929576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024016106a5565b60005b82811015610bda5783838281811061094657610946612e13565b61095c9260206080909202019081019150612e52565b15610ac2576109d360006005600087878681811061097c5761097c612e13565b90506080020160200160208101906109949190612362565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020611bad565b50508383828181106109e7576109e7612e13565b9050608002016040013560056000868685818110610a0757610a07612e13565b9050608002016020016020810190610a1f9190612362565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002060020155838382818110610a5b57610a5b612e13565b9050608002016060013560056000868685818110610a7b57610a7b612e13565b9050608002016020016020810190610a939190612362565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002060010155610bc8565b610add60006006600087878681811061097c5761097c612e13565b5050838382818110610af157610af1612e13565b9050608002016040013560066000868685818110610b1157610b11612e13565b9050608002016020016020810190610b299190612362565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002060020155838382818110610b6557610b65612e13565b9050608002016060013560066000868685818110610b8557610b85612e13565b9050608002016020016020810190610b9d9190612362565b73ffffffffffffffffffffffffffffffffffffffff1681526020810191909152604001600020600101555b80610bd281612e6d565b91505061092c565b507f19863caed14ed012a54f927e56250018b7ac3c04fd197e0edf23369f75a6ccd48383604051610c0c929190612ea5565b60405180910390a1505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c6a576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c748282611c01565b5050565b60025473ffffffffffffffffffffffffffffffffffffffff163314610cc9576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cd233611c87565b565b60015473ffffffffffffffffffffffffffffffffffffffff163314610d25576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260005b81811015610e9057838382818110610d4357610d43612e13565b90506020020135600003610d83576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b838382818110610d9557610d95612e13565b9050602002013560086000888885818110610db257610db2612e13565b9050602002016020810190610dc79190612362565b73ffffffffffffffffffffffffffffffffffffffff1681526020810191909152604001600020557f0fdcc1015152882d3bf501506be25357c645aff7e0df94d2b21c45e102e81a0c868683818110610e2157610e21612e13565b9050602002016020810190610e369190612362565b858584818110610e4857610e48612e13565b6040805173ffffffffffffffffffffffffffffffffffffffff90951685526020918202939093013590840152500160405180910390a180610e8881612e6d565b915050610d29565b505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600660205260408120610ec690611d00565b92915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610f1d576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b604080516060808201835260008083526020830152918101919091523373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611017576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060608101515b919050565b61104e6040518060800160405280600081526020016000815260200160008152602001600081525090565b5073ffffffffffffffffffffffffffffffffffffffff16600090815260056020908152604091829020825160808101845281548152600182015492810192909252600281015492820192909252600390910154606082015290565b3360009081527f271b3e2292ab6fd3ff496cd98d6d375af02f11568a701741f48bba7789f13a7060205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff16611136576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024016106a5565b611141848484611d67565b50505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611198576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260005b81811015610e90578585828181106111b6576111b6612e13565b905060200201356000036111f6576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83838281811061120857611208612e13565b905060200201356007600088888581811061122557611225612e13565b905060200201358152602001908152602001600020819055507f6cc2f5d066d41fc5850125943b942623567700e44d15463154a87bb5d3332e9186868381811061127157611271612e13565b9050602002013585858481811061128a5761128a612e13565b905060200201356040516112a8929190918252602082015260400190565b60405180910390a1806112ba81612e6d565b91505061119c565b604080516060818101835260008083526020830152918101829052600054600114611349576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e43590000000000000000000000000000000000000000000060448201526064016106a5565b60026000553373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146113bd576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008560200151600001518060200190518101906113de9190612f28565b925092509250856000015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461144d576040517f5b0a758300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061145e886000015185611e5c565b6040805173ffffffffffffffffffffffffffffffffffffffff89166020820152908101839052606081018290529193509150608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815260608301825273ffffffffffffffffffffffffffffffffffffffff9097168252602082810194909452805193840181526000808552908201939093526001909255509296929550919350505050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166105b3565b6115706040518060800160405280600081526020016000815260200160008152602001600081525090565b5073ffffffffffffffffffffffffffffffffffffffff16600090815260066020908152604091829020825160808101845281548152600182015492810192909252600281015492820192909252600390910154606082015290565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600560205260408120610ec690611d00565b6040805160608181018352600080835260208301529181018290523373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611683576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000156116c1576116bf8360000151846040015160200151611efa565b505b6000806116da8560000151866040015160200151611e5c565b60408051602080820185905281830193909352815180820383018152606090910182529701519081019190915294959350505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611761576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c748282611f84565b60408051808201909152606080825260208201523373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146117ee576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008083606001518060200190518101906118099190612f6b565b91509150600061181c8560400151611b87565b9050811561195d576040805180820190915260808681015151875173ffffffffffffffffffffffffffffffffffffffff91821660608501529183018590521660a08201528060c08101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905281526020016118a28484612f8f565b6040516020016118b491815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815291528651608080890151516020808b0151855173ffffffffffffffffffffffffffffffffffffffff95861681529490921690840152828401889052606083018790529082015290519195507fec590f5738bffdca5d4fb4f9e9d902924be6ad3aedb5c5d0b39b208ea41c1e1b919081900360a00190a16119a7565b604080516060810182526000918101918252908152602081016119808484612f8f565b60405160200161199291815260200190565b60405160208183030381529060405281525093505b505050919050565b6040517ff290aafa00000000000000000000000000000000000000000000000000000000815260048101829052600090819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f290aafa906024016000604051808303816000875af1158015611a41573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611a879190810190612c87565b90506105b381612007565b604080516060808201835260008083526020830152918101829052907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314611b1d576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000015611b5957611b598360000151846040015160200151612030565b611b6f8360000151846040015160200151612100565b50506040908101518151602081019092526000825291565b805160009015611ba55781806020019051810190610ec69190612fa7565b506000919050565b6000806000611bbb84611d00565b4285559050848110611be257611bd18582612dfc565b600385015584925060009150611bf9565b60006003850155915081611bf68186612dfc565b91505b509250929050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092556002805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b80546000908190611d119042612dfc565b90506000836001015482611d259190612fc0565b90508360020154846003015482611d3c9190612f8f565b1115611d4e5783600201549250611d60565b6003840154611d5d9082612f8f565b92505b5050919050565b73ffffffffffffffffffffffffffffffffffffffff8216611db4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff841601611e0057611dfb8282612191565b505050565b8273ffffffffffffffffffffffffffffffffffffffff163b600003611e51576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dfb838383612206565b73ffffffffffffffffffffffffffffffffffffffff821660009081526005602052604081206002015481908103611ebf576040517fec914c0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600560205260409020611eef908490611bad565b909590945092505050565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260086020526040812054808203611f59576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260408120805493508491611f778386612f8f565b9091555091949350505050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b805160009015611ba5576000828060200190518101906120279190612f28565b50949350505050565b73ffffffffffffffffffffffffffffffffffffffff821660009081526008602052604081205490819003612090576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260409020548211156120d8576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260076020526040812080548492906120f6908490612dfc565b9091555050505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600660205260408120600201549003612161576040517fec914c0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600660205260409020610c749082906122d5565b600080600080600085875af1905080611dfb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c45440000000000000000000000000060448201526064016106a5565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080611141576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c4544000000000000000000000000000000000060448201526064016106a5565b60006122e082611d00565b9050828110612300574282556122f68382612dfc565b6003830155505050565b6040517f47ebad2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461235457600080fd5b50565b803561101e81612332565b60006020828403121561237457600080fd5b81356105b381612332565b60006020828403121561239157600080fd5b813567ffffffffffffffff8111156123a857600080fd5b8201608081850312156105b357600080fd5b60005b838110156123d55781810151838201526020016123bd565b838111156111415750506000910152565b600081518084526123fe8160208601602086016123ba565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600082516040602084015261244c60608401826123e6565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084830301604085015261248782826123e6565b95945050505050565b600080602083850312156124a357600080fd5b823567ffffffffffffffff808211156124bb57600080fd5b818501915085601f8301126124cf57600080fd5b8135818111156124de57600080fd5b8660208260071b85010111156124f357600080fd5b60209290920196919550909350505050565b6000806040838503121561251857600080fd5b82359150602083013561252a81612332565b809150509250929050565b60008083601f84011261254757600080fd5b50813567ffffffffffffffff81111561255f57600080fd5b6020830191508360208260051b850101111561257a57600080fd5b9250929050565b6000806000806040858703121561259757600080fd5b843567ffffffffffffffff808211156125af57600080fd5b6125bb88838901612535565b909650945060208701359150808211156125d457600080fd5b506125e187828801612535565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561263f5761263f6125ed565b60405290565b6040516080810167ffffffffffffffff8111828210171561263f5761263f6125ed565b6040805190810167ffffffffffffffff8111828210171561263f5761263f6125ed565b60405160a0810167ffffffffffffffff8111828210171561263f5761263f6125ed565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156126f5576126f56125ed565b604052919050565b600067ffffffffffffffff821115612717576127176125ed565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261275457600080fd5b8135612767612762826126fd565b6126ae565b81815284602083860101111561277c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000606082840312156127ab57600080fd5b6127b361261c565b905081356127c081612332565b815260208281013590820152604082013567ffffffffffffffff8111156127e657600080fd5b6127f284828501612743565b60408301525092915050565b60006020828403121561281057600080fd5b813567ffffffffffffffff8082111561282857600080fd5b908301906080828603121561283c57600080fd5b612844612645565b823561284f81612332565b815260208301358281111561286357600080fd5b61286f87828601612743565b60208301525060408301358281111561288757600080fd5b61289387828601612743565b6040830152506060830135828111156128ab57600080fd5b6128b787828601612799565b60608301525095945050505050565b73ffffffffffffffffffffffffffffffffffffffff815116825260208101516020830152600060408201516060604085015261290560608501826123e6565b949350505050565b6020815260006105b360208301846128c6565b60008060006060848603121561293557600080fd5b833561294081612332565b9250602084013561295081612332565b929592945050506040919091013590565b60006020828403121561297357600080fd5b813567ffffffffffffffff8082111561298b57600080fd5b908301906040828603121561299f57600080fd5b6129a7612668565b82356129b281612332565b81526020830135828111156129c657600080fd5b9290920191604083870312156129db57600080fd5b6129e3612668565b8335838111156129f257600080fd5b6129fe88828701612743565b825250602084013583811115612a1357600080fd5b612a1f88828701612743565b6020830152508060208301525080935050505092915050565b604081526000612a4b60408301856123e6565b828103602084015261248781856128c6565b600060208284031215612a6f57600080fd5b813567ffffffffffffffff80821115612a8757600080fd5b9083019060608286031215612a9b57600080fd5b612aa361261c565b8235612aae81612332565b8152602083013582811115612ac257600080fd5b612ace87828601612743565b602083015250604083013582811115612ae657600080fd5b612af287828601612799565b60408301525095945050505050565b600060208284031215612b1357600080fd5b5035919050565b600060208284031215612b2c57600080fd5b813567ffffffffffffffff80821115612b4457600080fd5b9083019060a08286031215612b5857600080fd5b612b6061268b565b612b6983612357565b815260208301356020820152604083013582811115612b8757600080fd5b612b9387828601612743565b604083015250606083013582811115612bab57600080fd5b612bb787828601612743565b606083015250608083013582811115612bcf57600080fd5b612bdb87828601612799565b60808301525095945050505050565b600060208284031215612bfc57600080fd5b813567ffffffffffffffff80821115612c1457600080fd5b9083019060608286031215612c2857600080fd5b612c3061261c565b8235612c3b81612332565b81526020830135612c4b81612332565b6020820152604083013582811115612ae657600080fd5b604081526000612c7560408301856128c6565b828103602084015261248781856123e6565b600060208284031215612c9957600080fd5b815167ffffffffffffffff811115612cb057600080fd5b8201601f81018413612cc157600080fd5b8051612ccf612762826126fd565b818152856020838501011115612ce457600080fd5b6124878260208301602086016123ba565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612d2a57600080fd5b83018035915067ffffffffffffffff821115612d4557600080fd5b60200191503681900382131561257a57600080fd5b600080600060608486031215612d6f57600080fd5b8335612d7a81612332565b95602085013595506040909401359392505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112612dc357600080fd5b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015612e0e57612e0e612dcd565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8035801515811461101e57600080fd5b600060208284031215612e6457600080fd5b6105b382612e42565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612e9e57612e9e612dcd565b5060010190565b6020808252818101839052600090604080840186845b87811015612f1b57612ecc82612e42565b1515835284820135612edd81612332565b73ffffffffffffffffffffffffffffffffffffffff168386015281840135848401526060808301359084015260809283019290910190600101612ebb565b5090979650505050505050565b600080600060608486031215612f3d57600080fd5b8351612f4881612332565b602085015160408601519194509250612f6081612332565b809150509250925092565b60008060408385031215612f7e57600080fd5b505080516020909101519092909150565b60008219821115612fa257612fa2612dcd565b500190565b600060208284031215612fb957600080fd5b5051919050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612ff857612ff8612dcd565b50029056fea2646970667358221220a13ccb40499af75f6380cffdc976428f7edc0a7ca6844e5b2f2e9a75df2b0fa764736f6c634300080d003300000000000000000000000044a44837894b5edc2bde64567fc62599b3b88f4c000000000000000000000000b5b1e1ba18d323a2a7313f970bf4310cf8d60b8d0000000000000000000000000000000000000000000000000000000000000001

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101c45760003560e01c806374f86ade116100f9578063d4bbfea311610097578063e445e7dd11610071578063e445e7dd1461046b578063e73915c214610474578063f2f09c9614610487578063f59ad990146104ae57600080fd5b8063d4bbfea314610425578063d547741f14610445578063dd19fe381461045857600080fd5b806391d14854116100d357806391d14854146103c9578063af93f83b146103ec578063b5f1e82a146103ff578063cf36b9171461041257600080fd5b806374f86ade146103775780637afb99531461038a5780638da5cb5b146103ab57600080fd5b80633caef0f41161016657806362811bf21161014057806362811bf2146102d7578063629a0393146102f75780636651232a1461033d5780636ccae0541461036457600080fd5b80633caef0f41461029e57806352957178146102b15780635b94db27146102c457600080fd5b80632bc9c08a116101a25780632bc9c08a1461024e5780632f2ff15d1461026357806336cc21b8146102765780633bd1adec1461029657600080fd5b8063093c5eb1146101c95780631306ac3b146101ef57806320f99c0a1461020f575b600080fd5b6101dc6101d7366004612362565b6104cf565b6040519081526020015b60405180910390f35b6102026101fd36600461237f565b6105ba565b6040516101e69190612430565b60025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101e6565b61026161025c366004612490565b61089c565b005b610261610271366004612505565b610c19565b6101dc610284366004612362565b60086020526000908152604090205481565b610261610c78565b6102616102ac366004612581565b610cd4565b6101dc6102bf366004612362565b610e98565b6102616102d2366004612362565b610ecc565b6102ea6102e53660046127fe565b610f8c565b6040516101e6919061290d565b61030a610305366004612362565b611023565b6040516101e691908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b6102297f000000000000000000000000b5b1e1ba18d323a2a7313f970bf4310cf8d60b8d81565b610261610372366004612920565b6110a9565b610261610385366004612581565b611147565b61039d610398366004612961565b6112c2565b6040516101e6929190612a38565b60015473ffffffffffffffffffffffffffffffffffffffff16610229565b6103dc6103d7366004612505565b61150d565b60405190151581526020016101e6565b61030a6103fa366004612362565b611545565b6101dc61040d366004612362565b6115cb565b61039d610420366004612a5d565b6115f9565b6101dc610433366004612b01565b60076020526000908152604090205481565b610261610453366004612505565b611710565b610202610466366004612b1a565b61176b565b6101dc60045481565b6101dc610482366004612b01565b6119af565b6103dc7f000000000000000000000000000000000000000000000000000000000000000181565b6104c16104bc366004612bea565b611a92565b6040516101e6929190612c62565b6040517f4b0a885400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff828116600483015260009182917f000000000000000000000000b5b1e1ba18d323a2a7313f970bf4310cf8d60b8d1690634b0a8854906024016000604051808303816000875af1158015610562573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105a89190810190612c87565b90506105b381611b87565b9392505050565b60408051808201909152606080825260208201523373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b5b1e1ba18d323a2a7313f970bf4310cf8d60b8d161461063d576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000546001146106ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e43590000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6002600090815580806106c46040860186612cf5565b8101906106d19190612d5a565b919450925090507f8b3544fa225539b17e942d41841bf832b900055aa60660631db9559bbdcd8b366107066020870187612362565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291861660208381019190915290820185905260608201849052870135608082015260a00160405180910390a160006107aa6107626060880188612d8f565b610770906020810190612cf5565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b8792505050565b90506107b68382612dfc565b6040516020016107c891815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020868101919091528490839061080f90890189612362565b6040805173ffffffffffffffffffffffffffffffffffffffff9485166020820152908101929092529091166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528552600082900361088d5760408051600081526020810190915285525b50506001600055509092915050565b3360009081527fbd500bc6ab4a9bcd7eb9f453a5938fad0b08d3dbaae22ba7976ac385056bde2960205260409020547f129109734c476f17817fbe7bcf461de566dcce58e4c0cb61b62d1b9af26fe47f9060ff16610929576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024016106a5565b60005b82811015610bda5783838281811061094657610946612e13565b61095c9260206080909202019081019150612e52565b15610ac2576109d360006005600087878681811061097c5761097c612e13565b90506080020160200160208101906109949190612362565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020611bad565b50508383828181106109e7576109e7612e13565b9050608002016040013560056000868685818110610a0757610a07612e13565b9050608002016020016020810190610a1f9190612362565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002060020155838382818110610a5b57610a5b612e13565b9050608002016060013560056000868685818110610a7b57610a7b612e13565b9050608002016020016020810190610a939190612362565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002060010155610bc8565b610add60006006600087878681811061097c5761097c612e13565b5050838382818110610af157610af1612e13565b9050608002016040013560066000868685818110610b1157610b11612e13565b9050608002016020016020810190610b299190612362565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002060020155838382818110610b6557610b65612e13565b9050608002016060013560066000868685818110610b8557610b85612e13565b9050608002016020016020810190610b9d9190612362565b73ffffffffffffffffffffffffffffffffffffffff1681526020810191909152604001600020600101555b80610bd281612e6d565b91505061092c565b507f19863caed14ed012a54f927e56250018b7ac3c04fd197e0edf23369f75a6ccd48383604051610c0c929190612ea5565b60405180910390a1505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c6a576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c748282611c01565b5050565b60025473ffffffffffffffffffffffffffffffffffffffff163314610cc9576040517f7c91ccdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cd233611c87565b565b60015473ffffffffffffffffffffffffffffffffffffffff163314610d25576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260005b81811015610e9057838382818110610d4357610d43612e13565b90506020020135600003610d83576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b838382818110610d9557610d95612e13565b9050602002013560086000888885818110610db257610db2612e13565b9050602002016020810190610dc79190612362565b73ffffffffffffffffffffffffffffffffffffffff1681526020810191909152604001600020557f0fdcc1015152882d3bf501506be25357c645aff7e0df94d2b21c45e102e81a0c868683818110610e2157610e21612e13565b9050602002016020810190610e369190612362565b858584818110610e4857610e48612e13565b6040805173ffffffffffffffffffffffffffffffffffffffff90951685526020918202939093013590840152500160405180910390a180610e8881612e6d565b915050610d29565b505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600660205260408120610ec690611d00565b92915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610f1d576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b604080516060808201835260008083526020830152918101919091523373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b5b1e1ba18d323a2a7313f970bf4310cf8d60b8d1614611017576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060608101515b919050565b61104e6040518060800160405280600081526020016000815260200160008152602001600081525090565b5073ffffffffffffffffffffffffffffffffffffffff16600090815260056020908152604091829020825160808101845281548152600182015492810192909252600281015492820192909252600390910154606082015290565b3360009081527f271b3e2292ab6fd3ff496cd98d6d375af02f11568a701741f48bba7789f13a7060205260409020547fc4c453d647953c0fd35db5a34ee76e60fb4abc3a8fb891a25936b70b38f292539060ff16611136576040517f962f6333000000000000000000000000000000000000000000000000000000008152600481018290526024016106a5565b611141848484611d67565b50505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611198576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260005b81811015610e90578585828181106111b6576111b6612e13565b905060200201356000036111f6576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83838281811061120857611208612e13565b905060200201356007600088888581811061122557611225612e13565b905060200201358152602001908152602001600020819055507f6cc2f5d066d41fc5850125943b942623567700e44d15463154a87bb5d3332e9186868381811061127157611271612e13565b9050602002013585858481811061128a5761128a612e13565b905060200201356040516112a8929190918252602082015260400190565b60405180910390a1806112ba81612e6d565b91505061119c565b604080516060818101835260008083526020830152918101829052600054600114611349576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e43590000000000000000000000000000000000000000000060448201526064016106a5565b60026000553373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b5b1e1ba18d323a2a7313f970bf4310cf8d60b8d16146113bd576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008560200151600001518060200190518101906113de9190612f28565b925092509250856000015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461144d576040517f5b0a758300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061145e886000015185611e5c565b6040805173ffffffffffffffffffffffffffffffffffffffff89166020820152908101839052606081018290529193509150608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815260608301825273ffffffffffffffffffffffffffffffffffffffff9097168252602082810194909452805193840181526000808552908201939093526001909255509296929550919350505050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166105b3565b6115706040518060800160405280600081526020016000815260200160008152602001600081525090565b5073ffffffffffffffffffffffffffffffffffffffff16600090815260066020908152604091829020825160808101845281548152600182015492810192909252600281015492820192909252600390910154606082015290565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600560205260408120610ec690611d00565b6040805160608181018352600080835260208301529181018290523373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b5b1e1ba18d323a2a7313f970bf4310cf8d60b8d1614611683576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000001156116c1576116bf8360000151846040015160200151611efa565b505b6000806116da8560000151866040015160200151611e5c565b60408051602080820185905281830193909352815180820383018152606090910182529701519081019190915294959350505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611761576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c748282611f84565b60408051808201909152606080825260208201523373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b5b1e1ba18d323a2a7313f970bf4310cf8d60b8d16146117ee576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008083606001518060200190518101906118099190612f6b565b91509150600061181c8560400151611b87565b9050811561195d576040805180820190915260808681015151875173ffffffffffffffffffffffffffffffffffffffff91821660608501529183018590521660a08201528060c08101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905281526020016118a28484612f8f565b6040516020016118b491815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815291528651608080890151516020808b0151855173ffffffffffffffffffffffffffffffffffffffff95861681529490921690840152828401889052606083018790529082015290519195507fec590f5738bffdca5d4fb4f9e9d902924be6ad3aedb5c5d0b39b208ea41c1e1b919081900360a00190a16119a7565b604080516060810182526000918101918252908152602081016119808484612f8f565b60405160200161199291815260200190565b60405160208183030381529060405281525093505b505050919050565b6040517ff290aafa00000000000000000000000000000000000000000000000000000000815260048101829052600090819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b5b1e1ba18d323a2a7313f970bf4310cf8d60b8d169063f290aafa906024016000604051808303816000875af1158015611a41573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611a879190810190612c87565b90506105b381612007565b604080516060808201835260008083526020830152918101829052907f000000000000000000000000b5b1e1ba18d323a2a7313f970bf4310cf8d60b8d73ffffffffffffffffffffffffffffffffffffffff163314611b1d576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000115611b5957611b598360000151846040015160200151612030565b611b6f8360000151846040015160200151612100565b50506040908101518151602081019092526000825291565b805160009015611ba55781806020019051810190610ec69190612fa7565b506000919050565b6000806000611bbb84611d00565b4285559050848110611be257611bd18582612dfc565b600385015584925060009150611bf9565b60006003850155915081611bf68186612dfc565b91505b509250929050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551909184917f2ae6a113c0ed5b78a53413ffbb7679881f11145ccfba4fb92e863dfcd5a1d2f39190a35050565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092556002805490911690556040517ffbe19c9b601f5ee90b44c7390f3fa2319eba01762d34ee372aeafd59b25c7f8790600090a250565b80546000908190611d119042612dfc565b90506000836001015482611d259190612fc0565b90508360020154846003015482611d3c9190612f8f565b1115611d4e5783600201549250611d60565b6003840154611d5d9082612f8f565b92505b5050919050565b73ffffffffffffffffffffffffffffffffffffffff8216611db4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff841601611e0057611dfb8282612191565b505050565b8273ffffffffffffffffffffffffffffffffffffffff163b600003611e51576040517f1eb00b0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dfb838383612206565b73ffffffffffffffffffffffffffffffffffffffff821660009081526005602052604081206002015481908103611ebf576040517fec914c0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600560205260409020611eef908490611bad565b909590945092505050565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260086020526040812054808203611f59576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260408120805493508491611f778386612f8f565b9091555091949350505050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551909184917f155aaafb6329a2098580462df33ec4b7441b19729b9601c5fc17ae1cf99a8a529190a35050565b805160009015611ba5576000828060200190518101906120279190612f28565b50949350505050565b73ffffffffffffffffffffffffffffffffffffffff821660009081526008602052604081205490819003612090576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260409020548211156120d8576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260076020526040812080548492906120f6908490612dfc565b9091555050505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600660205260408120600201549003612161576040517fec914c0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600660205260409020610c749082906122d5565b600080600080600085875af1905080611dfb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c45440000000000000000000000000060448201526064016106a5565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080611141576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c4544000000000000000000000000000000000060448201526064016106a5565b60006122e082611d00565b9050828110612300574282556122f68382612dfc565b6003830155505050565b6040517f47ebad2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461235457600080fd5b50565b803561101e81612332565b60006020828403121561237457600080fd5b81356105b381612332565b60006020828403121561239157600080fd5b813567ffffffffffffffff8111156123a857600080fd5b8201608081850312156105b357600080fd5b60005b838110156123d55781810151838201526020016123bd565b838111156111415750506000910152565b600081518084526123fe8160208601602086016123ba565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600082516040602084015261244c60608401826123e6565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084830301604085015261248782826123e6565b95945050505050565b600080602083850312156124a357600080fd5b823567ffffffffffffffff808211156124bb57600080fd5b818501915085601f8301126124cf57600080fd5b8135818111156124de57600080fd5b8660208260071b85010111156124f357600080fd5b60209290920196919550909350505050565b6000806040838503121561251857600080fd5b82359150602083013561252a81612332565b809150509250929050565b60008083601f84011261254757600080fd5b50813567ffffffffffffffff81111561255f57600080fd5b6020830191508360208260051b850101111561257a57600080fd5b9250929050565b6000806000806040858703121561259757600080fd5b843567ffffffffffffffff808211156125af57600080fd5b6125bb88838901612535565b909650945060208701359150808211156125d457600080fd5b506125e187828801612535565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561263f5761263f6125ed565b60405290565b6040516080810167ffffffffffffffff8111828210171561263f5761263f6125ed565b6040805190810167ffffffffffffffff8111828210171561263f5761263f6125ed565b60405160a0810167ffffffffffffffff8111828210171561263f5761263f6125ed565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156126f5576126f56125ed565b604052919050565b600067ffffffffffffffff821115612717576127176125ed565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261275457600080fd5b8135612767612762826126fd565b6126ae565b81815284602083860101111561277c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000606082840312156127ab57600080fd5b6127b361261c565b905081356127c081612332565b815260208281013590820152604082013567ffffffffffffffff8111156127e657600080fd5b6127f284828501612743565b60408301525092915050565b60006020828403121561281057600080fd5b813567ffffffffffffffff8082111561282857600080fd5b908301906080828603121561283c57600080fd5b612844612645565b823561284f81612332565b815260208301358281111561286357600080fd5b61286f87828601612743565b60208301525060408301358281111561288757600080fd5b61289387828601612743565b6040830152506060830135828111156128ab57600080fd5b6128b787828601612799565b60608301525095945050505050565b73ffffffffffffffffffffffffffffffffffffffff815116825260208101516020830152600060408201516060604085015261290560608501826123e6565b949350505050565b6020815260006105b360208301846128c6565b60008060006060848603121561293557600080fd5b833561294081612332565b9250602084013561295081612332565b929592945050506040919091013590565b60006020828403121561297357600080fd5b813567ffffffffffffffff8082111561298b57600080fd5b908301906040828603121561299f57600080fd5b6129a7612668565b82356129b281612332565b81526020830135828111156129c657600080fd5b9290920191604083870312156129db57600080fd5b6129e3612668565b8335838111156129f257600080fd5b6129fe88828701612743565b825250602084013583811115612a1357600080fd5b612a1f88828701612743565b6020830152508060208301525080935050505092915050565b604081526000612a4b60408301856123e6565b828103602084015261248781856128c6565b600060208284031215612a6f57600080fd5b813567ffffffffffffffff80821115612a8757600080fd5b9083019060608286031215612a9b57600080fd5b612aa361261c565b8235612aae81612332565b8152602083013582811115612ac257600080fd5b612ace87828601612743565b602083015250604083013582811115612ae657600080fd5b612af287828601612799565b60408301525095945050505050565b600060208284031215612b1357600080fd5b5035919050565b600060208284031215612b2c57600080fd5b813567ffffffffffffffff80821115612b4457600080fd5b9083019060a08286031215612b5857600080fd5b612b6061268b565b612b6983612357565b815260208301356020820152604083013582811115612b8757600080fd5b612b9387828601612743565b604083015250606083013582811115612bab57600080fd5b612bb787828601612743565b606083015250608083013582811115612bcf57600080fd5b612bdb87828601612799565b60808301525095945050505050565b600060208284031215612bfc57600080fd5b813567ffffffffffffffff80821115612c1457600080fd5b9083019060608286031215612c2857600080fd5b612c3061261c565b8235612c3b81612332565b81526020830135612c4b81612332565b6020820152604083013582811115612ae657600080fd5b604081526000612c7560408301856128c6565b828103602084015261248781856123e6565b600060208284031215612c9957600080fd5b815167ffffffffffffffff811115612cb057600080fd5b8201601f81018413612cc157600080fd5b8051612ccf612762826126fd565b818152856020838501011115612ce457600080fd5b6124878260208301602086016123ba565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612d2a57600080fd5b83018035915067ffffffffffffffff821115612d4557600080fd5b60200191503681900382131561257a57600080fd5b600080600060608486031215612d6f57600080fd5b8335612d7a81612332565b95602085013595506040909401359392505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112612dc357600080fd5b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015612e0e57612e0e612dcd565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8035801515811461101e57600080fd5b600060208284031215612e6457600080fd5b6105b382612e42565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612e9e57612e9e612dcd565b5060010190565b6020808252818101839052600090604080840186845b87811015612f1b57612ecc82612e42565b1515835284820135612edd81612332565b73ffffffffffffffffffffffffffffffffffffffff168386015281840135848401526060808301359084015260809283019290910190600101612ebb565b5090979650505050505050565b600080600060608486031215612f3d57600080fd5b8351612f4881612332565b602085015160408601519194509250612f6081612332565b809150509250925092565b60008060408385031215612f7e57600080fd5b505080516020909101519092909150565b60008219821115612fa257612fa2612dcd565b500190565b600060208284031215612fb957600080fd5b5051919050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612ff857612ff8612dcd565b50029056fea2646970667358221220a13ccb40499af75f6380cffdc976428f7edc0a7ca6844e5b2f2e9a75df2b0fa764736f6c634300080d0033