BurnMintTokenPool

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}
"
    },
    "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// 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);
}
"
    },
    "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @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);
}
"
    },
    "contracts/abstract/BurnMintTokenPoolAbstract.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity 0.8.24;\r
import {IBurnMintERC20} from "../interface/IBurnMintERC20.sol";\r
import {TokenPool} from "./TokenPool.sol";\r
import {Pool} from "../library/Pool.sol";\r
abstract contract BurnMintTokenPoolAbstract is TokenPool {\r
    /// @notice Contains the specific burn call for a pool.\r
    /// @dev overriding this method allows us to create pools with different burn signatures\r
    /// without duplicating the underlying logic.\r
    function _burn(uint256 amount) internal virtual;\r
\r
    /// @notice Burn the token in the pool\r
    /// @dev The _validateLockOrBurn check is an essential security check\r
    function lockOrBurn(\r
        Pool.LockOrBurnInV1 calldata lockOrBurnIn\r
    ) external virtual override returns (Pool.LockOrBurnOutV1 memory) {\r
        _validateLockOrBurn(lockOrBurnIn);\r
\r
        _burn(lockOrBurnIn.amount);\r
\r
        emit Burned(msg.sender, lockOrBurnIn.amount);\r
\r
        return\r
            Pool.LockOrBurnOutV1({\r
                destTokenAddress: getRemoteToken(\r
                    lockOrBurnIn.remoteChainSelector\r
                ),\r
                destPoolData: _encodeLocalDecimals()\r
            });\r
    }\r
\r
    /// @notice Mint tokens from the pool to the recipient\r
    /// @dev The _validateReleaseOrMint check is an essential security check\r
    function releaseOrMint(\r
        Pool.ReleaseOrMintInV1 calldata releaseOrMintIn\r
    ) external virtual override returns (Pool.ReleaseOrMintOutV1 memory) {\r
        _validateReleaseOrMint(releaseOrMintIn);\r
\r
        // Calculate the local amount\r
        uint256 localAmount = _calculateLocalAmount(\r
            releaseOrMintIn.amount,\r
            _parseRemoteDecimals(releaseOrMintIn.sourcePoolData)\r
        );\r
\r
        // Mint to the receiver\r
        IBurnMintERC20(address(i_token)).mint(\r
            releaseOrMintIn.receiver,\r
            localAmount\r
        );\r
\r
        emit Minted(msg.sender, releaseOrMintIn.receiver, localAmount);\r
\r
        return Pool.ReleaseOrMintOutV1({destinationAmount: localAmount});\r
    }\r
}\r
\r
"
    },
    "contracts/abstract/Ownable2Step.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.4;\r
import {IOwnable} from "../interface/IOwnable.sol";\r
/// @notice A minimal contract that implements 2-step ownership transfer and nothing more. It's made to be minimal\r
/// to reduce the impact of the bytecode size on any contract that inherits from it.\r
contract Ownable2Step is IOwnable {\r
    /// @notice The pending owner is the address to which ownership may be transferred.\r
    address private s_pendingOwner;\r
    /// @notice The owner is the current owner of the contract.\r
    /// @dev The owner is the second storage variable so any implementing contract could pack other state with it\r
    /// instead of the much less used s_pendingOwner.\r
    address private s_owner;\r
\r
    error OwnerCannotBeZero();\r
    error MustBeProposedOwner();\r
    error CannotTransferToSelf();\r
    error OnlyCallableByOwner();\r
\r
    event OwnershipTransferRequested(address indexed from, address indexed to);\r
    event OwnershipTransferred(address indexed from, address indexed to);\r
\r
    constructor(address newOwner, address pendingOwner) {\r
        if (newOwner == address(0)) {\r
            revert OwnerCannotBeZero();\r
        }\r
\r
        s_owner = newOwner;\r
        if (pendingOwner != address(0)) {\r
            _transferOwnership(pendingOwner);\r
        }\r
    }\r
\r
    /// @notice Get the current owner\r
    function owner() public view override returns (address) {\r
        return s_owner;\r
    }\r
\r
    /// @notice Allows an owner to begin transferring ownership to a new address. The new owner needs to call\r
    /// `acceptOwnership` to accept the transfer before any permissions are changed.\r
    /// @param to The address to which ownership will be transferred.\r
    function transferOwnership(address to) public override onlyOwner {\r
        _transferOwnership(to);\r
    }\r
\r
    /// @notice validate, transfer ownership, and emit relevant events\r
    /// @param to The address to which ownership will be transferred.\r
    function _transferOwnership(address to) private {\r
        if (to == msg.sender) {\r
            revert CannotTransferToSelf();\r
        }\r
\r
        s_pendingOwner = to;\r
\r
        emit OwnershipTransferRequested(s_owner, to);\r
    }\r
\r
    /// @notice Allows an ownership transfer to be completed by the recipient.\r
    function acceptOwnership() external override {\r
        if (msg.sender != s_pendingOwner) {\r
            revert MustBeProposedOwner();\r
        }\r
\r
        address oldOwner = s_owner;\r
        s_owner = msg.sender;\r
        s_pendingOwner = address(0);\r
\r
        emit OwnershipTransferred(oldOwner, msg.sender);\r
    }\r
\r
    /// @notice validate access\r
    function _validateOwnership() internal view {\r
        if (msg.sender != s_owner) {\r
            revert OnlyCallableByOwner();\r
        }\r
    }\r
\r
    /// @notice Reverts if called by anyone other than the contract owner.\r
    modifier onlyOwner() {\r
        _validateOwnership();\r
        _;\r
    }\r
}"
    },
    "contracts/abstract/Ownable2StepMsgSender.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.4;\r
import {Ownable2Step} from "./Ownable2Step.sol";\r
/// @notice Sets the msg.sender to be the owner of the contract and does not set a pending owner.\r
contract Ownable2StepMsgSender is Ownable2Step {\r
    constructor() Ownable2Step(msg.sender, address(0)) {}\r
}\r
"
    },
    "contracts/abstract/TokenPool.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity 0.8.24;\r
