{"file_path":"contracts/fusd/FUSDGateway.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {IFUSD} from \"../interfaces/IFUSD.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {AccessControlEnumerableUpgradeable} from\n    \"@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol\";\nimport {PausableUpgradeable} from \"@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol\";\nimport {ReentrancyGuardUpgradeable} from \"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {IFUSDGateway} from \"../interfaces/IFUSDGateway.sol\";\nimport {IKycModule} from \"../interfaces/IKycModule.sol\";\nimport {IFUSDLP} from \"../interfaces/IFUSDLP.sol\";\nimport {TokenDecimalsConvert} from \"../utils/TokenDecimalsConvert.sol\";\nimport {ITokenBridgeSender} from \"../interfaces/ITokenBridgeSender.sol\";\nimport {AddressConvert} from \"../utils/AddressConvert.sol\";\nimport {BitMaps} from \"@openzeppelin/contracts/utils/structs/BitMaps.sol\";\n\n/**\n * @title FUSDGateway\n * @notice Gateway contract for minting and redeeming FUSD tokens with collateral assets\n * @dev Handles both instant operations and manual requests for FUSD minting/burning\n * @author Finchain Team\n */\ncontract FUSDGateway is\n    IFUSDGateway,\n    AccessControlEnumerableUpgradeable,\n    PausableUpgradeable,\n    ReentrancyGuardUpgradeable\n{\n    using SafeERC20 for IERC20;\n    using Math for uint256;\n    using TokenDecimalsConvert for uint256;\n    using BitMaps for BitMaps.BitMap;\n\n    /// @dev Storage structure for FUSDGateway contract using ERC7201 pattern\n    /// @custom:storage-location erc7201:finchain.storage.FUSDGateway\n    struct FUSDGatewayStorage {\n        /// @dev FUSD token contract address\n        address fusd;\n        /// @dev FUSDLP collateral token contract address\n        address lp;\n        /// @dev Treasury address for storing collateral\n        address treasury;\n        /// @dev KYC module contract address\n        address kycModule;\n        /// @dev Fee rate for minting operations (basis points)\n        uint256 mintFeeRate;\n        /// @dev Fee rate for redemption operations (basis points)\n        uint256 redeemFeeRate;\n        /// @dev Address to receive collected fees\n        address feeTo;\n        address bridgeSender;\n        BitMaps.BitMap usedCustomMessageIds;\n    }\n\n    /// @dev Storage slot for FUSDGateway data using ERC7201 pattern\n    // keccak256(abi.encode(uint256(keccak256(\"finchain.storage.FUSDGateway\")) - 1)) & ~bytes32(uint256(0xff))\n    // OK\n    bytes32 internal constant FUSDGatewayStorageLocation =\n        0xe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600;\n\n    /// @dev Base decimals constant for calculations (18 decimals)\n    uint256 internal constant _BASE_DECIMALS = 1e18;\n\n    uint256 internal constant _MAX_FEE_RATE = 1e16; // 1%\n\n    /// @dev Role identifier for minting permissions\n    bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n    /// @dev Role identifier for pausing permissions\n    bytes32 public constant PAUSER_ROLE = keccak256(\"PAUSER_ROLE\");\n\n    /**\n     * @notice Gets the FUSDGateway storage struct\n     * @dev Uses ERC7201 storage pattern for upgradeable contracts\n     * @return $ Reference to the FUSDGateway storage struct\n     */\n    function _getFUSDGatewayStorage() internal pure returns (FUSDGatewayStorage storage $) {\n        bytes32 position = FUSDGatewayStorageLocation;\n        assembly {\n            $.slot := position\n        }\n    }\n\n    /**\n     * @dev Callback function for receiving native tokens.\n     */\n    receive() external payable {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        if (msg.sender != $.bridgeSender) {\n            revert InvalidNativeTokenSender();\n        }\n    }\n\n    /// @custom:oz-upgrades-unsafe-allow constructor\n    constructor() {\n        _disableInitializers();\n    }\n\n    /**\n     * @notice Initializes the FUSDGateway contract\n     * @dev Sets up all necessary addresses and parameters\n     * @param _fusd Address of the FUSD token contract\n     * @param _lp Address of the FUSDLP collateral contract\n     * @param _treasury Address of the treasury for storing collateral\n     * @param _kycModule Address of the KYC module contract\n     * @param _mintFeeRate Fee rate for minting operations (basis points)\n     * @param _redeemFeeRate Fee rate for redemption operations (basis points)\n     * @param _feeTo Address to receive collected fees\n     * @param admin Address to be granted DEFAULT_ADMIN_ROLE\n     */\n    function initialize(\n        address _fusd,\n        address _lp,\n        address _treasury,\n        address _kycModule,\n        uint256 _mintFeeRate,\n        uint256 _redeemFeeRate,\n        address _feeTo,\n        address _bridgeSender,\n        address admin\n    ) external initializer {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        __AccessControlEnumerable_init();\n        __Pausable_init();\n        __ReentrancyGuard_init();\n        $.fusd = _fusd;\n        $.lp = _lp;\n        $.treasury = _treasury;\n        $.kycModule = _kycModule;\n        _checkFeeRate(_mintFeeRate);\n        _checkFeeRate(_redeemFeeRate);\n        $.mintFeeRate = _mintFeeRate;\n        $.redeemFeeRate = _redeemFeeRate;\n        $.feeTo = _feeTo;\n        $.bridgeSender = _bridgeSender;\n        _grantRole(DEFAULT_ADMIN_ROLE, admin);\n    }\n\n    /**\n     * @notice Direct mint function for project operations\n     * @dev Only callable by accounts with DEFAULT_ADMIN_ROLE when not paused\n     * @param toBytes32 Address to receive minted FUSD tokens(bytes32 format for cross-chain)\n     * @param amount Amount of FUSD tokens to mint (18 decimals)\n     *     _grantRole(DEFAULT_ADMIN_ROLE, admin);\n     * @param destinationChainIdOrSelector Target chain ID or selector for cross-chain operations\n     */\n    function mint(bytes32 toBytes32, uint256 amount, uint64 destinationChainIdOrSelector)\n        external\n        payable\n        whenNotPaused\n        onlyRole(DEFAULT_ADMIN_ROLE)\n        returns (bytes32 messageId)\n    {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        if (destinationChainIdOrSelector == 0) {\n            address to = AddressConvert.convertBytes32ToEVMAddress(toBytes32);\n            IFUSD($.fusd).mint(to, amount);\n        } else {\n            // First mint to the current contract\n            IFUSD($.fusd).mint(address(this), amount);\n            // Approve\n            IERC20($.fusd).approve($.bridgeSender, amount);\n            // Then send to the destination chain via the bridge contract\n            messageId = ITokenBridgeSender($.bridgeSender).send{value: msg.value}(\n                destinationChainIdOrSelector, toBytes32, $.fusd, amount, ITokenBridgeSender.PayFeesIn.Native\n            );\n        }\n        _refundNativeToken(address(this).balance);\n        emit DirectMint(toBytes32, amount, destinationChainIdOrSelector);\n        return messageId;\n    }\n\n    /**\n     * @notice Direct burn function for project operations\n     * @dev Only callable by accounts with DEFAULT_ADMIN_ROLE when not paused\n     * @param amount Amount of FUSD tokens to burn (18 decimals)\n     */\n    function burn(uint256 amount) public whenNotPaused onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        IERC20($.fusd).safeTransferFrom(msg.sender, address(this), amount);\n        IFUSD($.fusd).burn(amount);\n        emit DirectBurn(msg.sender, amount);\n    }\n\n    function mintWithMessageId(bytes32 customMessageIdBytes32, address to, uint256 amount)\n        external\n        whenNotPaused\n        onlyRole(MINTER_ROLE)\n    {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        _consumeCustomMessageId(uint256(customMessageIdBytes32));\n        IFUSD($.fusd).mint(to, amount);\n        emit MintWithCustomMessageId(customMessageIdBytes32, to, amount);\n    }\n\n    /**\n     * @notice Manual redemption request by users\n     * @dev Burns FUSD tokens and emits event for manual processing by project team\n     * @param amount Amount of FUSD tokens to redeem (18 decimals)\n     */\n    function redeemRequest(uint256 amount) external whenNotPaused nonReentrant {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        if (amount == 0) {\n            revert RedeemAmountIsZero();\n        }\n        IKycModule($.kycModule).validateAddress(msg.sender);\n        IERC20($.fusd).safeTransferFrom(msg.sender, address(this), amount);\n        IFUSD($.fusd).burn(amount);\n        emit RedeemRequested(msg.sender, amount);\n    }\n\n    /**\n     * @notice Instant mint FUSD using FUSDLP collateral\n     * @dev Transfers collateral to treasury and mints FUSD to user after deducting fees\n     * @param toBytes32 Address to receive minted FUSD tokens(bytes32 format for cross-chain)\n     * @param collateral Address of the collateral asset (must be FUSDLP)\n     * @param collateralAmount Amount of collateral asset (18 decimals)\n     * @param destinationChainIdOrSelector Target chain ID or selector for cross-chain operations\n     */\n    function instantMint(\n        bytes32 toBytes32,\n        address collateral,\n        uint256 collateralAmount,\n        uint64 destinationChainIdOrSelector\n    ) external payable whenNotPaused nonReentrant returns (bytes32 messageId) {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        IKycModule($.kycModule).validateAddress(msg.sender);\n        (uint256 mintFUSDAmount, uint256 netCollateralAmount, uint256 feeInCollateral) =\n            previewMint(collateral, collateralAmount);\n        // Collect fee in FUSDLP\n        if (feeInCollateral > 0) {\n            IERC20(collateral).safeTransferFrom(msg.sender, $.feeTo, feeInCollateral.from18Decimals(collateral));\n        }\n        IERC20(collateral).safeTransferFrom(msg.sender, $.treasury, netCollateralAmount.from18Decimals(collateral));\n        if (destinationChainIdOrSelector == 0) {\n            // Mint FUSD\n            address user = AddressConvert.convertBytes32ToEVMAddress(toBytes32);\n            IFUSD($.fusd).mint(user, mintFUSDAmount);\n        } else {\n            IFUSD($.fusd).mint(address(this), mintFUSDAmount);\n            // Approve\n            IERC20($.fusd).approve($.bridgeSender, mintFUSDAmount);\n            // Then send to the destination chain via the bridge contract\n            messageId = ITokenBridgeSender($.bridgeSender).send{value: msg.value}(\n                destinationChainIdOrSelector, toBytes32, $.fusd, mintFUSDAmount, ITokenBridgeSender.PayFeesIn.Native\n            );\n        }\n        _refundNativeToken(address(this).balance);\n\n        emit InstantMint(\n            msg.sender,\n            toBytes32,\n            collateral,\n            collateralAmount,\n            mintFUSDAmount,\n            feeInCollateral,\n            destinationChainIdOrSelector\n        );\n    }\n\n    /**\n     * @notice Instant redeem FUSDLP using FUSD\n     * @dev Burns FUSD from user and transfers collateral asset from treasury\n     * @param toBytes32 Address to receive redeemed collateral asset\n     * @param redeemCollateral Address of the collateral asset to redeem\n     * @param FUSDAmountToBurn Amount of FUSD tokens to redeem (18 decimals)\n     */\n    function instantRedeem(bytes32 toBytes32, address redeemCollateral, uint256 FUSDAmountToBurn)\n        external\n        whenNotPaused\n        nonReentrant\n    {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        address user = msg.sender;\n        IKycModule($.kycModule).validateAddress(user);\n        (uint256 netCollateralAmount, uint256 feeInCollateral) = previewRedeem(redeemCollateral, FUSDAmountToBurn);\n        // Burn FUSD\n        IERC20($.fusd).safeTransferFrom(user, address(this), FUSDAmountToBurn);\n        IFUSD($.fusd).burn(FUSDAmountToBurn);\n        // Redeem collateral\n        address to = AddressConvert.convertBytes32ToEVMAddress(toBytes32);\n        if (to == address(0)) {\n            revert ZeroAddress();\n        }\n        IERC20(redeemCollateral).safeTransferFrom($.treasury, to, netCollateralAmount.from18Decimals(redeemCollateral));\n        // Transfer fee\n        if (feeInCollateral > 0) {\n            IERC20(redeemCollateral).safeTransferFrom(\n                $.treasury, $.feeTo, feeInCollateral.from18Decimals(redeemCollateral)\n            );\n        }\n\n        emit InstantRedeem(user, toBytes32, redeemCollateral, FUSDAmountToBurn, netCollateralAmount, feeInCollateral);\n    }\n\n    /**\n     * @notice Converts collateral asset amount to FUSD amount\n     * @dev Only supports FUSDLP as collateral asset\n     * @param collateral Address of the collateral asset\n     * @param amount Amount of collateral asset (18 decimals)\n     * @return Amount of FUSD that can be minted (18 decimals)\n     */\n    function convertFromCollateral(address collateral, uint256 amount) public view returns (uint256) {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        if (collateral != $.lp) {\n            revert UnsupportedAsset(collateral);\n        }\n        uint256 rate = IFUSDLP($.lp).getExchangeRateWithAdjustment();\n        uint256 FUSDAmount = amount.mulDiv(rate, _BASE_DECIMALS);\n        return FUSDAmount;\n    }\n\n    /**\n     * @notice Converts FUSD amount to collateral asset amount\n     * @dev Only supports FUSDLP as collateral asset\n     * @param collateral Address of the collateral asset\n     * @param amount Amount of FUSD (18 decimals)\n     * @return Amount of collateral asset that can be redeemed (18 decimals)\n     */\n    function convertToCollateral(address collateral, uint256 amount) public view returns (uint256) {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        if (collateral != $.lp) {\n            revert UnsupportedAsset(collateral);\n        }\n        uint256 rate = IFUSDLP($.lp).getExchangeRateWithAdjustment();\n        uint256 lpAmount = amount.mulDiv(_BASE_DECIMALS, rate);\n        return lpAmount;\n    }\n\n    /**\n     * @notice Previews the amount of FUSD that can be minted with given collateral\n     * @dev Calculates fees and net mint amount\n     * @param collateral Address of the collateral asset\n     * @param collateralAmount Amount of collateral asset (18 decimals)\n     * @return mintAmount Amount of FUSD to be minted (18 decimals)\n     * @return netAmount Net amount of collateral after fees (18 decimals)\n     * @return fee Fee amount in collateral asset (18 decimals)\n     */\n    function previewMint(address collateral, uint256 collateralAmount)\n        public\n        view\n        returns (uint256, uint256, uint256)\n    {\n        if (collateralAmount == 0) {\n            revert CollateralAmountIsZero();\n        }\n        uint256 feeInCollateral = calculateFee(collateralAmount, FeeType.Mint);\n        uint256 netCollateralAmount = collateralAmount - feeInCollateral;\n        uint256 FUSDAmount = convertFromCollateral(collateral, netCollateralAmount);\n        return (FUSDAmount, netCollateralAmount, feeInCollateral);\n    }\n\n    /**\n     * @notice Previews the amount of collateral that can be redeemed with given FUSD\n     * @dev Calculates fees and net redeem amount\n     * @param collateral Address of the collateral asset\n     * @param FUSDAmountToBurn Amount of FUSD (18 decimals)\n     * @return redeemAmount Amount of asset to be redeemed (18 decimals)\n     * @return fee Fee amount in asset (18 decimals)\n     */\n    function previewRedeem(address collateral, uint256 FUSDAmountToBurn) public view returns (uint256, uint256) {\n        uint256 collateralAmount = convertToCollateral(collateral, FUSDAmountToBurn);\n        uint256 feeInCollateral = calculateFee(collateralAmount, FeeType.Redeem);\n        uint256 netCollateralAmount = collateralAmount - feeInCollateral;\n        return (netCollateralAmount, feeInCollateral);\n    }\n\n    /**\n     * @notice Calculates fee for given amount and fee type\n     * @dev Uses configured fee rates for mint/redeem operations\n     * @param amount Base amount to calculate fee on\n     * @param feeType Type of fee (Mint or Redeem)\n     * @return Calculated fee amount\n     */\n    function calculateFee(uint256 amount, FeeType feeType) public view returns (uint256) {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        uint256 feeRate;\n        if (feeType == FeeType.Mint) {\n            feeRate = $.mintFeeRate;\n        } else if (feeType == FeeType.Redeem) {\n            feeRate = $.redeemFeeRate;\n        } else {\n            revert InvalidFeeType(uint8(feeType));\n        }\n        uint256 fee = amount.mulDiv(feeRate, _BASE_DECIMALS);\n        return fee;\n    }\n\n    /**\n     * @notice Updates the mint fee rate\n     * @dev Only callable by accounts with DEFAULT_ADMIN_ROLE\n     * @param newRate New mint fee rate in basis points\n     */\n    function updateMintFeeRate(uint256 newRate) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        _checkFeeRate(newRate);\n        uint256 oldRate = $.mintFeeRate;\n        $.mintFeeRate = newRate;\n        emit MintFeeRateUpdated(oldRate, newRate);\n    }\n\n    /**\n     * @notice Updates the redeem fee rate\n     * @dev Only callable by accounts with DEFAULT_ADMIN_ROLE\n     * @param newRate New redeem fee rate in basis points\n     */\n    function updateRedeemFeeRate(uint256 newRate) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        _checkFeeRate(newRate);\n        uint256 oldRate = $.redeemFeeRate;\n        $.redeemFeeRate = newRate;\n        emit RedeemFeeRateUpdated(oldRate, newRate);\n    }\n\n    /**\n     * @notice Sets the fee recipient address\n     * @dev Only callable by accounts with DEFAULT_ADMIN_ROLE\n     * @param newFeeTo New address to receive fees\n     */\n    function setFeeTo(address newFeeTo) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        if (newFeeTo == address(0)) {\n            revert ZeroFeeToAddress();\n        }\n        address oldFeeTo = $.feeTo;\n        $.feeTo = newFeeTo;\n        emit FeeToUpdated(oldFeeTo, newFeeTo);\n    }\n\n    function setTreasury(address newTreasury) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        if (newTreasury == address(0)) {\n            revert ZeroTreasuryAddress();\n        }\n        address oldTreasury = $.treasury;\n        $.treasury = newTreasury;\n        emit TreasuryUpdated(oldTreasury, newTreasury);\n    }\n\n    /**\n     * @notice Pauses the contract\n     * @dev Only callable by accounts with PAUSER_ROLE\n     */\n    function pause() external onlyRole(PAUSER_ROLE) {\n        _pause();\n    }\n\n    /**\n     * @notice Unpauses the contract\n     * @dev Only callable by accounts with PAUSER_ROLE\n     */\n    function unpause() external onlyRole(PAUSER_ROLE) {\n        _unpause();\n    }\n\n    function _checkFeeRate(uint256 feeRate) internal pure {\n        if (feeRate >= _MAX_FEE_RATE) {\n            revert FeeRateTooHigh();\n        }\n    }\n\n    function _refundNativeToken(uint256 amount) internal {\n        if (amount > 0) {\n            (bool success,) = payable(msg.sender).call{value: amount}(\"\");\n            if (!success) {\n                revert RefundFailed();\n            }\n        }\n    }\n\n    function isCustomMessageIdUsed(uint256 _customMessageId) external view returns (bool) {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        return $.usedCustomMessageIds.get(_customMessageId);\n    }\n\n    /// @notice Consume the custom message ID to prevent reuse\n    function _consumeCustomMessageId(uint256 _customMessageId) internal {\n        FUSDGatewayStorage storage $ = _getFUSDGatewayStorage();\n        require(!$.usedCustomMessageIds.get(_customMessageId), CustomMessageIdIsUsed(_customMessageId));\n        $.usedCustomMessageIds.set(_customMessageId);\n    }\n}\n","deployed_bytecode":"0x6080806040526004361015610078575b50361561001b57600080fd5b6001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66075416330361004e57005b7f205790380000000000000000000000000000000000000000000000000000000060005260046000fd5b600090813560e01c90816301ffc9a71461240f5750806302fc5a7a146123725780631edb03ea1461235357806321ff4d0314612164578063248a9ca3146121175780632f2ff15d146120b757806336568abe146120595780633ceb3079146120315780633f4ba83a14611f7257806342966c6814611e5a578063599faaac14611c055780635c975abb14611bc35780636ecfb7dd146115d0578063821438971461153357806382300ee3146114565780638456cb59146113bd5780639010d07c1461135957806391d14854146112ed578063a217fddf146112d1578063a3246ad314611202578063a533350b14610d12578063b1bd3b6714610a0d578063c79212c714610636578063ca15c873146105ed578063cbe52ae3146105a5578063d1f810a51461056a578063d53913931461052f578063d547741f146104c6578063e338b10a14610464578063e63ab1e914610429578063f0f44260146103065763f46901ed0361000f5734610303576020600319360112610303576101fa6124e2565b6102026128c0565b6001600160a01b0381169081156102db576102b46001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66065416916001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66065416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660655565b7f8f93286d6f131e956d1aa672d3ecdc817f24efc20b223b0de5d591f454edc3478380a380f35b6004837f0fcf8185000000000000000000000000000000000000000000000000000000008152fd5b80fd5b5034610303576020600319360112610303576103206124e2565b6103286128c0565b6001600160a01b038116908115610401576103da6001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66025416916001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66025416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660255565b7f4ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a8380a380f35b6004837fa3b900da000000000000000000000000000000000000000000000000000000008152fd5b503461030357806003193601126103035760206040517f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a8152f35b50346103035760206003193601126103035760206104bc60043560ff6001918060081c6000527fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6608602052161b60406000205416151590565b6040519015158152f35b50346103035760406003193601126103035761052b6004356104e66124f8565b90610526610521826000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260016040600020015490565b6129b7565b612de3565b5080f35b503461030357806003193601126103035760206040517f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a68152f35b50346103035760406003193601126103035760606105926105896124e2565b6024359061284b565b9060405192835260208301526040820152f35b50346103035760406003193601126103035760406105cd6105c46124e2565b602435906125a8565b6105e06105d9826127a3565b809261280f565b9082519182526020820152f35b503461030357602060031936011261030357604060209160043581527fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e8237170593200083522054604051908152f35b5060606003193601126103035760043590602435916044359167ffffffffffffffff8316908184036103035761066a612bf8565b6106726128c0565b80938215600014610779575061068783612f71565b6001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600541690813b15610775576040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b03919091166004820152602481018790529082908290604490829084905af1801561076a57610755575b505060406020947ecfbdbf2a567934b88f7f1e102e7388ca42c2053b550be440295bf1a87b08b0925b61074347613041565b825191825286820152a2604051908152f35b610760828092612538565b6103035780610711565b6040513d84823e3d90fd5b8280fd5b9080959294506001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416803b15610a09576040517f40c10f19000000000000000000000000000000000000000000000000000000008152306004820152602481018590529082908290604490829084905af1801561076a576109f0575b50507fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600547fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6607546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018590529291602091849160449183918b91165af19081156109e55783926020926109ba575b506001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66075416856001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600541692610934604051968795869485947f1472b4bb000000000000000000000000000000000000000000000000000000008652600486016127ce565b039134905af19485156109ae5794610974575b5060407ecfbdbf2a567934b88f7f1e102e7388ca42c2053b550be440295bf1a87b08b0916020959461073a565b93506020843d6020116109a6575b8161098f60209383612538565b810103126109a1579251926040610947565b600080fd5b3d9150610982565b604051903d90823e3d90fd5b6109d990833d85116109de575b6109d18183612538565b81019061269b565b6108a2565b503d6109c7565b6040513d88823e3d90fd5b816109fa91612538565b610a055784386107fd565b8480fd5b5080fd5b503461030357610a1c3661250e565b610a27929192612bf8565b610a2f612c4d565b602460206001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66035416604051928380927f5e8e30a60000000000000000000000000000000000000000000000000000000082523360048301525afa8015610d0757610cea575b50610aa681846125a8565b90610aba610ab3836127a3565b809361280f565b90610af3816001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600541630903390612cc6565b856001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416803b15610a09578180916024604051809481937f42966c680000000000000000000000000000000000000000000000000000000083528860048401525af1801561076a57610cd1575b5050610b7384612f71565b946001600160a01b03861615610ca957610bce6001600160a01b038216966001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6602541690610bc78487612e38565b9189612cc6565b83610c37575b506040519384526020840152604083015260608201527f37eee8ffd8d25c551c45e4dc284a4d5c489b096682ccbaa8e27d91219fbe4e4b60803392a360017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005580f35b610ca3906001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6602541690610c9c6001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660654169187612e38565b9188612cc6565b38610bd4565b6004877fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b81610cdb91612538565b610ce6578538610b68565b8580fd5b610d029060203d6020116109de576109d18183612538565b610a9b565b6040513d87823e3d90fd5b50608060031936011261030357600435610d2a6124f8565b6064359160443567ffffffffffffffff8416808503610ce657610d4b612bf8565b610d53612c4d565b8594602460206001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66035416604051928380927f5e8e30a60000000000000000000000000000000000000000000000000000000082523360048301525afa80156111f7576111da575b50610e20610dcf848761284b565b939192908461118c575b610e186001600160a01b038a16996001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6602541692612e38565b90338a612cc6565b83610f515750610e2f85612f71565b886001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600541691823b15610a09576040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b0391909116600482015260248101849052918290604490829084905af18015610f4657610f2d575b50602097505b610ec747613041565b60405193845287840152604083015260608201527f6ee6cac29825e1539d401d35c08a492819f2f49423d8233cfcd110f03b4e294160803392a460017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055604051908152f35b610f38898092612538565b610f425787610eb8565b8780fd5b6040513d8b823e3d90fd5b909650876001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416803b15610a09576040517f40c10f19000000000000000000000000000000000000000000000000000000008152306004820152602481018a90529082908290604490829084905af1801561076a57611177575b50507fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600547fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6607546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018a905291602091839160449183918e91165af18015610f4657916020918a938a9b5061115c575b506001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66075416876001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660054169261110c6040519d8e95869485947f1472b4bb000000000000000000000000000000000000000000000000000000008652600486016127ce565b039134905af19081156109ae5790611129575b6020975095610ebe565b506020873d602011611154575b8161114360209383612538565b810103126109a1576020965161111f565b3d9150611136565b61117290833d85116109de576109d18183612538565b61107a565b8161118191612538565b610f42578738610fd3565b6111d56001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660654166111c48b88612e38565b90336001600160a01b038d16612cc6565b610dd9565b6111f29060203d6020116109de576109d18183612538565b610dc1565b6040513d8a823e3d90fd5b50346103035760206003193601126103035760043581527fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e8237170593200060205260408120604051908160208254918281520190819285526020852090855b8181106112bb5750505082611271910383612538565b604051928392602084019060208552518091526040840192915b818110611299575050500390f35b82516001600160a01b031684528594506020938401939092019160010161128b565b825484526020909301926001928301920161125b565b5034610303578060031936011261030357602090604051908152f35b5034610303576040600319360112610303576001600160a01b0360406113116124f8565b9260043581527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052209116600052602052602060ff604060002054166040519015158152f35b5034610303576040600319360112610303576001600160a01b036113ad60209260043581527fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e8237170593200084526040602435912061338f565b90549060031b1c16604051908152f35b50346103035780600319360112610303576113d661292c565b6113de612bf8565b600160ff197fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005416177fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b5034610303576040600319360112610303576024359060028210156103035761147e8261276a565b816114bd57505060206114b57fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6604545b600435612b60565b604051908152f35b6114c68261276a565b600182036114fc57505060206114b57fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6605546114ad565b60ff8261150a60249461276a565b7f8f3eadca00000000000000000000000000000000000000000000000000000000835216600452fd5b5034610303576020600319360112610303577fa1e82d3c645e1aa21b5f4c80f1503f00763f250a86c6ded28a4739d855eb613060406004356115736128c0565b61157c81612a36565b7fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66045490807fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66045582519182526020820152a180f35b503461030357610120600319360112610303576115eb6124e2565b6115f36124f8565b6044356001600160a01b0381168103611bbf576064356001600160a01b038116809103610a055760c43560a4356084356001600160a01b0383168303610f425760e435936001600160a01b038516809503611bbb5761010435956001600160a01b03871697888803611bb7577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549960ff8b60401c16159a67ffffffffffffffff811680159081611baf575b6001149081611ba5575b159081611b9c575b50611b7457926001600160a01b036119d7979593816118a8948f97611a439e9d9c9a9860017fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008316177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055611b1f575b5061172a613336565b611732613336565b61173a613336565b611742613336565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055167fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660055167fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66015416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6601556001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66025416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660255565b7fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66035416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66035561191881612a36565b61192182612a36565b7fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6604557fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6605556001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66065416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660655565b7fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66075416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6607556130df565b611ae4575b50611a505780f35b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b611b18908380527fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e823717059320006020526040842061343e565b5038611a48565b7fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005538611721565b60048d7ff92ee8a9000000000000000000000000000000000000000000000000000000008152fd5b905015386116b1565b303b1591506116a9565b8d915061169f565b8a80fd5b8880fd5b8380fd5b5034610303578060031936011261030357602060ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166040519015158152f35b503461030357611c143661250e565b9190611c1e612bf8565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a684527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604084206001600160a01b03331660005260205260ff6040600020541615611e0a57611cc98260ff6001918060081c6000527fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6608602052161b60406000205416151590565b611dde578160081c84527fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660860205260408420600160ff84161b8154179055836001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416803b15610a09576040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602481018690529082908290604490829084905af1801561076a57611dc9575b505060206001600160a01b037fc038cf98e232734adcebf7159edd211c497cfb6127adb0a5de27e1957de254a6926040519586521693a380f35b81611dd391612538565b611bbf578338611d8f565b602484837f284b69a1000000000000000000000000000000000000000000000000000000008252600452fd5b6044847fe2517d3f000000000000000000000000000000000000000000000000000000008152336004527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6602452fd5b503461030357602060031936011261030357600435611e77612bf8565b611e7f6128c0565b611eb7816001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600541630903390612cc6565b816001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416803b15610a09578180916024604051809481937f42966c680000000000000000000000000000000000000000000000000000000083528860048401525af1801561076a57611f5d575b50506040519081527f4af30430618fbf9e19d90d7b37a70770c992d7e131bfe2b5abf2202f7d9b1e5560203392a280f35b81611f6791612538565b610a09578138611f2c565b5034610303578060031936011261030357611f8b61292c565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff8116156120095760ff19167fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a180f35b6004827f8dfc202b000000000000000000000000000000000000000000000000000000008152fd5b50346103035760406003193601126103035760206114b56120506124e2565b602435906126b3565b5034610303576040600319360112610303576120736124f8565b336001600160a01b0382160361208f5761052b90600435612de3565b6004827f6697b232000000000000000000000000000000000000000000000000000000008152fd5b50346103035760406003193601126103035761052b6004356120d76124f8565b90612112610521826000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260016040600020015490565b612d8a565b50346103035760206003193601126103035760206114b56004356000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260016040600020015490565b50346103035760206003193601126103035760043590612182612bf8565b61218a612c4d565b811561232b57602460206001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66035416604051928380927f5e8e30a60000000000000000000000000000000000000000000000000000000082523360048301525afa801561076a5761230e575b50612235826001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600541630903390612cc6565b6001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416803b15610a09578180916024604051809481937f42966c680000000000000000000000000000000000000000000000000000000083528860048401525af1801561076a576122fe575b50906040519081527fa1a009bfa4d4ebaf046d2b27cbc657074cb3b637a247a3dbdf767eda4955efc260203392a260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005580f35b8161230891612538565b386122a9565b6123269060203d6020116109de576109d18183612538565b6121fc565b807f3a1b5efe0000000000000000000000000000000000000000000000000000000060049252fd5b50346103035760406003193601126103035760206114b56105c46124e2565b5034610303576020600319360112610303577fc80374ea7e06d4b5c899356b78f1a0cd27b97916cd878974620ddce80bc2a78460406004356123b26128c0565b6123bb81612a36565b7fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66055490807fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66055582519182526020820152a180f35b905034610a09576020600319360112610a09576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361077557602092507f5a05180f000000000000000000000000000000000000000000000000000000008114908115612485575b5015158152f35b7f7965db0b000000000000000000000000000000000000000000000000000000008114915081156124b8575b503861247e565b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014386124b1565b600435906001600160a01b03821682036109a157565b602435906001600160a01b03821682036109a157565b60031960609101126109a157600435906024356001600160a01b03811681036109a1579060443590565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761257957604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6001600160a01b03807fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66015416911681810361266e5750906020600492604051938480927fb57a803a0000000000000000000000000000000000000000000000000000000082525afa9081156126625760009161262c575b6126299250612aa9565b90565b90506020823d60201161265a575b8161264760209383612538565b810103126109a15761262991519061261f565b3d915061263a565b6040513d6000823e3d90fd5b7fee84f40b0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b908160209103126109a1575180151581036109a15790565b6001600160a01b03807fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66015416911681810361266e5750906020600492604051938480927fb57a803a0000000000000000000000000000000000000000000000000000000082525afa90811561266257600091612734575b6126299250612b60565b90506020823d602011612762575b8161274f60209383612538565b810103126109a15761262991519061272a565b3d9150612742565b6002111561277457565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66055461262991612b60565b926001600160a01b039195949267ffffffffffffffff60a0860197168552602085015216604083015260608201526002600010156127745760806000910152565b9190820391821161281c57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9181156128965761289161288a6128837fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66045485612b60565b809461280f565b80946126b3565b929190565b7f609ac0e10000000000000000000000000000000000000000000000000000000060005260046000fd5b3360009081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff16156128f957565b7fe2517d3f0000000000000000000000000000000000000000000000000000000060005233600452600060245260446000fd5b3360009081527f75442b0a96088b5456bc4ed01394c96a4feec0f883c9494257d76b96ab1c9b6b602052604090205460ff161561296557565b7fe2517d3f00000000000000000000000000000000000000000000000000000000600052336004527f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a60245260446000fd5b806000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260406000206001600160a01b03331660005260205260ff6040600020541615612a055750565b7fe2517d3f000000000000000000000000000000000000000000000000000000006000523360045260245260446000fd5b662386f26fc100001115612a4657565b7fe30ce51e0000000000000000000000000000000000000000000000000000000060005260046000fd5b8115612a7a570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600019670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414612b545783821115612b3b57670de0b6b3a7640000829109816000038216809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b50634e487b71600052156003026011186020526024601cfd5b50906126299250612a70565b9190916000906000198482099084810292838084109303928084039314612be55782670de0b6b3a76400001115612bd357507faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b634e487b71905260116020526024601cfd5b505050670de0b6b3a76400009192500490565b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005416612c2357565b7fd93c06650000000000000000000000000000000000000000000000000000000060005260046000fd5b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005414612c9c5760027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b7f3ee5aeb50000000000000000000000000000000000000000000000000000000060005260046000fd5b92906020926000926001600160a01b036040519281878501957f23b872dd000000000000000000000000000000000000000000000000000000008752166024850152166044830152606482015260648152612d22608482612538565b519082855af115612662576000513d612d8157506001600160a01b0381163b155b612d4a5750565b6001600160a01b03907f5274afe7000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b60011415612d43565b612d948282613191565b9182612d9f57505090565b612ddf916000527fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e823717059320006020526001600160a01b03604060002091169061343e565b5090565b612ded8282613269565b9182612df857505090565b612ddf916000527fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e823717059320006020526001600160a01b0360406000209116906134b4565b9060206001600160a01b03916004604051809481937f313ce567000000000000000000000000000000000000000000000000000000008352165afa90811561266257600091612f34575b5060ff16601203906012821161281c57604d821161281c57612ea791600a0a90612a70565b8015612eb05790565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f546f6b656e446563696d616c73436f6e766572743a20616d6f756e742069732060448201527f746f6f20736d616c6c00000000000000000000000000000000000000000000006064820152fd5b6020813d602011612f69575b81612f4d60209383612538565b81010312610a0957519060ff82168203610303575060ff612e82565b3d9150612f40565b6040516020810182815260208252612f8a604083612538565b602082510361300d5760208181845185010103126109a157516001600160a01b038111908115613001575b50612fc757506001600160a01b031690565b612ffd906040519182917f8d666f60000000000000000000000000000000000000000000000000000000008352600483016133d6565b0390fd5b61040091501038612fb5565b6040517f8d666f6000000000000000000000000000000000000000000000000000000000815280612ffd84600483016133d6565b806130495750565b600080808093335af13d156130da573d67ffffffffffffffff8111612579576040519061309e60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160183612538565b8152600060203d92013e5b156130b057565b7ff0c49d440000000000000000000000000000000000000000000000000000000060005260046000fd5b6130a9565b6001600160a01b03811660009081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff1661318b576001600160a01b031660008181527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d60205260408120805460ff191660011790553391907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b50600090565b806000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260406000206001600160a01b03831660005260205260ff604060002054161560001461326257806000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260406000206001600160a01b0383166000526020526040600020600160ff198254161790556001600160a01b03339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d600080a4600190565b5050600090565b806000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260406000206001600160a01b03831660005260205260ff6040600020541660001461326257806000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260406000206001600160a01b038316600052602052604060002060ff1981541690556001600160a01b03339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b600080a4600190565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561336557565b7fd7e6bcf80000000000000000000000000000000000000000000000000000000060005260046000fd5b80548210156133a75760005260206000200190600090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9190916020815282519283602083015260005b8481106134285750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b80602080928401015160408286010152016133e9565b60018101908260005281602052604060002054156000146134ac578054680100000000000000008110156125795761349761348082600187940185558461338f565b81939154906000199060031b92831b921b19161790565b90555491600052602052604060002055600190565b505050600090565b906001820191816000528260205260406000205480151560001461359657600019810181811161281c57825490600019820191821161281c5781810361355f575b5050508054801561353057600019019061350f828261338f565b60001982549160031b1b191690555560005260205260006040812055600190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b61357f61356f613480938661338f565b90549060031b1c9283928661338f565b9055600052836020526040600020553880806134f5565b5050505060009056","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"paris","libraries":{},"metadata":{"appendCBOR":false,"bytecodeHash":"none","useLiteralContent":true},"optimizer":{"enabled":true,"runs":9999},"outputSelection":{"*":{"":["*"],"*":["*"]}},"viaIR":true},"optimization_runs":9999,"sourcify_repo_url":null,"decoded_constructor_args":null,"compiler_version":"v0.8.26+commit.8a97fa7a","is_verified_via_verifier_alliance":false,"verified_at":"2026-06-04T11:21:06.291053Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x6080806040523460d2577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c1660c1576002600160401b03196001600160401b03821601605c575b60405161359f90816100d88239f35b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a13880604d565b63f92ee8a960e01b60005260046000fd5b600080fdfe6080806040526004361015610078575b50361561001b57600080fd5b6001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66075416330361004e57005b7f205790380000000000000000000000000000000000000000000000000000000060005260046000fd5b600090813560e01c90816301ffc9a71461240f5750806302fc5a7a146123725780631edb03ea1461235357806321ff4d0314612164578063248a9ca3146121175780632f2ff15d146120b757806336568abe146120595780633ceb3079146120315780633f4ba83a14611f7257806342966c6814611e5a578063599faaac14611c055780635c975abb14611bc35780636ecfb7dd146115d0578063821438971461153357806382300ee3146114565780638456cb59146113bd5780639010d07c1461135957806391d14854146112ed578063a217fddf146112d1578063a3246ad314611202578063a533350b14610d12578063b1bd3b6714610a0d578063c79212c714610636578063ca15c873146105ed578063cbe52ae3146105a5578063d1f810a51461056a578063d53913931461052f578063d547741f146104c6578063e338b10a14610464578063e63ab1e914610429578063f0f44260146103065763f46901ed0361000f5734610303576020600319360112610303576101fa6124e2565b6102026128c0565b6001600160a01b0381169081156102db576102b46001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66065416916001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66065416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660655565b7f8f93286d6f131e956d1aa672d3ecdc817f24efc20b223b0de5d591f454edc3478380a380f35b6004837f0fcf8185000000000000000000000000000000000000000000000000000000008152fd5b80fd5b5034610303576020600319360112610303576103206124e2565b6103286128c0565b6001600160a01b038116908115610401576103da6001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66025416916001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66025416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660255565b7f4ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a8380a380f35b6004837fa3b900da000000000000000000000000000000000000000000000000000000008152fd5b503461030357806003193601126103035760206040517f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a8152f35b50346103035760206003193601126103035760206104bc60043560ff6001918060081c6000527fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6608602052161b60406000205416151590565b6040519015158152f35b50346103035760406003193601126103035761052b6004356104e66124f8565b90610526610521826000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260016040600020015490565b6129b7565b612de3565b5080f35b503461030357806003193601126103035760206040517f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a68152f35b50346103035760406003193601126103035760606105926105896124e2565b6024359061284b565b9060405192835260208301526040820152f35b50346103035760406003193601126103035760406105cd6105c46124e2565b602435906125a8565b6105e06105d9826127a3565b809261280f565b9082519182526020820152f35b503461030357602060031936011261030357604060209160043581527fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e8237170593200083522054604051908152f35b5060606003193601126103035760043590602435916044359167ffffffffffffffff8316908184036103035761066a612bf8565b6106726128c0565b80938215600014610779575061068783612f71565b6001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600541690813b15610775576040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b03919091166004820152602481018790529082908290604490829084905af1801561076a57610755575b505060406020947ecfbdbf2a567934b88f7f1e102e7388ca42c2053b550be440295bf1a87b08b0925b61074347613041565b825191825286820152a2604051908152f35b610760828092612538565b6103035780610711565b6040513d84823e3d90fd5b8280fd5b9080959294506001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416803b15610a09576040517f40c10f19000000000000000000000000000000000000000000000000000000008152306004820152602481018590529082908290604490829084905af1801561076a576109f0575b50507fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600547fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6607546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018590529291602091849160449183918b91165af19081156109e55783926020926109ba575b506001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66075416856001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600541692610934604051968795869485947f1472b4bb000000000000000000000000000000000000000000000000000000008652600486016127ce565b039134905af19485156109ae5794610974575b5060407ecfbdbf2a567934b88f7f1e102e7388ca42c2053b550be440295bf1a87b08b0916020959461073a565b93506020843d6020116109a6575b8161098f60209383612538565b810103126109a1579251926040610947565b600080fd5b3d9150610982565b604051903d90823e3d90fd5b6109d990833d85116109de575b6109d18183612538565b81019061269b565b6108a2565b503d6109c7565b6040513d88823e3d90fd5b816109fa91612538565b610a055784386107fd565b8480fd5b5080fd5b503461030357610a1c3661250e565b610a27929192612bf8565b610a2f612c4d565b602460206001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66035416604051928380927f5e8e30a60000000000000000000000000000000000000000000000000000000082523360048301525afa8015610d0757610cea575b50610aa681846125a8565b90610aba610ab3836127a3565b809361280f565b90610af3816001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600541630903390612cc6565b856001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416803b15610a09578180916024604051809481937f42966c680000000000000000000000000000000000000000000000000000000083528860048401525af1801561076a57610cd1575b5050610b7384612f71565b946001600160a01b03861615610ca957610bce6001600160a01b038216966001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6602541690610bc78487612e38565b9189612cc6565b83610c37575b506040519384526020840152604083015260608201527f37eee8ffd8d25c551c45e4dc284a4d5c489b096682ccbaa8e27d91219fbe4e4b60803392a360017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005580f35b610ca3906001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6602541690610c9c6001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660654169187612e38565b9188612cc6565b38610bd4565b6004877fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b81610cdb91612538565b610ce6578538610b68565b8580fd5b610d029060203d6020116109de576109d18183612538565b610a9b565b6040513d87823e3d90fd5b50608060031936011261030357600435610d2a6124f8565b6064359160443567ffffffffffffffff8416808503610ce657610d4b612bf8565b610d53612c4d565b8594602460206001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66035416604051928380927f5e8e30a60000000000000000000000000000000000000000000000000000000082523360048301525afa80156111f7576111da575b50610e20610dcf848761284b565b939192908461118c575b610e186001600160a01b038a16996001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6602541692612e38565b90338a612cc6565b83610f515750610e2f85612f71565b886001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600541691823b15610a09576040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b0391909116600482015260248101849052918290604490829084905af18015610f4657610f2d575b50602097505b610ec747613041565b60405193845287840152604083015260608201527f6ee6cac29825e1539d401d35c08a492819f2f49423d8233cfcd110f03b4e294160803392a460017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055604051908152f35b610f38898092612538565b610f425787610eb8565b8780fd5b6040513d8b823e3d90fd5b909650876001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416803b15610a09576040517f40c10f19000000000000000000000000000000000000000000000000000000008152306004820152602481018a90529082908290604490829084905af1801561076a57611177575b50507fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600547fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6607546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018a905291602091839160449183918e91165af18015610f4657916020918a938a9b5061115c575b506001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66075416876001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660054169261110c6040519d8e95869485947f1472b4bb000000000000000000000000000000000000000000000000000000008652600486016127ce565b039134905af19081156109ae5790611129575b6020975095610ebe565b506020873d602011611154575b8161114360209383612538565b810103126109a1576020965161111f565b3d9150611136565b61117290833d85116109de576109d18183612538565b61107a565b8161118191612538565b610f42578738610fd3565b6111d56001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660654166111c48b88612e38565b90336001600160a01b038d16612cc6565b610dd9565b6111f29060203d6020116109de576109d18183612538565b610dc1565b6040513d8a823e3d90fd5b50346103035760206003193601126103035760043581527fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e8237170593200060205260408120604051908160208254918281520190819285526020852090855b8181106112bb5750505082611271910383612538565b604051928392602084019060208552518091526040840192915b818110611299575050500390f35b82516001600160a01b031684528594506020938401939092019160010161128b565b825484526020909301926001928301920161125b565b5034610303578060031936011261030357602090604051908152f35b5034610303576040600319360112610303576001600160a01b0360406113116124f8565b9260043581527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052209116600052602052602060ff604060002054166040519015158152f35b5034610303576040600319360112610303576001600160a01b036113ad60209260043581527fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e8237170593200084526040602435912061338f565b90549060031b1c16604051908152f35b50346103035780600319360112610303576113d661292c565b6113de612bf8565b600160ff197fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005416177fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b5034610303576040600319360112610303576024359060028210156103035761147e8261276a565b816114bd57505060206114b57fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6604545b600435612b60565b604051908152f35b6114c68261276a565b600182036114fc57505060206114b57fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6605546114ad565b60ff8261150a60249461276a565b7f8f3eadca00000000000000000000000000000000000000000000000000000000835216600452fd5b5034610303576020600319360112610303577fa1e82d3c645e1aa21b5f4c80f1503f00763f250a86c6ded28a4739d855eb613060406004356115736128c0565b61157c81612a36565b7fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66045490807fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66045582519182526020820152a180f35b503461030357610120600319360112610303576115eb6124e2565b6115f36124f8565b6044356001600160a01b0381168103611bbf576064356001600160a01b038116809103610a055760c43560a4356084356001600160a01b0383168303610f425760e435936001600160a01b038516809503611bbb5761010435956001600160a01b03871697888803611bb7577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549960ff8b60401c16159a67ffffffffffffffff811680159081611baf575b6001149081611ba5575b159081611b9c575b50611b7457926001600160a01b036119d7979593816118a8948f97611a439e9d9c9a9860017fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008316177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0055611b1f575b5061172a613336565b611732613336565b61173a613336565b611742613336565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055167fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660055167fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66015416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6601556001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66025416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660255565b7fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66035416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66035561191881612a36565b61192182612a36565b7fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6604557fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6605556001600160a01b03167fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66065416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660655565b7fffffffffffffffffffffffff00000000000000000000000000000000000000007fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66075416177fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6607556130df565b611ae4575b50611a505780f35b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b611b18908380527fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e823717059320006020526040842061343e565b5038611a48565b7fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005538611721565b60048d7ff92ee8a9000000000000000000000000000000000000000000000000000000008152fd5b905015386116b1565b303b1591506116a9565b8d915061169f565b8a80fd5b8880fd5b8380fd5b5034610303578060031936011261030357602060ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330054166040519015158152f35b503461030357611c143661250e565b9190611c1e612bf8565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a684527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604084206001600160a01b03331660005260205260ff6040600020541615611e0a57611cc98260ff6001918060081c6000527fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6608602052161b60406000205416151590565b611dde578160081c84527fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f660860205260408420600160ff84161b8154179055836001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416803b15610a09576040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602481018690529082908290604490829084905af1801561076a57611dc9575b505060206001600160a01b037fc038cf98e232734adcebf7159edd211c497cfb6127adb0a5de27e1957de254a6926040519586521693a380f35b81611dd391612538565b611bbf578338611d8f565b602484837f284b69a1000000000000000000000000000000000000000000000000000000008252600452fd5b6044847fe2517d3f000000000000000000000000000000000000000000000000000000008152336004527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6602452fd5b503461030357602060031936011261030357600435611e77612bf8565b611e7f6128c0565b611eb7816001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600541630903390612cc6565b816001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416803b15610a09578180916024604051809481937f42966c680000000000000000000000000000000000000000000000000000000083528860048401525af1801561076a57611f5d575b50506040519081527f4af30430618fbf9e19d90d7b37a70770c992d7e131bfe2b5abf2202f7d9b1e5560203392a280f35b81611f6791612538565b610a09578138611f2c565b5034610303578060031936011261030357611f8b61292c565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff8116156120095760ff19167fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a180f35b6004827f8dfc202b000000000000000000000000000000000000000000000000000000008152fd5b50346103035760406003193601126103035760206114b56120506124e2565b602435906126b3565b5034610303576040600319360112610303576120736124f8565b336001600160a01b0382160361208f5761052b90600435612de3565b6004827f6697b232000000000000000000000000000000000000000000000000000000008152fd5b50346103035760406003193601126103035761052b6004356120d76124f8565b90612112610521826000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260016040600020015490565b612d8a565b50346103035760206003193601126103035760206114b56004356000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260016040600020015490565b50346103035760206003193601126103035760043590612182612bf8565b61218a612c4d565b811561232b57602460206001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66035416604051928380927f5e8e30a60000000000000000000000000000000000000000000000000000000082523360048301525afa801561076a5761230e575b50612235826001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f6600541630903390612cc6565b6001600160a01b037fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66005416803b15610a09578180916024604051809481937f42966c680000000000000000000000000000000000000000000000000000000083528860048401525af1801561076a576122fe575b50906040519081527fa1a009bfa4d4ebaf046d2b27cbc657074cb3b637a247a3dbdf767eda4955efc260203392a260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005580f35b8161230891612538565b386122a9565b6123269060203d6020116109de576109d18183612538565b6121fc565b807f3a1b5efe0000000000000000000000000000000000000000000000000000000060049252fd5b50346103035760406003193601126103035760206114b56105c46124e2565b5034610303576020600319360112610303577fc80374ea7e06d4b5c899356b78f1a0cd27b97916cd878974620ddce80bc2a78460406004356123b26128c0565b6123bb81612a36565b7fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66055490807fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66055582519182526020820152a180f35b905034610a09576020600319360112610a09576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361077557602092507f5a05180f000000000000000000000000000000000000000000000000000000008114908115612485575b5015158152f35b7f7965db0b000000000000000000000000000000000000000000000000000000008114915081156124b8575b503861247e565b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014386124b1565b600435906001600160a01b03821682036109a157565b602435906001600160a01b03821682036109a157565b60031960609101126109a157600435906024356001600160a01b03811681036109a1579060443590565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761257957604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6001600160a01b03807fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66015416911681810361266e5750906020600492604051938480927fb57a803a0000000000000000000000000000000000000000000000000000000082525afa9081156126625760009161262c575b6126299250612aa9565b90565b90506020823d60201161265a575b8161264760209383612538565b810103126109a15761262991519061261f565b3d915061263a565b6040513d6000823e3d90fd5b7fee84f40b0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b908160209103126109a1575180151581036109a15790565b6001600160a01b03807fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66015416911681810361266e5750906020600492604051938480927fb57a803a0000000000000000000000000000000000000000000000000000000082525afa90811561266257600091612734575b6126299250612b60565b90506020823d602011612762575b8161274f60209383612538565b810103126109a15761262991519061272a565b3d9150612742565b6002111561277457565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66055461262991612b60565b926001600160a01b039195949267ffffffffffffffff60a0860197168552602085015216604083015260608201526002600010156127745760806000910152565b9190820391821161281c57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9181156128965761289161288a6128837fe5aec6c70f9410d2edf9b51ae8946a723e7550fcac9bb219d5513469917f66045485612b60565b809461280f565b80946126b3565b929190565b7f609ac0e10000000000000000000000000000000000000000000000000000000060005260046000fd5b3360009081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff16156128f957565b7fe2517d3f0000000000000000000000000000000000000000000000000000000060005233600452600060245260446000fd5b3360009081527f75442b0a96088b5456bc4ed01394c96a4feec0f883c9494257d76b96ab1c9b6b602052604090205460ff161561296557565b7fe2517d3f00000000000000000000000000000000000000000000000000000000600052336004527f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a60245260446000fd5b806000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260406000206001600160a01b03331660005260205260ff6040600020541615612a055750565b7fe2517d3f000000000000000000000000000000000000000000000000000000006000523360045260245260446000fd5b662386f26fc100001115612a4657565b7fe30ce51e0000000000000000000000000000000000000000000000000000000060005260046000fd5b8115612a7a570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600019670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414612b545783821115612b3b57670de0b6b3a7640000829109816000038216809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b50634e487b71600052156003026011186020526024601cfd5b50906126299250612a70565b9190916000906000198482099084810292838084109303928084039314612be55782670de0b6b3a76400001115612bd357507faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b634e487b71905260116020526024601cfd5b505050670de0b6b3a76400009192500490565b60ff7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005416612c2357565b7fd93c06650000000000000000000000000000000000000000000000000000000060005260046000fd5b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005414612c9c5760027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b7f3ee5aeb50000000000000000000000000000000000000000000000000000000060005260046000fd5b92906020926000926001600160a01b036040519281878501957f23b872dd000000000000000000000000000000000000000000000000000000008752166024850152166044830152606482015260648152612d22608482612538565b519082855af115612662576000513d612d8157506001600160a01b0381163b155b612d4a5750565b6001600160a01b03907f5274afe7000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b60011415612d43565b612d948282613191565b9182612d9f57505090565b612ddf916000527fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e823717059320006020526001600160a01b03604060002091169061343e565b5090565b612ded8282613269565b9182612df857505090565b612ddf916000527fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e823717059320006020526001600160a01b0360406000209116906134b4565b9060206001600160a01b03916004604051809481937f313ce567000000000000000000000000000000000000000000000000000000008352165afa90811561266257600091612f34575b5060ff16601203906012821161281c57604d821161281c57612ea791600a0a90612a70565b8015612eb05790565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f546f6b656e446563696d616c73436f6e766572743a20616d6f756e742069732060448201527f746f6f20736d616c6c00000000000000000000000000000000000000000000006064820152fd5b6020813d602011612f69575b81612f4d60209383612538565b81010312610a0957519060ff82168203610303575060ff612e82565b3d9150612f40565b6040516020810182815260208252612f8a604083612538565b602082510361300d5760208181845185010103126109a157516001600160a01b038111908115613001575b50612fc757506001600160a01b031690565b612ffd906040519182917f8d666f60000000000000000000000000000000000000000000000000000000008352600483016133d6565b0390fd5b61040091501038612fb5565b6040517f8d666f6000000000000000000000000000000000000000000000000000000000815280612ffd84600483016133d6565b806130495750565b600080808093335af13d156130da573d67ffffffffffffffff8111612579576040519061309e60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160183612538565b8152600060203d92013e5b156130b057565b7ff0c49d440000000000000000000000000000000000000000000000000000000060005260046000fd5b6130a9565b6001600160a01b03811660009081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff1661318b576001600160a01b031660008181527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d60205260408120805460ff191660011790553391907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b50600090565b806000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260406000206001600160a01b03831660005260205260ff604060002054161560001461326257806000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260406000206001600160a01b0383166000526020526040600020600160ff198254161790556001600160a01b03339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d600080a4600190565b5050600090565b806000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260406000206001600160a01b03831660005260205260ff6040600020541660001461326257806000527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260406000206001600160a01b038316600052602052604060002060ff1981541690556001600160a01b03339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b600080a4600190565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561336557565b7fd7e6bcf80000000000000000000000000000000000000000000000000000000060005260046000fd5b80548210156133a75760005260206000200190600090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9190916020815282519283602083015260005b8481106134285750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b80602080928401015160408286010152016133e9565b60018101908260005281602052604060002054156000146134ac578054680100000000000000008110156125795761349761348082600187940185558461338f565b81939154906000199060031b92831b921b19161790565b90555491600052602052604060002055600190565b505050600090565b906001820191816000528260205260406000205480151560001461359657600019810181811161281c57825490600019820191821161281c5781810361355f575b5050508054801561353057600019019061350f828261338f565b60001982549160031b1b191690555560005260205260006040812055600190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b61357f61356f613480938661338f565b90549060031b1c9283928661338f565b9055600052836020526040600020553880806134f5565b5050505060009056","name":"FUSDGateway","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"paris","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"@openzeppelin/contracts/utils/structs/EnumerableSet.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.20;\n\nimport {Arrays} from \"../Arrays.sol\";\nimport {Math} from \"../math/Math.sol\";\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n * - Set can be cleared (all elements removed) in O(n).\n *\n * ```solidity\n * contract Example {\n *     // Add the library methods\n *     using EnumerableSet for EnumerableSet.AddressSet;\n *\n *     // Declare a set state variable\n *     EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * The following types are supported:\n *\n * - `bytes32` (`Bytes32Set`) since v3.3.0\n * - `address` (`AddressSet`) since v3.3.0\n * - `uint256` (`UintSet`) since v3.3.0\n * - `string` (`StringSet`) since v5.4.0\n * - `bytes` (`BytesSet`) since v5.4.0\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position is the index of the value in the `values` array plus 1.\n        // Position 0 is used to mean a value is not in the set.\n        mapping(bytes32 value => uint256) _positions;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._positions[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We cache the value's position to prevent multiple reads from the same storage slot\n        uint256 position = set._positions[value];\n\n        if (position != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 valueIndex = position - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (valueIndex != lastIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the lastValue to the index where the value to delete is\n                set._values[valueIndex] = lastValue;\n                // Update the tracked position of the lastValue (that was just moved)\n                set._positions[lastValue] = position;\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the tracked position for the deleted slot\n            delete set._positions[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes all the values from a set. O(n).\n     *\n     * WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that\n     * using it may render the function uncallable if the set grows to the point where clearing it consumes too much\n     * gas to fit in a block.\n     */\n    function _clear(Set storage set) private {\n        uint256 len = _length(set);\n        for (uint256 i = 0; i < len; ++i) {\n            delete set._positions[set._values[i]];\n        }\n        Arrays.unsafeSetLength(set._values, 0);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._positions[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    /**\n     * @dev Return a slice of the set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set, uint256 start, uint256 end) private view returns (bytes32[] memory) {\n        unchecked {\n            end = Math.min(end, _length(set));\n            start = Math.min(start, end);\n\n            uint256 len = end - start;\n            bytes32[] memory result = new bytes32[](len);\n            for (uint256 i = 0; i < len; ++i) {\n                result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n            }\n            return result;\n        }\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Removes all the values from a set. O(n).\n     *\n     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n     */\n    function clear(Bytes32Set storage set) internal {\n        _clear(set._inner);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        bytes32[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Return a slice of the set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set, uint256 start, uint256 end) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = _values(set._inner, start, end);\n        bytes32[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes all the values from a set. O(n).\n     *\n     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n     */\n    function clear(AddressSet storage set) internal {\n        _clear(set._inner);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Return a slice of the set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set, uint256 start, uint256 end) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner, start, end);\n        address[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes all the values from a set. O(n).\n     *\n     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n     */\n    function clear(UintSet storage set) internal {\n        _clear(set._inner);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Return a slice of the set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set, uint256 start, uint256 end) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner, start, end);\n        uint256[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    struct StringSet {\n        // Storage of set values\n        string[] _values;\n        // Position is the index of the value in the `values` array plus 1.\n        // Position 0 is used to mean a value is not in the set.\n        mapping(string value => uint256) _positions;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(StringSet storage set, string memory value) internal returns (bool) {\n        if (!contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._positions[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(StringSet storage set, string memory value) internal returns (bool) {\n        // We cache the value's position to prevent multiple reads from the same storage slot\n        uint256 position = set._positions[value];\n\n        if (position != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 valueIndex = position - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (valueIndex != lastIndex) {\n                string memory lastValue = set._values[lastIndex];\n\n                // Move the lastValue to the index where the value to delete is\n                set._values[valueIndex] = lastValue;\n                // Update the tracked position of the lastValue (that was just moved)\n                set._positions[lastValue] = position;\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the tracked position for the deleted slot\n            delete set._positions[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes all the values from a set. O(n).\n     *\n     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n     */\n    function clear(StringSet storage set) internal {\n        uint256 len = length(set);\n        for (uint256 i = 0; i < len; ++i) {\n            delete set._positions[set._values[i]];\n        }\n        Arrays.unsafeSetLength(set._values, 0);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(StringSet storage set, string memory value) internal view returns (bool) {\n        return set._positions[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(StringSet storage set) internal view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(StringSet storage set, uint256 index) internal view returns (string memory) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(StringSet storage set) internal view returns (string[] memory) {\n        return set._values;\n    }\n\n    /**\n     * @dev Return a slice of the set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(StringSet storage set, uint256 start, uint256 end) internal view returns (string[] memory) {\n        unchecked {\n            end = Math.min(end, length(set));\n            start = Math.min(start, end);\n\n            uint256 len = end - start;\n            string[] memory result = new string[](len);\n            for (uint256 i = 0; i < len; ++i) {\n                result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n            }\n            return result;\n        }\n    }\n\n    struct BytesSet {\n        // Storage of set values\n        bytes[] _values;\n        // Position is the index of the value in the `values` array plus 1.\n        // Position 0 is used to mean a value is not in the set.\n        mapping(bytes value => uint256) _positions;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(BytesSet storage set, bytes memory value) internal returns (bool) {\n        if (!contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._positions[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(BytesSet storage set, bytes memory value) internal returns (bool) {\n        // We cache the value's position to prevent multiple reads from the same storage slot\n        uint256 position = set._positions[value];\n\n        if (position != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 valueIndex = position - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (valueIndex != lastIndex) {\n                bytes memory lastValue = set._values[lastIndex];\n\n                // Move the lastValue to the index where the value to delete is\n                set._values[valueIndex] = lastValue;\n                // Update the tracked position of the lastValue (that was just moved)\n                set._positions[lastValue] = position;\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the tracked position for the deleted slot\n            delete set._positions[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes all the values from a set. O(n).\n     *\n     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n     */\n    function clear(BytesSet storage set) internal {\n        uint256 len = length(set);\n        for (uint256 i = 0; i < len; ++i) {\n            delete set._positions[set._values[i]];\n        }\n        Arrays.unsafeSetLength(set._values, 0);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(BytesSet storage set, bytes memory value) internal view returns (bool) {\n        return set._positions[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(BytesSet storage set) internal view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(BytesSet storage set, uint256 index) internal view returns (bytes memory) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(BytesSet storage set) internal view returns (bytes[] memory) {\n        return set._values;\n    }\n\n    /**\n     * @dev Return a slice of the set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(BytesSet storage set, uint256 start, uint256 end) internal view returns (bytes[] memory) {\n        unchecked {\n            end = Math.min(end, length(set));\n            start = Math.min(start, end);\n\n            uint256 len = end - start;\n            bytes[] memory result = new bytes[](len);\n            for (uint256 i = 0; i < len; ++i) {\n                result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n            }\n            return result;\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},{"file_path":"@openzeppelin/contracts/utils/Arrays.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/Arrays.sol)\n// This file was procedurally generated from scripts/generate/templates/Arrays.js.\n\npragma solidity ^0.8.20;\n\nimport {Comparators} from \"./Comparators.sol\";\nimport {SlotDerivation} from \"./SlotDerivation.sol\";\nimport {StorageSlot} from \"./StorageSlot.sol\";\nimport {Math} from \"./math/Math.sol\";\n\n/**\n * @dev Collection of functions related to array types.\n */\nlibrary Arrays {\n    using SlotDerivation for bytes32;\n    using StorageSlot for bytes32;\n\n    /**\n     * @dev Sort an array of uint256 (in memory) following the provided comparator function.\n     *\n     * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n     * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n     *\n     * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n     * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n     * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n     * consume more gas than is available in a block, leading to potential DoS.\n     *\n     * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n     */\n    function sort(\n        uint256[] memory array,\n        function(uint256, uint256) pure returns (bool) comp\n    ) internal pure returns (uint256[] memory) {\n        _quickSort(_begin(array), _end(array), comp);\n        return array;\n    }\n\n    /**\n     * @dev Variant of {sort} that sorts an array of uint256 in increasing order.\n     */\n    function sort(uint256[] memory array) internal pure returns (uint256[] memory) {\n        sort(array, Comparators.lt);\n        return array;\n    }\n\n    /**\n     * @dev Sort an array of address (in memory) following the provided comparator function.\n     *\n     * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n     * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n     *\n     * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n     * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n     * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n     * consume more gas than is available in a block, leading to potential DoS.\n     *\n     * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n     */\n    function sort(\n        address[] memory array,\n        function(address, address) pure returns (bool) comp\n    ) internal pure returns (address[] memory) {\n        sort(_castToUint256Array(array), _castToUint256Comp(comp));\n        return array;\n    }\n\n    /**\n     * @dev Variant of {sort} that sorts an array of address in increasing order.\n     */\n    function sort(address[] memory array) internal pure returns (address[] memory) {\n        sort(_castToUint256Array(array), Comparators.lt);\n        return array;\n    }\n\n    /**\n     * @dev Sort an array of bytes32 (in memory) following the provided comparator function.\n     *\n     * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n     * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n     *\n     * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n     * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n     * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n     * consume more gas than is available in a block, leading to potential DoS.\n     *\n     * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n     */\n    function sort(\n        bytes32[] memory array,\n        function(bytes32, bytes32) pure returns (bool) comp\n    ) internal pure returns (bytes32[] memory) {\n        sort(_castToUint256Array(array), _castToUint256Comp(comp));\n        return array;\n    }\n\n    /**\n     * @dev Variant of {sort} that sorts an array of bytes32 in increasing order.\n     */\n    function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {\n        sort(_castToUint256Array(array), Comparators.lt);\n        return array;\n    }\n\n    /**\n     * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops\n     * at end (exclusive). Sorting follows the `comp` comparator.\n     *\n     * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.\n     *\n     * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should\n     * be used only if the limits are within a memory array.\n     */\n    function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {\n        unchecked {\n            if (end - begin < 0x40) return;\n\n            // Use first element as pivot\n            uint256 pivot = _mload(begin);\n            // Position where the pivot should be at the end of the loop\n            uint256 pos = begin;\n\n            for (uint256 it = begin + 0x20; it < end; it += 0x20) {\n                if (comp(_mload(it), pivot)) {\n                    // If the value stored at the iterator's position comes before the pivot, we increment the\n                    // position of the pivot and move the value there.\n                    pos += 0x20;\n                    _swap(pos, it);\n                }\n            }\n\n            _swap(begin, pos); // Swap pivot into place\n            _quickSort(begin, pos, comp); // Sort the left side of the pivot\n            _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot\n        }\n    }\n\n    /**\n     * @dev Pointer to the memory location of the first element of `array`.\n     */\n    function _begin(uint256[] memory array) private pure returns (uint256 ptr) {\n        assembly (\"memory-safe\") {\n            ptr := add(array, 0x20)\n        }\n    }\n\n    /**\n     * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word\n     * that comes just after the last element of the array.\n     */\n    function _end(uint256[] memory array) private pure returns (uint256 ptr) {\n        unchecked {\n            return _begin(array) + array.length * 0x20;\n        }\n    }\n\n    /**\n     * @dev Load memory word (as a uint256) at location `ptr`.\n     */\n    function _mload(uint256 ptr) private pure returns (uint256 value) {\n        assembly {\n            value := mload(ptr)\n        }\n    }\n\n    /**\n     * @dev Swaps the elements memory location `ptr1` and `ptr2`.\n     */\n    function _swap(uint256 ptr1, uint256 ptr2) private pure {\n        assembly {\n            let value1 := mload(ptr1)\n            let value2 := mload(ptr2)\n            mstore(ptr1, value2)\n            mstore(ptr2, value1)\n        }\n    }\n\n    /// @dev Helper: low level cast address memory array to uint256 memory array\n    function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {\n        assembly {\n            output := input\n        }\n    }\n\n    /// @dev Helper: low level cast bytes32 memory array to uint256 memory array\n    function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {\n        assembly {\n            output := input\n        }\n    }\n\n    /// @dev Helper: low level cast address comp function to uint256 comp function\n    function _castToUint256Comp(\n        function(address, address) pure returns (bool) input\n    ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n        assembly {\n            output := input\n        }\n    }\n\n    /// @dev Helper: low level cast bytes32 comp function to uint256 comp function\n    function _castToUint256Comp(\n        function(bytes32, bytes32) pure returns (bool) input\n    ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n        assembly {\n            output := input\n        }\n    }\n\n    /**\n     * @dev Searches a sorted `array` and returns the first index that contains\n     * a value greater or equal to `element`. If no such index exists (i.e. all\n     * values in the array are strictly less than `element`), the array length is\n     * returned. Time complexity O(log n).\n     *\n     * NOTE: The `array` is expected to be sorted in ascending order, and to\n     * contain no repeated elements.\n     *\n     * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks\n     * support for repeated elements in the array. The {lowerBound} function should\n     * be used instead.\n     */\n    function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n        uint256 low = 0;\n        uint256 high = array.length;\n\n        if (high == 0) {\n            return 0;\n        }\n\n        while (low < high) {\n            uint256 mid = Math.average(low, high);\n\n            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n            // because Math.average rounds towards zero (it does integer division with truncation).\n            if (unsafeAccess(array, mid).value > element) {\n                high = mid;\n            } else {\n                low = mid + 1;\n            }\n        }\n\n        // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.\n        if (low > 0 && unsafeAccess(array, low - 1).value == element) {\n            return low - 1;\n        } else {\n            return low;\n        }\n    }\n\n    /**\n     * @dev Searches an `array` sorted in ascending order and returns the first\n     * index that contains a value greater or equal than `element`. If no such index\n     * exists (i.e. all values in the array are strictly less than `element`), the array\n     * length is returned. Time complexity O(log n).\n     *\n     * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].\n     */\n    function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n        uint256 low = 0;\n        uint256 high = array.length;\n\n        if (high == 0) {\n            return 0;\n        }\n\n        while (low < high) {\n            uint256 mid = Math.average(low, high);\n\n            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n            // because Math.average rounds towards zero (it does integer division with truncation).\n            if (unsafeAccess(array, mid).value < element) {\n                // this cannot overflow because mid < high\n                unchecked {\n                    low = mid + 1;\n                }\n            } else {\n                high = mid;\n            }\n        }\n\n        return low;\n    }\n\n    /**\n     * @dev Searches an `array` sorted in ascending order and returns the first\n     * index that contains a value strictly greater than `element`. If no such index\n     * exists (i.e. all values in the array are strictly less than `element`), the array\n     * length is returned. Time complexity O(log n).\n     *\n     * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].\n     */\n    function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n        uint256 low = 0;\n        uint256 high = array.length;\n\n        if (high == 0) {\n            return 0;\n        }\n\n        while (low < high) {\n            uint256 mid = Math.average(low, high);\n\n            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n            // because Math.average rounds towards zero (it does integer division with truncation).\n            if (unsafeAccess(array, mid).value > element) {\n                high = mid;\n            } else {\n                // this cannot overflow because mid < high\n                unchecked {\n                    low = mid + 1;\n                }\n            }\n        }\n\n        return low;\n    }\n\n    /**\n     * @dev Same as {lowerBound}, but with an array in memory.\n     */\n    function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n        uint256 low = 0;\n        uint256 high = array.length;\n\n        if (high == 0) {\n            return 0;\n        }\n\n        while (low < high) {\n            uint256 mid = Math.average(low, high);\n\n            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n            // because Math.average rounds towards zero (it does integer division with truncation).\n            if (unsafeMemoryAccess(array, mid) < element) {\n                // this cannot overflow because mid < high\n                unchecked {\n                    low = mid + 1;\n                }\n            } else {\n                high = mid;\n            }\n        }\n\n        return low;\n    }\n\n    /**\n     * @dev Same as {upperBound}, but with an array in memory.\n     */\n    function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n        uint256 low = 0;\n        uint256 high = array.length;\n\n        if (high == 0) {\n            return 0;\n        }\n\n        while (low < high) {\n            uint256 mid = Math.average(low, high);\n\n            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n            // because Math.average rounds towards zero (it does integer division with truncation).\n            if (unsafeMemoryAccess(array, mid) > element) {\n                high = mid;\n            } else {\n                // this cannot overflow because mid < high\n                unchecked {\n                    low = mid + 1;\n                }\n            }\n        }\n\n        return low;\n    }\n\n    /**\n     * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n     *\n     * WARNING: Only use if you are certain `pos` is lower than the array length.\n     */\n    function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {\n        bytes32 slot;\n        assembly (\"memory-safe\") {\n            slot := arr.slot\n        }\n        return slot.deriveArray().offset(pos).getAddressSlot();\n    }\n\n    /**\n     * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n     *\n     * WARNING: Only use if you are certain `pos` is lower than the array length.\n     */\n    function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {\n        bytes32 slot;\n        assembly (\"memory-safe\") {\n            slot := arr.slot\n        }\n        return slot.deriveArray().offset(pos).getBytes32Slot();\n    }\n\n    /**\n     * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n     *\n     * WARNING: Only use if you are certain `pos` is lower than the array length.\n     */\n    function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {\n        bytes32 slot;\n        assembly (\"memory-safe\") {\n            slot := arr.slot\n        }\n        return slot.deriveArray().offset(pos).getUint256Slot();\n    }\n\n    /**\n     * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n     *\n     * WARNING: Only use if you are certain `pos` is lower than the array length.\n     */\n    function unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) {\n        bytes32 slot;\n        assembly (\"memory-safe\") {\n            slot := arr.slot\n        }\n        return slot.deriveArray().offset(pos).getBytesSlot();\n    }\n\n    /**\n     * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n     *\n     * WARNING: Only use if you are certain `pos` is lower than the array length.\n     */\n    function unsafeAccess(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) {\n        bytes32 slot;\n        assembly (\"memory-safe\") {\n            slot := arr.slot\n        }\n        return slot.deriveArray().offset(pos).getStringSlot();\n    }\n\n    /**\n     * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n     *\n     * WARNING: Only use if you are certain `pos` is lower than the array length.\n     */\n    function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {\n        assembly {\n            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n        }\n    }\n\n    /**\n     * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n     *\n     * WARNING: Only use if you are certain `pos` is lower than the array length.\n     */\n    function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {\n        assembly {\n            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n        }\n    }\n\n    /**\n     * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n     *\n     * WARNING: Only use if you are certain `pos` is lower than the array length.\n     */\n    function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {\n        assembly {\n            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n        }\n    }\n\n    /**\n     * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n     *\n     * WARNING: Only use if you are certain `pos` is lower than the array length.\n     */\n    function unsafeMemoryAccess(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory res) {\n        assembly {\n            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n        }\n    }\n\n    /**\n     * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n     *\n     * WARNING: Only use if you are certain `pos` is lower than the array length.\n     */\n    function unsafeMemoryAccess(string[] memory arr, uint256 pos) internal pure returns (string memory res) {\n        assembly {\n            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n        }\n    }\n\n    /**\n     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n     *\n     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n     */\n    function unsafeSetLength(address[] storage array, uint256 len) internal {\n        assembly (\"memory-safe\") {\n            sstore(array.slot, len)\n        }\n    }\n\n    /**\n     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n     *\n     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n     */\n    function unsafeSetLength(bytes32[] storage array, uint256 len) internal {\n        assembly (\"memory-safe\") {\n            sstore(array.slot, len)\n        }\n    }\n\n    /**\n     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n     *\n     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n     */\n    function unsafeSetLength(uint256[] storage array, uint256 len) internal {\n        assembly (\"memory-safe\") {\n            sstore(array.slot, len)\n        }\n    }\n\n    /**\n     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n     *\n     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n     */\n    function unsafeSetLength(bytes[] storage array, uint256 len) internal {\n        assembly (\"memory-safe\") {\n            sstore(array.slot, len)\n        }\n    }\n\n    /**\n     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n     *\n     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n     */\n    function unsafeSetLength(string[] storage array, uint256 len) internal {\n        assembly (\"memory-safe\") {\n            sstore(array.slot, len)\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (access/extensions/IAccessControlEnumerable.sol)\n\npragma solidity >=0.8.4;\n\nimport {IAccessControl} from \"../IAccessControl.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC-165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n    /**\n     * @dev Returns one of the accounts that have `role`. `index` must be a\n     * value between 0 and {getRoleMemberCount}, non-inclusive.\n     *\n     * Role bearers are not sorted in any particular way, and their ordering may\n     * change at any point.\n     *\n     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n     * you perform all queries on the same block. See the following\n     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n     * for more information.\n     */\n    function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n    /**\n     * @dev Returns the number of accounts that have `role`. Can be used\n     * together with {getRoleMember} to enumerate all bearers of a role.\n     */\n    function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/access/IAccessControl.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (access/IAccessControl.sol)\n\npragma solidity >=0.8.4;\n\n/**\n * @dev External interface of AccessControl declared to support ERC-165 detection.\n */\ninterface IAccessControl {\n    /**\n     * @dev The `account` is missing a role.\n     */\n    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n    /**\n     * @dev The caller of a function is not the expected one.\n     *\n     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n     */\n    error AccessControlBadConfirmation();\n\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted to signal this.\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).\n     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165Upgradeable is Initializable, IERC165 {\n    function __ERC165_init() internal onlyInitializing {\n    }\n\n    function __ERC165_init_unchained() internal onlyInitializing {\n    }\n    /// @inheritdoc IERC165\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"},{"file_path":"contracts/interfaces/IFUSDGateway.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\n/**\n * @title IFUSDGateway\n * @notice FUSD Gateway contract interface.\n * @dev Defines events and functions for FUSD minting and burning operations.\n */\ninterface IFUSDGateway {\n    /// ==========================================\n    /// ============= Enum Definitions ===========\n    /// ==========================================\n\n    /**\n     * @notice Fee type enum for calculating fees for different operations.\n     * @dev Mint: Fee type for minting operations, Redeem: Fee type for redemption operations.\n     */\n    enum FeeType {\n        Mint, // Minting operation\n        Redeem // Redemption operation\n\n    }\n\n    /// ==========================================\n    /// ============= Error Definitions ==========\n    /// ==========================================\n\n    /**\n     * @notice Error thrown when an unsupported asset is used.\n     * @param asset The address of the unsupported asset.\n     */\n    error UnsupportedAsset(address asset);\n\n    /**\n     * @notice Error thrown when an invalid fee type is provided.\n     * @param feeType The invalid fee type.\n     */\n    error InvalidFeeType(uint8 feeType);\n\n    /**\n     * @notice Error thrown when an account has an insufficient balance.\n     * @param account The account address.\n     * @param available The available balance.\n     * @param required The required balance.\n     */\n    error InsufficientBalance(address account, uint256 available, uint256 required);\n\n    error RefundFailed();\n\n    error InvalidNativeTokenSender();\n\n    error CollateralAmountIsZero();\n    error RedeemAmountIsZero();\n\n    error ZeroFeeToAddress();\n\n    error ZeroTreasuryAddress();\n\n    error CustomMessageIdIsUsed(uint256 customMessageId);\n\n    error FeeRateTooHigh();\n\n    error ZeroAddress();\n\n    /// ==========================================\n    /// ============= Event Definitions ==========\n    /// ==========================================\n\n    /**\n     * @notice Event triggered when a user requests to redeem collateral assets.\n     * @param user The address of the user requesting redemption.\n     * @param amount The amount requested for redemption.\n     */\n    event RedeemRequested(address indexed user, uint256 amount);\n\n    /**\n     * @notice Event triggered when the minting fee rate is updated.\n     * @param oldRate The old minting fee rate.\n     * @param newRate The new minting fee rate.\n     */\n    event MintFeeRateUpdated(uint256 oldRate, uint256 newRate);\n\n    /**\n     * @notice Event triggered when the redemption fee rate is updated.\n     * @param oldRate The old redemption fee rate.\n     * @param newRate The new redemption fee rate.\n     */\n    event RedeemFeeRateUpdated(uint256 oldRate, uint256 newRate);\n\n    /**\n     * @notice Event triggered when the project directly mints tokens.\n     * @param toBytes32 The address receiving the minted tokens.\n     * @param amount The minted amount.\n     * @param destinationChainIdOrSelector The target chain ID or selector for cross-chain operations.\n     */\n    event DirectMint(bytes32 indexed toBytes32, uint256 amount, uint64 destinationChainIdOrSelector);\n\n    /**\n     * @notice Event triggered when the project directly burns tokens.\n     * @param from The address from which tokens are burned.\n     * @param amount The burned amount.\n     */\n    event DirectBurn(address indexed from, uint256 amount);\n\n    event MintWithCustomMessageId(bytes32 indexed customMessageId, address indexed to, uint256 amount);\n\n    /**\n     * @notice Event triggered when tokens are instantly minted using collateral.\n     * @param minter The address of the user initiating the mint.\n     * @param toBytes32 The address of the user minting the tokens.\n     * @param collateral The address of the collateral asset used.\n     * @param collateralAmount The amount of the collateral asset.\n     * @param fusdAmount The amount of FUSD minted.\n     * @param fee The fee collected.\n     * @param destinationChainIdOrSelector The target chain ID or selector for cross-chain operations.\n     */\n    event InstantMint(\n        address indexed minter,\n        bytes32 indexed toBytes32,\n        address indexed collateral,\n        uint256 collateralAmount,\n        uint256 fusdAmount,\n        uint256 fee,\n        uint64 destinationChainIdOrSelector\n    );\n\n    /**\n     * @notice Event triggered on instant token redemption.\n     * @param user The address of the user redeeming the tokens.\n     * @param toBytes32 The address receiving the redeemed collateral asset.\n     * @param collateral The address of the redeemed collateral asset.\n     * @param fusdAmount The amount of FUSD burned.\n     * @param collateralAmount The amount of collateral asset redeemed.\n     * @param fee The fee collected.\n     */\n    event InstantRedeem(\n        address indexed user,\n        bytes32 toBytes32,\n        address indexed collateral,\n        uint256 fusdAmount,\n        uint256 collateralAmount,\n        uint256 fee\n    );\n\n    /**\n     * @notice Event triggered when the fee recipient address is updated.\n     * @param oldFeeTo The old fee recipient address.\n     * @param newFeeTo The new fee recipient address.\n     */\n    event FeeToUpdated(address indexed oldFeeTo, address indexed newFeeTo);\n\n    event TreasuryUpdated(address indexed oldTreasury, address indexed newTreasury);\n\n    /// ==========================================\n    /// ============= Function Definitions =======\n    /// ==========================================\n\n    /**\n     * @notice Direct mint function for project operations.\n     * @param toBytes32 The address to receive the minted tokens.\n     * @param amount The amount to mint.\n     * @param destinationChainIdOrSelector The target chain ID or selector for cross-chain operations.\n     * @return messageId Returns the CCIP message ID, or custom chain message ID\n     */\n    function mint(bytes32 toBytes32, uint256 amount, uint64 destinationChainIdOrSelector)\n        external\n        payable\n        returns (bytes32 messageId);\n\n    /**\n     * @notice Direct burn function for project operations.\n     * @param amount The amount to burn.\n     */\n    function burn(uint256 amount) external;\n\n    function mintWithMessageId(bytes32 customMessageIdBytes32, address to, uint256 amount) external;\n\n    /**\n     * @notice User request to redeem collateral assets.\n     * @param amount The redemption amount.\n     */\n    function redeemRequest(uint256 amount) external;\n\n    /**\n     * @notice Instantly mint FUSD using collateral assets.\n     * @param toBytes32 The address to receive the minted tokens (bytes32 format for cross-chain).\n     * @param collateral The address of the collateral asset.\n     * @param collateralAmount The amount of the collateral asset.\n     * @param destinationChainIdOrSelector The target chain ID or selector for cross-chain operations.\n     * @return messageId Returns the CCIP message ID, or 0 for custom chains.\n     */\n    function instantMint(\n        bytes32 toBytes32,\n        address collateral,\n        uint256 collateralAmount,\n        uint64 destinationChainIdOrSelector\n    ) external payable returns (bytes32 messageId);\n\n    /**\n     * @notice Instantly redeem collateral assets using FUSD.\n     * @param toBytes32 The address to receive the redeemed collateral asset (bytes32 format for cross-chain).\n     * @param redeemCollateral The address of the collateral asset to redeem.\n     * @param FUSDAmountToBurn The amount of FUSD to redeem.\n     */\n    function instantRedeem(bytes32 toBytes32, address redeemCollateral, uint256 FUSDAmountToBurn) external;\n\n    /**\n     * @notice Previews the amount of FUSD that can be minted with a given collateral.\n     * @dev Calculates fees and the net mint amount.\n     * @param collateral The address of the collateral asset.\n     * @param collateralAmount The amount of the collateral asset (18 decimal precision).\n     * @return mintAmount The amount of FUSD that can be minted (18 decimal precision).\n     * @return netAmount The net amount of collateral after fees (18 decimal precision).\n     * @return fee The fee amount in terms of the collateral asset (18 decimal precision).\n     */\n    function previewMint(address collateral, uint256 collateralAmount)\n        external\n        view\n        returns (uint256 mintAmount, uint256 netAmount, uint256 fee);\n\n    /**\n     * @notice Previews a redemption operation.\n     * @param collateral The address of the collateral asset to redeem.\n     * @param FUSDAmountToBurn The amount of FUSD to be burned.\n     * @return redeemAmount The amount of the asset that can be redeemed.\n     * @return fee The fee amount in terms of the asset.\n     */\n    function previewRedeem(address collateral, uint256 FUSDAmountToBurn)\n        external\n        view\n        returns (uint256 redeemAmount, uint256 fee);\n\n    /**\n     * @notice Converts a collateral asset amount to a FUSD amount.\n     * @param collateral The address of the collateral asset.\n     * @param amount The amount of the collateral asset (18 decimal precision).\n     * @return The amount of FUSD that can be minted (18 decimal precision).\n     */\n    function convertFromCollateral(address collateral, uint256 amount) external view returns (uint256);\n\n    /**\n     * @notice Converts a FUSD amount to a collateral asset amount.\n     * @param collateral The address of the collateral asset.\n     * @param amount The amount of FUSD (18 decimal precision).\n     * @return The amount of collateral asset that can be redeemed (18 decimal precision).\n     */\n    function convertToCollateral(address collateral, uint256 amount) external view returns (uint256);\n\n    /**\n     * @notice Calculates the fee for a given amount and fee type.\n     * @param amount The base amount to calculate the fee on.\n     * @param feeType The fee type (Mint or Redeem).\n     * @return The calculated fee amount.\n     */\n    function calculateFee(uint256 amount, FeeType feeType) external view returns (uint256);\n\n    /**\n     * @notice Updates the minting fee rate.\n     * @param newRate The new minting fee rate.\n     */\n    function updateMintFeeRate(uint256 newRate) external;\n\n    /**\n     * @notice Updates the redemption fee rate.\n     * @param newRate The new redemption fee rate.\n     */\n    function updateRedeemFeeRate(uint256 newRate) external;\n\n    /**\n     * @notice Sets the fee recipient address.\n     * @param newFeeTo The new address to receive fees.\n     */\n    function setFeeTo(address newFeeTo) external;\n\n    /**\n     * @notice Pauses the contract's functions.\n     */\n    function pause() external;\n\n    /**\n     * @notice Resumes the contract's functions.\n     */\n    function unpause() external;\n\n    /**\n     * @notice Sets the treasury address.\n     * @param newTreasury The new treasury address.\n     */\n    function setTreasury(address newTreasury) external;\n\n    function isCustomMessageIdUsed(uint256 _customMessageId) external view returns (bool);\n}\n"},{"file_path":"contracts/interfaces/IFUSDLP.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\n/**\n * @title IFUSDLP\n * @notice FUSDLP (Staked Real World Assets) contract interface\n * @dev Defines functions for FUSDLP token operations and reserve management\n */\ninterface IFUSDLP {\n    /// ==========================================\n    /// ============= Enum Definitions ===================\n    /// ==========================================\n\n    /**\n     * @notice Fee type enumeration\n     * @dev Used to distinguish fee types for different operations\n     */\n    enum FeeType {\n        Deposit, // Deposit fee\n        Withdraw, // Withdraw fee\n        Redeem // Redeem fee\n\n    }\n    /// ==========================================\n    /// ============= Error Definitions ===================\n    /// ==========================================\n\n    /**\n     * @notice Error thrown when array lengths do not match\n     * @dev This error is triggered when the lengths of array parameters passed in are inconsistent\n     */\n    error InvalidArrayLength();\n\n    /**\n     * @notice Error thrown when an asset is not supported\n     * @dev This error is triggered when trying to operate on an unconfigured reserve asset\n     * @param assetKey The identifier of the unsupported asset\n     */\n    error AssetNotSupported(bytes32 assetKey);\n\n    /**\n     * @notice Error thrown when the total ratio is invalid\n     * @dev This error is triggered when the sum of reserve asset ratios does not equal 100%\n     * @param totalRatio The invalid total ratio value (should be 1,000,000 for 100%)\n     */\n    error InvalidTotalRatio(uint256 totalRatio);\n\n    /**\n     * @notice Error thrown for invalid fee type\n     * @dev This error is triggered when an invalid fee type is passed\n     */\n    error InvalidFeeType();\n\n    /**\n     * @notice Error thrown when refund fails\n     * @dev This error is triggered when refunding native tokens fails\n     */\n    error RefundFailed();\n\n    /**\n     * @notice Invalid native token sender\n     * @dev This error is triggered when a non-bridgeSender sends native tokens\n     */\n    error InvalidNativeTokenSender();\n\n    error ZeroFeeToAddress();\n\n    error ZeroTreasuryAddress();\n\n    error CustomMessageIdIsUsed(uint256 customMessageId);\n\n    error AssetKeysDuplicate(bytes32 assetKey);\n\n    error BelowMinimumCombinationAmount(uint256 amount);\n\n    error FeeRateTooHigh();\n\n    error RatioIsZero(bytes32 assetKey);\n\n    error ZeroAddress();\n\n    /// ==========================================\n    /// ============= Event Definitions ===================\n    /// ==========================================\n\n    /**\n     * @notice Event triggered when a reserve asset ratio is updated\n     * @dev Triggered when the admin updates the allocation ratio of a reserve asset\n     * @param assetKey The identifier of the asset whose ratio is updated\n     * @param newRatio The new asset allocation ratio (1,000,000 = 100%)\n     */\n    event ReserveRatioUpdated(bytes32 indexed assetKey, uint256 newRatio);\n\n    /**\n     * @notice Event triggered when a price feed is updated\n     * @dev Triggered when the admin sets a new price oracle for a reserve asset\n     * @param assetKey The identifier of the asset whose price feed is updated\n     * @param oldFeed The old price feed contract address\n     * @param newFeed The new price feed contract address\n     */\n    event PriceFeedUpdated(bytes32 indexed assetKey, address indexed oldFeed, address indexed newFeed);\n\n    /**\n     * @notice Event triggered when assets are deposited\n     * @dev Triggered when a user successfully deposits reserve assets and receives LP tokens\n     * @param depositor The address of the user who initiated the deposit\n     * @param toBytes32 The address of the user who deposited the assets\n     * @param assetKeys Array of deposited asset identifiers\n     * @param amounts Array of corresponding deposit amounts (18 decimals precision)\n     * @param shares The number of LP tokens the user received (18 decimals precision)\n     * @param destinationChainIdOrSelector The destination chain ID or selector, 0 for no cross-chain\n     */\n    event AssetsDeposited(\n        address indexed depositor,\n        bytes32 indexed toBytes32,\n        bytes32[] assetKeys,\n        uint256[] amounts,\n        uint256 shares,\n        uint64 destinationChainIdOrSelector\n    );\n\n    /**\n     * @notice Event triggered when assets are withdrawn\n     * @dev Triggered when a user successfully redeems reserve assets and burns LP tokens\n     * @param user The address of the user who redeemed the assets\n     * @param assetKeys Array of redeemed asset identifiers\n     * @param amounts Array of corresponding redemption amounts (18 decimals precision)\n     * @param shares The number of LP tokens the user burned (18 decimals precision)\n     */\n    event AssetsWithdrawn(\n        address indexed user, bytes32 indexed toBytes32, bytes32[] assetKeys, uint256[] amounts, uint256 shares\n    );\n\n    /**\n     * @notice Event triggered when a reserve asset address is set\n     * @dev Triggered when the admin sets the mapping between an asset key and an ERC20 contract address\n     * @param assetKey The reserve asset identifier\n     * @param assetAddress The ERC20 contract address\n     */\n    event ReserveAssetSet(bytes32 indexed assetKey, address indexed assetAddress);\n\n    /**\n     * @notice Event triggered when the deposit fee is updated\n     * @dev Triggered when the admin updates the deposit fee\n     * @param oldFee The old deposit fee\n     * @param newFee The new deposit fee\n     */\n    event DepositFeeUpdated(uint256 oldFee, uint256 newFee);\n\n    /**\n     * @notice Event triggered when the redeem fee is updated\n     * @dev Triggered when the admin updates the redeem fee\n     * @param oldFee The old redeem fee\n     * @param newFee The new redeem fee\n     */\n    event RedeemFeeUpdated(uint256 oldFee, uint256 newFee);\n\n    event FeeToUpdated(address indexed oldFeeTo, address indexed newFeeTo);\n\n    event ReserveTreasuryUpdated(address indexed oldTreasury, address indexed newTreasury);\n\n    event MintWithCustomMessageId(bytes32 indexed customMessageId, address indexed to, uint256 amount);\n\n    event MinimumCombinationAmountUpdated(uint256 oldAmount, uint256 newAmount);\n\n    /// ==========================================\n    /// ============= Function Definitions ===================\n    /// ==========================================\n\n    /**\n     * @notice Gets the current exchange rate of FUSDLP tokens to USD\n     * @dev Returns the USD value of 1 LP token\n     * @return exchangeRate The exchange rate, represented with 18 decimals (1e18 = 1 USD)\n     */\n    function getExchangeRate() external view returns (uint256 exchangeRate);\n\n    /**\n     * @notice  Gets the adjusted exchange rate of FUSDLP tokens to USD\n     * @dev     Returns the adjusted USD value of 1 LP token considering recent reserve changes\n     * @return  uint256  The adjusted exchange rate, represented with 18 decimals (1e18 = 1 USD)\n     */\n    function getExchangeRateWithAdjustment() external view returns (uint256);\n\n    /**\n     * @notice Mints tokens to a specified address\n     * @dev Only callable by accounts with MINTER_ROLE when not paused\n     * @param to Address to receive the minted tokens\n     * @param amount Amount of tokens to mint\n     */\n    function mint(address to, uint256 amount) external;\n\n    /**\n     * @notice Burns tokens from the caller's balance\n     * @param amount Amount of tokens to burn\n     */\n    function burn(uint256 amount) external;\n\n    function mintWithCustomMessageId(bytes32 customMessageIdBytes32, address to, uint256 amount) external;\n\n    /**\n     * @notice Deposit a basket of reserve assets and mint FUSDLP tokens\n     * @dev Validates reserve asset ratios and transfers assets to treasury, then mints corresponding LP tokens\n     * @dev Requires user to have passed KYC verification, contract not paused, and provided asset ratios to exactly match configured ratios\n     * @param combinationAmounts The amounts of a combination of reserves(reserveA-reserveB-...) to deposit (18 decimal precision)\n     * @param destinationChainIdOrSelector Destination chain ID or selector, 0 means no cross-chain\n     */\n    function deposit(bytes32 toBytes32, uint256 combinationAmounts, uint64 destinationChainIdOrSelector)\n        external\n        payable\n        returns (bytes32 messageId);\n\n    /**\n     * @notice Previews the result of a deposit operation\n     * @dev Calculates the number of LP tokens and the fee for depositing a specified amount of assets\n     * @param combinationAmounts The amounts of a combination of reserves(reserveA-reserveB-...) to deposit (18 decimal precision)\n     * @return assetKeys Array of reserve asset identifiers\n     * @return assetAddresses Array of reserve asset ERC20 contract addresses\n     * @return amounts Array of reserve asset amounts the user needs to deposit\n     * @return netShares The number of LP tokens the user will receive after deducting the fee\n     * @return feeAmount The fee amount for the deposit operation\n     */\n    function previewDeposit(uint256 combinationAmounts)\n        external\n        view\n        returns (\n            bytes32[] memory assetKeys,\n            address[] memory assetAddresses,\n            uint256[] memory amounts,\n            uint256 netShares,\n            uint256 feeAmount\n        );\n\n    /**\n     * @notice Redeems a basket of reserve assets and burns FUSDLP tokens\n     * @dev The user burns a specified number of LP tokens to receive all reserve assets proportionally\n     * @dev Requires the user to have passed KYC verification and the contract not to be paused.\n     * @param toBytes32 The address to receive the redeemed reserve assets\n     * @param shares The number of FUSDLP tokens to burn (18 decimals precision)\n     */\n    function redeem(bytes32 toBytes32, uint256 shares) external;\n\n    /**\n     * @notice Previews the result of a redeem operation\n     * @dev Calculates the amount of reserve assets and the fee for burning a specified number of LP tokens\n     * @param shares The number of FUSDLP tokens to burn (18 decimals precision)\n     * @return assetKeys Array of reserve asset identifiers\n     * @return assetAddresses Array of reserve asset ERC20 contract addresses\n     * @return amounts Array of reserve asset amounts the user will receive\n     * @return feeAmount The fee amount for the redeem operation\n     */\n    function previewRedeem(uint256 shares)\n        external\n        view\n        returns (\n            bytes32[] memory assetKeys,\n            address[] memory assetAddresses,\n            uint256[] memory amounts,\n            uint256 feeAmount\n        );\n\n    /**\n     * @notice Calculates the operation fee\n     * @dev Calculates the corresponding fee based on the operation type and amount\n     * @param amount The operation amount\n     * @param feeType The fee type (Deposit, Withdraw, or Redeem)\n     * @return fee The fee amount\n     */\n    function calculateFee(uint256 amount, FeeType feeType) external view returns (uint256 fee);\n\n    /**\n     * @notice  Sets comprehensive information of reserve assets\n     * @dev     Sets the mapping between reserve asset identifiers and their ERC20 contract addresses, allocation ratios, and price feed contracts.\n     * @param   assetKeys  Array of reserve asset identifiers\n     * @param   assetAddresses  Array of corresponding ERC20 contract addresses\n     * @param   ratio  Array of corresponding allocation ratios (1,000,000 = 100%)\n     * @param   priceFeed  Array of corresponding price feed contract addresses\n     */\n    function setReservesInfo(\n        bytes32[] calldata assetKeys,\n        address[] calldata assetAddresses,\n        uint256[] calldata ratio,\n        address[] calldata priceFeed\n    ) external;\n\n    /**\n     * @notice Gets comprehensive information of all reserve assets\n     * @dev Returns detailed information of all configured reserve assets, including identifiers, ratios, current values, etc.\n     * @return assetKeys Array of reserve asset identifiers\n     * @return assetAddresses Array of reserve asset ERC20 contract addresses\n     * @return ratios Array of corresponding allocation ratios (1,000,000 = 100%)\n     * @return values Array of corresponding current USD values (18 decimals precision)\n     * @return totalValue The total USD value of all reserve assets (18 decimals precision)\n     * @return updateAt The last update timestamp\n     */\n    function getTotalReservesInfo()\n        external\n        view\n        returns (\n            bytes32[] memory assetKeys,\n            address[] memory assetAddresses,\n            uint256[] memory ratios,\n            uint256[] memory values,\n            uint256 totalValue,\n            uint256 updateAt\n        );\n\n    /**\n     * @notice Gets the reserve asset allocation ratios\n     * @dev Queries the current allocation ratio of specified reserve assets\n     * @param assetKeys Array of reserve asset identifiers\n     * @return ratios Array of corresponding allocation ratios (1,000,000 = 100%)\n     */\n    function getReservesRatio(bytes32[] calldata assetKeys) external view returns (uint256[] memory ratios);\n\n    /**\n     * @notice Gets the price feed contract for a reserve asset\n     * @dev Queries the price oracle contract address for a specified reserve asset\n     * @param assetKey The reserve asset identifier\n     * @return priceFeed The price feed contract address\n     */\n    function getReservePriceFeed(bytes32 assetKey) external view returns (address priceFeed);\n\n    /**\n     * @notice Updates the deposit fee\n     * @dev Only callable by the admin. Updates the fee rate for deposit operations.\n     * @param _depositFee The new deposit fee rate\n     */\n    function updateDepositFee(uint256 _depositFee) external;\n\n    /**\n     * @notice Updates the redeem fee\n     * @dev Only callable by the admin. Updates the fee rate for redeem operations.\n     * @param _redeemFee The new redeem fee rate\n     */\n    function updateRedeemFee(uint256 _redeemFee) external;\n\n    /**\n     * @notice Sets the fee recipient address\n     * @dev Only callable by the admin. Sets the address that will receive the fees.\n     * @param _feeTo The address to receive the fees\n     */\n    function setFeeTo(address _feeTo) external;\n\n    /**\n     * @notice Sets the reserve treasury address\n     * @dev Only callable by the admin. Sets the address where reserve assets are stored.\n     * @param _reserveTreasury The new reserve treasury address\n     */\n    function setReserveTreasury(address _reserveTreasury) external;\n\n    /**\n     * @notice Gets the CCIP admin address\n     * @dev Returns the address that has admin permissions for CCIP operations\n     * @return admin The CCIP admin address\n     */\n    function getCCIPAdmin() external view returns (address admin);\n\n    /**\n     * @notice Gets the total USD value of specified reserve assets and amounts\n     * @dev Calculates the total USD value of specified asset arrays and corresponding amounts, used for value calculation during deposit and redemption.\n     * @param assetKeys Array of reserve asset identifiers\n     * @param amounts Array of corresponding amounts (18 decimals precision)\n     * @return totalValue The total USD value represented with 18 decimals\n     */\n    function getReservesValue(bytes32[] memory assetKeys, uint256[] memory amounts)\n        external\n        view\n        returns (uint256 totalValue);\n\n    /**\n     * @notice Gets the USD value of a specific reserve asset amount\n     * @dev Calculates the USD value of a single reserve asset through the price oracle\n     * @param assetKey The reserve asset identifier\n     * @param amount The reserve asset amount (18 decimals precision)\n     * @return value The USD value represented with 18 decimals\n     */\n    function getReserveValue(bytes32 assetKey, uint256 amount) external view returns (uint256 value);\n\n    /**\n     * @notice Gets the ERC20 contract address of a reserve asset\n     * @dev Queries the ERC20 contract address corresponding to a specified asset key\n     * @param assetKey The reserve asset identifier\n     * @return assetAddress The ERC20 contract address\n     */\n    function getReserveAddress(bytes32 assetKey) external view returns (address assetAddress);\n\n    /**\n     * @notice Pauses the contract functions\n     * @dev Only callable by an account with the PAUSER_ROLE. Pauses deposit and redeem functions.\n     */\n    function pause() external;\n\n    /**\n     * @notice Unpauses the contract functions\n     * @dev Only callable by an account with the PAUSER_ROLE. Resumes deposit and redeem functions.\n     */\n    function unpause() external;\n\n    /**\n     * @notice Sets the minimum combination amount for deposit operations\n     * @dev Only callable by the admin. Sets the minimum amount of combination for deposit operations.\n     * @param _minimumCombinationAmount The new minimum combination amount\n     */\n    function setMinimumCombinationAmount(uint256 _minimumCombinationAmount) external;\n\n    /**\n     * @notice Gets all asset keys and their corresponding addresses\n     * @dev Returns the asset keys and ERC20 contract addresses for all configured reserve assets\n     * @return assetKeys Array of reserve asset identifiers\n     * @return assetAddresses Array of corresponding ERC20 contract addresses\n     */\n    function getAssetKeysAndAddress()\n        external\n        view\n        returns (bytes32[] memory assetKeys, address[] memory assetAddresses);\n\n    function isCustomMessageIdUsed(uint256 _customMessageId) external view returns (bool);\n}\n"},{"file_path":"contracts/utils/TokenDecimalsConvert.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {IERC20Metadata, IERC20} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nlibrary TokenDecimalsConvert {\n    function to18Decimals(uint256 amount, address token) internal view returns (uint256) {\n        uint8 decimals = IERC20Metadata(token).decimals();\n        return amount * (10 ** (18 - uint256(decimals)));\n    }\n\n    function from18Decimals(uint256 amount, address token) internal view returns (uint256) {\n        uint8 decimals = IERC20Metadata(token).decimals();\n        uint256 amountWithTokenDecimals = amount / (10 ** (18 - uint256(decimals)));\n        if (amountWithTokenDecimals == 0) {\n            revert(\"TokenDecimalsConvert: amount is too small\");\n        }\n        return amountWithTokenDecimals;\n    }\n}\n"},{"file_path":"@chainlink/contracts-ccip/contracts/libraries/MerkleMultiProof.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.4;\n\nlibrary MerkleMultiProof {\n  /// @notice Leaf domain separator, should be used as the first 32 bytes of a leaf's preimage.\n  bytes32 internal constant LEAF_DOMAIN_SEPARATOR = 0x0000000000000000000000000000000000000000000000000000000000000000;\n  /// @notice Internal domain separator, should be used as the first 32 bytes of an internal node's preimage.\n  bytes32 internal constant INTERNAL_DOMAIN_SEPARATOR =\n    0x0000000000000000000000000000000000000000000000000000000000000001;\n\n  uint256 internal constant MAX_NUM_HASHES = 256;\n\n  error InvalidProof();\n  error LeavesCannotBeEmpty();\n\n  /// @notice Computes the root based on provided pre-hashed leaf nodes in leaves, internal nodes  in proofs, and using\n  /// proofFlagBits' i-th bit to determine if an element of proofs or one of the previously computed leafs or internal\n  /// nodes will be used for the i-th hash.\n  /// @param leaves Should be pre-hashed and the first 32 bytes of a leaf's preimage should match LEAF_DOMAIN_SEPARATOR.\n  /// @param proofs Hashes to be used instead of a leaf hash when the proofFlagBits indicates a proof should be used.\n  /// @param proofFlagBits A single uint256 of which each bit indicates whether a leaf or a proof needs to be used in\n  /// a hash operation.\n  /// @dev the maximum number of hash operations it set to 256. Any input that would require more than 256 hashes to get\n  /// to a root will revert.\n  /// @dev For given input `leaves` = [a,b,c] `proofs` = [D] and `proofFlagBits` = 5\n  ///     totalHashes = 3 + 1 - 1 = 3\n  ///  ** round 1 **\n  ///    proofFlagBits = (5 >> 0) & 1 = true\n  ///    hashes[0] = hashPair(a, b)\n  ///    (leafPos, hashPos, proofPos) = (2, 0, 0);\n  ///\n  ///  ** round 2 **\n  ///    proofFlagBits = (5 >> 1) & 1 = false\n  ///    hashes[1] = hashPair(D, c)\n  ///    (leafPos, hashPos, proofPos) = (3, 0, 1);\n  ///\n  ///  ** round 3 **\n  ///    proofFlagBits = (5 >> 2) & 1 = true\n  ///    hashes[2] = hashPair(hashes[0], hashes[1])\n  ///    (leafPos, hashPos, proofPos) = (3, 2, 1);\n  ///\n  ///    i = 3 and no longer < totalHashes. The algorithm is done\n  ///    return hashes[totalHashes - 1] = hashes[2]; the last hash we computed.\n  // We mark this function as internal to force it to be inlined in contracts that use it, but semantically it is public.\n  function _merkleRoot(\n    bytes32[] memory leaves,\n    bytes32[] memory proofs,\n    uint256 proofFlagBits\n  ) internal pure returns (bytes32) {\n    unchecked {\n      uint256 leavesLen = leaves.length;\n      uint256 proofsLen = proofs.length;\n      if (leavesLen == 0) revert LeavesCannotBeEmpty();\n      if (!(leavesLen <= MAX_NUM_HASHES + 1 && proofsLen <= MAX_NUM_HASHES + 1)) revert InvalidProof();\n      uint256 totalHashes = leavesLen + proofsLen - 1;\n      if (!(totalHashes <= MAX_NUM_HASHES)) revert InvalidProof();\n      if (totalHashes == 0) {\n        return leaves[0];\n      }\n      bytes32[] memory hashes = new bytes32[](totalHashes);\n      (uint256 leafPos, uint256 hashPos, uint256 proofPos) = (0, 0, 0);\n\n      for (uint256 i = 0; i < totalHashes; ++i) {\n        // Checks if the bit flag signals the use of a supplied proof or a leaf/previous hash.\n        bytes32 a;\n        if (proofFlagBits & (1 << i) == (1 << i)) {\n          // Use a leaf or a previously computed hash.\n          if (leafPos < leavesLen) {\n            a = leaves[leafPos++];\n          } else {\n            a = hashes[hashPos++];\n          }\n        } else {\n          // Use a supplied proof.\n          a = proofs[proofPos++];\n        }\n\n        // The second part of the hashed pair is never a proof as hashing two proofs would result in a\n        // hash that can already be computed offchain.\n        bytes32 b;\n        if (leafPos < leavesLen) {\n          b = leaves[leafPos++];\n        } else {\n          b = hashes[hashPos++];\n        }\n\n        if (!(hashPos <= i)) revert InvalidProof();\n\n        hashes[i] = _hashPair(a, b);\n      }\n      if (!(hashPos == totalHashes - 1 && leafPos == leavesLen && proofPos == proofsLen)) revert InvalidProof();\n      // Return the last hash.\n      return hashes[totalHashes - 1];\n    }\n  }\n\n  /// @notice Hashes two bytes32 objects in their given order, prepended by the INTERNAL_DOMAIN_SEPARATOR.\n  function _hashInternalNode(bytes32 left, bytes32 right) private pure returns (bytes32 hash) {\n    return keccak256(abi.encode(INTERNAL_DOMAIN_SEPARATOR, left, right));\n  }\n\n  /// @notice Hashes two bytes32 objects. The order is taken into account, using the lower value first.\n  function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\n    return a < b ? _hashInternalNode(a, b) : _hashInternalNode(b, a);\n  }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/math/SafeCast.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n    /**\n     * @dev Value doesn't fit in an uint of `bits` size.\n     */\n    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n    /**\n     * @dev An int value doesn't fit in an uint of `bits` size.\n     */\n    error SafeCastOverflowedIntToUint(int256 value);\n\n    /**\n     * @dev Value doesn't fit in an int of `bits` size.\n     */\n    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n    /**\n     * @dev An uint value doesn't fit in an int of `bits` size.\n     */\n    error SafeCastOverflowedUintToInt(uint256 value);\n\n    /**\n     * @dev Returns the downcasted uint248 from uint256, reverting on\n     * overflow (when the input is greater than largest uint248).\n     *\n     * Counterpart to Solidity's `uint248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     */\n    function toUint248(uint256 value) internal pure returns (uint248) {\n        if (value > type(uint248).max) {\n            revert SafeCastOverflowedUintDowncast(248, value);\n        }\n        return uint248(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint240 from uint256, reverting on\n     * overflow (when the input is greater than largest uint240).\n     *\n     * Counterpart to Solidity's `uint240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     */\n    function toUint240(uint256 value) internal pure returns (uint240) {\n        if (value > type(uint240).max) {\n            revert SafeCastOverflowedUintDowncast(240, value);\n        }\n        return uint240(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint232 from uint256, reverting on\n     * overflow (when the input is greater than largest uint232).\n     *\n     * Counterpart to Solidity's `uint232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     */\n    function toUint232(uint256 value) internal pure returns (uint232) {\n        if (value > type(uint232).max) {\n            revert SafeCastOverflowedUintDowncast(232, value);\n        }\n        return uint232(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint224 from uint256, reverting on\n     * overflow (when the input is greater than largest uint224).\n     *\n     * Counterpart to Solidity's `uint224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toUint224(uint256 value) internal pure returns (uint224) {\n        if (value > type(uint224).max) {\n            revert SafeCastOverflowedUintDowncast(224, value);\n        }\n        return uint224(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint216 from uint256, reverting on\n     * overflow (when the input is greater than largest uint216).\n     *\n     * Counterpart to Solidity's `uint216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     */\n    function toUint216(uint256 value) internal pure returns (uint216) {\n        if (value > type(uint216).max) {\n            revert SafeCastOverflowedUintDowncast(216, value);\n        }\n        return uint216(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint208 from uint256, reverting on\n     * overflow (when the input is greater than largest uint208).\n     *\n     * Counterpart to Solidity's `uint208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     */\n    function toUint208(uint256 value) internal pure returns (uint208) {\n        if (value > type(uint208).max) {\n            revert SafeCastOverflowedUintDowncast(208, value);\n        }\n        return uint208(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint200 from uint256, reverting on\n     * overflow (when the input is greater than largest uint200).\n     *\n     * Counterpart to Solidity's `uint200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     */\n    function toUint200(uint256 value) internal pure returns (uint200) {\n        if (value > type(uint200).max) {\n            revert SafeCastOverflowedUintDowncast(200, value);\n        }\n        return uint200(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint192 from uint256, reverting on\n     * overflow (when the input is greater than largest uint192).\n     *\n     * Counterpart to Solidity's `uint192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     */\n    function toUint192(uint256 value) internal pure returns (uint192) {\n        if (value > type(uint192).max) {\n            revert SafeCastOverflowedUintDowncast(192, value);\n        }\n        return uint192(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint184 from uint256, reverting on\n     * overflow (when the input is greater than largest uint184).\n     *\n     * Counterpart to Solidity's `uint184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     */\n    function toUint184(uint256 value) internal pure returns (uint184) {\n        if (value > type(uint184).max) {\n            revert SafeCastOverflowedUintDowncast(184, value);\n        }\n        return uint184(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint176 from uint256, reverting on\n     * overflow (when the input is greater than largest uint176).\n     *\n     * Counterpart to Solidity's `uint176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     */\n    function toUint176(uint256 value) internal pure returns (uint176) {\n        if (value > type(uint176).max) {\n            revert SafeCastOverflowedUintDowncast(176, value);\n        }\n        return uint176(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint168 from uint256, reverting on\n     * overflow (when the input is greater than largest uint168).\n     *\n     * Counterpart to Solidity's `uint168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     */\n    function toUint168(uint256 value) internal pure returns (uint168) {\n        if (value > type(uint168).max) {\n            revert SafeCastOverflowedUintDowncast(168, value);\n        }\n        return uint168(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint160 from uint256, reverting on\n     * overflow (when the input is greater than largest uint160).\n     *\n     * Counterpart to Solidity's `uint160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     */\n    function toUint160(uint256 value) internal pure returns (uint160) {\n        if (value > type(uint160).max) {\n            revert SafeCastOverflowedUintDowncast(160, value);\n        }\n        return uint160(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint152 from uint256, reverting on\n     * overflow (when the input is greater than largest uint152).\n     *\n     * Counterpart to Solidity's `uint152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     */\n    function toUint152(uint256 value) internal pure returns (uint152) {\n        if (value > type(uint152).max) {\n            revert SafeCastOverflowedUintDowncast(152, value);\n        }\n        return uint152(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint144 from uint256, reverting on\n     * overflow (when the input is greater than largest uint144).\n     *\n     * Counterpart to Solidity's `uint144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     */\n    function toUint144(uint256 value) internal pure returns (uint144) {\n        if (value > type(uint144).max) {\n            revert SafeCastOverflowedUintDowncast(144, value);\n        }\n        return uint144(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint136 from uint256, reverting on\n     * overflow (when the input is greater than largest uint136).\n     *\n     * Counterpart to Solidity's `uint136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     */\n    function toUint136(uint256 value) internal pure returns (uint136) {\n        if (value > type(uint136).max) {\n            revert SafeCastOverflowedUintDowncast(136, value);\n        }\n        return uint136(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        if (value > type(uint128).max) {\n            revert SafeCastOverflowedUintDowncast(128, value);\n        }\n        return uint128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint120 from uint256, reverting on\n     * overflow (when the input is greater than largest uint120).\n     *\n     * Counterpart to Solidity's `uint120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     */\n    function toUint120(uint256 value) internal pure returns (uint120) {\n        if (value > type(uint120).max) {\n            revert SafeCastOverflowedUintDowncast(120, value);\n        }\n        return uint120(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint112 from uint256, reverting on\n     * overflow (when the input is greater than largest uint112).\n     *\n     * Counterpart to Solidity's `uint112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     */\n    function toUint112(uint256 value) internal pure returns (uint112) {\n        if (value > type(uint112).max) {\n            revert SafeCastOverflowedUintDowncast(112, value);\n        }\n        return uint112(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint104 from uint256, reverting on\n     * overflow (when the input is greater than largest uint104).\n     *\n     * Counterpart to Solidity's `uint104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     */\n    function toUint104(uint256 value) internal pure returns (uint104) {\n        if (value > type(uint104).max) {\n            revert SafeCastOverflowedUintDowncast(104, value);\n        }\n        return uint104(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint96 from uint256, reverting on\n     * overflow (when the input is greater than largest uint96).\n     *\n     * Counterpart to Solidity's `uint96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toUint96(uint256 value) internal pure returns (uint96) {\n        if (value > type(uint96).max) {\n            revert SafeCastOverflowedUintDowncast(96, value);\n        }\n        return uint96(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint88 from uint256, reverting on\n     * overflow (when the input is greater than largest uint88).\n     *\n     * Counterpart to Solidity's `uint88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     */\n    function toUint88(uint256 value) internal pure returns (uint88) {\n        if (value > type(uint88).max) {\n            revert SafeCastOverflowedUintDowncast(88, value);\n        }\n        return uint88(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint80 from uint256, reverting on\n     * overflow (when the input is greater than largest uint80).\n     *\n     * Counterpart to Solidity's `uint80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     */\n    function toUint80(uint256 value) internal pure returns (uint80) {\n        if (value > type(uint80).max) {\n            revert SafeCastOverflowedUintDowncast(80, value);\n        }\n        return uint80(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint72 from uint256, reverting on\n     * overflow (when the input is greater than largest uint72).\n     *\n     * Counterpart to Solidity's `uint72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     */\n    function toUint72(uint256 value) internal pure returns (uint72) {\n        if (value > type(uint72).max) {\n            revert SafeCastOverflowedUintDowncast(72, value);\n        }\n        return uint72(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint64 from uint256, reverting on\n     * overflow (when the input is greater than largest uint64).\n     *\n     * Counterpart to Solidity's `uint64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        if (value > type(uint64).max) {\n            revert SafeCastOverflowedUintDowncast(64, value);\n        }\n        return uint64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint56 from uint256, reverting on\n     * overflow (when the input is greater than largest uint56).\n     *\n     * Counterpart to Solidity's `uint56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     */\n    function toUint56(uint256 value) internal pure returns (uint56) {\n        if (value > type(uint56).max) {\n            revert SafeCastOverflowedUintDowncast(56, value);\n        }\n        return uint56(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint48 from uint256, reverting on\n     * overflow (when the input is greater than largest uint48).\n     *\n     * Counterpart to Solidity's `uint48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     */\n    function toUint48(uint256 value) internal pure returns (uint48) {\n        if (value > type(uint48).max) {\n            revert SafeCastOverflowedUintDowncast(48, value);\n        }\n        return uint48(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint40 from uint256, reverting on\n     * overflow (when the input is greater than largest uint40).\n     *\n     * Counterpart to Solidity's `uint40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     */\n    function toUint40(uint256 value) internal pure returns (uint40) {\n        if (value > type(uint40).max) {\n            revert SafeCastOverflowedUintDowncast(40, value);\n        }\n        return uint40(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint32 from uint256, reverting on\n     * overflow (when the input is greater than largest uint32).\n     *\n     * Counterpart to Solidity's `uint32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        if (value > type(uint32).max) {\n            revert SafeCastOverflowedUintDowncast(32, value);\n        }\n        return uint32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint24 from uint256, reverting on\n     * overflow (when the input is greater than largest uint24).\n     *\n     * Counterpart to Solidity's `uint24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     */\n    function toUint24(uint256 value) internal pure returns (uint24) {\n        if (value > type(uint24).max) {\n            revert SafeCastOverflowedUintDowncast(24, value);\n        }\n        return uint24(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint16 from uint256, reverting on\n     * overflow (when the input is greater than largest uint16).\n     *\n     * Counterpart to Solidity's `uint16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        if (value > type(uint16).max) {\n            revert SafeCastOverflowedUintDowncast(16, value);\n        }\n        return uint16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint8 from uint256, reverting on\n     * overflow (when the input is greater than largest uint8).\n     *\n     * Counterpart to Solidity's `uint8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     */\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        if (value > type(uint8).max) {\n            revert SafeCastOverflowedUintDowncast(8, value);\n        }\n        return uint8(value);\n    }\n\n    /**\n     * @dev Converts a signed int256 into an unsigned uint256.\n     *\n     * Requirements:\n     *\n     * - input must be greater than or equal to 0.\n     */\n    function toUint256(int256 value) internal pure returns (uint256) {\n        if (value < 0) {\n            revert SafeCastOverflowedIntToUint(value);\n        }\n        return uint256(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int248 from int256, reverting on\n     * overflow (when the input is less than smallest int248 or\n     * greater than largest int248).\n     *\n     * Counterpart to Solidity's `int248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     */\n    function toInt248(int256 value) internal pure returns (int248 downcasted) {\n        downcasted = int248(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(248, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int240 from int256, reverting on\n     * overflow (when the input is less than smallest int240 or\n     * greater than largest int240).\n     *\n     * Counterpart to Solidity's `int240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     */\n    function toInt240(int256 value) internal pure returns (int240 downcasted) {\n        downcasted = int240(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(240, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int232 from int256, reverting on\n     * overflow (when the input is less than smallest int232 or\n     * greater than largest int232).\n     *\n     * Counterpart to Solidity's `int232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     */\n    function toInt232(int256 value) internal pure returns (int232 downcasted) {\n        downcasted = int232(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(232, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int224 from int256, reverting on\n     * overflow (when the input is less than smallest int224 or\n     * greater than largest int224).\n     *\n     * Counterpart to Solidity's `int224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toInt224(int256 value) internal pure returns (int224 downcasted) {\n        downcasted = int224(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(224, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int216 from int256, reverting on\n     * overflow (when the input is less than smallest int216 or\n     * greater than largest int216).\n     *\n     * Counterpart to Solidity's `int216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     */\n    function toInt216(int256 value) internal pure returns (int216 downcasted) {\n        downcasted = int216(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(216, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int208 from int256, reverting on\n     * overflow (when the input is less than smallest int208 or\n     * greater than largest int208).\n     *\n     * Counterpart to Solidity's `int208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     */\n    function toInt208(int256 value) internal pure returns (int208 downcasted) {\n        downcasted = int208(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(208, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int200 from int256, reverting on\n     * overflow (when the input is less than smallest int200 or\n     * greater than largest int200).\n     *\n     * Counterpart to Solidity's `int200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     */\n    function toInt200(int256 value) internal pure returns (int200 downcasted) {\n        downcasted = int200(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(200, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int192 from int256, reverting on\n     * overflow (when the input is less than smallest int192 or\n     * greater than largest int192).\n     *\n     * Counterpart to Solidity's `int192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     */\n    function toInt192(int256 value) internal pure returns (int192 downcasted) {\n        downcasted = int192(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(192, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int184 from int256, reverting on\n     * overflow (when the input is less than smallest int184 or\n     * greater than largest int184).\n     *\n     * Counterpart to Solidity's `int184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     */\n    function toInt184(int256 value) internal pure returns (int184 downcasted) {\n        downcasted = int184(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(184, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int176 from int256, reverting on\n     * overflow (when the input is less than smallest int176 or\n     * greater than largest int176).\n     *\n     * Counterpart to Solidity's `int176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     */\n    function toInt176(int256 value) internal pure returns (int176 downcasted) {\n        downcasted = int176(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(176, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int168 from int256, reverting on\n     * overflow (when the input is less than smallest int168 or\n     * greater than largest int168).\n     *\n     * Counterpart to Solidity's `int168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     */\n    function toInt168(int256 value) internal pure returns (int168 downcasted) {\n        downcasted = int168(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(168, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int160 from int256, reverting on\n     * overflow (when the input is less than smallest int160 or\n     * greater than largest int160).\n     *\n     * Counterpart to Solidity's `int160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     */\n    function toInt160(int256 value) internal pure returns (int160 downcasted) {\n        downcasted = int160(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(160, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int152 from int256, reverting on\n     * overflow (when the input is less than smallest int152 or\n     * greater than largest int152).\n     *\n     * Counterpart to Solidity's `int152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     */\n    function toInt152(int256 value) internal pure returns (int152 downcasted) {\n        downcasted = int152(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(152, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int144 from int256, reverting on\n     * overflow (when the input is less than smallest int144 or\n     * greater than largest int144).\n     *\n     * Counterpart to Solidity's `int144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     */\n    function toInt144(int256 value) internal pure returns (int144 downcasted) {\n        downcasted = int144(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(144, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int136 from int256, reverting on\n     * overflow (when the input is less than smallest int136 or\n     * greater than largest int136).\n     *\n     * Counterpart to Solidity's `int136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     */\n    function toInt136(int256 value) internal pure returns (int136 downcasted) {\n        downcasted = int136(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(136, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int128 from int256, reverting on\n     * overflow (when the input is less than smallest int128 or\n     * greater than largest int128).\n     *\n     * Counterpart to Solidity's `int128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toInt128(int256 value) internal pure returns (int128 downcasted) {\n        downcasted = int128(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(128, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int120 from int256, reverting on\n     * overflow (when the input is less than smallest int120 or\n     * greater than largest int120).\n     *\n     * Counterpart to Solidity's `int120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     */\n    function toInt120(int256 value) internal pure returns (int120 downcasted) {\n        downcasted = int120(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(120, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int112 from int256, reverting on\n     * overflow (when the input is less than smallest int112 or\n     * greater than largest int112).\n     *\n     * Counterpart to Solidity's `int112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     */\n    function toInt112(int256 value) internal pure returns (int112 downcasted) {\n        downcasted = int112(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(112, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int104 from int256, reverting on\n     * overflow (when the input is less than smallest int104 or\n     * greater than largest int104).\n     *\n     * Counterpart to Solidity's `int104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     */\n    function toInt104(int256 value) internal pure returns (int104 downcasted) {\n        downcasted = int104(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(104, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int96 from int256, reverting on\n     * overflow (when the input is less than smallest int96 or\n     * greater than largest int96).\n     *\n     * Counterpart to Solidity's `int96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toInt96(int256 value) internal pure returns (int96 downcasted) {\n        downcasted = int96(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(96, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int88 from int256, reverting on\n     * overflow (when the input is less than smallest int88 or\n     * greater than largest int88).\n     *\n     * Counterpart to Solidity's `int88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     */\n    function toInt88(int256 value) internal pure returns (int88 downcasted) {\n        downcasted = int88(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(88, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int80 from int256, reverting on\n     * overflow (when the input is less than smallest int80 or\n     * greater than largest int80).\n     *\n     * Counterpart to Solidity's `int80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     */\n    function toInt80(int256 value) internal pure returns (int80 downcasted) {\n        downcasted = int80(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(80, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int72 from int256, reverting on\n     * overflow (when the input is less than smallest int72 or\n     * greater than largest int72).\n     *\n     * Counterpart to Solidity's `int72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     */\n    function toInt72(int256 value) internal pure returns (int72 downcasted) {\n        downcasted = int72(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(72, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int64 from int256, reverting on\n     * overflow (when the input is less than smallest int64 or\n     * greater than largest int64).\n     *\n     * Counterpart to Solidity's `int64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toInt64(int256 value) internal pure returns (int64 downcasted) {\n        downcasted = int64(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(64, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int56 from int256, reverting on\n     * overflow (when the input is less than smallest int56 or\n     * greater than largest int56).\n     *\n     * Counterpart to Solidity's `int56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     */\n    function toInt56(int256 value) internal pure returns (int56 downcasted) {\n        downcasted = int56(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(56, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int48 from int256, reverting on\n     * overflow (when the input is less than smallest int48 or\n     * greater than largest int48).\n     *\n     * Counterpart to Solidity's `int48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     */\n    function toInt48(int256 value) internal pure returns (int48 downcasted) {\n        downcasted = int48(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(48, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int40 from int256, reverting on\n     * overflow (when the input is less than smallest int40 or\n     * greater than largest int40).\n     *\n     * Counterpart to Solidity's `int40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     */\n    function toInt40(int256 value) internal pure returns (int40 downcasted) {\n        downcasted = int40(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(40, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int32 from int256, reverting on\n     * overflow (when the input is less than smallest int32 or\n     * greater than largest int32).\n     *\n     * Counterpart to Solidity's `int32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toInt32(int256 value) internal pure returns (int32 downcasted) {\n        downcasted = int32(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(32, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int24 from int256, reverting on\n     * overflow (when the input is less than smallest int24 or\n     * greater than largest int24).\n     *\n     * Counterpart to Solidity's `int24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     */\n    function toInt24(int256 value) internal pure returns (int24 downcasted) {\n        downcasted = int24(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(24, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int16 from int256, reverting on\n     * overflow (when the input is less than smallest int16 or\n     * greater than largest int16).\n     *\n     * Counterpart to Solidity's `int16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toInt16(int256 value) internal pure returns (int16 downcasted) {\n        downcasted = int16(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(16, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int8 from int256, reverting on\n     * overflow (when the input is less than smallest int8 or\n     * greater than largest int8).\n     *\n     * Counterpart to Solidity's `int8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     */\n    function toInt8(int256 value) internal pure returns (int8 downcasted) {\n        downcasted = int8(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(8, value);\n        }\n    }\n\n    /**\n     * @dev Converts an unsigned uint256 into a signed int256.\n     *\n     * Requirements:\n     *\n     * - input must be less than or equal to maxInt256.\n     */\n    function toInt256(uint256 value) internal pure returns (int256) {\n        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n        if (value > uint256(type(int256).max)) {\n            revert SafeCastOverflowedUintToInt(value);\n        }\n        return int256(value);\n    }\n\n    /**\n     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n     */\n    function toUint(bool b) internal pure returns (uint256 u) {\n        assembly (\"memory-safe\") {\n            u := iszero(iszero(b))\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/Comparators.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides a set of functions to compare values.\n *\n * _Available since v5.1._\n */\nlibrary Comparators {\n    function lt(uint256 a, uint256 b) internal pure returns (bool) {\n        return a < b;\n    }\n\n    function gt(uint256 a, uint256 b) internal pure returns (bool) {\n        return a > b;\n    }\n}\n"},{"file_path":"contracts/interfaces/IFUSD.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\n/**\n * @title IFUSD\n * @notice FUSD stablecoin interface, defining the core functions of the FUSD token.\n * @dev Implements ERC20 and ERC2612 standards, as well as custom minting, burning, and share mechanisms.\n */\ninterface IFUSD {\n    /// Error Definitions\n\n    /**\n     * @notice ERC2612 permit deadline expired error.\n     * @param deadline The deadline for the permit.\n     * @param blockTimestamp The current block timestamp.\n     */\n    error ERC2612ExpiredDeadline(uint256 deadline, uint256 blockTimestamp);\n\n    /**\n     * @notice ERC2612 invalid signature error.\n     * @param signer The signer's address.\n     * @param owner The owner's address.\n     */\n    error ERC2612InvalidSignature(address signer, address owner);\n\n    /**\n     * @notice ERC20 insufficient balance error (ERC-6093 standard).\n     * @param sender The sender's address.\n     * @param balance The sender's current balance.\n     * @param needed The required amount.\n     */\n    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);\n\n    /**\n     * @notice ERC20 invalid sender error.\n     * @param sender The invalid sender address.\n     */\n    error ERC20InvalidSender(address sender);\n\n    /**\n     * @notice ERC20 invalid receiver error.\n     * @param receiver The invalid receiver address.\n     */\n    error ERC20InvalidReceiver(address receiver);\n\n    /**\n     * @notice ERC20 insufficient allowance error.\n     * @param spender The spender's address.\n     * @param allowance The current allowance.\n     * @param needed The required amount.\n     */\n    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);\n\n    /**\n     * @notice ERC20 invalid approver error.\n     * @param approver The invalid approver address.\n     */\n    error ERC20InvalidApprover(address approver);\n\n    /**\n     * @notice ERC20 invalid spender error.\n     * @param spender The invalid spender address.\n     */\n    error ERC20InvalidSpender(address spender);\n\n    error AmountTooSmall(uint256 amount);\n\n    /// Event Definitions\n\n    /**\n     * @notice Token transfer event.\n     * @param from The sender's address.\n     * @param to The receiver's address.\n     * @param value The transfer amount.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @notice Token approval event.\n     * @param owner The token owner's address.\n     * @param spender The address of the approved spender.\n     * @param value The approved amount.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /// Function Definitions\n\n    // ERC20 Standard Functions\n    /**\n     * @notice Gets the token name.\n     * @return The token name string.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @notice Gets the token symbol.\n     * @return The token symbol string.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @notice Gets the token decimals.\n     * @return The number of token decimals.\n     */\n    function decimals() external view returns (uint8);\n\n    /**\n     * @notice Gets the total token supply.\n     * @return The total token supply.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @notice Gets the token balance of a specified account.\n     * @param account The address of the account to query.\n     * @return The token balance of the account.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @notice Transfers tokens to a specified address.\n     * @param to The receiver's address.\n     * @param value The transfer amount.\n     * @return Whether the operation was successful.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @notice Queries the allowance.\n     * @param owner The token owner's address.\n     * @param spender The spender's address.\n     * @return The approved amount.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @notice Approves a specified address to spend tokens.\n     * @param spender The address to be approved.\n     * @param value The approved amount.\n     * @return Whether the operation was successful.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @notice Transfers tokens on behalf of another (requires prior approval).\n     * @param from The sender's address.\n     * @param to The receiver's address.\n     * @param value The transfer amount.\n     * @return Whether the operation was successful.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n\n    // ERC2612 Standard Functions\n    /**\n     * @notice Approves via signature.\n     * @param owner The token owner's address.\n     * @param spender The address to be approved.\n     * @param value The approved amount.\n     * @param deadline The signature validity deadline.\n     * @param v The v value of the signature.\n     * @param r The r value of the signature.\n     * @param s The s value of the signature.\n     */\n    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n        external;\n\n    /**\n     * @notice Gets the nonce of an account, used to prevent replay attacks.\n     * @param owner The account address.\n     * @return The current nonce value.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @notice Gets the domain separator for EIP-712 signatures.\n     * @return The domain separator.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n    // Custom Functions\n    /**\n     * @notice Gets the total shares of the token.\n     * @return The total shares of the token.\n     */\n    function totalShares() external view returns (uint256);\n\n    /**\n     * @notice Gets the shares of a specified account.\n     * @param account The address of the account to query.\n     * @return The shares of the account.\n     */\n    function sharesOf(address account) external view returns (uint256);\n\n    /**\n     * @notice Mints tokens to a specified address.\n     * @param to The address to receive the minted tokens.\n     * @param amount The amount to mint.\n     */\n    function mint(address to, uint256 amount) external;\n\n    /**\n     * @notice Burns the caller's tokens.\n     * @param amount The amount to burn.\n     */\n    function burn(uint256 amount) external;\n\n    /**\n     * @notice Increases the allowance.\n     * @param spender The address to be approved.\n     * @param amount The amount to increase the allowance by.\n     * @return Whether the operation was successful.\n     */\n    function increaseAllowance(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @notice Decreases the allowance.\n     * @param spender The address to be approved.\n     * @param amount The amount to decrease the allowance by.\n     * @return Whether the operation was successful.\n     */\n    function decreaseAllowance(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @notice Converts a token amount to shares.\n     * @param amount The token amount.\n     * @return shares The corresponding shares.\n     */\n    function convertToShares(uint256 amount) external view returns (uint256 shares);\n\n    /**\n     * @notice Converts shares to a token amount.\n     * @param shares The shares.\n     * @return amount The corresponding token amount.\n     */\n    function convertToTokens(uint256 shares) external view returns (uint256 amount);\n\n    /**\n     * @notice Gets the bonus multiplier.\n     * @return The current bonus multiplier.\n     */\n    function getBonusMultiplier() external view returns (uint256);\n\n    /**\n     * @notice Checks if the contract is paused.\n     * @return Whether it is paused.\n     */\n    function paused() external view returns (bool);\n\n    /**\n     * @notice Pauses the contract functions.\n     */\n    function pause() external;\n\n    /**\n     * @notice Resumes the contract functions.\n     */\n    function unpause() external;\n\n    function getCCIPAdmin() external view returns (address);\n}\n"},{"file_path":"contracts/interfaces/ITokenBridgeSender.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\n/**\n * @title ITokenBridgeSender\n * @dev Cross-chain token bridge sender contract interface, compatible with chains that do not support CCIP\n * @notice This interface defines the public functions of the TokenBridgeSender contract\n */\ninterface ITokenBridgeSender {\n    /**\n     * @dev Enum for fee payment methods\n     * @param Native Pay fees with native tokens\n     * @param LINK Pay fees with LINK tokens\n     */\n    enum PayFeesIn {\n        Native,\n        LINK\n    }\n\n    /// @dev Error for unsupported destination chain\n    error DestinationChainNotSupported(uint64 destinationChainSelector);\n    /// @dev Error for unsupported token\n    error TokenNotSupported(address token);\n    /// @dev Error for zero address\n    error AddressZero();\n    /// @dev Error for insufficient fee funds\n    error InsufficientFeeFunds(address token, uint256 available, uint256 required);\n    /// @dev Error for failed refund\n    error RefundFailed();\n\n    /**\n     * @dev Event for successful CCIP token transfer\n     * @param messageId CCIP message ID\n     * @param destinationChainSelector Destination chain selector\n     * @param receiverBytes32 Receiver address\n     * @param token Token address\n     * @param tokenAmount Token amount\n     * @param feeToken Fee token address\n     * @param fees Fee amount\n     */\n    event CCIPTokensTransferSuccess(\n        bytes32 indexed messageId,\n        uint64 indexed destinationChainSelector,\n        bytes32 receiverBytes32,\n        address token,\n        uint256 tokenAmount,\n        address feeToken,\n        uint256 fees\n    );\n\n    /**\n     * @dev Event for successful custom token transfer\n     * @param destinationChainId Destination chain ID\n     * @param receiverBytes32 Receiver address\n     * @param token Token address\n     * @param tokenAmount Token amount\n     */\n    event CustomTokensTransferSuccess(\n        bytes32 messageId,\n        uint64 indexed destinationChainId,\n        bytes32 receiverBytes32,\n        address token,\n        uint256 tokenAmount\n    );\n\n    /**\n     * @dev Sends tokens to the destination chain\n     * @param destinationChain Destination chain ID or selector\n     * @param receiverBytes32 Receiver address\n     * @param bridgeToken Bridge token address\n     * @param bridgeAmount Bridge token amount\n     * @param payFeesIn Method for paying fees\n     * @return messageId Returns the CCIP message ID, or custom chain message ID\n     */\n    function send(\n        uint64 destinationChain,\n        bytes32 receiverBytes32,\n        address bridgeToken,\n        uint256 bridgeAmount,\n        PayFeesIn payFeesIn\n    ) external payable returns (bytes32);\n\n    /**\n     * @dev Sets the CCIP router address\n     * @param router The new CCIP router address\n     */\n    function setRouter(address router) external;\n\n    /**\n     * @dev Sets the LINK token address\n     * @param link The new LINK token address\n     */\n    function setLink(address link) external;\n\n    /**\n     * @dev Sets a supported chain selector\n     * @param chainSelector The chain selector\n     * @param supported Whether the chain is supported\n     */\n    function setSupportedChainSelector(uint64 chainSelector, bool supported) external;\n\n    /**\n     * @dev Sets a supported token\n     * @param token The token address\n     * @param supported Whether the token is supported\n     */\n    function setSupportedToken(address token, bool supported) external;\n\n    /**\n     * @dev Sets a custom chain ID\n     * @param chainId The chain ID\n     * @param supported Whether the custom chain is supported\n     */\n    function setCustomChainId(uint64 chainId, bool supported) external;\n\n    /**\n     * @dev Sets the custom fee quoter address\n     * @param _customFeeQuoter The new custom fee quoter address\n     */\n    function setCustomFeeQuoter(address _customFeeQuoter) external;\n\n    /**\n     * @dev Gets the CCIP router address\n     * @return The current CCIP router address\n     */\n    function getRouter() external view returns (address);\n\n    /**\n     * @dev Gets the LINK token address\n     * @return The current LINK token address\n     */\n    function getLink() external view returns (address);\n\n    /**\n     * @notice Pauses the contract functions\n     */\n    function pause() external;\n\n    /**\n     * @notice Resumes the contract functions\n     */\n    function unpause() external;\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    /**\n     * @dev An operation with an ERC-20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     *\n     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n     * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n     * set here.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            safeTransfer(token, to, value);\n        } else if (!token.transferAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferFromAndCallRelaxed(\n        IERC1363 token,\n        address from,\n        address to,\n        uint256 value,\n        bytes memory data\n    ) internal {\n        if (to.code.length == 0) {\n            safeTransferFrom(token, from, to, value);\n        } else if (!token.transferFromAndCall(from, to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n     * once without retrying, and relies on the returned value to be true.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            forceApprove(token, to, value);\n        } else if (!token.approveAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            // bubble errors\n            if iszero(success) {\n                let ptr := mload(0x40)\n                returndatacopy(ptr, 0, returndatasize())\n                revert(ptr, returndatasize())\n            }\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n\n        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        bool success;\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (access/extensions/AccessControlEnumerable.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControlEnumerable} from \"@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\";\nimport {AccessControlUpgradeable} from \"../AccessControlUpgradeable.sol\";\nimport {EnumerableSet} from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerable, AccessControlUpgradeable {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControlEnumerable\n    struct AccessControlEnumerableStorage {\n        mapping(bytes32 role => EnumerableSet.AddressSet) _roleMembers;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.AccessControlEnumerable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant AccessControlEnumerableStorageLocation = 0xc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e82371705932000;\n\n    function _getAccessControlEnumerableStorage() private pure returns (AccessControlEnumerableStorage storage $) {\n        assembly {\n            $.slot := AccessControlEnumerableStorageLocation\n        }\n    }\n\n    function __AccessControlEnumerable_init() internal onlyInitializing {\n    }\n\n    function __AccessControlEnumerable_init_unchained() internal onlyInitializing {\n    }\n    /// @inheritdoc IERC165\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns one of the accounts that have `role`. `index` must be a\n     * value between 0 and {getRoleMemberCount}, non-inclusive.\n     *\n     * Role bearers are not sorted in any particular way, and their ordering may\n     * change at any point.\n     *\n     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n     * you perform all queries on the same block. See the following\n     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n     * for more information.\n     */\n    function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();\n        return $._roleMembers[role].at(index);\n    }\n\n    /**\n     * @dev Returns the number of accounts that have `role`. Can be used\n     * together with {getRoleMember} to enumerate all bearers of a role.\n     */\n    function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();\n        return $._roleMembers[role].length();\n    }\n\n    /**\n     * @dev Return all accounts that have `role`\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function getRoleMembers(bytes32 role) public view virtual returns (address[] memory) {\n        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();\n        return $._roleMembers[role].values();\n    }\n\n    /**\n     * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n     */\n    function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();\n        bool granted = super._grantRole(role, account);\n        if (granted) {\n            $._roleMembers[role].add(account);\n        }\n        return granted;\n    }\n\n    /**\n     * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();\n        bool revoked = super._revokeRole(role, account);\n        if (revoked) {\n            $._roleMembers[role].remove(account);\n        }\n        return revoked;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)\n\npragma solidity ^0.8.20;\n\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract PausableUpgradeable is Initializable, ContextUpgradeable {\n    /// @custom:storage-location erc7201:openzeppelin.storage.Pausable\n    struct PausableStorage {\n        bool _paused;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Pausable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;\n\n    function _getPausableStorage() private pure returns (PausableStorage storage $) {\n        assembly {\n            $.slot := PausableStorageLocation\n        }\n    }\n\n    /**\n     * @dev Emitted when the pause is triggered by `account`.\n     */\n    event Paused(address account);\n\n    /**\n     * @dev Emitted when the pause is lifted by `account`.\n     */\n    event Unpaused(address account);\n\n    /**\n     * @dev The operation failed because the contract is paused.\n     */\n    error EnforcedPause();\n\n    /**\n     * @dev The operation failed because the contract is not paused.\n     */\n    error ExpectedPause();\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is not paused.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    modifier whenNotPaused() {\n        _requireNotPaused();\n        _;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is paused.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    modifier whenPaused() {\n        _requirePaused();\n        _;\n    }\n\n    function __Pausable_init() internal onlyInitializing {\n    }\n\n    function __Pausable_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev Returns true if the contract is paused, and false otherwise.\n     */\n    function paused() public view virtual returns (bool) {\n        PausableStorage storage $ = _getPausableStorage();\n        return $._paused;\n    }\n\n    /**\n     * @dev Throws if the contract is paused.\n     */\n    function _requireNotPaused() internal view virtual {\n        if (paused()) {\n            revert EnforcedPause();\n        }\n    }\n\n    /**\n     * @dev Throws if the contract is not paused.\n     */\n    function _requirePaused() internal view virtual {\n        if (!paused()) {\n            revert ExpectedPause();\n        }\n    }\n\n    /**\n     * @dev Triggers stopped state.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    function _pause() internal virtual whenNotPaused {\n        PausableStorage storage $ = _getPausableStorage();\n        $._paused = true;\n        emit Paused(_msgSender());\n    }\n\n    /**\n     * @dev Returns to normal state.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    function _unpause() internal virtual whenPaused {\n        PausableStorage storage $ = _getPausableStorage();\n        $._paused = false;\n        emit Unpaused(_msgSender());\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/interfaces/IERC1363.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n    /*\n     * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n     * 0xb0202a11 ===\n     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n     */\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @param data Additional data with no specified format, sent in call to `spender`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},{"file_path":"@openzeppelin/contracts/utils/StorageSlot.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC-1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.\n *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n *     function _getImplementation() internal view returns (address) {\n *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n *     }\n *\n *     function _setImplementation(address newImplementation) internal {\n *         require(newImplementation.code.length > 0);\n *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n *     }\n * }\n * ```\n *\n * TIP: Consider using this library along with {SlotDerivation}.\n */\nlibrary StorageSlot {\n    struct AddressSlot {\n        address value;\n    }\n\n    struct BooleanSlot {\n        bool value;\n    }\n\n    struct Bytes32Slot {\n        bytes32 value;\n    }\n\n    struct Uint256Slot {\n        uint256 value;\n    }\n\n    struct Int256Slot {\n        int256 value;\n    }\n\n    struct StringSlot {\n        string value;\n    }\n\n    struct BytesSlot {\n        bytes value;\n    }\n\n    /**\n     * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n     */\n    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns a `BooleanSlot` with member `value` located at `slot`.\n     */\n    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.\n     */\n    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns a `Uint256Slot` with member `value` located at `slot`.\n     */\n    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns a `Int256Slot` with member `value` located at `slot`.\n     */\n    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns a `StringSlot` with member `value` located at `slot`.\n     */\n    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n     */\n    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := store.slot\n        }\n    }\n\n    /**\n     * @dev Returns a `BytesSlot` with member `value` located at `slot`.\n     */\n    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n     */\n    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := store.slot\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"},{"file_path":"contracts/utils/AddressConvert.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Internal} from \"@chainlink/contracts-ccip/contracts/libraries/Internal.sol\";\n\nlibrary AddressConvert {\n    function convertEVMAddressToBytes32(address evmAddr) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(evmAddr)));\n    }\n\n    function convertBytes32ToEVMAddress(bytes32 data) internal pure returns (address) {\n        Internal._validateEVMAddress(abi.encode(data));\n        return address(uint160(uint256(data)));\n    }\n}\n"},{"file_path":"contracts/interfaces/IKycModule.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\n/**\n * @title IKycModule\n * @notice KYC module interface, providing account KYC verification and banning functions\n * @dev Defines the core functions and events for managing account KYC status\n */\ninterface IKycModule {\n    /// Error definitions\n\n    /**\n     * @notice Error thrown when an account has already passed KYC verification\n     * @param account The address of the account that has passed KYC\n     */\n    error AccountIsKyc(address account);\n\n    /**\n     * @notice Error thrown when an account has not passed KYC verification\n     * @param account The address of the account that has not passed KYC\n     */\n    error AccountNotKyc(address account);\n\n    /**\n     * @notice Error thrown when an account is banned\n     * @param account The address of the banned account\n     */\n    error AccountIsBanned(address account);\n\n    /**\n     * @notice Error thrown when trying to unban an account that is not banned\n     * @param account The address of the account that is not banned\n     */\n    error AccountIsNotBanned(address account);\n\n    error AccountIsZeroAddress();\n\n    /// Event definitions\n\n    /**\n     * @notice Event triggered when an account is approved for KYC\n     * @param account The address of the account approved for KYC\n     */\n    event AccountKycApproved(address indexed account);\n\n    /**\n     * @notice Event triggered when an account's KYC approval is removed\n     * @param account The address of the account whose KYC is removed\n     */\n    event AccountKycRemoved(address indexed account);\n\n    /**\n     * @notice Event triggered when an account is banned\n     * @param account The address of the banned account\n     */\n    event AccountBanned(address indexed account);\n\n    /**\n     * @notice Event triggered when an account is unbanned\n     * @param account The address of the unbanned account\n     */\n    event AccountUnbanned(address indexed account);\n\n    /**\n     * @notice Event triggered when the KYC check feature is enabled\n     */\n    event KycCheckEnabled();\n\n    /**\n     * @notice Event triggered when the KYC check feature is disabled\n     */\n    event KycCheckDisabled();\n\n    /**\n     * @notice Checks if an account is banned\n     * @param account The address of the account to check\n     * @return Whether the account is banned\n     */\n    function isBanned(address account) external view returns (bool);\n\n    /**\n     * @notice Bans multiple accounts\n     * @param accounts Array of account addresses to ban\n     */\n    function ban(address[] calldata accounts) external;\n\n    /**\n     * @notice Unbans multiple accounts\n     * @param accounts Array of account addresses to unban\n     */\n    function unban(address[] calldata accounts) external;\n\n    /**\n     * @notice Checks if an account has passed KYC verification\n     * @param account The address of the account to check\n     * @return Whether the account has passed KYC verification\n     */\n    function isKyc(address account) external view returns (bool);\n\n    /**\n     * @notice Checks if the KYC verification feature is enabled\n     * @return Whether the KYC verification feature is enabled\n     */\n    function isKycEnabled() external view returns (bool);\n\n    /**\n     * @notice Enables the KYC check feature\n     */\n    function enableKycCheck() external;\n\n    /**\n     * @notice Disables the KYC check feature\n     */\n    function disableKycCheck() external;\n\n    /**\n     * @notice Adds KYC verification for multiple accounts\n     * @param accounts Array of account addresses to add KYC verification for\n     */\n    function addKyc(address[] calldata accounts) external;\n\n    /**\n     * @notice Removes KYC verification for multiple accounts\n     * @param accounts Array of account addresses to remove KYC verification for\n     */\n    function removeKyc(address[] calldata accounts) external;\n\n    /**\n     * @notice Validates the legitimacy of an account address (has passed KYC and is not banned)\n     * @param account The account address to validate\n     * @dev Throws an error if validation fails\n     * @return Boolean indicating if the address is valid\n     */\n    function validateAddress(address account) external view returns (bool);\n\n    /**\n     * @notice Validates if an account is banned\n     * @param account The account address to validate\n     * @dev Throws an error if the account is banned\n     * @return Boolean indicating if the account is banned\n     */\n    function validateBanned(address account) external view returns (bool);\n}\n"},{"file_path":"@openzeppelin/contracts/utils/SlotDerivation.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)\n// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots\n * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by\n * the solidity language / compiler.\n *\n * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].\n *\n * Example usage:\n * ```solidity\n * contract Example {\n *     // Add the library methods\n *     using StorageSlot for bytes32;\n *     using SlotDerivation for bytes32;\n *\n *     // Declare a namespace\n *     string private constant _NAMESPACE = \"<namespace>\"; // eg. OpenZeppelin.Slot\n *\n *     function setValueInNamespace(uint256 key, address newValue) internal {\n *         _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;\n *     }\n *\n *     function getValueInNamespace(uint256 key) internal view returns (address) {\n *         return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;\n *     }\n * }\n * ```\n *\n * TIP: Consider using this library along with {StorageSlot}.\n *\n * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking\n * upgrade safety will ignore the slots accessed through this library.\n *\n * _Available since v5.1._\n */\nlibrary SlotDerivation {\n    /**\n     * @dev Derive an ERC-7201 slot from a string (namespace).\n     */\n    function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {\n        assembly (\"memory-safe\") {\n            mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))\n            slot := and(keccak256(0x00, 0x20), not(0xff))\n        }\n    }\n\n    /**\n     * @dev Add an offset to a slot to get the n-th element of a structure or an array.\n     */\n    function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {\n        unchecked {\n            return bytes32(uint256(slot) + pos);\n        }\n    }\n\n    /**\n     * @dev Derive the location of the first element in an array from the slot where the length is stored.\n     */\n    function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {\n        assembly (\"memory-safe\") {\n            mstore(0x00, slot)\n            result := keccak256(0x00, 0x20)\n        }\n    }\n\n    /**\n     * @dev Derive the location of a mapping element from the key.\n     */\n    function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {\n        assembly (\"memory-safe\") {\n            mstore(0x00, and(key, shr(96, not(0))))\n            mstore(0x20, slot)\n            result := keccak256(0x00, 0x40)\n        }\n    }\n\n    /**\n     * @dev Derive the location of a mapping element from the key.\n     */\n    function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {\n        assembly (\"memory-safe\") {\n            mstore(0x00, iszero(iszero(key)))\n            mstore(0x20, slot)\n            result := keccak256(0x00, 0x40)\n        }\n    }\n\n    /**\n     * @dev Derive the location of a mapping element from the key.\n     */\n    function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {\n        assembly (\"memory-safe\") {\n            mstore(0x00, key)\n            mstore(0x20, slot)\n            result := keccak256(0x00, 0x40)\n        }\n    }\n\n    /**\n     * @dev Derive the location of a mapping element from the key.\n     */\n    function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {\n        assembly (\"memory-safe\") {\n            mstore(0x00, key)\n            mstore(0x20, slot)\n            result := keccak256(0x00, 0x40)\n        }\n    }\n\n    /**\n     * @dev Derive the location of a mapping element from the key.\n     */\n    function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {\n        assembly (\"memory-safe\") {\n            mstore(0x00, key)\n            mstore(0x20, slot)\n            result := keccak256(0x00, 0x40)\n        }\n    }\n\n    /**\n     * @dev Derive the location of a mapping element from the key.\n     */\n    function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {\n        assembly (\"memory-safe\") {\n            let length := mload(key)\n            let begin := add(key, 0x20)\n            let end := add(begin, length)\n            let cache := mload(end)\n            mstore(end, slot)\n            result := keccak256(begin, add(length, 0x20))\n            mstore(end, cache)\n        }\n    }\n\n    /**\n     * @dev Derive the location of a mapping element from the key.\n     */\n    function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {\n        assembly (\"memory-safe\") {\n            let length := mload(key)\n            let begin := add(key, 0x20)\n            let end := add(begin, length)\n            let cache := mload(end)\n            mstore(end, slot)\n            result := keccak256(begin, add(length, 0x20))\n            mstore(end, cache)\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,\n * consider using {ReentrancyGuardTransient} instead.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant NOT_ENTERED = 1;\n    uint256 private constant ENTERED = 2;\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard\n    struct ReentrancyGuardStorage {\n        uint256 _status;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ReentrancyGuard\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;\n\n    function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {\n        assembly {\n            $.slot := ReentrancyGuardStorageLocation\n        }\n    }\n\n    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\n\n    function __ReentrancyGuard_init() internal onlyInitializing {\n        __ReentrancyGuard_init_unchained();\n    }\n\n    function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n        $._status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n        // On the first call to nonReentrant, _status will be NOT_ENTERED\n        if ($._status == ENTERED) {\n            revert ReentrancyGuardReentrantCall();\n        }\n\n        // Any calls to nonReentrant after this point will fail\n        $._status = ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        $._status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n        return $._status == ENTERED;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/Panic.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n *      using Panic for uint256;\n *\n *      // Use any of the declared internal constants\n *      function foo() { Panic.GENERIC.panic(); }\n *\n *      // Alternatively\n *      function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n    /// @dev generic / unspecified error\n    uint256 internal constant GENERIC = 0x00;\n    /// @dev used by the assert() builtin\n    uint256 internal constant ASSERT = 0x01;\n    /// @dev arithmetic underflow or overflow\n    uint256 internal constant UNDER_OVERFLOW = 0x11;\n    /// @dev division or modulo by zero\n    uint256 internal constant DIVISION_BY_ZERO = 0x12;\n    /// @dev enum conversion error\n    uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n    /// @dev invalid encoding in storage\n    uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n    /// @dev empty array pop\n    uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n    /// @dev array out of bounds access\n    uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n    /// @dev resource error (too large allocation or too large array)\n    uint256 internal constant RESOURCE_ERROR = 0x41;\n    /// @dev calling invalid internal function\n    uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n    /// @dev Reverts with a panic code. Recommended to use with\n    /// the internal constants with predefined codes.\n    function panic(uint256 code) internal pure {\n        assembly (\"memory-safe\") {\n            mstore(0x00, 0x4e487b71)\n            mstore(0x20, code)\n            revert(0x1c, 0x24)\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},{"file_path":"@openzeppelin/contracts/utils/structs/BitMaps.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/BitMaps.sol)\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for managing uint256 to bool mapping in a compact and efficient way, provided the keys are sequential.\n * Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor].\n *\n * BitMaps pack 256 booleans across each bit of a single 256-bit slot of `uint256` type.\n * Hence booleans corresponding to 256 _sequential_ indices would only consume a single slot,\n * unlike the regular `bool` which would consume an entire slot for a single value.\n *\n * This results in gas savings in two ways:\n *\n * - Setting a zero value to non-zero only once every 256 times\n * - Accessing the same warm slot for every 256 _sequential_ indices\n */\nlibrary BitMaps {\n    struct BitMap {\n        mapping(uint256 bucket => uint256) _data;\n    }\n\n    /**\n     * @dev Returns whether the bit at `index` is set.\n     */\n    function get(BitMap storage bitmap, uint256 index) internal view returns (bool) {\n        uint256 bucket = index >> 8;\n        uint256 mask = 1 << (index & 0xff);\n        return bitmap._data[bucket] & mask != 0;\n    }\n\n    /**\n     * @dev Sets the bit at `index` to the boolean `value`.\n     */\n    function setTo(BitMap storage bitmap, uint256 index, bool value) internal {\n        if (value) {\n            set(bitmap, index);\n        } else {\n            unset(bitmap, index);\n        }\n    }\n\n    /**\n     * @dev Sets the bit at `index`.\n     */\n    function set(BitMap storage bitmap, uint256 index) internal {\n        uint256 bucket = index >> 8;\n        uint256 mask = 1 << (index & 0xff);\n        bitmap._data[bucket] |= mask;\n    }\n\n    /**\n     * @dev Unsets the bit at `index`.\n     */\n    function unset(BitMap storage bitmap, uint256 index) internal {\n        uint256 bucket = index >> 8;\n        uint256 mask = 1 << (index & 0xff);\n        bitmap._data[bucket] &= ~mask;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Storage of the initializable contract.\n     *\n     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n     * when using with upgradeable contracts.\n     *\n     * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n     */\n    struct InitializableStorage {\n        /**\n         * @dev Indicates that the contract has been initialized.\n         */\n        uint64 _initialized;\n        /**\n         * @dev Indicates that the contract is in the process of being initialized.\n         */\n        bool _initializing;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n    /**\n     * @dev The contract is already initialized.\n     */\n    error InvalidInitialization();\n\n    /**\n     * @dev The contract is not initializing.\n     */\n    error NotInitializing();\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint64 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n     * production.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        // Cache values to avoid duplicated sloads\n        bool isTopLevelCall = !$._initializing;\n        uint64 initialized = $._initialized;\n\n        // Allowed calls:\n        // - initialSetup: the contract is not in the initializing state and no previous version was\n        //                 initialized\n        // - construction: the contract is initialized at version 1 (no reinitialization) and the\n        //                 current contract is just being deployed\n        bool initialSetup = initialized == 0 && isTopLevelCall;\n        bool construction = initialized == 1 && address(this).code.length == 0;\n\n        if (!initialSetup && !construction) {\n            revert InvalidInitialization();\n        }\n        $._initialized = 1;\n        if (isTopLevelCall) {\n            $._initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            $._initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint64 version) {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing || $._initialized >= version) {\n            revert InvalidInitialization();\n        }\n        $._initialized = version;\n        $._initializing = true;\n        _;\n        $._initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        _checkInitializing();\n        _;\n    }\n\n    /**\n     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n     */\n    function _checkInitializing() internal view virtual {\n        if (!_isInitializing()) {\n            revert NotInitializing();\n        }\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing) {\n            revert InvalidInitialization();\n        }\n        if ($._initialized != type(uint64).max) {\n            $._initialized = type(uint64).max;\n            emit Initialized(type(uint64).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint64) {\n        return _getInitializableStorage()._initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _getInitializableStorage()._initializing;\n    }\n\n    /**\n     * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.\n     *\n     * NOTE: Consider following the ERC-7201 formula to derive storage locations.\n     */\n    function _initializableStorageSlot() internal pure virtual returns (bytes32) {\n        return INITIALIZABLE_STORAGE;\n    }\n\n    /**\n     * @dev Returns a pointer to the storage namespace.\n     */\n    // solhint-disable-next-line var-name-mixedcase\n    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n        bytes32 slot = _initializableStorageSlot();\n        assembly {\n            $.slot := slot\n        }\n    }\n}\n"},{"file_path":"@chainlink/contracts-ccip/contracts/libraries/Internal.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {MerkleMultiProof} from \"../libraries/MerkleMultiProof.sol\";\n\n/// @notice Library for CCIP internal definitions common to multiple contracts.\n/// @dev The following is a non-exhaustive list of \"known issues\" for CCIP:\n/// - We could implement yield claiming for Blast. This is not worth the custom code path on non-blast chains.\n/// - uint32 is used for timestamps, which will overflow in 2106. This is not a concern for the current use case, as we\n/// expect to have migrated to a new version by then.\nlibrary Internal {\n  error InvalidEVMAddress(bytes encodedAddress);\n  error Invalid32ByteAddress(bytes encodedAddress);\n  error InvalidTVMAddress(bytes encodedAddress);\n\n  /// @dev We limit return data to a selector plus 4 words. This is to avoid malicious contracts from returning\n  /// large amounts of data and causing repeated out-of-gas scenarios.\n  uint16 internal constant MAX_RET_BYTES = 4 + 4 * 32;\n  /// @dev The expected number of bytes returned by the balanceOf function.\n  uint256 internal constant MAX_BALANCE_OF_RET_BYTES = 32;\n\n  /// @dev The address used to send calls for gas estimation.\n  /// You only need to use this address if the minimum gas limit specified by the user is not actually enough to execute the\n  /// given message and you're attempting to estimate the actual necessary gas limit\n  address public constant GAS_ESTIMATION_SENDER = address(0xC11C11C11C11C11C11C11C11C11C11C11C11C1);\n\n  /// @notice A collection of token price and gas price updates.\n  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\n  struct PriceUpdates {\n    TokenPriceUpdate[] tokenPriceUpdates;\n    GasPriceUpdate[] gasPriceUpdates;\n  }\n\n  /// @notice Token price in USD.\n  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\n  struct TokenPriceUpdate {\n    address sourceToken; // Source token.\n    uint224 usdPerToken; // 1e18 USD per 1e18 of the smallest token denomination.\n  }\n\n  /// @notice Gas price for a given chain in USD, its value may contain tightly packed fields.\n  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\n  struct GasPriceUpdate {\n    uint64 destChainSelector; // Destination chain selector.\n    uint224 usdPerUnitGas; // 1e18 USD per smallest unit (e.g. wei) of destination chain gas.\n  }\n\n  /// @notice A timestamped uint224 value that can contain several tightly packed fields.\n  struct TimestampedPackedUint224 {\n    uint224 value; // ────╮ Value in uint224, packed.\n    uint32 timestamp; // ─╯ Timestamp of the most recent price update.\n  }\n\n  /// @dev Gas price is stored in 112-bit unsigned int. uint224 can pack 2 prices.\n  /// When packing L1 and L2 gas prices, L1 gas price is left-shifted to the higher-order bits.\n  /// Using uint8 type, which cannot be higher than other bit shift operands, to avoid shift operand type warning.\n  uint8 public constant GAS_PRICE_BITS = 112;\n\n  struct SourceTokenData {\n    // The source pool address, abi encoded. This value is trusted as it was obtained through the onRamp. It can be\n    // relied upon by the destination pool to validate the source pool.\n    bytes sourcePoolAddress;\n    // The address of the destination token, abi encoded in the case of EVM chains.\n    // This value is UNTRUSTED as any pool owner can return whatever value they want.\n    bytes destTokenAddress;\n    // Optional pool data to be transferred to the destination chain. Be default this is capped at\n    // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead\n    // has to be set for the specific token.\n    bytes extraData;\n    uint32 destGasAmount; // The amount of gas available for the releaseOrMint and balanceOf calls on the offRamp\n  }\n\n  /// @notice Report that is submitted by the execution DON at the execution phase, including chain selector data.\n  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\n  struct ExecutionReport {\n    uint64 sourceChainSelector; // Source chain selector for which the report is submitted.\n    Any2EVMRampMessage[] messages;\n    // Contains a bytes array for each message, each inner bytes array contains bytes per transferred token.\n    bytes[][] offchainTokenData;\n    bytes32[] proofs;\n    uint256 proofFlagBits;\n  }\n\n  /// @dev Any2EVMRampMessage struct has 10 fields, including 3 variable unnested arrays, sender, data and tokenAmounts.\n  /// Each variable array takes 1 more slot to store its length.\n  /// When abi encoded, excluding array contents, Any2EVMMessage takes up a fixed number of 13 slots, 32 bytes each.\n  /// Assume 1 slot for sender\n  /// For structs that contain arrays, 1 more slot is added to the front, reaching a total of 14.\n  /// The fixed bytes does not cover struct data (this is represented by MESSAGE_FIXED_BYTES_PER_TOKEN)\n  uint256 public constant MESSAGE_FIXED_BYTES = 32 * 15;\n\n  /// @dev Any2EVMTokensTransfer struct bytes length\n  /// 0x20\n  /// sourcePoolAddress_offset\n  /// destTokenAddress\n  /// destGasAmount\n  /// extraData_offset\n  /// amount\n  /// sourcePoolAddress_length\n  /// sourcePoolAddress_content // assume 1 slot\n  /// extraData_length // contents billed separately\n  uint256 public constant MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * (4 + (3 + 2));\n\n  bytes32 internal constant ANY_2_EVM_MESSAGE_HASH = keccak256(\"Any2EVMMessageHashV1\");\n  bytes32 internal constant EVM_2_ANY_MESSAGE_HASH = keccak256(\"EVM2AnyMessageHashV1\");\n\n  /// @dev Used to hash messages for multi-lane family-agnostic OffRamps.\n  /// OnRamp hash(EVM2AnyMessage) != Any2EVMRampMessage.messageId.\n  /// OnRamp hash(EVM2AnyMessage) != OffRamp hash(Any2EVMRampMessage).\n  /// @param original OffRamp message to hash.\n  /// @param metadataHash Hash preimage to ensure global uniqueness.\n  /// @return hashedMessage hashed message as a keccak256.\n  function _hash(Any2EVMRampMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {\n    // Fixed-size message fields are included in nested hash to reduce stack pressure.\n    // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.\n    return keccak256(\n      abi.encode(\n        MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,\n        metadataHash,\n        keccak256(\n          abi.encode(\n            original.header.messageId,\n            original.receiver,\n            original.header.sequenceNumber,\n            original.gasLimit,\n            original.header.nonce\n          )\n        ),\n        keccak256(original.sender),\n        keccak256(original.data),\n        keccak256(abi.encode(original.tokenAmounts))\n      )\n    );\n  }\n\n  function _hash(EVM2AnyRampMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {\n    // Fixed-size message fields are included in nested hash to reduce stack pressure.\n    // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.\n    return keccak256(\n      abi.encode(\n        MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,\n        metadataHash,\n        keccak256(\n          abi.encode(\n            original.sender,\n            original.header.sequenceNumber,\n            original.header.nonce,\n            original.feeToken,\n            original.feeTokenAmount\n          )\n        ),\n        keccak256(original.receiver),\n        keccak256(original.data),\n        keccak256(abi.encode(original.tokenAmounts)),\n        keccak256(original.extraArgs)\n      )\n    );\n  }\n\n  /// @dev We disallow the first 1024 addresses to avoid calling into a range known for hosting precompiles. Calling\n  /// into precompiles probably won't cause any issues, but to be safe we can disallow this range. It is extremely\n  /// unlikely that anyone would ever be able to generate an address in this range. There is no official range of\n  /// precompiles, but EIP-7587 proposes to reserve the range 0x100 to 0x1ff. Our range is more conservative, even\n  /// though it might not be exhaustive for all chains, which is OK. We also disallow the zero address, which is a\n  /// common practice.\n  uint256 public constant EVM_PRECOMPILE_SPACE = 1024;\n\n  // According to the Aptos docs, the first 0xa addresses are reserved for precompiles.\n  // https://github.com/aptos-labs/aptos-core/blob/main/aptos-move/framework/aptos-framework/doc/account.md#function-create_framework_reserved_account-1\n  uint256 public constant APTOS_PRECOMPILE_SPACE = 0x0b;\n\n  /// @notice This methods provides validation for parsing abi encoded addresses by ensuring the address is within the\n  /// EVM address space. If it isn't it will revert with an InvalidEVMAddress error, which we can catch and handle\n  /// more gracefully than a revert from abi.decode.\n  function _validateEVMAddress(\n    bytes memory encodedAddress\n  ) internal pure {\n    if (encodedAddress.length != 32) revert InvalidEVMAddress(encodedAddress);\n    uint256 encodedAddressUint = abi.decode(encodedAddress, (uint256));\n    if (encodedAddressUint > type(uint160).max || encodedAddressUint < EVM_PRECOMPILE_SPACE) {\n      revert InvalidEVMAddress(encodedAddress);\n    }\n  }\n\n  /// @notice This methods provides validation for parsing abi encoded addresses by ensuring the address is within the\n  /// bounds of [minValue, uint256.max]. If it isn't it will revert with an Invalid32ByteAddress error.\n  function _validate32ByteAddress(bytes memory encodedAddress, uint256 minValue) internal pure {\n    if (encodedAddress.length != 32) revert Invalid32ByteAddress(encodedAddress);\n    if (minValue > 0) {\n      if (abi.decode(encodedAddress, (uint256)) < minValue) {\n        revert Invalid32ByteAddress(encodedAddress);\n      }\n    }\n  }\n\n  /// @notice This methods provides validation for TON User-friendly addresses by ensuring the address is 36 bytes long.\n  /// @dev The encodedAddress is expected to be the 36-byte raw representation:\n  /// - 1 byte: flags (isBounceable, isTestnetOnly, etc.)\n  /// - 1 byte: workchain_id (0x00 for BaseChain, 0xff for MasterChain)\n  /// - 32 bytes: account_id\n  /// - 2 bytes: CRC16 checksum(computationally heavy, validation omitted for simplicity)\n  /// @param encodedAddress The 36-byte TON address.\n  function _validateTVMAddress(\n    bytes memory encodedAddress\n  ) internal pure {\n    if (encodedAddress.length != 36) revert InvalidTVMAddress(encodedAddress);\n    bytes32 accountId;\n    assembly {\n      accountId := mload(add(encodedAddress, 0x22)) // 0x22 = 0x20 (data start) + 2 (offset for account_id)\n    }\n    if (accountId == bytes32(0)) revert InvalidTVMAddress(encodedAddress);\n  }\n\n  /// @notice Enum listing the possible message execution states within the offRamp contract.\n  /// UNTOUCHED never executed.\n  /// IN_PROGRESS currently being executed, used a replay protection.\n  /// SUCCESS successfully executed. End state.\n  /// FAILURE unsuccessfully executed, manual execution is now enabled.\n  /// @dev RMN depends on this enum, if changing, please notify the RMN maintainers.\n  enum MessageExecutionState {\n    UNTOUCHED,\n    IN_PROGRESS,\n    SUCCESS,\n    FAILURE\n  }\n\n  /// @notice CCIP OCR plugin type, used to separate execution & commit transmissions and configs.\n  enum OCRPluginType {\n    Commit,\n    Execution\n  }\n\n  /// @notice Family-agnostic header for OnRamp & OffRamp messages.\n  /// The messageId is not expected to match hash(message), since it may originate from another ramp family.\n  struct RampMessageHeader {\n    bytes32 messageId; // Unique identifier for the message, generated with the source chain's encoding scheme (i.e. not necessarily abi.encoded).\n    uint64 sourceChainSelector; // ─╮ the chain selector of the source chain, note: not chainId.\n    uint64 destChainSelector; //    │ the chain selector of the destination chain, note: not chainId.\n    uint64 sequenceNumber; //       │ sequence number, not unique across lanes.\n    uint64 nonce; // ───────────────╯ nonce for this lane for this sender, not unique across senders/lanes.\n  }\n\n  struct EVM2AnyTokenTransfer {\n    // The source pool EVM address. This value is trusted as it was obtained through the onRamp. It can be relied\n    // upon by the destination pool to validate the source pool.\n    address sourcePoolAddress;\n    // The EVM address of the destination token.\n    // This value is UNTRUSTED as any pool owner can return whatever value they want.\n    bytes destTokenAddress;\n    // Optional pool data to be transferred to the destination chain. Be default this is capped at\n    // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead\n    // has to be set for the specific token.\n    bytes extraData;\n    uint256 amount; // Amount of tokens.\n    // Destination chain data used to execute the token transfer on the destination chain. For an EVM destination, it\n    // consists of the amount of gas available for the releaseOrMint and transfer calls made by the offRamp.\n    bytes destExecData;\n  }\n\n  struct Any2EVMTokenTransfer {\n    // The source pool EVM address encoded to bytes. This value is trusted as it is obtained through the onRamp. It can\n    // be relied upon by the destination pool to validate the source pool.\n    bytes sourcePoolAddress;\n    address destTokenAddress; // ─╮ Address of destination token\n    uint32 destGasAmount; // ─────╯ The amount of gas available for the releaseOrMint and transfer calls on the offRamp.\n    // Optional pool data to be transferred to the destination chain. Be default this is capped at\n    // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead\n    // has to be set for the specific token.\n    bytes extraData;\n    uint256 amount; // Amount of tokens.\n  }\n\n  /// @notice Family-agnostic message routed to an OffRamp.\n  /// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage), hash(Any2EVMRampMessage) != messageId due to encoding\n  /// and parameter differences.\n  struct Any2EVMRampMessage {\n    RampMessageHeader header; // Message header.\n    bytes sender; // sender address on the source chain.\n    bytes data; // arbitrary data payload supplied by the message sender.\n    address receiver; // receiver address on the destination chain.\n    uint256 gasLimit; // user supplied maximum gas amount available for dest chain execution.\n    Any2EVMTokenTransfer[] tokenAmounts; // array of tokens and amounts to transfer.\n  }\n\n  /// @notice Family-agnostic message emitted from the OnRamp.\n  /// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage) due to encoding & parameter differences.\n  /// messageId = hash(EVM2AnyRampMessage) using the source EVM chain's encoding format.\n  struct EVM2AnyRampMessage {\n    RampMessageHeader header; // Message header.\n    address sender; // sender address on the source chain.\n    bytes data; // arbitrary data payload supplied by the message sender.\n    bytes receiver; // receiver address on the destination chain.\n    bytes extraArgs; // destination-chain specific extra args, such as the gasLimit for EVM chains.\n    address feeToken; // fee token.\n    uint256 feeTokenAmount; // fee token amount.\n    uint256 feeValueJuels; // fee amount in Juels.\n    EVM2AnyTokenTransfer[] tokenAmounts; // array of tokens and amounts to transfer.\n  }\n\n  // bytes4(keccak256(\"CCIP ChainFamilySelector EVM\"));\n  bytes4 public constant CHAIN_FAMILY_SELECTOR_EVM = 0x2812d52c;\n\n  // bytes4(keccak256(\"CCIP ChainFamilySelector SVM\"));\n  bytes4 public constant CHAIN_FAMILY_SELECTOR_SVM = 0x1e10bdc4;\n\n  // bytes4(keccak256(\"CCIP ChainFamilySelector APTOS\"));\n  bytes4 public constant CHAIN_FAMILY_SELECTOR_APTOS = 0xac77ffec;\n\n  // bytes4(keccak256(\"CCIP ChainFamilySelector SUI\"));\n  bytes4 public constant CHAIN_FAMILY_SELECTOR_SUI = 0xc4e05953;\n\n  // byte4(keccak256(\"CCIP ChainFamilySelector TVM\"));\n  bytes4 public constant CHAIN_FAMILY_SELECTOR_TVM = 0x647e2ba9;\n\n  /// @dev Holds a merkle root and interval for a source chain so that an array of these can be passed in the CommitReport.\n  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\n  /// @dev inefficient struct packing intentionally chosen to maintain order of specificity. Not a storage struct so impact is minimal.\n  // solhint-disable-next-line gas-struct-packing\n  struct MerkleRoot {\n    uint64 sourceChainSelector; // Remote source chain selector that the Merkle Root is scoped to\n    bytes onRampAddress; //        Generic onRamp address, to support arbitrary sources; for EVM, use abi.encode\n    uint64 minSeqNr; // ─────────╮ Minimum sequence number, inclusive\n    uint64 maxSeqNr; // ─────────╯ Maximum sequence number, inclusive\n    bytes32 merkleRoot; //         Merkle root covering the interval & source chain messages\n  }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/math/Math.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Floor, // Toward negative infinity\n        Ceil, // Toward positive infinity\n        Trunc, // Toward zero\n        Expand // Away from zero\n    }\n\n    /**\n     * @dev Return the 512-bit addition of two uint256.\n     *\n     * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.\n     */\n    function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n        assembly (\"memory-safe\") {\n            low := add(a, b)\n            high := lt(low, a)\n        }\n    }\n\n    /**\n     * @dev Return the 512-bit multiplication of two uint256.\n     *\n     * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.\n     */\n    function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n        // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n        // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n        // variables such that product = high * 2²⁵⁶ + low.\n        assembly (\"memory-safe\") {\n            let mm := mulmod(a, b, not(0))\n            low := mul(a, b)\n            high := sub(sub(mm, low), lt(mm, low))\n        }\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            uint256 c = a + b;\n            success = c >= a;\n            result = c * SafeCast.toUint(success);\n        }\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            uint256 c = a - b;\n            success = c <= a;\n            result = c * SafeCast.toUint(success);\n        }\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            uint256 c = a * b;\n            assembly (\"memory-safe\") {\n                // Only true when the multiplication doesn't overflow\n                // (c / a == b) || (a == 0)\n                success := or(eq(div(c, a), b), iszero(a))\n            }\n            // equivalent to: success ? c : 0\n            result = c * SafeCast.toUint(success);\n        }\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            success = b > 0;\n            assembly (\"memory-safe\") {\n                // The `DIV` opcode returns zero when the denominator is 0.\n                result := div(a, b)\n            }\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            success = b > 0;\n            assembly (\"memory-safe\") {\n                // The `MOD` opcode returns zero when the denominator is 0.\n                result := mod(a, b)\n            }\n        }\n    }\n\n    /**\n     * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.\n     */\n    function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {\n        (bool success, uint256 result) = tryAdd(a, b);\n        return ternary(success, result, type(uint256).max);\n    }\n\n    /**\n     * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.\n     */\n    function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {\n        (, uint256 result) = trySub(a, b);\n        return result;\n    }\n\n    /**\n     * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.\n     */\n    function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {\n        (bool success, uint256 result) = tryMul(a, b);\n        return ternary(success, result, type(uint256).max);\n    }\n\n    /**\n     * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n     *\n     * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n     * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n     * one branch when needed, making this function more expensive.\n     */\n    function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n        unchecked {\n            // branchless ternary works because:\n            // b ^ (a ^ b) == a\n            // b ^ 0 == b\n            return b ^ ((a ^ b) * SafeCast.toUint(condition));\n        }\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return ternary(a > b, a, b);\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return ternary(a < b, a, b);\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds towards infinity instead\n     * of rounding towards zero.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (b == 0) {\n            // Guarantee the same behavior as in a regular Solidity division.\n            Panic.panic(Panic.DIVISION_BY_ZERO);\n        }\n\n        // The following calculation ensures accurate ceiling division without overflow.\n        // Since a is non-zero, (a - 1) / b will not overflow.\n        // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n        // but the largest value we can obtain is type(uint256).max - 1, which happens\n        // when a = type(uint256).max and b = 1.\n        unchecked {\n            return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n        }\n    }\n\n    /**\n     * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n     * denominator == 0.\n     *\n     * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n     * Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            (uint256 high, uint256 low) = mul512(x, y);\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (high == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return low / denominator;\n            }\n\n            // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n            if (denominator <= high) {\n                Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n            }\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [high low].\n            uint256 remainder;\n            assembly (\"memory-safe\") {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                high := sub(high, gt(remainder, low))\n                low := sub(low, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n            uint256 twos = denominator & (0 - denominator);\n            assembly (\"memory-safe\") {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [high low] by twos.\n                low := div(low, twos)\n\n                // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from high into low.\n            low |= high * twos;\n\n            // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n            // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n            // works in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n            inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n            inverse *= 2 - denominator * inverse; // inverse mod 2³²\n            inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n            inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n            inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n            // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high\n            // is no longer required.\n            result = low * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n    }\n\n    /**\n     * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.\n     */\n    function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {\n        unchecked {\n            (uint256 high, uint256 low) = mul512(x, y);\n            if (high >= 1 << n) {\n                Panic.panic(Panic.UNDER_OVERFLOW);\n            }\n            return (high << (256 - n)) | (low >> n);\n        }\n    }\n\n    /**\n     * @dev Calculates x * y >> n with full precision, following the selected rounding direction.\n     */\n    function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {\n        return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);\n    }\n\n    /**\n     * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n     *\n     * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n     * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n     *\n     * If the input value is not inversible, 0 is returned.\n     *\n     * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n     * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n     */\n    function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n        unchecked {\n            if (n == 0) return 0;\n\n            // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n            // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n            // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n            // ax + ny = 1\n            // ax = 1 + (-y)n\n            // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n            // If the remainder is 0 the gcd is n right away.\n            uint256 remainder = a % n;\n            uint256 gcd = n;\n\n            // Therefore the initial coefficients are:\n            // ax + ny = gcd(a, n) = n\n            // 0a + 1n = n\n            int256 x = 0;\n            int256 y = 1;\n\n            while (remainder != 0) {\n                uint256 quotient = gcd / remainder;\n\n                (gcd, remainder) = (\n                    // The old remainder is the next gcd to try.\n                    remainder,\n                    // Compute the next remainder.\n                    // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n                    // where gcd is at most n (capped to type(uint256).max)\n                    gcd - remainder * quotient\n                );\n\n                (x, y) = (\n                    // Increment the coefficient of a.\n                    y,\n                    // Decrement the coefficient of n.\n                    // Can overflow, but the result is casted to uint256 so that the\n                    // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n                    x - y * int256(quotient)\n                );\n            }\n\n            if (gcd != 1) return 0; // No inverse exists.\n            return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n        }\n    }\n\n    /**\n     * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n     *\n     * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n     * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n     * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n     *\n     * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n     */\n    function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n        unchecked {\n            return Math.modExp(a, p - 2, p);\n        }\n    }\n\n    /**\n     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n     *\n     * Requirements:\n     * - modulus can't be zero\n     * - underlying staticcall to precompile must succeed\n     *\n     * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n     * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n     * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n     * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n     * interpreted as 0.\n     */\n    function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n        (bool success, uint256 result) = tryModExp(b, e, m);\n        if (!success) {\n            Panic.panic(Panic.DIVISION_BY_ZERO);\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n     * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n     * to operate modulo 0 or if the underlying precompile reverted.\n     *\n     * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n     * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n     * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n     * of a revert, but the result may be incorrectly interpreted as 0.\n     */\n    function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n        if (m == 0) return (false, 0);\n        assembly (\"memory-safe\") {\n            let ptr := mload(0x40)\n            // | Offset    | Content    | Content (Hex)                                                      |\n            // |-----------|------------|--------------------------------------------------------------------|\n            // | 0x00:0x1f | size of b  | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n            // | 0x20:0x3f | size of e  | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n            // | 0x40:0x5f | size of m  | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n            // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n            // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n            // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n            mstore(ptr, 0x20)\n            mstore(add(ptr, 0x20), 0x20)\n            mstore(add(ptr, 0x40), 0x20)\n            mstore(add(ptr, 0x60), b)\n            mstore(add(ptr, 0x80), e)\n            mstore(add(ptr, 0xa0), m)\n\n            // Given the result < m, it's guaranteed to fit in 32 bytes,\n            // so we can use the memory scratch space located at offset 0.\n            success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n            result := mload(0x00)\n        }\n    }\n\n    /**\n     * @dev Variant of {modExp} that supports inputs of arbitrary length.\n     */\n    function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n        (bool success, bytes memory result) = tryModExp(b, e, m);\n        if (!success) {\n            Panic.panic(Panic.DIVISION_BY_ZERO);\n        }\n        return result;\n    }\n\n    /**\n     * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n     */\n    function tryModExp(\n        bytes memory b,\n        bytes memory e,\n        bytes memory m\n    ) internal view returns (bool success, bytes memory result) {\n        if (_zeroBytes(m)) return (false, new bytes(0));\n\n        uint256 mLen = m.length;\n\n        // Encode call args in result and move the free memory pointer\n        result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n        assembly (\"memory-safe\") {\n            let dataPtr := add(result, 0x20)\n            // Write result on top of args to avoid allocating extra memory.\n            success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n            // Overwrite the length.\n            // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n            mstore(result, mLen)\n            // Set the memory pointer after the returned data.\n            mstore(0x40, add(dataPtr, mLen))\n        }\n    }\n\n    /**\n     * @dev Returns whether the provided byte array is zero.\n     */\n    function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n        for (uint256 i = 0; i < byteArray.length; ++i) {\n            if (byteArray[i] != 0) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n     * towards zero.\n     *\n     * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n     * using integer operations.\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        unchecked {\n            // Take care of easy edge cases when a == 0 or a == 1\n            if (a <= 1) {\n                return a;\n            }\n\n            // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n            // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n            // the current value as `ε_n = | x_n - sqrt(a) |`.\n            //\n            // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n            // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n            // bigger than any uint256.\n            //\n            // By noticing that\n            // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n            // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n            // to the msb function.\n            uint256 aa = a;\n            uint256 xn = 1;\n\n            if (aa >= (1 << 128)) {\n                aa >>= 128;\n                xn <<= 64;\n            }\n            if (aa >= (1 << 64)) {\n                aa >>= 64;\n                xn <<= 32;\n            }\n            if (aa >= (1 << 32)) {\n                aa >>= 32;\n                xn <<= 16;\n            }\n            if (aa >= (1 << 16)) {\n                aa >>= 16;\n                xn <<= 8;\n            }\n            if (aa >= (1 << 8)) {\n                aa >>= 8;\n                xn <<= 4;\n            }\n            if (aa >= (1 << 4)) {\n                aa >>= 4;\n                xn <<= 2;\n            }\n            if (aa >= (1 << 2)) {\n                xn <<= 1;\n            }\n\n            // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n            //\n            // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n            // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n            // This is going to be our x_0 (and ε_0)\n            xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n            // From here, Newton's method give us:\n            // x_{n+1} = (x_n + a / x_n) / 2\n            //\n            // One should note that:\n            // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n            //              = ((x_n² + a) / (2 * x_n))² - a\n            //              = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n            //              = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n            //              = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n            //              = (x_n² - a)² / (2 * x_n)²\n            //              = ((x_n² - a) / (2 * x_n))²\n            //              ≥ 0\n            // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n            //\n            // This gives us the proof of quadratic convergence of the sequence:\n            // ε_{n+1} = | x_{n+1} - sqrt(a) |\n            //         = | (x_n + a / x_n) / 2 - sqrt(a) |\n            //         = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n            //         = | (x_n - sqrt(a))² / (2 * x_n) |\n            //         = | ε_n² / (2 * x_n) |\n            //         = ε_n² / | (2 * x_n) |\n            //\n            // For the first iteration, we have a special case where x_0 is known:\n            // ε_1 = ε_0² / | (2 * x_0) |\n            //     ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n            //     ≤ 2**(2*e-4) / (3 * 2**(e-1))\n            //     ≤ 2**(e-3) / 3\n            //     ≤ 2**(e-3-log2(3))\n            //     ≤ 2**(e-4.5)\n            //\n            // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n            // ε_{n+1} = ε_n² / | (2 * x_n) |\n            //         ≤ (2**(e-k))² / (2 * 2**(e-1))\n            //         ≤ 2**(2*e-2*k) / 2**e\n            //         ≤ 2**(e-2*k)\n            xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5)  -- special case, see above\n            xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9)    -- general case with k = 4.5\n            xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18)   -- general case with k = 9\n            xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36)   -- general case with k = 18\n            xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72)   -- general case with k = 36\n            xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144)  -- general case with k = 72\n\n            // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n            // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n            // sqrt(a) or sqrt(a) + 1.\n            return xn - SafeCast.toUint(xn > a / xn);\n        }\n    }\n\n    /**\n     * @dev Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 x) internal pure returns (uint256 r) {\n        // If value has upper 128 bits set, log2 result is at least 128\n        r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n        // If upper 64 bits of 128-bit half set, add 64 to result\n        r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n        // If upper 32 bits of 64-bit half set, add 32 to result\n        r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n        // If upper 16 bits of 32-bit half set, add 16 to result\n        r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n        // If upper 8 bits of 16-bit half set, add 8 to result\n        r |= SafeCast.toUint((x >> r) > 0xff) << 3;\n        // If upper 4 bits of 8-bit half set, add 4 to result\n        r |= SafeCast.toUint((x >> r) > 0xf) << 2;\n\n        // Shifts value right by the current result and use it as an index into this lookup table:\n        //\n        // | x (4 bits) |  index  | table[index] = MSB position |\n        // |------------|---------|-----------------------------|\n        // |    0000    |    0    |        table[0] = 0         |\n        // |    0001    |    1    |        table[1] = 0         |\n        // |    0010    |    2    |        table[2] = 1         |\n        // |    0011    |    3    |        table[3] = 1         |\n        // |    0100    |    4    |        table[4] = 2         |\n        // |    0101    |    5    |        table[5] = 2         |\n        // |    0110    |    6    |        table[6] = 2         |\n        // |    0111    |    7    |        table[7] = 2         |\n        // |    1000    |    8    |        table[8] = 3         |\n        // |    1001    |    9    |        table[9] = 3         |\n        // |    1010    |   10    |        table[10] = 3        |\n        // |    1011    |   11    |        table[11] = 3        |\n        // |    1100    |   12    |        table[12] = 3        |\n        // |    1101    |   13    |        table[13] = 3        |\n        // |    1110    |   14    |        table[14] = 3        |\n        // |    1111    |   15    |        table[15] = 3        |\n        //\n        // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.\n        assembly (\"memory-safe\") {\n            r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 x) internal pure returns (uint256 r) {\n        // If value has upper 128 bits set, log2 result is at least 128\n        r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n        // If upper 64 bits of 128-bit half set, add 64 to result\n        r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n        // If upper 32 bits of 64-bit half set, add 32 to result\n        r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n        // If upper 16 bits of 32-bit half set, add 16 to result\n        r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n        // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8\n        return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n        }\n    }\n\n    /**\n     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n     */\n    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n        return uint8(rounding) % 2 == 1;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"@openzeppelin/contracts/access/IAccessControl.sol\";\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {ERC165Upgradeable} from \"../utils/introspection/ERC165Upgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {\n    struct RoleData {\n        mapping(address account => bool) hasRole;\n        bytes32 adminRole;\n    }\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl\n    struct AccessControlStorage {\n        mapping(bytes32 role => RoleData) _roles;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.AccessControl\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;\n\n    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {\n        assembly {\n            $.slot := AccessControlStorageLocation\n        }\n    }\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with an {AccessControlUnauthorizedAccount} error including the required role.\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    function __AccessControl_init() internal onlyInitializing {\n    }\n\n    function __AccessControl_init_unchained() internal onlyInitializing {\n    }\n    /// @inheritdoc IERC165\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        return $._roles[role].hasRole[account];\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n     * is missing `role`.\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert AccessControlUnauthorizedAccount(account, role);\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        return $._roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n        if (callerConfirmation != _msgSender()) {\n            revert AccessControlBadConfirmation();\n        }\n\n        _revokeRole(role, callerConfirmation);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        $._roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        if (!hasRole(role, account)) {\n            $._roles[role].hasRole[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        if (hasRole(role, account)) {\n            $._roles[role].hasRole[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/interfaces/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},{"file_path":"@openzeppelin/contracts/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"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":[],"name":"CollateralAmountIsZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"customMessageId","type":"uint256"}],"name":"CustomMessageIdIsUsed","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FeeRateTooHigh","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"bytes","name":"encodedAddress","type":"bytes"}],"name":"InvalidEVMAddress","type":"error"},{"inputs":[{"internalType":"uint8","name":"feeType","type":"uint8"}],"name":"InvalidFeeType","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidNativeTokenSender","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"RedeemAmountIsZero","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"RefundFailed","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"UnsupportedAsset","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroFeeToAddress","type":"error"},{"inputs":[],"name":"ZeroTreasuryAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DirectBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"toBytes32","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"destinationChainIdOrSelector","type":"uint64"}],"name":"DirectMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldFeeTo","type":"address"},{"indexed":true,"internalType":"address","name":"newFeeTo","type":"address"}],"name":"FeeToUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":true,"internalType":"bytes32","name":"toBytes32","type":"bytes32"},{"indexed":true,"internalType":"address","name":"collateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fusdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"destinationChainIdOrSelector","type":"uint64"}],"name":"InstantMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bytes32","name":"toBytes32","type":"bytes32"},{"indexed":true,"internalType":"address","name":"collateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"fusdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"InstantRedeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"MintFeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"customMessageId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"MintWithCustomMessageId","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"RedeemFeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RedeemRequested","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":"oldTreasury","type":"address"},{"indexed":true,"internalType":"address","name":"newTreasury","type":"address"}],"name":"TreasuryUpdated","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":"MINTER_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":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"enum IFUSDGateway.FeeType","name":"feeType","type":"uint8"}],"name":"calculateFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collateral","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"convertFromCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collateral","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"convertToCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[{"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":"_fusd","type":"address"},{"internalType":"address","name":"_lp","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_kycModule","type":"address"},{"internalType":"uint256","name":"_mintFeeRate","type":"uint256"},{"internalType":"uint256","name":"_redeemFeeRate","type":"uint256"},{"internalType":"address","name":"_feeTo","type":"address"},{"internalType":"address","name":"_bridgeSender","type":"address"},{"internalType":"address","name":"admin","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"toBytes32","type":"bytes32"},{"internalType":"address","name":"collateral","type":"address"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"internalType":"uint64","name":"destinationChainIdOrSelector","type":"uint64"}],"name":"instantMint","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"toBytes32","type":"bytes32"},{"internalType":"address","name":"redeemCollateral","type":"address"},{"internalType":"uint256","name":"FUSDAmountToBurn","type":"uint256"}],"name":"instantRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_customMessageId","type":"uint256"}],"name":"isCustomMessageIdUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"toBytes32","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint64","name":"destinationChainIdOrSelector","type":"uint64"}],"name":"mint","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"customMessageIdBytes32","type":"bytes32"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintWithMessageId","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":"address","name":"collateral","type":"address"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collateral","type":"address"},{"internalType":"uint256","name":"FUSDAmountToBurn","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"redeemRequest","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":"address","name":"newFeeTo","type":"address"}],"name":"setFeeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTreasury","type":"address"}],"name":"setTreasury","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":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"updateMintFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"updateRedeemFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":null}