ETH Price: $2,119.45 (-2.25%)

Contract

0xF5d225C8027CAa293c0302Aa98CF8E437caEc4E9
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

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

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

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

Contract Source Code Verified (Exact Match)

Contract Name:
MultiLockMintERC721Pool

Compiler Version
v0.8.29+commit.ab55807c

Optimization Enabled:
Yes with 10 runs

Other Settings:
cancun EvmVersion, Unlicense license
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";

import {TokenPool} from "src/pools/TokenPool.sol";
import {MultiTokenPool} from "src/pools/MultiTokenPool.sol";
import {LockMintERC721Pool} from "src/pools/erc721/LockMintERC721Pool.sol";

import {IMultiLockMintERC721Pool} from "src/interfaces/pools/erc721/IMultiLockMintERC721Pool.sol";
import {Pool} from "src/libraries/Pool.sol";

contract MultiLockMintERC721Pool is MultiTokenPool, LockMintERC721Pool, IMultiLockMintERC721Pool {
    string public constant override typeAndVersion = "MultiLockMintERC721Pool 1.0.0";

    constructor() {
        _disableInitializers();
    }

    function initialize(address admin, address router, uint64 currentChainSelector) external initializer {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        __PausableExtended_init(admin);
        __RateLimitConsumer_init(admin);
        __SharedStorageConsumer_init(admin);
        __TokenPool_init(admin, router, currentChainSelector);
    }

    /**
     * @inheritdoc IMultiLockMintERC721Pool
     */
    function withdrawLiquidity(address[] calldata localTokens, address[] calldata tos, uint256[] calldata ids)
        external
        onlyRole(DEFAULT_ADMIN_ROLE)
    {
        uint256 tokenCount = localTokens.length;
        _requireEqualLength(tokenCount, ids.length);
        _requireEqualLength(tokenCount, tos.length);
        _requireNonZero(tokenCount);

        for (uint256 i; i < tokenCount; ++i) {
            _requireLocalToken(localTokens[i]);
            _requireNonZero(tos[i]);

            IERC721(localTokens[i]).transferFrom(address(this), tos[i], ids[i]);
        }
    }

    /**
     * @inheritdoc IMultiLockMintERC721Pool
     */
    function crossTransfer(
        address localToken,
        uint64 remoteChainSelector,
        address to,
        uint256 id,
        address feeToken,
        uint256 gasLimit
    ) external payable returns (bytes32 messageId) {
        return _crossBatchTransfer(localToken, remoteChainSelector, to, _toSingletonArray(id), feeToken, gasLimit);
    }

    /**
     * @inheritdoc IMultiLockMintERC721Pool
     */
    function crossBatchTransfer(
        address localToken,
        uint64 remoteChainSelector,
        address to,
        uint256[] calldata ids,
        address feeToken,
        uint256 gasLimit
    ) external payable returns (bytes32 messageId) {
        return _crossBatchTransfer(localToken, remoteChainSelector, to, ids, feeToken, gasLimit);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(MultiTokenPool, LockMintERC721Pool)
        returns (bool)
    {
        return interfaceId == type(IMultiLockMintERC721Pool).interfaceId
            || LockMintERC721Pool.supportsInterface(interfaceId) || MultiTokenPool.supportsInterface(interfaceId);
    }

    function _releaseOrMint(Pool.ReleaseOrMint memory releaseOrMint)
        internal
        virtual
        override(TokenPool, LockMintERC721Pool)
    {
        // Prevent the case when localToken is mapped to many remote chains
        // and the message is sent to from the remote chain that is unmapped with the localToken
        _requireNonZero(getRemoteToken(releaseOrMint.localToken, releaseOrMint.remoteChainSelector));
        super._releaseOrMint(releaseOrMint);
    }

    function _crossBatchTransfer(
        address localToken,
        uint64 remoteChainSelector,
        address to,
        uint256[] memory ids,
        address feeToken,
        uint256 gasLimit
    ) internal nonZero(to) returns (bytes32 messageId) {
        bytes memory data = abi.encode(ids);
        _lockOrBurn(
            Pool.LockOrBurn({remoteChainSelector: remoteChainSelector, localToken: localToken, extraData: data})
        );

        address remoteToken = getRemoteToken(localToken, remoteChainSelector);
        _requireNonZero(remoteToken);
        messageId = _sendDataPayFeeToken({
            remoteChainSelector: remoteChainSelector,
            receiver: getRemotePool(remoteChainSelector),
            data: abi.encode(
                Pool.ReleaseOrMint({
                    originalSender: msg.sender,
                    remoteChainSelector: getCurrentChainSelector(),
                    receiver: to,
                    localToken: remoteToken,
                    remotePoolAddress: address(this),
                    remotePoolData: data
                })
            ),
            gasLimit: gasLimit,
            allowOutOfOrderExecution: true,
            feeToken: feeToken
        });
        _storeMessageId(getCurrentChainSelector(), messageId);
    }

    function _toSingletonArray(uint256 id) internal pure returns (uint256[] memory ids) {
        ids = new uint256[](1);
        ids[0] = id;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {ITypeAndVersion} from "@chainlink/contracts-ccip/src/v0.8/shared/interfaces/ITypeAndVersion.sol";

import {AccessControlEnumerableUpgradeable} from
    "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";

import {CCIPSenderReceiverUpgradeable} from "src/extensions/CCIPSenderReceiverUpgradeable.sol";

import {ITokenPool} from "src/interfaces/pools/ITokenPool.sol";
import {Pool} from "src/libraries/Pool.sol";

abstract contract TokenPool is AccessControlEnumerableUpgradeable, CCIPSenderReceiverUpgradeable, ITokenPool {
    bytes32 public constant TOKEN_POOL_OWNER_ROLE = keccak256("TOKEN_POOL_OWNER_ROLE");

    /// @dev Gap for future upgrades
    uint256[50] private __gap1;

    /// @dev Mapping of chain selector to array of message IDs
    mapping(uint64 chainSelector => bytes32[] messageIds) private s_messageIds;
    /// @dev Mapping of chain selector to exists mapping of message IDs
    mapping(uint64 chainSelector => mapping(bytes32 messageId => bool exists)) private s_messageIdExists;

    /// @dev Gap for future upgrades
    uint256[50] private __gap2;

    modifier onlyLocalToken(address localToken) {
        _requireLocalToken(localToken);
        _;
    }

    function __TokenPool_init(address owner, address router, uint64 currentChainSelector) internal onlyInitializing {
        __TokenPool_init_unchained(owner);
        __CCIPSenderReceiver_init(router, currentChainSelector);
    }

    function __TokenPool_init_unchained(address owner) internal onlyInitializing {
        _grantRole(TOKEN_POOL_OWNER_ROLE, owner);
    }

    /**
     * @inheritdoc ITokenPool
     */
    function addRemotePool(uint64 remoteChainSelector, address remotePool) external onlyRole(TOKEN_POOL_OWNER_ROLE) {
        _addRemoteChain(remoteChainSelector, remotePool);
        emit RemotePoolAdded(msg.sender, remoteChainSelector, remotePool);
    }

    /**
     * @inheritdoc ITokenPool
     */
    function removeRemotePool(uint64 remoteChainSelector) external onlyRole(TOKEN_POOL_OWNER_ROLE) {
        _removeRemoteChain(remoteChainSelector);
        emit RemotePoolRemoved(msg.sender, remoteChainSelector);
    }

    /**
     * @inheritdoc ITokenPool
     */
    function mapRemoteToken(address localToken, uint64 remoteChainSelector, address remoteToken)
        external
        onlyRole(TOKEN_POOL_OWNER_ROLE)
        nonZero(localToken)
        onlyEnabledChain(remoteChainSelector)
    {
        _requireNonZero(remoteToken);
        _mapRemoteToken(localToken, remoteChainSelector, remoteToken);
        emit RemoteTokenMapped(msg.sender, remoteChainSelector, localToken, remoteToken);
    }

    /**
     * @inheritdoc ITokenPool
     */
    function unmapRemoteToken(address localToken, uint64 remoteChainSelector)
        external
        onlyRole(TOKEN_POOL_OWNER_ROLE)
        onlyEnabledChain(remoteChainSelector)
    {
        _unmapRemoteToken(localToken, remoteChainSelector);
        emit RemoteTokenUnmapped(msg.sender, remoteChainSelector, localToken);
    }

    /**
     * @inheritdoc ITokenPool
     */
    function getRemotePool(uint64 remoteChainSelector) public view returns (address remotePool) {
        return _getRemoteSender(remoteChainSelector);
    }

    /**
     * @inheritdoc ITokenPool
     */
    function getRemotePools()
        external
        view
        returns (uint64[] memory remoteChainSelectors, address[] memory remotePools)
    {
        remoteChainSelectors = getSupportedChains();
        uint256 length = remoteChainSelectors.length;
        remotePools = new address[](length);

        for (uint256 i; i < length; ++i) {
            remotePools[i] = getRemotePool(remoteChainSelectors[i]);
        }
    }

    /**
     * @inheritdoc ITokenPool
     */
    function getMessageIds(uint64 chainSelector, uint256 offset, uint256 limit)
        external
        view
        returns (uint256 length, bytes32[] memory messageIds)
    {
        length = s_messageIds[chainSelector].length;

        if (offset >= length) return (length, new bytes32[](0));
        if (offset + limit > length) limit = length - offset;

        messageIds = new bytes32[](limit);
        for (uint256 i; i < limit; ++i) {
            messageIds[i] = s_messageIds[chainSelector][offset + i];
        }
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(AccessControlEnumerableUpgradeable, CCIPSenderReceiverUpgradeable)
        returns (bool)
    {
        return interfaceId == type(ITypeAndVersion).interfaceId || interfaceId == type(ITokenPool).interfaceId
            || super.supportsInterface(interfaceId);
    }

    function _storeMessageId(uint64 chainSelector, bytes32 messageId) internal {
        if (s_messageIdExists[chainSelector][messageId]) revert MessageIdAlreadyExists(chainSelector, messageId);
        s_messageIds[chainSelector].push(messageId);
        s_messageIdExists[chainSelector][messageId] = true;
    }

    /**
     * @dev Virtual function to be implemented by derived contracts to handle the lock or burn operation.
     */
    function _lockOrBurn(Pool.LockOrBurn memory lockOrBurn) internal virtual;

    /**
     * @dev Virtual function to be implemented by derived contracts to handle the release or mint operation.
     */
    function _releaseOrMint(Pool.ReleaseOrMint memory releaseOrMint) internal virtual;

    /**
     * @dev Virtual function to be implemented by derived contracts to handle the mapping of remote tokens.
     */
    function _mapRemoteToken(address localToken, uint64 remoteChainSelector, address remoteToken) internal virtual;

    /**
     * @dev Virtual function to be implemented by derived contracts to handle the unmapping of remote tokens.
     */
    function _unmapRemoteToken(address localToken, uint64 remoteChainSelector) internal virtual;

    /**
     * @dev Internal function to require that the local token is supported by the pool.
     */
    function _requireLocalToken(address localToken) internal view virtual;
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

import {TokenPool} from "src/pools/TokenPool.sol";
import {ITokenPool} from "src/interfaces/pools/ITokenPool.sol";
import {IMultiTokenPool} from "src/interfaces/pools/IMultiTokenPool.sol";

abstract contract MultiTokenPool is TokenPool, IMultiTokenPool {
    using EnumerableSet for EnumerableSet.AddressSet;

    /// @dev Gap for future upgrades
    uint256[50] private __gap1;

    /// @dev The set of local tokens.
    EnumerableSet.AddressSet private s_localTokens;
    /// @dev The mapping of local token address => remote chain selector => remote token address.
    mapping(address local => mapping(uint64 remoteChainSelector => address)) private s_remoteTokens;

    /// @dev Gap for future upgrades
    uint256[50] private __gap2;

    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IMultiTokenPool).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @inheritdoc IMultiTokenPool
     */
    function getSupportedTokensForChain(uint64 remoteChainSelector)
        public
        view
        returns (address[] memory localTokens, address[] memory remoteTokens)
    {
        if (!isSupportedChain(remoteChainSelector)) return (new address[](0), new address[](0));

        uint256 tokenCount = s_localTokens.length();
        localTokens = new address[](tokenCount);
        remoteTokens = new address[](tokenCount);
        uint256 count;

        for (uint256 i; i < tokenCount; ++i) {
            address localToken = s_localTokens.at(i);
            address remoteToken = s_remoteTokens[localToken][remoteChainSelector];
            if (remoteToken != address(0)) {
                localTokens[count] = localToken;
                remoteTokens[count] = remoteToken;
                ++count;
            }
        }

        assembly ("memory-safe") {
            mstore(localTokens, count)
            mstore(remoteTokens, count)
        }
    }

    /**
     * @inheritdoc IMultiTokenPool
     */
    function getTokens() public view returns (address[] memory localTokens) {
        address[] memory tokenSet = s_localTokens.values();
        uint256 tokenCount = tokenSet.length;

        localTokens = new address[](tokenCount);
        uint256 count;
        for (uint256 i; i < tokenCount; ++i) {
            if (isSupportedToken(tokenSet[i])) {
                localTokens[count++] = tokenSet[i];
            }
        }

        assembly ("memory-safe") {
            mstore(localTokens, count)
        }
    }

    /**
     * @inheritdoc ITokenPool
     */
    function isSupportedToken(address localToken) public view virtual override returns (bool yes) {
        // Short circuit if the token is not in the set
        if (!s_localTokens.contains(localToken)) return false;

        // Check if the token has a mapping on any enabled chain
        uint64[] memory supportedChains = getSupportedChains();
        uint256 chainCount = supportedChains.length;

        for (uint256 i; i < chainCount; ++i) {
            if (getRemoteToken(localToken, supportedChains[i]) != address(0)) {
                return true;
            }
        }

        return false;
    }

    /**
     * @inheritdoc IMultiTokenPool
     */
    function getRemoteToken(address localToken, uint64 remoteChainSelector) public view returns (address remoteToken) {
        if (!isSupportedChain(remoteChainSelector)) return address(0);
        return s_remoteTokens[localToken][remoteChainSelector];
    }

    /**
     * @dev See {ITokenPool-mapRemoteToken}.
     */
    function _mapRemoteToken(address localToken, uint64 remoteChainSelector, address remoteToken)
        internal
        virtual
        override
    {
        // Check if the remote token is already mapped to the local token
        (address[] memory existingLocalTokens, address[] memory existingRemoteTokens) =
            getSupportedTokensForChain(remoteChainSelector);
        if (existingRemoteTokens.length > 0) {
            for (uint256 i; i < existingRemoteTokens.length; ++i) {
                if (existingRemoteTokens[i] == remoteToken) {
                    revert TokenAlreadyMapped(existingLocalTokens[i], remoteToken);
                }
            }
        }

        s_localTokens.add(localToken);
        s_remoteTokens[localToken][remoteChainSelector] = remoteToken;
    }

    /**
     * @dev See {ITokenPool-unmapRemoteToken}.
     */
    function _unmapRemoteToken(address localToken, uint64 remoteChainSelector) internal virtual override {
        address remoteToken = s_remoteTokens[localToken][remoteChainSelector];
        if (remoteToken == address(0)) revert TokenNotMapped(localToken, remoteChainSelector);
        delete s_remoteTokens[localToken][remoteChainSelector];

        // If the token is not mapped to any other chain, remove it from the set
        if (!isSupportedToken(localToken)) s_localTokens.remove(localToken);
    }

    /**
     * @dev See {TokenPool-requireLocalToken}.
     */
    function _requireLocalToken(address localToken) internal view virtual override {
        if (!isSupportedToken(localToken)) revert OnlyLocalToken();
    }

    /**
     * @dev Checks if the two arrays have the same length.
     */
    function _requireEqualLength(uint256 a, uint256 b) internal pure {
        if (a != b) revert LengthMismatch(a, b);
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";

import {AccessControlEnumerableUpgradeable} from
    "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC721Mintable} from "src/interfaces/external/IERC721Mintable.sol";

import {PausableExtendedUpgradeable} from "src/extensions/PausableExtendedUpgradeable.sol";
import {RateLimitConsumerUpgradeable} from "src/extensions/RateLimitConsumerUpgradeable.sol";
import {SharedStorageConsumerUpgradeable} from "src/extensions/SharedStorageConsumerUpgradeable.sol";
import {TokenPool} from "src/pools/TokenPool.sol";
import {ILockMintERC721Pool} from "src/interfaces/pools/erc721/ILockMintERC721Pool.sol";
import {Pool} from "src/libraries/Pool.sol";

abstract contract LockMintERC721Pool is
    PausableExtendedUpgradeable,
    RateLimitConsumerUpgradeable,
    SharedStorageConsumerUpgradeable,
    TokenPool,
    ILockMintERC721Pool
{
    /**
     * @inheritdoc ILockMintERC721Pool
     */
    function estimateFee(address feeToken, uint64 remoteChainSelector, uint256 tokenCount, uint256 gasLimit)
        external
        view
        returns (uint256 fee)
    {
        Pool.ReleaseOrMint memory empty;
        empty.remotePoolData = abi.encode(new uint256[](tokenCount));

        (fee,) = _getSendDataFee({
            remoteChainSelector: remoteChainSelector,
            receiver: getRemotePool(remoteChainSelector),
            data: abi.encode(empty),
            gasLimit: gasLimit,
            allowOutOfOrderExecution: true,
            feeToken: feeToken
        });
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(PausableExtendedUpgradeable, RateLimitConsumerUpgradeable, SharedStorageConsumerUpgradeable, TokenPool)
        returns (bool)
    {
        return interfaceId == type(ILockMintERC721Pool).interfaceId || TokenPool.supportsInterface(interfaceId)
            || SharedStorageConsumerUpgradeable.supportsInterface(interfaceId)
            || RateLimitConsumerUpgradeable.supportsInterface(interfaceId)
            || PausableExtendedUpgradeable.supportsInterface(interfaceId);
    }

    function _ccipReceive(Client.Any2EVMMessage calldata message) internal virtual override {
        Pool.ReleaseOrMint memory releaseOrMint = abi.decode(message.data, (Pool.ReleaseOrMint));

        // Validate the message.sourceChainSelector against the releaseOrMint.remoteChainSelector
        if (message.sourceChainSelector != releaseOrMint.remoteChainSelector) {
            revert RemoteChainSelectorNotMatch(message.sourceChainSelector, releaseOrMint.remoteChainSelector);
        }
        // Validate the message.sender against the releaseOrMint.remotePoolAddress
        address remoteSender = abi.decode(message.sender, (address));
        if (remoteSender != releaseOrMint.remotePoolAddress) {
            revert RemotePoolNotMatch(remoteSender, releaseOrMint.remotePoolAddress);
        }
        _requireNonZero(releaseOrMint.originalSender);

        _storeMessageId(releaseOrMint.remoteChainSelector, message.messageId);
        _releaseOrMint(releaseOrMint);

        emit CrossTransfer(
            releaseOrMint.originalSender,
            releaseOrMint.receiver,
            message.messageId,
            abi.decode(releaseOrMint.remotePoolData, (uint256[])),
            message.sourceChainSelector,
            getCurrentChainSelector()
        );
    }

    function _releaseOrMint(Pool.ReleaseOrMint memory releaseOrMint) internal virtual override whenNotPaused {
        uint256[] memory ids = abi.decode(releaseOrMint.remotePoolData, (uint256[]));
        uint256 tokenCount = ids.length;
        _requireNonZero(tokenCount);

        _requireNonZero(releaseOrMint.receiver);
        _requireLocalToken(releaseOrMint.localToken);

        for (uint256 i; i < tokenCount; ++i) {
            uint256 id = ids[i];
            address owned = _tryGetOwnerOf(releaseOrMint.localToken, id);

            if (owned == address(this) || isSharedStorage(owned)) {
                IERC721(releaseOrMint.localToken).transferFrom(owned, releaseOrMint.receiver, id);
            } else {
                IERC721Mintable(releaseOrMint.localToken).mint(releaseOrMint.receiver, id);
            }
        }

        _requireDelivered(releaseOrMint.localToken, releaseOrMint.receiver, ids);
        _consumeInboundRateLimit(releaseOrMint.remoteChainSelector, releaseOrMint.localToken, tokenCount);
    }

    function _lockOrBurn(Pool.LockOrBurn memory lockOrBurn)
        internal
        virtual
        override
        whenNotPaused
        onlyLocalToken(lockOrBurn.localToken)
        onlyEnabledChain(lockOrBurn.remoteChainSelector)
    {
        uint256[] memory ids = abi.decode(lockOrBurn.extraData, (uint256[]));
        uint256 tokenCount = ids.length;
        _requireNonZero(tokenCount);

        for (uint256 i; i < tokenCount; ++i) {
            IERC721(lockOrBurn.localToken).transferFrom(msg.sender, address(this), ids[i]);
        }

        _requireDelivered(lockOrBurn.localToken, address(this), ids);
        _consumeOutboundRateLimit(lockOrBurn.remoteChainSelector, lockOrBurn.localToken, tokenCount);
    }

    function _requireDelivered(address token, address recipient, uint256[] memory ids) internal view {
        uint256 tokenCount = ids.length;

        for (uint256 i; i < tokenCount; ++i) {
            if (_tryGetOwnerOf(token, ids[i]) != recipient) revert ERC721TransferFailed(recipient, ids[i]);
        }
    }

    function _tryGetOwnerOf(address token, uint256 id) internal view returns (address ownedBy) {
        try IERC721(token).ownerOf(id) returns (address by) {
            return by;
        } catch {
            // Handle the case where the token does not exist or is not an ERC721
            return address(0);
        }
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

interface IMultiLockMintERC721Pool {
    /**
     * @dev Withdraw the liquidity of the tokens in the pool.
     * Requirements:
     * - The caller must have `DEFAULT_ADMIN_ROLE`.
     * - The `localTokens` must be the same length as `tos` and `ids`.
     * - The `tos` must not be zero.
     * - `localTokens` must be supported by the pool.
     */
    function withdrawLiquidity(address[] calldata localTokens, address[] calldata tos, uint256[] calldata ids)
        external;

    /**
     * @dev Cross transfer a single token to the remote chain.
     * Requirements:
     * - `to` must not be zero.
     * - `id` must be approved for transfer.
     * - token fee should be query via `estimateFee` before calling this function.
     * - if `feeToken` is native (address(0)), the caller must send enough native tokens to cover the fee.
     * - if `feeToken` is ERC20, the caller must approve the pool to spend the fee token.
     * @return messageId The message ID of the cross transfer.
     */
    function crossTransfer(
        address localToken,
        uint64 remoteChainSelector,
        address to,
        uint256 id,
        address feeToken,
        uint256 gasLimit
    ) external payable returns (bytes32 messageId);

    /**
     * @dev Cross transfer multiple tokens to the remote chain.
     * Requirements:
     * - `to` must not be zero.
     * - `ids` must be approved for transfer.
     * - token fee should be query via `estimateFee` before calling this function.
     * - if `feeToken` is native (address(0)), the caller must send enough native tokens to cover the fee.
     * - if `feeToken` is ERC20, the caller must approve the pool to spend the fee token.
     * @return messageId The message ID of the cross transfer.
     */
    function crossBatchTransfer(
        address localToken,
        uint64 remoteChainSelector,
        address to,
        uint256[] calldata ids,
        address feeToken,
        uint256 gasLimit
    ) external payable returns (bytes32 messageId);
}

File 7 of 49 : Pool.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

library Pool {
    struct LockOrBurn {
        uint64 remoteChainSelector;
        address localToken;
        bytes extraData;
    }

    struct ReleaseOrMint {
        address originalSender;
        uint64 remoteChainSelector;
        address receiver;
        address localToken;
        address remotePoolAddress;
        bytes remotePoolData;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 9 of 49 : ITypeAndVersion.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ITypeAndVersion {
  function typeAndVersion() external pure returns (string memory);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/extensions/AccessControlEnumerable.sol)

pragma solidity ^0.8.20;

import {IAccessControlEnumerable} from "@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol";
import {AccessControlUpgradeable} from "../AccessControlUpgradeable.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";

/**
 * @dev Extension of {AccessControl} that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerable, AccessControlUpgradeable {
    using EnumerableSet for EnumerableSet.AddressSet;

    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControlEnumerable
    struct AccessControlEnumerableStorage {
        mapping(bytes32 role => EnumerableSet.AddressSet) _roleMembers;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControlEnumerable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AccessControlEnumerableStorageLocation = 0xc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e82371705932000;

    function _getAccessControlEnumerableStorage() private pure returns (AccessControlEnumerableStorage storage $) {
        assembly {
            $.slot := AccessControlEnumerableStorageLocation
        }
    }

    function __AccessControlEnumerable_init() internal onlyInitializing {
    }

    function __AccessControlEnumerable_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {
        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
        return $._roleMembers[role].at(index);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {
        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
        return $._roleMembers[role].length();
    }

    /**
     * @dev Return all accounts that have `role`
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function getRoleMembers(bytes32 role) public view virtual returns (address[] memory) {
        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
        return $._roleMembers[role].values();
    }

    /**
     * @dev Overload {AccessControl-_grantRole} to track enumerable memberships
     */
    function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {
        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
        bool granted = super._grantRole(role, account);
        if (granted) {
            $._roleMembers[role].add(account);
        }
        return granted;
    }

    /**
     * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships
     */
    function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {
        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
        bool revoked = super._revokeRole(role, account);
        if (revoked) {
            $._roleMembers[role].remove(account);
        }
        return revoked;
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IRMN} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRMN.sol";
import {IWrappedNative} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IWrappedNative.sol";
import {IAny2EVMMessageReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IAny2EVMMessageReceiver.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";

import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

import {IRouterClientExtended} from "src/interfaces/external/IRouterClientExtended.sol";
import {IEVM2EVMOnRamp} from "src/interfaces/external/IEVM2EVMOnRamp.sol";
import {ICCIPSenderReceiver} from "src/interfaces/extensions/ICCIPSenderReceiver.sol";
import {Error} from "src/libraries/Error.sol";

abstract contract CCIPSenderReceiverUpgradeable is Initializable, ICCIPSenderReceiver {
    using SafeERC20 for IERC20;
    using EnumerableSet for EnumerableSet.UintSet;

    /// @dev Gap for future storage
    uint256[50] private __gap1;

    /// @dev Current chain selector
    uint64 private s_currentChainSelector;
    /// @dev CCIP Risk Management Network Proxy
    IRMN private s_rmnProxy;
    /// @dev CCIP Router
    IRouterClientExtended private s_router;
    /// @dev Remote chain selectors set
    EnumerableSet.UintSet private s_remoteChainSelectors;
    /// @dev Mapping of remote chain selector to enabled sender. This is the address that is allowed to send messages from the remote chain.
    mapping(uint64 remoteChainSelector => address) private s_remoteSenders;

    /// @dev Gap for future storage
    uint256[50] private __gap2;

    modifier onlyEnabledChain(uint64 remoteChainSelector) {
        _requireEnabledChain(remoteChainSelector);
        _;
    }

    modifier onlyLocalChain(uint64 currentChainSelector) {
        _requireLocalChain(currentChainSelector);
        _;
    }

    modifier nonZero(address addr) {
        _requireNonZero(addr);
        _;
    }

    modifier notCursed(uint64 remoteChainSelector) {
        _requireNotCursed(remoteChainSelector);
        _;
    }

    function __CCIPSenderReceiver_init(address router, uint64 currentChainSelector) internal onlyInitializing {
        __CCIPSenderReceiver_init_unchained(router, currentChainSelector);
    }

    function __CCIPSenderReceiver_init_unchained(address router, uint64 currentChainSelector)
        internal
        onlyInitializing
    {
        _requireNonZero(currentChainSelector);

        s_router = IRouterClientExtended(router);
        s_rmnProxy = IRMN(s_router.getArmProxy());
        s_currentChainSelector = currentChainSelector;
    }

    /**
     * @inheritdoc IAny2EVMMessageReceiver
     */
    function ccipReceive(Client.Any2EVMMessage calldata message)
        external
        override
        notCursed(message.sourceChainSelector)
    {
        address sender = abi.decode(message.sender, (address));

        _requireEnabledSender(message.sourceChainSelector, sender);
        _requireRouter();

        _ccipReceive(message);

        emit MessageReceived(sender, message.messageId);
    }

    /**
     * @inheritdoc ICCIPSenderReceiver
     */
    function isFeeTokenSupported(uint64 remoteChainSelector, address feeToken) external view returns (bool yes) {
        address[] memory feeTokens = getFeeTokens(remoteChainSelector);
        uint256 feeTokenCount = feeTokens.length;
        if (feeTokenCount == 0) return false;

        for (uint256 i; i < feeTokenCount; ++i) {
            if (feeTokens[i] == feeToken) return true;
        }

        return false;
    }

    /**
     * @inheritdoc ICCIPSenderReceiver
     */
    function getFeeTokens(uint64 remoteChainSelector)
        public
        view
        onlyEnabledChain(remoteChainSelector)
        returns (address[] memory feeTokens)
    {
        return IEVM2EVMOnRamp(s_router.getOnRamp(remoteChainSelector)).getDynamicConfig().priceRegistry.getFeeTokens();
    }

    /**
     * @inheritdoc ICCIPSenderReceiver
     */
    function isLocalChain(uint64 currentChainSelector) public view returns (bool yes) {
        return currentChainSelector == s_currentChainSelector;
    }

    /**
     * @inheritdoc ICCIPSenderReceiver
     */
    function isSupportedChain(uint64 remoteChainSelector) public view returns (bool yes) {
        return s_remoteChainSelectors.contains(remoteChainSelector) && s_router.isChainSupported(remoteChainSelector);
    }

    /**
     * @inheritdoc ICCIPSenderReceiver
     */
    function isSenderEnabled(uint64 remoteChainSelector, address sender) public view returns (bool yes) {
        if (!isSupportedChain(remoteChainSelector)) return false;
        return s_remoteSenders[remoteChainSelector] == sender;
    }

    /**
     * @inheritdoc ICCIPSenderReceiver
     */
    function getSupportedChains() public view returns (uint64[] memory remoteChainSelectors) {
        uint256[] memory values = s_remoteChainSelectors.values();
        uint256 length = values.length;
        remoteChainSelectors = new uint64[](length);
        uint256 count;

        for (uint256 i; i < length; ++i) {
            uint64 chain = uint64(values[i]);
            if (s_router.isChainSupported(chain)) {
                remoteChainSelectors[count++] = chain;
            }
        }

        assembly ("memory-safe") {
            // Resize the array to the actual number of supported chains
            mstore(remoteChainSelectors, count)
        }
    }

    /**
     * @inheritdoc ICCIPSenderReceiver
     */
    function getCurrentChainSelector() public view returns (uint64 currentChainSelector) {
        return s_currentChainSelector;
    }

    /**
     * @inheritdoc ICCIPSenderReceiver
     */
    function getRouter() public view returns (IRouterClientExtended router) {
        return s_router;
    }

    /**
     * @inheritdoc ICCIPSenderReceiver
     */
    function getRmnProxy() external view returns (IRMN rmnProxy) {
        return s_rmnProxy;
    }

    /**
     * @notice IERC165 supports an interfaceId
     * @param interfaceId The interfaceId to check
     * @return true if the interfaceId is supported
     * @dev Should indicate whether the contract implements IAny2EVMMessageReceiver
     * e.g. return interfaceId == type(IAny2EVMMessageReceiver).interfaceId || interfaceId == type(IERC165).interfaceId
     * This allows CCIP to check if ccipReceive is available before calling it.
     * If this returns false or reverts, only tokens are transferred to the receiver.
     * If this returns true, tokens are transferred and ccipReceive is called atomically.
     * Additionally, if the receiver address does not have code associated with
     * it at the time of execution (EXTCODESIZE returns 0), only tokens will be transferred.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(ICCIPSenderReceiver).interfaceId
            || interfaceId == type(IAny2EVMMessageReceiver).interfaceId || interfaceId == type(IERC165).interfaceId;
    }

    /**
     * @notice Override this function in your implementation.
     * @param message Any2EVMMessage
     */
    function _ccipReceive(Client.Any2EVMMessage calldata message) internal virtual;

    /**
     * @dev Enable a remote chain
     * @param remoteChainSelector The chain selector of the remote chain
     * @param remoteSender The address of the sender on the remote chain
     */
    function _addRemoteChain(uint64 remoteChainSelector, address remoteSender) internal {
        _requireNonZero(remoteSender);

        if (remoteChainSelector == s_currentChainSelector) revert OnlyRemoteChain(remoteChainSelector);
        if (!s_router.isChainSupported(remoteChainSelector)) revert ChainNotSupported(remoteChainSelector);

        if (!s_remoteChainSelectors.add(remoteChainSelector)) revert ChainAlreadyEnabled(remoteChainSelector);
        s_remoteSenders[remoteChainSelector] = remoteSender;

        emit RemoteChainEnabled(msg.sender, remoteChainSelector, remoteSender);
    }

    /**
     * @dev Disable a remote chain
     * @param remoteChainSelector The chain selector of the remote chain
     */
    function _removeRemoteChain(uint64 remoteChainSelector) internal {
        if (!s_remoteChainSelectors.remove(remoteChainSelector)) revert NonExistentChain(remoteChainSelector);
        delete s_remoteSenders[remoteChainSelector];

        emit RemoteChainDisabled(msg.sender, remoteChainSelector);
    }

    /**
     * @notice Send data to a remote chain and pay fee by ERC20 token
     * If the feeToken is address(0), the fee will be wrapped into WrappedNative token.
     * Revert if the feeToken is not supported by the remote chain.
     */
    function _sendDataPayFeeToken(
        uint64 remoteChainSelector,
        address receiver,
        bytes memory data,
        uint256 gasLimit,
        bool allowOutOfOrderExecution,
        address feeToken
    ) internal notCursed(remoteChainSelector) returns (bytes32 messageId) {
        _requireNonZero(receiver);
        _requireNonZero(gasLimit);
        _requireNonZero(data.length);

        (uint256 fee, Client.EVM2AnyMessage memory message) =
            _getSendDataFee(remoteChainSelector, receiver, data, gasLimit, allowOutOfOrderExecution, feeToken);

        uint256 overspent;
        if (feeToken == address(0)) {
            if (msg.value < fee) revert InsufficientAllowance(fee, msg.value);

            feeToken = s_router.getWrappedNative();
            // Overwrite feeToken to wrapped native token
            message.feeToken = feeToken;
            IWrappedNative(feeToken).deposit{value: fee}();

            overspent = msg.value - fee;
        } else {
            if (msg.value != 0) revert MsgValueNotAllowed(msg.value);
            IERC20(feeToken).safeTransferFrom(msg.sender, address(this), fee);
        }

        IERC20(feeToken).approve(address(s_router), fee);

        messageId = s_router.ccipSend(remoteChainSelector, message);

        if (overspent > 0) {
            // solhint-disable-next-line avoid-low-level-calls
            (bool success,) = msg.sender.call{value: overspent}("");
            if (!success) revert RefundFailed(msg.sender, overspent);
            emit Refunded(msg.sender, overspent);
        }

        emit MessageSent(msg.sender, messageId);
    }

    /**
     * @notice Estimate the fee for sending data to a remote chain
     */
    function _getSendDataFee(
        uint64 remoteChainSelector,
        address receiver,
        bytes memory data,
        uint256 gasLimit,
        bool allowOutOfOrderExecution,
        address feeToken
    ) internal view onlyEnabledChain(remoteChainSelector) returns (uint256 fee, Client.EVM2AnyMessage memory message) {
        message = Client.EVM2AnyMessage({
            receiver: abi.encode(receiver),
            data: data,
            tokenAmounts: new Client.EVMTokenAmount[](0),
            extraArgs: Client._argsToBytes(
                Client.EVMExtraArgsV2({gasLimit: gasLimit, allowOutOfOrderExecution: allowOutOfOrderExecution})
            ),
            feeToken: feeToken
        });

        fee = s_router.getFee(remoteChainSelector, message);
    }

    function _getRemoteSender(uint64 remoteChainSelector) internal view returns (address remoteAddress) {
        if (!isSupportedChain(remoteChainSelector)) return address(0);
        return s_remoteSenders[remoteChainSelector];
    }

    function _requireLocalChain(uint64 currentChainSelector) internal view {
        if (currentChainSelector != s_currentChainSelector) revert OnlyLocalChain(currentChainSelector);
    }

    function _requireRouter() internal view {
        if (msg.sender != address(s_router)) revert InvalidRouter(address(s_router), msg.sender);
    }

    function _requireNonZero(address addr) internal pure {
        if (addr == address(0)) revert Error.ZeroAddressNotAllowed();
    }

    function _requireNonZero(uint256 val) internal pure {
        if (val == 0) revert ZeroValueNotAllowed();
    }

    function _requireNotCursed(uint64 remoteChainSelector) internal view {
        if (s_rmnProxy.isCursed(bytes16(uint128(remoteChainSelector)))) revert CursedByRMN();
    }

    function _requireEnabledChain(uint64 remoteChainSelector) internal view {
        if (!isSupportedChain(remoteChainSelector)) revert NonExistentChain(remoteChainSelector);
    }

    function _requireEnabledSender(uint64 remoteChainSelector, address sender) internal view {
        if (!isSenderEnabled(remoteChainSelector, sender)) revert SenderNotEnabled(remoteChainSelector, sender);
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {ITypeAndVersion} from "@chainlink/contracts-ccip/src/v0.8/shared/interfaces/ITypeAndVersion.sol";

interface ITokenPool is ITypeAndVersion {
    /// @dev Throw if the messageId already exists.
    error MessageIdAlreadyExists(uint64 chainSelector, bytes32 messageId);

    /// @dev emit when gas config for cross-chain message is set.
    event GasLimitConfigured(address indexed by, uint32 fixedGas, uint32 dynamicGas);
    /// @dev emit when remote pool is added.
    event RemotePoolAdded(address indexed by, uint64 indexed remoteChainSelector, address indexed remotePool);
    /// @dev emit when remote pool is removed.
    event RemotePoolRemoved(address indexed by, uint64 indexed remoteChainSelector);
    /// @dev emit when remote token is mapped.
    event RemoteTokenMapped(
        address indexed by, uint64 indexed remoteChainSelector, address indexed localToken, address remoteToken
    );
    /// @dev emit when remote token is unmapped.
    event RemoteTokenUnmapped(address indexed by, uint64 indexed remoteChainSelector, address indexed localToken);

    /**
     * @dev Token pool owner role.
     * Value is equal to keccak256("TOKEN_POOL_OWNER_ROLE").
     */
    function TOKEN_POOL_OWNER_ROLE() external view returns (bytes32);

    /**
     * @dev Enabled `remotePool` to interact with this pool.
     * Requirements:
     * - `remotePool` is not null.
     * - `remoteChainSelector` is not null.
     * - `remoteChainSelector` != `currentChainSelector`.
     * - Caller must have `TOKEN_POOL_OWNER_ROLE`.
     * - `remoteChainSelector` must be supported by CCIP router.
     */
    function addRemotePool(uint64 remoteChainSelector, address remotePool) external;

    /**
     * @dev Disable `remotePool` to interact with this pool.
     * Requirements:
     * - `remoteChainSelector` is not null.
     * - `remoteChainSelector` != `currentChainSelector`.
     * - Caller must have `TOKEN_POOL_OWNER_ROLE`.
     * - Remote pool must be added before.
     *
     * Removing a remote pool does not delete the token mappings for the specified remote chain.
     * However, all tokens mapped to the removed remote pool will be deactivated.
     */
    function removeRemotePool(uint64 remoteChainSelector) external;

    /**
     * @dev Map local token to remote token for a given remote chain.
     * Requirements:
     * - `localToken` is not null.
     * - `remoteChainSelector` must be enabled.
     * - `remoteToken` is not null.
     * - Caller must have `TOKEN_POOL_OWNER_ROLE`.
     */
    function mapRemoteToken(address localToken, uint64 remoteChainSelector, address remoteToken) external;

    /**
     * @dev Unmap local token to remote token for a given remote chain.
     * Requirements:
     * - `localToken` must be added before.
     * - `remoteChainSelector` must be enabled.
     * - Caller must have `TOKEN_POOL_OWNER_ROLE`.
     * - If `remoteChainSelector` is not enabled in this pool or no remote token is mapped to `localToken`, `localToken` will be removed from the set.
     */
    function unmapRemoteToken(address localToken, uint64 remoteChainSelector) external;

    /**
     * @dev Get all supported chain selectors along with their remote pools pair for this pool/
     * @return remoteChainSelectors The list of remote chain selectors.
     * @return remotePools The list of enabled sender pools for the given remote chain.
     */
    function getRemotePools()
        external
        view
        returns (uint64[] memory remoteChainSelectors, address[] memory remotePools);

    /**
     * @dev Get remote token address for a given local token and remote chain.
     * Returns zero address if the token is not mapped or `remoteChainSelector` is disabled.
     */
    function getRemotePool(uint64 remoteChainSelector) external view returns (address remotePool);

    /**
     * @dev Returns whether the token is supported by the pool.
     */
    function isSupportedToken(address token) external view returns (bool yes);

    /**
     * @dev Returns the array of message IDs for the given chain selector.
     */
    function getMessageIds(uint64 chainSelector, uint256 offset, uint256 limit)
        external
        view
        returns (uint256 length, bytes32[] memory messageIds);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes32 value => uint256) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._positions[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

interface IMultiTokenPool {
    /// @dev Revert if the given token is not supported by the pool.
    error OnlyLocalToken();
    /// @dev Revert if array lengths do not match.
    error LengthMismatch(uint256 expected, uint256 actual);
    /// @dev Revert if the local token does not have remote token mapped given the remote chain.
    error TokenNotMapped(address localToken, uint64 remoteChainSelector);
    /// @dev Revert if the local token already has remote token mapped given the remote chain.
    error TokenAlreadyMapped(address localToken, address remoteToken);

    /**
     * @dev Get all supported token pair for a given chain.
     * Requirements:
     * - The remote chain is be enabled by the pool.
     * @param remoteChainSelector The selector of the remote chain.
     * @return localTokens The list of local tokens supported by the pool.
     * @return remoteTokens The list of remote tokens supported by the pool.
     */
    function getSupportedTokensForChain(uint64 remoteChainSelector)
        external
        view
        returns (address[] memory localTokens, address[] memory remoteTokens);

    /**
     * @dev Get all supported local tokens.
     * @return localTokens The list of local tokens supported by the pool.
     */
    function getTokens() external view returns (address[] memory localTokens);

    /**
     * @dev Get remote token address for a given local token and remote chain.
     * Requirements:
     * - The local token must be supported by the pool.
     * - The remote chain must be enabled by the pool.
     */
    function getRemoteToken(address localToken, uint64 remoteChainSelector)
        external
        view
        returns (address remoteToken);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// End consumer library.
library Client {
  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
  struct EVMTokenAmount {
    address token; // token address on the local chain.
    uint256 amount; // Amount of tokens.
  }

  struct Any2EVMMessage {
    bytes32 messageId; // MessageId corresponding to ccipSend on source.
    uint64 sourceChainSelector; // Source chain selector.
    bytes sender; // abi.decode(sender) if coming from an EVM chain.
    bytes data; // payload sent in original message.
    EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation.
  }

  // If extraArgs is empty bytes, the default is 200k gas limit.
  struct EVM2AnyMessage {
    bytes receiver; // abi.encode(receiver address) for dest EVM chains
    bytes data; // Data payload
    EVMTokenAmount[] tokenAmounts; // Token transfers
    address feeToken; // Address of feeToken. address(0) means you will send msg.value.
    bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV2)
  }

  // bytes4(keccak256("CCIP EVMExtraArgsV1"));
  bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;

  struct EVMExtraArgsV1 {
    uint256 gasLimit;
  }

  function _argsToBytes(
    EVMExtraArgsV1 memory extraArgs
  ) internal pure returns (bytes memory bts) {
    return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);
  }

  // bytes4(keccak256("CCIP EVMExtraArgsV2"));
  bytes4 public constant EVM_EXTRA_ARGS_V2_TAG = 0x181dcf10;

  /// @param gasLimit: gas limit for the callback on the destination chain.
  /// @param allowOutOfOrderExecution: if true, it indicates that the message can be executed in any order relative to other messages from the same sender.
  /// This value's default varies by chain. On some chains, a particular value is enforced, meaning if the expected value
  /// is not set, the message request will revert.
  struct EVMExtraArgsV2 {
    uint256 gasLimit;
    bool allowOutOfOrderExecution;
  }

  function _argsToBytes(
    EVMExtraArgsV2 memory extraArgs
  ) internal pure returns (bytes memory bts) {
    return abi.encodeWithSelector(EVM_EXTRA_ARGS_V2_TAG, extraArgs);
  }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";

interface IERC721Mintable is IERC721 {
    function mint(address to, uint256 id) external;
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import {AccessControlEnumerableUpgradeable} from
    "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";

import {IPausable} from "src/interfaces/external/IPausable.sol";
import {IPausableExtended} from "src/interfaces/extensions/IPausableExtended.sol";

abstract contract PausableExtendedUpgradeable is
    PausableUpgradeable,
    AccessControlEnumerableUpgradeable,
    IPausableExtended
{
    /// @inheritdoc IPausableExtended
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

    /// @dev Gap for future storage
    uint256[50] private __gap1;

    address private s_globalPauser;

    /// @dev Gap for future storage
    uint256[50] private __gap2;

    function __PausableExtended_init(address globalPauser) internal onlyInitializing {
        __PausableExtended_init_unchained(globalPauser);
    }

    function __PausableExtended_init_unchained(address globalPauser) internal onlyInitializing {
        s_globalPauser = globalPauser;
        _grantRole(PAUSER_ROLE, globalPauser);
    }

    /**
     * @inheritdoc IPausableExtended
     */
    function pause() external onlyRole(PAUSER_ROLE) {
        _pause();
    }

    /**
     * @inheritdoc IPausableExtended
     */
    function unpause() external onlyRole(PAUSER_ROLE) {
        _unpause();
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IPausableExtended).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @inheritdoc IPausableExtended
     */
    function getGlobalPauser() external view returns (address globalPauser) {
        return s_globalPauser;
    }

    /**
     * @inheritdoc IPausableExtended
     */
    function setGlobalPauser(address globalPauser) external onlyRole(DEFAULT_ADMIN_ROLE) {
        s_globalPauser = globalPauser;

        if (globalPauser == address(0)) {
            _revokeRole(PAUSER_ROLE, s_globalPauser);
            return;
        }

        _grantRole(PAUSER_ROLE, globalPauser);
    }

    function paused() public view virtual override returns (bool) {
        address globalPauser = s_globalPauser;
        return (hasRole(PAUSER_ROLE, globalPauser) && _hasCode(globalPauser) && IPausable(globalPauser).paused())
            || PausableUpgradeable.paused();
    }

    function _hasCode(address target) private view returns (bool) {
        return target.code.length > 0;
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {RateLimiter} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/RateLimiter.sol";

import {AccessControlEnumerableUpgradeable} from
    "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";

import {IRateLimitConsumer} from "src/interfaces/extensions/IRateLimitConsumer.sol";

abstract contract RateLimitConsumerUpgradeable is AccessControlEnumerableUpgradeable, IRateLimitConsumer {
    using RateLimiter for RateLimiter.Config;
    using RateLimiter for RateLimiter.TokenBucket;

    bytes32 public constant RATE_LIMITER_ROLE = keccak256("RATE_LIMITER_ROLE");

    uint256[50] private __gap1;

    /// @dev The outbound rate limit configuration for the given chain selector.
    mapping(uint64 remoteChainSelector => RateLimiter.TokenBucket) private s_outboundConfig;
    /// @dev The inbound rate limit configuration for the given chain selector.
    mapping(uint64 remoteChainSelector => RateLimiter.TokenBucket) private s_inboundConfig;

    uint256[50] private __gap2;

    function __RateLimitConsumer_init(address rateLimiter) internal onlyInitializing {
        __RateLimitConsumer_init_unchained(rateLimiter);
    }

    function __RateLimitConsumer_init_unchained(address rateLimiter) internal onlyInitializing {
        _grantRole(RATE_LIMITER_ROLE, rateLimiter);
    }

    /**
     * @inheritdoc IRateLimitConsumer
     */
    function setChainRateLimiterConfig(
        uint64 remoteChainSelector,
        RateLimiter.Config calldata outboundConfig,
        RateLimiter.Config calldata inboundConfig
    ) external onlyRole(RATE_LIMITER_ROLE) {
        _setRateLimitConfig(remoteChainSelector, outboundConfig, inboundConfig);
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IRateLimitConsumer).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @inheritdoc IRateLimitConsumer
     */
    function getCurrentOutboundRateLimiterState(uint64 remoteChainSelector)
        external
        view
        returns (RateLimiter.TokenBucket memory state)
    {
        return s_outboundConfig[remoteChainSelector]._currentTokenBucketState();
    }

    /**
     * @inheritdoc IRateLimitConsumer
     */
    function getCurrentInboundRateLimiterState(uint64 remoteChainSelector)
        external
        view
        returns (RateLimiter.TokenBucket memory state)
    {
        return s_inboundConfig[remoteChainSelector]._currentTokenBucketState();
    }

    /**
     * @notice Consumes outbound rate limiting capacity in this pool
     */
    function _consumeOutboundRateLimit(uint64 remoteChainSelector, address token, uint256 amount) internal {
        s_outboundConfig[remoteChainSelector]._consume(amount, token);
    }

    /**
     * @notice Consumes inbound rate limiting capacity in this pool
     */
    function _consumeInboundRateLimit(uint64 remoteChainSelector, address token, uint256 amount) internal {
        s_inboundConfig[remoteChainSelector]._consume(amount, token);
    }

    function _setRateLimitConfig(
        uint64 remoteChainSelector,
        RateLimiter.Config memory outboundConfig,
        RateLimiter.Config memory inboundConfig
    ) internal {
        outboundConfig._validateTokenBucketConfig({mustBeDisabled: false});
        s_outboundConfig[remoteChainSelector]._setTokenBucketConfig(outboundConfig);

        inboundConfig._validateTokenBucketConfig({mustBeDisabled: false});
        s_inboundConfig[remoteChainSelector]._setTokenBucketConfig(inboundConfig);

        emit RateLimitConfigured(msg.sender, remoteChainSelector, outboundConfig, inboundConfig);
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {AccessControlEnumerableUpgradeable} from
    "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";

import {ISharedStorageConsumer} from "src/interfaces/extensions/ISharedStorageConsumer.sol";
import {Error} from "src/libraries/Error.sol";

abstract contract SharedStorageConsumerUpgradeable is AccessControlEnumerableUpgradeable, ISharedStorageConsumer {
    bytes32 public constant SHARED_STORAGE_SETTER_ROLE = keccak256("SHARED_STORAGE_SETTER_ROLE");

    /// @dev Gap for future upgrades
    uint256[50] private __gap1;

    /// @dev Mapping of shared storage addresses to their allowed status
    mapping(address sharedStorage => bool allowed) private s_sharedStorage;

    /// @dev Gap for future upgrades
    uint256[50] private __gap2;

    function __SharedStorageConsumer_init(address sharedStorageSetter) internal onlyInitializing {
        __SharedStorageConsumer_init_unchained(sharedStorageSetter);
    }

    function __SharedStorageConsumer_init_unchained(address sharedStorageSetter) internal onlyInitializing {
        _grantRole(SHARED_STORAGE_SETTER_ROLE, sharedStorageSetter);
    }

    /**
     * @inheritdoc ISharedStorageConsumer
     */
    function setSharedStorage(address sharedStorage, bool shouldAdd) external onlyRole(SHARED_STORAGE_SETTER_ROLE) {
        if (sharedStorage == address(0)) revert Error.ZeroAddressNotAllowed();
        s_sharedStorage[sharedStorage] = shouldAdd;
        emit SharedStorageUpdated(msg.sender, sharedStorage, shouldAdd);
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(ISharedStorageConsumer).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @inheritdoc ISharedStorageConsumer
     */
    function isSharedStorage(address sharedStorage) public view returns (bool yes) {
        return s_sharedStorage[sharedStorage];
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

interface ILockMintERC721Pool {
    /// @dev Throws when ccip's message source chain selector does not match with decoded input.
    error RemoteChainSelectorNotMatch(uint64 expected, uint64 actual);
    /// @dev Throws when ccip's message original sender does not match with current pool config.
    error RemotePoolNotMatch(address expected, address actual);
    /// @dev Throws when failed to mint token.
    error MintFailed(address minter, address to, uint256 id);
    /// @dev Throws when failed to transfer token.
    error ERC721TransferFailed(address recipient, uint256 id);

    /// @dev Emit when successfully bridged nfts for user.
    event CrossTransfer(
        address indexed srcFrom,
        address indexed dstTo,
        bytes32 indexed messageId,
        uint256[] ids,
        uint64 srcChainSelector,
        uint64 dstChainSelector
    );

    /**
     * @dev Estimate the fee to pay for CCIP protocol to bridge the tokens.
     * @param feeToken The token to pay the fee.
     * @param remoteChainSelector The chain selector of the destination chain.
     * @param tokenCount The number of tokens to bridge.
     * @param gasLimit The gas limit for the transaction on the remote chain.
     * @return fee The estimated fee in the feeToken.
     */
    function estimateFee(address feeToken, uint64 remoteChainSelector, uint256 tokenCount, uint256 gasLimit)
        external
        view
        returns (uint256 fee);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "../IAccessControl.sol";

/**
 * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
 */
interface IAccessControlEnumerable is IAccessControl {
    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;


    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
    struct AccessControlStorage {
        mapping(bytes32 role => RoleData) _roles;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;

    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
        assembly {
            $.slot := AccessControlStorageLocation
        }
    }

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        AccessControlStorage storage $ = _getAccessControlStorage();
        bytes32 previousAdminRole = getRoleAdmin(role);
        $._roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (!hasRole(role, account)) {
            $._roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (hasRole(role, account)) {
            $._roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reinitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
     *
     * NOTE: Consider following the ERC-7201 formula to derive storage locations.
     */
    function _initializableStorageSlot() internal pure virtual returns (bytes32) {
        return INITIALIZABLE_STORAGE;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        bytes32 slot = _initializableStorageSlot();
        assembly {
            $.slot := slot
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @notice This interface contains the only RMN-related functions that might be used on-chain by other CCIP contracts.
interface IRMN {
  /// @notice A Merkle root tagged with the address of the commit store contract it is destined for.
  struct TaggedRoot {
    address commitStore;
    bytes32 root;
  }

  /// @notice Callers MUST NOT cache the return value as a blessed tagged root could become unblessed.
  function isBlessed(
    TaggedRoot calldata taggedRoot
  ) external view returns (bool);

  /// @notice Iff there is an active global or legacy curse, this function returns true.
  function isCursed() external view returns (bool);

  /// @notice Iff there is an active global curse, or an active curse for `subject`, this function returns true.
  /// @param subject To check whether a particular chain is cursed, set to bytes16(uint128(chainSelector)).
  function isCursed(
    bytes16 subject
  ) external view returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";

interface IWrappedNative is IERC20 {
  function deposit() external payable;

  function withdraw(
    uint256 wad
  ) external;
}

File 26 of 49 : IAny2EVMMessageReceiver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Client} from "../libraries/Client.sol";

/// @notice Application contracts that intend to receive messages from
/// the router should implement this interface.
interface IAny2EVMMessageReceiver {
  /// @notice Called by the Router to deliver a message.
  /// If this reverts, any token transfers also revert. The message
  /// will move to a FAILED state and become available for manual execution.
  /// @param message CCIP Message
  /// @dev Note ensure you check the msg.sender is the OffRampRouter
  function ccipReceive(
    Client.Any2EVMMessage calldata message
  ) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

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

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
import {IRouter} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouter.sol";

interface IRouterClientExtended is IRouter, IRouterClient {
    function getArmProxy() external view returns (address);
    function getWrappedNative() external view returns (address);
}

File 30 of 49 : IEVM2EVMOnRamp.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IPriceRegistry} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IPriceRegistry.sol";

interface IEVM2EVMOnRamp {
    /// @dev Struct to contains the dynamic configuration
    struct DynamicConfig {
        address router; // ──────────────────────────╮ Router address
        uint16 maxNumberOfTokensPerMsg; //           │ Maximum number of distinct ERC20 token transferred per message
        uint32 destGasOverhead; //                   │ Gas charged on top of the gasLimit to cover destination chain costs
        uint16 destGasPerPayloadByte; //             │ Destination chain gas charged for passing each byte of `data` payload to receiver
        uint32 destDataAvailabilityOverheadGas; // ──╯ Extra data availability gas charged on top of the message, e.g. for OCR
        uint16 destGasPerDataAvailabilityByte; // ───╮ Amount of gas to charge per byte of message data that needs availability
        uint16 destDataAvailabilityMultiplierBps; // │ Multiplier for data availability gas, multiples of bps, or 0.0001
        IPriceRegistry priceRegistry; //                    │ Price registry address
        uint32 maxDataBytes; //                      │ Maximum payload data size in bytes
        uint32 maxPerMsgGasLimit; // ────────────────╯ Maximum gas limit for messages targeting EVMs
        //                                           │
        // The following three properties are defaults, they can be overridden by setting the TokenTransferFeeConfig for a token
        uint16 defaultTokenFeeUSDCents; // ──────────╮ Default token fee charged per token transfer
        uint32 defaultTokenDestGasOverhead; //       │ Default gas charged to execute the token transfer on the destination chain
        bool enforceOutOfOrder; // ──────────────────╯ Whether to enforce the allowOutOfOrderExecution extraArg value to be true.
    }

    function getDynamicConfig() external view returns (DynamicConfig memory dynamicConfig);
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IRMN} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRMN.sol";
import {IAny2EVMMessageReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IAny2EVMMessageReceiver.sol";

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {IRouterClientExtended} from "src/interfaces/external/IRouterClientExtended.sol";

interface ICCIPSenderReceiver is IAny2EVMMessageReceiver, IERC165 {
    /// @dev Revert if the remote chain is cursed by RMN.
    error CursedByRMN();
    /// @dev Revert if the sender is not enabled for the remote chain.
    error SenderNotEnabled(uint64 chainSelector, address sender);
    /// @dev Revert if the provided chain selector is current chain selector.
    error OnlyRemoteChain(uint64 chainSelector);
    /// @dev Revert if the provided chain selector is not current chain selector.
    error OnlyLocalChain(uint64 chainSelector);
    /// @dev Revert if the provided value is zero.
    error ZeroValueNotAllowed();
    /// @dev Revert if the provided address is not a valid router.
    error InvalidRouter(address expected, address actual);
    /// @dev Revert if the provided `chainSelector` is not enabled.
    error NonExistentChain(uint64 chainSelector);
    /// @dev Revert if the provided `chainSelector` is already enabled.
    error ChainAlreadyEnabled(uint64 chainSelector);
    /// @dev Revert if the provided `chainSelector` is not supported by CCIP router.
    error ChainNotSupported(uint64 chainSelector);
    /// @dev Revert if not allow receiving msg.value.
    error MsgValueNotAllowed(uint256 value);
    /// @dev Revert if failed to refund to the sender.
    error RefundFailed(address to, uint256 value);
    /// @dev Revert if provided fee is insufficient.
    error InsufficientAllowance(uint256 expected, uint256 actual);

    /// @dev Emit when refunded to the sender.
    event Refunded(address indexed to, uint256 value);
    /// @dev Emit when the message is sent to CCIP.
    event MessageSent(address indexed by, bytes32 indexed messageId);
    /// @dev Emit when the message is received from CCIP.
    event MessageReceived(address by, bytes32 indexed messageId);
    /// @dev Emit when the given `chainSelector` is disabled.
    event RemoteChainDisabled(address indexed by, uint64 indexed chainSelector);
    /// @dev Emit when the given `chainSelector` is enabled.
    event RemoteChainEnabled(address indexed by, uint64 indexed chainSelector, address indexed remoteSender);

    /*
     * @dev Check whether the given `feeToken` is supported for the given `remoteChainSelector`.
     */
    function isFeeTokenSupported(uint64 remoteChainSelector, address feeToken) external view returns (bool yes);

    /*
     * @dev Get all supported fee tokens for the given `remoteChainSelector`.
     */
    function getFeeTokens(uint64 remoteChainSelector) external view returns (address[] memory feeTokens);

    /*
     * @dev Check whether given `chainSelector` is current chain selector.
     */
    function isLocalChain(uint64 currentChainSelector) external view returns (bool yes);

    /*
     * @dev Check whether given `chainSelector` is supported by this contract.
     */
    function isSupportedChain(uint64 remoteChainSelector) external view returns (bool yes);

    /*
     * @dev Get all supported chains for this contract.
     */
    function getSupportedChains() external view returns (uint64[] memory remoteChainSelectors);

    /*
     * @dev Check whether the given `sender` is enabled for the given `remoteChainSelector`.
     */
    function isSenderEnabled(uint64 remoteChainSelector, address sender) external view returns (bool yes);

    /*
     * @dev Get chain selector of the current chain.
     */
    function getCurrentChainSelector() external view returns (uint64 currentChainSelector);

    /*
     * @dev Get CCIP router address.
     */
    function getRouter() external view returns (IRouterClientExtended router);

    /*
     * @dev Get RMN proxy address.
     */
    function getRmnProxy() external view returns (IRMN rmnProxy);
}

File 32 of 49 : Error.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

library Error {
    error ZeroAddressNotAllowed();
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;

import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Pausable
    struct PausableStorage {
        bool _paused;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;

    function _getPausableStorage() private pure returns (PausableStorage storage $) {
        assembly {
            $.slot := PausableStorageLocation
        }
    }

    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

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

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    function __Pausable_init() internal onlyInitializing {
    }

    function __Pausable_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        PausableStorage storage $ = _getPausableStorage();
        return $._paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        PausableStorage storage $ = _getPausableStorage();
        $._paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        PausableStorage storage $ = _getPausableStorage();
        $._paused = false;
        emit Unpaused(_msgSender());
    }
}

File 34 of 49 : IPausable.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

interface IPausable {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

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

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    function paused() external view returns (bool);
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

interface IPausableExtended {
    /**
     * @dev Pauser role.
     * Value is equal to keccak256("PAUSER_ROLE").
     */
    function PAUSER_ROLE() external view returns (bytes32);

    /**
     * @dev Get global pauser address.
     */
    function getGlobalPauser() external view returns (address globalPauser);

    /**
     * @dev Set global pauser address.
     * Requirements:
     * - The caller must have the DEFAULT_ADMIN_ROLE.
     * @param globalPauser The address of the global pauser.
     */
    function setGlobalPauser(address globalPauser) external;

    /**
     * @dev Pause the contract.
     * Requirements:
     * - The caller must have the PAUSER_ROLE.
     */
    function pause() external;

    /**
     * @dev Unpause the contract.
     * Requirements:
     * - The caller must have the PAUSER_ROLE.
     */
    function unpause() external;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;

/// @notice Implements Token Bucket rate limiting.
/// @dev uint128 is safe for rate limiter state.
/// For USD value rate limiting, it can adequately store USD value in 18 decimals.
/// For ERC20 token amount rate limiting, all tokens that will be listed will have at most
/// a supply of uint128.max tokens, and it will therefore not overflow the bucket.
/// In exceptional scenarios where tokens consumed may be larger than uint128,
/// e.g. compromised issuer, an enabled RateLimiter will check and revert.
library RateLimiter {
  error BucketOverfilled();
  error OnlyCallableByAdminOrOwner();
  error TokenMaxCapacityExceeded(uint256 capacity, uint256 requested, address tokenAddress);
  error TokenRateLimitReached(uint256 minWaitInSeconds, uint256 available, address tokenAddress);
  error AggregateValueMaxCapacityExceeded(uint256 capacity, uint256 requested);
  error AggregateValueRateLimitReached(uint256 minWaitInSeconds, uint256 available);
  error InvalidRateLimitRate(Config rateLimiterConfig);
  error DisabledNonZeroRateLimit(Config config);
  error RateLimitMustBeDisabled();

  event TokensConsumed(uint256 tokens);
  event ConfigChanged(Config config);

  struct TokenBucket {
    uint128 tokens; // ──────╮ Current number of tokens that are in the bucket.
    uint32 lastUpdated; //   │ Timestamp in seconds of the last token refill, good for 100+ years.
    bool isEnabled; // ──────╯ Indication whether the rate limiting is enabled or not
    uint128 capacity; // ────╮ Maximum number of tokens that can be in the bucket.
    uint128 rate; // ────────╯ Number of tokens per second that the bucket is refilled.
  }

  struct Config {
    bool isEnabled; // Indication whether the rate limiting should be enabled
    uint128 capacity; // ────╮ Specifies the capacity of the rate limiter
    uint128 rate; //  ───────╯ Specifies the rate of the rate limiter
  }

  /// @notice _consume removes the given tokens from the pool, lowering the
  /// rate tokens allowed to be consumed for subsequent calls.
  /// @param requestTokens The total tokens to be consumed from the bucket.
  /// @param tokenAddress The token to consume capacity for, use 0x0 to indicate aggregate value capacity.
  /// @dev Reverts when requestTokens exceeds bucket capacity or available tokens in the bucket
  /// @dev emits removal of requestTokens if requestTokens is > 0
  function _consume(TokenBucket storage s_bucket, uint256 requestTokens, address tokenAddress) internal {
    // If there is no value to remove or rate limiting is turned off, skip this step to reduce gas usage
    if (!s_bucket.isEnabled || requestTokens == 0) {
      return;
    }

    uint256 tokens = s_bucket.tokens;
    uint256 capacity = s_bucket.capacity;
    uint256 timeDiff = block.timestamp - s_bucket.lastUpdated;

    if (timeDiff != 0) {
      if (tokens > capacity) revert BucketOverfilled();

      // Refill tokens when arriving at a new block time
      tokens = _calculateRefill(capacity, tokens, timeDiff, s_bucket.rate);

      s_bucket.lastUpdated = uint32(block.timestamp);
    }

    if (capacity < requestTokens) {
      // Token address 0 indicates consuming aggregate value rate limit capacity.
      if (tokenAddress == address(0)) revert AggregateValueMaxCapacityExceeded(capacity, requestTokens);
      revert TokenMaxCapacityExceeded(capacity, requestTokens, tokenAddress);
    }
    if (tokens < requestTokens) {
      uint256 rate = s_bucket.rate;
      // Wait required until the bucket is refilled enough to accept this value, round up to next higher second
      // Consume is not guaranteed to succeed after wait time passes if there is competing traffic.
      // This acts as a lower bound of wait time.
      uint256 minWaitInSeconds = ((requestTokens - tokens) + (rate - 1)) / rate;

      if (tokenAddress == address(0)) revert AggregateValueRateLimitReached(minWaitInSeconds, tokens);
      revert TokenRateLimitReached(minWaitInSeconds, tokens, tokenAddress);
    }
    tokens -= requestTokens;

    // Downcast is safe here, as tokens is not larger than capacity
    s_bucket.tokens = uint128(tokens);
    emit TokensConsumed(requestTokens);
  }

  /// @notice Gets the token bucket with its values for the block it was requested at.
  /// @return The token bucket.
  function _currentTokenBucketState(
    TokenBucket memory bucket
  ) internal view returns (TokenBucket memory) {
    // We update the bucket to reflect the status at the exact time of the
    // call. This means we might need to refill a part of the bucket based
    // on the time that has passed since the last update.
    bucket.tokens =
      uint128(_calculateRefill(bucket.capacity, bucket.tokens, block.timestamp - bucket.lastUpdated, bucket.rate));
    bucket.lastUpdated = uint32(block.timestamp);
    return bucket;
  }

  /// @notice Sets the rate limited config.
  /// @param s_bucket The token bucket
  /// @param config The new config
  function _setTokenBucketConfig(TokenBucket storage s_bucket, Config memory config) internal {
    // First update the bucket to make sure the proper rate is used for all the time
    // up until the config change.
    uint256 timeDiff = block.timestamp - s_bucket.lastUpdated;
    if (timeDiff != 0) {
      s_bucket.tokens = uint128(_calculateRefill(s_bucket.capacity, s_bucket.tokens, timeDiff, s_bucket.rate));

      s_bucket.lastUpdated = uint32(block.timestamp);
    }

    s_bucket.tokens = uint128(_min(config.capacity, s_bucket.tokens));
    s_bucket.isEnabled = config.isEnabled;
    s_bucket.capacity = config.capacity;
    s_bucket.rate = config.rate;

    emit ConfigChanged(config);
  }

  /// @notice Validates the token bucket config
  function _validateTokenBucketConfig(Config memory config, bool mustBeDisabled) internal pure {
    if (config.isEnabled) {
      if (config.rate >= config.capacity || config.rate == 0) {
        revert InvalidRateLimitRate(config);
      }
      if (mustBeDisabled) {
        revert RateLimitMustBeDisabled();
      }
    } else {
      if (config.rate != 0 || config.capacity != 0) {
        revert DisabledNonZeroRateLimit(config);
      }
    }
  }

  /// @notice Calculate refilled tokens
  /// @param capacity bucket capacity
  /// @param tokens current bucket tokens
  /// @param timeDiff block time difference since last refill
  /// @param rate bucket refill rate
  /// @return the value of tokens after refill
  function _calculateRefill(
    uint256 capacity,
    uint256 tokens,
    uint256 timeDiff,
    uint256 rate
  ) private pure returns (uint256) {
    return _min(capacity, tokens + timeDiff * rate);
  }

  /// @notice Return the smallest of two integers
  /// @param a first int
  /// @param b second int
  /// @return smallest
  function _min(uint256 a, uint256 b) internal pure returns (uint256) {
    return a < b ? a : b;
  }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {RateLimiter} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/RateLimiter.sol";

interface IRateLimitConsumer {
    /// @dev Emit when the rate limit is configured.
    event RateLimitConfigured(
        address indexed by,
        uint64 indexed chainSelector,
        RateLimiter.Config outboundConfig,
        RateLimiter.Config inboundConfig
    );

    function RATE_LIMITER_ROLE() external view returns (bytes32);

    /**
     * @notice Sets the chain rate limiter config.
     * @param remoteChainSelector The remote chain selector for which the rate limits apply.
     * @param outboundConfig The new outbound rate limiter config, meaning the onRamp rate limits for the given chain.
     * @param inboundConfig The new inbound rate limiter config, meaning the offRamp rate limits for the given chain.
     */
    function setChainRateLimiterConfig(
        uint64 remoteChainSelector,
        RateLimiter.Config memory outboundConfig,
        RateLimiter.Config memory inboundConfig
    ) external;

    /**
     * @notice Gets the token bucket with its values for the block it was requested at.
     * @return state The token bucket.
     */
    function getCurrentOutboundRateLimiterState(uint64 remoteChainSelector)
        external
        view
        returns (RateLimiter.TokenBucket memory state);

    /**
     * @notice Gets the token bucket with its values for the block it was requested at.
     * @return state The token bucket.
     */
    function getCurrentInboundRateLimiterState(uint64 remoteChainSelector)
        external
        view
        returns (RateLimiter.TokenBucket memory state);
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

interface ISharedStorageConsumer {
    /// @dev emit when shared storage is set.
    event SharedStorageUpdated(address indexed sender, address indexed sharedStorage, bool shouldAdd);

    /**
     * @dev Sets the shared storage address. Used for pool to transferFrom
     * @param sharedStorage The address of the shared storage contract.
     * @param shouldAdd A boolean indicating whether to add or remove the shared storage.
     */
    function setSharedStorage(address sharedStorage, bool shouldAdd) external;

    /**
     * @dev Shared storage setter role.
     * Value is equal to keccak256("SHARED_STORAGE_SETTER_ROLE").
     */
    function SHARED_STORAGE_SETTER_ROLE() external view returns (bytes32);

    /**
     * @dev Checks if the given address is a shared storage.
     * @param sharedStorage The address to check.
     * @return yes A boolean indicating whether the address is a shared storage.
     */
    function isSharedStorage(address sharedStorage) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165Upgradeable is Initializable, IERC165 {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
  /**
   * @dev Emitted when `value` tokens are moved from one account (`from`) to
   * another (`to`).
   *
   * Note that `value` may be zero.
   */
  event Transfer(address indexed from, address indexed to, uint256 value);

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

  /**
   * @dev Returns the amount of tokens in existence.
   */
  function totalSupply() external view returns (uint256);

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

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

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {Client} from "../libraries/Client.sol";

interface IRouterClient {
  error UnsupportedDestinationChain(uint64 destChainSelector);
  error InsufficientFeeTokenAmount();
  error InvalidMsgValue();

  /// @notice Checks if the given chain ID is supported for sending/receiving.
  /// @param destChainSelector The chain to check.
  /// @return supported is true if it is supported, false if not.
  function isChainSupported(
    uint64 destChainSelector
  ) external view returns (bool supported);

  /// @param destinationChainSelector The destination chainSelector
  /// @param message The cross-chain CCIP message including data and/or tokens
  /// @return fee returns execution fee for the message
  /// delivery to destination chain, denominated in the feeToken specified in the message.
  /// @dev Reverts with appropriate reason upon invalid message.
  function getFee(
    uint64 destinationChainSelector,
    Client.EVM2AnyMessage memory message
  ) external view returns (uint256 fee);

  /// @notice Request a message to be sent to the destination chain
  /// @param destinationChainSelector The destination chain ID
  /// @param message The cross-chain CCIP message including data and/or tokens
  /// @return messageId The message ID
  /// @dev Note if msg.value is larger than the required fee (from getFee) we accept
  /// the overpayment with no refund.
  /// @dev Reverts with appropriate reason upon invalid message.
  function ccipSend(
    uint64 destinationChainSelector,
    Client.EVM2AnyMessage calldata message
  ) external payable returns (bytes32);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Client} from "../libraries/Client.sol";

interface IRouter {
  error OnlyOffRamp();

  /// @notice Route the message to its intended receiver contract.
  /// @param message Client.Any2EVMMessage struct.
  /// @param gasForCallExactCheck of params for exec
  /// @param gasLimit set of params for exec
  /// @param receiver set of params for exec
  /// @dev if the receiver is a contracts that signals support for CCIP execution through EIP-165.
  /// the contract is called. If not, only tokens are transferred.
  /// @return success A boolean value indicating whether the ccip message was received without errors.
  /// @return retBytes A bytes array containing return data form CCIP receiver.
  /// @return gasUsed the gas used by the external customer call. Does not include any overhead.
  function routeMessage(
    Client.Any2EVMMessage calldata message,
    uint16 gasForCallExactCheck,
    uint256 gasLimit,
    address receiver
  ) external returns (bool success, bytes memory retBytes, uint256 gasUsed);

  /// @notice Returns the configured onramp for a specific destination chain.
  /// @param destChainSelector The destination chain Id to get the onRamp for.
  /// @return onRampAddress The address of the onRamp.
  function getOnRamp(
    uint64 destChainSelector
  ) external view returns (address onRampAddress);

  /// @notice Return true if the given offRamp is a configured offRamp for the given source chain.
  /// @param sourceChainSelector The source chain selector to check.
  /// @param offRamp The address of the offRamp to check.
  function isOffRamp(uint64 sourceChainSelector, address offRamp) external view returns (bool isOffRamp);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {Internal} from "../libraries/Internal.sol";

interface IPriceRegistry {
  /// @notice Update the price for given tokens and gas prices for given chains.
  /// @param priceUpdates The price updates to apply.
  function updatePrices(
    Internal.PriceUpdates memory priceUpdates
  ) external;

  /// @notice Get the `tokenPrice` for a given token.
  /// @param token The token to get the price for.
  /// @return tokenPrice The tokenPrice for the given token.
  function getTokenPrice(
    address token
  ) external view returns (Internal.TimestampedPackedUint224 memory);

  /// @notice Get the `tokenPrice` for a given token, checks if the price is valid.
  /// @param token The token to get the price for.
  /// @return tokenPrice The tokenPrice for the given token if it exists and is valid.
  function getValidatedTokenPrice(
    address token
  ) external view returns (uint224);

  /// @notice Get the `tokenPrice` for an array of tokens.
  /// @param tokens The tokens to get prices for.
  /// @return tokenPrices The tokenPrices for the given tokens.
  function getTokenPrices(
    address[] calldata tokens
  ) external view returns (Internal.TimestampedPackedUint224[] memory);

  /// @notice Get an encoded `gasPrice` for a given destination chain ID.
  /// The 224-bit result encodes necessary gas price components.
  /// On L1 chains like Ethereum or Avax, the only component is the gas price.
  /// On Optimistic Rollups, there are two components - the L2 gas price, and L1 base fee for data availability.
  /// On future chains, there could be more or differing price components.
  /// PriceRegistry does not contain chain-specific logic to parse destination chain price components.
  /// @param destChainSelector The destination chain to get the price for.
  /// @return gasPrice The encoded gasPrice for the given destination chain ID.
  function getDestinationChainGasPrice(
    uint64 destChainSelector
  ) external view returns (Internal.TimestampedPackedUint224 memory);

  /// @notice Gets the fee token price and the gas price, both denominated in dollars.
  /// @param token The source token to get the price for.
  /// @param destChainSelector The destination chain to get the gas price for.
  /// @return tokenPrice The price of the feeToken in 1e18 dollars per base unit.
  /// @return gasPrice The price of gas in 1e18 dollars per base unit.
  function getTokenAndGasPrices(
    address token,
    uint64 destChainSelector
  ) external view returns (uint224 tokenPrice, uint224 gasPrice);

  /// @notice Convert a given token amount to target token amount.
  /// @param fromToken The given token address.
  /// @param fromTokenAmount The given token amount.
  /// @param toToken The target token address.
  /// @return toTokenAmount The target token amount.
  function convertTokenAmount(
    address fromToken,
    uint256 fromTokenAmount,
    address toToken
  ) external view returns (uint256 toTokenAmount);

  /// @notice Get the list of fee tokens.
  /// @return feeTokens The tokens set as fee tokens.
  function getFeeTokens() external view returns (address[] memory);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol";
import {Client} from "./Client.sol";

// Library for CCIP internal definitions common to multiple contracts.
library Internal {
  error InvalidEVMAddress(bytes encodedAddress);

  /// @dev The minimum amount of gas to perform the call with exact gas.
  /// We include this in the offramp so that we can redeploy to adjust it
  /// should a hardfork change the gas costs of relevant opcodes in callWithExactGas.
  uint16 internal constant GAS_FOR_CALL_EXACT_CHECK = 5_000;
  // @dev We limit return data to a selector plus 4 words. This is to avoid
  // malicious contracts from returning large amounts of data and causing
  // repeated out-of-gas scenarios.
  uint16 internal constant MAX_RET_BYTES = 4 + 4 * 32;
  /// @dev The expected number of bytes returned by the balanceOf function.
  uint256 internal constant MAX_BALANCE_OF_RET_BYTES = 32;

  /// @notice A collection of token price and gas price updates.
  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
  struct PriceUpdates {
    TokenPriceUpdate[] tokenPriceUpdates;
    GasPriceUpdate[] gasPriceUpdates;
  }

  /// @notice Token price in USD.
  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
  struct TokenPriceUpdate {
    address sourceToken; // Source token
    uint224 usdPerToken; // 1e18 USD per 1e18 of the smallest token denomination.
  }

  /// @notice Gas price for a given chain in USD, its value may contain tightly packed fields.
  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
  struct GasPriceUpdate {
    uint64 destChainSelector; // Destination chain selector
    uint224 usdPerUnitGas; // 1e18 USD per smallest unit (e.g. wei) of destination chain gas
  }

  /// @notice A timestamped uint224 value that can contain several tightly packed fields.
  struct TimestampedPackedUint224 {
    uint224 value; // ───────╮ Value in uint224, packed.
    uint32 timestamp; // ────╯ Timestamp of the most recent price update.
  }

  /// @dev Gas price is stored in 112-bit unsigned int. uint224 can pack 2 prices.
  /// When packing L1 and L2 gas prices, L1 gas price is left-shifted to the higher-order bits.
  /// Using uint8 type, which cannot be higher than other bit shift operands, to avoid shift operand type warning.
  uint8 public constant GAS_PRICE_BITS = 112;

  struct PoolUpdate {
    address token; // The IERC20 token address
    address pool; // The token pool address
  }

  struct SourceTokenData {
    // The source pool address, abi encoded. This value is trusted as it was obtained through the onRamp. It can be
    // relied upon by the destination pool to validate the source pool.
    bytes sourcePoolAddress;
    // The address of the destination token, abi encoded in the case of EVM chains
    // This value is UNTRUSTED as any pool owner can return whatever value they want.
    bytes destTokenAddress;
    // Optional pool data to be transferred to the destination chain. Be default this is capped at
    // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
    // has to be set for the specific token.
    bytes extraData;
    uint32 destGasAmount; // The amount of gas available for the releaseOrMint and balanceOf calls on the offRamp
  }

  /// @notice Report that is submitted by the execution DON at the execution phase. (including chain selector data)
  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
  struct ExecutionReportSingleChain {
    uint64 sourceChainSelector; // Source chain selector for which the report is submitted
    Any2EVMRampMessage[] messages;
    // Contains a bytes array for each message, each inner bytes array contains bytes per transferred token
    bytes[][] offchainTokenData;
    bytes32[] proofs;
    uint256 proofFlagBits;
  }

  /// @notice Report that is submitted by the execution DON at the execution phase.
  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
  struct ExecutionReport {
    EVM2EVMMessage[] messages;
    // Contains a bytes array for each message, each inner bytes array contains bytes per transferred token
    bytes[][] offchainTokenData;
    bytes32[] proofs;
    uint256 proofFlagBits;
  }

  /// @notice The cross chain message that gets committed to EVM chains.
  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
  struct EVM2EVMMessage {
    uint64 sourceChainSelector; // ────────╮ the chain selector of the source chain, note: not chainId
    address sender; // ────────────────────╯ sender address on the source chain
    address receiver; // ──────────────────╮ receiver address on the destination chain
    uint64 sequenceNumber; // ─────────────╯ sequence number, not unique across lanes
    uint256 gasLimit; //                     user supplied maximum gas amount available for dest chain execution
    bool strict; // ───────────────────────╮ DEPRECATED
    uint64 nonce; //                       │ nonce for this lane for this sender, not unique across senders/lanes
    address feeToken; // ──────────────────╯ fee token
    uint256 feeTokenAmount; //               fee token amount
    bytes data; //                           arbitrary data payload supplied by the message sender
    Client.EVMTokenAmount[] tokenAmounts; // array of tokens and amounts to transfer
    bytes[] sourceTokenData; //              array of token data, one per token
    bytes32 messageId; //                    a hash of the message data
  }

  /// @dev EVM2EVMMessage struct has 13 fields, including 3 variable arrays.
  /// Each variable array takes 1 more slot to store its length.
  /// When abi encoded, excluding array contents,
  /// EVM2EVMMessage takes up a fixed number of 16 lots, 32 bytes each.
  /// For structs that contain arrays, 1 more slot is added to the front, reaching a total of 17.
  uint256 public constant MESSAGE_FIXED_BYTES = 32 * 17;

  /// @dev Each token transfer adds 1 EVMTokenAmount and 3 bytes at 3 slots each and one slot for the destGasAmount.
  /// When abi encoded, each EVMTokenAmount takes 2 slots, each bytes takes 1 slot for length, one slot of data and one
  /// slot for the offset. This results in effectively 3*3 slots per SourceTokenData.
  /// 0x20
  /// destGasAmount
  /// sourcePoolAddress_offset
  /// destTokenAddress_offset
  /// extraData_offset
  /// sourcePoolAddress_length
  /// sourcePoolAddress_content // assume 1 slot
  /// destTokenAddress_length
  /// destTokenAddress_content // assume 1 slot
  /// extraData_length // contents billed separately
  uint256 public constant MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * ((1 + 3 * 3) + 2);

  /// @dev Any2EVMRampMessage struct has 10 fields, including 3 variable unnested arrays (data, receiver and tokenAmounts).
  /// Each variable array takes 1 more slot to store its length.
  /// When abi encoded, excluding array contents,
  /// Any2EVMMessage takes up a fixed number of 13 slots, 32 bytes each.
  /// For structs that contain arrays, 1 more slot is added to the front, reaching a total of 14.
  /// The fixed bytes does not cover struct data (this is represented by ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN)
  uint256 public constant ANY_2_EVM_MESSAGE_FIXED_BYTES = 32 * 14;

  /// @dev Each token transfer adds 1 RampTokenAmount
  /// RampTokenAmount has 5 fields, 2 of which are bytes type, 1 Address, 1 uint256 and 1 uint32.
  /// Each bytes type takes 1 slot for length, 1 slot for data and 1 slot for the offset.
  /// address
  /// uint256 amount takes 1 slot.
  /// uint32 destGasAmount takes 1 slot.
  uint256 public constant ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * ((2 * 3) + 3);

  bytes32 internal constant EVM_2_EVM_MESSAGE_HASH = keccak256("EVM2EVMMessageHashV2");

  /// @dev Used to hash messages for single-lane ramps.
  /// OnRamp hash(EVM2EVMMessage) = OffRamp hash(EVM2EVMMessage)
  /// The EVM2EVMMessage's messageId is expected to be the output of this hash function
  /// @param original Message to hash
  /// @param metadataHash Immutable metadata hash representing a lane with a fixed OnRamp
  /// @return hashedMessage hashed message as a keccak256
  function _hash(EVM2EVMMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
    // Fixed-size message fields are included in nested hash to reduce stack pressure.
    // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.
    return keccak256(
      abi.encode(
        MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
        metadataHash,
        keccak256(
          abi.encode(
            original.sender,
            original.receiver,
            original.sequenceNumber,
            original.gasLimit,
            original.strict,
            original.nonce,
            original.feeToken,
            original.feeTokenAmount
          )
        ),
        keccak256(original.data),
        keccak256(abi.encode(original.tokenAmounts)),
        keccak256(abi.encode(original.sourceTokenData))
      )
    );
  }

  bytes32 internal constant ANY_2_EVM_MESSAGE_HASH = keccak256("Any2EVMMessageHashV1");
  bytes32 internal constant EVM_2_ANY_MESSAGE_HASH = keccak256("EVM2AnyMessageHashV1");

  /// @dev Used to hash messages for multi-lane family-agnostic OffRamps.
  /// OnRamp hash(EVM2AnyMessage) != Any2EVMRampMessage.messageId
  /// OnRamp hash(EVM2AnyMessage) != OffRamp hash(Any2EVMRampMessage)
  /// @param original OffRamp message to hash
  /// @param metadataHash Hash preimage to ensure global uniqueness
  /// @return hashedMessage hashed message as a keccak256
  function _hash(Any2EVMRampMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
    // Fixed-size message fields are included in nested hash to reduce stack pressure.
    // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.
    return keccak256(
      abi.encode(
        MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
        metadataHash,
        keccak256(
          abi.encode(
            original.header.messageId,
            original.receiver,
            original.header.sequenceNumber,
            original.gasLimit,
            original.header.nonce
          )
        ),
        keccak256(original.sender),
        keccak256(original.data),
        keccak256(abi.encode(original.tokenAmounts))
      )
    );
  }

  function _hash(EVM2AnyRampMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
    // Fixed-size message fields are included in nested hash to reduce stack pressure.
    // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.
    return keccak256(
      abi.encode(
        MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
        metadataHash,
        keccak256(
          abi.encode(
            original.sender,
            original.header.sequenceNumber,
            original.header.nonce,
            original.feeToken,
            original.feeTokenAmount
          )
        ),
        keccak256(original.receiver),
        keccak256(original.data),
        keccak256(abi.encode(original.tokenAmounts)),
        keccak256(original.extraArgs)
      )
    );
  }

  /// @dev We disallow the first 1024 addresses to avoid calling into a range known for hosting precompiles. Calling
  /// into precompiles probably won't cause any issues, but to be safe we can disallow this range. It is extremely
  /// unlikely that anyone would ever be able to generate an address in this range. There is no official range of
  /// precompiles, but EIP-7587 proposes to reserve the range 0x100 to 0x1ff. Our range is more conservative, even
  /// though it might not be exhaustive for all chains, which is OK. We also disallow the zero address, which is a
  /// common practice.
  uint256 public constant PRECOMPILE_SPACE = 1024;

  /// @notice This methods provides validation for parsing abi encoded addresses by ensuring the
  /// address is within the EVM address space. If it isn't it will revert with an InvalidEVMAddress error, which
  /// we can catch and handle more gracefully than a revert from abi.decode.
  /// @return The address if it is valid, the function will revert otherwise.
  function _validateEVMAddress(
    bytes memory encodedAddress
  ) internal pure returns (address) {
    if (encodedAddress.length != 32) revert InvalidEVMAddress(encodedAddress);
    uint256 encodedAddressUint = abi.decode(encodedAddress, (uint256));
    if (encodedAddressUint > type(uint160).max || encodedAddressUint < PRECOMPILE_SPACE) {
      revert InvalidEVMAddress(encodedAddress);
    }
    return address(uint160(encodedAddressUint));
  }

  /// @notice Enum listing the possible message execution states within
  /// the offRamp contract.
  /// UNTOUCHED never executed
  /// IN_PROGRESS currently being executed, used a replay protection
  /// SUCCESS successfully executed. End state
  /// FAILURE unsuccessfully executed, manual execution is now enabled.
  /// @dev RMN depends on this enum, if changing, please notify the RMN maintainers.
  enum MessageExecutionState {
    UNTOUCHED,
    IN_PROGRESS,
    SUCCESS,
    FAILURE
  }

  /// @notice CCIP OCR plugin type, used to separate execution & commit transmissions and configs
  enum OCRPluginType {
    Commit,
    Execution
  }

  /// @notice Family-agnostic header for OnRamp & OffRamp messages.
  /// The messageId is not expected to match hash(message), since it may originate from another ramp family
  struct RampMessageHeader {
    bytes32 messageId; // Unique identifier for the message, generated with the source chain's encoding scheme (i.e. not necessarily abi.encoded)
    uint64 sourceChainSelector; // ──╮ the chain selector of the source chain, note: not chainId
    uint64 destChainSelector; //     | the chain selector of the destination chain, note: not chainId
    uint64 sequenceNumber; //        │ sequence number, not unique across lanes
    uint64 nonce; // ────────────────╯ nonce for this lane for this sender, not unique across senders/lanes
  }

  struct EVM2AnyTokenTransfer {
    // The source pool EVM address. This value is trusted as it was obtained through the onRamp. It can be
    // relied upon by the destination pool to validate the source pool.
    address sourcePoolAddress;
    // The EVM address of the destination token
    // This value is UNTRUSTED as any pool owner can return whatever value they want.
    bytes destTokenAddress;
    // Optional pool data to be transferred to the destination chain. Be default this is capped at
    // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
    // has to be set for the specific token.
    bytes extraData;
    uint256 amount; // Amount of tokens.
    // Destination chain specific execution data encoded in bytes
    // for an EVM destination, it consists of the amount of gas available for the releaseOrMint
    // and transfer calls made by the offRamp
    bytes destExecData;
  }

  struct Any2EVMTokenTransfer {
    // The source pool EVM address encoded to bytes. This value is trusted as it is obtained through the onRamp. It can be
    // relied upon by the destination pool to validate the source pool.
    bytes sourcePoolAddress;
    address destTokenAddress; // ───╮ Address of destination token
    uint32 destGasAmount; //────────╯ The amount of gas available for the releaseOrMint and transfer calls on the offRamp.
    // Optional pool data to be transferred to the destination chain. Be default this is capped at
    // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
    // has to be set for the specific token.
    bytes extraData;
    uint256 amount; // Amount of tokens.
  }

  /// @notice Family-agnostic message routed to an OffRamp
  /// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage), hash(Any2EVMRampMessage) != messageId
  /// due to encoding & parameter differences
  struct Any2EVMRampMessage {
    RampMessageHeader header; // Message header
    bytes sender; // sender address on the source chain
    bytes data; // arbitrary data payload supplied by the message sender
    address receiver; // receiver address on the destination chain
    uint256 gasLimit; // user supplied maximum gas amount available for dest chain execution
    Any2EVMTokenTransfer[] tokenAmounts; // array of tokens and amounts to transfer
  }

  /// @notice Family-agnostic message emitted from the OnRamp
  /// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage) due to encoding & parameter differences
  /// messageId = hash(EVM2AnyRampMessage) using the source EVM chain's encoding format
  struct EVM2AnyRampMessage {
    RampMessageHeader header; // Message header
    address sender; // sender address on the source chain
    bytes data; // arbitrary data payload supplied by the message sender
    bytes receiver; // receiver address on the destination chain
    bytes extraArgs; // destination-chain specific extra args, such as the gasLimit for EVM chains
    address feeToken; // fee token
    uint256 feeTokenAmount; // fee token amount
    uint256 feeValueJuels; // fee amount in Juels
    EVM2AnyTokenTransfer[] tokenAmounts; // array of tokens and amounts to transfer
  }

  // bytes4(keccak256("CCIP ChainFamilySelector EVM"))
  bytes4 public constant CHAIN_FAMILY_SELECTOR_EVM = 0x2812d52c;

  /// @dev Struct to hold a merkle root and an interval for a source chain so that an array of these can be passed in the CommitReport.
  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
  /// @dev ineffiecient struct packing intentionally chosen to maintain order of specificity. Not a storage struct so impact is minimal.
  // solhint-disable-next-line gas-struct-packing
  struct MerkleRoot {
    uint64 sourceChainSelector; //     Remote source chain selector that the Merkle Root is scoped to
    bytes onRampAddress; //            Generic onramp address, to support arbitrary sources; for EVM, use abi.encode
    uint64 minSeqNr; // ─────────────╮ Minimum sequence number, inclusive
    uint64 maxSeqNr; // ─────────────╯ Maximum sequence number, inclusive
    bytes32 merkleRoot; //             Merkle root covering the interval & source chain messages
  }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;

library MerkleMultiProof {
  /// @notice Leaf domain separator, should be used as the first 32 bytes of a leaf's preimage.
  bytes32 internal constant LEAF_DOMAIN_SEPARATOR = 0x0000000000000000000000000000000000000000000000000000000000000000;
  /// @notice Internal domain separator, should be used as the first 32 bytes of an internal node's preiimage.
  bytes32 internal constant INTERNAL_DOMAIN_SEPARATOR =
    0x0000000000000000000000000000000000000000000000000000000000000001;

  uint256 internal constant MAX_NUM_HASHES = 256;

  error InvalidProof();
  error LeavesCannotBeEmpty();

  /// @notice Computes the root based on provided pre-hashed leaf nodes in
  /// leaves, internal nodes in proofs, and using proofFlagBits' i-th bit to
  /// determine if an element of proofs or one of the previously computed leafs
  /// or internal nodes will be used for the i-th hash.
  /// @param leaves Should be pre-hashed and the first 32 bytes of a leaf's
  /// preimage should match LEAF_DOMAIN_SEPARATOR.
  /// @param proofs The hashes to be used instead of a leaf hash when the proofFlagBits
  ///  indicates a proof should be used.
  /// @param proofFlagBits A single uint256 of which each bit indicates whether a leaf or
  ///  a proof needs to be used in a hash operation.
  /// @dev the maximum number of hash operations it set to 256. Any input that would require
  ///  more than 256 hashes to get to a root will revert.
  /// @dev For given input `leaves` = [a,b,c] `proofs` = [D] and `proofFlagBits` = 5
  ///     totalHashes = 3 + 1 - 1 = 3
  ///  ** round 1 **
  ///    proofFlagBits = (5 >> 0) & 1 = true
  ///    hashes[0] = hashPair(a, b)
  ///    (leafPos, hashPos, proofPos) = (2, 0, 0);
  ///
  ///  ** round 2 **
  ///    proofFlagBits = (5 >> 1) & 1 = false
  ///    hashes[1] = hashPair(D, c)
  ///    (leafPos, hashPos, proofPos) = (3, 0, 1);
  ///
  ///  ** round 3 **
  ///    proofFlagBits = (5 >> 2) & 1 = true
  ///    hashes[2] = hashPair(hashes[0], hashes[1])
  ///    (leafPos, hashPos, proofPos) = (3, 2, 1);
  ///
  ///    i = 3 and no longer < totalHashes. The algorithm is done
  ///    return hashes[totalHashes - 1] = hashes[2]; the last hash we computed.
  // We mark this function as internal to force it to be inlined in contracts
  // that use it, but semantically it is public.
  // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
  function merkleRoot(
    bytes32[] memory leaves,
    bytes32[] memory proofs,
    uint256 proofFlagBits
  ) internal pure returns (bytes32) {
    unchecked {
      uint256 leavesLen = leaves.length;
      uint256 proofsLen = proofs.length;
      if (leavesLen == 0) revert LeavesCannotBeEmpty();
      if (!(leavesLen <= MAX_NUM_HASHES + 1 && proofsLen <= MAX_NUM_HASHES + 1)) revert InvalidProof();
      uint256 totalHashes = leavesLen + proofsLen - 1;
      if (!(totalHashes <= MAX_NUM_HASHES)) revert InvalidProof();
      if (totalHashes == 0) {
        return leaves[0];
      }
      bytes32[] memory hashes = new bytes32[](totalHashes);
      (uint256 leafPos, uint256 hashPos, uint256 proofPos) = (0, 0, 0);

      for (uint256 i = 0; i < totalHashes; ++i) {
        // Checks if the bit flag signals the use of a supplied proof or a leaf/previous hash.
        bytes32 a;
        if (proofFlagBits & (1 << i) == (1 << i)) {
          // Use a leaf or a previously computed hash.
          if (leafPos < leavesLen) {
            a = leaves[leafPos++];
          } else {
            a = hashes[hashPos++];
          }
        } else {
          // Use a supplied proof.
          a = proofs[proofPos++];
        }

        // The second part of the hashed pair is never a proof as hashing two proofs would result in a
        // hash that can already be computed offchain.
        bytes32 b;
        if (leafPos < leavesLen) {
          b = leaves[leafPos++];
        } else {
          b = hashes[hashPos++];
        }

        if (!(hashPos <= i)) revert InvalidProof();

        hashes[i] = _hashPair(a, b);
      }
      if (!(hashPos == totalHashes - 1 && leafPos == leavesLen && proofPos == proofsLen)) revert InvalidProof();
      // Return the last hash.
      return hashes[totalHashes - 1];
    }
  }

  /// @notice Hashes two bytes32 objects in their given order, prepended by the
  /// INTERNAL_DOMAIN_SEPARATOR.
  function _hashInternalNode(bytes32 left, bytes32 right) private pure returns (bytes32 hash) {
    return keccak256(abi.encode(INTERNAL_DOMAIN_SEPARATOR, left, right));
  }

  /// @notice Hashes two bytes32 objects. The order is taken into account,
  /// using the lower value first.
  function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
    return a < b ? _hashInternalNode(a, b) : _hashInternalNode(b, a);
  }
}

Settings
{
  "remappings": [
    "@chainlink/contracts-ccip/=lib/ccip/contracts/",
    "@chainlink/contracts/=lib/chainlink-brownie-contracts/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@solady/=lib/solady/src/",
    "ccip/=lib/ccip/contracts/",
    "chainlink-brownie-contracts/=lib/chainlink-brownie-contracts/contracts/src/v0.6/vendor/@arbitrum/nitro-contracts/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solady/=lib/solady/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"AggregateValueMaxCapacityExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"minWaitInSeconds","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"AggregateValueRateLimitReached","type":"error"},{"inputs":[],"name":"BucketOverfilled","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"ChainAlreadyEnabled","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"ChainNotSupported","type":"error"},{"inputs":[],"name":"CursedByRMN","type":"error"},{"inputs":[{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"config","type":"tuple"}],"name":"DisabledNonZeroRateLimit","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ERC721TransferFailed","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"rateLimiterConfig","type":"tuple"}],"name":"InvalidRateLimitRate","type":"error"},{"inputs":[{"internalType":"address","name":"expected","type":"address"},{"internalType":"address","name":"actual","type":"address"}],"name":"InvalidRouter","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"LengthMismatch","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"MessageIdAlreadyExists","type":"error"},{"inputs":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"MintFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"MsgValueNotAllowed","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"NonExistentChain","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"OnlyLocalChain","type":"error"},{"inputs":[],"name":"OnlyLocalToken","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"OnlyRemoteChain","type":"error"},{"inputs":[],"name":"RateLimitMustBeDisabled","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"RefundFailed","type":"error"},{"inputs":[{"internalType":"uint64","name":"expected","type":"uint64"},{"internalType":"uint64","name":"actual","type":"uint64"}],"name":"RemoteChainSelectorNotMatch","type":"error"},{"inputs":[{"internalType":"address","name":"expected","type":"address"},{"internalType":"address","name":"actual","type":"address"}],"name":"RemotePoolNotMatch","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"address","name":"sender","type":"address"}],"name":"SenderNotEnabled","type":"error"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"address","name":"remoteToken","type":"address"}],"name":"TokenAlreadyMapped","type":"error"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenMaxCapacityExceeded","type":"error"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"TokenNotMapped","type":"error"},{"inputs":[{"internalType":"uint256","name":"minWaitInSeconds","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenRateLimitReached","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"inputs":[],"name":"ZeroValueNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"config","type":"tuple"}],"name":"ConfigChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"srcFrom","type":"address"},{"indexed":true,"internalType":"address","name":"dstTo","type":"address"},{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint64","name":"srcChainSelector","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"dstChainSelector","type":"uint64"}],"name":"CrossTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint32","name":"fixedGas","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"dynamicGas","type":"uint32"}],"name":"GasLimitConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"MessageReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"MessageSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"chainSelector","type":"uint64"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"outboundConfig","type":"tuple"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"inboundConfig","type":"tuple"}],"name":"RateLimitConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Refunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"RemoteChainDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"chainSelector","type":"uint64"},{"indexed":true,"internalType":"address","name":"remoteSender","type":"address"}],"name":"RemoteChainEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"indexed":true,"internalType":"address","name":"remotePool","type":"address"}],"name":"RemotePoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"RemotePoolRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"indexed":true,"internalType":"address","name":"localToken","type":"address"},{"indexed":false,"internalType":"address","name":"remoteToken","type":"address"}],"name":"RemoteTokenMapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"indexed":true,"internalType":"address","name":"localToken","type":"address"}],"name":"RemoteTokenUnmapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"sharedStorage","type":"address"},{"indexed":false,"internalType":"bool","name":"shouldAdd","type":"bool"}],"name":"SharedStorageUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"TokensConsumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATE_LIMITER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARED_STORAGE_SETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_POOL_OWNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"remotePool","type":"address"}],"name":"addRemotePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes","name":"sender","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"destTokenAmounts","type":"tuple[]"}],"internalType":"struct Client.Any2EVMMessage","name":"message","type":"tuple"}],"name":"ccipReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"crossBatchTransfer","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"crossTransfer","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"uint256","name":"tokenCount","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"estimateFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentChainSelector","outputs":[{"internalType":"uint64","name":"currentChainSelector","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getCurrentInboundRateLimiterState","outputs":[{"components":[{"internalType":"uint128","name":"tokens","type":"uint128"},{"internalType":"uint32","name":"lastUpdated","type":"uint32"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.TokenBucket","name":"state","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getCurrentOutboundRateLimiterState","outputs":[{"components":[{"internalType":"uint128","name":"tokens","type":"uint128"},{"internalType":"uint32","name":"lastUpdated","type":"uint32"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.TokenBucket","name":"state","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getFeeTokens","outputs":[{"internalType":"address[]","name":"feeTokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGlobalPauser","outputs":[{"internalType":"address","name":"globalPauser","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getMessageIds","outputs":[{"internalType":"uint256","name":"length","type":"uint256"},{"internalType":"bytes32[]","name":"messageIds","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getRemotePool","outputs":[{"internalType":"address","name":"remotePool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRemotePools","outputs":[{"internalType":"uint64[]","name":"remoteChainSelectors","type":"uint64[]"},{"internalType":"address[]","name":"remotePools","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getRemoteToken","outputs":[{"internalType":"address","name":"remoteToken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRmnProxy","outputs":[{"internalType":"contract IRMN","name":"rmnProxy","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMembers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRouter","outputs":[{"internalType":"contract IRouterClientExtended","name":"router","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupportedChains","outputs":[{"internalType":"uint64[]","name":"remoteChainSelectors","type":"uint64[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getSupportedTokensForChain","outputs":[{"internalType":"address[]","name":"localTokens","type":"address[]"},{"internalType":"address[]","name":"remoteTokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokens","outputs":[{"internalType":"address[]","name":"localTokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint64","name":"currentChainSelector","type":"uint64"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"feeToken","type":"address"}],"name":"isFeeTokenSupported","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"currentChainSelector","type":"uint64"}],"name":"isLocalChain","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"sender","type":"address"}],"name":"isSenderEnabled","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sharedStorage","type":"address"}],"name":"isSharedStorage","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"isSupportedChain","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"}],"name":"isSupportedToken","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"remoteToken","type":"address"}],"name":"mapRemoteToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"removeRemotePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"outboundConfig","type":"tuple"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"inboundConfig","type":"tuple"}],"name":"setChainRateLimiterConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"globalPauser","type":"address"}],"name":"setGlobalPauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sharedStorage","type":"address"},{"internalType":"bool","name":"shouldAdd","type":"bool"}],"name":"setSharedStorage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"unmapRemoteToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"localTokens","type":"address[]"},{"internalType":"address[]","name":"tos","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"withdrawLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080604052348015600e575f5ffd5b5060156019565b60c9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560685760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b614fce806100d65f395ff3fe608060405260043610610243575f3560e01c8063017e25e31461024757806301ffc9a71461026857806307a40f0b1461029c5780630a2fd493146102bb578063181f5a77146102e757806320cf81231461033c578063240028e81461035b578063248a9ca31461037a5780632e86678f146103a75780632f2ff15d146103c65780632faa5dc7146103e55780633195ac8314610404578063322cfeda1461043057806333fbf7191461044f57806336568abe1461046e5780633ab9e4921461048d5780633f4ba83a146104a05780633fd8c1b5146104b457806346e28a09146104e157806356b5440c146105005780635c975abb1461052d5780636b0e4f86146105415780636e15e242146105605780637879ec311461057d5780638456cb591461059c57806385572ffb146105b05780638926f54f146105cf5780638bdd6d8e146105ee5780638f20071d1461060e5780639010d07c1461063d57806391d148541461065c5780639bc53a201461067b578063a217fddf1461069a578063a3246ad3146106ad578063aa6ca808146106cc578063af58d59f146106e0578063b0f479a114610752578063bb0edba014610770578063bd9421e11461078f578063c4bffe2b146107ae578063c75eea9c146107cf578063ca15c873146107ee578063cf7401f31461080d578063d3bd04f11461082c578063d547741f1461083f578063d6111d861461085e578063db87d27814610880578063dc0bd971146108a0578063e60d6462146108c5578063e63ab1e9146108e5578063eab2c75714610905575b5f5ffd5b348015610252575f5ffd5b50610266610261366004614037565b610926565b005b348015610273575f5ffd5b50610287610282366004614052565b610996565b60405190151581526020015b60405180910390f35b3480156102a7575f5ffd5b506102666102b6366004614086565b6109cf565b3480156102c6575f5ffd5b506102da6102d53660046140d3565b610a6f565b60405161029391906140ec565b3480156102f2575f5ffd5b5061032f6040518060400160405280601d81526020017f4d756c74694c6f636b4d696e74455243373231506f6f6c20312e302e3000000081525081565b604051610293919061412e565b348015610347575f5ffd5b50610266610356366004614140565b610a79565b348015610366575f5ffd5b50610287610375366004614037565b610adf565b348015610385575f5ffd5b5061039961039436600461416a565b610b67565b604051908152602001610293565b3480156103b2575f5ffd5b506102666103c1366004614181565b610b85565b3480156103d1575f5ffd5b506102666103e03660046141c7565b610c21565b3480156103f0575f5ffd5b506102666103ff3660046140d3565b610c43565b34801561040f575f5ffd5b5061042361041e3660046140d3565b610c9c565b604051610293919061422d565b34801561043b575f5ffd5b5061039961044a36600461423f565b610de4565b34801561045a575f5ffd5b506102666104693660046142c7565b610ebb565b348015610479575f5ffd5b506102666104883660046141c7565b611022565b61039961049b366004614363565b611055565b3480156104ab575f5ffd5b50610266611077565b3480156104bf575f5ffd5b506104d36104ce3660046143cd565b611099565b6040516102939291906143fd565b3480156104ec575f5ffd5b506102876104fb366004614037565b6111a5565b34801561050b575f5ffd5b5061051f61051a3660046140d3565b6111c2565b60405161029392919061444a565b348015610538575f5ffd5b50610287611357565b34801561054c575f5ffd5b5061028761055b366004614140565b61140c565b34801561056b575f5ffd5b506032546001600160a01b03166102da565b348015610588575f5ffd5b5061026661059736600461446e565b61144e565b3480156105a7575f5ffd5b50610266611573565b3480156105bb575f5ffd5b506102666105ca3660046144b2565b611592565b3480156105da575f5ffd5b506102876105e93660046140d3565b611632565b3480156105f9575f5ffd5b506103995f516020614f195f395f51905f5281565b348015610619575f5ffd5b506102876106283660046140d3565b610162546001600160401b0391821691161490565b348015610648575f5ffd5b506102da6106573660046144e8565b6116bf565b348015610667575f5ffd5b506102876106763660046141c7565b6116eb565b348015610686575f5ffd5b506102da610695366004614508565b61171f565b3480156106a5575f5ffd5b506103995f81565b3480156106b8575f5ffd5b506104236106c736600461416a565b611768565b3480156106d7575f5ffd5b5061042361178c565b3480156106eb575f5ffd5b506106ff6106fa3660046140d3565b611880565b604051610293919081516001600160801b03908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b34801561075d575f5ffd5b50610163546001600160a01b03166102da565b34801561077b575f5ffd5b5061026661078a366004614508565b611906565b34801561079a575f5ffd5b506102876107a9366004614140565b611977565b3480156107b9575f5ffd5b506107c26119f4565b6040516102939190614574565b3480156107da575f5ffd5b506106ff6107e93660046140d3565b611b32565b3480156107f9575f5ffd5b5061039961080836600461416a565b611bb8565b348015610818575f5ffd5b5061026661082736600461459c565b611bdb565b61039961083a3660046145d5565b611c19565b34801561084a575f5ffd5b506102666108593660046141c7565b611c68565b348015610869575f5ffd5b50610872611c84565b604051610293929190614666565b34801561088b575f5ffd5b506103995f516020614f595f395f51905f5281565b3480156108ab575f5ffd5b5061016254600160401b90046001600160a01b03166102da565b3480156108d0575f5ffd5b506103995f516020614f395f395f51905f5281565b3480156108f0575f5ffd5b506103995f516020614f795f395f51905f5281565b348015610910575f5ffd5b50610919611d3c565b6040516102939190614678565b5f61093081611d4c565b603280546001600160a01b0319166001600160a01b03841690811790915561097b57603254610976905f516020614f795f395f51905f52906001600160a01b0316611d56565b505050565b6109765f516020614f795f395f51905f5283611d95565b5050565b5f6001600160e01b03198216636d7f8bbd60e11b14806109ba57506109ba82611dcb565b806109c957506109c982611e1c565b92915050565b5f516020614f595f395f51905f526109e681611d4c565b6001600160a01b038316610a0d576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0383165f81815260fd6020908152604091829020805460ff1916861515908117909155915191825233917f613ecbe5e56592771e18a638a133dc61a4488af23ac95580246a6dfa5edf240291015b60405180910390a3505050565b5f6109c982611e40565b5f516020614f195f395f51905f52610a9081611d4c565b610a9a8383611e7a565b6040516001600160a01b038316906001600160401b0385169033907f9f60ea76bb48f63c19a3d1bc23acb2a57138cbf18441efefe59a3d0c124d93ac905f90a4505050565b5f610aec61023183611fe5565b610af757505f919050565b5f610b006119f4565b80519091505f5b81811015610b5d575f6001600160a01b0316610b3c86858481518110610b2f57610b2f61468c565b602002602001015161171f565b6001600160a01b031614610b5557506001949350505050565b600101610b07565b505f949350505050565b5f5f610b71611ff9565b5f9384526020525050604090206001015490565b5f516020614f195f395f51905f52610b9c81611d4c565b83610ba68161201d565b83610bb081612044565b610bb98461201d565b610bc486868661206c565b856001600160a01b0316856001600160401b0316336001600160a01b03167feea3add3a72bfdec05437019247fe0e77d59874c7ae83510efc39677e14f9aa087604051610c1191906140ec565b60405180910390a4505050505050565b610c2a82610b67565b610c3381611d4c565b610c3d8383611d95565b50505050565b5f516020614f195f395f51905f52610c5a81611d4c565b610c6382612155565b6040516001600160401b0383169033907faf18d5efc97c08e5572a2feab86f2b1200f9ccceac5f451c0cce5d00822c5010905f90a35050565b606081610ca881612044565b6101635460405163a8d87a3b60e01b81526001600160a01b039091169063a8d87a3b90610cd9908690600401614678565b602060405180830381865afa158015610cf4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d1891906146ab565b6001600160a01b0316637437ff9f6040518163ffffffff1660e01b81526004016101a060405180830381865afa158015610d54573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d789190614784565b60e001516001600160a01b031663cdc73d516040518163ffffffff1660e01b81526004015f60405180830381865afa158015610db6573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ddd91908101906148a9565b9392505050565b6040805160c0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820152836001600160401b03811115610e2b57610e2b6146c6565b604051908082528060200260200182016040528015610e54578160200160208202803683370190505b50604051602001610e65919061496d565b60408051601f1981840301815291905260a0820152610eb085610e8781610a6f565b83604051602001610e98919061497f565b6040516020818303038152906040528660018b6121d9565b509695505050505050565b5f610ec581611d4c565b85610ed0818461238a565b610eda818661238a565b610ee3816123b4565b5f5b8181101561101757610f1c898983818110610f0257610f0261468c565b9050602002016020810190610f179190614037565b6123d4565b610f4b878783818110610f3157610f3161468c565b9050602002016020810190610f469190614037565b61201d565b888882818110610f5d57610f5d61468c565b9050602002016020810190610f729190614037565b6001600160a01b03166323b872dd30898985818110610f9357610f9361468c565b9050602002016020810190610fa89190614037565b888886818110610fba57610fba61468c565b905060200201356040518463ffffffff1660e01b8152600401610fdf939291906149ec565b5f604051808303815f87803b158015610ff6575f5ffd5b505af1158015611008573d5f5f3e3d5ffd5b50505050806001019050610ee5565b505050505050505050565b6001600160a01b038116331461104b5760405163334bd91960e11b815260040160405180910390fd5b6109768282611d56565b5f61106c878787611065886123fa565b8787612440565b979650505050505050565b5f516020614f795f395f51905f5261108e81611d4c565b611096612568565b50565b6001600160401b0383165f9081526101cb602052604090205460608184106110cf5750604080515f81526020810190915261119d565b816110da8486614a24565b11156110ed576110ea8483614a37565b92505b826001600160401b03811115611105576111056146c6565b60405190808252806020026020018201604052801561112e578160200160208202803683370190505b5090505f5b8381101561119b576001600160401b0386165f9081526101cb6020526040902061115d8287614a24565b8154811061116d5761116d61468c565b905f5260205f2001548282815181106111885761118861468c565b6020908102919091010152600101611133565b505b935093915050565b6001600160a01b03165f90815260fd602052604090205460ff1690565b6060806111ce83611632565b6111ef575050604080515f8082526020820190815281830190925292909150565b5f6111fb6102316125be565b9050806001600160401b03811115611215576112156146c6565b60405190808252806020026020018201604052801561123e578160200160208202803683370190505b509250806001600160401b03811115611259576112596146c6565b604051908082528060200260200182016040528015611282578160200160208202803683370190505b5091505f5f5b82811015611349575f61129d610231836125c7565b6001600160a01b038082165f908152610233602090815260408083206001600160401b038d16845290915290205491925016801561133f57818785815181106112e8576112e861468c565b60200260200101906001600160a01b031690816001600160a01b0316815250508086858151811061131b5761131b61468c565b6001600160a01b039092166020928302919091019091015261133c84614a4a565b93505b5050600101611288565b508084528083525050915091565b6032545f906001600160a01b031661137c5f516020614f795f395f51905f52826116eb565b801561139157506001600160a01b0381163b15155b80156113f85750806001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113d4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113f89190614a62565b8061140657506114066125d2565b91505090565b5f61141683611632565b61142157505f6109c9565b506001600160401b03919091165f90815261016660205260409020546001600160a01b0390811691161490565b5f6114576125e6565b805490915060ff600160401b82041615906001600160401b03165f8115801561147d5750825b90505f826001600160401b031660011480156114985750303b155b9050811580156114a6575080155b156114c45760405163f92ee8a960e01b815260040160405180910390fd5b84546001600160401b031916600117855583156114ed57845460ff60401b1916600160401b1785555b6114f75f89611d95565b506115018861260e565b61150a8861261f565b61151388612630565b61151e888888612641565b831561156957845460ff60401b191685556040517fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29061156090600190614678565b60405180910390a15b5050505050505050565b5f516020614f795f395f51905f5261158a81611d4c565b61109661265c565b6115a260408201602083016140d3565b6115ab816126a2565b5f6115b96040840184614a7d565b8101906115c69190614037565b90506115e16115db60408501602086016140d3565b82612741565b6115e9612782565b6115f2836127c0565b825f01357fce0ee41dd56ba56504e3cbb18167239f0ff664e41824e710d406e710e3ed0a388260405161162591906140ec565b60405180910390a2505050565b5f6116486101646001600160401b038416612957565b80156109c9575061016354604051631491520b60e31b81526001600160a01b039091169063a48a905890611680908590600401614678565b602060405180830381865afa15801561169b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109c99190614a62565b5f5f6116c9612962565b5f8581526020829052604090209091506116e390846125c7565b949350505050565b5f5f6116f5611ff9565b5f948552602090815260408086206001600160a01b03959095168652939052505090205460ff1690565b5f61172982611632565b61173457505f6109c9565b506001600160a01b039182165f908152610233602090815260408083206001600160401b0394909416835292905220541690565b60605f611773612962565b5f848152602082905260409020909150610ddd90612986565b60605f61179a610231612986565b8051909150806001600160401b038111156117b7576117b76146c6565b6040519080825280602002602001820160405280156117e0578160200160208202803683370190505b5092505f5f5b82811015611876576118108482815181106118035761180361468c565b6020026020010151610adf565b1561186e578381815181106118275761182761468c565b602002602001015185838061183b90614a4a565b94508151811061184d5761184d61468c565b60200260200101906001600160a01b031690816001600160a01b0316815250505b6001016117e6565b5080845250505090565b611888613fe6565b6001600160401b0382165f90815260986020908152604091829020825160a08101845281546001600160801b038082168352600160801b80830463ffffffff1695840195909552600160a01b90910460ff1615159482019490945260019091015480841660608301529190910490911660808201526109c990612992565b5f516020614f195f395f51905f5261191d81611d4c565b8161192781612044565b61193184846129fc565b6040516001600160a01b038516906001600160401b0385169033907f1397d60c55aea4f977e36de26ece59e6c1111bb420cc66e2d9565bc475bf82ef905f90a450505050565b5f5f61198284610c9c565b80519091505f819003611999575f925050506109c9565b5f5b818110156119e957846001600160a01b03168382815181106119bf576119bf61468c565b60200260200101516001600160a01b0316036119e157600193505050506109c9565b60010161199b565b505f95945050505050565b60605f611a02610164612986565b8051909150806001600160401b03811115611a1f57611a1f6146c6565b604051908082528060200260200182016040528015611a48578160200160208202803683370190505b5092505f5f5b82811015611876575f848281518110611a6957611a6961468c565b602090810291909101015161016354604051631491520b60e31b81529192506001600160a01b03169063a48a905890611aa6908490600401614678565b602060405180830381865afa158015611ac1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ae59190614a62565b15611b2957808684611af681614a4a565b955081518110611b0857611b0861468c565b60200260200101906001600160401b031690816001600160401b0316815250505b50600101611a4e565b611b3a613fe6565b6001600160401b0382165f90815260976020908152604091829020825160a08101845281546001600160801b038082168352600160801b80830463ffffffff1695840195909552600160a01b90910460ff1615159482019490945260019091015480841660608301529190910490911660808201526109c990612992565b5f5f611bc2612962565b5f848152602082905260409020909150610ddd906125be565b5f516020614f395f395f51905f52611bf281611d4c565b610c3d84611c0536869003860186614ad5565b611c1436869003860186614ad5565b612ab6565b5f611c5c8888888888808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152508a92508991506124409050565b98975050505050505050565b611c7182610b67565b611c7a81611d4c565b610c3d8383611d56565b606080611c8f6119f4565b8051909250806001600160401b03811115611cac57611cac6146c6565b604051908082528060200260200182016040528015611cd5578160200160208202803683370190505b5091505f5b81811015611d3657611d04848281518110611cf757611cf761468c565b6020026020010151610a6f565b838281518110611d1657611d1661468c565b6001600160a01b0390921660209283029190910190910152600101611cda565b50509091565b610162546001600160401b031690565b6110968133612b51565b5f5f611d60612962565b90505f611d6d8585612b7c565b905080156116e3575f858152602083905260409020611d8c9085612bfb565b50949350505050565b5f5f611d9f612962565b90505f611dac8585612c0f565b905080156116e3575f858152602083905260409020611d8c9085612ca4565b5f6001600160e01b031982166319167f6d60e11b1480611def5750611def82612cb8565b80611dfe5750611dfe82612cf7565b80611e0d5750611e0d82612d17565b806109c957506109c982612d37565b5f6001600160e01b031982166319c7358960e21b14806109c957506109c982612cb8565b5f611e4a82611632565b611e5557505f919050565b506001600160401b03165f90815261016660205260409020546001600160a01b031690565b611e838161201d565b610162546001600160401b0390811690831603611ebe578160405163af86032f60e01b8152600401611eb59190614678565b60405180910390fd5b61016354604051631491520b60e31b81526001600160a01b039091169063a48a905890611eef908590600401614678565b602060405180830381865afa158015611f0a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f2e9190614a62565b611f4d578160405163172ced9d60e11b8152600401611eb59190614678565b611f626101646001600160401b038416612d5b565b611f815781604051632f2c07d760e01b8152600401611eb59190614678565b6001600160401b0382165f818152610166602052604080822080546001600160a01b0319166001600160a01b038616908117909155905190929133917f8de8fd9740da5fc201a38a6085490fd6dfc07ce3a73938627eac66a5e748cefb9190a45050565b5f610ddd836001600160a01b038416612d66565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680090565b6001600160a01b038116611096576040516342bcdf7f60e11b815260040160405180910390fd5b61204d81611632565b6110965780604051631e670e4b60e01b8152600401611eb59190614678565b5f5f612077846111c2565b8051919350915015612100575f5b81518110156120fe57836001600160a01b03168282815181106120aa576120aa61468c565b60200260200101516001600160a01b0316036120f6578281815181106120d2576120d261468c565b602002602001015184604051631cfa01f360e11b8152600401611eb5929190614b42565b600101612085565b505b61210c61023186612ca4565b5050506001600160a01b039283165f908152610233602090815260408083206001600160401b039590951683529390529190912080546001600160a01b03191691909216179055565b61216a6101646001600160401b038316612d7d565b6121895780604051631e670e4b60e01b8152600401611eb59190614678565b6001600160401b0381165f818152610166602052604080822080546001600160a01b03191690555133917fb7c3517ce5cb1b2e820e49d7850f4e0e71cde55b70c0995bab3b7eafe3abc87291a350565b5f6122146040518060a001604052806060815260200160608152602001606081526020015f6001600160a01b03168152602001606081525090565b8761221e81612044565b6040805160a08101909152806122378a60c083016140ec565b60408051808303601f1901815291815290825260208083018b905281515f808252918101835292909101919061228e565b604080518082019091525f80825260208201528152602001906001900390816122685790505b508152602001856001600160a01b0316815260200161230760405180604001604052808a81526020018915158152506040805182516024820152602092830151151560448083019190915282518083039091018152606490910190915290810180516001600160e01b0316630181dcf160e41b17905290565b9052610163546040516320487ded60e01b81529193506001600160a01b0316906320487ded9061233d908c908690600401614b5c565b602060405180830381865afa158015612358573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061237c9190614c2e565b925050965096945050505050565b808214610992576040516355c5b3e360e11b81526004810183905260248101829052604401611eb5565b805f036110965760405163273e150360e21b815260040160405180910390fd5b6123dd81610adf565b6110965760405163f850ff3b60e01b815260040160405180910390fd5b6040805160018082528183019092526060916020808301908036833701905050905081815f8151811061242f5761242f61468c565b602002602001018181525050919050565b5f8461244b8161201d565b5f8560405160200161245d919061496d565b60408051601f198184030181526060830182526001600160401b038b1683526001600160a01b038c166020840152908201819052915061249c90612d88565b5f6124a78a8a61171f565b90506124b28161201d565b612548896124bf8b610a6f565b6040518060c00160405280336001600160a01b031681526020016124e1611d3c565b6001600160401b031681526020018c6001600160a01b03168152602001856001600160a01b03168152602001306001600160a01b0316815260200186815250604051602001612530919061497f565b6040516020818303038152906040528860018b612e88565b935061255b612555611d3c565b856131f7565b5050509695505050505050565b61257061329f565b5f6125796132c4565b805460ff1916815590507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516125b391906140ec565b60405180910390a150565b5f6109c9825490565b5f610ddd83836132e8565b5f5f6125dc6132c4565b5460ff1692915050565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a006109c9565b61261661330e565b61109681613333565b61262761330e565b6110968161336d565b61263861330e565b6110968161338c565b61264961330e565b612652836133ab565b61097682826133ca565b6126646133dc565b5f61266d6132c4565b805460ff1916600117815590507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125a63390565b61016254604051632cbc26bb60e01b8152608083901b600160801b600160c01b03166004820152600160401b9091046001600160a01b031690632cbc26bb90602401602060405180830381865afa1580156126ff573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127239190614a62565b1561109657604051630a75a23b60e31b815260040160405180910390fd5b61274b828261140c565b6109925760405163d5079a3560e01b81526001600160401b03831660048201526001600160a01b0382166024820152604401611eb5565b610163546001600160a01b031633146127be5761016354604051637ec1982b60e01b8152611eb5916001600160a01b0316903390600401614b42565b565b5f6127ce6060830183614a7d565b8101906127db9190614cb0565b905080602001516001600160401b03168260200160208101906127fe91906140d3565b6001600160401b03161461284d5761281c60408301602084016140d3565b6020820151604051638428f1f760e01b81526001600160401b03928316600482015291166024820152604401611eb5565b5f61285b6040840184614a7d565b8101906128689190614037565b905081608001516001600160a01b0316816001600160a01b0316146128a75760808201516040516310c4624f60e21b8152611eb5918391600401614b42565b81516128b29061201d565b60208201516128c29084356131f7565b6128cb82613402565b825f013582604001516001600160a01b0316835f01516001600160a01b03167f55e75798c6b341acacc33826c47c58fccf851dda1790809862e7299fe1874d448560a001518060200190518101906129239190614d75565b6129336040890160208a016140d3565b61293b611d3c565b60405161294a93929190614dfb565b60405180910390a4505050565b5f610ddd8383612d66565b7fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e8237170593200090565b60605f610ddd83613420565b61299a613fe6565b6129e182606001516001600160801b0316835f01516001600160801b0316846020015163ffffffff16426129ce9190614a37565b85608001516001600160801b0316613479565b6001600160801b031682525063ffffffff4216602082015290565b6001600160a01b038083165f908152610233602090815260408083206001600160401b03861684529091529020541680612a6357604051639bc50b1760e01b81526001600160a01b03841660048201526001600160401b0383166024820152604401611eb5565b6001600160a01b0383165f908152610233602090815260408083206001600160401b0386168452909152902080546001600160a01b0319169055612aa683610adf565b61097657610c3d61023184612bfb565b612ac0825f6134a0565b6001600160401b0383165f908152609760205260409020612ae19083613561565b612aeb815f6134a0565b6001600160401b0383165f908152609860205260409020612b0c9082613561565b826001600160401b0316336001600160a01b03167f3a6cd4bdc00dc992306b6d7795432a8934d7c9fbdb85b49faad03dad43c817248484604051610a62929190614e57565b612b5b82826116eb565b61099257808260405163e2517d3f60e01b8152600401611eb5929190614e72565b5f5f612b86611ff9565b9050612b9284846116eb565b15612bf2575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a460019150506109c9565b5f9150506109c9565b5f610ddd836001600160a01b03841661367a565b5f5f612c19611ff9565b9050612c2584846116eb565b612bf2575f848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055612c5a3390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a460019150506109c9565b5f610ddd836001600160a01b038416613754565b5f6001600160e01b0319821663181f5a7760e01b1480612ce857506001600160e01b0319821663d6d62d0d60e01b145b806109c957506109c98261379b565b5f6001600160e01b03198216634d60abbd60e11b14806109c957506109c9825b5f6001600160e01b031982166320bfad4960e11b14806109c957506109c9825b5f6001600160e01b0319821663324c152b60e01b14806109c957506109c9826137eb565b5f610ddd8383613754565b5f9081526001919091016020526040902054151590565b5f610ddd838361367a565b612d906133dc565b8060200151612d9e816123d4565b8151612da981612044565b5f8360400151806020019051810190612dc29190614d75565b8051909150612dd0816123b4565b5f5b81811015612e5f5785602001516001600160a01b03166323b872dd3330868581518110612e0157612e0161468c565b60200260200101516040518463ffffffff1660e01b8152600401612e27939291906149ec565b5f604051808303815f87803b158015612e3e575f5ffd5b505af1158015612e50573d5f5f3e3d5ffd5b50505050806001019050612dd2565b50612e6f8560200151308461380f565b612e81855f0151866020015183613894565b5050505050565b5f86612e93816126a2565b612e9c8761201d565b612ea5856123b4565b612eaf86516123b4565b5f5f612ebf8a8a8a8a8a8a6121d9565b90925090505f6001600160a01b038616612ff55782341015612efd5760405163054365bb60e31b815260048101849052346024820152604401611eb5565b6101635f9054906101000a90046001600160a01b03166001600160a01b031663e861e9076040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f4e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f7291906146ab565b95508582606001906001600160a01b031690816001600160a01b031681525050856001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004015f604051808303818588803b158015612fcb575f5ffd5b505af1158015612fdd573d5f5f3e3d5ffd5b50505050508234612fee9190614a37565b905061302b565b3415613016576040516336334e4560e01b8152346004820152602401611eb5565b61302b6001600160a01b0387163330866138b6565b6101635460405163095ea7b360e01b81526001600160a01b038881169263095ea7b39261306092909116908790600401614e72565b6020604051808303815f875af115801561307c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130a09190614a62565b50610163546040516396f4e9f960e01b81526001600160a01b03909116906396f4e9f9906130d4908e908690600401614b5c565b6020604051808303815f875af11580156130f0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131149190614c2e565b945080156131bd576040515f90339083908381818185875af1925050503d805f811461315b576040519150601f19603f3d011682016040523d82523d5f602084013e613160565b606091505b50509050806131865733826040516357b9d85960e11b8152600401611eb5929190614e72565b60405182815233907fd7dee2702d63ad89917b6a4da9981c90c4d24f8c2bdfd64c604ecae57d8d06519060200160405180910390a2505b604051859033907fb06a7d56e5736d613c3122470fadaf19fa9b76fbc2244c4ed1bab9c2c4d6213b905f90a3505050509695505050505050565b6001600160401b0382165f9081526101cc6020908152604080832084845290915290205460ff161561324e576040516342cb76b360e11b81526001600160401b038316600482015260248101829052604401611eb5565b6001600160401b039091165f8181526101cb60209081526040808320805460018181018355918552838520018690559383526101cc825280832094835293905291909120805460ff19169091179055565b6132a7611357565b6127be57604051638dfc202b60e01b815260040160405180910390fd5b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330090565b5f825f0182815481106132fd576132fd61468c565b905f5260205f200154905092915050565b613316613910565b6127be57604051631afcd79f60e31b815260040160405180910390fd5b61333b61330e565b603280546001600160a01b0319166001600160a01b0383161790556109925f516020614f795f395f51905f5282611d95565b61337561330e565b6109925f516020614f395f395f51905f5282611d95565b61339461330e565b6109925f516020614f595f395f51905f5282611d95565b6133b361330e565b6109925f516020614f195f395f51905f5282611d95565b6133d261330e565b6109928282613929565b6133e4611357565b156127be5760405163d93c066560e01b815260040160405180910390fd5b613417610f468260600151836020015161171f565b61109681613a04565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561346d57602002820191905f5260205f20905b815481526020019060010190808311613459575b50505050509050919050565b5f613497856134888486614e8b565b6134929087614a24565b613ba4565b95945050505050565b81511561351a5781602001516001600160801b031682604001516001600160801b03161015806134db575060408201516001600160801b0316155b156134fb5781604051632008344960e21b8152600401611eb59190614ea2565b80156109925760405163433fc33d60e01b815260040160405180910390fd5b60408201516001600160801b0316151580613541575060208201516001600160801b031615155b1561099257816040516335a2be7360e21b8152600401611eb59190614ea2565b81545f9061357c90600160801b900463ffffffff1642614a37565b905080156135da57600183015483546135ae916001600160801b03808216928116918591600160801b90910416613479565b83546001600160801b03919091166001600160a01b031990911617600160801b4263ffffffff16021783555b602082015183546135f7916001600160801b039081169116613ba4565b835483511515600160a01b02600164ff0000000160801b03199091166001600160801b039283161717845560208301516040808501518316600160801b0291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c199061366d908490614ea2565b60405180910390a1505050565b5f8181526001830160205260408120548015612bf2575f61369c600183614a37565b85549091505f906136af90600190614a37565b905080821461370e575f865f0182815481106136cd576136cd61468c565b905f5260205f200154905080875f0184815481106136ed576136ed61468c565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061371f5761371f614eb0565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506109c9565b5f61375f8383612d66565b61379457508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556109c9565b505f6109c9565b5f6001600160e01b031982166351fdd48d60e11b14806137cb57506001600160e01b031982166385572ffb60e01b145b806109c957506001600160e01b031982166301ffc9a760e01b1492915050565b5f6001600160e01b03198216635a05180f60e01b14806109c957506109c982613bb9565b80515f5b81811015612e8157836001600160a01b03166138488685848151811061383b5761383b61468c565b6020026020010151613bed565b6001600160a01b03161461388c57838382815181106138695761386961468c565b6020026020010151604051631cc2e71960e31b8152600401611eb5929190614e72565b600101613813565b6001600160401b0383165f908152609760205260409020610976908284613c62565b610c3d84856001600160a01b03166323b872dd8686866040516024016138de939291906149ec565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050613e73565b5f6139196125e6565b54600160401b900460ff16919050565b61393161330e565b613943816001600160401b03166123b4565b61016380546001600160a01b0319166001600160a01b03841690811790915560408051635246492f60e01b81529051635246492f916004808201926020929091908290030181865afa15801561399b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139bf91906146ab565b61016280546001600160401b039093166001600160401b03196001600160a01b0393909316600160401b02929092166001600160e01b03199093169290921717905550565b613a0c6133dc565b5f8160a00151806020019051810190613a259190614d75565b8051909150613a33816123b4565b613a40836040015161201d565b613a4d83606001516123d4565b5f5b81811015613b7d575f838281518110613a6a57613a6a61468c565b602002602001015190505f613a83866060015183613bed565b90506001600160a01b038116301480613aa05750613aa0816111a5565b15613b0f5785606001516001600160a01b03166323b872dd828860400151856040518463ffffffff1660e01b8152600401613add939291906149ec565b5f604051808303815f87803b158015613af4575f5ffd5b505af1158015613b06573d5f5f3e3d5ffd5b50505050613b73565b85606001516001600160a01b03166340c10f198760400151846040518363ffffffff1660e01b8152600401613b45929190614e72565b5f604051808303815f87803b158015613b5c575f5ffd5b505af1158015613b6e573d5f5f3e3d5ffd5b505050505b5050600101613a4f565b50613b91836060015184604001518461380f565b6109768360200151846060015183613ecb565b5f818310613bb25781610ddd565b5090919050565b5f6001600160e01b03198216637965db0b60e01b14806109c957506301ffc9a760e01b6001600160e01b03198316146109c9565b6040516331a9108f60e11b8152600481018290525f906001600160a01b03841690636352211e90602401602060405180830381865afa925050508015613c50575060408051601f3d908101601f19168201909252613c4d918101906146ab565b60015b613c5b57505f6109c9565b90506109c9565b8254600160a01b900460ff161580613c78575081155b15613c8257505050565b825460018401546001600160801b03808316929116905f90613cb190600160801b900463ffffffff1642614a37565b90508015613d1d5781831115613cda57604051634b92ca1560e11b815260040160405180910390fd5b6001860154613cfe90839085908490600160801b90046001600160801b0316613479565b865463ffffffff60801b1916600160801b4263ffffffff160217875592505b84821015613d75576001600160a01b038416613d565760405163f94ebcd160e01b81526004810183905260248101869052604401611eb5565b818585604051630d3b2b9560e11b8152600401611eb593929190614ec4565b84831015613e1257600186810154600160801b90046001600160801b0316905f908290613da29082614a37565b613dac878a614a37565b613db69190614a24565b613dc09190614ee3565b90506001600160a01b038616613df3576040516302a4f38160e31b81526004810182905260248101869052604401611eb5565b808587604051636864691d60e11b8152600401611eb593929190614ec4565b613e1c8584614a37565b86546001600160801b0319166001600160801b0382161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b5f613e876001600160a01b03841683613eed565b905080515f14158015613eab575080806020019051810190613ea99190614a62565b155b156109765782604051635274afe760e01b8152600401611eb591906140ec565b6001600160401b0383165f908152609860205260409020610976908284613c62565b6060610ddd83835f845f5f856001600160a01b03168486604051613f119190614f02565b5f6040518083038185875af1925050503d805f8114613f4b576040519150601f19603f3d011682016040523d82523d5f602084013e613f50565b606091505b5091509150613f60868383613f6a565b9695505050505050565b606082613f7f57613f7a82613fbd565b610ddd565b8151158015613f9657506001600160a01b0384163b155b15613fb65783604051639996b31560e01b8152600401611eb591906140ec565b5080610ddd565b805115613fcd5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6040805160a0810182525f8082526020820181905291810182905260608101829052608081019190915290565b6001600160a01b0381168114611096575f5ffd5b803561403281614013565b919050565b5f60208284031215614047575f5ffd5b8135610ddd81614013565b5f60208284031215614062575f5ffd5b81356001600160e01b031981168114610ddd575f5ffd5b8015158114611096575f5ffd5b5f5f60408385031215614097575f5ffd5b82356140a281614013565b915060208301356140b281614079565b809150509250929050565b80356001600160401b0381168114614032575f5ffd5b5f602082840312156140e3575f5ffd5b610ddd826140bd565b6001600160a01b0391909116815260200190565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610ddd6020830184614100565b5f5f60408385031215614151575f5ffd5b61415a836140bd565b915060208301356140b281614013565b5f6020828403121561417a575f5ffd5b5035919050565b5f5f5f60608486031215614193575f5ffd5b833561419e81614013565b92506141ac602085016140bd565b915060408401356141bc81614013565b809150509250925092565b5f5f604083850312156141d8575f5ffd5b8235915060208301356140b281614013565b5f8151808452602084019350602083015f5b828110156142235781516001600160a01b03168652602095860195909101906001016141fc565b5093949350505050565b602081525f610ddd60208301846141ea565b5f5f5f5f60808587031215614252575f5ffd5b843561425d81614013565b935061426b602086016140bd565b93969395505050506040820135916060013590565b5f5f83601f840112614290575f5ffd5b5081356001600160401b038111156142a6575f5ffd5b6020830191508360208260051b85010111156142c0575f5ffd5b9250929050565b5f5f5f5f5f5f606087890312156142dc575f5ffd5b86356001600160401b038111156142f1575f5ffd5b6142fd89828a01614280565b90975095505060208701356001600160401b0381111561431b575f5ffd5b61432789828a01614280565b90955093505060408701356001600160401b03811115614345575f5ffd5b61435189828a01614280565b979a9699509497509295939492505050565b5f5f5f5f5f5f60c08789031215614378575f5ffd5b863561438381614013565b9550614391602088016140bd565b945060408701356143a181614013565b93506060870135925060808701356143b881614013565b9598949750929591949360a090920135925050565b5f5f5f606084860312156143df575f5ffd5b6143e8846140bd565b95602085013595506040909401359392505050565b5f60408201848352604060208401528084518083526060850191506020860192505f5b8181101561443e578351835260209384019390920191600101614420565b50909695505050505050565b604081525f61445c60408301856141ea565b828103602084015261349781856141ea565b5f5f5f60608486031215614480575f5ffd5b833561448b81614013565b9250602084013561449b81614013565b91506144a9604085016140bd565b90509250925092565b5f602082840312156144c2575f5ffd5b81356001600160401b038111156144d7575f5ffd5b820160a08185031215610ddd575f5ffd5b5f5f604083850312156144f9575f5ffd5b50508035926020909101359150565b5f5f60408385031215614519575f5ffd5b823561452481614013565b9150614532602084016140bd565b90509250929050565b5f8151808452602084019350602083015f5b828110156142235781516001600160401b031686526020958601959091019060010161454d565b602081525f610ddd602083018461453b565b5f60608284031215614596575f5ffd5b50919050565b5f5f5f60e084860312156145ae575f5ffd5b6145b7846140bd565b92506145c68560208601614586565b91506144a98560808601614586565b5f5f5f5f5f5f5f60c0888a0312156145eb575f5ffd5b87356145f681614013565b9650614604602089016140bd565b9550604088013561461481614013565b945060608801356001600160401b0381111561462e575f5ffd5b61463a8a828b01614280565b909550935050608088013561464e81614013565b96999598509396929591949193505060a09091013590565b604081525f61445c604083018561453b565b6001600160401b0391909116815260200190565b634e487b7160e01b5f52603260045260245ffd5b805161403281614013565b5f602082840312156146bb575f5ffd5b8151610ddd81614013565b634e487b7160e01b5f52604160045260245ffd5b6040516101a081016001600160401b03811182821017156146fd576146fd6146c6565b60405290565b60405160c081016001600160401b03811182821017156146fd576146fd6146c6565b604051601f8201601f191681016001600160401b038111828210171561474d5761474d6146c6565b604052919050565b805161ffff81168114614032575f5ffd5b805163ffffffff81168114614032575f5ffd5b805161403281614079565b5f6101a0828403128015614796575f5ffd5b5061479f6146da565b6147a8836146a0565b81526147b660208401614755565b60208201526147c760408401614766565b60408201526147d860608401614755565b60608201526147e960808401614766565b60808201526147fa60a08401614755565b60a082015261480b60c08401614755565b60c082015261481c60e084016146a0565b60e082015261482e6101008401614766565b6101008201526148416101208401614766565b6101208201526148546101408401614755565b6101408201526148676101608401614766565b61016082015261487a6101808401614779565b6101808201529392505050565b5f6001600160401b0382111561489f5761489f6146c6565b5060051b60200190565b5f602082840312156148b9575f5ffd5b81516001600160401b038111156148ce575f5ffd5b8201601f810184136148de575f5ffd5b80516148f16148ec82614887565b614725565b8082825260208201915060208360051b850101925086831115614912575f5ffd5b6020840193505b82841015613f6057835161492c81614013565b825260209384019390910190614919565b5f8151808452602084019350602083015f5b8281101561422357815186526020958601959091019060010161494f565b602081525f610ddd602083018461493d565b602080825282516001600160a01b0390811683830152908301516001600160401b0316604080840191909152830151811660608084019190915283015181166080808401919091528301511660a08083019190915282015160c0808301525f906116e360e0840182614100565b6001600160a01b039384168152919092166020820152604081019190915260600190565b634e487b7160e01b5f52601160045260245ffd5b808201808211156109c9576109c9614a10565b818103818111156109c9576109c9614a10565b5f60018201614a5b57614a5b614a10565b5060010190565b5f60208284031215614a72575f5ffd5b8151610ddd81614079565b5f5f8335601e19843603018112614a92575f5ffd5b8301803591506001600160401b03821115614aab575f5ffd5b6020019150368190038213156142c0575f5ffd5b80356001600160801b0381168114614032575f5ffd5b5f6060828403128015614ae6575f5ffd5b50604051606081016001600160401b0381118282101715614b0957614b096146c6565b6040528235614b1781614079565b8152614b2560208401614abf565b6020820152614b3660408401614abf565b60408201529392505050565b6001600160a01b0392831681529116602082015260400190565b60018060401b0383168152604060208201525f825160a06040840152614b8560e0840182614100565b90506020840151603f19848303016060850152614ba28282614100565b6040860151858203603f190160808701528051808352602091820194505f93509101905b80831015614bfd57835180516001600160a01b03168352602090810151818401529093019260019290920191604090910190614bc6565b5060608601516001600160a01b031660a08601526080860151858203603f190160c0870152925061106c8184614100565b5f60208284031215614c3e575f5ffd5b5051919050565b5f82601f830112614c54575f5ffd5b81356001600160401b03811115614c6d57614c6d6146c6565b614c80601f8201601f1916602001614725565b818152846020838601011115614c94575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60208284031215614cc0575f5ffd5b81356001600160401b03811115614cd5575f5ffd5b820160c08185031215614ce6575f5ffd5b614cee614703565b8135614cf981614013565b8152614d07602083016140bd565b60208201526040820135614d1a81614013565b60408201526060820135614d2d81614013565b6060820152614d3e60808301614027565b608082015260a08201356001600160401b03811115614d5b575f5ffd5b614d6786828501614c45565b60a083015250949350505050565b5f60208284031215614d85575f5ffd5b81516001600160401b03811115614d9a575f5ffd5b8201601f81018413614daa575f5ffd5b8051614db86148ec82614887565b8082825260208201915060208360051b850101925086831115614dd9575f5ffd5b6020840193505b82841015613f60578351825260209384019390910190614de0565b606081525f614e0d606083018661493d565b6001600160401b0394851660208401529290931660409091015292915050565b8051151582526020808201516001600160801b039081169184019190915260409182015116910152565b60c08101614e658285614e2d565b610ddd6060830184614e2d565b6001600160a01b03929092168252602082015260400190565b80820281158282048414176109c9576109c9614a10565b606081016109c98284614e2d565b634e487b7160e01b5f52603160045260245ffd5b92835260208301919091526001600160a01b0316604082015260600190565b5f82614efd57634e487b7160e01b5f52601260045260245ffd5b500490565b5f82518060208501845e5f92019182525091905056fe9562977e123fbe4558c4ac6a21f5c0a7f5ee8c1bd1bb59ec24cd079022975cb815975e67e85433b86162c65eeaf7d19d2b619671751d1f6d4d320dc195d465db1688c00bd4b3d5d2661432cff443a73d99517e416fd98c1425d800f7b6b0b9e965d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aa2646970667358221220bba0137ca3101440e2b76765b14e4154ddbde848a7797d09aa47ff6d4820a23064736f6c634300081d0033

Deployed Bytecode

0x608060405260043610610243575f3560e01c8063017e25e31461024757806301ffc9a71461026857806307a40f0b1461029c5780630a2fd493146102bb578063181f5a77146102e757806320cf81231461033c578063240028e81461035b578063248a9ca31461037a5780632e86678f146103a75780632f2ff15d146103c65780632faa5dc7146103e55780633195ac8314610404578063322cfeda1461043057806333fbf7191461044f57806336568abe1461046e5780633ab9e4921461048d5780633f4ba83a146104a05780633fd8c1b5146104b457806346e28a09146104e157806356b5440c146105005780635c975abb1461052d5780636b0e4f86146105415780636e15e242146105605780637879ec311461057d5780638456cb591461059c57806385572ffb146105b05780638926f54f146105cf5780638bdd6d8e146105ee5780638f20071d1461060e5780639010d07c1461063d57806391d148541461065c5780639bc53a201461067b578063a217fddf1461069a578063a3246ad3146106ad578063aa6ca808146106cc578063af58d59f146106e0578063b0f479a114610752578063bb0edba014610770578063bd9421e11461078f578063c4bffe2b146107ae578063c75eea9c146107cf578063ca15c873146107ee578063cf7401f31461080d578063d3bd04f11461082c578063d547741f1461083f578063d6111d861461085e578063db87d27814610880578063dc0bd971146108a0578063e60d6462146108c5578063e63ab1e9146108e5578063eab2c75714610905575b5f5ffd5b348015610252575f5ffd5b50610266610261366004614037565b610926565b005b348015610273575f5ffd5b50610287610282366004614052565b610996565b60405190151581526020015b60405180910390f35b3480156102a7575f5ffd5b506102666102b6366004614086565b6109cf565b3480156102c6575f5ffd5b506102da6102d53660046140d3565b610a6f565b60405161029391906140ec565b3480156102f2575f5ffd5b5061032f6040518060400160405280601d81526020017f4d756c74694c6f636b4d696e74455243373231506f6f6c20312e302e3000000081525081565b604051610293919061412e565b348015610347575f5ffd5b50610266610356366004614140565b610a79565b348015610366575f5ffd5b50610287610375366004614037565b610adf565b348015610385575f5ffd5b5061039961039436600461416a565b610b67565b604051908152602001610293565b3480156103b2575f5ffd5b506102666103c1366004614181565b610b85565b3480156103d1575f5ffd5b506102666103e03660046141c7565b610c21565b3480156103f0575f5ffd5b506102666103ff3660046140d3565b610c43565b34801561040f575f5ffd5b5061042361041e3660046140d3565b610c9c565b604051610293919061422d565b34801561043b575f5ffd5b5061039961044a36600461423f565b610de4565b34801561045a575f5ffd5b506102666104693660046142c7565b610ebb565b348015610479575f5ffd5b506102666104883660046141c7565b611022565b61039961049b366004614363565b611055565b3480156104ab575f5ffd5b50610266611077565b3480156104bf575f5ffd5b506104d36104ce3660046143cd565b611099565b6040516102939291906143fd565b3480156104ec575f5ffd5b506102876104fb366004614037565b6111a5565b34801561050b575f5ffd5b5061051f61051a3660046140d3565b6111c2565b60405161029392919061444a565b348015610538575f5ffd5b50610287611357565b34801561054c575f5ffd5b5061028761055b366004614140565b61140c565b34801561056b575f5ffd5b506032546001600160a01b03166102da565b348015610588575f5ffd5b5061026661059736600461446e565b61144e565b3480156105a7575f5ffd5b50610266611573565b3480156105bb575f5ffd5b506102666105ca3660046144b2565b611592565b3480156105da575f5ffd5b506102876105e93660046140d3565b611632565b3480156105f9575f5ffd5b506103995f516020614f195f395f51905f5281565b348015610619575f5ffd5b506102876106283660046140d3565b610162546001600160401b0391821691161490565b348015610648575f5ffd5b506102da6106573660046144e8565b6116bf565b348015610667575f5ffd5b506102876106763660046141c7565b6116eb565b348015610686575f5ffd5b506102da610695366004614508565b61171f565b3480156106a5575f5ffd5b506103995f81565b3480156106b8575f5ffd5b506104236106c736600461416a565b611768565b3480156106d7575f5ffd5b5061042361178c565b3480156106eb575f5ffd5b506106ff6106fa3660046140d3565b611880565b604051610293919081516001600160801b03908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b34801561075d575f5ffd5b50610163546001600160a01b03166102da565b34801561077b575f5ffd5b5061026661078a366004614508565b611906565b34801561079a575f5ffd5b506102876107a9366004614140565b611977565b3480156107b9575f5ffd5b506107c26119f4565b6040516102939190614574565b3480156107da575f5ffd5b506106ff6107e93660046140d3565b611b32565b3480156107f9575f5ffd5b5061039961080836600461416a565b611bb8565b348015610818575f5ffd5b5061026661082736600461459c565b611bdb565b61039961083a3660046145d5565b611c19565b34801561084a575f5ffd5b506102666108593660046141c7565b611c68565b348015610869575f5ffd5b50610872611c84565b604051610293929190614666565b34801561088b575f5ffd5b506103995f516020614f595f395f51905f5281565b3480156108ab575f5ffd5b5061016254600160401b90046001600160a01b03166102da565b3480156108d0575f5ffd5b506103995f516020614f395f395f51905f5281565b3480156108f0575f5ffd5b506103995f516020614f795f395f51905f5281565b348015610910575f5ffd5b50610919611d3c565b6040516102939190614678565b5f61093081611d4c565b603280546001600160a01b0319166001600160a01b03841690811790915561097b57603254610976905f516020614f795f395f51905f52906001600160a01b0316611d56565b505050565b6109765f516020614f795f395f51905f5283611d95565b5050565b5f6001600160e01b03198216636d7f8bbd60e11b14806109ba57506109ba82611dcb565b806109c957506109c982611e1c565b92915050565b5f516020614f595f395f51905f526109e681611d4c565b6001600160a01b038316610a0d576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0383165f81815260fd6020908152604091829020805460ff1916861515908117909155915191825233917f613ecbe5e56592771e18a638a133dc61a4488af23ac95580246a6dfa5edf240291015b60405180910390a3505050565b5f6109c982611e40565b5f516020614f195f395f51905f52610a9081611d4c565b610a9a8383611e7a565b6040516001600160a01b038316906001600160401b0385169033907f9f60ea76bb48f63c19a3d1bc23acb2a57138cbf18441efefe59a3d0c124d93ac905f90a4505050565b5f610aec61023183611fe5565b610af757505f919050565b5f610b006119f4565b80519091505f5b81811015610b5d575f6001600160a01b0316610b3c86858481518110610b2f57610b2f61468c565b602002602001015161171f565b6001600160a01b031614610b5557506001949350505050565b600101610b07565b505f949350505050565b5f5f610b71611ff9565b5f9384526020525050604090206001015490565b5f516020614f195f395f51905f52610b9c81611d4c565b83610ba68161201d565b83610bb081612044565b610bb98461201d565b610bc486868661206c565b856001600160a01b0316856001600160401b0316336001600160a01b03167feea3add3a72bfdec05437019247fe0e77d59874c7ae83510efc39677e14f9aa087604051610c1191906140ec565b60405180910390a4505050505050565b610c2a82610b67565b610c3381611d4c565b610c3d8383611d95565b50505050565b5f516020614f195f395f51905f52610c5a81611d4c565b610c6382612155565b6040516001600160401b0383169033907faf18d5efc97c08e5572a2feab86f2b1200f9ccceac5f451c0cce5d00822c5010905f90a35050565b606081610ca881612044565b6101635460405163a8d87a3b60e01b81526001600160a01b039091169063a8d87a3b90610cd9908690600401614678565b602060405180830381865afa158015610cf4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d1891906146ab565b6001600160a01b0316637437ff9f6040518163ffffffff1660e01b81526004016101a060405180830381865afa158015610d54573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d789190614784565b60e001516001600160a01b031663cdc73d516040518163ffffffff1660e01b81526004015f60405180830381865afa158015610db6573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ddd91908101906148a9565b9392505050565b6040805160c0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820152836001600160401b03811115610e2b57610e2b6146c6565b604051908082528060200260200182016040528015610e54578160200160208202803683370190505b50604051602001610e65919061496d565b60408051601f1981840301815291905260a0820152610eb085610e8781610a6f565b83604051602001610e98919061497f565b6040516020818303038152906040528660018b6121d9565b509695505050505050565b5f610ec581611d4c565b85610ed0818461238a565b610eda818661238a565b610ee3816123b4565b5f5b8181101561101757610f1c898983818110610f0257610f0261468c565b9050602002016020810190610f179190614037565b6123d4565b610f4b878783818110610f3157610f3161468c565b9050602002016020810190610f469190614037565b61201d565b888882818110610f5d57610f5d61468c565b9050602002016020810190610f729190614037565b6001600160a01b03166323b872dd30898985818110610f9357610f9361468c565b9050602002016020810190610fa89190614037565b888886818110610fba57610fba61468c565b905060200201356040518463ffffffff1660e01b8152600401610fdf939291906149ec565b5f604051808303815f87803b158015610ff6575f5ffd5b505af1158015611008573d5f5f3e3d5ffd5b50505050806001019050610ee5565b505050505050505050565b6001600160a01b038116331461104b5760405163334bd91960e11b815260040160405180910390fd5b6109768282611d56565b5f61106c878787611065886123fa565b8787612440565b979650505050505050565b5f516020614f795f395f51905f5261108e81611d4c565b611096612568565b50565b6001600160401b0383165f9081526101cb602052604090205460608184106110cf5750604080515f81526020810190915261119d565b816110da8486614a24565b11156110ed576110ea8483614a37565b92505b826001600160401b03811115611105576111056146c6565b60405190808252806020026020018201604052801561112e578160200160208202803683370190505b5090505f5b8381101561119b576001600160401b0386165f9081526101cb6020526040902061115d8287614a24565b8154811061116d5761116d61468c565b905f5260205f2001548282815181106111885761118861468c565b6020908102919091010152600101611133565b505b935093915050565b6001600160a01b03165f90815260fd602052604090205460ff1690565b6060806111ce83611632565b6111ef575050604080515f8082526020820190815281830190925292909150565b5f6111fb6102316125be565b9050806001600160401b03811115611215576112156146c6565b60405190808252806020026020018201604052801561123e578160200160208202803683370190505b509250806001600160401b03811115611259576112596146c6565b604051908082528060200260200182016040528015611282578160200160208202803683370190505b5091505f5f5b82811015611349575f61129d610231836125c7565b6001600160a01b038082165f908152610233602090815260408083206001600160401b038d16845290915290205491925016801561133f57818785815181106112e8576112e861468c565b60200260200101906001600160a01b031690816001600160a01b0316815250508086858151811061131b5761131b61468c565b6001600160a01b039092166020928302919091019091015261133c84614a4a565b93505b5050600101611288565b508084528083525050915091565b6032545f906001600160a01b031661137c5f516020614f795f395f51905f52826116eb565b801561139157506001600160a01b0381163b15155b80156113f85750806001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113d4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113f89190614a62565b8061140657506114066125d2565b91505090565b5f61141683611632565b61142157505f6109c9565b506001600160401b03919091165f90815261016660205260409020546001600160a01b0390811691161490565b5f6114576125e6565b805490915060ff600160401b82041615906001600160401b03165f8115801561147d5750825b90505f826001600160401b031660011480156114985750303b155b9050811580156114a6575080155b156114c45760405163f92ee8a960e01b815260040160405180910390fd5b84546001600160401b031916600117855583156114ed57845460ff60401b1916600160401b1785555b6114f75f89611d95565b506115018861260e565b61150a8861261f565b61151388612630565b61151e888888612641565b831561156957845460ff60401b191685556040517fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29061156090600190614678565b60405180910390a15b5050505050505050565b5f516020614f795f395f51905f5261158a81611d4c565b61109661265c565b6115a260408201602083016140d3565b6115ab816126a2565b5f6115b96040840184614a7d565b8101906115c69190614037565b90506115e16115db60408501602086016140d3565b82612741565b6115e9612782565b6115f2836127c0565b825f01357fce0ee41dd56ba56504e3cbb18167239f0ff664e41824e710d406e710e3ed0a388260405161162591906140ec565b60405180910390a2505050565b5f6116486101646001600160401b038416612957565b80156109c9575061016354604051631491520b60e31b81526001600160a01b039091169063a48a905890611680908590600401614678565b602060405180830381865afa15801561169b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109c99190614a62565b5f5f6116c9612962565b5f8581526020829052604090209091506116e390846125c7565b949350505050565b5f5f6116f5611ff9565b5f948552602090815260408086206001600160a01b03959095168652939052505090205460ff1690565b5f61172982611632565b61173457505f6109c9565b506001600160a01b039182165f908152610233602090815260408083206001600160401b0394909416835292905220541690565b60605f611773612962565b5f848152602082905260409020909150610ddd90612986565b60605f61179a610231612986565b8051909150806001600160401b038111156117b7576117b76146c6565b6040519080825280602002602001820160405280156117e0578160200160208202803683370190505b5092505f5f5b82811015611876576118108482815181106118035761180361468c565b6020026020010151610adf565b1561186e578381815181106118275761182761468c565b602002602001015185838061183b90614a4a565b94508151811061184d5761184d61468c565b60200260200101906001600160a01b031690816001600160a01b0316815250505b6001016117e6565b5080845250505090565b611888613fe6565b6001600160401b0382165f90815260986020908152604091829020825160a08101845281546001600160801b038082168352600160801b80830463ffffffff1695840195909552600160a01b90910460ff1615159482019490945260019091015480841660608301529190910490911660808201526109c990612992565b5f516020614f195f395f51905f5261191d81611d4c565b8161192781612044565b61193184846129fc565b6040516001600160a01b038516906001600160401b0385169033907f1397d60c55aea4f977e36de26ece59e6c1111bb420cc66e2d9565bc475bf82ef905f90a450505050565b5f5f61198284610c9c565b80519091505f819003611999575f925050506109c9565b5f5b818110156119e957846001600160a01b03168382815181106119bf576119bf61468c565b60200260200101516001600160a01b0316036119e157600193505050506109c9565b60010161199b565b505f95945050505050565b60605f611a02610164612986565b8051909150806001600160401b03811115611a1f57611a1f6146c6565b604051908082528060200260200182016040528015611a48578160200160208202803683370190505b5092505f5f5b82811015611876575f848281518110611a6957611a6961468c565b602090810291909101015161016354604051631491520b60e31b81529192506001600160a01b03169063a48a905890611aa6908490600401614678565b602060405180830381865afa158015611ac1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ae59190614a62565b15611b2957808684611af681614a4a565b955081518110611b0857611b0861468c565b60200260200101906001600160401b031690816001600160401b0316815250505b50600101611a4e565b611b3a613fe6565b6001600160401b0382165f90815260976020908152604091829020825160a08101845281546001600160801b038082168352600160801b80830463ffffffff1695840195909552600160a01b90910460ff1615159482019490945260019091015480841660608301529190910490911660808201526109c990612992565b5f5f611bc2612962565b5f848152602082905260409020909150610ddd906125be565b5f516020614f395f395f51905f52611bf281611d4c565b610c3d84611c0536869003860186614ad5565b611c1436869003860186614ad5565b612ab6565b5f611c5c8888888888808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152508a92508991506124409050565b98975050505050505050565b611c7182610b67565b611c7a81611d4c565b610c3d8383611d56565b606080611c8f6119f4565b8051909250806001600160401b03811115611cac57611cac6146c6565b604051908082528060200260200182016040528015611cd5578160200160208202803683370190505b5091505f5b81811015611d3657611d04848281518110611cf757611cf761468c565b6020026020010151610a6f565b838281518110611d1657611d1661468c565b6001600160a01b0390921660209283029190910190910152600101611cda565b50509091565b610162546001600160401b031690565b6110968133612b51565b5f5f611d60612962565b90505f611d6d8585612b7c565b905080156116e3575f858152602083905260409020611d8c9085612bfb565b50949350505050565b5f5f611d9f612962565b90505f611dac8585612c0f565b905080156116e3575f858152602083905260409020611d8c9085612ca4565b5f6001600160e01b031982166319167f6d60e11b1480611def5750611def82612cb8565b80611dfe5750611dfe82612cf7565b80611e0d5750611e0d82612d17565b806109c957506109c982612d37565b5f6001600160e01b031982166319c7358960e21b14806109c957506109c982612cb8565b5f611e4a82611632565b611e5557505f919050565b506001600160401b03165f90815261016660205260409020546001600160a01b031690565b611e838161201d565b610162546001600160401b0390811690831603611ebe578160405163af86032f60e01b8152600401611eb59190614678565b60405180910390fd5b61016354604051631491520b60e31b81526001600160a01b039091169063a48a905890611eef908590600401614678565b602060405180830381865afa158015611f0a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f2e9190614a62565b611f4d578160405163172ced9d60e11b8152600401611eb59190614678565b611f626101646001600160401b038416612d5b565b611f815781604051632f2c07d760e01b8152600401611eb59190614678565b6001600160401b0382165f818152610166602052604080822080546001600160a01b0319166001600160a01b038616908117909155905190929133917f8de8fd9740da5fc201a38a6085490fd6dfc07ce3a73938627eac66a5e748cefb9190a45050565b5f610ddd836001600160a01b038416612d66565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680090565b6001600160a01b038116611096576040516342bcdf7f60e11b815260040160405180910390fd5b61204d81611632565b6110965780604051631e670e4b60e01b8152600401611eb59190614678565b5f5f612077846111c2565b8051919350915015612100575f5b81518110156120fe57836001600160a01b03168282815181106120aa576120aa61468c565b60200260200101516001600160a01b0316036120f6578281815181106120d2576120d261468c565b602002602001015184604051631cfa01f360e11b8152600401611eb5929190614b42565b600101612085565b505b61210c61023186612ca4565b5050506001600160a01b039283165f908152610233602090815260408083206001600160401b039590951683529390529190912080546001600160a01b03191691909216179055565b61216a6101646001600160401b038316612d7d565b6121895780604051631e670e4b60e01b8152600401611eb59190614678565b6001600160401b0381165f818152610166602052604080822080546001600160a01b03191690555133917fb7c3517ce5cb1b2e820e49d7850f4e0e71cde55b70c0995bab3b7eafe3abc87291a350565b5f6122146040518060a001604052806060815260200160608152602001606081526020015f6001600160a01b03168152602001606081525090565b8761221e81612044565b6040805160a08101909152806122378a60c083016140ec565b60408051808303601f1901815291815290825260208083018b905281515f808252918101835292909101919061228e565b604080518082019091525f80825260208201528152602001906001900390816122685790505b508152602001856001600160a01b0316815260200161230760405180604001604052808a81526020018915158152506040805182516024820152602092830151151560448083019190915282518083039091018152606490910190915290810180516001600160e01b0316630181dcf160e41b17905290565b9052610163546040516320487ded60e01b81529193506001600160a01b0316906320487ded9061233d908c908690600401614b5c565b602060405180830381865afa158015612358573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061237c9190614c2e565b925050965096945050505050565b808214610992576040516355c5b3e360e11b81526004810183905260248101829052604401611eb5565b805f036110965760405163273e150360e21b815260040160405180910390fd5b6123dd81610adf565b6110965760405163f850ff3b60e01b815260040160405180910390fd5b6040805160018082528183019092526060916020808301908036833701905050905081815f8151811061242f5761242f61468c565b602002602001018181525050919050565b5f8461244b8161201d565b5f8560405160200161245d919061496d565b60408051601f198184030181526060830182526001600160401b038b1683526001600160a01b038c166020840152908201819052915061249c90612d88565b5f6124a78a8a61171f565b90506124b28161201d565b612548896124bf8b610a6f565b6040518060c00160405280336001600160a01b031681526020016124e1611d3c565b6001600160401b031681526020018c6001600160a01b03168152602001856001600160a01b03168152602001306001600160a01b0316815260200186815250604051602001612530919061497f565b6040516020818303038152906040528860018b612e88565b935061255b612555611d3c565b856131f7565b5050509695505050505050565b61257061329f565b5f6125796132c4565b805460ff1916815590507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516125b391906140ec565b60405180910390a150565b5f6109c9825490565b5f610ddd83836132e8565b5f5f6125dc6132c4565b5460ff1692915050565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a006109c9565b61261661330e565b61109681613333565b61262761330e565b6110968161336d565b61263861330e565b6110968161338c565b61264961330e565b612652836133ab565b61097682826133ca565b6126646133dc565b5f61266d6132c4565b805460ff1916600117815590507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125a63390565b61016254604051632cbc26bb60e01b8152608083901b600160801b600160c01b03166004820152600160401b9091046001600160a01b031690632cbc26bb90602401602060405180830381865afa1580156126ff573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127239190614a62565b1561109657604051630a75a23b60e31b815260040160405180910390fd5b61274b828261140c565b6109925760405163d5079a3560e01b81526001600160401b03831660048201526001600160a01b0382166024820152604401611eb5565b610163546001600160a01b031633146127be5761016354604051637ec1982b60e01b8152611eb5916001600160a01b0316903390600401614b42565b565b5f6127ce6060830183614a7d565b8101906127db9190614cb0565b905080602001516001600160401b03168260200160208101906127fe91906140d3565b6001600160401b03161461284d5761281c60408301602084016140d3565b6020820151604051638428f1f760e01b81526001600160401b03928316600482015291166024820152604401611eb5565b5f61285b6040840184614a7d565b8101906128689190614037565b905081608001516001600160a01b0316816001600160a01b0316146128a75760808201516040516310c4624f60e21b8152611eb5918391600401614b42565b81516128b29061201d565b60208201516128c29084356131f7565b6128cb82613402565b825f013582604001516001600160a01b0316835f01516001600160a01b03167f55e75798c6b341acacc33826c47c58fccf851dda1790809862e7299fe1874d448560a001518060200190518101906129239190614d75565b6129336040890160208a016140d3565b61293b611d3c565b60405161294a93929190614dfb565b60405180910390a4505050565b5f610ddd8383612d66565b7fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e8237170593200090565b60605f610ddd83613420565b61299a613fe6565b6129e182606001516001600160801b0316835f01516001600160801b0316846020015163ffffffff16426129ce9190614a37565b85608001516001600160801b0316613479565b6001600160801b031682525063ffffffff4216602082015290565b6001600160a01b038083165f908152610233602090815260408083206001600160401b03861684529091529020541680612a6357604051639bc50b1760e01b81526001600160a01b03841660048201526001600160401b0383166024820152604401611eb5565b6001600160a01b0383165f908152610233602090815260408083206001600160401b0386168452909152902080546001600160a01b0319169055612aa683610adf565b61097657610c3d61023184612bfb565b612ac0825f6134a0565b6001600160401b0383165f908152609760205260409020612ae19083613561565b612aeb815f6134a0565b6001600160401b0383165f908152609860205260409020612b0c9082613561565b826001600160401b0316336001600160a01b03167f3a6cd4bdc00dc992306b6d7795432a8934d7c9fbdb85b49faad03dad43c817248484604051610a62929190614e57565b612b5b82826116eb565b61099257808260405163e2517d3f60e01b8152600401611eb5929190614e72565b5f5f612b86611ff9565b9050612b9284846116eb565b15612bf2575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a460019150506109c9565b5f9150506109c9565b5f610ddd836001600160a01b03841661367a565b5f5f612c19611ff9565b9050612c2584846116eb565b612bf2575f848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055612c5a3390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a460019150506109c9565b5f610ddd836001600160a01b038416613754565b5f6001600160e01b0319821663181f5a7760e01b1480612ce857506001600160e01b0319821663d6d62d0d60e01b145b806109c957506109c98261379b565b5f6001600160e01b03198216634d60abbd60e11b14806109c957506109c9825b5f6001600160e01b031982166320bfad4960e11b14806109c957506109c9825b5f6001600160e01b0319821663324c152b60e01b14806109c957506109c9826137eb565b5f610ddd8383613754565b5f9081526001919091016020526040902054151590565b5f610ddd838361367a565b612d906133dc565b8060200151612d9e816123d4565b8151612da981612044565b5f8360400151806020019051810190612dc29190614d75565b8051909150612dd0816123b4565b5f5b81811015612e5f5785602001516001600160a01b03166323b872dd3330868581518110612e0157612e0161468c565b60200260200101516040518463ffffffff1660e01b8152600401612e27939291906149ec565b5f604051808303815f87803b158015612e3e575f5ffd5b505af1158015612e50573d5f5f3e3d5ffd5b50505050806001019050612dd2565b50612e6f8560200151308461380f565b612e81855f0151866020015183613894565b5050505050565b5f86612e93816126a2565b612e9c8761201d565b612ea5856123b4565b612eaf86516123b4565b5f5f612ebf8a8a8a8a8a8a6121d9565b90925090505f6001600160a01b038616612ff55782341015612efd5760405163054365bb60e31b815260048101849052346024820152604401611eb5565b6101635f9054906101000a90046001600160a01b03166001600160a01b031663e861e9076040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f4e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f7291906146ab565b95508582606001906001600160a01b031690816001600160a01b031681525050856001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004015f604051808303818588803b158015612fcb575f5ffd5b505af1158015612fdd573d5f5f3e3d5ffd5b50505050508234612fee9190614a37565b905061302b565b3415613016576040516336334e4560e01b8152346004820152602401611eb5565b61302b6001600160a01b0387163330866138b6565b6101635460405163095ea7b360e01b81526001600160a01b038881169263095ea7b39261306092909116908790600401614e72565b6020604051808303815f875af115801561307c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130a09190614a62565b50610163546040516396f4e9f960e01b81526001600160a01b03909116906396f4e9f9906130d4908e908690600401614b5c565b6020604051808303815f875af11580156130f0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131149190614c2e565b945080156131bd576040515f90339083908381818185875af1925050503d805f811461315b576040519150601f19603f3d011682016040523d82523d5f602084013e613160565b606091505b50509050806131865733826040516357b9d85960e11b8152600401611eb5929190614e72565b60405182815233907fd7dee2702d63ad89917b6a4da9981c90c4d24f8c2bdfd64c604ecae57d8d06519060200160405180910390a2505b604051859033907fb06a7d56e5736d613c3122470fadaf19fa9b76fbc2244c4ed1bab9c2c4d6213b905f90a3505050509695505050505050565b6001600160401b0382165f9081526101cc6020908152604080832084845290915290205460ff161561324e576040516342cb76b360e11b81526001600160401b038316600482015260248101829052604401611eb5565b6001600160401b039091165f8181526101cb60209081526040808320805460018181018355918552838520018690559383526101cc825280832094835293905291909120805460ff19169091179055565b6132a7611357565b6127be57604051638dfc202b60e01b815260040160405180910390fd5b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330090565b5f825f0182815481106132fd576132fd61468c565b905f5260205f200154905092915050565b613316613910565b6127be57604051631afcd79f60e31b815260040160405180910390fd5b61333b61330e565b603280546001600160a01b0319166001600160a01b0383161790556109925f516020614f795f395f51905f5282611d95565b61337561330e565b6109925f516020614f395f395f51905f5282611d95565b61339461330e565b6109925f516020614f595f395f51905f5282611d95565b6133b361330e565b6109925f516020614f195f395f51905f5282611d95565b6133d261330e565b6109928282613929565b6133e4611357565b156127be5760405163d93c066560e01b815260040160405180910390fd5b613417610f468260600151836020015161171f565b61109681613a04565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561346d57602002820191905f5260205f20905b815481526020019060010190808311613459575b50505050509050919050565b5f613497856134888486614e8b565b6134929087614a24565b613ba4565b95945050505050565b81511561351a5781602001516001600160801b031682604001516001600160801b03161015806134db575060408201516001600160801b0316155b156134fb5781604051632008344960e21b8152600401611eb59190614ea2565b80156109925760405163433fc33d60e01b815260040160405180910390fd5b60408201516001600160801b0316151580613541575060208201516001600160801b031615155b1561099257816040516335a2be7360e21b8152600401611eb59190614ea2565b81545f9061357c90600160801b900463ffffffff1642614a37565b905080156135da57600183015483546135ae916001600160801b03808216928116918591600160801b90910416613479565b83546001600160801b03919091166001600160a01b031990911617600160801b4263ffffffff16021783555b602082015183546135f7916001600160801b039081169116613ba4565b835483511515600160a01b02600164ff0000000160801b03199091166001600160801b039283161717845560208301516040808501518316600160801b0291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c199061366d908490614ea2565b60405180910390a1505050565b5f8181526001830160205260408120548015612bf2575f61369c600183614a37565b85549091505f906136af90600190614a37565b905080821461370e575f865f0182815481106136cd576136cd61468c565b905f5260205f200154905080875f0184815481106136ed576136ed61468c565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061371f5761371f614eb0565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506109c9565b5f61375f8383612d66565b61379457508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556109c9565b505f6109c9565b5f6001600160e01b031982166351fdd48d60e11b14806137cb57506001600160e01b031982166385572ffb60e01b145b806109c957506001600160e01b031982166301ffc9a760e01b1492915050565b5f6001600160e01b03198216635a05180f60e01b14806109c957506109c982613bb9565b80515f5b81811015612e8157836001600160a01b03166138488685848151811061383b5761383b61468c565b6020026020010151613bed565b6001600160a01b03161461388c57838382815181106138695761386961468c565b6020026020010151604051631cc2e71960e31b8152600401611eb5929190614e72565b600101613813565b6001600160401b0383165f908152609760205260409020610976908284613c62565b610c3d84856001600160a01b03166323b872dd8686866040516024016138de939291906149ec565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050613e73565b5f6139196125e6565b54600160401b900460ff16919050565b61393161330e565b613943816001600160401b03166123b4565b61016380546001600160a01b0319166001600160a01b03841690811790915560408051635246492f60e01b81529051635246492f916004808201926020929091908290030181865afa15801561399b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139bf91906146ab565b61016280546001600160401b039093166001600160401b03196001600160a01b0393909316600160401b02929092166001600160e01b03199093169290921717905550565b613a0c6133dc565b5f8160a00151806020019051810190613a259190614d75565b8051909150613a33816123b4565b613a40836040015161201d565b613a4d83606001516123d4565b5f5b81811015613b7d575f838281518110613a6a57613a6a61468c565b602002602001015190505f613a83866060015183613bed565b90506001600160a01b038116301480613aa05750613aa0816111a5565b15613b0f5785606001516001600160a01b03166323b872dd828860400151856040518463ffffffff1660e01b8152600401613add939291906149ec565b5f604051808303815f87803b158015613af4575f5ffd5b505af1158015613b06573d5f5f3e3d5ffd5b50505050613b73565b85606001516001600160a01b03166340c10f198760400151846040518363ffffffff1660e01b8152600401613b45929190614e72565b5f604051808303815f87803b158015613b5c575f5ffd5b505af1158015613b6e573d5f5f3e3d5ffd5b505050505b5050600101613a4f565b50613b91836060015184604001518461380f565b6109768360200151846060015183613ecb565b5f818310613bb25781610ddd565b5090919050565b5f6001600160e01b03198216637965db0b60e01b14806109c957506301ffc9a760e01b6001600160e01b03198316146109c9565b6040516331a9108f60e11b8152600481018290525f906001600160a01b03841690636352211e90602401602060405180830381865afa925050508015613c50575060408051601f3d908101601f19168201909252613c4d918101906146ab565b60015b613c5b57505f6109c9565b90506109c9565b8254600160a01b900460ff161580613c78575081155b15613c8257505050565b825460018401546001600160801b03808316929116905f90613cb190600160801b900463ffffffff1642614a37565b90508015613d1d5781831115613cda57604051634b92ca1560e11b815260040160405180910390fd5b6001860154613cfe90839085908490600160801b90046001600160801b0316613479565b865463ffffffff60801b1916600160801b4263ffffffff160217875592505b84821015613d75576001600160a01b038416613d565760405163f94ebcd160e01b81526004810183905260248101869052604401611eb5565b818585604051630d3b2b9560e11b8152600401611eb593929190614ec4565b84831015613e1257600186810154600160801b90046001600160801b0316905f908290613da29082614a37565b613dac878a614a37565b613db69190614a24565b613dc09190614ee3565b90506001600160a01b038616613df3576040516302a4f38160e31b81526004810182905260248101869052604401611eb5565b808587604051636864691d60e11b8152600401611eb593929190614ec4565b613e1c8584614a37565b86546001600160801b0319166001600160801b0382161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b5f613e876001600160a01b03841683613eed565b905080515f14158015613eab575080806020019051810190613ea99190614a62565b155b156109765782604051635274afe760e01b8152600401611eb591906140ec565b6001600160401b0383165f908152609860205260409020610976908284613c62565b6060610ddd83835f845f5f856001600160a01b03168486604051613f119190614f02565b5f6040518083038185875af1925050503d805f8114613f4b576040519150601f19603f3d011682016040523d82523d5f602084013e613f50565b606091505b5091509150613f60868383613f6a565b9695505050505050565b606082613f7f57613f7a82613fbd565b610ddd565b8151158015613f9657506001600160a01b0384163b155b15613fb65783604051639996b31560e01b8152600401611eb591906140ec565b5080610ddd565b805115613fcd5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6040805160a0810182525f8082526020820181905291810182905260608101829052608081019190915290565b6001600160a01b0381168114611096575f5ffd5b803561403281614013565b919050565b5f60208284031215614047575f5ffd5b8135610ddd81614013565b5f60208284031215614062575f5ffd5b81356001600160e01b031981168114610ddd575f5ffd5b8015158114611096575f5ffd5b5f5f60408385031215614097575f5ffd5b82356140a281614013565b915060208301356140b281614079565b809150509250929050565b80356001600160401b0381168114614032575f5ffd5b5f602082840312156140e3575f5ffd5b610ddd826140bd565b6001600160a01b0391909116815260200190565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610ddd6020830184614100565b5f5f60408385031215614151575f5ffd5b61415a836140bd565b915060208301356140b281614013565b5f6020828403121561417a575f5ffd5b5035919050565b5f5f5f60608486031215614193575f5ffd5b833561419e81614013565b92506141ac602085016140bd565b915060408401356141bc81614013565b809150509250925092565b5f5f604083850312156141d8575f5ffd5b8235915060208301356140b281614013565b5f8151808452602084019350602083015f5b828110156142235781516001600160a01b03168652602095860195909101906001016141fc565b5093949350505050565b602081525f610ddd60208301846141ea565b5f5f5f5f60808587031215614252575f5ffd5b843561425d81614013565b935061426b602086016140bd565b93969395505050506040820135916060013590565b5f5f83601f840112614290575f5ffd5b5081356001600160401b038111156142a6575f5ffd5b6020830191508360208260051b85010111156142c0575f5ffd5b9250929050565b5f5f5f5f5f5f606087890312156142dc575f5ffd5b86356001600160401b038111156142f1575f5ffd5b6142fd89828a01614280565b90975095505060208701356001600160401b0381111561431b575f5ffd5b61432789828a01614280565b90955093505060408701356001600160401b03811115614345575f5ffd5b61435189828a01614280565b979a9699509497509295939492505050565b5f5f5f5f5f5f60c08789031215614378575f5ffd5b863561438381614013565b9550614391602088016140bd565b945060408701356143a181614013565b93506060870135925060808701356143b881614013565b9598949750929591949360a090920135925050565b5f5f5f606084860312156143df575f5ffd5b6143e8846140bd565b95602085013595506040909401359392505050565b5f60408201848352604060208401528084518083526060850191506020860192505f5b8181101561443e578351835260209384019390920191600101614420565b50909695505050505050565b604081525f61445c60408301856141ea565b828103602084015261349781856141ea565b5f5f5f60608486031215614480575f5ffd5b833561448b81614013565b9250602084013561449b81614013565b91506144a9604085016140bd565b90509250925092565b5f602082840312156144c2575f5ffd5b81356001600160401b038111156144d7575f5ffd5b820160a08185031215610ddd575f5ffd5b5f5f604083850312156144f9575f5ffd5b50508035926020909101359150565b5f5f60408385031215614519575f5ffd5b823561452481614013565b9150614532602084016140bd565b90509250929050565b5f8151808452602084019350602083015f5b828110156142235781516001600160401b031686526020958601959091019060010161454d565b602081525f610ddd602083018461453b565b5f60608284031215614596575f5ffd5b50919050565b5f5f5f60e084860312156145ae575f5ffd5b6145b7846140bd565b92506145c68560208601614586565b91506144a98560808601614586565b5f5f5f5f5f5f5f60c0888a0312156145eb575f5ffd5b87356145f681614013565b9650614604602089016140bd565b9550604088013561461481614013565b945060608801356001600160401b0381111561462e575f5ffd5b61463a8a828b01614280565b909550935050608088013561464e81614013565b96999598509396929591949193505060a09091013590565b604081525f61445c604083018561453b565b6001600160401b0391909116815260200190565b634e487b7160e01b5f52603260045260245ffd5b805161403281614013565b5f602082840312156146bb575f5ffd5b8151610ddd81614013565b634e487b7160e01b5f52604160045260245ffd5b6040516101a081016001600160401b03811182821017156146fd576146fd6146c6565b60405290565b60405160c081016001600160401b03811182821017156146fd576146fd6146c6565b604051601f8201601f191681016001600160401b038111828210171561474d5761474d6146c6565b604052919050565b805161ffff81168114614032575f5ffd5b805163ffffffff81168114614032575f5ffd5b805161403281614079565b5f6101a0828403128015614796575f5ffd5b5061479f6146da565b6147a8836146a0565b81526147b660208401614755565b60208201526147c760408401614766565b60408201526147d860608401614755565b60608201526147e960808401614766565b60808201526147fa60a08401614755565b60a082015261480b60c08401614755565b60c082015261481c60e084016146a0565b60e082015261482e6101008401614766565b6101008201526148416101208401614766565b6101208201526148546101408401614755565b6101408201526148676101608401614766565b61016082015261487a6101808401614779565b6101808201529392505050565b5f6001600160401b0382111561489f5761489f6146c6565b5060051b60200190565b5f602082840312156148b9575f5ffd5b81516001600160401b038111156148ce575f5ffd5b8201601f810184136148de575f5ffd5b80516148f16148ec82614887565b614725565b8082825260208201915060208360051b850101925086831115614912575f5ffd5b6020840193505b82841015613f6057835161492c81614013565b825260209384019390910190614919565b5f8151808452602084019350602083015f5b8281101561422357815186526020958601959091019060010161494f565b602081525f610ddd602083018461493d565b602080825282516001600160a01b0390811683830152908301516001600160401b0316604080840191909152830151811660608084019190915283015181166080808401919091528301511660a08083019190915282015160c0808301525f906116e360e0840182614100565b6001600160a01b039384168152919092166020820152604081019190915260600190565b634e487b7160e01b5f52601160045260245ffd5b808201808211156109c9576109c9614a10565b818103818111156109c9576109c9614a10565b5f60018201614a5b57614a5b614a10565b5060010190565b5f60208284031215614a72575f5ffd5b8151610ddd81614079565b5f5f8335601e19843603018112614a92575f5ffd5b8301803591506001600160401b03821115614aab575f5ffd5b6020019150368190038213156142c0575f5ffd5b80356001600160801b0381168114614032575f5ffd5b5f6060828403128015614ae6575f5ffd5b50604051606081016001600160401b0381118282101715614b0957614b096146c6565b6040528235614b1781614079565b8152614b2560208401614abf565b6020820152614b3660408401614abf565b60408201529392505050565b6001600160a01b0392831681529116602082015260400190565b60018060401b0383168152604060208201525f825160a06040840152614b8560e0840182614100565b90506020840151603f19848303016060850152614ba28282614100565b6040860151858203603f190160808701528051808352602091820194505f93509101905b80831015614bfd57835180516001600160a01b03168352602090810151818401529093019260019290920191604090910190614bc6565b5060608601516001600160a01b031660a08601526080860151858203603f190160c0870152925061106c8184614100565b5f60208284031215614c3e575f5ffd5b5051919050565b5f82601f830112614c54575f5ffd5b81356001600160401b03811115614c6d57614c6d6146c6565b614c80601f8201601f1916602001614725565b818152846020838601011115614c94575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60208284031215614cc0575f5ffd5b81356001600160401b03811115614cd5575f5ffd5b820160c08185031215614ce6575f5ffd5b614cee614703565b8135614cf981614013565b8152614d07602083016140bd565b60208201526040820135614d1a81614013565b60408201526060820135614d2d81614013565b6060820152614d3e60808301614027565b608082015260a08201356001600160401b03811115614d5b575f5ffd5b614d6786828501614c45565b60a083015250949350505050565b5f60208284031215614d85575f5ffd5b81516001600160401b03811115614d9a575f5ffd5b8201601f81018413614daa575f5ffd5b8051614db86148ec82614887565b8082825260208201915060208360051b850101925086831115614dd9575f5ffd5b6020840193505b82841015613f60578351825260209384019390910190614de0565b606081525f614e0d606083018661493d565b6001600160401b0394851660208401529290931660409091015292915050565b8051151582526020808201516001600160801b039081169184019190915260409182015116910152565b60c08101614e658285614e2d565b610ddd6060830184614e2d565b6001600160a01b03929092168252602082015260400190565b80820281158282048414176109c9576109c9614a10565b606081016109c98284614e2d565b634e487b7160e01b5f52603160045260245ffd5b92835260208301919091526001600160a01b0316604082015260600190565b5f82614efd57634e487b7160e01b5f52601260045260245ffd5b500490565b5f82518060208501845e5f92019182525091905056fe9562977e123fbe4558c4ac6a21f5c0a7f5ee8c1bd1bb59ec24cd079022975cb815975e67e85433b86162c65eeaf7d19d2b619671751d1f6d4d320dc195d465db1688c00bd4b3d5d2661432cff443a73d99517e416fd98c1425d800f7b6b0b9e965d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aa2646970667358221220bba0137ca3101440e2b76765b14e4154ddbde848a7797d09aa47ff6d4820a23064736f6c634300081d0033

Deployed Bytecode Sourcemap

473:4391:48:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1932:306:28;;;;;;;;;;-1:-1:-1;1932:306:28;;;;;:::i;:::-;;:::i;:::-;;2564:366:48;;;;;;;;;;-1:-1:-1;2564:366:48;;;;;:::i;:::-;;:::i;:::-;;;997:14:49;;990:22;972:41;;960:2;945:18;2564:366:48;;;;;;;;1281:322:30;;;;;;;;;;-1:-1:-1;1281:322:30;;;;;:::i;:::-;;:::i;3158:153:46:-;;;;;;;;;;-1:-1:-1;3158:153:46;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;576:80:48:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;1721:252:46:-;;;;;;;;;;-1:-1:-1;1721:252:46;;;;;:::i;:::-;;:::i;2738:607:45:-;;;;;;;;;;-1:-1:-1;2738:607:45;;;;;:::i;:::-;;:::i;4759:191:12:-;;;;;;;;;;-1:-1:-1;4759:191:12;;;;;:::i;:::-;;:::i;:::-;;;3436:25:49;;;3424:2;3409:18;4759:191:12;3290:177:49;2293:434:46;;;;;;;;;;-1:-1:-1;2293:434:46;;;;;:::i;:::-;;:::i;5246:136:12:-;;;;;;;;;;-1:-1:-1;5246:136:12;;;;;:::i;:::-;;:::i;2025:216:46:-;;;;;;;;;;-1:-1:-1;2025:216:46;;;;;:::i;:::-;;:::i;4041:300:27:-;;;;;;;;;;-1:-1:-1;4041:300:27;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;1170:591:47:-;;;;;;;;;;-1:-1:-1;1170:591:47;;;;;:::i;:::-;;:::i;1132:589:48:-;;;;;;;;;;-1:-1:-1;1132:589:48;;;;;:::i;:::-;;:::i;6348:245:12:-;;;;;;;;;;-1:-1:-1;6348:245:12;;;;;:::i;:::-;;:::i;1787:353:48:-;;;;;;:::i;:::-;;:::i;1416:77:28:-;;;;;;;;;;;;;:::i;3842:525:46:-;;;;;;;;;;-1:-1:-1;3842:525:46;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;1883:133:30:-;;;;;;;;;;-1:-1:-1;1883:133:30;;;;;:::i;:::-;;:::i;1156:958:45:-;;;;;;;;;;-1:-1:-1;1156:958:45;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;2244:275:28:-;;;;;;;;;;;;;:::i;4887:236:27:-;;;;;;;;;;-1:-1:-1;4887:236:27;;;;;:::i;:::-;;:::i;1763:110:28:-;;;;;;;;;;-1:-1:-1;1852:14:28;;-1:-1:-1;;;;;1852:14:28;1763:110;;722:344:48;;;;;;;;;;-1:-1:-1;722:344:48;;;;;:::i;:::-;;:::i;1284:73:28:-;;;;;;;;;;;;;:::i;3095:402:27:-;;;;;;;;;;-1:-1:-1;3095:402:27;;;;;:::i;:::-;;:::i;4615:211::-;;;;;;;;;;-1:-1:-1;4615:211:27;;;;;:::i;:::-;;:::i;643:82:46:-;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;643:82:46;;4402:152:27;;;;;;;;;;-1:-1:-1;4402:152:27;;;;;:::i;:::-;4525:22;;-1:-1:-1;;;;;4501:46:27;;;4525:22;;4501:46;;4402:152;2492:233:13;;;;;;;;;;-1:-1:-1;2492:233:13;;;;;:::i;:::-;;:::i;3732:207:12:-;;;;;;;;;;-1:-1:-1;3732:207:12;;;;;:::i;:::-;;:::i;3402:256:45:-;;;;;;;;;;-1:-1:-1;3402:256:45;;;;;:::i;:::-;;:::i;2317:49:12:-;;;;;;;;;;-1:-1:-1;2317:49:12;2362:4;2317:49;;3658:227:13;;;;;;;;;;-1:-1:-1;3658:227:13;;;;;:::i;:::-;;:::i;2171:515:45:-;;;;;;;;;;;;;:::i;2346:247:29:-;;;;;;;;;;-1:-1:-1;2346:247:29;;;;;:::i;:::-;;:::i;:::-;;;;;;11443:13:49;;-1:-1:-1;;;;;11439:39:49;;;11421:58;;11539:4;11527:17;;;11521:24;11547:10;11517:41;11495:20;;;11488:71;11629:4;11617:17;;;11611:24;11604:32;11597:40;11575:20;;;11568:70;11698:4;11686:17;;;11680:24;11676:50;;11654:20;;;11647:80;11466:3;11775:17;;;11769:24;11765:50;11743:20;;;11736:80;;;;11408:3;11393:19;;11216:606;6104:104:27;;;;;;;;;;-1:-1:-1;6193:8:27;;-1:-1:-1;;;;;6193:8:27;6104:104;;2779:327:46;;;;;;;;;;-1:-1:-1;2779:327:46;;;;;:::i;:::-;;:::i;3558:422:27:-;;;;;;;;;;-1:-1:-1;3558:422:27;;;;;:::i;:::-;;:::i;5184:667::-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;2037:249:29:-;;;;;;;;;;-1:-1:-1;2037:249:29;;;;;:::i;:::-;;:::i;2893:222:13:-;;;;;;;;;;-1:-1:-1;2893:222:13;;;;;:::i;:::-;;:::i;1460:305:29:-;;;;;;;;;;-1:-1:-1;1460:305:29;;;;;:::i;:::-;;:::i;2206:352:48:-;;;;;;:::i;:::-;;:::i;5662:138:12:-;;;;;;;;;;-1:-1:-1;5662:138:12;;;;;:::i;:::-;;:::i;3363:427:46:-;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;474:92:30:-;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;474:92:30;;6269:95:27;;;;;;;;;;-1:-1:-1;6347:10:27;;-1:-1:-1;;;6347:10:27;;-1:-1:-1;;;;;6347:10:27;6269:95;;605:74:29;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;605:74:29;;646:62:28;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;646:62:28;;5912:131:27;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;1932:306:28:-;2362:4:12;3191:16;2362:4;3191:10;:16::i;:::-;2027:14:28::1;:29:::0;;-1:-1:-1;;;;;;2027:29:28::1;-1:-1:-1::0;;;;;2027:29:28;::::1;::::0;;::::1;::::0;;;2067:117:::1;;2138:14;::::0;2113:40:::1;::::0;-1:-1:-1;;;;;;;;;;;684:24:28;-1:-1:-1;;;;;2138:14:28::1;2113:11;:40::i;:::-;;1932:306:::0;;:::o;2067:117::-:1;2194:37;-1:-1:-1::0;;;;;;;;;;;2218:12:28::1;2194:10;:37::i;3217:1:12:-;1932:306:28::0;;:::o;2564:366:48:-;2725:4;-1:-1:-1;;;;;;2752:57:48;;-1:-1:-1;;;2752:57:48;;:122;;;2825:49;2862:11;2825:36;:49::i;:::-;2752:171;;;;2878:45;2911:11;2878:32;:45::i;:::-;2745:178;2564:366;-1:-1:-1;;2564:366:48:o;1281:322:30:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;-1:-1:-1;;;;;1406:27:30;::::1;1402:69;;1442:29;;-1:-1:-1::0;;;1442:29:30::1;;;;;;;;;;;1402:69;-1:-1:-1::0;;;;;1481:30:30;::::1;;::::0;;;:15:::1;:30;::::0;;;;;;;;:42;;-1:-1:-1;;1481:42:30::1;::::0;::::1;;::::0;;::::1;::::0;;;1538:58;;972:41:49;;;1559:10:30::1;::::0;1538:58:::1;::::0;945:18:49;1538:58:30::1;;;;;;;;1281:322:::0;;;:::o;3158:153:46:-;3230:18;3267:37;3284:19;3267:16;:37::i;1721:252::-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;1843:48:46::1;1859:19;1880:10;1843:15;:48::i;:::-;1906:60;::::0;-1:-1:-1;;;;;1906:60:46;::::1;::::0;-1:-1:-1;;;;;1906:60:46;::::1;::::0;1922:10:::1;::::0;1906:60:::1;::::0;;;::::1;1721:252:::0;;;:::o;2738:607:45:-;2822:8;2903:34;:13;2926:10;2903:22;:34::i;:::-;2898:53;;-1:-1:-1;2946:5:45;;2738:607;-1:-1:-1;2738:607:45:o;2898:53::-;3027:31;3061:20;:18;:20::i;:::-;3112:22;;3027:54;;-1:-1:-1;3091:18:45;3145:171;3165:10;3161:1;:14;3145:171;;;3258:1;-1:-1:-1;;;;;3200:60:45;:46;3215:10;3227:15;3243:1;3227:18;;;;;;;;:::i;:::-;;;;;;;3200:14;:46::i;:::-;-1:-1:-1;;;;;3200:60:45;;3196:110;;-1:-1:-1;3287:4:45;;2738:607;-1:-1:-1;;;;2738:607:45:o;3196:110::-;3177:3;;3145:171;;;-1:-1:-1;3333:5:45;;2738:607;-1:-1:-1;;;;2738:607:45:o;4759:191:12:-;4824:7;4843:30;4876:26;:24;:26::i;:::-;4919:8;:14;;;;;-1:-1:-1;;4919:14:12;;;:24;;;;4759:191::o;2293:434:46:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;2459:10:46::1;2325:21:27;2341:4;2325:15;:21::i;:::-;2496:19:46::2;2092:41:27;2113:19;2092:20;:41::i;:::-;2531:28:46::3;2547:11;2531:15;:28::i;:::-;2569:61;2585:10;2597:19;2618:11;2569:15;:61::i;:::-;2696:10;-1:-1:-1::0;;;;;2645:75:46::3;2675:19;-1:-1:-1::0;;;;;2645:75:46::3;2663:10;-1:-1:-1::0;;;;;2645:75:46::3;;2708:11;2645:75;;;;;;:::i;:::-;;;;;;;;2356:1:27::2;3217::12::1;2293:434:46::0;;;;:::o;5246:136:12:-;5320:18;5333:4;5320:12;:18::i;:::-;3191:16;3202:4;3191:10;:16::i;:::-;5350:25:::1;5361:4;5367:7;5350:10;:25::i;:::-;;5246:136:::0;;;:::o;2025:216:46:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;2130:39:46::1;2149:19;2130:18;:39::i;:::-;2184:50;::::0;-1:-1:-1;;;;;2184:50:46;::::1;::::0;2202:10:::1;::::0;2184:50:::1;::::0;;;::::1;2025:216:::0;;:::o;4041:300:27:-;4182:26;4144:19;2092:41;2113:19;2092:20;:41::i;:::-;4246:8:::1;::::0;:39:::1;::::0;-1:-1:-1;;;4246:39:27;;-1:-1:-1;;;;;4246:8:27;;::::1;::::0;:18:::1;::::0;:39:::1;::::0;4265:19;;4246:39:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;4231:72:27::1;;:74;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:88;;;-1:-1:-1::0;;;;;4231:101:27::1;;:103;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;4231:103:27::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;4224:110:::0;4041:300;-1:-1:-1;;;4041:300:27:o;1170:591:47:-;-1:-1:-1;;;;;;;;1322:11:47;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1438:10:47;-1:-1:-1;;;;;1424:25:47;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1424:25:47;;1413:37;;;;;;;;:::i;:::-;;;;-1:-1:-1;;1413:37:47;;;;;;;;;1390:20;;;:60;1470:284;1521:19;1564:34;1521:19;1564:13;:34::i;:::-;1629:5;1618:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;1659:8;1707:4;1735:8;1470:15;:284::i;:::-;-1:-1:-1;1461:293:47;1170:591;-1:-1:-1;;;;;;1170:591:47:o;1132:589:48:-;2362:4:12;3191:16;2362:4;3191:10;:16::i;:::-;1328:11:48;1356:43:::1;1328:11:::0;1388:3;1356:19:::1;:43::i;:::-;1409;1429:10:::0;1441:3;1409:19:::1;:43::i;:::-;1462:27;1478:10;1462:15;:27::i;:::-;1505:9;1500:215;1520:10;1516:1;:14;1500:215;;;1551:34;1570:11;;1582:1;1570:14;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;1551:18;:34::i;:::-;1599:23;1615:3;;1619:1;1615:6;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;1599:15;:23::i;:::-;1645:11;;1657:1;1645:14;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;1637:36:48::1;;1682:4;1689:3;;1693:1;1689:6;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;1697:3;;1701:1;1697:6;;;;;;;:::i;:::-;;;;;;;1637:67;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1532:3;;;;;1500:215;;;;1297:424;1132:589:::0;;;;;;;:::o;6348:245:12:-;-1:-1:-1;;;;;6441:34:12;;966:10:15;6441:34:12;6437:102;;6498:30;;-1:-1:-1;;;6498:30:12;;;;;;;;;;;6437:102;6549:37;6561:4;6567:18;6549:11;:37::i;1787:353:48:-;1998:17;2034:99;2054:10;2066:19;2087:2;2091:21;2109:2;2091:17;:21::i;:::-;2114:8;2124;2034:19;:99::i;:::-;2027:106;1787:353;-1:-1:-1;;;;;;;1787:353:48:o;1416:77:28:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;1476:10:28::1;:8;:10::i;:::-;1416:77:::0;:::o;3842:525:46:-;-1:-1:-1;;;;;4033:27:46;;3965:14;4033:27;;;:12;:27;;;;;:34;3981:27;4082:16;;;4078:55;;-1:-1:-1;4116:16:46;;;4130:1;4116:16;;;;;;;;4100:33;;4078:55;4164:6;4147:14;4156:5;4147:6;:14;:::i;:::-;:23;4143:52;;;4180:15;4189:6;4180;:15;:::i;:::-;4172:23;;4143:52;4233:5;-1:-1:-1;;;;;4219:20:46;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4219:20:46;;4206:33;;4254:9;4249:112;4269:5;4265:1;:9;4249:112;;;-1:-1:-1;;;;;4311:27:46;;;;;;:12;:27;;;;;4339:10;4348:1;4339:6;:10;:::i;:::-;4311:39;;;;;;;;:::i;:::-;;;;;;;;;4295:10;4306:1;4295:13;;;;;;;;:::i;:::-;;;;;;;;;;:55;4276:3;;4249:112;;;;3842:525;;;;;;;:::o;1883:133:30:-;-1:-1:-1;;;;;1979:30:30;1952:8;1979:30;;;:15;:30;;;;;;;;;1883:133::o;1156:958:45:-;1265:28;1295:29;1345:37;1362:19;1345:16;:37::i;:::-;1340:87;;-1:-1:-1;;1392:16:45;;;1406:1;1392:16;;;;;;1410;;;;;;;;;1392;;;-1:-1:-1;1156:958:45:o;1340:87::-;1438:18;1459:22;:13;:20;:22::i;:::-;1438:43;;1519:10;-1:-1:-1;;;;;1505:25:45;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1505:25:45;;1491:39;;1569:10;-1:-1:-1;;;;;1555:25:45;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1555:25:45;;1540:40;;1590:13;1619:9;1614:369;1634:10;1630:1;:14;1614:369;;;1665:18;1686:19;:13;1703:1;1686:16;:19::i;:::-;-1:-1:-1;;;;;1741:26:45;;;1719:19;1741:26;;;:14;:26;;;;;;;;-1:-1:-1;;;;;1741:47:45;;;;;;;;;;1665:40;;-1:-1:-1;1741:47:45;1806:25;;1802:171;;1872:10;1851:11;1863:5;1851:18;;;;;;;;:::i;:::-;;;;;;:31;-1:-1:-1;;;;;1851:31:45;;;-1:-1:-1;;;;;1851:31:45;;;;;1922:11;1900:12;1913:5;1900:19;;;;;;;;:::i;:::-;-1:-1:-1;;;;;1900:33:45;;;:19;;;;;;;;;;;:33;1951:7;;;:::i;:::-;;;1802:171;-1:-1:-1;;1646:3:45;;1614:369;;;;2052:5;2039:11;2032:26;2092:5;2078:12;2071:27;2018:90;;1156:958;;;:::o;2244:275:28:-;2339:14;;2300:4;;-1:-1:-1;;;;;2339:14:28;2371:34;-1:-1:-1;;;;;;;;;;;2339:14:28;2371:7;:34::i;:::-;:60;;;;-1:-1:-1;;;;;;2604:18:28;;;:22;;2409;2371:96;;;;;2445:12;-1:-1:-1;;;;;2435:30:28;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2370:142;;;;2484:28;:26;:28::i;:::-;2363:149;;;2244:275;:::o;4887:236:27:-;4977:8;5002:37;5019:19;5002:16;:37::i;:::-;4997:56;;-1:-1:-1;5048:5:27;5041:12;;4997:56;-1:-1:-1;;;;;;5070:36:27;;;;;;;;:15;:36;;;;;;-1:-1:-1;;;;;5070:36:27;;;:46;;;;4887:236::o;722:344:48:-;4158:30:14;4191:26;:24;:26::i;:::-;4302:15;;4158:59;;-1:-1:-1;4302:15:14;-1:-1:-1;;;4302:15:14;;;4301:16;;-1:-1:-1;;;;;4348:14:14;4279:19;4724:16;;:34;;;;;4744:14;4724:34;4704:54;;4768:17;4788:11;-1:-1:-1;;;;;4788:16:14;4803:1;4788:16;:50;;;;-1:-1:-1;4816:4:14;4808:25;:30;4788:50;4768:70;;4854:12;4853:13;:30;;;;;4871:12;4870:13;4853:30;4849:91;;;4906:23;;-1:-1:-1;;;4906:23:14;;;;;;;;;;;4849:91;4949:18;;-1:-1:-1;;;;;;4949:18:14;4966:1;4949:18;;;4977:67;;;;5011:22;;-1:-1:-1;;;;5011:22:14;-1:-1:-1;;;5011:22:14;;;4977:67;833:37:48::1;2362:4:12;864:5:48::0;833:10:::1;:37::i;:::-;;880:30;904:5;880:23;:30::i;:::-;920:31;945:5;920:24;:31::i;:::-;961:35;990:5;961:28;:35::i;:::-;1006:53;1023:5;1030:6;1038:20;1006:16;:53::i;:::-;5068:14:14::0;5064:101;;;5098:23;;-1:-1:-1;;;;5098:23:14;;;5140:14;;;;;;5098:23;;5140:14;:::i;:::-;;;;;;;;5064:101;4092:1079;;;;;722:344:48;;;:::o;1284:73:28:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;1342:8:28::1;:6;:8::i;3095:402:27:-:0;3208:27;;;;;;;;:::i;:::-;2427:38;2445:19;2427:17;:38::i;:::-;3251:14:::1;3279;;::::0;::::1;:7:::0;:14:::1;:::i;:::-;3268:37;;;;;;;:::i;:::-;3251:54:::0;-1:-1:-1;3316:58:27::1;3338:27;::::0;;;::::1;::::0;::::1;;:::i;:::-;3367:6;3316:21;:58::i;:::-;3384:16;:14;:16::i;:::-;3411:21;3424:7;3411:12;:21::i;:::-;3472:7;:17;;;3448:42;3464:6;3448:42;;;;;;:::i;:::-;;;;;;;;3241:256;3095:402:::0;;:::o;4615:211::-;4690:8;4717:52;:22;-1:-1:-1;;;;;4717:52:27;;:31;:52::i;:::-;:102;;;;-1:-1:-1;4773:8:27;;:46;;-1:-1:-1;;;4773:46:27;;-1:-1:-1;;;;;4773:8:27;;;;:25;;:46;;4799:19;;4773:46;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;2492:233:13:-;2573:7;2592:40;2635:36;:34;:36::i;:::-;2688:14;:20;;;;;;;;;;2592:79;;-1:-1:-1;2688:30:13;;2712:5;2688:23;:30::i;:::-;2681:37;2492:233;-1:-1:-1;;;;2492:233:13:o;3732:207:12:-;3809:4;3825:30;3858:26;:24;:26::i;:::-;3901:8;:14;;;;;;;;;;;-1:-1:-1;;;;;3901:31:12;;;;;;;;;-1:-1:-1;;3901:31:12;;;;;;3732:207::o;3402:256:45:-;3495:19;3531:37;3548:19;3531:16;:37::i;:::-;3526:61;;-1:-1:-1;3585:1:45;3570:17;;3526:61;-1:-1:-1;;;;;;3604:26:45;;;;;;;:14;:26;;;;;;;;-1:-1:-1;;;;;3604:47:45;;;;;;;;;;;;;3402:256::o;3658:227:13:-;3725:16;3753:40;3796:36;:34;:36::i;:::-;3849:14;:20;;;;;;;;;;3753:79;;-1:-1:-1;3849:29:13;;:27;:29::i;2171:515:45:-;2213:28;2253:25;2281:22;:13;:20;:22::i;:::-;2334:15;;2253:50;;-1:-1:-1;2334:15:45;-1:-1:-1;;;;;2374:25:45;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2374:25:45;;2360:39;;2409:13;2437:9;2432:163;2452:10;2448:1;:14;2432:163;;;2487:29;2504:8;2513:1;2504:11;;;;;;;;:::i;:::-;;;;;;;2487:16;:29::i;:::-;2483:102;;;2559:8;2568:1;2559:11;;;;;;;;:::i;:::-;;;;;;;2536;2548:7;;;;;:::i;:::-;;;2536:20;;;;;;;;:::i;:::-;;;;;;:34;-1:-1:-1;;;;;2536:34:45;;;-1:-1:-1;;;;;2536:34:45;;;;;2483:102;2464:3;;2432:163;;;;2664:5;2651:11;2644:26;2630:50;;;2171:515;:::o;2346:247:29:-;2464:36;;:::i;:::-;-1:-1:-1;;;;;2523:36:29;;;;;;:15;:36;;;;;;;;;:61;;;;;;;;;-1:-1:-1;;;;;2523:61:29;;;;;-1:-1:-1;;;2523:61:29;;;;;;;;;;;;-1:-1:-1;;;2523:61:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:63;;:61;:63::i;2779:327:46:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;2935:19:46::1;2092:41:27;2113:19;2092:20;:41::i;:::-;2970:50:46::2;2988:10;3000:19;2970:17;:50::i;:::-;3035:64;::::0;-1:-1:-1;;;;;3035:64:46;::::2;::::0;-1:-1:-1;;;;;3035:64:46;::::2;::::0;3055:10:::2;::::0;3035:64:::2;::::0;;;::::2;3217:1:12::1;2779:327:46::0;;;:::o;3558:422:27:-;3656:8;3676:26;3705:33;3718:19;3705:12;:33::i;:::-;3772:16;;3676:62;;-1:-1:-1;3748:21:27;3802:18;;;3798:36;;3829:5;3822:12;;;;;;3798:36;3850:9;3845:106;3865:13;3861:1;:17;3845:106;;;3919:8;-1:-1:-1;;;;;3903:24:27;:9;3913:1;3903:12;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;3903:24:27;;3899:41;;3936:4;3929:11;;;;;;;3899:41;3880:3;;3845:106;;;-1:-1:-1;3968:5:27;;3558:422;-1:-1:-1;;;;;3558:422:27:o;5184:667::-;5235:36;5283:23;5309:31;:22;:29;:31::i;:::-;5367:13;;5283:57;;-1:-1:-1;5367:13:27;-1:-1:-1;;;;;5413:20:27;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;5413:20:27;;5390:43;;5443:13;5472:9;5467:211;5487:6;5483:1;:10;5467:211;;;5514:12;5536:6;5543:1;5536:9;;;;;;;;:::i;:::-;;;;;;;;;;;5564:8;;:32;;-1:-1:-1;;;5564:32:27;;5536:9;;-1:-1:-1;;;;;;5564:8:27;;:25;;:32;;5536:9;;5564:32;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5560:108;;;5648:5;5616:20;5637:7;;;;:::i;:::-;;;5616:29;;;;;;;;:::i;:::-;;;;;;:37;-1:-1:-1;;;;;5616:37:27;;;-1:-1:-1;;;;;5616:37:27;;;;;5560:108;-1:-1:-1;5495:3:27;;5467:211;;2037:249:29;2156:36;;:::i;:::-;-1:-1:-1;;;;;2215:37:29;;;;;;:16;:37;;;;;;;;;:62;;;;;;;;;-1:-1:-1;;;;;2215:62:29;;;;;-1:-1:-1;;;2215:62:29;;;;;;;;;;;;-1:-1:-1;;;2215:62:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:64;;:62;:64::i;2893:222:13:-;2964:7;2983:40;3026:36;:34;:36::i;:::-;3079:14;:20;;;;;;;;;;2983:79;;-1:-1:-1;3079:29:13;;:27;:29::i;1460:305:29:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;1687:71:29::1;1707:19:::0;1687:71:::1;;::::0;;::::1;::::0;::::1;1728:14:::0;1687:71:::1;:::i;:::-;;;::::0;;::::1;::::0;::::1;1744:13:::0;1687:71:::1;:::i;:::-;:19;:71::i;2206:352:48:-:0;2434:17;2470:81;2490:10;2502:19;2523:2;2527:3;;2470:81;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2532:8:48;;-1:-1:-1;2542:8:48;;-1:-1:-1;2470:19:48;;-1:-1:-1;2470:81:48:i;:::-;2463:88;2206:352;-1:-1:-1;;;;;;;;2206:352:48:o;5662:138:12:-;5737:18;5750:4;5737:12;:18::i;:::-;3191:16;3202:4;3191:10;:16::i;:::-;5767:26:::1;5779:4;5785:7;5767:11;:26::i;3363:427:46:-:0;3436:36;3474:28;3541:20;:18;:20::i;:::-;3588:27;;3518:43;;-1:-1:-1;3588:27:46;-1:-1:-1;;;;;3639:21:46;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3639:21:46;;3625:35;;3676:9;3671:113;3691:6;3687:1;:10;3671:113;;;3735:38;3749:20;3770:1;3749:23;;;;;;;;:::i;:::-;;;;;;;3735:13;:38::i;:::-;3718:11;3730:1;3718:14;;;;;;;;:::i;:::-;-1:-1:-1;;;;;3718:55:46;;;:14;;;;;;;;;;;:55;3699:3;;3671:113;;;;3508:282;3363:427;;:::o;5912:131:27:-;6014:22;;-1:-1:-1;;;;;6014:22:27;;5912:131::o;4148:103:12:-;4214:30;4225:4;966:10:15;4214::12;:30::i;4438:353:13:-;4525:4;4541:40;4584:36;:34;:36::i;:::-;4541:79;;4630:12;4645:32;4663:4;4669:7;4645:17;:32::i;:::-;4630:47;;4691:7;4687:74;;;4714:14;:20;;;;;;;;;;:36;;4742:7;4714:27;:36::i;:::-;;4777:7;4438:353;-1:-1:-1;;;;4438:353:13:o;3987:348::-;4073:4;4089:40;4132:36;:34;:36::i;:::-;4089:79;;4178:12;4193:31;4210:4;4216:7;4193:16;:31::i;:::-;4178:46;;4238:7;4234:71;;;4261:14;:20;;;;;;;;;;:33;;4286:7;4261:24;:33::i;1767:587:47:-;1996:4;-1:-1:-1;;;;;;2023:52:47;;-1:-1:-1;;;2023:52:47;;:96;;;2079:40;2107:11;2079:27;:40::i;:::-;2023:175;;;;2135:63;2186:11;2135:50;:63::i;:::-;2023:250;;;;2214:59;2261:11;2214:46;:59::i;:::-;2023:324;;;;2289:58;2335:11;2289:45;:58::i;896:203:45:-;981:4;-1:-1:-1;;;;;;1004:48:45;;-1:-1:-1;;;1004:48:45;;:88;;;1056:36;1080:11;1056:23;:36::i;11622:231:27:-;11699:21;11737:37;11754:19;11737:16;:37::i;:::-;11732:61;;-1:-1:-1;11791:1:27;;11622:231;-1:-1:-1;11622:231:27:o;11732:61::-;-1:-1:-1;;;;;;11810:36:27;;;;;:15;:36;;;;;;-1:-1:-1;;;;;11810:36:27;;11622:231::o;7854:597::-;7948:29;7964:12;7948:15;:29::i;:::-;8015:22;;-1:-1:-1;;;;;8015:22:27;;;7992:45;;;;7988:94;;8062:19;8046:36;;-1:-1:-1;;;8046:36:27;;;;;;;;:::i;:::-;;;;;;;;7988:94;8097:8;;:46;;-1:-1:-1;;;8097:46:27;;-1:-1:-1;;;;;8097:8:27;;;;:25;;:46;;8123:19;;8097:46;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8092:98;;8170:19;8152:38;;-1:-1:-1;;;8152:38:27;;;;;;;;:::i;8092:98::-;8206:47;:22;-1:-1:-1;;;;;8206:47:27;;:26;:47::i;:::-;8201:101;;8282:19;8262:40;;-1:-1:-1;;;8262:40:27;;;;;;;;:::i;8201:101::-;-1:-1:-1;;;;;8312:36:27;;;;;;:15;:36;;;;;;:51;;-1:-1:-1;;;;;;8312:51:27;-1:-1:-1;;;;;8312:51:27;;;;;;;;8379:65;;8312:51;;:36;8398:10;;8379:65;;8312:36;8379:65;7854:597;;:::o;8871:165:26:-;8951:4;8974:55;8984:3;-1:-1:-1;;;;;9004:23:26;;8974:9;:55::i;2787:177:12:-;2920:28;;2787:177::o;12199:130:27:-;-1:-1:-1;;;;;12266:18:27;;12262:60;;12293:29;;-1:-1:-1;;;12293:29:27;;;;;;;;;;;12628:177;12715:37;12732:19;12715:16;:37::i;:::-;12710:88;;12778:19;12761:37;;-1:-1:-1;;;12761:37:27;;;;;;;;:::i;3725:792:45:-;3958:36;3996:37;4049:47;4076:19;4049:26;:47::i;:::-;4110:27;;3957:139;;-1:-1:-1;3957:139:45;-1:-1:-1;4110:31:45;4106:294;;4162:9;4157:233;4177:20;:27;4173:1;:31;4157:233;;;4260:11;-1:-1:-1;;;;;4233:38:45;:20;4254:1;4233:23;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;4233:38:45;;4229:147;;4321:19;4341:1;4321:22;;;;;;;;:::i;:::-;;;;;;;4345:11;4302:55;;-1:-1:-1;;;4302:55:45;;;;;;;;;:::i;4229:147::-;4206:3;;4157:233;;;;4106:294;4410:29;:13;4428:10;4410:17;:29::i;:::-;-1:-1:-1;;;;;;;;4449:26:45;;;;;;;:14;:26;;;;;;;;-1:-1:-1;;;;;4449:47:45;;;;;;;;;;;;;:61;;-1:-1:-1;;;;;;4449:61:45;;;;;;;;3725:792::o;8581:304:27:-;8661:50;:22;-1:-1:-1;;;;;8661:50:27;;:29;:50::i;:::-;8656:101;;8737:19;8720:37;;-1:-1:-1;;;8720:37:27;;;;;;;;:::i;8656:101::-;-1:-1:-1;;;;;8774:36:27;;;;;;:15;:36;;;;;;8767:43;;-1:-1:-1;;;;;;8767:43:27;;;8826:52;8846:10;;8826:52;;;8581:304;:::o;10842:774::-;11114:11;11127:36;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11127:36:27;11084:19;2092:41;2113:19;2092:20;:41::i;:::-;11185:362:::1;::::0;;::::1;::::0;::::1;::::0;;;;11231:20:::1;11242:8:::0;11231:20;;;::::1;:::i;:::-;;::::0;;;;::::1;-1:-1:-1::0;;11231:20:27;;;;;;11185:362;;;11231:20:::1;11185:362:::0;;::::1;::::0;;;11303:30;;-1:-1:-1;11303:30:27;;;;;::::1;::::0;;11185:362;;;;;11303:30;::::1;::::0;::::1;-1:-1:-1::0;;;;;;;;;;;;;;;;;11303:30:27::1;;;;;;;;;;;;;;;;11185:362;;;;11528:8;-1:-1:-1::0;;;;;11185:362:27::1;;;;;11358:146;11395:95;;;;;;;;11428:8;11395:95;;;;11464:24;11395:95;;;;::::0;2187:56:6;;;31992:13:49;;2187:56:6;;;31974:32:49;32076:4;32064:17;;;32058:24;32051:32;32044:40;32022:20;;;;32015:70;;;;2187:56:6;;;;;;;;;;31947:18:49;;;;2187:56:6;;;;;;;;-1:-1:-1;;;;;2187:56:6;-1:-1:-1;;;2187:56:6;;;;2070:178;11358:146:27::1;11185:362:::0;;11564:8:::1;::::0;:45:::1;::::0;-1:-1:-1;;;11564:45:27;;11175:372;;-1:-1:-1;;;;;;11564:8:27::1;::::0;:15:::1;::::0;:45:::1;::::0;11580:19;;11175:372;;11564:45:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11558:51;;10842:774:::0;;;;;;;;;;:::o;5395:121:45:-;5479:1;5474;:6;5470:39;;5489:20;;-1:-1:-1;;;5489:20:45;;;;;26540:25:49;;;26581:18;;;26574:34;;;26513:18;;5489:20:45;26366:248:49;12335:111:27;12401:3;12408:1;12401:8;12397:42;;12418:21;;-1:-1:-1;;;12418:21:27;;;;;;;;;;;5160:154:45;5254:28;5271:10;5254:16;:28::i;:::-;5249:58;;5291:16;;-1:-1:-1;;;5291:16:45;;;;;;;;;;;4718:144:48;4818:16;;;4832:1;4818:16;;;;;;;;;4780:20;;4818:16;;;;;;;;;;;-1:-1:-1;4818:16:48;4812:22;;4853:2;4844:3;4848:1;4844:6;;;;;;;;:::i;:::-;;;;;;:11;;;;;4718:144;;;:::o;3419:1293::-;3650:17;3637:2;2325:21:27;2341:4;2325:15;:21::i;:::-;3679:17:48::1;3710:3;3699:15;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;3699:15:48;;::::1;::::0;;;3749:100:::1;::::0;::::1;::::0;;-1:-1:-1;;;;;3749:100:48;::::1;::::0;;-1:-1:-1;;;;;3749:100:48;::::1;3699:15;3749:100:::0;::::1;::::0;;;;;;;3699:15;-1:-1:-1;3724:135:48::1;::::0;:11:::1;:135::i;:::-;3870:19;3892:47;3907:10;3919:19;3892:14;:47::i;:::-;3870:69;;3949:28;3965:11;3949:15;:28::i;:::-;3999:643;4055:19;4098:34;4112:19;4098:13;:34::i;:::-;4180:329;;;;;;;;4237:10;-1:-1:-1::0;;;;;4180:329:48::1;;;;;4290:25;:23;:25::i;:::-;-1:-1:-1::0;;;;;4180:329:48::1;;;;;4347:2;-1:-1:-1::0;;;;;4180:329:48::1;;;;;4383:11;-1:-1:-1::0;;;;;4180:329:48::1;;;;;4443:4;-1:-1:-1::0;;;;;4180:329:48::1;;;;;4486:4;4180:329;;::::0;4152:371:::1;;;;;;;;:::i;:::-;;;;;;;;;;;;;4547:8;4595:4;4623:8;3999:20;:643::i;:::-;3987:655;;4652:53;4668:25;:23;:25::i;:::-;4695:9;4652:15;:53::i;:::-;3669:1043;;3419:1293:::0;;;;;;;;;:::o;3478:178:16:-;2226:16;:14;:16::i;:::-;3536:25:::1;3564:21;:19;:21::i;:::-;3595:17:::0;;-1:-1:-1;;3595:17:16::1;::::0;;;-1:-1:-1;3627:22:16::1;966:10:15::0;3636:12:16::1;3627:22;;;;;;:::i;:::-;;;;;;;;3526:130;3478:178::o:0;9117:115:26:-;9180:7;9206:19;9214:3;4556:18;;4474:107;9574:156;9648:7;9698:22;9702:3;9714:5;9698:3;:22::i;2496:145:16:-;2543:4;2559:25;2587:21;:19;:21::i;:::-;2625:9;;;;2496:145;-1:-1:-1;;2496:145:16:o;9071:205:14:-;9129:30;;3147:66;9186:27;8819:122;890:145:28;6929:20:14;:18;:20::i;:::-;981:47:28::1;1015:12;981:33;:47::i;1099:145:29:-:0;6929:20:14;:18;:20::i;:::-;1190:47:29::1;1225:11;1190:34;:47::i;863:169:30:-:0;6929:20:14;:18;:20::i;:::-;966:59:30::1;1005:19;966:38;:59::i;1302:227:46:-:0;6929:20:14;:18;:20::i;:::-;1424:33:46::1;1451:5;1424:26;:33::i;:::-;1467:55;1493:6;1501:20;1467:25;:55::i;3170:176:16:-:0;1979:19;:17;:19::i;:::-;3229:25:::1;3257:21;:19;:21::i;:::-;3288:16:::0;;-1:-1:-1;;3288:16:16::1;3300:4;3288:16;::::0;;3229:49;-1:-1:-1;3319:20:16::1;3326:12;966:10:15::0;;887:96;12452:170:27;12535:10;;:58;;-1:-1:-1;;;12535:58:27;;12555:37;;;;-1:-1:-1;;;;;;;12555:37:27;12535:58;;;26765:56:49;-1:-1:-1;;;12535:10:27;;;-1:-1:-1;;;;;12535:10:27;;:19;;26738:18:49;;12535:58:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12531:84;;;12602:13;;-1:-1:-1;;;12602:13:27;;;;;;;;;;;12811:209;12915:44;12931:19;12952:6;12915:15;:44::i;:::-;12910:103;;12968:45;;-1:-1:-1;;;12968:45:27;;-1:-1:-1;;;;;27022:31:49;;12968:45:27;;;27004:50:49;-1:-1:-1;;;;;27090:32:49;;27070:18;;;27063:60;26977:18;;12968:45:27;26832:297:49;12048:145:27;12124:8;;-1:-1:-1;;;;;12124:8:27;12102:10;:31;12098:88;;12164:8;;12142:44;;-1:-1:-1;;;12142:44:27;;;;-1:-1:-1;;;;;12164:8:27;;12175:10;;12142:44;;;:::i;12098:88::-;12048:145::o;2360:1275:47:-;2458:39;2511:12;;;;:7;:12;:::i;:::-;2500:46;;;;;;;:::i;:::-;2458:88;;2690:13;:33;;;-1:-1:-1;;;;;2659:64:47;:7;:27;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;2659:64:47;;2655:193;;2774:27;;;;;;;;:::i;:::-;2803:33;;;;2746:91;;-1:-1:-1;;;2746:91:47;;-1:-1:-1;;;;;29023:31:49;;;2746:91:47;;;29005:50:49;29091:31;;29071:18;;;29064:59;28978:18;;2746:91:47;28835:294:49;2655:193:47;2940:20;2974:14;;;;:7;:14;:::i;:::-;2963:37;;;;;;;:::i;:::-;2940:60;;3030:13;:31;;;-1:-1:-1;;;;;3014:47:47;:12;-1:-1:-1;;;;;3014:47:47;;3010:150;;3117:31;;;;3084:65;;-1:-1:-1;;;3084:65:47;;;;3103:12;;3084:65;;;:::i;3010:150::-;3185:28;;3169:45;;:15;:45::i;:::-;3241:33;;;;3225:69;;3276:17;;3225:15;:69::i;:::-;3304:29;3319:13;3304:14;:29::i;:::-;3454:7;:17;;;3418:13;:22;;;-1:-1:-1;;;;;3349:279:47;3376:13;:28;;;-1:-1:-1;;;;;3349:279:47;;3496:13;:28;;;3485:53;;;;;;;;;;;;:::i;:::-;3552:27;;;;;;;;:::i;:::-;3593:25;:23;:25::i;:::-;3349:279;;;;;;;;:::i;:::-;;;;;;;;2448:1187;;2360:1275;:::o;11317:144:26:-;11394:4;11417:37;11427:3;11447:5;11417:9;:37::i;1250:207:13:-;1403:38;;1250:207::o;10270:300:26:-;10333:16;10361:22;10386:19;10394:3;10386:7;:19::i;4429:530:9:-;4521:18;;:::i;:::-;4785:99;4802:6;:15;;;-1:-1:-1;;;;;4785:99:9;4819:6;:13;;;-1:-1:-1;;;;;4785:99:9;4852:6;:18;;;4834:36;;:15;:36;;;;:::i;:::-;4872:6;:11;;;-1:-1:-1;;;;;4785:99:9;:16;:99::i;:::-;-1:-1:-1;;;;;4755:130:9;;;-1:-1:-1;4891:44:9;4919:15;4891:44;:18;;;:44;4755:6;4429:530::o;4586:505:45:-;-1:-1:-1;;;;;4719:26:45;;;4697:19;4719:26;;;:14;:26;;;;;;;;-1:-1:-1;;;;;4719:47:45;;;;;;;;;;;;4776:85;;4814:47;;-1:-1:-1;;;4814:47:45;;-1:-1:-1;;;;;30713:32:49;;4814:47:45;;;30695:51:49;-1:-1:-1;;;;;30782:31:49;;30762:18;;;30755:59;30668:18;;4814:47:45;30523:297:49;4776:85:45;-1:-1:-1;;;;;4878:26:45;;;;;;:14;:26;;;;;;;;-1:-1:-1;;;;;4878:47:45;;;;;;;;;4871:54;;-1:-1:-1;;;;;;4871:54:45;;;5022:28;4893:10;5022:16;:28::i;:::-;5017:67;;5052:32;:13;5073:10;5052:20;:32::i;3140:605:29:-;3329:66;:14;3388:5;3329:41;:66::i;:::-;-1:-1:-1;;;;;3405:37:29;;;;;;:16;:37;;;;;:75;;3465:14;3405:59;:75::i;:::-;3491:65;:13;3549:5;3491:40;:65::i;:::-;-1:-1:-1;;;;;3566:36:29;;;;;;:15;:36;;;;;:73;;3625:13;3566:58;:73::i;:::-;3687:19;-1:-1:-1;;;;;3655:83:29;3675:10;-1:-1:-1;;;;;3655:83:29;;3708:14;3724:13;3655:83;;;;;;;:::i;4381:197:12:-;4469:22;4477:4;4483:7;4469;:22::i;:::-;4464:108;;4547:7;4556:4;4514:47;;-1:-1:-1;;;4514:47:12;;;;;;;;;:::i;7894:388::-;7972:4;7988:30;8021:26;:24;:26::i;:::-;7988:59;;8061:22;8069:4;8075:7;8061;:22::i;:::-;8057:219;;;8133:5;8099:14;;;;;;;;;;;-1:-1:-1;;;;;8099:31:12;;;;;;;;;;:39;;-1:-1:-1;;8099:39:12;;;8157:40;966:10:15;;8099:14:12;;8157:40;;8133:5;8157:40;8218:4;8211:11;;;;;8057:219;8260:5;8253:12;;;;;8634:156:26;8707:4;8730:53;8738:3;-1:-1:-1;;;;;8758:23:26;;8730:7;:53::i;7270:387:12:-;7347:4;7363:30;7396:26;:24;:26::i;:::-;7363:59;;7437:22;7445:4;7451:7;7437;:22::i;:::-;7432:219;;7475:8;:14;;;;;;;;;;;-1:-1:-1;;;;;7475:31:12;;;;;;;;;:38;;-1:-1:-1;;7475:38:12;7509:4;7475:38;;;7559:12;966:10:15;;887:96;7559:12:12;-1:-1:-1;;;;;7532:40:12;7550:7;-1:-1:-1;;;;;7532:40:12;7544:4;7532:40;;;;;;;;;;7593:4;7586:11;;;;;8316:150:26;8386:4;8409:50;8414:3;-1:-1:-1;;;;;8434:23:26;;8409:4;:50::i;4373:373:46:-;4565:4;-1:-1:-1;;;;;;4592:48:46;;-1:-1:-1;;;4592:48:46;;:95;;-1:-1:-1;;;;;;;4644:43:46;;-1:-1:-1;;;4644:43:46;4592:95;:147;;;;4703:36;4727:11;4703:23;:36::i;1609:210:30:-;1694:4;-1:-1:-1;;;;;;1717:55:30;;-1:-1:-1;;;1717:55:30;;:95;;;1776:36;1800:11;1771:206:29;1856:4;-1:-1:-1;;;;;;1879:51:29;;-1:-1:-1;;;1879:51:29;;:91;;;1934:36;1958:11;1499:205:28;1584:4;-1:-1:-1;;;;;;1607:50:28;;-1:-1:-1;;;1607:50:28;;:90;;;1661:36;1685:11;1661:23;:36::i;10804:129:26:-;10871:4;10894:32;10899:3;10919:5;10894:4;:32::i;4264:129::-;4337:4;4360:21;;;:14;;;;;:21;;;;;;:26;;;4264:129::o;11101:135::-;11171:4;11194:35;11202:3;11222:5;11194:7;:35::i;4677:721:47:-;1979:19:16;:17;:19::i;:::-;4828:10:47::1;:21;;;1248:30:46;1267:10;1248:18;:30::i;:::-;4876::47::0;;2092:41:27::2;4876:30:47::0;2092:20:27::2;:41::i;:::-;4922:20:47::3;4956:10;:20;;;4945:45;;;;;;;;;;;;:::i;:::-;5021:10:::0;;4922:68;;-1:-1:-1;5041:27:47::3;5021:10:::0;5041:15:::3;:27::i;:::-;5084:9;5079:140;5099:10;5095:1;:14;5079:140;;;5138:10;:21;;;-1:-1:-1::0;;;;;5130:43:47::3;;5174:10;5194:4;5201:3;5205:1;5201:6;;;;;;;;:::i;:::-;;;;;;;5130:78;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5111:3;;;;;5079:140;;;;5229:60;5247:10;:21;;;5278:4;5285:3;5229:17;:60::i;:::-;5299:92;5325:10;:30;;;5357:10;:21;;;5380:10;5299:25;:92::i;:::-;4912:486;;1288:1:46::2;2008::16::1;4677:721:47::0;:::o;9133:1620:27:-;9398:17;9368:19;2427:38;2445:19;2427:17;:38::i;:::-;9427:25:::1;9443:8;9427:15;:25::i;:::-;9462;9478:8;9462:15;:25::i;:::-;9497:28;9513:4;:11;9497:15;:28::i;:::-;9537:11;9550:36;9602:98;9618:19;9639:8;9649:4;9655:8;9665:24;9691:8;9602:15;:98::i;:::-;9536:164:::0;;-1:-1:-1;9536:164:27;-1:-1:-1;9711:17:27::1;-1:-1:-1::0;;;;;9742:22:27;::::1;9738:538;;9796:3;9784:9;:15;9780:65;;;9808:37;::::0;-1:-1:-1;;;9808:37:27;;::::1;::::0;::::1;26540:25:49::0;;;9835:9:27::1;26581:18:49::0;;;26574:34;26513:18;;9808:37:27::1;26366:248:49::0;9780:65:27::1;9871:8;;;;;;;;;-1:-1:-1::0;;;;;9871:8:27::1;-1:-1:-1::0;;;;;9871:25:27::1;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9860:38;;9989:8;9970:7;:16;;:27;-1:-1:-1::0;;;;;9970:27:27::1;;;-1:-1:-1::0;;;;;9970:27:27::1;;;::::0;::::1;10026:8;-1:-1:-1::0;;;;;10011:32:27::1;;10051:3;10011:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10096:3;10084:9;:15;;;;:::i;:::-;10072:27;;9738:538;;;10134:9;:14:::0;10130:56:::1;;10157:29;::::0;-1:-1:-1;;;10157:29:27;;10176:9:::1;10157:29;::::0;::::1;3436:25:49::0;3409:18;;10157:29:27::1;3290:177:49::0;10130:56:27::1;10200:65;-1:-1:-1::0;;;;;10200:33:27;::::1;10234:10;10254:4;10261:3:::0;10200:33:::1;:65::i;:::-;10319:8;::::0;10286:48:::1;::::0;-1:-1:-1;;;10286:48:27;;-1:-1:-1;;;;;10286:24:27;;::::1;::::0;::::1;::::0;:48:::1;::::0;10319:8;;::::1;::::0;10330:3;;10286:48:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;10357:8:27::1;::::0;:47:::1;::::0;-1:-1:-1;;;10357:47:27;;-1:-1:-1;;;;;10357:8:27;;::::1;::::0;:17:::1;::::0;:47:::1;::::0;10375:19;;10396:7;;10357:47:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10345:59:::0;-1:-1:-1;10419:13:27;;10415:282:::1;;10529:37;::::0;10512:12:::1;::::0;10529:10:::1;::::0;10552:9;;10512:12;10529:37;10512:12;10529:37;10552:9;10529:10;:37:::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10511:55;;;10585:7;10580:56;;10614:10;10626:9;10601:35;;-1:-1:-1::0;;;10601:35:27::1;;;;;;;;;:::i;10580:56::-;10655:31;::::0;3436:25:49;;;10664:10:27::1;::::0;10655:31:::1;::::0;3424:2:49;3409:18;10655:31:27::1;;;;;;;10434:263;10415:282;10712:34;::::0;10736:9;;10724:10:::1;::::0;10712:34:::1;::::0;;;::::1;9417:1336;;;9133:1620:::0;;;;;;;;;:::o;4752:309:46:-;-1:-1:-1;;;;;4841:32:46;;;;;;:17;:32;;;;;;;;:43;;;;;;;;;;;4837:104;;;4893:48;;-1:-1:-1;;;4893:48:46;;-1:-1:-1;;;;;32964:31:49;;4893:48:46;;;32946:50:49;33012:18;;;33005:34;;;32919:18;;4893:48:46;32774:271:49;4837:104:46;-1:-1:-1;;;;;4951:27:46;;;;;;;:12;:27;;;;;;;;:43;;;;;;;;;;;;;;;;;;5004:32;;;:17;:32;;;;;:43;;;;;;;;;;:50;;-1:-1:-1;;5004:50:46;;;;;;4752:309::o;2909:126:16:-;2972:8;:6;:8::i;:::-;2967:62;;3003:15;;-1:-1:-1;;;3003:15:16;;;;;;;;;;;1147:162;1270:23;;1147:162::o;4923:118:26:-;4990:7;5016:3;:11;;5028:5;5016:18;;;;;;;;:::i;:::-;;;;;;;;;5009:25;;4923:118;;;;:::o;7082:141:14:-;7149:17;:15;:17::i;:::-;7144:73;;7189:17;;-1:-1:-1;;;7189:17:14;;;;;;;;;;;1041:184:28;6929:20:14;:18;:20::i;:::-;1142:14:28::1;:29:::0;;-1:-1:-1;;;;;;1142:29:28::1;-1:-1:-1::0;;;;;1142:29:28;::::1;;::::0;;1181:37:::1;-1:-1:-1::0;;;;;;;;;;;1142:29:28;1181:10:::1;:37::i;1250:150:29:-:0;6929:20:14;:18;:20::i;:::-;1351:42:29::1;-1:-1:-1::0;;;;;;;;;;;1381:11:29::1;1351:10;:42::i;1038:179:30:-:0;6929:20:14;:18;:20::i;:::-;1151:59:30::1;-1:-1:-1::0;;;;;;;;;;;1190:19:30::1;1151:10;:59::i;1535:134:46:-:0;6929:20:14;:18;:20::i;:::-;1622:40:46::1;-1:-1:-1::0;;;;;;;;;;;1656:5:46::1;1622:10;:40::i;2489:188:27:-:0;6929:20:14;:18;:20::i;:::-;2605:65:27::1;2641:6;2649:20;2605:35;:65::i;2709:128:16:-:0;2774:8;:6;:8::i;:::-;2770:61;;;2805:15;;-1:-1:-1;;;2805:15:16;;;;;;;;;;;2936:477:48;3269:92;3285:75;3300:13;:24;;;3326:13;:33;;;3285:14;:75::i;3269:92::-;3371:35;3392:13;3371:20;:35::i;5581:109:26:-;5637:16;5672:3;:11;;5665:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5581:109;;;:::o;6554:201:9:-;6688:7;6710:40;6715:8;6734:15;6745:4;6734:8;:15;:::i;:::-;6725:24;;:6;:24;:::i;:::-;6710:4;:40::i;:::-;6703:47;6554:201;-1:-1:-1;;;;;6554:201:9:o;5833:451::-;5936:16;;5932:348;;;5981:6;:15;;;-1:-1:-1;;;;;5966:30:9;:6;:11;;;-1:-1:-1;;;;;5966:30:9;;;:50;;;-1:-1:-1;6000:11:9;;;;-1:-1:-1;;;;;6000:16:9;;5966:50;5962:110;;;6056:6;6035:28;;-1:-1:-1;;;6035:28:9;;;;;;;;:::i;5962:110::-;6083:14;6079:71;;;6116:25;;-1:-1:-1;;;6116:25:9;;;;;;;;;;;5932:348;6174:11;;;;-1:-1:-1;;;;;6174:16:9;;;;:40;;-1:-1:-1;6194:15:9;;;;-1:-1:-1;;;;;6194:20:9;;;6174:40;6170:104;;;6258:6;6233:32;;-1:-1:-1;;;6233:32:9;;;;;;;;:::i;5081:700::-;5336:20;;5299:16;;5318:38;;-1:-1:-1;;;5336:20:9;;;;5318:15;:38;:::i;:::-;5299:57;-1:-1:-1;5366:13:9;;5362:193;;5432:17;;;;5451:15;;5415:77;;-1:-1:-1;;;;;5432:17:9;;;;5451:15;;;5468:8;;-1:-1:-1;;;5478:13:9;;;;5415:16;:77::i;:::-;5389:104;;-1:-1:-1;;;;;5389:104:9;;;;-1:-1:-1;;;;;;5502:46:9;;;;-1:-1:-1;;;5532:15:9;5502:46;;;;;;5362:193;5592:15;;;;5609;;5587:38;;-1:-1:-1;;;;;5587:38:9;;;;5609:15;5587:4;:38::i;:::-;5561:65;;5653:16;;5632:37;;-1:-1:-1;;;5632:37:9;-1:-1:-1;;;;;;5632:37:9;;;-1:-1:-1;;;;;5561:65:9;;;5632:37;;;;5695:15;;;;5732:11;;;;;5716:27;;-1:-1:-1;;;5716:27:9;5675:35;;;;5716:27;5561:65;5675:17;;5716:27;5755:21;;;;;5653:6;;5755:21;:::i;:::-;;;;;;;;5173:608;5081:700;;:::o;2815:1368:26:-;2881:4;3010:21;;;:14;;;:21;;;;;;3046:13;;3042:1135;;3413:18;3434:12;3445:1;3434:8;:12;:::i;:::-;3480:18;;3413:33;;-1:-1:-1;3460:17:26;;3480:22;;3501:1;;3480:22;:::i;:::-;3460:42;;3535:9;3521:10;:23;3517:378;;3564:17;3584:3;:11;;3596:9;3584:22;;;;;;;;:::i;:::-;;;;;;;;;3564:42;;3731:9;3705:3;:11;;3717:10;3705:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;3844:25;;;:14;;;:25;;;;;:36;;;3517:378;3973:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;4076:3;:14;;:21;4091:5;4076:21;;;;;;;;;;;4069:28;;;4119:4;4112:11;;;;;;;2241:406;2304:4;2325:21;2335:3;2340:5;2325:9;:21::i;:::-;2320:321;;-1:-1:-1;2362:23:26;;;;;;;;:11;:23;;;;;;;;;;;;;2544:18;;2520:21;;;:14;;;:21;;;;;;:42;;;;2576:11;;2320:321;-1:-1:-1;2625:5:26;2618:12;;7169:283:27;7254:4;-1:-1:-1;;;;;;7277:52:27;;-1:-1:-1;;;7277:52:27;;:124;;-1:-1:-1;;;;;;;7345:56:27;;-1:-1:-1;;;7345:56:27;7277:124;:168;;;-1:-1:-1;;;;;;;7405:40:27;;-1:-1:-1;;;7405:40:27;7270:175;7169:283;-1:-1:-1;;7169:283:27:o;1695:212:13:-;1780:4;-1:-1:-1;;;;;;1803:57:13;;-1:-1:-1;;;1803:57:13;;:97;;;1864:36;1888:11;1864:23;:36::i;5404:311:47:-;5532:10;;5511:18;5553:156;5573:10;5569:1;:14;5553:156;;;5641:9;-1:-1:-1;;;;;5608:42:47;:29;5623:5;5630:3;5634:1;5630:6;;;;;;;;:::i;:::-;;;;;;;5608:14;:29::i;:::-;-1:-1:-1;;;;;5608:42:47;;5604:94;;5680:9;5691:3;5695:1;5691:6;;;;;;;;:::i;:::-;;;;;;;5659:39;;-1:-1:-1;;;5659:39:47;;;;;;;;;:::i;5604:94::-;5585:3;;5553:156;;2684:181:29;-1:-1:-1;;;;;2797:37:29;;;;;;:16;:37;;;;;:61;;2844:6;2852:5;2797:46;:61::i;1702:188:22:-;1802:81;1822:5;1844;-1:-1:-1;;;;;1844:18:22;;1865:4;1871:2;1875:5;1829:53;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1829:53:22;;;;;;;;;;;1802:19;:81::i;8485:120:14:-;8535:4;8558:26;:24;:26::i;:::-;:40;-1:-1:-1;;;8558:40:14;;;;;;-1:-1:-1;8485:120:14:o;2683:347:27:-;6929:20:14;:18;:20::i;:::-;2829:37:27::1;2845:20;-1:-1:-1::0;;;;;2829:37:27::1;:15;:37::i;:::-;2877:8;:40:::0;;-1:-1:-1;;;;;;2877:40:27::1;-1:-1:-1::0;;;;;2877:40:27;::::1;::::0;;::::1;::::0;;;2945:22:::1;::::0;;-1:-1:-1;;;2945:22:27;;;;:20:::1;::::0;:22:::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;2877:40;2945:22:::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2927:10;:41:::0;;-1:-1:-1;;;;;2978:45:27;;::::1;-1:-1:-1::0;;;;;;;;;;;2927:41:27;;;::::1;-1:-1:-1::0;;;2927:41:27::1;2978:45:::0;;;;-1:-1:-1;;;;;;2978:45:27;;;;;;;::::1;::::0;;-1:-1:-1;2683:347:27:o;3641:1030:47:-;1979:19:16;:17;:19::i;:::-;3756:20:47::1;3790:13;:28;;;3779:53;;;;;;;;;;;;:::i;:::-;3863:10:::0;;3756:76;;-1:-1:-1;3883:27:47::1;3863:10:::0;3883:15:::1;:27::i;:::-;3921:39;3937:13;:22;;;3921:15;:39::i;:::-;3970:44;3989:13;:24;;;3970:18;:44::i;:::-;4030:9;4025:450;4045:10;4041:1;:14;4025:450;;;4076:10;4089:3;4093:1;4089:6;;;;;;;;:::i;:::-;;;;;;;4076:19;;4109:13;4125:44;4140:13;:24;;;4166:2;4125:14;:44::i;:::-;4109:60:::0;-1:-1:-1;;;;;;4188:22:47;::::1;4205:4;4188:22;::::0;:48:::1;;;4214:22;4230:5;4214:15;:22::i;:::-;4184:281;;;4264:13;:24;;;-1:-1:-1::0;;;;;4256:46:47::1;;4303:5;4310:13;:22;;;4334:2;4256:81;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4184:281;;;4392:13;:24;;;-1:-1:-1::0;;;;;4376:46:47::1;;4423:13;:22;;;4447:2;4376:74;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4184:281;-1:-1:-1::0;;4057:3:47::1;;4025:450;;;;4485:72;4503:13;:24;;;4529:13;:22;;;4553:3;4485:17;:72::i;:::-;4567:97;4592:13;:33;;;4627:13;:24;;;4653:10;4567:24;:97::i;6883:99:9:-:0;6942:7;6968:1;6964;:5;:13;;6976:1;6964:13;;;-1:-1:-1;6972:1:9;;6883:99;-1:-1:-1;6883:99:9:o;3443:202:12:-;3528:4;-1:-1:-1;;;;;;3551:47:12;;-1:-1:-1;;;3551:47:12;;:87;;-1:-1:-1;;;;;;;;;;1134:40:17;;;3602:36:12;1035:146:17;5721:324:47;5826:26;;-1:-1:-1;;;5826:26:47;;;;;3436:25:49;;;5795:15:47;;-1:-1:-1;;;;;5826:22:47;;;;;3409:18:49;;5826:26:47;;;;;;;;;;;;;;;;;;-1:-1:-1;5826:26:47;;;;;;;;-1:-1:-1;;5826:26:47;;;;;;;;;;;;:::i;:::-;;;5822:217;;-1:-1:-1;6026:1:47;6011:17;;5822:217;5895:2;-1:-1:-1;5888:9:47;;2516:1790:9;2734:18;;-1:-1:-1;;;2734:18:9;;;;2733:19;;:41;;-1:-1:-1;2756:18:9;;2733:41;2729:68;;;2516:1790;;;:::o;2729:68::-;2820:15;;;2860:17;;;-1:-1:-1;;;;;2820:15:9;;;;2860:17;;;2803:14;;2902:38;;-1:-1:-1;;;2920:20:9;;;;2902:15;:38;:::i;:::-;2883:57;-1:-1:-1;2951:13:9;;2947:271;;2987:8;2978:6;:17;2974:48;;;3004:18;;-1:-1:-1;;;3004:18:9;;;;;;;;;;;2974:48;3142:13;;;;3097:59;;3114:8;;3124:6;;3132:8;;-1:-1:-1;;;3142:13:9;;-1:-1:-1;;;;;3142:13:9;3097:16;:59::i;:::-;3165:46;;-1:-1:-1;;;;3165:46:9;-1:-1:-1;;;3195:15:9;3165:46;;;;;;3088:68;-1:-1:-1;2947:271:9;3239:13;3228:8;:24;3224:302;;;-1:-1:-1;;;;;3348:26:9;;3344:97;;3383:58;;-1:-1:-1;;;3383:58:9;;;;;26540:25:49;;;26581:18;;;26574:34;;;26513:18;;3383:58:9;26366:248:49;3344:97:9;3481:8;3491:13;3506:12;3456:63;;-1:-1:-1;;;3456:63:9;;;;;;;;;;:::i;3224:302::-;3544:13;3535:6;:22;3531:594;;;3582:13;;;;;-1:-1:-1;;;3582:13:9;;-1:-1:-1;;;;;3582:13:9;;3567:12;;3582:13;;3921:8;;3582:13;3921:8;:::i;:::-;3894:22;3910:6;3894:13;:22;:::i;:::-;3893:37;;;;:::i;:::-;3892:46;;;;:::i;:::-;3865:73;-1:-1:-1;;;;;;3951:26:9;;3947:95;;3986:56;;-1:-1:-1;;;3986:56:9;;;;;26540:25:49;;;26581:18;;;26574:34;;;26513:18;;3986:56:9;26366:248:49;3947:95:9;4079:16;4097:6;4105:12;4057:61;;-1:-1:-1;;;4057:61:9;;;;;;;;;;:::i;3531:594::-;4130:23;4140:13;4130:23;;:::i;:::-;4228:33;;-1:-1:-1;;;;;;4228:33:9;-1:-1:-1;;;;;4228:33:9;;;;;4272:29;;3436:25:49;;;4228:33:9;;-1:-1:-1;4272:29:9;;3424:2:49;3409:18;4272:29:9;;;;;;;2618:1688;;;2516:1790;;;:::o;4059:629:22:-;4478:23;4504:33;-1:-1:-1;;;;;4504:27:22;;4532:4;4504:27;:33::i;:::-;4478:59;;4551:10;:17;4572:1;4551:22;;:57;;;;;4589:10;4578:30;;;;;;;;;;;;:::i;:::-;4577:31;4551:57;4547:135;;;4664:5;4631:40;;-1:-1:-1;;;4631:40:22;;;;;;;;:::i;2955:179:29:-;-1:-1:-1;;;;;3067:36:29;;;;;;:15;:36;;;;;:60;;3113:6;3121:5;3067:45;:60::i;2705:151:24:-;2780:12;2811:38;2833:6;2841:4;2847:1;2780:12;3421;3435:23;3462:6;-1:-1:-1;;;;;3462:11:24;3481:5;3488:4;3462:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3420:73;;;;3510:55;3537:6;3545:7;3554:10;3510:26;:55::i;:::-;3503:62;3180:392;-1:-1:-1;;;;;;3180:392:24:o;4625:582::-;4769:12;4798:7;4793:408;;4821:19;4829:10;4821:7;:19::i;:::-;4793:408;;;5045:17;;:22;:49;;;;-1:-1:-1;;;;;;5071:18:24;;;:23;5045:49;5041:119;;;5138:6;5121:24;;-1:-1:-1;;;5121:24:24;;;;;;;;:::i;5041:119::-;-1:-1:-1;5180:10:24;5173:17;;5743:516;5874:17;;:21;5870:383;;6102:10;6096:17;6158:15;6145:10;6141:2;6137:19;6130:44;5870:383;6225:17;;-1:-1:-1;;;6225:17:24;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:131:49:-;-1:-1:-1;;;;;89:31:49;;79:42;;69:70;;135:1;132;125:12;150:134;218:20;;247:31;218:20;247:31;:::i;:::-;150:134;;;:::o;289:247::-;348:6;401:2;389:9;380:7;376:23;372:32;369:52;;;417:1;414;407:12;369:52;456:9;443:23;475:31;500:5;475:31;:::i;541:286::-;599:6;652:2;640:9;631:7;627:23;623:32;620:52;;;668:1;665;658:12;620:52;694:23;;-1:-1:-1;;;;;;746:32:49;;736:43;;726:71;;793:1;790;783:12;1024:118;1110:5;1103:13;1096:21;1089:5;1086:32;1076:60;;1132:1;1129;1122:12;1147:382;1212:6;1220;1273:2;1261:9;1252:7;1248:23;1244:32;1241:52;;;1289:1;1286;1279:12;1241:52;1328:9;1315:23;1347:31;1372:5;1347:31;:::i;:::-;1397:5;-1:-1:-1;1454:2:49;1439:18;;1426:32;1467:30;1426:32;1467:30;:::i;:::-;1516:7;1506:17;;;1147:382;;;;;:::o;1534:171::-;1601:20;;-1:-1:-1;;;;;1650:30:49;;1640:41;;1630:69;;1695:1;1692;1685:12;1710:184;1768:6;1821:2;1809:9;1800:7;1796:23;1792:32;1789:52;;;1837:1;1834;1827:12;1789:52;1860:28;1878:9;1860:28;:::i;2008:203::-;-1:-1:-1;;;;;2172:32:49;;;;2154:51;;2142:2;2127:18;;2008:203::o;2216:289::-;2258:3;2296:5;2290:12;2323:6;2318:3;2311:19;2379:6;2372:4;2365:5;2361:16;2354:4;2349:3;2345:14;2339:47;2431:1;2424:4;2415:6;2410:3;2406:16;2402:27;2395:38;2494:4;2487:2;2483:7;2478:2;2470:6;2466:15;2462:29;2457:3;2453:39;2449:50;2442:57;;;2216:289;;;;:::o;2510:220::-;2659:2;2648:9;2641:21;2622:4;2679:45;2720:2;2709:9;2705:18;2697:6;2679:45;:::i;2735:319::-;2802:6;2810;2863:2;2851:9;2842:7;2838:23;2834:32;2831:52;;;2879:1;2876;2869:12;2831:52;2902:28;2920:9;2902:28;:::i;:::-;2892:38;;2980:2;2969:9;2965:18;2952:32;2993:31;3018:5;2993:31;:::i;3059:226::-;3118:6;3171:2;3159:9;3150:7;3146:23;3142:32;3139:52;;;3187:1;3184;3177:12;3139:52;-1:-1:-1;3232:23:49;;3059:226;-1:-1:-1;3059:226:49:o;3472:460::-;3548:6;3556;3564;3617:2;3605:9;3596:7;3592:23;3588:32;3585:52;;;3633:1;3630;3623:12;3585:52;3672:9;3659:23;3691:31;3716:5;3691:31;:::i;:::-;3741:5;-1:-1:-1;3765:37:49;3798:2;3783:18;;3765:37;:::i;:::-;3755:47;;3854:2;3843:9;3839:18;3826:32;3867:33;3892:7;3867:33;:::i;:::-;3919:7;3909:17;;;3472:460;;;;;:::o;3937:367::-;4005:6;4013;4066:2;4054:9;4045:7;4041:23;4037:32;4034:52;;;4082:1;4079;4072:12;4034:52;4127:23;;;-1:-1:-1;4226:2:49;4211:18;;4198:32;4239:33;4198:32;4239:33;:::i;4309:446::-;4362:3;4400:5;4394:12;4427:6;4422:3;4415:19;4459:4;4454:3;4450:14;4443:21;;4498:4;4491:5;4487:16;4521:1;4531:199;4545:6;4542:1;4539:13;4531:199;;;4610:13;;-1:-1:-1;;;;;4606:39:49;4594:52;;4675:4;4666:14;;;;4703:17;;;;4642:1;4560:9;4531:199;;;-1:-1:-1;4746:3:49;;4309:446;-1:-1:-1;;;;4309:446:49:o;4760:261::-;4939:2;4928:9;4921:21;4902:4;4959:56;5011:2;5000:9;4996:18;4988:6;4959:56;:::i;5026:560::-;5111:6;5119;5127;5135;5188:3;5176:9;5167:7;5163:23;5159:33;5156:53;;;5205:1;5202;5195:12;5156:53;5244:9;5231:23;5263:31;5288:5;5263:31;:::i;:::-;5313:5;-1:-1:-1;5337:37:49;5370:2;5355:18;;5337:37;:::i;:::-;5026:560;;5327:47;;-1:-1:-1;;;;5447:2:49;5432:18;;5419:32;;5550:2;5535:18;5522:32;;5026:560::o;5773:367::-;5836:8;5846:6;5900:3;5893:4;5885:6;5881:17;5877:27;5867:55;;5918:1;5915;5908:12;5867:55;-1:-1:-1;5941:20:49;;-1:-1:-1;;;;;5973:30:49;;5970:50;;;6016:1;6013;6006:12;5970:50;6053:4;6045:6;6041:17;6029:29;;6113:3;6106:4;6096:6;6093:1;6089:14;6081:6;6077:27;6073:38;6070:47;6067:67;;;6130:1;6127;6120:12;6067:67;5773:367;;;;;:::o;6145:1099::-;6303:6;6311;6319;6327;6335;6343;6396:2;6384:9;6375:7;6371:23;6367:32;6364:52;;;6412:1;6409;6402:12;6364:52;6439:23;;-1:-1:-1;;;;;6474:30:49;;6471:50;;;6517:1;6514;6507:12;6471:50;6556:70;6618:7;6609:6;6598:9;6594:22;6556:70;:::i;:::-;6645:8;;-1:-1:-1;6530:96:49;-1:-1:-1;;6733:2:49;6718:18;;6705:32;-1:-1:-1;;;;;6749:32:49;;6746:52;;;6794:1;6791;6784:12;6746:52;6833:72;6897:7;6886:8;6875:9;6871:24;6833:72;:::i;:::-;6924:8;;-1:-1:-1;6807:98:49;-1:-1:-1;;7012:2:49;6997:18;;6984:32;-1:-1:-1;;;;;7028:32:49;;7025:52;;;7073:1;7070;7063:12;7025:52;7112:72;7176:7;7165:8;7154:9;7150:24;7112:72;:::i;:::-;6145:1099;;;;-1:-1:-1;6145:1099:49;;-1:-1:-1;6145:1099:49;;7203:8;;6145:1099;-1:-1:-1;;;6145:1099:49:o;7249:844::-;7352:6;7360;7368;7376;7384;7392;7445:3;7433:9;7424:7;7420:23;7416:33;7413:53;;;7462:1;7459;7452:12;7413:53;7501:9;7488:23;7520:31;7545:5;7520:31;:::i;:::-;7570:5;-1:-1:-1;7594:37:49;7627:2;7612:18;;7594:37;:::i;:::-;7584:47;;7683:2;7672:9;7668:18;7655:32;7696:33;7721:7;7696:33;:::i;:::-;7748:7;-1:-1:-1;7828:2:49;7813:18;;7800:32;;-1:-1:-1;7910:3:49;7895:19;;7882:33;7924;7882;7924;:::i;:::-;7249:844;;;;-1:-1:-1;7249:844:49;;;;;8056:3;8041:19;;;8028:33;;-1:-1:-1;;7249:844:49:o;8098:418::-;8174:6;8182;8190;8243:2;8231:9;8222:7;8218:23;8214:32;8211:52;;;8259:1;8256;8249:12;8211:52;8282:28;8300:9;8282:28;:::i;:::-;8272:38;8379:2;8364:18;;8351:32;;-1:-1:-1;8480:2:49;8465:18;;;8452:32;;8098:418;-1:-1:-1;;;8098:418:49:o;8521:682::-;8691:4;8739:2;8728:9;8724:18;8769:6;8758:9;8751:25;8812:2;8807;8796:9;8792:18;8785:30;8835:6;8870;8864:13;8901:6;8893;8886:22;8939:2;8928:9;8924:18;8917:25;;8977:2;8969:6;8965:15;8951:29;;8998:1;9008:169;9022:6;9019:1;9016:13;9008:169;;;9083:13;;9071:26;;9126:2;9152:15;;;;9117:12;;;;9044:1;9037:9;9008:169;;;-1:-1:-1;9194:3:49;;8521:682;-1:-1:-1;;;;;;8521:682:49:o;9208:465::-;9465:2;9454:9;9447:21;9428:4;9491:56;9543:2;9532:9;9528:18;9520:6;9491:56;:::i;:::-;9595:9;9587:6;9583:22;9578:2;9567:9;9563:18;9556:50;9623:44;9660:6;9652;9623:44;:::i;9678:460::-;9754:6;9762;9770;9823:2;9811:9;9802:7;9798:23;9794:32;9791:52;;;9839:1;9836;9829:12;9791:52;9878:9;9865:23;9897:31;9922:5;9897:31;:::i;:::-;9947:5;-1:-1:-1;10004:2:49;9989:18;;9976:32;10017:33;9976:32;10017:33;:::i;:::-;10069:7;-1:-1:-1;10095:37:49;10128:2;10113:18;;10095:37;:::i;:::-;10085:47;;9678:460;;;;;:::o;10143:393::-;10235:6;10288:2;10276:9;10267:7;10263:23;10259:32;10256:52;;;10304:1;10301;10294:12;10256:52;10331:23;;-1:-1:-1;;;;;10366:30:49;;10363:50;;;10409:1;10406;10399:12;10363:50;10432:22;;10488:3;10470:16;;;10466:26;10463:46;;;10505:1;10502;10495:12;10541:346;10609:6;10617;10670:2;10658:9;10649:7;10645:23;10641:32;10638:52;;;10686:1;10683;10676:12;10638:52;-1:-1:-1;;10731:23:49;;;10851:2;10836:18;;;10823:32;;-1:-1:-1;10541:346:49:o;10892:319::-;10959:6;10967;11020:2;11008:9;10999:7;10995:23;10991:32;10988:52;;;11036:1;11033;11026:12;10988:52;11075:9;11062:23;11094:31;11119:5;11094:31;:::i;:::-;11144:5;-1:-1:-1;11168:37:49;11201:2;11186:18;;11168:37;:::i;:::-;11158:47;;10892:319;;;;;:::o;12065:444::-;12117:3;12155:5;12149:12;12182:6;12177:3;12170:19;12214:4;12209:3;12205:14;12198:21;;12253:4;12246:5;12242:16;12276:1;12286:198;12300:6;12297:1;12294:13;12286:198;;;12365:13;;-1:-1:-1;;;;;12361:38:49;12349:51;;12429:4;12420:14;;;;12457:17;;;;12396:1;12315:9;12286:198;;12514:258;12691:2;12680:9;12673:21;12654:4;12711:55;12762:2;12751:9;12747:18;12739:6;12711:55;:::i;12777:154::-;12836:5;12881:2;12872:6;12867:3;12863:16;12859:25;12856:45;;;12897:1;12894;12887:12;12856:45;-1:-1:-1;12919:6:49;12777:154;-1:-1:-1;12777:154:49:o;12936:434::-;13064:6;13072;13080;13133:3;13121:9;13112:7;13108:23;13104:33;13101:53;;;13150:1;13147;13140:12;13101:53;13173:28;13191:9;13173:28;:::i;:::-;13163:38;;13220:62;13274:7;13269:2;13258:9;13254:18;13220:62;:::i;:::-;13210:72;;13301:63;13356:7;13350:3;13339:9;13335:19;13301:63;:::i;13375:1049::-;13505:6;13513;13521;13529;13537;13545;13553;13606:3;13594:9;13585:7;13581:23;13577:33;13574:53;;;13623:1;13620;13613:12;13574:53;13662:9;13649:23;13681:31;13706:5;13681:31;:::i;:::-;13731:5;-1:-1:-1;13755:37:49;13788:2;13773:18;;13755:37;:::i;:::-;13745:47;;13844:2;13833:9;13829:18;13816:32;13857:33;13882:7;13857:33;:::i;:::-;13909:7;-1:-1:-1;13967:2:49;13952:18;;13939:32;-1:-1:-1;;;;;13983:30:49;;13980:50;;;14026:1;14023;14016:12;13980:50;14065:70;14127:7;14118:6;14107:9;14103:22;14065:70;:::i;:::-;14154:8;;-1:-1:-1;14039:96:49;-1:-1:-1;;14241:3:49;14226:19;;14213:33;14255;14213;14255;:::i;:::-;13375:1049;;;;-1:-1:-1;13375:1049:49;;;;;;;;-1:-1:-1;;14387:3:49;14372:19;;;14359:33;;13375:1049::o;14429:462::-;14684:2;14673:9;14666:21;14647:4;14710:55;14761:2;14750:9;14746:18;14738:6;14710:55;:::i;15116:200::-;-1:-1:-1;;;;;15278:31:49;;;;15260:50;;15248:2;15233:18;;15116:200::o;15321:127::-;15382:10;15377:3;15373:20;15370:1;15363:31;15413:4;15410:1;15403:15;15437:4;15434:1;15427:15;15453:138;15532:13;;15554:31;15532:13;15554:31;:::i;15596:251::-;15666:6;15719:2;15707:9;15698:7;15694:23;15690:32;15687:52;;;15735:1;15732;15725:12;15687:52;15767:9;15761:16;15786:31;15811:5;15786:31;:::i;15852:127::-;15913:10;15908:3;15904:20;15901:1;15894:31;15944:4;15941:1;15934:15;15968:4;15965:1;15958:15;15984:252;16056:2;16050:9;16098:3;16086:16;;-1:-1:-1;;;;;16117:34:49;;16153:22;;;16114:62;16111:88;;;16179:18;;:::i;:::-;16215:2;16208:22;15984:252;:::o;16241:253::-;16313:2;16307:9;16355:4;16343:17;;-1:-1:-1;;;;;16375:34:49;;16411:22;;;16372:62;16369:88;;;16437:18;;:::i;16499:275::-;16570:2;16564:9;16635:2;16616:13;;-1:-1:-1;;16612:27:49;16600:40;;-1:-1:-1;;;;;16655:34:49;;16691:22;;;16652:62;16649:88;;;16717:18;;:::i;:::-;16753:2;16746:22;16499:275;;-1:-1:-1;16499:275:49:o;16779:163::-;16857:13;;16910:6;16899:18;;16889:29;;16879:57;;16932:1;16929;16922:12;16947:167;17025:13;;17078:10;17067:22;;17057:33;;17047:61;;17104:1;17101;17094:12;17119:132;17195:13;;17217:28;17195:13;17217:28;:::i;17256:1339::-;17357:6;17417:3;17405:9;17396:7;17392:23;17388:33;17433:2;17430:22;;;17448:1;17445;17438:12;17430:22;-1:-1:-1;17490:22:49;;:::i;:::-;17535:40;17565:9;17535:40;:::i;:::-;17528:5;17521:55;17608:48;17652:2;17641:9;17637:18;17608:48;:::i;:::-;17603:2;17596:5;17592:14;17585:72;17689:48;17733:2;17722:9;17718:18;17689:48;:::i;:::-;17684:2;17677:5;17673:14;17666:72;17770:48;17814:2;17803:9;17799:18;17770:48;:::i;:::-;17765:2;17758:5;17754:14;17747:72;17852:49;17896:3;17885:9;17881:19;17852:49;:::i;:::-;17846:3;17839:5;17835:15;17828:74;17935:49;17979:3;17968:9;17964:19;17935:49;:::i;:::-;17929:3;17922:5;17918:15;17911:74;18018:49;18062:3;18051:9;18047:19;18018:49;:::i;:::-;18012:3;18005:5;18001:15;17994:74;18101:50;18146:3;18135:9;18131:19;18101:50;:::i;:::-;18095:3;18088:5;18084:15;18077:75;18185:49;18229:3;18218:9;18214:19;18185:49;:::i;:::-;18179:3;18172:5;18168:15;18161:74;18268:49;18312:3;18301:9;18297:19;18268:49;:::i;:::-;18262:3;18255:5;18251:15;18244:74;18351:49;18395:3;18384:9;18380:19;18351:49;:::i;:::-;18345:3;18338:5;18334:15;18327:74;18434:49;18478:3;18467:9;18463:19;18434:49;:::i;:::-;18428:3;18421:5;18417:15;18410:74;18517:47;18559:3;18548:9;18544:19;18517:47;:::i;:::-;18511:3;18500:15;;18493:72;18504:5;17256:1339;-1:-1:-1;;;17256:1339:49:o;18600:183::-;18660:4;-1:-1:-1;;;;;18682:30:49;;18679:56;;;18715:18;;:::i;:::-;-1:-1:-1;18760:1:49;18756:14;18772:4;18752:25;;18600:183::o;18788:951::-;18883:6;18936:2;18924:9;18915:7;18911:23;18907:32;18904:52;;;18952:1;18949;18942:12;18904:52;18979:16;;-1:-1:-1;;;;;19007:30:49;;19004:50;;;19050:1;19047;19040:12;19004:50;19073:22;;19126:4;19118:13;;19114:27;-1:-1:-1;19104:55:49;;19155:1;19152;19145:12;19104:55;19188:2;19182:9;19211:64;19227:47;19267:6;19227:47;:::i;:::-;19211:64;:::i;:::-;19297:3;19321:6;19316:3;19309:19;19353:2;19348:3;19344:12;19337:19;;19408:2;19398:6;19395:1;19391:14;19387:2;19383:23;19379:32;19365:46;;19434:7;19426:6;19423:19;19420:39;;;19455:1;19452;19445:12;19420:39;19487:2;19483;19479:11;19468:22;;19499:210;19515:6;19510:3;19507:15;19499:210;;;19588:3;19582:10;19605:31;19630:5;19605:31;:::i;:::-;19649:18;;19696:2;19532:12;;;;19687;;;;19499:210;;19744:420;19797:3;19835:5;19829:12;19862:6;19857:3;19850:19;19894:4;19889:3;19885:14;19878:21;;19933:4;19926:5;19922:16;19956:1;19966:173;19980:6;19977:1;19974:13;19966:173;;;20041:13;;20029:26;;20084:4;20075:14;;;;20112:17;;;;20002:1;19995:9;19966:173;;20169:261;20348:2;20337:9;20330:21;20311:4;20368:56;20420:2;20409:9;20405:18;20397:6;20368:56;:::i;20435:782::-;20626:2;20608:21;;;20669:13;;-1:-1:-1;;;;;20665:39:49;;;20645:18;;;20638:67;20751:15;;;20745:22;-1:-1:-1;;;;;20741:47:49;20777:2;20721:18;;;20714:75;;;;20835:15;;20829:22;20825:48;;20820:2;20805:18;;;20798:76;;;;20921:15;;20915:22;20911:48;;20905:3;20890:19;;;20883:77;;;;21007:16;;21001:23;20997:49;20692:3;20976:19;;;20969:78;;;;21082:16;;21076:23;21137:4;21115:20;;;21108:34;-1:-1:-1;;21159:52:49;21206:3;21191:19;;21076:23;21159:52;:::i;21222:371::-;-1:-1:-1;;;;;21442:32:49;;;21424:51;;21511:32;;;;21506:2;21491:18;;21484:60;21575:2;21560:18;;21553:34;;;;21412:2;21397:18;;21222:371::o;21598:127::-;21659:10;21654:3;21650:20;21647:1;21640:31;21690:4;21687:1;21680:15;21714:4;21711:1;21704:15;21730:125;21795:9;;;21816:10;;;21813:36;;;21829:18;;:::i;21860:128::-;21927:9;;;21948:11;;;21945:37;;;21962:18;;:::i;21993:135::-;22032:3;22053:17;;;22050:43;;22073:18;;:::i;:::-;-1:-1:-1;22120:1:49;22109:13;;21993:135::o;22133:245::-;22200:6;22253:2;22241:9;22232:7;22228:23;22224:32;22221:52;;;22269:1;22266;22259:12;22221:52;22301:9;22295:16;22320:28;22342:5;22320:28;:::i;22597:521::-;22674:4;22680:6;22740:11;22727:25;22834:2;22830:7;22819:8;22803:14;22799:29;22795:43;22775:18;22771:68;22761:96;;22853:1;22850;22843:12;22761:96;22880:33;;22932:20;;;-1:-1:-1;;;;;;22964:30:49;;22961:50;;;23007:1;23004;22997:12;22961:50;23040:4;23028:17;;-1:-1:-1;23071:14:49;23067:27;;;23057:38;;23054:58;;;23108:1;23105;23098:12;23383:173;23451:20;;-1:-1:-1;;;;;23500:31:49;;23490:42;;23480:70;;23546:1;23543;23536:12;23561:702;23644:6;23704:2;23692:9;23683:7;23679:23;23675:32;23719:2;23716:22;;;23734:1;23731;23724:12;23716:22;-1:-1:-1;23803:2:49;23797:9;23845:2;23833:15;;-1:-1:-1;;;;;23863:34:49;;23899:22;;;23860:62;23857:88;;;23925:18;;:::i;:::-;23961:2;23954:22;23998:23;;24030:28;23998:23;24030:28;:::i;:::-;24067:21;;24121:38;24155:2;24140:18;;24121:38;:::i;:::-;24116:2;24108:6;24104:15;24097:63;24193:38;24227:2;24216:9;24212:18;24193:38;:::i;:::-;24188:2;24176:15;;24169:63;24180:6;23561:702;-1:-1:-1;;;23561:702:49:o;24268:300::-;-1:-1:-1;;;;;24460:32:49;;;24442:51;;24529:32;;24524:2;24509:18;;24502:60;24430:2;24415:18;;24268:300::o;24573:1553::-;24818:1;24814;24810:2;24806:10;24802:18;24794:6;24790:31;24779:9;24772:50;24858:2;24853;24842:9;24838:18;24831:30;24753:4;24896:6;24890:13;24939:4;24934:2;24923:9;24919:18;24912:32;24967:52;25014:3;25003:9;24999:19;24985:12;24967:52;:::i;:::-;24953:66;;25068:2;25060:6;25056:15;25050:22;25140:2;25136:7;25124:9;25116:6;25112:22;25108:36;25103:2;25092:9;25088:18;25081:64;25168:41;25202:6;25186:14;25168:41;:::i;:::-;25258:2;25246:15;;25240:22;25303;;;-1:-1:-1;;25299:36:49;25293:3;25278:19;;25271:65;25385:21;;25415:22;;;25465:2;25491:23;;;;-1:-1:-1;25532:1:49;;-1:-1:-1;25453:15:49;;;25542:280;25556:6;25553:1;25550:13;25542:280;;;25615:13;;25657:9;;-1:-1:-1;;;;;25653:35:49;25641:48;;25737:2;25729:11;;;25723:18;25709:12;;;25702:40;25797:15;;;;25685:1;25571:9;;;;;25771:2;25762:12;;;;25542:280;;;-1:-1:-1;25871:2:49;25859:15;;25853:22;-1:-1:-1;;;;;1965:31:49;25934:4;25919:20;;1953:44;25989:3;25977:16;;25971:23;26035:19;;;-1:-1:-1;;26031:33:49;26025:3;26010:19;;26003:62;25971:23;-1:-1:-1;26082:38:49;26035:19;25971:23;26082:38;:::i;26131:230::-;26201:6;26254:2;26242:9;26233:7;26229:23;26225:32;26222:52;;;26270:1;26267;26260:12;26222:52;-1:-1:-1;26315:16:49;;26131:230;-1:-1:-1;26131:230:49:o;27134:558::-;27176:5;27229:3;27222:4;27214:6;27210:17;27206:27;27196:55;;27247:1;27244;27237:12;27196:55;27274:20;;-1:-1:-1;;;;;27306:30:49;;27303:56;;;27339:18;;:::i;:::-;27383:59;27430:2;27407:17;;-1:-1:-1;;27403:31:49;27436:4;27399:42;27383:59;:::i;:::-;27467:6;27458:7;27451:23;27521:3;27514:4;27505:6;27497;27493:19;27489:30;27486:39;27483:59;;;27538:1;27535;27528:12;27483:59;27603:6;27596:4;27588:6;27584:17;27577:4;27568:7;27564:18;27551:59;27659:1;27630:20;;;27652:4;27626:31;27619:42;;;;27634:7;27134:558;-1:-1:-1;;;27134:558:49:o;27697:1133::-;27787:6;27840:2;27828:9;27819:7;27815:23;27811:32;27808:52;;;27856:1;27853;27846:12;27808:52;27883:23;;-1:-1:-1;;;;;27918:30:49;;27915:50;;;27961:1;27958;27951:12;27915:50;27984:22;;28040:4;28022:16;;;28018:27;28015:47;;;28058:1;28055;28048:12;28015:47;28084:22;;:::i;:::-;28143:2;28130:16;28155:33;28180:7;28155:33;:::i;:::-;28197:22;;28251:30;28277:2;28269:11;;28251:30;:::i;:::-;28246:2;28239:5;28235:14;28228:54;28327:2;28323;28319:11;28306:25;28340:33;28365:7;28340:33;:::i;:::-;28400:2;28389:14;;28382:31;28458:2;28450:11;;28437:25;28471:33;28437:25;28471:33;:::i;:::-;28531:2;28520:14;;28513:31;28577:32;28604:3;28596:12;;28577:32;:::i;:::-;28571:3;28560:15;;28553:57;28656:3;28648:12;;28635:26;-1:-1:-1;;;;;28673:32:49;;28670:52;;;28718:1;28715;28708:12;28670:52;28755:44;28791:7;28780:8;28776:2;28772:17;28755:44;:::i;:::-;28749:3;28738:15;;28731:69;-1:-1:-1;28742:5:49;27697:1133;-1:-1:-1;;;;27697:1133:49:o;29134:930::-;29229:6;29282:2;29270:9;29261:7;29257:23;29253:32;29250:52;;;29298:1;29295;29288:12;29250:52;29325:16;;-1:-1:-1;;;;;29353:30:49;;29350:50;;;29396:1;29393;29386:12;29350:50;29419:22;;29472:4;29464:13;;29460:27;-1:-1:-1;29450:55:49;;29501:1;29498;29491:12;29450:55;29534:2;29528:9;29557:64;29573:47;29613:6;29573:47;:::i;29557:64::-;29643:3;29667:6;29662:3;29655:19;29699:2;29694:3;29690:12;29683:19;;29754:2;29744:6;29741:1;29737:14;29733:2;29729:23;29725:32;29711:46;;29780:7;29772:6;29769:19;29766:39;;;29801:1;29798;29791:12;29766:39;29833:2;29829;29825:11;29814:22;;29845:189;29861:6;29856:3;29853:15;29845:189;;;29951:10;;29974:18;;30021:2;29878:12;;;;30012;;;;29845:189;;30069:449;30300:2;30289:9;30282:21;30263:4;30320:56;30372:2;30361:9;30357:18;30349:6;30320:56;:::i;:::-;-1:-1:-1;;;;;30412:31:49;;;30407:2;30392:18;;30385:59;30480:31;;;;30432:2;30460:18;;;30453:59;30480:31;30312:64;-1:-1:-1;;30069:449:49:o;30825:271::-;30911:12;;30904:20;30897:28;30885:41;;30979:4;30968:16;;;30962:23;-1:-1:-1;;;;;30958:49:49;;;30942:14;;;30935:73;;;;31061:4;31050:16;;;31044:23;31040:49;31024:14;;31017:73;30825:271::o;31101:381::-;31359:3;31344:19;;31372:43;31348:9;31397:6;31372:43;:::i;:::-;31424:52;31472:2;31461:9;31457:18;31449:6;31424:52;:::i;31487:274::-;-1:-1:-1;;;;;31679:32:49;;;;31661:51;;31743:2;31728:18;;31721:34;31649:2;31634:18;;31487:274::o;33050:168::-;33123:9;;;33154;;33171:15;;;33165:22;;33151:37;33141:71;;33192:18;;:::i;33223:243::-;33405:2;33390:18;;33417:43;33394:9;33442:6;33417:43;:::i;33471:127::-;33532:10;33527:3;33523:20;33520:1;33513:31;33563:4;33560:1;33553:15;33587:4;33584:1;33577:15;33603:345;33805:25;;;33861:2;33846:18;;33839:34;;;;-1:-1:-1;;;;;33909:32:49;33904:2;33889:18;;33882:60;33793:2;33778:18;;33603:345::o;33953:217::-;33993:1;34019;34009:132;;34063:10;34058:3;34054:20;34051:1;34044:31;34098:4;34095:1;34088:15;34126:4;34123:1;34116:15;34009:132;-1:-1:-1;34155:9:49;;33953:217::o;34175:301::-;34304:3;34342:6;34336:13;34388:6;34381:4;34373:6;34369:17;34364:3;34358:37;34450:1;34414:16;;34439:13;;;-1:-1:-1;34414:16:49;34175:301;-1:-1:-1;34175:301:49:o

Swarm Source

ipfs://bba0137ca3101440e2b76765b14e4154ddbde848a7797d09aa47ff6d4820a230

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

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