import { IPoolV1 } from "../interface/IPoolV1.sol";\r
import {EnumerableSet} from "../library/EnumerableSet.sol";\r
import {RateLimiter} from "../library/RateLimiter.sol";\r
import {IRMN} from "../interface/IRMN.sol";\r
import { IPoolV1 } from "../interface/IPoolV1.sol";\r
import { IRouter } from "../interface/IRouter.sol";\r
\r
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";\r
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";\r
\r
// import { IERC20 } from "../interface/IERC20.sol";\r
// import { IERC20Metadata } from "../interface/IERC20Metadata.sol";\r
\r
import {Ownable2StepMsgSender} from "./Ownable2StepMsgSender.sol";\r
import {Pool} from "../library/Pool.sol";\r
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";\r
\r
\r
/// @dev This pool supports different decimals on different chains but using this feature could impact the total number\r
/// of tokens in circulation. Since all of the tokens are locked/burned on the source, and a rounded amount is minted/released on the\r
/// destination, the number of tokens minted/released could be less than the number of tokens burned/locked. This is because the source\r
/// chain does not know about the destination token decimals. This is not a problem if the decimals are the same on both\r
/// chains.\r
///\r
/// Example:\r
/// Assume there is a token with 6 decimals on chain A and 3 decimals on chain B.\r
/// - 1.234567 tokens are burned on chain A.\r
/// - 1.234    tokens are minted on chain B.\r
/// When sending the 1.234 tokens back to chain A, you will receive 1.234000 tokens on chain A, effectively losing\r
/// 0.000567 tokens.\r
/// In the case of a burnMint pool on chain A, these funds are burned in the pool on chain A.\r
/// In the case of a lockRelease pool on chain A, these funds accumulate in the pool on chain A.\r
abstract contract TokenPool is IPoolV1, Ownable2StepMsgSender {\r
    using EnumerableSet for EnumerableSet.Bytes32Set;\r
    using EnumerableSet for EnumerableSet.AddressSet;\r
    using EnumerableSet for EnumerableSet.UintSet;\r
    using RateLimiter for RateLimiter.TokenBucket;\r
\r
    error CallerIsNotARampOnRouter(address caller);\r
    error ZeroAddressNotAllowed();\r
    error SenderNotAllowed(address sender);\r
    error AllowListNotEnabled();\r
    error NonExistentChain(uint64 remoteChainSelector);\r
    error ChainNotAllowed(uint64 remoteChainSelector);\r
    error CursedByRMN();\r
    error ChainAlreadyExists(uint64 chainSelector);\r
    error InvalidSourcePoolAddress(bytes sourcePoolAddress);\r
    error InvalidToken(address token);\r
    error Unauthorized(address caller);\r
    error PoolAlreadyAdded(uint64 remoteChainSelector, bytes remotePoolAddress);\r
    error InvalidRemotePoolForChain(\r
        uint64 remoteChainSelector,\r
        bytes remotePoolAddress\r
    );\r
    error InvalidRemoteChainDecimals(bytes sourcePoolData);\r
    error OverflowDetected(\r
        uint8 remoteDecimals,\r
        uint8 localDecimals,\r
        uint256 remoteAmount\r
    );\r
    error InvalidDecimalArgs(uint8 expected, uint8 actual);\r
\r
    event Locked(address indexed sender, uint256 amount);\r
    event Burned(address indexed sender, uint256 amount);\r
    event Released(\r
        address indexed sender,\r
        address indexed recipient,\r
        uint256 amount\r
    );\r
    event Minted(\r
        address indexed sender,\r
        address indexed recipient,\r
        uint256 amount\r
    );\r
    event ChainAdded(\r
        uint64 remoteChainSelector,\r
        bytes remoteToken,\r
        RateLimiter.Config outboundRateLimiterConfig,\r
        RateLimiter.Config inboundRateLimiterConfig\r
    );\r
    event ChainConfigured(\r
        uint64 remoteChainSelector,\r
        RateLimiter.Config outboundRateLimiterConfig,\r
        RateLimiter.Config inboundRateLimiterConfig\r
    );\r
    event ChainRemoved(uint64 remoteChainSelector);\r
    event RemotePoolAdded(\r
        uint64 indexed remoteChainSelector,\r
        bytes remotePoolAddress\r
    );\r
    event RemotePoolRemoved(\r
        uint64 indexed remoteChainSelector,\r
        bytes remotePoolAddress\r
    );\r
    event AllowListAdd(address sender);\r
    event AllowListRemove(address sender);\r
    event RouterUpdated(address oldRouter, address newRouter);\r
    event RateLimitAdminSet(address rateLimitAdmin);\r
\r
    struct ChainUpdate {\r
        uint64 remoteChainSelector; // Remote chain selector\r
        bytes[] remotePoolAddresses; // Address of the remote pool, ABI encoded in the case of a remote EVM chain.\r
        bytes remoteTokenAddress; // Address of the remote token, ABI encoded in the case of a remote EVM chain.\r
        RateLimiter.Config outboundRateLimiterConfig; // Outbound rate limited config, meaning the rate limits for all of the onRamps for the given chain\r
        RateLimiter.Config inboundRateLimiterConfig; // Inbound rate limited config, meaning the rate limits for all of the offRamps for the given chain\r
    }\r
\r
    struct RemoteChainConfig {\r
        RateLimiter.TokenBucket outboundRateLimiterConfig; // Outbound rate limited config, meaning the rate limits for all of the onRamps for the given chain\r
        RateLimiter.TokenBucket inboundRateLimiterConfig; // Inbound rate limited config, meaning the rate limits for all of the offRamps for the given chain\r
        bytes remoteTokenAddress; // Address of the remote token, ABI encoded in the case of a remote EVM chain.\r
        EnumerableSet.Bytes32Set remotePools; // Set of remote pool hashes, ABI encoded in the case of a remote EVM chain.\r
    }\r
\r
    /// @dev The bridgeable token that is managed by this pool. Pools could support multiple tokens at the same time if\r
    /// required, but this implementation only supports one token.\r
    IERC20 internal immutable i_token;\r
    /// @dev The number of decimals of the token managed by this pool.\r
    uint8 internal immutable i_tokenDecimals;\r
    /// @dev The address of the RMN proxy\r
    address internal immutable i_rmnProxy;\r
    /// @dev The immutable flag that indicates if the pool is access-controlled.\r
    bool internal immutable i_allowlistEnabled;\r
    /// @dev A set of addresses allowed to trigger lockOrBurn as original senders.\r
    /// Only takes effect if i_allowlistEnabled is true.\r
    /// This can be used to ensure only token-issuer specified addresses can move tokens.\r
    EnumerableSet.AddressSet internal s_allowlist;\r
    /// @dev The address of the router\r
    IRouter internal s_router;\r
    /// @dev A set of allowed chain selectors. We want the allowlist to be enumerable to\r
    /// be able to quickly determine (without parsing logs) who can access the pool.\r
    /// @dev The chain selectors are in uint256 format because of the EnumerableSet implementation.\r
    EnumerableSet.UintSet internal s_remoteChainSelectors;\r
    mapping(uint64 remoteChainSelector => RemoteChainConfig)\r
        internal s_remoteChainConfigs;\r
    /// @notice A mapping of hashed pool addresses to their unhashed form. This is used to be able to find the actually\r
    /// configured pools and not just their hashed versions.\r
    mapping(bytes32 poolAddressHash => bytes poolAddress)\r
        internal s_remotePoolAddresses;\r
    /// @notice The address of the rate limiter admin.\r
    /// @dev Can be address(0) if none is configured.\r
    address internal s_rateLimitAdmin;\r
\r
    constructor(\r
        IERC20 token,\r
        uint8 localTokenDecimals,\r
        address[] memory allowlist,\r
        address rmnProxy,\r
        address router\r
    ) {\r
        if (\r
            address(token) == address(0) ||\r
            router == address(0) ||\r
            rmnProxy == address(0)\r
        ) revert ZeroAddressNotAllowed();\r
        i_token = token;\r
        i_rmnProxy = rmnProxy;\r
\r
        try IERC20Metadata(address(token)).decimals() returns (\r
            uint8 actualTokenDecimals\r
        ) {\r
            if (localTokenDecimals != actualTokenDecimals) {\r
                revert InvalidDecimalArgs(\r
                    localTokenDecimals,\r
                    actualTokenDecimals\r
                );\r
            }\r
        } catch {\r
            // The decimals function doesn't exist, which is possible since it's optional in the ERC20 spec. We skip the check and\r
            // assume the supplied token decimals are correct.\r
        }\r
        i_tokenDecimals = localTokenDecimals;\r
\r
        s_router = IRouter(router);\r
\r
        // Pool can be set as permissioned or permissionless at deployment time only to save hot-path gas.\r
        i_allowlistEnabled = allowlist.length > 0;\r
        if (i_allowlistEnabled) {\r
            _applyAllowListUpdates(new address[](0), allowlist);\r
        }\r
    }\r
\r
    /// @inheritdoc IPoolV1\r
    function isSupportedToken(\r
        address token\r
    ) public view virtual returns (bool) {\r
        return token == address(i_token);\r
    }\r
\r
    /// @notice Gets the IERC20 token that this pool can lock or burn.\r
    /// @return token The IERC20 token representation.\r
    function getToken() public view returns (IERC20 token) {\r
        return i_token;\r
    }\r
\r
    /// @notice Get RMN proxy address\r
    /// @return rmnProxy Address of RMN proxy\r
    function getRmnProxy() public view returns (address rmnProxy) {\r
        return i_rmnProxy;\r
    }\r
\r
    /// @notice Gets the pool's Router\r
    /// @return router The pool's Router\r
    function getRouter() public view returns (address router) {\r
        return address(s_router);\r
    }\r
\r
    /// @notice Sets the pool's Router\r
    /// @param newRouter The new Router\r
    function setRouter(address newRouter) public onlyOwner {\r
        if (newRouter == address(0)) revert ZeroAddressNotAllowed();\r
        address oldRouter = address(s_router);\r
        s_router = IRouter(newRouter);\r
\r
        emit RouterUpdated(oldRouter, newRouter);\r
    }\r
\r
    /// @notice Signals which version of the pool interface is supported\r
    function supportsInterface(\r
        bytes4 interfaceId\r
    ) public pure virtual override returns (bool) {\r
        return\r
            interfaceId == Pool.CCIP_POOL_V1 ||\r
            interfaceId == type(IPoolV1).interfaceId ||\r
            interfaceId == type(IERC165).interfaceId;\r
    }\r
\r
    // ================================================================\r
    // │                         Validation                           │\r
    // ================================================================\r
\r
    /// @notice Validates the lock or burn input for correctness on\r
    /// - token to be locked or burned\r
    /// - RMN curse status\r
    /// - allowlist status\r
    /// - if the sender is a valid onRamp\r
    /// - rate limit status\r
    /// @param lockOrBurnIn The input to validate.\r
    /// @dev This function should always be called before executing a lock or burn. Not doing so would allow\r
    /// for various exploits.\r
    function _validateLockOrBurn(\r
        Pool.LockOrBurnInV1 calldata lockOrBurnIn\r
    ) internal {\r
        if (!isSupportedToken(lockOrBurnIn.localToken))\r
            revert InvalidToken(lockOrBurnIn.localToken);\r
        if (\r
            IRMN(i_rmnProxy).isCursed(\r
                bytes16(uint128(lockOrBurnIn.remoteChainSelector))\r
            )\r
        ) revert CursedByRMN();\r
        _checkAllowList(lockOrBurnIn.originalSender);\r
\r
        _onlyOnRamp(lockOrBurnIn.remoteChainSelector);\r
        _consumeOutboundRateLimit(\r
            lockOrBurnIn.remoteChainSelector,\r
            lockOrBurnIn.amount\r
        );\r
    }\r
\r
    /// @notice Validates the release or mint input for correctness on\r
    /// - token to be released or minted\r
    /// - RMN curse status\r
    /// - if the sender is a valid offRamp\r
    /// - if the source pool is valid\r
    /// - rate limit status\r
    /// @param releaseOrMintIn The input to validate.\r
    /// @dev This function should always be called before executing a release or mint. Not doing so would allow\r
    /// for various exploits.\r
    function _validateReleaseOrMint(\r
        Pool.ReleaseOrMintInV1 calldata releaseOrMintIn\r
    ) internal {\r
        if (!isSupportedToken(releaseOrMintIn.localToken))\r
            revert InvalidToken(releaseOrMintIn.localToken);\r
        if (\r
            IRMN(i_rmnProxy).isCursed(\r
                bytes16(uint128(releaseOrMintIn.remoteChainSelector))\r
            )\r
        ) revert CursedByRMN();\r
        _onlyOffRamp(releaseOrMintIn.remoteChainSelector);\r
\r
        // Validates that the source pool address is configured on this pool.\r
        if (\r
            !isRemotePool(\r
                releaseOrMintIn.remoteChainSelector,\r
                releaseOrMintIn.sourcePoolAddress\r
            )\r
        ) {\r
            revert InvalidSourcePoolAddress(releaseOrMintIn.sourcePoolAddress);\r
        }\r
\r
        _consumeInboundRateLimit(\r
            releaseOrMintIn.remoteChainSelector,\r
            releaseOrMintIn.amount\r
        );\r
    }\r
\r
    // ================================================================\r
    // │                      Token decimals                          │\r
    // ================================================================\r
\r
    /// @notice Gets the IERC20 token decimals on the local chain.\r
    function getTokenDecimals() public view virtual returns (uint8 decimals) {\r
        return i_tokenDecimals;\r
    }\r
\r
    function _encodeLocalDecimals()\r
        internal\r
        view\r
        virtual\r
        returns (bytes memory)\r
    {\r
        return abi.encode(i_tokenDecimals);\r
    }\r
\r
    function _parseRemoteDecimals(\r
        bytes memory sourcePoolData\r
    ) internal view virtual returns (uint8) {\r
        // Fallback to the local token decimals if the source pool data is empty. This allows for backwards compatibility.\r
        if (sourcePoolData.length == 0) {\r
            return i_tokenDecimals;\r
        }\r
        if (sourcePoolData.length != 32) {\r
            revert InvalidRemoteChainDecimals(sourcePoolData);\r
        }\r
        uint256 remoteDecimals = abi.decode(sourcePoolData, (uint256));\r
        if (remoteDecimals > type(uint8).max) {\r
            revert InvalidRemoteChainDecimals(sourcePoolData);\r
        }\r
        return uint8(remoteDecimals);\r
    }\r
\r
    /// @notice Calculates the local amount based on the remote amount and decimals.\r
    /// @param remoteAmount The amount on the remote chain.\r
    /// @param remoteDecimals The decimals of the token on the remote chain.\r
    /// @return The local amount.\r
    /// @dev This function protects against overflows. If there is a transaction that hits the overflow check, it is\r
    /// probably incorrect as that means the amount cannot be represented on this chain. If the local decimals have been\r
    /// wrongly configured, the token issuer could redeploy the pool with the correct decimals and manually re-execute the\r
    /// CCIP tx to fix the issue.\r
    function _calculateLocalAmount(\r
        uint256 remoteAmount,\r
        uint8 remoteDecimals\r
    ) internal view virtual returns (uint256) {\r
        if (remoteDecimals == i_tokenDecimals) {\r
            return remoteAmount;\r
        }\r
        if (remoteDecimals > i_tokenDecimals) {\r
            uint8 decimalsDiff = remoteDecimals - i_tokenDecimals;\r
            if (decimalsDiff > 77) {\r
                // This is a safety check to prevent overflow in the next calculation.\r
                revert OverflowDetected(\r
                    remoteDecimals,\r
                    i_tokenDecimals,\r
                    remoteAmount\r
                );\r
            }\r
            // Solidity rounds down so there is no risk of minting more tokens than the remote chain sent.\r
            return remoteAmount / (10 ** decimalsDiff);\r
        }\r
\r
        // This is a safety check to prevent overflow in the next calculation.\r
        // More than 77 would never fit in a uint256 and would cause an overflow. We also check if the resulting amount\r
        // would overflow.\r
        uint8 diffDecimals = i_tokenDecimals - remoteDecimals;\r
        if (\r
            diffDecimals > 77 ||\r
            remoteAmount > type(uint256).max / (10 ** diffDecimals)\r
        ) {\r
            revert OverflowDetected(\r
                remoteDecimals,\r
                i_tokenDecimals,\r
                remoteAmount\r
            );\r
        }\r
\r
        return remoteAmount * (10 ** diffDecimals);\r
    }\r
\r
    // ================================================================\r
    // │                     Chain permissions                        │\r
    // ================================================================\r
\r
    /// @notice Gets the pool address on the remote chain.\r
    /// @param remoteChainSelector Remote chain selector.\r
    /// @dev To support non-evm chains, this value is encoded into bytes\r
    function getRemotePools(\r
        uint64 remoteChainSelector\r
    ) public view returns (bytes[] memory) {\r
        bytes32[] memory remotePoolHashes = s_remoteChainConfigs[\r
            remoteChainSelector\r
        ].remotePools.values();\r
\r
        bytes[] memory remotePools = new bytes[](remotePoolHashes.length);\r
        for (uint256 i = 0; i < remotePoolHashes.length; ++i) {\r
            remotePools[i] = s_remotePoolAddresses[remotePoolHashes[i]];\r
        }\r
\r
        return remotePools;\r
    }\r
\r
    /// @notice Checks if the pool address is configured on the remote chain.\r
    /// @param remoteChainSelector Remote chain selector.\r
    /// @param remotePoolAddress The address of the remote pool.\r
    function isRemotePool(\r
        uint64 remoteChainSelector,\r
        bytes calldata remotePoolAddress\r
    ) public view returns (bool) {\r
        return\r
            s_remoteChainConfigs[remoteChainSelector].remotePools.contains(\r
                keccak256(remotePoolAddress)\r
            );\r
    }\r
\r
    /// @notice Gets the token address on the remote chain.\r
    /// @param remoteChainSelector Remote chain selector.\r
    /// @dev To support non-evm chains, this value is encoded into bytes\r
    function getRemoteToken(\r
        uint64 remoteChainSelector\r
    ) public view returns (bytes memory) {\r
        return s_remoteChainConfigs[remoteChainSelector].remoteTokenAddress;\r
    }\r
\r
    /// @notice Adds a remote pool for a given chain selector. This could be due to a pool being upgraded on the remote\r
    /// chain. We don't simply want to replace the old pool as there could still be valid inflight messages from the old\r
    /// pool. This function allows for multiple pools to be added for a single chain selector.\r
    /// @param remoteChainSelector The remote chain selector for which the remote pool address is being added.\r
    /// @param remotePoolAddress The address of the new remote pool.\r
    function addRemotePool(\r
        uint64 remoteChainSelector,\r
        bytes calldata remotePoolAddress\r
    ) external onlyOwner {\r
        if (!isSupportedChain(remoteChainSelector))\r
            revert NonExistentChain(remoteChainSelector);\r
\r
        _setRemotePool(remoteChainSelector, remotePoolAddress);\r
    }\r
\r
    /// @notice Removes the remote pool address for a given chain selector.\r
    /// @dev All inflight txs from the remote pool will be rejected after it is removed. To ensure no loss of funds, there\r
    /// should be no inflight txs from the given pool.\r
    function removeRemotePool(\r
        uint64 remoteChainSelector,\r
        bytes calldata remotePoolAddress\r
    ) external onlyOwner {\r
        if (!isSupportedChain(remoteChainSelector))\r
            revert NonExistentChain(remoteChainSelector);\r
\r
        if (\r
            !s_remoteChainConfigs[remoteChainSelector].remotePools.remove(\r
                keccak256(remotePoolAddress)\r
            )\r
        ) {\r
            revert InvalidRemotePoolForChain(\r
                remoteChainSelector,\r
                remotePoolAddress\r
            );\r
        }\r
\r
        emit RemotePoolRemoved(remoteChainSelector, remotePoolAddress);\r
    }\r
\r
    /// @inheritdoc IPoolV1\r
    function isSupportedChain(\r
        uint64 remoteChainSelector\r
    ) public view returns (bool) {\r
        return s_remoteChainSelectors.contains(remoteChainSelector);\r
    }\r
\r
    /// @notice Get list of allowed chains\r
    /// @return list of chains.\r
    function getSupportedChains() public view returns (uint64[] memory) {\r
        uint256[] memory uint256ChainSelectors = s_remoteChainSelectors\r
            .values();\r
        uint64[] memory chainSelectors = new uint64[](\r
            uint256ChainSelectors.length\r
        );\r
        for (uint256 i = 0; i < uint256ChainSelectors.length; ++i) {\r
            chainSelectors[i] = uint64(uint256ChainSelectors[i]);\r
        }\r
\r
        return chainSelectors;\r
    }\r
\r
    /// @notice Sets the permissions for a list of chains selectors. Actual senders for these chains\r
    /// need to be allowed on the Router to interact with this pool.\r
    /// @param remoteChainSelectorsToRemove A list of chain selectors to remove.\r
    /// @param chainsToAdd A list of chains and their new permission status & rate limits. Rate limits\r
    /// are only used when the chain is being added through `allowed` being true.\r
    /// @dev Only callable by the owner\r
\r
    function applyChainUpdates(\r
        uint64[] calldata remoteChainSelectorsToRemove,\r
        ChainUpdate[] calldata chainsToAdd\r
    ) external virtual onlyOwner {\r
        for (uint256 i = 0; i < remoteChainSelectorsToRemove.length; ++i) {\r
            uint64 remoteChainSelectorToRemove = remoteChainSelectorsToRemove[\r
                i\r
            ];\r
            // If the chain doesn't exist, revert\r
            if (!s_remoteChainSelectors.remove(remoteChainSelectorToRemove)) {\r
                revert NonExistentChain(remoteChainSelectorToRemove);\r
            }\r
\r
            // Remove all remote pool hashes for the chain\r
            bytes32[] memory remotePools = s_remoteChainConfigs[\r
                remoteChainSelectorToRemove\r
            ].remotePools.values();\r
            for (uint256 j = 0; j < remotePools.length; ++j) {\r
                s_remoteChainConfigs[remoteChainSelectorToRemove]\r
                    .remotePools\r
                    .remove(remotePools[j]);\r
            }\r
\r
            delete s_remoteChainConfigs[remoteChainSelectorToRemove];\r
\r
            emit ChainRemoved(remoteChainSelectorToRemove);\r
        }\r
\r
        for (uint256 i = 0; i < chainsToAdd.length; ++i) {\r
            ChainUpdate memory newChain = chainsToAdd[i];\r
            RateLimiter._validateTokenBucketConfig(\r
                newChain.outboundRateLimiterConfig,\r
                false\r
            );\r
            RateLimiter._validateTokenBucketConfig(\r
                newChain.inboundRateLimiterConfig,\r
                false\r
            );\r
\r
            if (newChain.remoteTokenAddress.length == 0) {\r
                revert ZeroAddressNotAllowed();\r
            }\r
\r
            // If the chain already exists, revert\r
            if (!s_remoteChainSelectors.add(newChain.remoteChainSelector)) {\r
                revert ChainAlreadyExists(newChain.remoteChainSelector);\r
            }\r
\r
            RemoteChainConfig storage remoteChainConfig = s_remoteChainConfigs[\r
                newChain.remoteChainSelector\r
            ];\r
\r
            remoteChainConfig.outboundRateLimiterConfig = RateLimiter\r
                .TokenBucket({\r
                    rate: newChain.outboundRateLimiterConfig.rate,\r
                    capacity: newChain.outboundRateLimiterConfig.capacity,\r
                    tokens: newChain.outboundRateLimiterConfig.capacity,\r
                    lastUpdated: uint32(block.timestamp),\r
                    isEnabled: newChain.outboundRateLimiterConfig.isEnabled\r
                });\r
            remoteChainConfig.inboundRateLimiterConfig = RateLimiter\r
                .TokenBucket({\r
                    rate: newChain.inboundRateLimiterConfig.rate,\r
                    capacity: newChain.inboundRateLimiterConfig.capacity,\r
                    tokens: newChain.inboundRateLimiterConfig.capacity,\r
                    lastUpdated: uint32(block.timestamp),\r
                    isEnabled: newChain.inboundRateLimiterConfig.isEnabled\r
                });\r
            remoteChainConfig.remoteTokenAddress = newChain.remoteTokenAddress;\r
\r
            for (uint256 j = 0; j < newChain.remotePoolAddresses.length; ++j) {\r
                _setRemotePool(\r
                    newChain.remoteChainSelector,\r
                    newChain.remotePoolAddresses[j]\r
                );\r
            }\r
\r
            emit ChainAdded(\r
                newChain.remoteChainSelector,\r
                newChain.remoteTokenAddress,\r
                newChain.outboundRateLimiterConfig,\r
                newChain.inboundRateLimiterConfig\r
            );\r
        }\r
    }\r
\r
    /// @notice Adds a pool address to the allowed remote token pools for a particular chain.\r
    /// @param remoteChainSelector The remote chain selector for which the remote pool address is being added.\r
    /// @param remotePoolAddress The address of the new remote pool.\r
    function _setRemotePool(\r
        uint64 remoteChainSelector,\r
        bytes memory remotePoolAddress\r
    ) internal {\r
        if (remotePoolAddress.length == 0) {\r
            revert ZeroAddressNotAllowed();\r
        }\r
\r
        bytes32 poolHash = keccak256(remotePoolAddress);\r
\r
        // Check if the pool already exists.\r
        if (\r
            !s_remoteChainConfigs[remoteChainSelector].remotePools.add(poolHash)\r
        ) {\r
            revert PoolAlreadyAdded(remoteChainSelector, remotePoolAddress);\r
        }\r
\r
        // Add the pool to the mapping to be able to un-hash it later.\r
        s_remotePoolAddresses[poolHash] = remotePoolAddress;\r
\r
        emit RemotePoolAdded(remoteChainSelector, remotePoolAddress);\r
    }\r
\r
    // ================================================================\r
    // │                        Rate limiting                         │\r
    // ================================================================\r
\r
    /// @dev The inbound rate limits should be slightly higher than the outbound rate limits. This is because many chains\r
    /// finalize blocks in batches. CCIP also commits messages in batches: the commit plugin bundles multiple messages in\r
    /// a single merkle root.\r
    /// Imagine the following scenario.\r
    /// - Chain A has an inbound and outbound rate limit of 100 tokens capacity and 1 token per second refill rate.\r
    /// - Chain B has an inbound and outbound rate limit of 100 tokens capacity and 1 token per second refill rate.\r
    ///\r
    /// At time 0:\r
    /// - Chain A sends 100 tokens to Chain B.\r
    /// At time 5:\r
    /// - Chain A sends 5 tokens to Chain B.\r
    /// At time 6:\r
    /// The epoch that contains blocks [0-5] is finalized.\r
    /// Both transactions will be included in the same merkle root and become executable at the same time. This means\r
    /// the token pool on chain B requires a capacity of 105 to successfully execute both messages at the same time.\r
    /// The exact additional capacity required depends on the refill rate and the size of the source chain epochs and the\r
    /// CCIP round time. For simplicity, a 5-10% buffer should be sufficient in most cases.\r
\r
    /// @notice Sets the rate limiter admin address.\r
    /// @dev Only callable by the owner.\r
    /// @param rateLimitAdmin The new rate limiter admin address.\r
    function setRateLimitAdmin(address rateLimitAdmin) external onlyOwner {\r
        s_rateLimitAdmin = rateLimitAdmin;\r
        emit RateLimitAdminSet(rateLimitAdmin);\r
    }\r
\r
    /// @notice Gets the rate limiter admin address.\r
    function getRateLimitAdmin() external view returns (address) {\r
        return s_rateLimitAdmin;\r
    }\r
\r
    /// @notice Consumes outbound rate limiting capacity in this pool\r
    function _consumeOutboundRateLimit(\r
        uint64 remoteChainSelector,\r
        uint256 amount\r
    ) internal {\r
        s_remoteChainConfigs[remoteChainSelector]\r
            .outboundRateLimiterConfig\r
            ._consume(amount, address(i_token));\r
    }\r
\r
    /// @notice Consumes inbound rate limiting capacity in this pool\r
    function _consumeInboundRateLimit(\r
        uint64 remoteChainSelector,\r
        uint256 amount\r
    ) internal {\r
        s_remoteChainConfigs[remoteChainSelector]\r
            .inboundRateLimiterConfig\r
            ._consume(amount, address(i_token));\r
    }\r
\r
    /// @notice Gets the token bucket with its values for the block it was requested at.\r
    /// @return The token bucket.\r
    function getCurrentOutboundRateLimiterState(\r
        uint64 remoteChainSelector\r
    ) external view returns (RateLimiter.TokenBucket memory) {\r
        return\r
            s_remoteChainConfigs[remoteChainSelector]\r
                .outboundRateLimiterConfig\r
                ._currentTokenBucketState();\r
    }\r
\r
    /// @notice Gets the token bucket with its values for the block it was requested at.\r
    /// @return The token bucket.\r
    function getCurrentInboundRateLimiterState(\r
        uint64 remoteChainSelector\r
    ) external view returns (RateLimiter.TokenBucket memory) {\r
        return\r
            s_remoteChainConfigs[remoteChainSelector]\r
                .inboundRateLimiterConfig\r
                ._currentTokenBucketState();\r
    }\r
\r
    /// @notice Sets the chain rate limiter config.\r
    /// @param remoteChainSelector The remote chain selector for which the rate limits apply.\r
    /// @param outboundConfig The new outbound rate limiter config, meaning the onRamp rate limits for the given chain.\r
    /// @param inboundConfig The new inbound rate limiter config, meaning the offRamp rate limits for the given chain.\r
    function setChainRateLimiterConfig(\r
        uint64 remoteChainSelector,\r
        RateLimiter.Config memory outboundConfig,\r
        RateLimiter.Config memory inboundConfig\r
    ) external {\r
        if (msg.sender != s_rateLimitAdmin && msg.sender != owner())\r
            revert Unauthorized(msg.sender);\r
\r
        _setRateLimitConfig(remoteChainSelector, outboundConfig, inboundConfig);\r
    }\r
\r
    function _setRateLimitConfig(\r
        uint64 remoteChainSelector,\r
        RateLimiter.Config memory outboundConfig,\r
        RateLimiter.Config memory inboundConfig\r
    ) internal {\r
        if (!isSupportedChain(remoteChainSelector))\r
            revert NonExistentChain(remoteChainSelector);\r
        RateLimiter._validateTokenBucketConfig(outboundConfig, false);\r
        s_remoteChainConfigs[remoteChainSelector]\r
            .outboundRateLimiterConfig\r
            ._setTokenBucketConfig(outboundConfig);\r
        RateLimiter._validateTokenBucketConfig(inboundConfig, false);\r
        s_remoteChainConfigs[remoteChainSelector]\r
            .inboundRateLimiterConfig\r
            ._setTokenBucketConfig(inboundConfig);\r
        emit ChainConfigured(\r
            remoteChainSelector,\r
            outboundConfig,\r
            inboundConfig\r
        );\r
    }\r
\r
    // ================================================================\r
    // │                           Access                             │\r
    // ================================================================\r
\r
    /// @notice Checks whether remote chain selector is configured on this contract, and if the msg.sender\r
    /// is a permissioned onRamp for the given chain on the Router.\r
    function _onlyOnRamp(uint64 remoteChainSelector) internal view {\r
        if (!isSupportedChain(remoteChainSelector))\r
            revert ChainNotAllowed(remoteChainSelector);\r
        if (!(msg.sender == s_router.getOnRamp(remoteChainSelector)))\r
            revert CallerIsNotARampOnRouter(msg.sender);\r
    }\r
\r
    /// @notice Checks whether remote chain selector is configured on this contract, and if the msg.sender\r
    /// is a permissioned offRamp for the given chain on the Router.\r
    function _onlyOffRamp(uint64 remoteChainSelector) internal view {\r
        if (!isSupportedChain(remoteChainSelector))\r
            revert ChainNotAllowed(remoteChainSelector);\r
        if (!s_router.isOffRamp(remoteChainSelector, msg.sender))\r
            revert CallerIsNotARampOnRouter(msg.sender);\r
    }\r
\r
    // ================================================================\r
    // │                          Allowlist                           │\r
    // ================================================================\r
\r
    function _checkAllowList(address sender) internal view {\r
        if (i_allowlistEnabled) {\r
            if (!s_allowlist.contains(sender)) {\r
                revert SenderNotAllowed(sender);\r
            }\r
        }\r
    }\r
\r
    /// @notice Gets whether the allowlist functionality is enabled.\r
    /// @return true is enabled, false if not.\r
    function getAllowListEnabled() external view returns (bool) {\r
        return i_allowlistEnabled;\r
    }\r
\r
    /// @notice Gets the allowed addresses.\r
    /// @return The allowed addresses.\r
    function getAllowList() external view returns (address[] memory) {\r
        return s_allowlist.values();\r
    }\r
\r
    /// @notice Apply updates to the allow list.\r
    /// @param removes The addresses to be removed.\r
    /// @param adds The addresses to be added.\r
    function applyAllowListUpdates(\r
        address[] calldata removes,\r
        address[] calldata adds\r
    ) external onlyOwner {\r
        _applyAllowListUpdates(removes, adds);\r
    }\r
\r
    /// @notice Internal version of applyAllowListUpdates to allow for reuse in the constructor.\r
    function _applyAllowListUpdates(\r
        address[] memory removes,\r
        address[] memory adds\r
    ) internal {\r
        if (!i_allowlistEnabled) revert AllowListNotEnabled();\r
\r
        for (uint256 i = 0; i < removes.length; ++i) {\r
            address toRemove = removes[i];\r
            if (s_allowlist.remove(toRemove)) {\r
                emit AllowListRemove(toRemove);\r
            }\r
        }\r
        for (uint256 i = 0; i < adds.length; ++i) {\r
            address toAdd = adds[i];\r
            if (toAdd == address(0)) {\r
                continue;\r
            }\r
            if (s_allowlist.add(toAdd)) {\r
                emit AllowListAdd(toAdd);\r
            }\r
        }\r
    }\r
}\r
"
    },
    "contracts/interface/IBurnMintERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.0;\r
// import {IERC20} from "./IERC20.sol";\r
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";\r
interface IBurnMintERC20 is IERC20 {\r
    /// @notice Mints new tokens for a given address.\r
    /// @param account The address to mint the new tokens to.\r
    /// @param amount The number of tokens to be minted.\r
    /// @dev this function increases the total supply.\r
    function mint(address account, uint256 amount) external;\r
\r
    /// @notice Burns tokens from the sender.\r
    /// @param amount The number of tokens to be burned.\r
    /// @dev this function decreases the total supply.\r
    function burn(uint256 amount) external;\r
\r
    /// @notice Burns tokens from a given address..\r
    /// @param account The address to burn tokens from.\r
    /// @param amount The number of tokens to be burned.\r
    /// @dev this function decreases the total supply.\r
    function burn(address account, uint256 amount) external;\r
\r
    /// @notice Burns tokens from a given address..\r
    /// @param account The address to burn tokens from.\r
    /// @param amount The number of tokens to be burned.\r
    /// @dev this function decreases the total supply.\r
    function burnFrom(address account, uint256 amount) external;\r
}"
    },
    "contracts/interface/IOwnable.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.0;\r
\r
interface IOwnable {\r
    function owner() external returns (address);\r
\r
    function transferOwnership(address recipient) external;\r
\r
    function acceptOwnership() external;\r
}\r
"
    },
    "contracts/interface/IPoolV1.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.0;\r
\r
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";\r
import {Pool} from "../library/Pool.sol";\r
/// @notice Shared public interface for multiple V1 pool types.\r
/// Each pool type handles a different child token model (lock/unlock, mint/burn.)\r
interface IPoolV1 is IERC165 {\r
    /// @notice Lock tokens into the pool or burn the tokens.\r
    /// @param lockOrBurnIn Encoded data fields for the processing of tokens on the source chain.\r
    /// @return lockOrBurnOut Encoded data fields for the processing of tokens on the destination chain.\r
    function lockOrBurn(\r
        Pool.LockOrBurnInV1 calldata lockOrBurnIn\r
    ) external returns (Pool.LockOrBurnOutV1 memory lockOrBurnOut);\r
\r
    /// @notice Releases or mints tokens to the receiver address.\r
    /// @param releaseOrMintIn All data required to release or mint tokens.\r
    /// @return releaseOrMintOut The amount of tokens released or minted on the local chain, denominated\r
    /// in the local token's decimals.\r
    /// @dev The offramp asserts that the balanceOf of the receiver has been incremented by exactly the number\r
    /// of tokens that is returned in ReleaseOrMintOutV1.destinationAmount. If the amounts do not match, the tx reverts.\r
    function releaseOrMint(\r
        Pool.ReleaseOrMintInV1 calldata releaseOrMintIn\r
    ) external returns (Pool.ReleaseOrMintOutV1 memory);\r
\r
    /// @notice Checks whether a remote chain is supported in the token pool.\r
    /// @param remoteChainSelector The selector of the remote chain.\r
    /// @return true if the given chain is a permissioned remote chain.\r
    function isSupportedChain(\r
        uint64 remoteChainSelector\r
    ) external view returns (bool);\r
\r
    /// @notice Returns if the token pool supports the given token.\r
    /// @param token The address of the token.\r
    /// @return true if the token is supported by the pool.\r
    function isSupportedToken(address token) external view returns (bool);\r
}\r
"
    },
    "contracts/interface/IRMN.sol": {
      "content": "\r
// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.0;\r
\r
/// @notice This interface contains the only RMN-related functions that might be used on-chain by other CCIP contracts.\r
interface IRMN {\r
    /// @notice A Merkle root tagged with the address of the commit store contract it is destined for.\r
    struct TaggedRoot {\r
        address commitStore;\r
        bytes32 root;\r
    }\r
\r
    /// @notice Callers MUST NOT cache the return value as a blessed tagged root could become unblessed.\r
    function isBlessed(\r
        TaggedRoot calldata taggedRoot\r
    ) external view returns (bool);\r
\r
    /// @notice Iff there is an active global or legacy curse, this function returns true.\r
    function isCursed() external view returns (bool);\r
\r
    /// @notice Iff there is an active global curse, or an active curse for `subject`, this function returns true.\r
    /// @param subject To check whether a particular chain is cursed, set to bytes16(uint128(chainSelector)).\r
    function isCursed(bytes16 subject) external view returns (bool);\r
}"
    },
    "contracts/interface/IRouter.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.0;\r
import {Client} from "../library/Client.sol";\r
interface IRouter {\r
    error OnlyOffRamp();\r
\r
    /// @notice Route the message to its intended receiver contract.\r
    /// @param message Client.Any2EVMMessage struct.\r
    /// @param gasForCallExactCheck of params for exec\r
    /// @param gasLimit set of params for exec\r
    /// @param receiver set of params for exec\r
    /// @dev if the receiver is a contracts that signals support for CCIP execution through EIP-165.\r
    /// the contract is called. If not, only tokens are transferred.\r
    /// @return success A boolean value indicating whether the ccip message was received without errors.\r
    /// @return retBytes A bytes array containing return data form CCIP receiver.\r
    /// @return gasUsed the gas used by the external customer call. Does not include any overhead.\r
    function routeMessage(\r
        Client.Any2EVMMessage calldata message,\r
        uint16 gasForCallExactCheck,\r
        uint256 gasLimit,\r
        address receiver\r
    ) external returns (bool success, bytes memory retBytes, uint256 gasUsed);\r
\r
    /// @notice Returns the configured onramp for a specific destination chain.\r
    /// @param destChainSelector The destination chain Id to get the onRamp for.\r
    /// @return onRampAddress The address of the onRamp.\r
    function getOnRamp(\r
        uint64 destChainSelector\r
    ) external view returns (address onRampAddress);\r
\r
    /// @notice Return true if the given offRamp is a configured offRamp for the given source chain.\r
    /// @param sourceChainSelector The source chain selector to check.\r
    /// @param offRamp The address of the offRamp to check.\r
    function isOffRamp(\r
        uint64 sourceChainSelector,\r
        address offRamp\r
    ) external view returns (bool isOffRamp);\r
}"
    },
    "contracts/interface/ITypeAndVersion.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.0;\r
\r
interface ITypeAndVersion {\r
    function typeAndVersion() external pure returns (string memory);\r
}"
    },
    "contracts/library/Client.sol": {
      "content": "\r
// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.0;\r
\r
// End consumer library.\r
library Client {\r
    /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\r
    struct EVMTokenAmount {\r
        address token; // token address on the local chain.\r
        uint256 amount; // Amount of tokens.\r
    }\r
\r
    struct Any2EVMMessage {\r
        bytes32 messageId; // MessageId corresponding to ccipSend on source.\r
        uint64 sourceChainSelector; // Source chain selector.\r
        bytes sender; // abi.decode(sender) if coming from an EVM chain.\r
        bytes data; // payload sent in original message.\r
        EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation.\r
    }\r
\r
    // If extraArgs is empty bytes, the default is 200k gas limit.\r
    struct EVM2AnyMessage {\r
        bytes receiver; // abi.encode(receiver address) for dest EVM chains\r
        bytes data; // Data payload\r
        EVMTokenAmount[] tokenAmounts; // Token transfers\r
        address feeToken; // Address of feeToken. address(0) means you will send msg.value.\r
        bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV2)\r
    }\r
\r
    // bytes4(keccak256("CCIP EVMExtraArgsV1"));\r
    bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;\r
\r
    struct EVMExtraArgsV1 {\r
        uint256 gasLimit;\r
    }\r
\r
    function _argsToBytes(\r
        EVMExtraArgsV1 memory extraArgs\r
    ) internal pure returns (bytes memory bts) {\r
        return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);\r
    }\r
\r
    // bytes4(keccak256("CCIP EVMExtraArgsV2"));\r
    bytes4 public constant EVM_EXTRA_ARGS_V2_TAG = 0x181dcf10;\r
\r
    /// @param gasLimit: gas limit for the callback on the destination chain.\r
    /// @param allowOutOfOrderExecution: if true, it indicates that the message can be executed in any order relative to other messages from the same sender.\r
    /// This value's default varies by chain. On some chains, a particular value is enforced, meaning if the expected value\r
    /// is not set, the message request will revert.\r
    struct EVMExtraArgsV2 {\r
        uint256 gasLimit;\r
        bool allowOutOfOrderExecution;\r
    }\r
\r
    function _argsToBytes(\r
        EVMExtraArgsV2 memory extraArgs\r
    ) internal pure returns (bytes memory bts) {\r
        return abi.encodeWithSelector(EVM_EXTRA_ARGS_V2_TAG, extraArgs);\r
    }\r
}\r
"
    },
    "contracts/library/EnumerableSet.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.20;\r
\r
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\r
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\r
\r
/**\r
 * @dev Library for managing\r
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\r
 * types.\r
 *\r
 * Sets have the following properties:\r
 *\r
 * - Elements are added, removed, and checked for existence in constant time\r
 * (O(1)).\r
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.\r
 *\r
 * ```solidity\r
 * contract Example {\r
 *     // Add the library methods\r
 *     using EnumerableSet for EnumerableSet.AddressSet;\r
 *\r
 *     // Declare a set state variable\r
 *     EnumerableSet.AddressSet private mySet;\r
 * }\r
 * ```\r
 *\r
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\r
 * and `uint256` (`UintSet`) are supported.\r
 *\r
 * [WARNING]\r
 * ====\r
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\r
 * unusable.\r
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\r
 *\r
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\r
 * array of EnumerableSet.\r
 * ====\r
 */\r
library EnumerableSet {\r
    // To implement this library for multiple types with as little code\r
    // repetition as possible, we write it in terms of a generic Set type with\r
    // bytes32 values.\r
    // The Set implementation uses private functions, and user-facing\r
    // implementations (such as AddressSet) are just wrappers around the\r
    // underlying Set.\r
    // This means that we can only create new EnumerableSets for types that fit\r
    // in bytes32.\r
\r
    struct Set {\r
        // Storage of set values\r
        bytes32[] _values;\r
        // Position is the index of the value in the `values` array plus 1.\r
        // Position 0 is used to mean a value is not in the set.\r
        mapping(bytes32 value => uint256) _positions;\r
    }\r
\r
    /**\r
     * @dev Add a value to a set. O(1).\r
     *\r
     * Returns true if the value was added to the set, that is if it was not\r
     * already present.\r
     */\r
    function _add(Set storage set, bytes32 value) private returns (bool) {\r
        if (!_contains(set, value)) {\r
            set._values.push(value);\r
            // The value is stored at length-1, but we add 1 to all indexes\r
            // and use 0 as a sentinel value\r
            set._positions[value] = set._values.length;\r
            return true;\r
        } else {\r
            return false;\r
        }\r
    }\r
\r
    /**\r
     * @dev Removes a value from a set. O(1).\r
     *\r
     * Returns true if the value was removed from the set, that is if it was\r
     * present.\r
     */\r
    function _remove(Set storage set, bytes32 value) private returns (bool) {\r
        // We cache the value's position to prevent multiple reads from the same storage slot\r
        uint256 position = set._positions[value];\r
\r
        if (position != 0) {\r
            // Equivalent to contains(set, value)\r
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\r
            // the array, and then remove the last element (sometimes called as 'swap and pop').\r
            // This modifies the order of the array, as noted in {at}.\r
\r
            uint256 valueIndex = position - 1;\r
            uint256 lastIndex = set._values.length - 1;\r
\r
            if (valueIndex != lastIndex) {\r
                bytes32 lastValue = set._values[lastIndex];\r
\r
                // Move the lastValue to the index where the value to delete is\r
                set._values[valueIndex] = lastValue;\r
                // Update the tracked position of the lastValue (that was just moved)\r
                set._positions[lastValue] = position;\r
            }\r
\r
            // Delete the slot where the moved value was stored\r
            set._values.pop();\r
\r
            // Delete the tracked position for the deleted slot\r
            delete set._positions[value];\r
\r
            return true;\r
        } else {\r
            return false;\r
        }\r
    }\r
\r
    /**\r
     * @dev Returns true if the value is in the set. O(1).\r
     */\r
    function _contains(\r
        Set storage set,\r
        bytes32 value\r
    ) private view returns (bool) {\r
        return set._positions[value] != 0;\r
    }\r
\r
    /**\r
     * @dev Returns the number of values on the set. O(1).\r
     */\r
    function _length(Set storage set) private view returns (uint256) {\r
        return set._values.length;\r
    }\r
\r
    /**\r
     * @dev Returns the value stored at position `index` in the set. O(1).\r
     *\r
     * Note that there are no guarantees on the ordering of values inside the\r
     * array, and it may change when more values are added or removed.\r
     *\r
     * Requirements:\r
     *\r
     * - `index` must be strictly less than {length}.\r
     */\r
    function _at(\r
        Set storage set,\r
        uint256 index\r
    ) private view returns (bytes32) {\r
        return set._values[index];\r
    }\r
\r
    /**\r
     * @dev Return the entire set in an array\r
     *\r
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\r
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\r
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\r
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\r
     */\r
    function _values(Set storage set) private view returns (bytes32[] memory) {\r
        return set._values;\r
    }\r
\r
    // Bytes32Set\r
\r
    struct Bytes32Set {\r
        Set _inner;\r
    }\r
\r
    /**\r
     * @dev Add a value to a set. O(1).\r
     *\r
     * Returns true if the value was added to the set, that is if it was not\r
     * already present.\r
     */\r
    function add(\r
        Bytes32Set storage set,\r
        bytes32 value\r
    ) internal returns (bool) {\r
        return _add(set._inner, value);\r
    }\r
\r
    /**\r
     * @dev Removes a value from a set. O(1).\r
     *\r
     * Returns true if the value was removed from the set, that is if it was\r
     * present.\r
     */\r
    function remove(\r
        Bytes32Set storage set,\r
        bytes32 value\r
    ) internal returns (bool) {\r
        return _remove(set._inner, value);\r
    }\r
\r
    /**\r
     * @dev Returns true if the value is in the set. O(1).\r
     */\r
    function contains(\r
        Bytes32Set storage set,\r
        bytes32 value\r
    ) internal view returns (bool) {\r
        return _contains(set._inner, value);\r
    }\r
\r
    /**\r
     * @dev Returns the number of values in the set. O(1).\r
     */\r
    function length(Bytes32Set storage set) internal view returns (uint256) {\r
        return _length(set._inner);\r
    }\r
\r
    /**\r
     * @dev Returns the value stored at position `index` in the set. O(1).\r
     *\r
     * Note that there are no guarantees on the ordering of values inside the\r
     * array, and it may change when more values are added or removed.\r
     *\r
     * Requirements:\r
     *\r
     * - `index` must be strictly less than {length}.\r
     */\r
    function at(\r
        Bytes32Set storage set,\r
        uint256 index\r
    ) internal view returns (bytes32) {\r
        return _at(set._inner, index);\r
    }\r
\r
    /**\r
     * @dev Return the entire set in an array\r
     *\r
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\r
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\r
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\r
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\r
     */\r
    function values(\r
        Bytes32Set storage set\r
    ) internal view returns (bytes32[] me

Tags:
ERC20, ERC165, Multisig, Mintable, Burnable, Swap, Upgradeable, Multi-Signature, Factory|addr:0xb503be040deb89fb5f169693bcd756d63ac31aa1|verified:true|block:23668182|tx:0x971c3fa246dbc521d48584a12a4ac14c8e540709774671f5dca02135dc4ff0b1|first_check:1761567280

Submitted on: 2025-10-27 13:14:41

Comments

Log in to comment.

No comments yet.