{"file_path":"contracts/fusd-lp/FUSDLP.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {\n    AccessControlEnumerableUpgradeable\n} from \"@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 {ERC20Upgradeable} from \"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol\";\nimport {EnumerableMap} from \"@openzeppelin/contracts/utils/structs/EnumerableMap.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {IBaseReservePriceFeed} from \"../interfaces/IBaseReservePriceFeed.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {TokenDecimalsConvert} from \"../utils/TokenDecimalsConvert.sol\";\nimport {IFUSDLP} from \"../interfaces/IFUSDLP.sol\";\nimport {IKycModule} from \"../interfaces/IKycModule.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {SafeCast} from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport {ITokenBridgeSender} from \"../interfaces/ITokenBridgeSender.sol\";\nimport {AddressConvert} from \"../utils/AddressConvert.sol\";\nimport {BitMaps} from \"@openzeppelin/contracts/utils/structs/BitMaps.sol\";\nimport {LibArray} from \"../utils/LibArray.sol\";\nimport {FUSDLPRevenueMath} from \"./FUSDLPRevenueMath.sol\";\n\n/**\n * @title FUSDLP\n * @notice FUSDLP, backed by reserve assets\n * @dev ERC20 LP token based on diversified real-world assets\n * @dev Users can deposit proportional reserve asset combinations to mint LP tokens, or burn LP tokens to redeem corresponding reserve assets\n * @author Finchain Team\n */\ncontract FUSDLP is\n    IFUSDLP,\n    ERC20Upgradeable,\n    AccessControlEnumerableUpgradeable,\n    PausableUpgradeable,\n    ReentrancyGuardUpgradeable\n{\n    using EnumerableMap for EnumerableMap.Bytes32ToUintMap;\n    using SafeERC20 for IERC20;\n    using TokenDecimalsConvert for uint256;\n    using Math for uint256;\n    using SafeCast for int256;\n    using SafeCast for uint256;\n    using BitMaps for BitMaps.BitMap;\n\n    /// @dev Storage structure for FUSDLP contract, using ERC7201 pattern to ensure upgrade safety\n    /// @custom:storage-location erc7201:finchain.storage.FUSDLP\n    struct FUSDLPStorage {\n        /// @dev Reserve asset treasury address, all reserve assets are stored at this address\n        address reserveTreasury;\n        /// @dev Last update reserve info timestamp\n        uint256 updateAt;\n        /// @dev KYC module contract address, used for user identity verification\n        address kycModule;\n        /// @dev Deposit fee (currently unused)\n        uint256 depositFee;\n        /// @dev Redeem fee (currently unused)\n        uint256 redeemFee;\n        address feeTo;\n        /// @dev Mapping from asset key to actual ERC20 contract address\n        mapping(bytes32 => address) reserves;\n        /// @dev Mapping of price feed contract addresses for each reserve asset\n        mapping(bytes32 => address) reservePriceFeed;\n        /// @dev Reserve asset allocation ratio mapping (EnumerableMap ensures enumerability)\n        EnumerableMap.Bytes32ToUintMap reserveRatio;\n        /// @dev Bridge sender contract address used for cross-chain token transfer\n        address bridgeSender;\n        /// @dev Bitmap tracking consumed custom message IDs to prevent replay\n        BitMaps.BitMap usedCustomMessageIds;\n        /// @dev Global LP value adjustment factor (18 decimals, 1e18 = 1.0)\n        uint256 adjustmentFactor;\n        /// @dev Minimum allowed combination amount for deposit/redeem operations (18 decimals)\n        uint256 minimumCombinationAmount;\n        bool depositRedeemEnabled;\n        /// @dev Recipient address for synced reserve revenue transfers\n        address revenueRecipient;\n        /// @dev Authorized caller address for revenue synchronization\n        address revenueSyncCaller;\n        /// @dev Last synced total reserve value snapshot (18 decimals)\n        uint256 lastSyncedReserveValue;\n        /// @dev Last synced LP value snapshot used by revenue sync logic (18 decimals)\n        uint256 lastSyncedLpValue;\n        /// @dev Revenue-specific LP adjustment factor derived during synchronization (18 decimals)\n        uint256 revenueAdjustmentFactor;\n        /// @dev Flag indicating whether revenue synchronization has been initialized\n        bool revenueSyncInitialized;\n        /// @dev LP share ratio used when deriving synced LP value changes (1e27 = 100%)\n        uint256 revenueLpShareRatio;\n        /// @dev Flag indicating whether revenue synchronization is currently enabled\n        bool revenueSyncEnabled;\n        /// @dev High watermark of post-sync reserve value used to distinguish recovery from net new profit\n        uint256 revenueReserveHighWatermark;\n        /// @dev LP value paired with the reserve high watermark to preserve prior realized protocol surplus\n        uint256 revenueLpHighWatermark;\n        /// @dev Internal reserve accounting used by LP pricing and revenue sync (18 decimals)\n        mapping(bytes32 => uint256) trackedReserveAmount;\n    }\n\n    /// @dev Storage slot for FUSDLP data, using ERC7201 pattern\n    /// keccak256(abi.encode(uint256(keccak256(\"finchain.storage.FUSDLP\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 internal constant FUSDLPStorageLocation =\n        0x965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538700;\n\n    /// @dev Constant representing 100%, using 27 decimal precision\n    uint256 internal constant _ONE_HUNDRED = 1e27;\n\n    /// @dev Constant for one combination unit, used for combination value calculation (18 decimal precision)\n    uint256 internal constant _ONE_COMBINATION_UNIT = 1e18;\n\n    /// @dev Base decimals constant, used for calculations (18 decimal precision)\n    uint256 internal constant _BASE_DECIMALS = 1e18;\n\n    uint256 internal constant _MAX_FEE_RATE = 1e16; // 1%\n\n    /// @dev Role identifier for pause permission\n    bytes32 public constant PAUSER_ROLE = keccak256(\"PAUSER_ROLE\");\n    /// @dev Role identifier for mint permission\n    bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n\n    /**\n     * @notice Get reference to FUSDLP storage structure\n     * @dev Uses ERC7201 storage pattern to ensure upgradeable contract storage safety\n     * @return $ Reference to FUSDLP storage structure\n     */\n    function _getsFUSDLPStorage() internal pure returns (FUSDLPStorage storage $) {\n        bytes32 position = FUSDLPStorageLocation;\n        assembly {\n            $.slot := position\n        }\n    }\n    /**\n     * @dev Callback function to receive native tokens\n     */\n\n    receive() external payable {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\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 Initialize FUSDLP contract\n     * @dev Sets up role permissions, token details, reserve treasury and related parameters\n     * @dev This function can only be called once after contract deployment\n     * @param _reserveTreasury Reserve asset treasury address, all reserve assets will be stored at this address\n     * @param admin Administrator address, will be granted DEFAULT_ADMIN_ROLE role\n     * @param _kycModule KYC module contract address, used for user identity verification\n     * @param _depositFee Deposit fee\n     * @param _redeemFee Redeem fee\n     * @param _feeTo Fee recipient address\n     * @param _bridgeSender Cross-chain bridge sender contract address\n     */\n    function initialize(\n        string memory _name,\n        string memory _symbol,\n        address _reserveTreasury,\n        address admin,\n        address _kycModule,\n        uint256 _depositFee,\n        uint256 _redeemFee,\n        address _feeTo,\n        address _bridgeSender\n    ) external initializer {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        $.reserveTreasury = _reserveTreasury;\n\n        __ERC20_init(_name, _symbol);\n\n        __AccessControlEnumerable_init();\n        __Pausable_init();\n        __ReentrancyGuard_init();\n\n        $.kycModule = _kycModule;\n\n        _checkFeeRate(_depositFee);\n        _checkFeeRate(_redeemFee);\n        $.depositFee = _depositFee;\n        $.redeemFee = _redeemFee;\n\n        $.feeTo = _feeTo;\n        $.bridgeSender = _bridgeSender;\n        $.adjustmentFactor = 1e18;\n        $.revenueAdjustmentFactor = 1e18;\n        $.revenueLpShareRatio = 1e27;\n        $.minimumCombinationAmount = 1e18;\n        $.depositRedeemEnabled = false;\n        _grantRole(DEFAULT_ADMIN_ROLE, admin);\n    }\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 whenNotPaused onlyRole(MINTER_ROLE) {\n        _mint(to, amount);\n        _refreshRevenueBaselineIfInitialized();\n    }\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 whenNotPaused onlyRole(MINTER_ROLE) {\n        _burn(msg.sender, amount);\n        _refreshRevenueBaselineIfInitialized();\n    }\n\n    function mintWithCustomMessageId(bytes32 customMessageIdBytes32, address to, uint256 amount)\n        external\n        whenNotPaused\n        onlyRole(MINTER_ROLE)\n    {\n        _consumeCustomMessageId(uint256(customMessageIdBytes32));\n        _mint(to, amount);\n        _refreshRevenueBaselineIfInitialized();\n        emit MintWithCustomMessageId(customMessageIdBytes32, to, amount);\n    }\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        nonReentrant\n        whenNotPaused\n        returns (bytes32 messageId)\n    {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        _checkDepositRedeemEnabled($.depositRedeemEnabled);\n        IKycModule($.kycModule).validateAddress(msg.sender);\n\n        (bytes32[] memory assetKeys,, uint256[] memory amounts, uint256 netShares, uint256 feeAmount) =\n            previewDeposit(combinationAmounts);\n        uint256 length = assetKeys.length;\n        for (uint256 i; i < length; ++i) {\n            bytes32 assetKey = assetKeys[i];\n            address asset = $.reserves[assetKey];\n            if (asset == address(0)) {\n                revert ZeroAddress();\n            }\n            uint256 amount = amounts[i];\n            IERC20(asset).safeTransferFrom(msg.sender, $.reserveTreasury, amount.from18Decimals(asset));\n            $.trackedReserveAmount[assetKey] += amount;\n        }\n\n        if (destinationChainIdOrSelector == 0) {\n            // No cross-chain, mint directly to user\n            address user = AddressConvert.convertBytes32ToEVMAddress(toBytes32);\n            _mint(user, netShares);\n        } else {\n            // Cross-chain, first mint to current contract\n            _mint(address(this), netShares);\n            // Approve\n            _approve(address(this), $.bridgeSender, netShares);\n            // Send to destination chain via bridge contract\n            messageId = ITokenBridgeSender($.bridgeSender).send{value: msg.value}(\n                destinationChainIdOrSelector, toBytes32, address(this), netShares, ITokenBridgeSender.PayFeesIn.Native\n            );\n        }\n\n        if (feeAmount > 0) {\n            _mint($.feeTo, feeAmount);\n        }\n\n        _refreshRevenueBaselineIfInitialized();\n        _refundNativeToken(address(this).balance);\n\n        emit AssetsDeposited(msg.sender, toBytes32, assetKeys, amounts, netShares, destinationChainIdOrSelector);\n    }\n\n    function previewDeposit(uint256 combinationAmounts)\n        public\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        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if (combinationAmounts < $.minimumCombinationAmount) {\n            revert BelowMinimumCombinationAmount(combinationAmounts);\n        }\n        (assetKeys, assetAddresses) = getAssetKeysAndAddress();\n        amounts = new uint256[](assetKeys.length);\n        uint256 length = assetKeys.length;\n        for (uint256 i; i < length; ++i) {\n            amounts[i] = combinationAmounts * $.reserveRatio.get(assetKeys[i]) / _ONE_HUNDRED;\n            if (amounts[i] == 0) {\n                revert ReserveAmountTooSmall(assetKeys[i]);\n            }\n        }\n        uint256 totalAmountsValue = getReservesValue(assetKeys, amounts);\n        uint256 shares = totalAmountsValue * _BASE_DECIMALS / getExchangeRateWithAdjustment();\n        feeAmount = calculateFee(shares, FeeType.Deposit);\n        netShares = shares - feeAmount;\n    }\n\n    /**\n     * @notice Redeem a basket of reserve assets and burn FUSDLP tokens\n     * @dev Validates reserve asset ratios and transfers assets from treasury to user, while burning corresponding LP tokens\n     * @dev Requires user to have passed KYC verification, contract not paused, and user has sufficient LP token balance\n     * @param shares Amount of FUSDLP tokens to burn (18 decimal precision)\n     */\n    function redeem(bytes32 toBytes32, uint256 shares) external nonReentrant whenNotPaused {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if (shares == 0) {\n            revert ZeroShares();\n        }\n        _checkDepositRedeemEnabled($.depositRedeemEnabled);\n        IKycModule($.kycModule).validateAddress(msg.sender);\n        (bytes32[] memory assetKeys,, uint256[] memory amounts, uint256 feeAmount) = previewRedeem(shares);\n        uint256 length = assetKeys.length;\n        address to = AddressConvert.convertBytes32ToEVMAddress(toBytes32);\n        if (to == address(0)) {\n            revert ZeroAddress();\n        }\n        for (uint256 i; i < length; ++i) {\n            bytes32 key = assetKeys[i];\n            address asset = $.reserves[key];\n            if (asset == address(0)) {\n                revert ZeroAddress();\n            }\n            uint256 amount = amounts[i];\n            IERC20(asset).safeTransferFrom($.reserveTreasury, to, amount.from18Decimals(asset));\n            $.trackedReserveAmount[key] -= amount;\n        }\n\n        _burn(msg.sender, shares);\n        if (feeAmount > 0) {\n            _mint($.feeTo, feeAmount);\n        }\n        _refreshRevenueBaselineIfInitialized();\n\n        emit AssetsWithdrawn(msg.sender, toBytes32, assetKeys, amounts, shares);\n    }\n\n    function previewRedeem(uint256 shares)\n        public\n        view\n        returns (\n            bytes32[] memory assetKeys,\n            address[] memory assetAddresses,\n            uint256[] memory amounts,\n            uint256 feeAmount\n        )\n    {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        feeAmount = calculateFee(shares, FeeType.Redeem);\n        (assetKeys, assetAddresses) = getAssetKeysAndAddress();\n        uint256 netShares = shares - feeAmount;\n        uint256 valueOfOneCombination = _getOneCombinationValue();\n        uint256 totalAmountsValue = netShares * getExchangeRateWithAdjustment() / _BASE_DECIMALS;\n        uint256 totalAmounts = totalAmountsValue * _BASE_DECIMALS / valueOfOneCombination;\n        amounts = new uint256[](assetKeys.length);\n        uint256 length = assetKeys.length;\n        for (uint256 i; i < length; ++i) {\n            uint256 ratio = $.reserveRatio.get(assetKeys[i]);\n            amounts[i] = totalAmounts * ratio / _ONE_HUNDRED;\n        }\n    }\n\n    function calculateFee(uint256 amount, FeeType feeType) public view returns (uint256) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 feeRate;\n        if (feeType == FeeType.Deposit) {\n            feeRate = $.depositFee;\n        } else if (feeType == FeeType.Redeem) {\n            feeRate = $.redeemFee;\n        } else {\n            revert InvalidFeeType();\n        }\n        uint256 fee = amount.mulDiv(feeRate, _BASE_DECIMALS);\n        return fee;\n    }\n\n    function setReservesInfo(\n        bytes32[] calldata assetKeys,\n        address[] calldata assetAddresses,\n        uint256[] calldata ratio,\n        address[] calldata priceFeed\n    ) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 prevExchangeRate = getExchangeRateWithAdjustment();\n        _checkAssetKeysDuplicate(assetKeys);\n        _setReserves(assetKeys, assetAddresses);\n        _setReservesRatio(assetKeys, ratio);\n        _setReservesPriceFeed(assetKeys, priceFeed);\n        uint256 newExchangeRate = getExchangeRate();\n        if (newExchangeRate == 0) {\n            revert NewExchangeRateIsZero();\n        }\n        uint256 revenueAdjustedExchangeRate = newExchangeRate.mulDiv(_revenueAdjustmentFactor(), _BASE_DECIMALS);\n        uint256 adjustmentFactor =\n            prevExchangeRate > 0 ? prevExchangeRate.mulDiv(_BASE_DECIMALS, revenueAdjustedExchangeRate) : 1e18;\n        if (adjustmentFactor == 0) {\n            revert InvalidAdjustmentFactor();\n        }\n        $.adjustmentFactor = adjustmentFactor;\n        $.updateAt = block.timestamp;\n    }\n\n    /**\n     * @notice Set ERC20 contract address mapping for reserve assets\n     * @dev Only admin role can call, establishes correspondence between asset keys and actual ERC20 contract addresses\n     * @dev Must be called before setting asset ratios to ensure asset keys have corresponding contract addresses\n     * @param assetKeys Reserve asset identifier array\n     * @param assetAddresses Corresponding ERC20 contract address array\n     */\n    function _setReserves(bytes32[] calldata assetKeys, address[] calldata assetAddresses) internal {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if (assetKeys.length != assetAddresses.length) {\n            revert InvalidArrayLength();\n        }\n        _checkReserveAddressesDuplicate(assetAddresses);\n        uint256 length = assetKeys.length;\n        for (uint256 i; i < length; ++i) {\n            $.reserves[assetKeys[i]] = assetAddresses[i];\n            emit ReserveAssetSet(assetKeys[i], assetAddresses[i]);\n        }\n    }\n\n    /**\n     * @notice Get ERC20 contract address of reserve asset\n     * @dev Query ERC20 contract address corresponding to specified asset key\n     * @param assetKey Reserve asset identifier\n     * @return assetAddress ERC20 contract address\n     */\n    function getReserveAddress(bytes32 assetKey) public view returns (address) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        return $.reserves[assetKey];\n    }\n\n    /**\n     * @notice Set reserve asset allocation ratios\n     * @dev Only admin role can call, sum of all ratios must equal 100%\n     * @dev Ratios use 27 decimal precision, 1e27 = 100%, 1e26 = 10%\n     * @param assetKeys Reserve asset identifier array\n     * @param ratio Corresponding allocation ratio array (27 decimal precision)\n     */\n    function _setReservesRatio(bytes32[] calldata assetKeys, uint256[] calldata ratio) internal {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        // remove old reserve ratios\n        uint256 oldLength = $.reserveRatio.length();\n        for (uint256 i; i < oldLength; ++i) {\n            (bytes32 key,) = $.reserveRatio.at(0);\n            $.reserveRatio.remove(key);\n        }\n        if (assetKeys.length != ratio.length) {\n            revert InvalidArrayLength();\n        }\n        uint256 length = assetKeys.length;\n        for (uint256 i; i < length; ++i) {\n            if (ratio[i] == 0) {\n                revert RatioIsZero(assetKeys[i]);\n            }\n\n            $.reserveRatio.set(assetKeys[i], ratio[i]);\n            emit ReserveRatioUpdated(assetKeys[i], ratio[i]);\n        }\n        _checkReserveRatioSum();\n    }\n\n    /**\n     * @notice Get reserve asset allocation ratios\n     * @dev Query current allocation ratio configuration for specified reserve assets\n     * @param assetKeys Reserve asset identifier array\n     * @return ratios Corresponding allocation ratio array (27 decimal precision, 1e27 = 100%)\n     */\n    function getReservesRatio(bytes32[] calldata assetKeys) external view returns (uint256[] memory) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256[] memory ratios = new uint256[](assetKeys.length);\n        uint256 length = assetKeys.length;\n        for (uint256 i; i < length; ++i) {\n            ratios[i] = $.reserveRatio.get(assetKeys[i]);\n        }\n        return ratios;\n    }\n\n    /**\n     * @notice Set price feed contracts for reserve assets\n     * @dev Only admin role can call, assets must already be supported (ratios configured)\n     * @dev Price feed contracts are used to obtain real-time USD prices of reserve assets\n     * @param assetKeys Reserve asset identifier array\n     * @param priceFeed Corresponding price feed contract address array\n     */\n    function _setReservesPriceFeed(bytes32[] calldata assetKeys, address[] calldata priceFeed) internal {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if (assetKeys.length != priceFeed.length) {\n            revert InvalidArrayLength();\n        }\n        uint256 length = assetKeys.length;\n        for (uint256 i; i < length; ++i) {\n            if (!$.reserveRatio.contains(assetKeys[i])) {\n                revert AssetNotSupported(assetKeys[i]);\n            }\n            address oldFeed = $.reservePriceFeed[assetKeys[i]];\n            $.reservePriceFeed[assetKeys[i]] = priceFeed[i];\n            emit PriceFeedUpdated(assetKeys[i], oldFeed, priceFeed[i]);\n        }\n    }\n\n    /**\n     * @notice Get price feed contract address for reserve asset\n     * @dev Query price oracle contract address for specified reserve asset\n     * @param assetKey Reserve asset identifier\n     * @return priceFeed Price feed contract address\n     */\n    function getReservePriceFeed(bytes32 assetKey) public view returns (address) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if (!$.reserveRatio.contains(assetKey)) {\n            revert AssetNotSupported(assetKey);\n        }\n        return $.reservePriceFeed[assetKey];\n    }\n\n    function updateDepositFee(uint256 _depositFee) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        _checkFeeRate(_depositFee);\n        uint256 oldFee = $.depositFee;\n        $.depositFee = _depositFee;\n        emit DepositFeeUpdated(oldFee, _depositFee);\n    }\n\n    function updateRedeemFee(uint256 _redeemFee) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        _checkFeeRate(_redeemFee);\n        uint256 oldFee = $.redeemFee;\n        $.redeemFee = _redeemFee;\n        emit RedeemFeeUpdated(oldFee, _redeemFee);\n    }\n\n    function setFeeTo(address _feeTo) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if (_feeTo == address(0)) {\n            revert ZeroFeeToAddress();\n        }\n        address oldFeeTo = $.feeTo;\n        $.feeTo = _feeTo;\n        emit FeeToUpdated(oldFeeTo, _feeTo);\n    }\n\n    function setReserveTreasury(address _reserveTreasury) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if (_reserveTreasury == address(0)) {\n            revert ZeroTreasuryAddress();\n        }\n        _checkRevenueRecipientConstraints($.revenueRecipient, _reserveTreasury);\n        uint256 length = $.reserveRatio.length();\n        for (uint256 i; i < length; ++i) {\n            (bytes32 assetKey,) = $.reserveRatio.at(i);\n            address asset = $.reserves[assetKey];\n            if (asset == address(0)) {\n                continue;\n            }\n            uint256 trackedAmount = $.trackedReserveAmount[assetKey];\n            uint256 treasuryAmount = IERC20(asset).balanceOf(_reserveTreasury).to18Decimals(asset);\n            if (treasuryAmount < trackedAmount) {\n                revert ReserveTreasuryAmountBelowTrackedAmount(assetKey, trackedAmount, treasuryAmount);\n            }\n        }\n        address oldTreasury = $.reserveTreasury;\n        $.reserveTreasury = _reserveTreasury;\n        _refreshRevenueBaselineIfInitialized();\n        emit ReserveTreasuryUpdated(oldTreasury, _reserveTreasury);\n    }\n\n    function setMinimumCombinationAmount(uint256 _minimumCombinationAmount) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 oldAmount = $.minimumCombinationAmount;\n        $.minimumCombinationAmount = _minimumCombinationAmount;\n        emit MinimumCombinationAmountUpdated(oldAmount, _minimumCombinationAmount);\n    }\n\n    function initializeRevenueSync(address revenueRecipient, address revenueSyncCaller, uint256 revenueLpShareRatio)\n        external\n        onlyRole(DEFAULT_ADMIN_ROLE)\n    {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        // Initialization can only be executed once\n        if ($.revenueSyncInitialized) {\n            revert RevenueSyncAlreadyInitialized();\n        }\n        // Recipient must not be the zero address\n        _checkRevenueRecipient(revenueRecipient);\n        // Sync caller must not be the zero address\n        _checkRevenueSyncCaller(revenueSyncCaller);\n        _checkRevenueRecipientConstraints(revenueRecipient, $.reserveTreasury);\n        if (revenueLpShareRatio > _ONE_HUNDRED) {\n            revert InvalidLpShareRatio(revenueLpShareRatio);\n        }\n        // Initial reserve value\n        uint256 initialReserveValue = _getCurrentReserveValue();\n        // Initial LP value = total supply * LP price\n        uint256 initialLpValue = totalSupply().mulDiv(_getEffectiveLpPrice(), _BASE_DECIMALS);\n        // Initialization must not start with a deficit\n        if (initialLpValue > initialReserveValue) {\n            revert InitialLpValueExceedsReserveValue(initialLpValue, initialReserveValue);\n        }\n        // Update revenue-sync related state\n        $.revenueRecipient = revenueRecipient;\n        $.revenueSyncCaller = revenueSyncCaller;\n        $.lastSyncedReserveValue = initialReserveValue;\n        $.lastSyncedLpValue = initialLpValue;\n        $.revenueAdjustmentFactor = 1e18;\n        $.revenueLpShareRatio = revenueLpShareRatio;\n        $.revenueSyncInitialized = true;\n        $.revenueSyncEnabled = true;\n        $.revenueReserveHighWatermark = initialReserveValue;\n        $.revenueLpHighWatermark = initialLpValue;\n\n        emit RevenueSyncInitialized(revenueRecipient, revenueSyncCaller, initialReserveValue, initialLpValue);\n    }\n\n    function setRevenueRecipient(address newRecipient) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        _checkRevenueRecipient(newRecipient);\n        _checkRevenueRecipientConstraints(newRecipient, $.reserveTreasury);\n        address oldRecipient = $.revenueRecipient;\n        $.revenueRecipient = newRecipient;\n        emit RevenueRecipientUpdated(oldRecipient, newRecipient);\n    }\n\n    function setRevenueSyncCaller(address newCaller) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        _checkRevenueSyncCaller(newCaller);\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        address oldCaller = $.revenueSyncCaller;\n        $.revenueSyncCaller = newCaller;\n        emit RevenueSyncCallerUpdated(oldCaller, newCaller);\n    }\n\n    function setRevenueLpShareRatio(uint256 newRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        if (newRatio > _ONE_HUNDRED) {\n            revert InvalidLpShareRatio(newRatio);\n        }\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 oldRatio = $.revenueLpShareRatio;\n        $.revenueLpShareRatio = newRatio;\n        _resetRevenueBaselineIfInitialized();\n        emit RevenueLpShareRatioUpdated(oldRatio, newRatio);\n    }\n\n    function setRevenueSyncEnabled(bool enabled) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        _checkRevenueSyncInitialized();\n        bool oldEnabled = $.revenueSyncEnabled;\n        if (oldEnabled == enabled) {\n            return;\n        }\n        $.revenueSyncEnabled = enabled;\n        if (enabled) {\n            _resetRevenueBaseline();\n        }\n        emit RevenueSyncEnabledUpdated(oldEnabled, enabled);\n    }\n\n    function resetRevenueBaseline() external onlyRole(DEFAULT_ADMIN_ROLE) {\n        _checkRevenueSyncInitialized();\n        _resetRevenueBaseline();\n    }\n\n    function syncReserve(bytes32 assetKey) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        address asset = getReserveAddress(assetKey);\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 oldTrackedAmount = $.trackedReserveAmount[assetKey];\n        uint256 newTrackedAmount = _getReserveTreasuryAmount(asset);\n        $.trackedReserveAmount[assetKey] = newTrackedAmount;\n        if ($.revenueSyncInitialized) {\n            _refreshRevenueBaseline();\n        }\n        emit ReserveBalanceSynced(assetKey, oldTrackedAmount, newTrackedAmount);\n    }\n\n    function syncRevenue() external nonReentrant {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if (!$.revenueSyncInitialized) {\n            return;\n        }\n        // Only sync caller or admin can trigger sync\n        if (msg.sender != $.revenueSyncCaller && !hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {\n            revert SyncRevenueCallerIsNotValid(msg.sender);\n        }\n        _syncRevenue();\n    }\n\n    function syncRevenueAdjustmentFactor(uint256 factor) external {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if (msg.sender != $.revenueSyncCaller && !hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {\n            revert SyncRevenueCallerIsNotValid(msg.sender);\n        }\n        if (factor == 0) {\n            revert InvalidAdjustmentFactor();\n        }\n        $.revenueAdjustmentFactor = factor;\n    }\n\n    /**\n     * @notice Refund remaining native tokens\n     * @dev Refunds remaining native tokens in the contract to the caller\n     * @param amount Amount of native tokens to refund\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    /**\n     * @notice Internal function: Verify if sum of reserve asset ratios equals 100%\n     * @dev Reverts transaction if total ratio does not equal _ONE_HUNDRED\n     */\n    function _checkReserveRatioSum() internal view {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 sum;\n        uint256 length = $.reserveRatio.length();\n        for (uint256 i; i < length; ++i) {\n            (, uint256 ratio) = $.reserveRatio.at(i);\n            sum += ratio;\n        }\n        if (sum != _ONE_HUNDRED) {\n            revert InvalidTotalRatio(sum);\n        }\n    }\n\n    function _checkAssetKeysDuplicate(bytes32[] memory assetKeys) internal pure {\n        uint256 length = assetKeys.length;\n        if (length > 1) {\n            LibArray.insertionSort(assetKeys);\n            for (uint256 i; i < length - 1; ++i) {\n                if (assetKeys[i] == assetKeys[i + 1]) {\n                    revert AssetKeysDuplicate(assetKeys[i]);\n                }\n            }\n        }\n    }\n\n    function _checkReserveAddressesDuplicate(address[] memory assetAddresses) internal pure {\n        uint256 length = assetAddresses.length;\n        if (length > 1) {\n            LibArray.insertionSort(assetAddresses);\n            for (uint256 i; i < length - 1; ++i) {\n                if (assetAddresses[i] == assetAddresses[i + 1]) {\n                    revert ReserveAddressDuplicate(assetAddresses[i]);\n                }\n            }\n        }\n    }\n\n    function getAssetKeysAndAddress() public view returns (bytes32[] memory, address[] memory) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 length = $.reserveRatio.length();\n        bytes32[] memory assetKeys = new bytes32[](length);\n        address[] memory assetAddresses = new address[](length);\n        for (uint256 i; i < length; ++i) {\n            (bytes32 assetKey,) = $.reserveRatio.at(i);\n            assetKeys[i] = assetKey;\n            assetAddresses[i] = $.reserves[assetKey];\n        }\n        return (assetKeys, assetAddresses);\n    }\n\n    function _update(address from, address to, uint256 amount) internal override {\n        _requireNotPaused();\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        address kycModule = $.kycModule;\n        IKycModule(kycModule).validateBanned(msg.sender);\n        // blacklist validation\n        if (from != address(0)) {\n            IKycModule(kycModule).validateBanned(from);\n        }\n        if (to != address(0)) {\n            IKycModule(kycModule).validateBanned(to);\n        }\n        super._update(from, to, amount);\n    }\n\n    /**\n     * @notice Get current exchange rate of LP token to USD\n     * @dev Returns USD value of 1 LP token (18 decimal precision)\n     * @dev Exchange rate is calculated based on standard combination value of current reserve assets\n     * @return exchangeRate Exchange rate value, represented as USD value in 18 decimal precision\n     */\n    function getExchangeRate() public view returns (uint256) {\n        return _getOneCombinationValue();\n    }\n\n    function getExchangeRateWithAdjustment() public view returns (uint256) {\n        return _getEffectiveLpPrice();\n    }\n\n    function _getEffectiveLpPrice() internal view returns (uint256) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 oneCombinationValue = _getOneCombinationValue();\n        uint256 adjustedValue = oneCombinationValue.mulDiv($.adjustmentFactor, _BASE_DECIMALS)\n            .mulDiv(_revenueAdjustmentFactor(), _BASE_DECIMALS);\n        return adjustedValue;\n    }\n\n    function getRevenueAdjustmentFactor() external view returns (uint256) {\n        return _revenueAdjustmentFactor();\n    }\n\n    function _revenueAdjustmentFactor() internal view returns (uint256) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 revenueAdjustmentFactor = $.revenueAdjustmentFactor;\n        return revenueAdjustmentFactor == 0 ? _BASE_DECIMALS : revenueAdjustmentFactor;\n    }\n\n    /**\n     * @notice Get USD value of one standard combination\n     * @dev Calculates total USD value of reserve asset combination composed by configured ratios\n     * @dev Used to determine intrinsic value of LP tokens and exchange rate calculation\n     * @return combinationValue USD value of one standard combination (18 decimal precision)\n     */\n    function _getOneCombinationValue() internal view returns (uint256) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 valueOfOneCombination;\n        uint256 length = $.reserveRatio.length();\n        for (uint256 i; i < length; ++i) {\n            (bytes32 assetKey, uint256 ratio) = $.reserveRatio.at(i);\n            valueOfOneCombination += getReserveValue(assetKey, _ONE_COMBINATION_UNIT * ratio / _ONE_HUNDRED);\n        }\n        return valueOfOneCombination;\n    }\n\n    /**\n     * @notice Get total USD value of specified reserve assets and amounts\n     * @dev Calculates total USD value for given asset arrays and corresponding amounts\n     * @dev Mainly used for value calculation during deposit and redeem operations\n     * @param assetKeys Reserve asset identifier array\n     * @param amounts Corresponding amount array (18 decimal precision)\n     * @return totalValue Total USD value (18 decimal precision)\n     */\n    function getReservesValue(bytes32[] memory assetKeys, uint256[] memory amounts) public view returns (uint256) {\n        uint256 totalValue;\n        uint256 length = assetKeys.length;\n        for (uint256 i; i < length; ++i) {\n            totalValue += getReserveValue(assetKeys[i], amounts[i]);\n        }\n        return totalValue;\n    }\n\n    /**\n     * @notice Get USD value of specific reserve asset amount\n     * @dev Obtains USD value of a single reserve asset through price feed contract\n     * @param assetKey Reserve asset identifier\n     * @param amount Reserve asset amount (18 decimal precision)\n     * @return value USD value (18 decimal precision)\n     */\n    function getReserveValue(bytes32 assetKey, uint256 amount) public view returns (uint256) {\n        address reservePriceFeed = getReservePriceFeed(assetKey);\n        uint256 assetValue = IBaseReservePriceFeed(reservePriceFeed).getReserveValueInUSD(amount);\n        return assetValue;\n    }\n\n    function getTrackedReserveAmount(bytes32 assetKey) external view returns (uint256 amount) {\n        getReserveAddress(assetKey);\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        return $.trackedReserveAmount[assetKey];\n    }\n\n    /**\n     * @notice Get comprehensive information of all reserve assets\n     * @dev Returns complete information including asset identifiers, allocation ratios, current values and last update time\n     * @dev Provides complete state snapshot of reserve asset pool for monitoring and management\n     * @return assetKeys Reserve asset identifier array\n     * @return assetAddresses Reserve asset ERC20 contract address array\n     * @return ratios Allocation ratio array (27 decimal precision, 1e27 = 100%)\n     * @return values Current USD value array (18 decimal precision)\n     * @return totalValue Total USD value of reserve assets (18 decimal precision)\n     * @return updateAt Last update timestamp\n     */\n    function getTotalReservesInfo()\n        public\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        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 length = $.reserveRatio.length();\n        assetKeys = new bytes32[](length);\n        assetAddresses = new address[](length);\n        ratios = new uint256[](length);\n        values = new uint256[](length);\n        for (uint256 i; i < length; ++i) {\n            (bytes32 assetKey, uint256 ratio) = $.reserveRatio.at(i);\n            assetKeys[i] = assetKey;\n            assetAddresses[i] = getReserveAddress(assetKey);\n            ratios[i] = ratio;\n            values[i] = _getTrackedReserveValue(assetKey, assetAddresses[i]);\n            totalValue += values[i];\n        }\n        updateAt = $.updateAt;\n    }\n\n    function _syncRevenue() internal {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        // Fetch latest reserve value\n        uint256 currentReserveValue = _getCurrentReserveValue();\n        // LP value from last sync\n        uint256 oldLpValue = $.lastSyncedLpValue;\n        uint256 newLpValue;\n        uint256 newEffectiveLpPrice;\n        uint256 newRevenueAdjustmentFactor = _revenueAdjustmentFactor();\n        uint256 supply = totalSupply();\n        uint256 oneCombinationValue = _getOneCombinationValue();\n        bool shouldShareRevenue = $.revenueSyncEnabled && currentReserveValue > $.revenueReserveHighWatermark;\n        // No sync needed when total LP supply is zero\n        if (supply == 0) {\n            $.lastSyncedReserveValue = currentReserveValue;\n            $.lastSyncedLpValue = 0;\n            $.revenueReserveHighWatermark = currentReserveValue;\n            $.revenueLpHighWatermark = 0;\n            return;\n        }\n        // Calculate latest LP value\n        newLpValue = shouldShareRevenue\n            ? _getNewLpValue(currentReserveValue)\n            : FUSDLPRevenueMath.getNewLpValueWithoutRevenueShare(\n                oldLpValue, currentReserveValue, $.lastSyncedReserveValue\n            );\n        if (newLpValue > currentReserveValue) {\n            revert SyncedLpValueExceedsReserveValue(newLpValue, currentReserveValue);\n        }\n        // Derive latest effective LP price\n        newEffectiveLpPrice = newLpValue.mulDiv(_BASE_DECIMALS, supply);\n        // Calculate revenue adjustment factor\n        newRevenueAdjustmentFactor = _deriveRevenueAdjustmentFactor(newEffectiveLpPrice, oneCombinationValue);\n        $.revenueAdjustmentFactor = newRevenueAdjustmentFactor;\n\n        if (!shouldShareRevenue) {\n            $.lastSyncedReserveValue = currentReserveValue;\n            $.lastSyncedLpValue = newLpValue;\n            if (newLpValue > $.revenueLpHighWatermark) {\n                $.revenueLpHighWatermark = newLpValue;\n            }\n            return;\n        }\n\n        (bytes32[] memory assetKeys, address[] memory assetAddresses) = getAssetKeysAndAddress();\n        uint256[] memory requiredAmounts = _getRequiredReserveAmounts(assetKeys, newLpValue, oneCombinationValue);\n        uint256 length = assetKeys.length;\n        bool hasReserveDeficit;\n\n        for (uint256 i; i < length; ++i) {\n            uint256 treasuryAmount = _getTrackedReserveAmount(assetKeys[i], assetAddresses[i]);\n            uint256 requiredAmount = requiredAmounts[i];\n            if (treasuryAmount < requiredAmount) {\n                hasReserveDeficit = true;\n                break;\n            }\n        }\n\n        if (!hasReserveDeficit) {\n            for (uint256 i; i < length; ++i) {\n                uint256 treasuryAmount = _getTrackedReserveAmount(assetKeys[i], assetAddresses[i]);\n                uint256 requiredAmount = requiredAmounts[i];\n                uint256 surplusAmount = treasuryAmount - requiredAmount;\n                if (surplusAmount == 0) {\n                    continue;\n                }\n\n                bytes32 assetKey = assetKeys[i];\n                address asset = assetAddresses[i];\n                uint256 surplusRaw =\n                    TokenDecimalsConvert.from18DecimalsWithoutRevert(surplusAmount, IERC20Metadata(asset).decimals());\n                if (surplusRaw == 0) {\n                    continue;\n                }\n                IERC20(asset).safeTransferFrom($.reserveTreasury, $.revenueRecipient, surplusRaw);\n                $.trackedReserveAmount[assetKey] -= surplusAmount;\n                emit RevenueTransferred(assetKey, asset, $.revenueRecipient, surplusAmount, surplusRaw);\n            }\n        }\n        // Persist synced baseline values\n        uint256 newReserveValue = _getCurrentReserveValue();\n        if (newLpValue > newReserveValue) {\n            revert SyncedLpValueExceedsReserveValue(newLpValue, newReserveValue);\n        }\n        $.lastSyncedReserveValue = newReserveValue;\n        $.lastSyncedLpValue = newLpValue;\n        if (newReserveValue > $.revenueReserveHighWatermark) {\n            $.revenueReserveHighWatermark = newReserveValue;\n        }\n        if (newLpValue > $.revenueLpHighWatermark) {\n            $.revenueLpHighWatermark = newLpValue;\n        }\n        emit RevenueSynced(currentReserveValue, newReserveValue, oldLpValue, newLpValue, newRevenueAdjustmentFactor);\n    }\n\n    function _refreshRevenueBaselineIfInitialized() internal {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if ($.revenueSyncInitialized) {\n            _refreshRevenueBaseline();\n        }\n    }\n\n    function _resetRevenueBaselineIfInitialized() internal {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if ($.revenueSyncInitialized) {\n            _resetRevenueBaseline();\n        }\n    }\n\n    function _refreshRevenueBaseline() internal {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 oldReserveValue = $.lastSyncedReserveValue;\n        uint256 oldLpValue = $.lastSyncedLpValue;\n        uint256 newReserveValue = _getCurrentReserveValue();\n        uint256 newLpValue = totalSupply().mulDiv(_getEffectiveLpPrice(), _BASE_DECIMALS);\n        if (newLpValue > newReserveValue) {\n            revert BaselineLpValueExceedsReserveValue(newLpValue, newReserveValue);\n        }\n        $.lastSyncedReserveValue = newReserveValue;\n        $.lastSyncedLpValue = newLpValue;\n        // Capital flows should translate the revenue watermark rather than overwrite it.\n        $.revenueReserveHighWatermark =\n            _shiftWatermark($.revenueReserveHighWatermark, newReserveValue.toInt256() - oldReserveValue.toInt256());\n        $.revenueLpHighWatermark =\n            _shiftWatermark($.revenueLpHighWatermark, newLpValue.toInt256() - oldLpValue.toInt256());\n        emit RevenueBaselineRefreshed(oldReserveValue, newReserveValue, oldLpValue, newLpValue);\n    }\n\n    function _resetRevenueBaseline() internal {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 oldReserveValue = $.lastSyncedReserveValue;\n        uint256 oldLpValue = $.lastSyncedLpValue;\n        uint256 newReserveValue = _getCurrentReserveValue();\n        uint256 newLpValue = totalSupply().mulDiv(_getEffectiveLpPrice(), _BASE_DECIMALS);\n        if (newLpValue > newReserveValue) {\n            revert BaselineLpValueExceedsReserveValue(newLpValue, newReserveValue);\n        }\n        $.lastSyncedReserveValue = newReserveValue;\n        $.lastSyncedLpValue = newLpValue;\n        $.revenueReserveHighWatermark = newReserveValue;\n        $.revenueLpHighWatermark = newLpValue;\n        emit RevenueBaselineRefreshed(oldReserveValue, newReserveValue, oldLpValue, newLpValue);\n    }\n\n    function _shiftWatermark(uint256 watermark, int256 delta) internal pure returns (uint256) {\n        if (delta >= 0) {\n            return watermark + delta.toUint256();\n        }\n\n        uint256 decrease = (-delta).toUint256();\n        if (decrease >= watermark) {\n            return 0;\n        }\n        return watermark - decrease;\n    }\n\n    function _getNewLpValue(uint256 currentReserveValue) internal view returns (uint256) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        return FUSDLPRevenueMath.getNewLpValue(\n            currentReserveValue,\n            $.revenueReserveHighWatermark,\n            $.revenueLpHighWatermark,\n            $.revenueLpShareRatio,\n            _ONE_HUNDRED\n        );\n    }\n\n    function _deriveRevenueAdjustmentFactor(uint256 effectiveLpPrice, uint256 oneCombinationValue)\n        internal\n        view\n        returns (uint256)\n    {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if (effectiveLpPrice == 0 || oneCombinationValue == 0 || $.adjustmentFactor == 0) {\n            revert InvalidRevenueAdjustmentInputs(effectiveLpPrice, oneCombinationValue, $.adjustmentFactor);\n        }\n\n        return\n            FUSDLPRevenueMath.deriveRevenueAdjustmentFactor(effectiveLpPrice, oneCombinationValue, $.adjustmentFactor);\n    }\n\n    function _getRequiredReserveAmounts(bytes32[] memory assetKeys, uint256 requiredLpValue, uint256 exchangeRate)\n        internal\n        view\n        returns (uint256[] memory requiredAmounts)\n    {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if (exchangeRate == 0) {\n            revert RequiredReserveExchangeRateIsZero();\n        }\n\n        uint256 requiredCombinations = Math.mulDiv(requiredLpValue, _BASE_DECIMALS, exchangeRate, Math.Rounding.Ceil);\n        uint256 length = assetKeys.length;\n        requiredAmounts = new uint256[](length);\n        for (uint256 i; i < length; ++i) {\n            requiredAmounts[i] =\n                requiredCombinations.mulDiv($.reserveRatio.get(assetKeys[i]), _ONE_HUNDRED, Math.Rounding.Ceil);\n        }\n    }\n\n    function _getCurrentReserveValue() internal view returns (uint256) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        uint256 totalValue;\n        uint256 length = $.reserveRatio.length();\n        for (uint256 i; i < length; ++i) {\n            (bytes32 assetKey,) = $.reserveRatio.at(i);\n            address asset = $.reserves[assetKey];\n            totalValue += _getTrackedReserveValue(assetKey, asset);\n        }\n        return totalValue;\n    }\n\n    function _getTrackedReserveValue(bytes32 assetKey, address asset) internal view returns (uint256) {\n        if (asset == address(0)) {\n            return 0;\n        }\n        uint256 balance = _getTrackedReserveAmount(assetKey, asset);\n        return getReserveValue(assetKey, balance);\n    }\n\n    function _getTrackedReserveAmount(bytes32 assetKey, address asset) internal view returns (uint256) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        asset;\n        return $.trackedReserveAmount[assetKey];\n    }\n\n    function _getReserveTreasuryAmount(address asset) internal view returns (uint256) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        return IERC20(asset).balanceOf($.reserveTreasury).to18Decimals(asset);\n    }\n\n    /**\n     * @notice Pause contract functions\n     * @dev Only accounts with PAUSER_ROLE role can call\n     * @dev After pausing, deposit and redeem operations will be disabled, but query functions are not affected\n     */\n    function pause() external onlyRole(PAUSER_ROLE) {\n        _pause();\n    }\n\n    /**\n     * @notice Resume contract functions\n     * @dev Only accounts with PAUSER_ROLE role can call\n     * @dev After resuming, deposit and redeem operations will be re-enabled\n     */\n    function unpause() external onlyRole(PAUSER_ROLE) {\n        _unpause();\n    }\n\n    function getCCIPAdmin() external view returns (address) {\n        return getRoleMember(DEFAULT_ADMIN_ROLE, 0);\n    }\n\n    function isCustomMessageIdUsed(uint256 _customMessageId) external view returns (bool) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        return $.usedCustomMessageIds.get(_customMessageId);\n    }\n\n    function setDepositRedeemEnabled(bool enabled) external onlyRole(DEFAULT_ADMIN_ROLE) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        bool oldStatus = $.depositRedeemEnabled;\n        $.depositRedeemEnabled = enabled;\n        emit DepositRedeemStatusUpdated(oldStatus, enabled);\n    }\n\n    function depositRedeemEnabled() external view returns (bool) {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        return $.depositRedeemEnabled;\n    }\n\n    /// @notice Consume the custom message ID to prevent reuse\n    function _consumeCustomMessageId(uint256 _customMessageId) internal {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        require(!$.usedCustomMessageIds.get(_customMessageId), CustomMessageIdIsUsed(_customMessageId));\n        $.usedCustomMessageIds.set(_customMessageId);\n    }\n\n    function _checkFeeRate(uint256 feeRate) internal pure {\n        if (feeRate >= _MAX_FEE_RATE) {\n            revert FeeRateTooHigh();\n        }\n    }\n\n    function _checkRevenueRecipient(address revenueRecipient) internal pure {\n        if (revenueRecipient == address(0)) {\n            revert ZeroAddress();\n        }\n    }\n\n    function _checkRevenueRecipientConstraints(address revenueRecipient, address reserveTreasury) internal view {\n        if (revenueRecipient == address(this)) {\n            revert RevenueRecipientCannotBeSelf(revenueRecipient);\n        }\n        if (revenueRecipient != address(0) && revenueRecipient == reserveTreasury) {\n            revert RevenueRecipientCannotBeReserveTreasury(revenueRecipient);\n        }\n    }\n\n    function _checkRevenueSyncCaller(address revenueSyncCaller) internal pure {\n        if (revenueSyncCaller == address(0)) {\n            revert ZeroAddress();\n        }\n    }\n\n    function _checkRevenueSyncInitialized() internal view {\n        FUSDLPStorage storage $ = _getsFUSDLPStorage();\n        if (!$.revenueSyncInitialized) {\n            revert RevenueSyncNotInitialized();\n        }\n    }\n\n    function _checkDepositRedeemEnabled(bool enabled) internal pure {\n        if (!enabled) {\n            revert DepositRedeemDisabled();\n        }\n    }\n}\n","deployed_bytecode":"0x60806040526004361015610023575b361561001957600080fd5b6100216136b9565b005b60003560e01c8063017def57146104135780630196db001461040e57806301ffc9a71461040957806306fdde0314610404578063095ea7b3146103ff5780630ccb2719146103fa57806310b8063b146103f55780631255899f146103f057806318160ddd146103eb57806323b872dd146103e6578063248a9ca3146103e157806324dd2630146103dc57806328b6076c146103d75780632b04ae2b146103d25780632f2ff15d146103cd578063313ce567146103c857806336568abe146103c35780633f4ba83a146103be57806340c10f19146103b957806342966c68146103b4578063487f9ca2146103af5780634cdad506146103aa5780635c975abb146103a5578063601fbd63146103a0578063673da1541461039b57806370a082311461039657806382300ee3146103915780638456cb591461038c57806385eb096b1461038757806386fbb6f3146103825780638984d4611461037d57806389fcbdc5146103785780638fd6a6ac146103735780639010d07c1461036e57806391d148541461036957806395d89b41146103645780639e4bca6b1461035f578063a217fddf1461035a578063a3246ad314610355578063a5aedeba14610350578063a9059cbb1461034b578063b16b0e9514610346578063b57a803a14610341578063b69545321461033c578063ca15c87314610337578063cd1818d114610332578063cddd41361461032d578063ce6e469814610328578063d0f2408514610323578063d53913931461031e578063d547741f14610319578063dd62ed3e14610314578063e20a15071461030f578063e20c40ba1461030a578063e31999b414610305578063e338b10a14610300578063e63ab1e9146102fb578063e6aa216c146102f6578063ef8b30f7146102f1578063f2b01850146102ec578063f46901ed146102e7578063fb00d514146102e25763fc0e6e4e0361000e5761283a565b6127b7565b612726565b612675565b612627565b61260c565b6125d1565b612570565b612552565b612522565b612406565b6123c6565b612392565b612357565b61232e565b612291565b6121cf565b61210c565b6120d3565b612040565b611fc3565b611f49565b611f1f565b611eea565b611e68565b611e38565b611c8e565b611bcc565b611b69565b611b15565b611aa6565b6119fe565b6119ce565b6119ad565b611969565b6118f5565b611872565b611816565b61160a565b6114c5565b61143c565b6113d8565b61124d565b611220565b6111e4565b611161565b611117565b6110fb565b6110c2565b610e91565b610e4e565b610d92565b610ccd565b610c06565b610baf565b61083b565b610778565b6106f6565b6106c1565b61058f565b6104d7565b6104aa565b3461049b57602036600319011261049b577f828cf983933545af35b9ba46eec951db1cb4c5433c3ec403aeced2963c2647906004356104506136eb565b6104598161386c565b600080516020615bcd8339815191525481600080516020615bcd833981519152556104966040519283928360209093929193604081019481520152565b0390a1005b600080fd5b8015150361049b57565b3461049b57602036600319011261049b576100216004356104ca816104a0565b6104d26136eb565b612855565b3461049b57602036600319011261049b5760043563ffffffff60e01b811680910361049b57602090635a05180f60e01b811490811561051c575b506040519015158152f35b637965db0b60e01b811491508115610536575b5038610511565b6301ffc9a760e01b1490503861052f565b60208082528251910181815290929160005b84811061057a575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201610559565b3461049b57600036600319011261049b576040516000600080516020615c0d833981519152546105be816128fc565b808452906001811690811561066257506001146105f6575b6105f2836105e681850382610d09565b60405191829182610547565b0390f35b600080516020615c0d83398151915260009081527f2ae08a8e29253f69ac5d979a101956ab8f8d9d7ded63fa7a83b16fc47648eab0939250905b808210610648575090915081016020016105e66105d6565b919260018160209254838588010152019101909291610630565b60ff191660208086019190915291151560051b840190910191506105e690506105d6565b6001600160a01b0381160361049b57565b608435906106a482610686565b565b60e435906106a482610686565b61010435906106a482610686565b3461049b57604036600319011261049b576106eb6004356106e181610686565b6024359033614e6f565b602060405160018152f35b3461049b57602036600319011261049b5760043561071381610686565b61071b6136eb565b610724816139ad565b600080516020615dcd833981519152546001600160a01b03169061074781612936565b6001600160a01b0316907f6f467c633fa7217ba6a3845632b7385764f9b966af28c57a334190aedf3602ca600080a3005b3461049b57602036600319011261049b576004356107946136eb565b676765c793fa10079d601b1b8111610827577f0527e14a979eae4df92dbdc207af2749a5b2602095816f4796618ada205a602b90600080516020615cad8339815191525481600080516020615cad8339815191525560ff600080516020615dad833981519152541661081a575b6040805191825260208201929092529081908101610496565b6108226138b8565b610801565b6363bf523b60e11b60005260045260246000fd5b606036600319011261049b57600435602435604435916001600160401b0383169283810361049b5761086b6139bd565b6108736139f9565b600092610897610892600080516020615ced8339815191525460ff1690565b613a23565b600080516020615bed833981519152546108c7906108bb906001600160a01b031681565b6001600160a01b031690565b604051632f47185360e11b81523360048201529190602090839060249082905afa918215610ada576108fe92610b82575b506135b4565b9193809593509790975160005b818110610adf5750506109ce579161097b87927f39ca5049a496c9f67bc317ee005dc40fc3e8136f0c865acbd6d91a10df8099ba946109556105f29a6109508a613cb5565b613bbb565b806109a5575b50610964613d54565b61096d47613d75565b604051938493339785612a97565b0390a36109956001600080516020615ead83398151915255565b6040519081529081906020820190565b600080516020615c4d833981519152546109c891906001600160a01b0316613bbb565b3861095b565b9450946109db8130613bbb565b600080516020615eed83398151915254610a009082906001600160a01b031630614e6f565b600080516020615eed83398151915254610a24906108bb906001600160a01b031681565b604051631472b4bb60e01b81526001600160401b03881660048201526024810186905230604482015260648101839052600060848201529290602090849060a490829034905af1928315610ada576105f2977f39ca5049a496c9f67bc317ee005dc40fc3e8136f0c865acbd6d91a10df8099ba9461097b92600091610aab575b5097610955565b610acd915060203d602011610ad3575b610ac58183610d09565b810190612a88565b38610aa4565b503d610abb565b6129f0565b610ae98188612a12565b5190610b04610af783612a26565b546001600160a01b031690565b6001600160a01b038116928315610b7157610b61610b6991610b5c600196610b2c878e612a12565b51600080516020615b4d83398151915254909690610b54906001600160a01b03169188613a54565b913390613b21565b612a43565b918254612a76565b90550161090b565b63d92e233d60e01b60005260046000fd5b610ba39060203d602011610ba8575b610b9b8183610d09565b8101906129db565b6108f8565b503d610b91565b3461049b57600036600319011261049b576020600080516020615d2d83398151915254604051908152f35b606090600319011261049b57600435610bf281610686565b90602435610bff81610686565b9060443590565b3461049b57610c1436610bda565b90610c3933610c2285612d10565b9060018060a01b0316600052602052604060002090565b54926000198410610c4f575b6106eb9350613dcc565b828410610cb0576001600160a01b03811615610c9a573315610c8457826106eb9403610c7e33610c2284612d10565b55610c45565b634a1406b160e11b600052600060045260246000fd5b63e602df0560e01b600052600060045260246000fd5b8284637dc7a0d960e11b6000523360045260245260445260646000fd5b3461049b57602036600319011261049b576020610ceb600435612ad4565b604051908152f35b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b03821117610d2a57604052565b610cf3565b6001600160401b038111610d2a5760051b60200190565b929190610d5281610d2f565b93610d606040519586610d09565b602085838152019160051b810192831161049b57905b828210610d8257505050565b8135815260209182019101610d76565b3461049b57604036600319011261049b576004356001600160401b03811161049b573660238201121561049b57610dd3903690602481600401359101610d46565b602435906001600160401b03821161049b573660238301121561049b57816004013591610dff83610d2f565b92610e0d6040519485610d09565b8084526024602085019160051b8301019136831161049b57602401905b828210610e3e576105f26109958686612af5565b8135815260209182019101610e2a565b3461049b57602036600319011261049b57600435610e6b81613530565b50600052600080516020615e0d8339815191526020526020604060002054604051908152f35b3461049b57610e9f36610bda565b610ea76136eb565b600080516020615dad8339815191525460ff166110b157610ec7836139ad565b610ed0826139ad565b600080516020615b4d83398151915254610ef3906001600160a01b031684613f24565b676765c793fa10079d601b1b811161109d57610f0d613f83565b91610f35610f27600080516020615d2d8339815191525490565b610f2f613ffa565b90614026565b9183831161107e5790610fd27f5e76b9b2a061e1e3d2e1f275d9dbf7d730d608fe36e0828c80ae1e34340a2e4d9392610f6d87612b43565b610f7683612936565b610f8c86600080516020615ccd83398151915255565b610fa284600080516020615b6d83398151915255565b610fc0670de0b6b3a7640000600080516020615c8d83398151915255565b600080516020615cad83398151915255565b610ffe600160ff19600080516020615dad833981519152541617600080516020615dad83398151915255565b61102a600160ff19600080516020615d8d833981519152541617600080516020615d8d83398151915255565b61104084600080516020615e8d83398151915255565b61105682600080516020615c6d83398151915255565b6040805194855260208501929092526001600160a01b0390811694169290819081015b0390a3005b632dc9987b60e21b6000526004839052602484905260446000fd5b6000fd5b6363bf523b60e11b60005260045260246000fd5b630663e84960e41b60005260046000fd5b3461049b57604036600319011261049b576100216024356004356110e582610686565b6110f66110f182612ad4565b613822565b61422a565b3461049b57600036600319011261049b57602060405160128152f35b3461049b57604036600319011261049b5760043560243561113781610686565b336001600160a01b03821603611150576100219161426e565b63334bd91960e11b60005260046000fd5b3461049b57600036600319011261049b5761117a61373e565b600080516020615e6d8339815191525460ff8116156111d35760ff1916600080516020615e6d833981519152557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b638dfc202b60e01b60005260046000fd5b3461049b57604036600319011261049b5761121860043561120481610686565b602435906112106139f9565b6109506137b0565b610021613d54565b3461049b57602036600319011261049b5761121860043561123f6139f9565b6112476137b0565b336142b2565b3461049b57602036600319011261049b576004356112696136eb565b61127281613530565b81600052600080516020615e0d83398151915260205260406000205460018060a01b03600080516020615b4d8339815191525416604051906370a0823160e01b8252600482015260208160248160018060a01b0387165afa928315610ada577fdf173d8e3147dcb07bf86ccb47a4443e162acd522d0bd3b6e3f9147a79c8b23b9361130592600091611348575b506145b6565b908161131085612a43565b55600080516020615dad8339815191525460ff1661133b575b604080519182526020820192909252a2005b611343614390565b611329565b611361915060203d602011610ad357610ac58183610d09565b386112ff565b906020808351928381520192019060005b8181106113855750505090565b8251845260209384019390920191600101611378565b906020808351928381520192019060005b8181106113b95750505090565b82516001600160a01b03168452602093840193909201916001016113ac565b3461049b57602036600319011261049b576114166114246114326113fd600435612c2f565b9392949091604051968796608088526080880190611367565b90868203602088015261139b565b908482036040860152611367565b9060608301520390f35b3461049b57600036600319011261049b57602060ff600080516020615e6d83398151915254166040519015158152f35b926114ad9061149f6114bb9461149160a098959b9a999b60c0895260c0890190611367565b90878203602089015261139b565b908582036040870152611367565b908382036060850152611367565b9460808201520152565b3461049b57600036600319011261049b576000600080516020615d4d833981519152546114f181612bfd565b906114fb81612bfd565b9261150582612bfd565b9161150f81612bfd565b906000905b808210611552575050906105f292917f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870154926040519687968761146c565b90926116026001916115e661156687615214565b90549060031b1c80600052600080516020615d6d833981519152602052604060002054816115948a8d612a12565b526115bb8c6115ac8b6115a686613530565b92612a12565b6001600160a01b039091169052565b6115c5898b612a12565b526115e06115d3898d612a12565b516001600160a01b031690565b90614567565b6115f08787612a12565b526115fb8686612a12565b5190612a76565b930190611514565b3461049b57604036600319011261049b576004356024356116296139bd565b6116316139f9565b801561180557611653610892600080516020615ced8339815191525460ff1690565b600080516020615bed83398151915254611677906108bb906001600160a01b031681565b604051632f47185360e11b815233600482015290602090829060249082905afa8015610ada576117e8575b506116ac81612c2f565b909150829392516116bc86613cb5565b6001600160a01b03811615610b715760005b828110611769575050509082916117067f0519b17bd58a626c9c8c8cf874404b2d1b8742321da306cee40ce3ebc812cedf94336142b2565b80611740575b50611715613d54565b611726604051928392339684612cf0565b0390a36100216001600080516020615ead83398151915255565b600080516020615c4d8339815191525461176391906001600160a01b0316613bbb565b3861170c565b6117738188612a12565b5190611781610af783612a26565b6001600160a01b038116928315610b71576117d86117e091610b5c600196886117aa888e612a12565b51600080516020615b4d833981519152549097906117d2906001600160a01b03169189613a54565b92613b21565b918254612b94565b9055016116ce565b6118009060203d602011610ba857610b9b8183610d09565b6116a2565b639811e0c760e01b60005260046000fd5b3461049b57602036600319011261049b5760043561183381610686565b60018060a01b03166000527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006020526020604060002054604051908152f35b3461049b57604036600319011261049b57600435602435600381101561049b57600090806118b8575050610ceb602091600080516020615bcd8339815191525490614026565b806118c4600292612d82565b036118e65750610ceb602091600080516020615ded8339815191525490614026565b633a08349960e01b8152600490fd5b3461049b57600036600319011261049b5761190e61373e565b6119166139f9565b600160ff19600080516020615e6d833981519152541617600080516020615e6d833981519152557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b3461049b57600036600319011261049b5761199f6105f2611988612dbb565b604092919251938493604085526040850190611367565b90838203602085015261139b565b3461049b57604036600319011261049b576020610ceb602435600435612e60565b3461049b57600036600319011261049b57602060ff600080516020615ced83398151915254166040519015158152f35b3461049b57602036600319011261049b57600435611a1b81610686565b611a236136eb565b611a2c816139ad565b600080516020615b4d83398151915254611a4f906001600160a01b031682613f24565b600080516020615ced8339815191525460081c6001600160a01b031690611a7581612b43565b6001600160a01b0316907f54faf859f8b04a3fce57f3bf185c6dcb0df7cdf90060a9617bcc9334e9d785ab600080a3005b3461049b57600036600319011261049b5760008052600080516020615bad8339815191526020527f615f0f9e84155bea8cc509fe18befeb1baf65611e38a6ba60964480fb29dfd44805415611b105760005260208060002060018060a01b03905416604051908152f35b6129fc565b3461049b57604036600319011261049b576020611b5060043560243590600052600080516020615bad83398151915283526040600020615249565b905460405160039290921b1c6001600160a01b03168152f35b3461049b57604036600319011261049b57602060ff611bc0602435600435611b9082610686565b600052600080516020615e4d833981519152845260406000209060018060a01b0316600052602052604060002090565b54166040519015158152f35b3461049b57600036600319011261049b576040516000600080516020615d0d83398151915254611bfb816128fc565b80845290600181169081156106625750600114611c22576105f2836105e681850382610d09565b600080516020615d0d83398151915260009081527f46a2803e59a4de4e7a4c574b1243f25977ac4c77d5a1a4a609b5394cebb4a2aa939250905b808210611c74575090915081016020016105e66105d6565b919260018160209254838588010152019101909291611c5c565b3461049b57602036600319011261049b57600435611cab81610686565b611cb36136eb565b6001600160a01b038116908115611e2757600080516020615ced83398151915254611ceb90829060081c6001600160a01b0316613f24565b600080516020615d4d8339815191525460005b818110611d62575050600080516020615b4d83398151915254611d2a906001600160a01b03169161296d565b611d32613d54565b6001600160a01b03167f12ba215d768031449a2499d64e291257e7f005e01b2b858d59414e3bb728d08b600080a3005b611d6b81615163565b50611d78610af782612a26565b6001600160a01b0381168015611e1c57611d9183612a43565b546040516370a0823160e01b81526001600160a01b038816600482015290929091602090839060249082905afa8015610ada57611dd592600091611e0457506145b6565b91818310611dea575050506001905b01611cfe565b6303c563e560e61b60005260045260245260445260646000fd5b611361915060203d8111610ad357610ac58183610d09565b505050600190611de4565b6351dc806d60e11b60005260046000fd5b3461049b57600036600319011261049b57602060405160008152f35b906020611e6592818152019061139b565b90565b3461049b57602036600319011261049b57600435600052600080516020615bad833981519152602052604060002060405190816020825491828152019160005260206000209060005b818110611ed4576105f285611ec881870382610d09565b60405191829182611e54565b8254845260209093019260019283019201611eb1565b3461049b57600036600319011261049b57611f036139bd565b611f0b612ebc565b6001600080516020615ead83398151915255005b3461049b57604036600319011261049b576106eb600435611f3f81610686565b6024359033613dcc565b3461049b57602036600319011261049b577faaf8f648880295798ded4114dd6c34d37444c6a0ccf160a98c1b5c644de08d8f600435611f866136eb565b600080516020615b8d8339815191525481600080516020615b8d833981519152556104966040519283928360209093929193604081019481520152565b3461049b57600036600319011261049b576020610ceb613ffa565b6001600160401b038111610d2a57601f01601f191660200190565b81601f8201121561049b5780359061201082611fde565b9261201e6040519485610d09565b8284526020838301011161049b57816000926020809301838601378301015290565b3461049b5761012036600319011261049b576004356001600160401b03811161049b57612071903690600401611ff9565b602435906001600160401b03821161049b57612094610021923690600401611ff9565b6044356120a081610686565b6064356120ac81610686565b6120b4610697565b60a4359160c435936120c46106a6565b956120cd6106b3565b97612f51565b3461049b57602036600319011261049b57600435600052600080516020615bad8339815191526020526020604060002054604051908152f35b3461049b57602036600319011261049b577f0422a01d7305ee5096fd51c2417c510b57e05d29fc40ab6943fabca4c2f28a2e60043561214a816104a0565b6121526136eb565b600080516020615ced833981519152805491151560ff81811660ff19851617909255604080519390921615158352602083015281908101610496565b9181601f8401121561049b578235916001600160401b03831161049b576020808501948460051b01011161049b57565b906020611e65928181520190611367565b3461049b57602036600319011261049b576004356001600160401b03811161049b576121ff90369060040161218e565b9061220982612bfd565b9160005b81811061222257604051806105f286826121be565b61222d8183856133a7565b3580600052600080516020615d6d83398151915260205260406000205490811580612281575b61226d5750906001916122668287612a12565b520161220d565b63015ab34360e11b60005260045260246000fd5b5061228b81615b1a565b15612253565b3461049b57608036600319011261049b576004356001600160401b03811161049b576122c190369060040161218e565b6024356001600160401b03811161049b576122e090369060040161218e565b6044939193356001600160401b03811161049b5761230290369060040161218e565b91606435956001600160401b03871161049b5761232661002197369060040161218e565b9690956133b7565b3461049b57600036600319011261049b576123476136eb565b61234f61388d565b6100216138b8565b3461049b57600036600319011261049b5760206040517f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a68152f35b3461049b57604036600319011261049b576100216024356004356123b582610686565b6123c16110f182612ad4565b61426e565b3461049b57604036600319011261049b5760206123fd6004356123e881610686565b610c22602435916123f883610686565b612d10565b54604051908152f35b3461049b57606036600319011261049b5760243560043561242682610686565b604435916124326139f9565b61243a6137b0565b61247c8260ff6001918060081c6000527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870c602052161b60406000205416151590565b61250d576110797fc038cf98e232734adcebf7159edd211c497cfb6127adb0a5de27e1957de254a6918360081c6000527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870c6020526040600020600160ff86161b81541790556124eb8582613bbb565b6124f3613d54565b6040519485526001600160a01b0316939081906020820190565b5063284b69a160e01b60005260045260246000fd5b3461049b57602036600319011261049b576020612540600435613530565b6040516001600160a01b039091168152f35b3461049b57602036600319011261049b576020612540600435613558565b3461049b57602036600319011261049b5760206125c760043560ff6001918060081c6000527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870c602052161b60406000205416151590565b6040519015158152f35b3461049b57600036600319011261049b5760206040517f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a8152f35b3461049b57600036600319011261049b576020610ceb6144d0565b3461049b57602036600319011261049b5761149161266661149f61264c6004356135b4565b93959260409591955197889760a0895260a0890190611367565b91606084015260808301520390f35b3461049b57602036600319011261049b57600435600080516020615dcd833981519152546001600160a01b0316331415806126ed575b6126d85780156126c757600080516020615c8d83398151915255005b6329adebad60e21b60005260046000fd5b63022f854760e21b6000523360045260246000fd5b503360009081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff16156126ab565b3461049b57602036600319011261049b5760043561274381610686565b61274b6136eb565b6001600160a01b0381169081156127a657600080516020615c4d833981519152546001600160a01b03169061277f906129a4565b7f8f93286d6f131e956d1aa672d3ecdc817f24efc20b223b0de5d591f454edc347600080a3005b630fcf818560e01b60005260046000fd5b3461049b57602036600319011261049b577f9fb7dbd1f2c1bd33dd68f78a38f699ff1ca487d7a7211ecc7df31d919f52043d6004356127f46136eb565b6127fd8161386c565b600080516020615ded8339815191525481600080516020615ded833981519152556104966040519283928360209093929193604081019481520152565b3461049b57600036600319011261049b576020610ceb614e4d565b61285d61388d565b60ff600080516020615d8d8339815191525416908015159182811515146128f757817fba1fd66f14f0aef66fe91ce6666647b14b4297998868663a23fd0cf18e38fb1c9360ff8019600080516020615d8d8339815191525416911617600080516020615d8d833981519152556128ea575b604080519115158252911515602082015290819081015b0390a1565b6128f26138b8565b6128ce565b505050565b90600182811c9216801561292c575b602083101461291657565b634e487b7160e01b600052602260045260246000fd5b91607f169161290b565b60018060a01b03166001600160601b0360a01b600080516020615dcd833981519152541617600080516020615dcd83398151915255565b60018060a01b03166001600160601b0360a01b600080516020615b4d833981519152541617600080516020615b4d83398151915255565b60018060a01b03166001600160601b0360a01b600080516020615c4d833981519152541617600080516020615c4d83398151915255565b9081602091031261049b5751611e65816104a0565b6040513d6000823e3d90fd5b634e487b7160e01b600052603260045260246000fd5b8051821015611b105760209160051b010190565b600052600080516020615c2d833981519152602052604060002090565b600052600080516020615e0d833981519152602052604060002090565b634e487b7160e01b600052601160045260246000fd5b91908201809211612a8357565b612a60565b9081602091031261049b575190565b929493612ac8606093612aba6001600160401b0394608088526080880190611367565b908682036020880152611367565b95604085015216910152565b600052600080516020615e4d83398151915260205260016040600020015490565b805160009283925b828410612b0b575050505090565b90919293612b2e612b1c8684612a12565b51612b278786612a12565b5190612e60565b8101809111612a835793600101929190612afd565b600080516020615ced8339815191528054610100600160a81b03191660089290921b610100600160a81b0316919091179055565b6012039060128211612a8357565b601119810191908211612a8357565b91908203918211612a8357565b90670de0b6b3a7640000820291808304670de0b6b3a76400001490151715612a8357565b81810292918115918404141715612a8357565b634e487b7160e01b600052601260045260246000fd5b8115612bf8570490565b612bd8565b90612c0782610d2f565b612c146040519182610d09565b8281528092612c25601f1991610d2f565b0190602036910137565b612c48600080516020615ded8339815191525482614026565b9182612c52612dbb565b9290929383958103908111612a8357612c8d670de0b6b3a7640000612c87612c786144d0565b93612c81613ffa565b90612bc5565b04612ba1565b8115612bf8570492612c9f8151612bfd565b9381519160005b838110612cb35750505050565b80676765c793fa10079d601b1b612cde612cd8612cd260019587612a12565b51615101565b86612bc5565b04612ce9828a612a12565b5201612ca6565b939291612d0b90612aba604093606088526060880190611367565b930152565b6001600160a01b031660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020526040902090565b6001600160a01b031660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006020526040902090565b60031115612d8c57565b634e487b7160e01b600052602160045260246000fd5b600080516020615bcd83398151915254611e6591614026565b600080516020615d4d8339815191525490612dd582612bfd565b612dde83612bfd565b9260005b818110612def5750509190565b80612dfb600192615214565b90549060031b1c80600052600080516020615d6d83398151915260205280612e238387612a12565b52600052600080516020615c2d833981519152602052818060a01b0360406000205416612e508288612a12565b90838060a01b0316905201612de2565b6020906001600160a01b0390612e7590613558565b1691602460405180948193631c287e7560e31b835260048301525afa908115610ada57600091612ea3575090565b611e65915060203d602011610ad357610ac58183610d09565b60ff600080516020615dad8339815191525416156106a457600080516020615dcd833981519152546001600160a01b031633141580612f18575b612f02576106a4614645565b63022f854760e21b600090815233600452602490fd5b503360009081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff1615612ef6565b9694929097959391600080516020615ecd83398151915254986001600160401b03612f92612f8560ff8d60401c1615151590565b9b6001600160401b031690565b16801590816130b3575b60011490816130a9575b1590816130a0575b5061308f57612ff3988a612fea60016001600160401b0319600080516020615ecd833981519152541617600080516020615ecd83398151915255565b613058576130bb565b612ff957565b61302560ff60401b19600080516020615ecd8339815191525416600080516020615ecd83398151915255565b604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29080602081016128e5565b61308a600160401b60ff60401b19600080516020615ecd833981519152541617600080516020615ecd83398151915255565b6130bb565b63f92ee8a960e01b60005260046000fd5b90501538612fae565b303b159150612fa6565b8b9150612f9c565b9098979593916130ce909795939761296d565b6130d66153ff565b6130de6153ff565b8051906001600160401b038211610d2a576131108261310b600080516020615c0d833981519152546128fc565b61544b565b602090601f83116001146132eb57936131c26131f8946131736132dd9c9d61315e876131fd9b986131e6986132349f9e9c6000926132e0575b50508160011b916000199060031b1c19161790565b600080516020615c0d833981519152556154fd565b61317b6153ff565b6131836153ff565b61318b614ae8565b60018060a01b03166001600160601b0360a01b600080516020615bed833981519152541617600080516020615bed83398151915255565b6131cb8161386c565b6131d48361386c565b600080516020615bcd83398151915255565b600080516020615ded83398151915255565b6129a4565b60018060a01b03166001600160601b0360a01b600080516020615eed833981519152541617600080516020615eed83398151915255565b613252670de0b6b3a7640000600080516020615e2d83398151915255565b613270670de0b6b3a7640000600080516020615c8d83398151915255565b613291676765c793fa10079d601b1b600080516020615cad83398151915255565b6132af670de0b6b3a7640000600080516020615b8d83398151915255565b6132d860ff19600080516020615ced8339815191525416600080516020615ced83398151915255565b6141c8565b50565b015190503880613149565b600080516020615c0d833981519152600052601f19831691907f2ae08a8e29253f69ac5d979a101956ab8f8d9d7ded63fa7a83b16fc47648eab09260005b81811061338f5750946131736132dd9c9d6001876131e6976132349e9d9b976131c2976131fd9e9b6131f89d10613376575b505050811b01600080516020615c0d833981519152556154fd565b015160001960f88460031b161c1916905538808061335b565b92936020600181928786015181550195019301613329565b9190811015611b105760051b0190565b91959397969490926133c76136eb565b6133cf613ffa565b966133db368686610d46565b805160018111613491575b5050986133fe613405939261340a999a9b8787614b16565b8484614c36565b614d3a565b6134126144d0565b80156134815761342490610f2f614e4d565b8115613471576134339161409f565b80156126c757600080516020615e2d833981519152556106a4427f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870155565b5050670de0b6b3a7640000613433565b629a859b60e21b60005260046000fd5b9998979695949392909a916134a58c615a47565b6000198b019a8b119a60008c5b612a83578181101561350d576134c8818f612a12565b5160018201808311612a83578f906134df91612a12565b51146134ee576001018c6134b2565b6134f8908e612a12565b5163dcd900bf60e01b60005260045260246000fd5b505061340a999b5061340594959697989a50906133fe91929b9a995092936133e6565b6000908152600080516020615c2d83398151915260205260409020546001600160a01b031690565b61356181615b1a565b156135a05760009081527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870760205260409020546001600160a01b031690565b63b6a8daab60e01b60005260045260246000fd5b90600080516020615b8d8339815191525482106136a3576135d3612dbb565b92909291836135e28151612bfd565b809382519060005b82811061362d575050506136046136099161361793612af5565b612ba1565b613611613ffa565b90612bee565b61362a61362382612da2565b8092612b94565b91565b9091925061365b61364a613644612cd28488612a12565b84612bc5565b676765c793fa10079d601b1b900490565b6136658288612a12565b526136708187612a12565b511561368257600101908592916135ea565b61368f6110999185612a12565b516360195c1560e11b600052600452602490565b638ab961fd60e01b600052600482905260246000fd5b600080516020615eed833981519152546001600160a01b031633036136da57565b63040af20760e31b60005260046000fd5b3360009081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff161561372457565b63e2517d3f60e01b60005233600452600060245260446000fd5b3360009081527f75442b0a96088b5456bc4ed01394c96a4feec0f883c9494257d76b96ab1c9b6b602052604090205460ff161561377757565b63e2517d3f60e01b600052336004527f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a60245260446000fd5b3360009081527f549fe2656c81d2947b3b913f0a53b9ea86c71e049f3a1b8aa23c09a8a05cb8d4602052604090205460ff16156137e957565b63e2517d3f60e01b600052336004527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a660245260446000fd5b6000818152600080516020615e4d8339815191526020908152604080832033845290915290205460ff16156138545750565b63e2517d3f60e01b6000523360045260245260446000fd5b662386f26fc10000111561387c57565b637186728f60e11b60005260046000fd5b60ff600080516020615dad8339815191525416156138a757565b634319513360e11b60005260046000fd5b600080516020615ccd8339815191525490600080516020615b6d83398151915254916138e2613f83565b906138fe600080516020615d2d83398151915254610f2f613ffa565b93828511613994577fdcef780e0b1062c780ef612f32c8f5301583a0630cacf576f247c0f0a9e2fbb293946128e59184600080516020615ccd8339815191525581600080516020615b6d8339815191525584600080516020615e8d8339815191525581600080516020615c6d83398151915255604051948594859094939260609260808301968352602083015260408201520152565b8285634d546de560e11b60005260045260245260446000fd5b6001600160a01b031615610b7157565b6002600080516020615ead83398151915254146139e8576002600080516020615ead83398151915255565b633ee5aeb560e01b60005260046000fd5b60ff600080516020615e6d8339815191525416613a1257565b63d93c066560e01b60005260046000fd5b15613a2a57565b6386fd6c3d60e01b60005260046000fd5b9081602091031261049b575160ff8116810361049b5790565b60405163313ce56760e01b815291602090839060049082906001600160a01b03165afa908115610ada57613a9092600092613af0575b50614ecd565b8015613a995790565b60405162461bcd60e51b815260206004820152602960248201527f546f6b656e446563696d616c73436f6e766572743a20616d6f756e74206973206044820152681d1bdbc81cdb585b1b60ba1b6064820152608490fd5b613b1391925060203d602011613b1a575b613b0b8183610d09565b810190613a3b565b9038613a8a565b503d613b01565b6040516323b872dd60e01b60208083019182526001600160a01b0394851660248401529490931660448201526064808201959095529384529260009190613b69608482610d09565b519082855af1156129f0576000513d613bb257506001600160a01b0381163b155b613b915750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b60011415613b8a565b906001600160a01b03821615613c9f57613bd36139f9565b600080516020615bed83398151915254613bf7906108bb906001600160a01b031681565b604051633196c08760e21b8152336004820152909290602081602481875afa8015610ada57613c82575b50604051633196c08760e21b81526001600160a01b038216600482015292602090849060249082905afa928315610ada576106a493613c63575b506000615745565b613c7b9060203d602011610ba857610b9b8183610d09565b5038613c5b565b613c9a9060203d602011610ba857610b9b8183610d09565b613c21565b63ec442f0560e01b600052600060045260246000fd5b6040516020810182815260208252613cce604083610d09565b6020825103613d3957613ce8906020835184010190612a88565b6001600160a01b038111908115613d2d575b50613d0c57506001600160a01b031690565b60405163046b337b60e51b8152908190613d299060048301610547565b0390fd5b61040091501038613cfa565b60405163046b337b60e51b815280613d298460048301610547565b60ff600080516020615dad8339815191525416613d6d57565b6106a4614390565b80613d7d5750565b600080808093335af13d15613dc7573d613d9681611fde565b90613da46040519283610d09565b8152600060203d92013e5b15613db657565b633c31275160e21b60005260046000fd5b613daf565b91906001600160a01b03831615613f0e576001600160a01b03811615613c9f57613df46139f9565b600080516020615bed83398151915254613e18906108bb906001600160a01b031681565b604051633196c08760e21b8152336004820152909390602081602481885afa8015610ada57613ef1575b50604051633196c08760e21b81526001600160a01b0382166004820152602081602481885afa8015610ada57613ed2575b50604051633196c08760e21b81526001600160a01b038316600482015293602090859060249082905afa938415610ada576106a494613eb3575b50615745565b613ecb9060203d602011610ba857610b9b8183610d09565b5038613ead565b613eea9060203d602011610ba857610b9b8183610d09565b5038613e73565b613f099060203d602011610ba857610b9b8183610d09565b613e42565b634b637e8f60e11b600052600060045260246000fd5b6001600160a01b031690308214613f6e578115159081613f5b575b50613f475750565b630f98d2bf60e01b60005260045260246000fd5b6001600160a01b03168214905038613f3f565b5063d751a98160e01b60005260045260246000fd5b6000600080516020615d4d833981519152546000905b808210613fa557505090565b9091613fe7613fb384615214565b905460039190911b1c6000818152600080516020615c2d83398151915260205260409020546001600160a01b031690614567565b8101809111612a83579160010190613f99565b611e6561401e6140086144d0565b600080516020615e2d8339815191525490614026565b610f2f614e4d565b6140308282614f1a565b91811561408e5781670de0b6b3a76400001115614087577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066993670de0b6b3a7640000910990828211900360ee1b910360121c170290565b6011614f2e565b50670de0b6b3a76400009250500490565b906140b2670de0b6b3a764000083614f1a565b919092831561412f578382111561412257670de0b6b3a7640000829109816000038216809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b6011600383150218614f2e565b5090611e659250612bee565b916141468284614f1a565b92909384156141bb57848311156141ae5790829109816000038216809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b6011600384150218614f2e565b505090611e659250612bee565b6141d3816000614f3f565b90816141dd575090565b60008052600080516020615bad833981519152602052614226906001600160a01b03167f615f0f9e84155bea8cc509fe18befeb1baf65611e38a6ba60964480fb29dfd4461586a565b5090565b6142348282614f3f565b918261423f57505090565b6000918252600080516020615bad8339815191526020526040909120614226916001600160a01b03169061586a565b6142788282614fed565b918261428357505090565b6000918252600080516020615bad8339815191526020526040909120614226916001600160a01b031690615910565b906001600160a01b03821615613f0e576142ca6139f9565b600080516020615bed833981519152546142ee906108bb906001600160a01b031681565b604051633196c08760e21b8152336004820152909290602081602481875afa8015610ada5761435a575b50604051633196c08760e21b81526001600160a01b038216600482015292602090849060249082905afa908115610ada576106a493600092613eb35750615745565b6143729060203d602011610ba857610b9b8183610d09565b614318565b81810392916000138015828513169184121617612a8357565b600080516020615ccd8339815191525490600080516020615b6d83398151915254916143ba613f83565b906143d6600080516020615d2d83398151915254610f2f613ffa565b93828511613994577fdcef780e0b1062c780ef612f32c8f5301583a0630cacf576f247c0f0a9e2fbb293946128e59184600080516020615ccd8339815191525581600080516020615b6d8339815191525561447061445e600080516020615e8d8339815191525461445861444989615092565b61445289615092565b90614377565b906150b7565b600080516020615e8d83398151915255565b6144ad61449b600080516020615c6d8339815191525461445861449286615092565b61445286615092565b600080516020615c6d83398151915255565b604051948594859094939260609260808301968352602083015260408201520152565b6000600080516020615d4d833981519152546000905b8082106144f257505090565b90916144fd83615214565b90549060031b1c80600052600080516020615d6d8339815191526020526040600020549081670de0b6b3a76400000291670de0b6b3a7640000830403612a8357676765c793fa10079d601b1b614554920490612e60565b8101809111612a835791600101906144e6565b906001600160a01b0316156145a2578061459c611e6592600052600080516020615e0d83398151915260205260406000205490565b90612e60565b50600090565b604d8111612a8357600a0a90565b60405163313ce56760e01b81529091602090829060049082906001600160a01b03165afa8015610ada5760ff91600091614626575b5016906012821461462157601282106146125761361161460d611e6593612b85565b6145a8565b612c8161460d611e6593612b77565b905090565b61463f915060203d602011613b1a57613b0b8183610d09565b386145eb565b61464d613f83565b90600080516020615b6d83398151915254614674600080516020615d2d8339815191525490565b9261467d6144d0565b600080516020615d8d8339815191525460ff169081614acf575b8515614a81578115614a61576146ac83615296565b955b838711614a4657816146c36146c8928961409f565b6152db565b916146df83600080516020615c8d83398151915255565b15614a03576146fa906146f0612dbb565b929091888361535e565b908051916000805b8481106149c9575b5015614823575b5050505061471d613f83565b9283861161480857907f012426c351bb738d75aead44c3641047561a6d47321f2c7e04b480667477af7794956128e59261476386600080516020615ccd83398151915255565b61477982600080516020615b6d83398151915255565b600080516020615e8d8339815191525486116147ed575b600080516020615c6d8339815191525482116147d2575b604051958695869192608093969594919660a084019784526020840152604083015260608201520152565b6147e882600080516020615c6d83398151915255565b6147a7565b61480386600080516020615e8d83398151915255565b614790565b63161ca8f560e31b6000526004869052602484905260446000fd5b60005b8381106148335750614711565b61487e61486d6148438386612a12565b5161484e8489612a12565b50600052600080516020615e0d83398151915260205260406000205490565b6148778385612a12565b5190612b94565b9081156149c05761488f8185612a12565b51916001600160a01b036148a66115d3848a612a12565b166040519363313ce56760e01b8552602085600481855afa948515610ada576001956148db916000916149a2575b5084614ecd565b801561499957600080516020615b4d833981519152547f175cb85b6e8fb1fca0c4e2d6b724596056919c2d4034c1f9fac1d1d8e0e4e64791906149469082906001600160a01b0316600080516020615ced8339815191525460081c6001600160a01b03169087613b21565b61494f83612a43565b61495a868254612b94565b9055600080516020615ced8339815191525460408051968752602087019290925260081c60a088901b889003166001600160a01b031694a45b01614826565b50505050614993565b6149ba915060203d8111613b1a57613b0b8183610d09565b386148d4565b60019150614993565b6149e16149d68286612a12565b5161484e8389612a12565b6149eb8285612a12565b51116149f957600101614702565b505060013861470a565b5050600080516020615ccd833981519152555090614a2d81600080516020615b6d83398151915255565b600080516020615c6d83398151915254811161449b5750565b63161ca8f560e31b6000526004879052602484905260446000fd5b614a7b600080516020615ccd833981519152548486615261565b956146ae565b50509050614ab8919250614aa181600080516020615ccd83398151915255565b61445e6000600080516020615b6d83398151915255565b6106a46000600080516020615c6d83398151915255565b600080516020615e8d8339815191525483119150614697565b614af06153ff565b614af86153ff565b6001600080516020615ead83398151915255565b35611e6581610686565b929190828103614c2557614b2983610d2f565b614b366040519182610d09565b838152602081018460051b84019036821161049b5784905b828210614c0b57505050614b619061561a565b60005b818110614b72575050505050565b80614bbe614b8b614b8660019488886133a7565b614b0c565b614b9f614b9984878b6133a7565b35612a26565b80546001600160a01b0319166001600160a01b03909216919091179055565b614bc98184886133a7565b35828060a01b03614bde614b868489896133a7565b16907f2c5101be4b11662e08f0e02544de444e4120439d1cd59f15359de94756a836bf600080a301614b64565b602080918335614c1a81610686565b815201910190614b4e565b634ec4810560e11b60005260046000fd5b9190600080516020615d4d8339815191525460005b818110614d1f575050838103614c255760005b818110614c725750505050506106a46156bd565b614c7d8186856133a7565b3515614cfd5780614ca7614c9460019385886133a7565b35614ca08389886133a7565b3590615ae6565b50614cb38184876133a7565b357f63295dce6ffdb7593fadb4c5c312e50fc826f065782caf4d80dbd70f5c56718f614cf4614ce3848a896133a7565b604051903581529081906020820190565b0390a201614c5e565b614d0b9061109992856133a7565b6312836e2960e11b60005235600452602490565b600190614d33614d2d6151bd565b50615ab1565b5001614c4b565b9092808403614c255760005b848110614d54575050505050565b614d6f614d6b614d658388876133a7565b35615b1a565b1590565b614e2b5780614db7610af7614d8760019489886133a7565b356000527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538707602052604060002090565b614dd6614dc8614b8684878a6133a7565b614b9f614d87858b8a6133a7565b614de18288876133a7565b35838060a01b03614df6614b8685888b6133a7565b1691848060a01b0316907fea9781e09546172aa405cb90d857735f1f5eebd53010d5f8cf91bd54e07e9e8f600080a401614d46565b614e396110999186856133a7565b63b6a8daab60e01b60005235600452602490565b600080516020615c8d8339815191525480611e655750670de0b6b3a764000090565b6001600160a01b03811691908215610c9a576001600160a01b038216938415610c845780614ec37f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92594610c22602095612d10565b55604051908152a3565b9060ff1690601282146146215760128210614efa576011198201918211612a8357612c81611e65926145a8565b9060120360128111612a8357614f0f906145a8565b908115612bf8570490565b906000198183099102908180821091030391565b634e487b716000526020526024601cfd5b6000818152600080516020615e4d833981519152602090815260408083206001600160a01b038616845290915290205460ff16614fe6576000818152600080516020615e4d833981519152602090815260408083206001600160a01b03861684529091529020805460ff1916600117905533916001600160a01b0316907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d600080a4600190565b5050600090565b6000818152600080516020615e4d833981519152602090815260408083206001600160a01b038616845290915290205460ff1615614fe6576000818152600080516020615e4d833981519152602090815260408083206001600160a01b03861684529091529020805460ff1916905533916001600160a01b0316907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b600080a4600190565b6001600160ff1b0381116150a35790565b63123baf0360e11b60005260045260246000fd5b9060008112156150ec57600160ff1b8114612a83576150d8906000036159cb565b81811015614fe6578103908111612a835790565b6150f5906159cb565b8101809111612a835790565b80600052600080516020615d6d8339815191526020526040600020549081158061512e575b61226d575090565b5060008181527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538709602052604090205415615126565b600080516020615d4d83398151915254811015611b10577f5c5fa22f08a36a7be50a2f0adcf2b13a5f19458fea36310124e841b505b2c7de01546000818152600080516020615d6d83398151915260205260409020549091565b600080516020615d4d8339815191525415611b10577f5c5fa22f08a36a7be50a2f0adcf2b13a5f19458fea36310124e841b505b2c7de546000818152600080516020615d6d83398151915260205260409020549091565b600080516020615d4d83398151915254811015611b1057600080516020615d4d83398151915260005260206000200190600090565b8054821015611b105760005260206000200190600090565b919081811015615280578103908111612a83578103908111612a835790565b908103908111612a83578101809111612a835790565b600080516020615e8d8339815191525490600080516020615c6d8339815191525491600080516020615cad83398151915254908203918211612a83576150f5916159ea565b9081158015615356575b801561533f575b615314579061530e611e6592600080516020615e2d8339815191525490614026565b9061409f565b600080516020615e2d8339815191525491631cbba81760e21b60005260045260245260445260646000fd5b50600080516020615e2d83398151915254156152ec565b5080156152e5565b929180156153ee5761536f91615a13565b825161537a81612bfd565b9360005b82811061538b5750505050565b6153958183612a12565b5180600052600080516020615d6d833981519152602052604060002054908115806153de575b61226d5750906153cd600192866159ea565b6153d78289612a12565b520161537e565b506153e881615b1a565b156153bb565b63656b5b4960e01b60005260046000fd5b60ff600080516020615ecd8339815191525460401c161561541c57565b631afcd79f60e31b60005260046000fd5b916154479183549060031b91821b91600019901b19161790565b9055565b601f8111615457575050565b600080516020615c0d8339815191526000526020600020906020601f840160051c830193106154a1575b601f0160051c01905b818110615495575050565b6000815560010161548a565b9091508190615481565b601f82116154b857505050565b6000526020600020906020601f840160051c830193106154f3575b601f0160051c01905b8181106154e7575050565b600081556001016154dc565b90915081906154d3565b9081516001600160401b038111610d2a5761553e8161552a600080516020615d0d833981519152546128fc565b600080516020615d0d8339815191526154ab565b602092601f82116001146155815761556f929382916000926132e05750508160011b916000199060031b1c19161790565b600080516020615d0d83398151915255565b600080516020615d0d833981519152600052601f198216937f46a2803e59a4de4e7a4c574b1243f25977ac4c77d5a1a4a609b5394cebb4a2aa9160005b86811061560257508360019596106155e9575b505050811b01600080516020615d0d83398151915255565b015160001960f88460031b161c191690553880806155d1565b919260206001819286850151815501940192016155be565b80519060018211615629575050565b909161563482615a47565b6000198301928311926000845b612a8357818110156156b6576001600160a01b0361565f8286612a12565b511660018201808311612a83576108bb6115d361567c9288612a12565b1461568a5760010184615641565b61569a6115d36110999286612a12565b63332c860960e21b6000526001600160a01b0316600452602490565b5050915050565b6000600080516020615d4d833981519152546000905b808210615705575050676765c793fa10079d601b1b81036156f15750565b630752747760e21b60005260045260246000fd5b909161571083615214565b90549060031b1c600052600080516020615d6d8339815191526020526040600020548101809111612a835791600101906156d3565b90916001600160a01b03821691826157fc57506157e3816157ab6157997fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef94600080516020615d2d83398151915254612a76565b600080516020615d2d83398151915255565b6001600160a01b03851694856157e8575061099581600080516020615d2d8339815191525403600080516020615d2d83398151915255565b0390a3565b6157f190612d49565b818154019055610995565b61580581612d49565b5482811061584557916157e39161583f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef950391612d49565b556157ab565b63391434e360e21b6000526001600160a01b0390911660045260245260445260646000fd5b6000828152600182016020526040902054614fe657805490600160401b821015610d2a57826158ba6158a3846001809601855584615249565b819391549060031b91821b91600019901b19161790565b905580549260005201602052604060002055600190565b805480156158fa5760001901906158e88282615249565b8154906000199060031b1b1916905555565b634e487b7160e01b600052603160045260246000fd5b60018101918060005282602052604060002054928315156000146159c2576000198401848111612a83578354600019810194908511612a83576000958583615973976159649503615979575b5050506158d1565b90600052602052604060002090565b55600190565b6159a96159a39161599a6159906159b99588615249565b90549060031b1c90565b92839187615249565b9061542d565b8590600052602052604060002090565b5538808061595c565b50505050600090565b600081126159d65790565b635467221960e11b60005260045260246000fd5b90676765c793fa10079d601b1b90615a0382828561413b565b920915158101809111612a835790565b90615a2781670de0b6b3a76400008461413b565b918115612bf857670de0b6b3a7640000900915158101809111612a835790565b805190600081528160051b81019260208201935b6020850191818311615aaa57825195805187811115615a9d575b6020820152601f19018051878111615a7557506020909691949295939601525b919092615a5b565b5050929093919450615a95565b9450505052565b611e659080600052600080516020615d6d83398151915260205260006040812055600080516020615d4d833981519152615910565b611e659181600052600080516020615d6d833981519152602052604060002055600080516020615d4d83398151915261586a565b6000527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870960205260406000205415159056fe965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538700965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538712965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870ec1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e82371705932000965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538703965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870252c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace03965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538706965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538705965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538718965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538713965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538715965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538711965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0452c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538708965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870a965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538716965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538714965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538710965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538704965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538719965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870d02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a5387179b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870b","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"paris","libraries":{},"metadata":{"appendCBOR":false,"bytecodeHash":"none"},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"":["*"],"*":["*"]}},"viaIR":true},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":null,"compiler_version":"v0.8.26+commit.8a97fa7a","is_verified_via_verifier_alliance":false,"verified_at":"2026-09-05T04:35:41.950085Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x6080806040523460d2577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c1660c1576002600160401b03196001600160401b03821601605c575b604051615f0d90816100d88239f35b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a13880604d565b63f92ee8a960e01b60005260046000fd5b600080fdfe60806040526004361015610023575b361561001957600080fd5b6100216136b9565b005b60003560e01c8063017def57146104135780630196db001461040e57806301ffc9a71461040957806306fdde0314610404578063095ea7b3146103ff5780630ccb2719146103fa57806310b8063b146103f55780631255899f146103f057806318160ddd146103eb57806323b872dd146103e6578063248a9ca3146103e157806324dd2630146103dc57806328b6076c146103d75780632b04ae2b146103d25780632f2ff15d146103cd578063313ce567146103c857806336568abe146103c35780633f4ba83a146103be57806340c10f19146103b957806342966c68146103b4578063487f9ca2146103af5780634cdad506146103aa5780635c975abb146103a5578063601fbd63146103a0578063673da1541461039b57806370a082311461039657806382300ee3146103915780638456cb591461038c57806385eb096b1461038757806386fbb6f3146103825780638984d4611461037d57806389fcbdc5146103785780638fd6a6ac146103735780639010d07c1461036e57806391d148541461036957806395d89b41146103645780639e4bca6b1461035f578063a217fddf1461035a578063a3246ad314610355578063a5aedeba14610350578063a9059cbb1461034b578063b16b0e9514610346578063b57a803a14610341578063b69545321461033c578063ca15c87314610337578063cd1818d114610332578063cddd41361461032d578063ce6e469814610328578063d0f2408514610323578063d53913931461031e578063d547741f14610319578063dd62ed3e14610314578063e20a15071461030f578063e20c40ba1461030a578063e31999b414610305578063e338b10a14610300578063e63ab1e9146102fb578063e6aa216c146102f6578063ef8b30f7146102f1578063f2b01850146102ec578063f46901ed146102e7578063fb00d514146102e25763fc0e6e4e0361000e5761283a565b6127b7565b612726565b612675565b612627565b61260c565b6125d1565b612570565b612552565b612522565b612406565b6123c6565b612392565b612357565b61232e565b612291565b6121cf565b61210c565b6120d3565b612040565b611fc3565b611f49565b611f1f565b611eea565b611e68565b611e38565b611c8e565b611bcc565b611b69565b611b15565b611aa6565b6119fe565b6119ce565b6119ad565b611969565b6118f5565b611872565b611816565b61160a565b6114c5565b61143c565b6113d8565b61124d565b611220565b6111e4565b611161565b611117565b6110fb565b6110c2565b610e91565b610e4e565b610d92565b610ccd565b610c06565b610baf565b61083b565b610778565b6106f6565b6106c1565b61058f565b6104d7565b6104aa565b3461049b57602036600319011261049b577f828cf983933545af35b9ba46eec951db1cb4c5433c3ec403aeced2963c2647906004356104506136eb565b6104598161386c565b600080516020615bcd8339815191525481600080516020615bcd833981519152556104966040519283928360209093929193604081019481520152565b0390a1005b600080fd5b8015150361049b57565b3461049b57602036600319011261049b576100216004356104ca816104a0565b6104d26136eb565b612855565b3461049b57602036600319011261049b5760043563ffffffff60e01b811680910361049b57602090635a05180f60e01b811490811561051c575b506040519015158152f35b637965db0b60e01b811491508115610536575b5038610511565b6301ffc9a760e01b1490503861052f565b60208082528251910181815290929160005b84811061057a575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201610559565b3461049b57600036600319011261049b576040516000600080516020615c0d833981519152546105be816128fc565b808452906001811690811561066257506001146105f6575b6105f2836105e681850382610d09565b60405191829182610547565b0390f35b600080516020615c0d83398151915260009081527f2ae08a8e29253f69ac5d979a101956ab8f8d9d7ded63fa7a83b16fc47648eab0939250905b808210610648575090915081016020016105e66105d6565b919260018160209254838588010152019101909291610630565b60ff191660208086019190915291151560051b840190910191506105e690506105d6565b6001600160a01b0381160361049b57565b608435906106a482610686565b565b60e435906106a482610686565b61010435906106a482610686565b3461049b57604036600319011261049b576106eb6004356106e181610686565b6024359033614e6f565b602060405160018152f35b3461049b57602036600319011261049b5760043561071381610686565b61071b6136eb565b610724816139ad565b600080516020615dcd833981519152546001600160a01b03169061074781612936565b6001600160a01b0316907f6f467c633fa7217ba6a3845632b7385764f9b966af28c57a334190aedf3602ca600080a3005b3461049b57602036600319011261049b576004356107946136eb565b676765c793fa10079d601b1b8111610827577f0527e14a979eae4df92dbdc207af2749a5b2602095816f4796618ada205a602b90600080516020615cad8339815191525481600080516020615cad8339815191525560ff600080516020615dad833981519152541661081a575b6040805191825260208201929092529081908101610496565b6108226138b8565b610801565b6363bf523b60e11b60005260045260246000fd5b606036600319011261049b57600435602435604435916001600160401b0383169283810361049b5761086b6139bd565b6108736139f9565b600092610897610892600080516020615ced8339815191525460ff1690565b613a23565b600080516020615bed833981519152546108c7906108bb906001600160a01b031681565b6001600160a01b031690565b604051632f47185360e11b81523360048201529190602090839060249082905afa918215610ada576108fe92610b82575b506135b4565b9193809593509790975160005b818110610adf5750506109ce579161097b87927f39ca5049a496c9f67bc317ee005dc40fc3e8136f0c865acbd6d91a10df8099ba946109556105f29a6109508a613cb5565b613bbb565b806109a5575b50610964613d54565b61096d47613d75565b604051938493339785612a97565b0390a36109956001600080516020615ead83398151915255565b6040519081529081906020820190565b600080516020615c4d833981519152546109c891906001600160a01b0316613bbb565b3861095b565b9450946109db8130613bbb565b600080516020615eed83398151915254610a009082906001600160a01b031630614e6f565b600080516020615eed83398151915254610a24906108bb906001600160a01b031681565b604051631472b4bb60e01b81526001600160401b03881660048201526024810186905230604482015260648101839052600060848201529290602090849060a490829034905af1928315610ada576105f2977f39ca5049a496c9f67bc317ee005dc40fc3e8136f0c865acbd6d91a10df8099ba9461097b92600091610aab575b5097610955565b610acd915060203d602011610ad3575b610ac58183610d09565b810190612a88565b38610aa4565b503d610abb565b6129f0565b610ae98188612a12565b5190610b04610af783612a26565b546001600160a01b031690565b6001600160a01b038116928315610b7157610b61610b6991610b5c600196610b2c878e612a12565b51600080516020615b4d83398151915254909690610b54906001600160a01b03169188613a54565b913390613b21565b612a43565b918254612a76565b90550161090b565b63d92e233d60e01b60005260046000fd5b610ba39060203d602011610ba8575b610b9b8183610d09565b8101906129db565b6108f8565b503d610b91565b3461049b57600036600319011261049b576020600080516020615d2d83398151915254604051908152f35b606090600319011261049b57600435610bf281610686565b90602435610bff81610686565b9060443590565b3461049b57610c1436610bda565b90610c3933610c2285612d10565b9060018060a01b0316600052602052604060002090565b54926000198410610c4f575b6106eb9350613dcc565b828410610cb0576001600160a01b03811615610c9a573315610c8457826106eb9403610c7e33610c2284612d10565b55610c45565b634a1406b160e11b600052600060045260246000fd5b63e602df0560e01b600052600060045260246000fd5b8284637dc7a0d960e11b6000523360045260245260445260646000fd5b3461049b57602036600319011261049b576020610ceb600435612ad4565b604051908152f35b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b03821117610d2a57604052565b610cf3565b6001600160401b038111610d2a5760051b60200190565b929190610d5281610d2f565b93610d606040519586610d09565b602085838152019160051b810192831161049b57905b828210610d8257505050565b8135815260209182019101610d76565b3461049b57604036600319011261049b576004356001600160401b03811161049b573660238201121561049b57610dd3903690602481600401359101610d46565b602435906001600160401b03821161049b573660238301121561049b57816004013591610dff83610d2f565b92610e0d6040519485610d09565b8084526024602085019160051b8301019136831161049b57602401905b828210610e3e576105f26109958686612af5565b8135815260209182019101610e2a565b3461049b57602036600319011261049b57600435610e6b81613530565b50600052600080516020615e0d8339815191526020526020604060002054604051908152f35b3461049b57610e9f36610bda565b610ea76136eb565b600080516020615dad8339815191525460ff166110b157610ec7836139ad565b610ed0826139ad565b600080516020615b4d83398151915254610ef3906001600160a01b031684613f24565b676765c793fa10079d601b1b811161109d57610f0d613f83565b91610f35610f27600080516020615d2d8339815191525490565b610f2f613ffa565b90614026565b9183831161107e5790610fd27f5e76b9b2a061e1e3d2e1f275d9dbf7d730d608fe36e0828c80ae1e34340a2e4d9392610f6d87612b43565b610f7683612936565b610f8c86600080516020615ccd83398151915255565b610fa284600080516020615b6d83398151915255565b610fc0670de0b6b3a7640000600080516020615c8d83398151915255565b600080516020615cad83398151915255565b610ffe600160ff19600080516020615dad833981519152541617600080516020615dad83398151915255565b61102a600160ff19600080516020615d8d833981519152541617600080516020615d8d83398151915255565b61104084600080516020615e8d83398151915255565b61105682600080516020615c6d83398151915255565b6040805194855260208501929092526001600160a01b0390811694169290819081015b0390a3005b632dc9987b60e21b6000526004839052602484905260446000fd5b6000fd5b6363bf523b60e11b60005260045260246000fd5b630663e84960e41b60005260046000fd5b3461049b57604036600319011261049b576100216024356004356110e582610686565b6110f66110f182612ad4565b613822565b61422a565b3461049b57600036600319011261049b57602060405160128152f35b3461049b57604036600319011261049b5760043560243561113781610686565b336001600160a01b03821603611150576100219161426e565b63334bd91960e11b60005260046000fd5b3461049b57600036600319011261049b5761117a61373e565b600080516020615e6d8339815191525460ff8116156111d35760ff1916600080516020615e6d833981519152557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b638dfc202b60e01b60005260046000fd5b3461049b57604036600319011261049b5761121860043561120481610686565b602435906112106139f9565b6109506137b0565b610021613d54565b3461049b57602036600319011261049b5761121860043561123f6139f9565b6112476137b0565b336142b2565b3461049b57602036600319011261049b576004356112696136eb565b61127281613530565b81600052600080516020615e0d83398151915260205260406000205460018060a01b03600080516020615b4d8339815191525416604051906370a0823160e01b8252600482015260208160248160018060a01b0387165afa928315610ada577fdf173d8e3147dcb07bf86ccb47a4443e162acd522d0bd3b6e3f9147a79c8b23b9361130592600091611348575b506145b6565b908161131085612a43565b55600080516020615dad8339815191525460ff1661133b575b604080519182526020820192909252a2005b611343614390565b611329565b611361915060203d602011610ad357610ac58183610d09565b386112ff565b906020808351928381520192019060005b8181106113855750505090565b8251845260209384019390920191600101611378565b906020808351928381520192019060005b8181106113b95750505090565b82516001600160a01b03168452602093840193909201916001016113ac565b3461049b57602036600319011261049b576114166114246114326113fd600435612c2f565b9392949091604051968796608088526080880190611367565b90868203602088015261139b565b908482036040860152611367565b9060608301520390f35b3461049b57600036600319011261049b57602060ff600080516020615e6d83398151915254166040519015158152f35b926114ad9061149f6114bb9461149160a098959b9a999b60c0895260c0890190611367565b90878203602089015261139b565b908582036040870152611367565b908382036060850152611367565b9460808201520152565b3461049b57600036600319011261049b576000600080516020615d4d833981519152546114f181612bfd565b906114fb81612bfd565b9261150582612bfd565b9161150f81612bfd565b906000905b808210611552575050906105f292917f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870154926040519687968761146c565b90926116026001916115e661156687615214565b90549060031b1c80600052600080516020615d6d833981519152602052604060002054816115948a8d612a12565b526115bb8c6115ac8b6115a686613530565b92612a12565b6001600160a01b039091169052565b6115c5898b612a12565b526115e06115d3898d612a12565b516001600160a01b031690565b90614567565b6115f08787612a12565b526115fb8686612a12565b5190612a76565b930190611514565b3461049b57604036600319011261049b576004356024356116296139bd565b6116316139f9565b801561180557611653610892600080516020615ced8339815191525460ff1690565b600080516020615bed83398151915254611677906108bb906001600160a01b031681565b604051632f47185360e11b815233600482015290602090829060249082905afa8015610ada576117e8575b506116ac81612c2f565b909150829392516116bc86613cb5565b6001600160a01b03811615610b715760005b828110611769575050509082916117067f0519b17bd58a626c9c8c8cf874404b2d1b8742321da306cee40ce3ebc812cedf94336142b2565b80611740575b50611715613d54565b611726604051928392339684612cf0565b0390a36100216001600080516020615ead83398151915255565b600080516020615c4d8339815191525461176391906001600160a01b0316613bbb565b3861170c565b6117738188612a12565b5190611781610af783612a26565b6001600160a01b038116928315610b71576117d86117e091610b5c600196886117aa888e612a12565b51600080516020615b4d833981519152549097906117d2906001600160a01b03169189613a54565b92613b21565b918254612b94565b9055016116ce565b6118009060203d602011610ba857610b9b8183610d09565b6116a2565b639811e0c760e01b60005260046000fd5b3461049b57602036600319011261049b5760043561183381610686565b60018060a01b03166000527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006020526020604060002054604051908152f35b3461049b57604036600319011261049b57600435602435600381101561049b57600090806118b8575050610ceb602091600080516020615bcd8339815191525490614026565b806118c4600292612d82565b036118e65750610ceb602091600080516020615ded8339815191525490614026565b633a08349960e01b8152600490fd5b3461049b57600036600319011261049b5761190e61373e565b6119166139f9565b600160ff19600080516020615e6d833981519152541617600080516020615e6d833981519152557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b3461049b57600036600319011261049b5761199f6105f2611988612dbb565b604092919251938493604085526040850190611367565b90838203602085015261139b565b3461049b57604036600319011261049b576020610ceb602435600435612e60565b3461049b57600036600319011261049b57602060ff600080516020615ced83398151915254166040519015158152f35b3461049b57602036600319011261049b57600435611a1b81610686565b611a236136eb565b611a2c816139ad565b600080516020615b4d83398151915254611a4f906001600160a01b031682613f24565b600080516020615ced8339815191525460081c6001600160a01b031690611a7581612b43565b6001600160a01b0316907f54faf859f8b04a3fce57f3bf185c6dcb0df7cdf90060a9617bcc9334e9d785ab600080a3005b3461049b57600036600319011261049b5760008052600080516020615bad8339815191526020527f615f0f9e84155bea8cc509fe18befeb1baf65611e38a6ba60964480fb29dfd44805415611b105760005260208060002060018060a01b03905416604051908152f35b6129fc565b3461049b57604036600319011261049b576020611b5060043560243590600052600080516020615bad83398151915283526040600020615249565b905460405160039290921b1c6001600160a01b03168152f35b3461049b57604036600319011261049b57602060ff611bc0602435600435611b9082610686565b600052600080516020615e4d833981519152845260406000209060018060a01b0316600052602052604060002090565b54166040519015158152f35b3461049b57600036600319011261049b576040516000600080516020615d0d83398151915254611bfb816128fc565b80845290600181169081156106625750600114611c22576105f2836105e681850382610d09565b600080516020615d0d83398151915260009081527f46a2803e59a4de4e7a4c574b1243f25977ac4c77d5a1a4a609b5394cebb4a2aa939250905b808210611c74575090915081016020016105e66105d6565b919260018160209254838588010152019101909291611c5c565b3461049b57602036600319011261049b57600435611cab81610686565b611cb36136eb565b6001600160a01b038116908115611e2757600080516020615ced83398151915254611ceb90829060081c6001600160a01b0316613f24565b600080516020615d4d8339815191525460005b818110611d62575050600080516020615b4d83398151915254611d2a906001600160a01b03169161296d565b611d32613d54565b6001600160a01b03167f12ba215d768031449a2499d64e291257e7f005e01b2b858d59414e3bb728d08b600080a3005b611d6b81615163565b50611d78610af782612a26565b6001600160a01b0381168015611e1c57611d9183612a43565b546040516370a0823160e01b81526001600160a01b038816600482015290929091602090839060249082905afa8015610ada57611dd592600091611e0457506145b6565b91818310611dea575050506001905b01611cfe565b6303c563e560e61b60005260045260245260445260646000fd5b611361915060203d8111610ad357610ac58183610d09565b505050600190611de4565b6351dc806d60e11b60005260046000fd5b3461049b57600036600319011261049b57602060405160008152f35b906020611e6592818152019061139b565b90565b3461049b57602036600319011261049b57600435600052600080516020615bad833981519152602052604060002060405190816020825491828152019160005260206000209060005b818110611ed4576105f285611ec881870382610d09565b60405191829182611e54565b8254845260209093019260019283019201611eb1565b3461049b57600036600319011261049b57611f036139bd565b611f0b612ebc565b6001600080516020615ead83398151915255005b3461049b57604036600319011261049b576106eb600435611f3f81610686565b6024359033613dcc565b3461049b57602036600319011261049b577faaf8f648880295798ded4114dd6c34d37444c6a0ccf160a98c1b5c644de08d8f600435611f866136eb565b600080516020615b8d8339815191525481600080516020615b8d833981519152556104966040519283928360209093929193604081019481520152565b3461049b57600036600319011261049b576020610ceb613ffa565b6001600160401b038111610d2a57601f01601f191660200190565b81601f8201121561049b5780359061201082611fde565b9261201e6040519485610d09565b8284526020838301011161049b57816000926020809301838601378301015290565b3461049b5761012036600319011261049b576004356001600160401b03811161049b57612071903690600401611ff9565b602435906001600160401b03821161049b57612094610021923690600401611ff9565b6044356120a081610686565b6064356120ac81610686565b6120b4610697565b60a4359160c435936120c46106a6565b956120cd6106b3565b97612f51565b3461049b57602036600319011261049b57600435600052600080516020615bad8339815191526020526020604060002054604051908152f35b3461049b57602036600319011261049b577f0422a01d7305ee5096fd51c2417c510b57e05d29fc40ab6943fabca4c2f28a2e60043561214a816104a0565b6121526136eb565b600080516020615ced833981519152805491151560ff81811660ff19851617909255604080519390921615158352602083015281908101610496565b9181601f8401121561049b578235916001600160401b03831161049b576020808501948460051b01011161049b57565b906020611e65928181520190611367565b3461049b57602036600319011261049b576004356001600160401b03811161049b576121ff90369060040161218e565b9061220982612bfd565b9160005b81811061222257604051806105f286826121be565b61222d8183856133a7565b3580600052600080516020615d6d83398151915260205260406000205490811580612281575b61226d5750906001916122668287612a12565b520161220d565b63015ab34360e11b60005260045260246000fd5b5061228b81615b1a565b15612253565b3461049b57608036600319011261049b576004356001600160401b03811161049b576122c190369060040161218e565b6024356001600160401b03811161049b576122e090369060040161218e565b6044939193356001600160401b03811161049b5761230290369060040161218e565b91606435956001600160401b03871161049b5761232661002197369060040161218e565b9690956133b7565b3461049b57600036600319011261049b576123476136eb565b61234f61388d565b6100216138b8565b3461049b57600036600319011261049b5760206040517f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a68152f35b3461049b57604036600319011261049b576100216024356004356123b582610686565b6123c16110f182612ad4565b61426e565b3461049b57604036600319011261049b5760206123fd6004356123e881610686565b610c22602435916123f883610686565b612d10565b54604051908152f35b3461049b57606036600319011261049b5760243560043561242682610686565b604435916124326139f9565b61243a6137b0565b61247c8260ff6001918060081c6000527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870c602052161b60406000205416151590565b61250d576110797fc038cf98e232734adcebf7159edd211c497cfb6127adb0a5de27e1957de254a6918360081c6000527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870c6020526040600020600160ff86161b81541790556124eb8582613bbb565b6124f3613d54565b6040519485526001600160a01b0316939081906020820190565b5063284b69a160e01b60005260045260246000fd5b3461049b57602036600319011261049b576020612540600435613530565b6040516001600160a01b039091168152f35b3461049b57602036600319011261049b576020612540600435613558565b3461049b57602036600319011261049b5760206125c760043560ff6001918060081c6000527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870c602052161b60406000205416151590565b6040519015158152f35b3461049b57600036600319011261049b5760206040517f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a8152f35b3461049b57600036600319011261049b576020610ceb6144d0565b3461049b57602036600319011261049b5761149161266661149f61264c6004356135b4565b93959260409591955197889760a0895260a0890190611367565b91606084015260808301520390f35b3461049b57602036600319011261049b57600435600080516020615dcd833981519152546001600160a01b0316331415806126ed575b6126d85780156126c757600080516020615c8d83398151915255005b6329adebad60e21b60005260046000fd5b63022f854760e21b6000523360045260246000fd5b503360009081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff16156126ab565b3461049b57602036600319011261049b5760043561274381610686565b61274b6136eb565b6001600160a01b0381169081156127a657600080516020615c4d833981519152546001600160a01b03169061277f906129a4565b7f8f93286d6f131e956d1aa672d3ecdc817f24efc20b223b0de5d591f454edc347600080a3005b630fcf818560e01b60005260046000fd5b3461049b57602036600319011261049b577f9fb7dbd1f2c1bd33dd68f78a38f699ff1ca487d7a7211ecc7df31d919f52043d6004356127f46136eb565b6127fd8161386c565b600080516020615ded8339815191525481600080516020615ded833981519152556104966040519283928360209093929193604081019481520152565b3461049b57600036600319011261049b576020610ceb614e4d565b61285d61388d565b60ff600080516020615d8d8339815191525416908015159182811515146128f757817fba1fd66f14f0aef66fe91ce6666647b14b4297998868663a23fd0cf18e38fb1c9360ff8019600080516020615d8d8339815191525416911617600080516020615d8d833981519152556128ea575b604080519115158252911515602082015290819081015b0390a1565b6128f26138b8565b6128ce565b505050565b90600182811c9216801561292c575b602083101461291657565b634e487b7160e01b600052602260045260246000fd5b91607f169161290b565b60018060a01b03166001600160601b0360a01b600080516020615dcd833981519152541617600080516020615dcd83398151915255565b60018060a01b03166001600160601b0360a01b600080516020615b4d833981519152541617600080516020615b4d83398151915255565b60018060a01b03166001600160601b0360a01b600080516020615c4d833981519152541617600080516020615c4d83398151915255565b9081602091031261049b5751611e65816104a0565b6040513d6000823e3d90fd5b634e487b7160e01b600052603260045260246000fd5b8051821015611b105760209160051b010190565b600052600080516020615c2d833981519152602052604060002090565b600052600080516020615e0d833981519152602052604060002090565b634e487b7160e01b600052601160045260246000fd5b91908201809211612a8357565b612a60565b9081602091031261049b575190565b929493612ac8606093612aba6001600160401b0394608088526080880190611367565b908682036020880152611367565b95604085015216910152565b600052600080516020615e4d83398151915260205260016040600020015490565b805160009283925b828410612b0b575050505090565b90919293612b2e612b1c8684612a12565b51612b278786612a12565b5190612e60565b8101809111612a835793600101929190612afd565b600080516020615ced8339815191528054610100600160a81b03191660089290921b610100600160a81b0316919091179055565b6012039060128211612a8357565b601119810191908211612a8357565b91908203918211612a8357565b90670de0b6b3a7640000820291808304670de0b6b3a76400001490151715612a8357565b81810292918115918404141715612a8357565b634e487b7160e01b600052601260045260246000fd5b8115612bf8570490565b612bd8565b90612c0782610d2f565b612c146040519182610d09565b8281528092612c25601f1991610d2f565b0190602036910137565b612c48600080516020615ded8339815191525482614026565b9182612c52612dbb565b9290929383958103908111612a8357612c8d670de0b6b3a7640000612c87612c786144d0565b93612c81613ffa565b90612bc5565b04612ba1565b8115612bf8570492612c9f8151612bfd565b9381519160005b838110612cb35750505050565b80676765c793fa10079d601b1b612cde612cd8612cd260019587612a12565b51615101565b86612bc5565b04612ce9828a612a12565b5201612ca6565b939291612d0b90612aba604093606088526060880190611367565b930152565b6001600160a01b031660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020526040902090565b6001600160a01b031660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace006020526040902090565b60031115612d8c57565b634e487b7160e01b600052602160045260246000fd5b600080516020615bcd83398151915254611e6591614026565b600080516020615d4d8339815191525490612dd582612bfd565b612dde83612bfd565b9260005b818110612def5750509190565b80612dfb600192615214565b90549060031b1c80600052600080516020615d6d83398151915260205280612e238387612a12565b52600052600080516020615c2d833981519152602052818060a01b0360406000205416612e508288612a12565b90838060a01b0316905201612de2565b6020906001600160a01b0390612e7590613558565b1691602460405180948193631c287e7560e31b835260048301525afa908115610ada57600091612ea3575090565b611e65915060203d602011610ad357610ac58183610d09565b60ff600080516020615dad8339815191525416156106a457600080516020615dcd833981519152546001600160a01b031633141580612f18575b612f02576106a4614645565b63022f854760e21b600090815233600452602490fd5b503360009081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff1615612ef6565b9694929097959391600080516020615ecd83398151915254986001600160401b03612f92612f8560ff8d60401c1615151590565b9b6001600160401b031690565b16801590816130b3575b60011490816130a9575b1590816130a0575b5061308f57612ff3988a612fea60016001600160401b0319600080516020615ecd833981519152541617600080516020615ecd83398151915255565b613058576130bb565b612ff957565b61302560ff60401b19600080516020615ecd8339815191525416600080516020615ecd83398151915255565b604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29080602081016128e5565b61308a600160401b60ff60401b19600080516020615ecd833981519152541617600080516020615ecd83398151915255565b6130bb565b63f92ee8a960e01b60005260046000fd5b90501538612fae565b303b159150612fa6565b8b9150612f9c565b9098979593916130ce909795939761296d565b6130d66153ff565b6130de6153ff565b8051906001600160401b038211610d2a576131108261310b600080516020615c0d833981519152546128fc565b61544b565b602090601f83116001146132eb57936131c26131f8946131736132dd9c9d61315e876131fd9b986131e6986132349f9e9c6000926132e0575b50508160011b916000199060031b1c19161790565b600080516020615c0d833981519152556154fd565b61317b6153ff565b6131836153ff565b61318b614ae8565b60018060a01b03166001600160601b0360a01b600080516020615bed833981519152541617600080516020615bed83398151915255565b6131cb8161386c565b6131d48361386c565b600080516020615bcd83398151915255565b600080516020615ded83398151915255565b6129a4565b60018060a01b03166001600160601b0360a01b600080516020615eed833981519152541617600080516020615eed83398151915255565b613252670de0b6b3a7640000600080516020615e2d83398151915255565b613270670de0b6b3a7640000600080516020615c8d83398151915255565b613291676765c793fa10079d601b1b600080516020615cad83398151915255565b6132af670de0b6b3a7640000600080516020615b8d83398151915255565b6132d860ff19600080516020615ced8339815191525416600080516020615ced83398151915255565b6141c8565b50565b015190503880613149565b600080516020615c0d833981519152600052601f19831691907f2ae08a8e29253f69ac5d979a101956ab8f8d9d7ded63fa7a83b16fc47648eab09260005b81811061338f5750946131736132dd9c9d6001876131e6976132349e9d9b976131c2976131fd9e9b6131f89d10613376575b505050811b01600080516020615c0d833981519152556154fd565b015160001960f88460031b161c1916905538808061335b565b92936020600181928786015181550195019301613329565b9190811015611b105760051b0190565b91959397969490926133c76136eb565b6133cf613ffa565b966133db368686610d46565b805160018111613491575b5050986133fe613405939261340a999a9b8787614b16565b8484614c36565b614d3a565b6134126144d0565b80156134815761342490610f2f614e4d565b8115613471576134339161409f565b80156126c757600080516020615e2d833981519152556106a4427f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870155565b5050670de0b6b3a7640000613433565b629a859b60e21b60005260046000fd5b9998979695949392909a916134a58c615a47565b6000198b019a8b119a60008c5b612a83578181101561350d576134c8818f612a12565b5160018201808311612a83578f906134df91612a12565b51146134ee576001018c6134b2565b6134f8908e612a12565b5163dcd900bf60e01b60005260045260246000fd5b505061340a999b5061340594959697989a50906133fe91929b9a995092936133e6565b6000908152600080516020615c2d83398151915260205260409020546001600160a01b031690565b61356181615b1a565b156135a05760009081527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870760205260409020546001600160a01b031690565b63b6a8daab60e01b60005260045260246000fd5b90600080516020615b8d8339815191525482106136a3576135d3612dbb565b92909291836135e28151612bfd565b809382519060005b82811061362d575050506136046136099161361793612af5565b612ba1565b613611613ffa565b90612bee565b61362a61362382612da2565b8092612b94565b91565b9091925061365b61364a613644612cd28488612a12565b84612bc5565b676765c793fa10079d601b1b900490565b6136658288612a12565b526136708187612a12565b511561368257600101908592916135ea565b61368f6110999185612a12565b516360195c1560e11b600052600452602490565b638ab961fd60e01b600052600482905260246000fd5b600080516020615eed833981519152546001600160a01b031633036136da57565b63040af20760e31b60005260046000fd5b3360009081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff161561372457565b63e2517d3f60e01b60005233600452600060245260446000fd5b3360009081527f75442b0a96088b5456bc4ed01394c96a4feec0f883c9494257d76b96ab1c9b6b602052604090205460ff161561377757565b63e2517d3f60e01b600052336004527f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a60245260446000fd5b3360009081527f549fe2656c81d2947b3b913f0a53b9ea86c71e049f3a1b8aa23c09a8a05cb8d4602052604090205460ff16156137e957565b63e2517d3f60e01b600052336004527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a660245260446000fd5b6000818152600080516020615e4d8339815191526020908152604080832033845290915290205460ff16156138545750565b63e2517d3f60e01b6000523360045260245260446000fd5b662386f26fc10000111561387c57565b637186728f60e11b60005260046000fd5b60ff600080516020615dad8339815191525416156138a757565b634319513360e11b60005260046000fd5b600080516020615ccd8339815191525490600080516020615b6d83398151915254916138e2613f83565b906138fe600080516020615d2d83398151915254610f2f613ffa565b93828511613994577fdcef780e0b1062c780ef612f32c8f5301583a0630cacf576f247c0f0a9e2fbb293946128e59184600080516020615ccd8339815191525581600080516020615b6d8339815191525584600080516020615e8d8339815191525581600080516020615c6d83398151915255604051948594859094939260609260808301968352602083015260408201520152565b8285634d546de560e11b60005260045260245260446000fd5b6001600160a01b031615610b7157565b6002600080516020615ead83398151915254146139e8576002600080516020615ead83398151915255565b633ee5aeb560e01b60005260046000fd5b60ff600080516020615e6d8339815191525416613a1257565b63d93c066560e01b60005260046000fd5b15613a2a57565b6386fd6c3d60e01b60005260046000fd5b9081602091031261049b575160ff8116810361049b5790565b60405163313ce56760e01b815291602090839060049082906001600160a01b03165afa908115610ada57613a9092600092613af0575b50614ecd565b8015613a995790565b60405162461bcd60e51b815260206004820152602960248201527f546f6b656e446563696d616c73436f6e766572743a20616d6f756e74206973206044820152681d1bdbc81cdb585b1b60ba1b6064820152608490fd5b613b1391925060203d602011613b1a575b613b0b8183610d09565b810190613a3b565b9038613a8a565b503d613b01565b6040516323b872dd60e01b60208083019182526001600160a01b0394851660248401529490931660448201526064808201959095529384529260009190613b69608482610d09565b519082855af1156129f0576000513d613bb257506001600160a01b0381163b155b613b915750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b60011415613b8a565b906001600160a01b03821615613c9f57613bd36139f9565b600080516020615bed83398151915254613bf7906108bb906001600160a01b031681565b604051633196c08760e21b8152336004820152909290602081602481875afa8015610ada57613c82575b50604051633196c08760e21b81526001600160a01b038216600482015292602090849060249082905afa928315610ada576106a493613c63575b506000615745565b613c7b9060203d602011610ba857610b9b8183610d09565b5038613c5b565b613c9a9060203d602011610ba857610b9b8183610d09565b613c21565b63ec442f0560e01b600052600060045260246000fd5b6040516020810182815260208252613cce604083610d09565b6020825103613d3957613ce8906020835184010190612a88565b6001600160a01b038111908115613d2d575b50613d0c57506001600160a01b031690565b60405163046b337b60e51b8152908190613d299060048301610547565b0390fd5b61040091501038613cfa565b60405163046b337b60e51b815280613d298460048301610547565b60ff600080516020615dad8339815191525416613d6d57565b6106a4614390565b80613d7d5750565b600080808093335af13d15613dc7573d613d9681611fde565b90613da46040519283610d09565b8152600060203d92013e5b15613db657565b633c31275160e21b60005260046000fd5b613daf565b91906001600160a01b03831615613f0e576001600160a01b03811615613c9f57613df46139f9565b600080516020615bed83398151915254613e18906108bb906001600160a01b031681565b604051633196c08760e21b8152336004820152909390602081602481885afa8015610ada57613ef1575b50604051633196c08760e21b81526001600160a01b0382166004820152602081602481885afa8015610ada57613ed2575b50604051633196c08760e21b81526001600160a01b038316600482015293602090859060249082905afa938415610ada576106a494613eb3575b50615745565b613ecb9060203d602011610ba857610b9b8183610d09565b5038613ead565b613eea9060203d602011610ba857610b9b8183610d09565b5038613e73565b613f099060203d602011610ba857610b9b8183610d09565b613e42565b634b637e8f60e11b600052600060045260246000fd5b6001600160a01b031690308214613f6e578115159081613f5b575b50613f475750565b630f98d2bf60e01b60005260045260246000fd5b6001600160a01b03168214905038613f3f565b5063d751a98160e01b60005260045260246000fd5b6000600080516020615d4d833981519152546000905b808210613fa557505090565b9091613fe7613fb384615214565b905460039190911b1c6000818152600080516020615c2d83398151915260205260409020546001600160a01b031690614567565b8101809111612a83579160010190613f99565b611e6561401e6140086144d0565b600080516020615e2d8339815191525490614026565b610f2f614e4d565b6140308282614f1a565b91811561408e5781670de0b6b3a76400001115614087577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066993670de0b6b3a7640000910990828211900360ee1b910360121c170290565b6011614f2e565b50670de0b6b3a76400009250500490565b906140b2670de0b6b3a764000083614f1a565b919092831561412f578382111561412257670de0b6b3a7640000829109816000038216809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b6011600383150218614f2e565b5090611e659250612bee565b916141468284614f1a565b92909384156141bb57848311156141ae5790829109816000038216809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b6011600384150218614f2e565b505090611e659250612bee565b6141d3816000614f3f565b90816141dd575090565b60008052600080516020615bad833981519152602052614226906001600160a01b03167f615f0f9e84155bea8cc509fe18befeb1baf65611e38a6ba60964480fb29dfd4461586a565b5090565b6142348282614f3f565b918261423f57505090565b6000918252600080516020615bad8339815191526020526040909120614226916001600160a01b03169061586a565b6142788282614fed565b918261428357505090565b6000918252600080516020615bad8339815191526020526040909120614226916001600160a01b031690615910565b906001600160a01b03821615613f0e576142ca6139f9565b600080516020615bed833981519152546142ee906108bb906001600160a01b031681565b604051633196c08760e21b8152336004820152909290602081602481875afa8015610ada5761435a575b50604051633196c08760e21b81526001600160a01b038216600482015292602090849060249082905afa908115610ada576106a493600092613eb35750615745565b6143729060203d602011610ba857610b9b8183610d09565b614318565b81810392916000138015828513169184121617612a8357565b600080516020615ccd8339815191525490600080516020615b6d83398151915254916143ba613f83565b906143d6600080516020615d2d83398151915254610f2f613ffa565b93828511613994577fdcef780e0b1062c780ef612f32c8f5301583a0630cacf576f247c0f0a9e2fbb293946128e59184600080516020615ccd8339815191525581600080516020615b6d8339815191525561447061445e600080516020615e8d8339815191525461445861444989615092565b61445289615092565b90614377565b906150b7565b600080516020615e8d83398151915255565b6144ad61449b600080516020615c6d8339815191525461445861449286615092565b61445286615092565b600080516020615c6d83398151915255565b604051948594859094939260609260808301968352602083015260408201520152565b6000600080516020615d4d833981519152546000905b8082106144f257505090565b90916144fd83615214565b90549060031b1c80600052600080516020615d6d8339815191526020526040600020549081670de0b6b3a76400000291670de0b6b3a7640000830403612a8357676765c793fa10079d601b1b614554920490612e60565b8101809111612a835791600101906144e6565b906001600160a01b0316156145a2578061459c611e6592600052600080516020615e0d83398151915260205260406000205490565b90612e60565b50600090565b604d8111612a8357600a0a90565b60405163313ce56760e01b81529091602090829060049082906001600160a01b03165afa8015610ada5760ff91600091614626575b5016906012821461462157601282106146125761361161460d611e6593612b85565b6145a8565b612c8161460d611e6593612b77565b905090565b61463f915060203d602011613b1a57613b0b8183610d09565b386145eb565b61464d613f83565b90600080516020615b6d83398151915254614674600080516020615d2d8339815191525490565b9261467d6144d0565b600080516020615d8d8339815191525460ff169081614acf575b8515614a81578115614a61576146ac83615296565b955b838711614a4657816146c36146c8928961409f565b6152db565b916146df83600080516020615c8d83398151915255565b15614a03576146fa906146f0612dbb565b929091888361535e565b908051916000805b8481106149c9575b5015614823575b5050505061471d613f83565b9283861161480857907f012426c351bb738d75aead44c3641047561a6d47321f2c7e04b480667477af7794956128e59261476386600080516020615ccd83398151915255565b61477982600080516020615b6d83398151915255565b600080516020615e8d8339815191525486116147ed575b600080516020615c6d8339815191525482116147d2575b604051958695869192608093969594919660a084019784526020840152604083015260608201520152565b6147e882600080516020615c6d83398151915255565b6147a7565b61480386600080516020615e8d83398151915255565b614790565b63161ca8f560e31b6000526004869052602484905260446000fd5b60005b8381106148335750614711565b61487e61486d6148438386612a12565b5161484e8489612a12565b50600052600080516020615e0d83398151915260205260406000205490565b6148778385612a12565b5190612b94565b9081156149c05761488f8185612a12565b51916001600160a01b036148a66115d3848a612a12565b166040519363313ce56760e01b8552602085600481855afa948515610ada576001956148db916000916149a2575b5084614ecd565b801561499957600080516020615b4d833981519152547f175cb85b6e8fb1fca0c4e2d6b724596056919c2d4034c1f9fac1d1d8e0e4e64791906149469082906001600160a01b0316600080516020615ced8339815191525460081c6001600160a01b03169087613b21565b61494f83612a43565b61495a868254612b94565b9055600080516020615ced8339815191525460408051968752602087019290925260081c60a088901b889003166001600160a01b031694a45b01614826565b50505050614993565b6149ba915060203d8111613b1a57613b0b8183610d09565b386148d4565b60019150614993565b6149e16149d68286612a12565b5161484e8389612a12565b6149eb8285612a12565b51116149f957600101614702565b505060013861470a565b5050600080516020615ccd833981519152555090614a2d81600080516020615b6d83398151915255565b600080516020615c6d83398151915254811161449b5750565b63161ca8f560e31b6000526004879052602484905260446000fd5b614a7b600080516020615ccd833981519152548486615261565b956146ae565b50509050614ab8919250614aa181600080516020615ccd83398151915255565b61445e6000600080516020615b6d83398151915255565b6106a46000600080516020615c6d83398151915255565b600080516020615e8d8339815191525483119150614697565b614af06153ff565b614af86153ff565b6001600080516020615ead83398151915255565b35611e6581610686565b929190828103614c2557614b2983610d2f565b614b366040519182610d09565b838152602081018460051b84019036821161049b5784905b828210614c0b57505050614b619061561a565b60005b818110614b72575050505050565b80614bbe614b8b614b8660019488886133a7565b614b0c565b614b9f614b9984878b6133a7565b35612a26565b80546001600160a01b0319166001600160a01b03909216919091179055565b614bc98184886133a7565b35828060a01b03614bde614b868489896133a7565b16907f2c5101be4b11662e08f0e02544de444e4120439d1cd59f15359de94756a836bf600080a301614b64565b602080918335614c1a81610686565b815201910190614b4e565b634ec4810560e11b60005260046000fd5b9190600080516020615d4d8339815191525460005b818110614d1f575050838103614c255760005b818110614c725750505050506106a46156bd565b614c7d8186856133a7565b3515614cfd5780614ca7614c9460019385886133a7565b35614ca08389886133a7565b3590615ae6565b50614cb38184876133a7565b357f63295dce6ffdb7593fadb4c5c312e50fc826f065782caf4d80dbd70f5c56718f614cf4614ce3848a896133a7565b604051903581529081906020820190565b0390a201614c5e565b614d0b9061109992856133a7565b6312836e2960e11b60005235600452602490565b600190614d33614d2d6151bd565b50615ab1565b5001614c4b565b9092808403614c255760005b848110614d54575050505050565b614d6f614d6b614d658388876133a7565b35615b1a565b1590565b614e2b5780614db7610af7614d8760019489886133a7565b356000527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538707602052604060002090565b614dd6614dc8614b8684878a6133a7565b614b9f614d87858b8a6133a7565b614de18288876133a7565b35838060a01b03614df6614b8685888b6133a7565b1691848060a01b0316907fea9781e09546172aa405cb90d857735f1f5eebd53010d5f8cf91bd54e07e9e8f600080a401614d46565b614e396110999186856133a7565b63b6a8daab60e01b60005235600452602490565b600080516020615c8d8339815191525480611e655750670de0b6b3a764000090565b6001600160a01b03811691908215610c9a576001600160a01b038216938415610c845780614ec37f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92594610c22602095612d10565b55604051908152a3565b9060ff1690601282146146215760128210614efa576011198201918211612a8357612c81611e65926145a8565b9060120360128111612a8357614f0f906145a8565b908115612bf8570490565b906000198183099102908180821091030391565b634e487b716000526020526024601cfd5b6000818152600080516020615e4d833981519152602090815260408083206001600160a01b038616845290915290205460ff16614fe6576000818152600080516020615e4d833981519152602090815260408083206001600160a01b03861684529091529020805460ff1916600117905533916001600160a01b0316907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d600080a4600190565b5050600090565b6000818152600080516020615e4d833981519152602090815260408083206001600160a01b038616845290915290205460ff1615614fe6576000818152600080516020615e4d833981519152602090815260408083206001600160a01b03861684529091529020805460ff1916905533916001600160a01b0316907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b600080a4600190565b6001600160ff1b0381116150a35790565b63123baf0360e11b60005260045260246000fd5b9060008112156150ec57600160ff1b8114612a83576150d8906000036159cb565b81811015614fe6578103908111612a835790565b6150f5906159cb565b8101809111612a835790565b80600052600080516020615d6d8339815191526020526040600020549081158061512e575b61226d575090565b5060008181527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538709602052604090205415615126565b600080516020615d4d83398151915254811015611b10577f5c5fa22f08a36a7be50a2f0adcf2b13a5f19458fea36310124e841b505b2c7de01546000818152600080516020615d6d83398151915260205260409020549091565b600080516020615d4d8339815191525415611b10577f5c5fa22f08a36a7be50a2f0adcf2b13a5f19458fea36310124e841b505b2c7de546000818152600080516020615d6d83398151915260205260409020549091565b600080516020615d4d83398151915254811015611b1057600080516020615d4d83398151915260005260206000200190600090565b8054821015611b105760005260206000200190600090565b919081811015615280578103908111612a83578103908111612a835790565b908103908111612a83578101809111612a835790565b600080516020615e8d8339815191525490600080516020615c6d8339815191525491600080516020615cad83398151915254908203918211612a83576150f5916159ea565b9081158015615356575b801561533f575b615314579061530e611e6592600080516020615e2d8339815191525490614026565b9061409f565b600080516020615e2d8339815191525491631cbba81760e21b60005260045260245260445260646000fd5b50600080516020615e2d83398151915254156152ec565b5080156152e5565b929180156153ee5761536f91615a13565b825161537a81612bfd565b9360005b82811061538b5750505050565b6153958183612a12565b5180600052600080516020615d6d833981519152602052604060002054908115806153de575b61226d5750906153cd600192866159ea565b6153d78289612a12565b520161537e565b506153e881615b1a565b156153bb565b63656b5b4960e01b60005260046000fd5b60ff600080516020615ecd8339815191525460401c161561541c57565b631afcd79f60e31b60005260046000fd5b916154479183549060031b91821b91600019901b19161790565b9055565b601f8111615457575050565b600080516020615c0d8339815191526000526020600020906020601f840160051c830193106154a1575b601f0160051c01905b818110615495575050565b6000815560010161548a565b9091508190615481565b601f82116154b857505050565b6000526020600020906020601f840160051c830193106154f3575b601f0160051c01905b8181106154e7575050565b600081556001016154dc565b90915081906154d3565b9081516001600160401b038111610d2a5761553e8161552a600080516020615d0d833981519152546128fc565b600080516020615d0d8339815191526154ab565b602092601f82116001146155815761556f929382916000926132e05750508160011b916000199060031b1c19161790565b600080516020615d0d83398151915255565b600080516020615d0d833981519152600052601f198216937f46a2803e59a4de4e7a4c574b1243f25977ac4c77d5a1a4a609b5394cebb4a2aa9160005b86811061560257508360019596106155e9575b505050811b01600080516020615d0d83398151915255565b015160001960f88460031b161c191690553880806155d1565b919260206001819286850151815501940192016155be565b80519060018211615629575050565b909161563482615a47565b6000198301928311926000845b612a8357818110156156b6576001600160a01b0361565f8286612a12565b511660018201808311612a83576108bb6115d361567c9288612a12565b1461568a5760010184615641565b61569a6115d36110999286612a12565b63332c860960e21b6000526001600160a01b0316600452602490565b5050915050565b6000600080516020615d4d833981519152546000905b808210615705575050676765c793fa10079d601b1b81036156f15750565b630752747760e21b60005260045260246000fd5b909161571083615214565b90549060031b1c600052600080516020615d6d8339815191526020526040600020548101809111612a835791600101906156d3565b90916001600160a01b03821691826157fc57506157e3816157ab6157997fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef94600080516020615d2d83398151915254612a76565b600080516020615d2d83398151915255565b6001600160a01b03851694856157e8575061099581600080516020615d2d8339815191525403600080516020615d2d83398151915255565b0390a3565b6157f190612d49565b818154019055610995565b61580581612d49565b5482811061584557916157e39161583f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef950391612d49565b556157ab565b63391434e360e21b6000526001600160a01b0390911660045260245260445260646000fd5b6000828152600182016020526040902054614fe657805490600160401b821015610d2a57826158ba6158a3846001809601855584615249565b819391549060031b91821b91600019901b19161790565b905580549260005201602052604060002055600190565b805480156158fa5760001901906158e88282615249565b8154906000199060031b1b1916905555565b634e487b7160e01b600052603160045260246000fd5b60018101918060005282602052604060002054928315156000146159c2576000198401848111612a83578354600019810194908511612a83576000958583615973976159649503615979575b5050506158d1565b90600052602052604060002090565b55600190565b6159a96159a39161599a6159906159b99588615249565b90549060031b1c90565b92839187615249565b9061542d565b8590600052602052604060002090565b5538808061595c565b50505050600090565b600081126159d65790565b635467221960e11b60005260045260246000fd5b90676765c793fa10079d601b1b90615a0382828561413b565b920915158101809111612a835790565b90615a2781670de0b6b3a76400008461413b565b918115612bf857670de0b6b3a7640000900915158101809111612a835790565b805190600081528160051b81019260208201935b6020850191818311615aaa57825195805187811115615a9d575b6020820152601f19018051878111615a7557506020909691949295939601525b919092615a5b565b5050929093919450615a95565b9450505052565b611e659080600052600080516020615d6d83398151915260205260006040812055600080516020615d4d833981519152615910565b611e659181600052600080516020615d6d833981519152602052604060002055600080516020615d4d83398151915261586a565b6000527f965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870960205260406000205415159056fe965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538700965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538712965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870ec1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e82371705932000965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538703965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870252c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace03965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538706965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538705965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538718965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538713965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538715965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538711965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0452c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538708965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870a965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538716965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538714965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538710965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538704965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a538719965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870d02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a5387179b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00965f35edc7af78459f3800f4cb8942d0d3db8adc82a47391c1689f9a3a53870b","name":"FUSDLP","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":false,"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/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     * @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 1e27 for 100%)\n     */\n    error InvalidTotalRatio(uint256 totalRatio);\n\n    error InvalidLpShareRatio(uint256 ratio);\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 ReserveAddressDuplicate(address assetAddress);\n\n    error BelowMinimumCombinationAmount(uint256 amount);\n\n    error FeeRateTooHigh();\n\n    error RatioIsZero(bytes32 assetKey);\n\n    error ReserveAmountTooSmall(bytes32 assetKey);\n\n    error ZeroAddress();\n\n    error ZeroShares();\n\n    error RevenueRecipientCannotBeReserveTreasury(address account);\n\n    error RevenueRecipientCannotBeSelf(address account);\n\n    error RevenueReserveDeficit(bytes32 assetKey, uint256 requiredAmount, uint256 treasuryAmount);\n\n    error NewExchangeRateIsZero();\n\n    error InitialLpValueExceedsReserveValue(uint256 initialLpValue, uint256 initialReserveValue);\n\n    error SyncedLpValueExceedsReserveValue(uint256 newLpValue, uint256 currentReserveValue);\n\n    error BaselineLpValueExceedsReserveValue(uint256 newLpValue, uint256 newReserveValue);\n\n    error ReserveValueDropExceedsLpValue(uint256 reserveDrop, uint256 oldLpValue);\n\n    error InvalidRevenueAdjustmentInputs(\n        uint256 effectiveLpPrice, uint256 oneCombinationValue, uint256 adjustmentFactor\n    );\n\n    error RequiredReserveExchangeRateIsZero();\n\n    error InvalidAdjustmentFactor();\n\n    error RevenueSyncAlreadyInitialized();\n\n    error RevenueSyncNotInitialized();\n\n    error RevenueSyncDisabled();\n\n    error SyncRevenueCallerIsNotValid(address caller);\n\n    error ReserveTreasuryAmountBelowTrackedAmount(bytes32 assetKey, uint256 trackedAmount, uint256 treasuryAmount);\n\n    error DepositRedeemDisabled();\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 (1e27 = 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    event RevenueSyncInitialized(\n        address indexed revenueRecipient,\n        address indexed revenueSyncCaller,\n        uint256 initialReserveValue,\n        uint256 initialLpValue\n    );\n\n    event RevenueSynced(\n        uint256 oldReserveValue,\n        uint256 newReserveValue,\n        uint256 oldLpValue,\n        uint256 newLpValue,\n        uint256 revenueAdjustmentFactor\n    );\n\n    event RevenueTransferred(\n        bytes32 indexed assetKey, address indexed asset, address indexed recipient, uint256 amount18, uint256 amountRaw\n    );\n\n    event RevenueRecipientUpdated(address indexed oldRecipient, address indexed newRecipient);\n\n    event RevenueSyncCallerUpdated(address indexed oldCaller, address indexed newCaller);\n\n    event RevenueLpShareRatioUpdated(uint256 oldRatio, uint256 newRatio);\n\n    event RevenueSyncEnabledUpdated(bool oldEnabled, bool newEnabled);\n\n    event RevenueBaselineRefreshed(\n        uint256 oldReserveValue, uint256 newReserveValue, uint256 oldLpValue, uint256 newLpValue\n    );\n\n    event ReserveBalanceSynced(bytes32 indexed assetKey, uint256 oldTrackedAmount, uint256 newTrackedAmount);\n\n    event RatioPrecisionMigrated(uint256 oldBase, uint256 newBase);\n    event DepositRedeemStatusUpdated(bool oldStatus, bool newStatus);\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    function resetRevenueBaseline() external;\n\n    function syncReserve(bytes32 assetKey) 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        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 (1e27 = 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 (1e27 = 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 (1e27 = 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    function getTrackedReserveAmount(bytes32 assetKey) external view returns (uint256 amount);\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    function initializeRevenueSync(address revenueRecipient, address revenueSyncCaller, uint256 revenueLpShareRatio)\n        external;\n\n    function setRevenueRecipient(address newRecipient) external;\n\n    function setRevenueSyncCaller(address newCaller) external;\n\n    function setRevenueLpShareRatio(uint256 newRatio) external;\n\n    function setRevenueSyncEnabled(bool enabled) external;\n\n    function syncRevenue() external;\n\n    function syncRevenueAdjustmentFactor(uint256 factor) external;\n\n    function getRevenueAdjustmentFactor() external view returns (uint256);\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    /**\n     * @notice Set whether deposit and redeem operations are enabled.\n     * @dev Only callable by admin.\n     * @param enabled New deposit/redeem operation status.\n     */\n    function setDepositRedeemEnabled(bool enabled) external;\n\n    /**\n     * @notice Returns whether deposit and redeem operations are enabled.\n     * @return True if deposit and redeem operations are enabled.\n     */\n    function depositRedeemEnabled() 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 from18DecimalsWithoutRevert(uint256 amount, uint8 decimals) internal pure returns (uint256) {\n        if (decimals == 18) {\n            return amount;\n        }\n        if (decimals < 18) {\n            return amount / (10 ** (18 - uint256(decimals)));\n        }\n        return amount * (10 ** (uint256(decimals) - 18));\n    }\n\n    function to18Decimals(uint256 amount, address token) internal view returns (uint256) {\n        uint8 decimals = IERC20Metadata(token).decimals();\n        if (decimals == 18) {\n            return amount;\n        }\n        if (decimals < 18) {\n            return amount * (10 ** (18 - uint256(decimals)));\n        }\n        return amount / (10 ** (uint256(decimals) - 18));\n    }\n\n    function from18Decimals(uint256 amount, address token) internal view returns (uint256) {\n        uint8 decimals = IERC20Metadata(token).decimals();\n        uint256 amountWithTokenDecimals = from18DecimalsWithoutRevert(amount, 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/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":"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {ContextUpgradeable} from \"../../utils/ContextUpgradeable.sol\";\nimport {IERC20Errors} from \"@openzeppelin/contracts/interfaces/draft-IERC6093.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC-20\n * applications.\n */\nabstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors {\n    /// @custom:storage-location erc7201:openzeppelin.storage.ERC20\n    struct ERC20Storage {\n        mapping(address account => uint256) _balances;\n\n        mapping(address account => mapping(address spender => uint256)) _allowances;\n\n        uint256 _totalSupply;\n\n        string _name;\n        string _symbol;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ERC20\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;\n\n    function _getERC20Storage() private pure returns (ERC20Storage storage $) {\n        assembly {\n            $.slot := ERC20StorageLocation\n        }\n    }\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * Both values are immutable: they can only be set once during construction.\n     */\n    function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {\n        __ERC20_init_unchained(name_, symbol_);\n    }\n\n    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n        ERC20Storage storage $ = _getERC20Storage();\n        $._name = name_;\n        $._symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual returns (string memory) {\n        ERC20Storage storage $ = _getERC20Storage();\n        return $._name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual returns (string memory) {\n        ERC20Storage storage $ = _getERC20Storage();\n        return $._symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual returns (uint8) {\n        return 18;\n    }\n\n    /// @inheritdoc IERC20\n    function totalSupply() public view virtual returns (uint256) {\n        ERC20Storage storage $ = _getERC20Storage();\n        return $._totalSupply;\n    }\n\n    /// @inheritdoc IERC20\n    function balanceOf(address account) public view virtual returns (uint256) {\n        ERC20Storage storage $ = _getERC20Storage();\n        return $._balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `value`.\n     */\n    function transfer(address to, uint256 value) public virtual returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, value);\n        return true;\n    }\n\n    /// @inheritdoc IERC20\n    function allowance(address owner, address spender) public view virtual returns (uint256) {\n        ERC20Storage storage $ = _getERC20Storage();\n        return $._allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 value) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, value);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Skips emitting an {Approval} event indicating an allowance update. This is not\n     * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `value`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `value`.\n     */\n    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, value);\n        _transfer(from, to, value);\n        return true;\n    }\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead.\n     */\n    function _transfer(address from, address to, uint256 value) internal {\n        if (from == address(0)) {\n            revert ERC20InvalidSender(address(0));\n        }\n        if (to == address(0)) {\n            revert ERC20InvalidReceiver(address(0));\n        }\n        _update(from, to, value);\n    }\n\n    /**\n     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`\n     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding\n     * this function.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _update(address from, address to, uint256 value) internal virtual {\n        ERC20Storage storage $ = _getERC20Storage();\n        if (from == address(0)) {\n            // Overflow check required: The rest of the code assumes that totalSupply never overflows\n            $._totalSupply += value;\n        } else {\n            uint256 fromBalance = $._balances[from];\n            if (fromBalance < value) {\n                revert ERC20InsufficientBalance(from, fromBalance, value);\n            }\n            unchecked {\n                // Overflow not possible: value <= fromBalance <= totalSupply.\n                $._balances[from] = fromBalance - value;\n            }\n        }\n\n        if (to == address(0)) {\n            unchecked {\n                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.\n                $._totalSupply -= value;\n            }\n        } else {\n            unchecked {\n                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.\n                $._balances[to] += value;\n            }\n        }\n\n        emit Transfer(from, to, value);\n    }\n\n    /**\n     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).\n     * Relies on the `_update` mechanism\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead.\n     */\n    function _mint(address account, uint256 value) internal {\n        if (account == address(0)) {\n            revert ERC20InvalidReceiver(address(0));\n        }\n        _update(address(0), account, value);\n    }\n\n    /**\n     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.\n     * Relies on the `_update` mechanism.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead\n     */\n    function _burn(address account, uint256 value) internal {\n        if (account == address(0)) {\n            revert ERC20InvalidSender(address(0));\n        }\n        _update(account, address(0), value);\n    }\n\n    /**\n     * @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     *\n     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.\n     */\n    function _approve(address owner, address spender, uint256 value) internal {\n        _approve(owner, spender, value, true);\n    }\n\n    /**\n     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.\n     *\n     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by\n     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any\n     * `Approval` event during `transferFrom` operations.\n     *\n     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to\n     * true using the following override:\n     *\n     * ```solidity\n     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {\n     *     super._approve(owner, spender, value, true);\n     * }\n     * ```\n     *\n     * Requirements are the same as {_approve}.\n     */\n    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {\n        ERC20Storage storage $ = _getERC20Storage();\n        if (owner == address(0)) {\n            revert ERC20InvalidApprover(address(0));\n        }\n        if (spender == address(0)) {\n            revert ERC20InvalidSpender(address(0));\n        }\n        $._allowances[owner][spender] = value;\n        if (emitEvent) {\n            emit Approval(owner, spender, value);\n        }\n    }\n\n    /**\n     * @dev Updates `owner`'s allowance for `spender` based on spent `value`.\n     *\n     * Does not update the allowance value in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Does not emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance < type(uint256).max) {\n            if (currentAllowance < value) {\n                revert ERC20InsufficientAllowance(spender, currentAllowance, value);\n            }\n            unchecked {\n                _approve(owner, spender, currentAllowance - value, false);\n            }\n        }\n    }\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     * @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":"contracts/interfaces/IBaseReservePriceFeed.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\n/**\n * @title IBaseReservePriceFeed\n * @notice Base reserve price feed interface for obtaining reserve asset price and value information.\n * @dev Defines the basic functions for getting reserve asset price and value.\n */\ninterface IBaseReservePriceFeed {\n    /**\n     * @notice Gets the reserve asset address.\n     * @return The contract address of the reserve asset.\n     */\n    function getReserve() external view returns (address);\n\n    /**\n     * @notice Gets the exchange rate between the reserve asset and USD.\n     * @return The exchange rate of the reserve asset to USD, expressed with 18 decimal precision.\n     */\n    function getReserveExchangeRate() external view returns (uint256);\n\n    function getReservePoR() external view returns (uint256);\n\n    /**\n     * @notice Calculates the USD value of a specified amount of reserve assets.\n     * @param amount The amount of the reserve asset.\n     * @return The equivalent USD amount, expressed with 18 decimal precision.\n     */\n    function getReserveValueInUSD(uint256 amount) external view returns (uint256);\n\n    /**\n     * @notice Calculates the USD value of the reserve assets held by a specified account.\n     * @param account The address of the account to query.\n     * @return The USD value of the reserve assets held by the account, expressed with 18 decimal precision.\n     */\n    function getReserveValueInUSDOf(address account) external view returns (uint256);\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/interfaces/draft-IERC6093.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC6093.sol)\npragma solidity >=0.8.4;\n\n/**\n * @dev Standard ERC-20 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.\n */\ninterface IERC20Errors {\n    /**\n     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     * @param balance Current balance for the interacting account.\n     * @param needed Minimum amount required to perform a transfer.\n     */\n    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);\n\n    /**\n     * @dev Indicates a failure with the token `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     */\n    error ERC20InvalidSender(address sender);\n\n    /**\n     * @dev Indicates a failure with the token `receiver`. Used in transfers.\n     * @param receiver Address to which tokens are being transferred.\n     */\n    error ERC20InvalidReceiver(address receiver);\n\n    /**\n     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.\n     * @param spender Address that may be allowed to operate on tokens without being their owner.\n     * @param allowance Amount of tokens a `spender` is allowed to operate with.\n     * @param needed Minimum amount required to perform a transfer.\n     */\n    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);\n\n    /**\n     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n     * @param approver Address initiating an approval operation.\n     */\n    error ERC20InvalidApprover(address approver);\n\n    /**\n     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.\n     * @param spender Address that may be allowed to operate on tokens without being their owner.\n     */\n    error ERC20InvalidSpender(address spender);\n}\n\n/**\n * @dev Standard ERC-721 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.\n */\ninterface IERC721Errors {\n    /**\n     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.\n     * Used in balance queries.\n     * @param owner Address of the current owner of a token.\n     */\n    error ERC721InvalidOwner(address owner);\n\n    /**\n     * @dev Indicates a `tokenId` whose `owner` is the zero address.\n     * @param tokenId Identifier number of a token.\n     */\n    error ERC721NonexistentToken(uint256 tokenId);\n\n    /**\n     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     * @param tokenId Identifier number of a token.\n     * @param owner Address of the current owner of a token.\n     */\n    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);\n\n    /**\n     * @dev Indicates a failure with the token `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     */\n    error ERC721InvalidSender(address sender);\n\n    /**\n     * @dev Indicates a failure with the token `receiver`. Used in transfers.\n     * @param receiver Address to which tokens are being transferred.\n     */\n    error ERC721InvalidReceiver(address receiver);\n\n    /**\n     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     * @param tokenId Identifier number of a token.\n     */\n    error ERC721InsufficientApproval(address operator, uint256 tokenId);\n\n    /**\n     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n     * @param approver Address initiating an approval operation.\n     */\n    error ERC721InvalidApprover(address approver);\n\n    /**\n     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     */\n    error ERC721InvalidOperator(address operator);\n}\n\n/**\n * @dev Standard ERC-1155 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.\n */\ninterface IERC1155Errors {\n    /**\n     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     * @param balance Current balance for the interacting account.\n     * @param needed Minimum amount required to perform a transfer.\n     * @param tokenId Identifier number of a token.\n     */\n    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);\n\n    /**\n     * @dev Indicates a failure with the token `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     */\n    error ERC1155InvalidSender(address sender);\n\n    /**\n     * @dev Indicates a failure with the token `receiver`. Used in transfers.\n     * @param receiver Address to which tokens are being transferred.\n     */\n    error ERC1155InvalidReceiver(address receiver);\n\n    /**\n     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     * @param owner Address of the current owner of a token.\n     */\n    error ERC1155MissingApprovalForAll(address operator, address owner);\n\n    /**\n     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n     * @param approver Address initiating an approval operation.\n     */\n    error ERC1155InvalidApprover(address approver);\n\n    /**\n     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     */\n    error ERC1155InvalidOperator(address operator);\n\n    /**\n     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.\n     * Used in batch transfers.\n     * @param idsLength Length of the array of token identifiers\n     * @param valuesLength Length of the array of token amounts\n     */\n    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);\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":"contracts/utils/LibArray.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nlibrary LibArray {\n    function insertionSort(uint256[] memory a) internal pure {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let n := mload(a) // Length of `a`.\n            mstore(a, 0) // For insertion sort's inner loop to terminate.\n            let h := add(a, shl(5, n)) // High slot.\n            let w := not(0x1f)\n            for { let i := add(a, 0x20) } 1 {} {\n                i := add(i, 0x20)\n                if gt(i, h) { break }\n                let k := mload(i) // Key.\n                let j := add(i, w) // The slot before the current slot.\n                let v := mload(j) // The value of `j`.\n                if iszero(gt(v, k)) { continue }\n                for {} 1 {} {\n                    mstore(add(j, 0x20), v)\n                    j := add(j, w) // `sub(j, 0x20)`.\n                    v := mload(j)\n                    if iszero(gt(v, k)) { break }\n                }\n                mstore(add(j, 0x20), k)\n            }\n            mstore(a, n) // Restore the length of `a`.\n        }\n    }\n\n    function insertionSort(bytes32[] memory a) internal pure {\n        insertionSort(_toUints(a));\n    }\n\n    /// @dev Sorts the array in-place with insertion sort.\n    function insertionSort(address[] memory a) internal pure {\n        insertionSort(_toUints(a));\n    }\n\n    /// @dev Reinterpret cast to an uint256 array.\n    function _toUints(bytes32[] memory a) private pure returns (uint256[] memory casted) {\n        assembly {\n            casted := a\n        }\n    }\n\n    /// @dev Reinterpret cast to an uint256 array.\n    function _toUints(address[] memory a) private pure returns (uint256[] memory casted) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // As any address written to memory will have the upper 96 bits\n            // of the word zeroized (as per Solidity spec), we can directly\n            // compare these addresses as if they are whole uint256 words.\n            casted := a\n        }\n    }\n}\n"},{"file_path":"contracts/fusd-lp/FUSDLPRevenueMath.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nlibrary FUSDLPRevenueMath {\n    using Math for uint256;\n\n    function getNewLpValue(\n        uint256 currentReserveValue,\n        uint256 reserveHighWatermark,\n        uint256 lpHighWatermark,\n        uint256 lpShareRatio,\n        uint256 ratioBase\n    ) internal pure returns (uint256) {\n        // Only net value above the high watermark is treated as new profit.\n        uint256 profit = currentReserveValue - reserveHighWatermark;\n        return lpHighWatermark + profit.mulDiv(lpShareRatio, ratioBase, Math.Rounding.Ceil);\n    }\n\n    function getNewLpValueWithoutRevenueShare(\n        uint256 oldLpValue,\n        uint256 currentReserveValue,\n        uint256 lastSyncedReserveValue\n    ) internal pure returns (uint256) {\n        if (currentReserveValue >= lastSyncedReserveValue) {\n            return oldLpValue + (currentReserveValue - lastSyncedReserveValue);\n        }\n        return oldLpValue - (lastSyncedReserveValue - currentReserveValue);\n    }\n\n    function deriveRevenueAdjustmentFactor(\n        uint256 effectiveLpPrice,\n        uint256 oneCombinationValue,\n        uint256 adjustmentFactor\n    ) internal pure returns (uint256) {\n        // Reserve value * adjustmentFactor (continuity factor after reserve adjustment)\n        uint256 denominator = oneCombinationValue.mulDiv(adjustmentFactor, 1e18);\n        // effectiveLpPrice = oneCombinationValue * adjustmentFactor * revenueAdjustmentFactor)\n        return effectiveLpPrice.mulDiv(1e18, denominator);\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/structs/EnumerableMap.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/structs/EnumerableMap.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.\n\npragma solidity ^0.8.20;\n\nimport {EnumerableSet} from \"./EnumerableSet.sol\";\n\n/**\n * @dev Library for managing an enumerable variant of Solidity's\n * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]\n * type.\n *\n * Maps have the following properties:\n *\n * - Entries are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Entries are enumerated in O(n). No guarantees are made on the ordering.\n * - Map can be cleared (all entries removed) in O(n).\n *\n * ```solidity\n * contract Example {\n *     // Add the library methods\n *     using EnumerableMap for EnumerableMap.UintToAddressMap;\n *\n *     // Declare a set state variable\n *     EnumerableMap.UintToAddressMap private myMap;\n * }\n * ```\n *\n * The following map types are supported:\n *\n * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0\n * - `address -> uint256` (`AddressToUintMap`) since v4.6.0\n * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0\n * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0\n * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0\n * - `uint256 -> bytes32` (`UintToBytes32Map`) since v5.1.0\n * - `address -> address` (`AddressToAddressMap`) since v5.1.0\n * - `address -> bytes32` (`AddressToBytes32Map`) since v5.1.0\n * - `bytes32 -> address` (`Bytes32ToAddressMap`) since v5.1.0\n * - `bytes -> bytes` (`BytesToBytesMap`) 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 EnumerableMap, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableMap.\n * ====\n */\nlibrary EnumerableMap {\n    using EnumerableSet for *;\n\n    // To implement this library for multiple types with as little code repetition as possible, we write it in\n    // terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions,\n    // and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map.\n    // This means that we can only create new EnumerableMaps for types that fit in bytes32.\n\n    /**\n     * @dev Query for a nonexistent map key.\n     */\n    error EnumerableMapNonexistentKey(bytes32 key);\n\n    struct Bytes32ToBytes32Map {\n        // Storage of keys\n        EnumerableSet.Bytes32Set _keys;\n        mapping(bytes32 key => bytes32) _values;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {\n        map._values[key] = value;\n        return map._keys.add(key);\n    }\n\n    /**\n     * @dev Removes a key-value pair from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {\n        delete map._values[key];\n        return map._keys.remove(key);\n    }\n\n    /**\n     * @dev Removes all the entries from a map. 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 map grows to the point where clearing it consumes too much gas to fit in a block.\n     */\n    function clear(Bytes32ToBytes32Map storage map) internal {\n        uint256 len = length(map);\n        for (uint256 i = 0; i < len; ++i) {\n            delete map._values[map._keys.at(i)];\n        }\n        map._keys.clear();\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {\n        return map._keys.contains(key);\n    }\n\n    /**\n     * @dev Returns the number of key-value pairs in the map. O(1).\n     */\n    function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {\n        return map._keys.length();\n    }\n\n    /**\n     * @dev Returns the key-value pair stored at position `index` in the map. O(1).\n     *\n     * Note that there are no guarantees on the ordering of entries inside the\n     * array, and it may change when more entries are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32 key, bytes32 value) {\n        bytes32 atKey = map._keys.at(index);\n        return (atKey, map._values[atKey]);\n    }\n\n    /**\n     * @dev Tries to return the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool exists, bytes32 value) {\n        bytes32 val = map._values[key];\n        if (val == bytes32(0)) {\n            return (contains(map, key), bytes32(0));\n        } else {\n            return (true, val);\n        }\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {\n        bytes32 value = map._values[key];\n        if (value == 0 && !contains(map, key)) {\n            revert EnumerableMapNonexistentKey(key);\n        }\n        return value;\n    }\n\n    /**\n     * @dev Returns an array containing all the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {\n        return map._keys.values();\n    }\n\n    /**\n     * @dev Returns an array containing a slice of the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(\n        Bytes32ToBytes32Map storage map,\n        uint256 start,\n        uint256 end\n    ) internal view returns (bytes32[] memory) {\n        return map._keys.values(start, end);\n    }\n\n    // UintToUintMap\n\n    struct UintToUintMap {\n        Bytes32ToBytes32Map _inner;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {\n        return set(map._inner, bytes32(key), bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {\n        return remove(map._inner, bytes32(key));\n    }\n\n    /**\n     * @dev Removes all the entries from a map. O(n).\n     *\n     * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that\n     * using it may render the function uncallable if the map grows to the point where clearing it consumes too much\n     * gas to fit in a block.\n     */\n    function clear(UintToUintMap storage map) internal {\n        clear(map._inner);\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {\n        return contains(map._inner, bytes32(key));\n    }\n\n    /**\n     * @dev Returns the number of elements in the map. O(1).\n     */\n    function length(UintToUintMap storage map) internal view returns (uint256) {\n        return length(map._inner);\n    }\n\n    /**\n     * @dev Returns the element stored at position `index` in the map. O(1).\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(UintToUintMap storage map, uint256 index) internal view returns (uint256 key, uint256 value) {\n        (bytes32 atKey, bytes32 val) = at(map._inner, index);\n        return (uint256(atKey), uint256(val));\n    }\n\n    /**\n     * @dev Tries to return the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool exists, uint256 value) {\n        (bool success, bytes32 val) = tryGet(map._inner, bytes32(key));\n        return (success, uint256(val));\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {\n        return uint256(get(map._inner, bytes32(key)));\n    }\n\n    /**\n     * @dev Returns an array containing all the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {\n        bytes32[] memory store = keys(map._inner);\n        uint256[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Returns an array containing a slice of the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(UintToUintMap storage map, uint256 start, uint256 end) internal view returns (uint256[] memory) {\n        bytes32[] memory store = keys(map._inner, start, end);\n        uint256[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintToAddressMap\n\n    struct UintToAddressMap {\n        Bytes32ToBytes32Map _inner;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {\n        return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {\n        return remove(map._inner, bytes32(key));\n    }\n\n    /**\n     * @dev Removes all the entries from a map. O(n).\n     *\n     * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that\n     * using it may render the function uncallable if the map grows to the point where clearing it consumes too much\n     * gas to fit in a block.\n     */\n    function clear(UintToAddressMap storage map) internal {\n        clear(map._inner);\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {\n        return contains(map._inner, bytes32(key));\n    }\n\n    /**\n     * @dev Returns the number of elements in the map. O(1).\n     */\n    function length(UintToAddressMap storage map) internal view returns (uint256) {\n        return length(map._inner);\n    }\n\n    /**\n     * @dev Returns the element stored at position `index` in the map. O(1).\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(UintToAddressMap storage map, uint256 index) internal view returns (uint256 key, address value) {\n        (bytes32 atKey, bytes32 val) = at(map._inner, index);\n        return (uint256(atKey), address(uint160(uint256(val))));\n    }\n\n    /**\n     * @dev Tries to return the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool exists, address value) {\n        (bool success, bytes32 val) = tryGet(map._inner, bytes32(key));\n        return (success, address(uint160(uint256(val))));\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {\n        return address(uint160(uint256(get(map._inner, bytes32(key)))));\n    }\n\n    /**\n     * @dev Returns an array containing all the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {\n        bytes32[] memory store = keys(map._inner);\n        uint256[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Returns an array containing a slice of the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(UintToAddressMap storage map, uint256 start, uint256 end) internal view returns (uint256[] memory) {\n        bytes32[] memory store = keys(map._inner, start, end);\n        uint256[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintToBytes32Map\n\n    struct UintToBytes32Map {\n        Bytes32ToBytes32Map _inner;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(UintToBytes32Map storage map, uint256 key, bytes32 value) internal returns (bool) {\n        return set(map._inner, bytes32(key), value);\n    }\n\n    /**\n     * @dev Removes a value from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(UintToBytes32Map storage map, uint256 key) internal returns (bool) {\n        return remove(map._inner, bytes32(key));\n    }\n\n    /**\n     * @dev Removes all the entries from a map. O(n).\n     *\n     * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that\n     * using it may render the function uncallable if the map grows to the point where clearing it consumes too much\n     * gas to fit in a block.\n     */\n    function clear(UintToBytes32Map storage map) internal {\n        clear(map._inner);\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(UintToBytes32Map storage map, uint256 key) internal view returns (bool) {\n        return contains(map._inner, bytes32(key));\n    }\n\n    /**\n     * @dev Returns the number of elements in the map. O(1).\n     */\n    function length(UintToBytes32Map storage map) internal view returns (uint256) {\n        return length(map._inner);\n    }\n\n    /**\n     * @dev Returns the element stored at position `index` in the map. O(1).\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(UintToBytes32Map storage map, uint256 index) internal view returns (uint256 key, bytes32 value) {\n        (bytes32 atKey, bytes32 val) = at(map._inner, index);\n        return (uint256(atKey), val);\n    }\n\n    /**\n     * @dev Tries to return the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(UintToBytes32Map storage map, uint256 key) internal view returns (bool exists, bytes32 value) {\n        (bool success, bytes32 val) = tryGet(map._inner, bytes32(key));\n        return (success, val);\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(UintToBytes32Map storage map, uint256 key) internal view returns (bytes32) {\n        return get(map._inner, bytes32(key));\n    }\n\n    /**\n     * @dev Returns an array containing all the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(UintToBytes32Map storage map) internal view returns (uint256[] memory) {\n        bytes32[] memory store = keys(map._inner);\n        uint256[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Returns an array containing a slice of the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(UintToBytes32Map storage map, uint256 start, uint256 end) internal view returns (uint256[] memory) {\n        bytes32[] memory store = keys(map._inner, start, end);\n        uint256[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    // AddressToUintMap\n\n    struct AddressToUintMap {\n        Bytes32ToBytes32Map _inner;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {\n        return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(AddressToUintMap storage map, address key) internal returns (bool) {\n        return remove(map._inner, bytes32(uint256(uint160(key))));\n    }\n\n    /**\n     * @dev Removes all the entries from a map. O(n).\n     *\n     * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that\n     * using it may render the function uncallable if the map grows to the point where clearing it consumes too much\n     * gas to fit in a block.\n     */\n    function clear(AddressToUintMap storage map) internal {\n        clear(map._inner);\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(AddressToUintMap storage map, address key) internal view returns (bool) {\n        return contains(map._inner, bytes32(uint256(uint160(key))));\n    }\n\n    /**\n     * @dev Returns the number of elements in the map. O(1).\n     */\n    function length(AddressToUintMap storage map) internal view returns (uint256) {\n        return length(map._inner);\n    }\n\n    /**\n     * @dev Returns the element stored at position `index` in the map. O(1).\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(AddressToUintMap storage map, uint256 index) internal view returns (address key, uint256 value) {\n        (bytes32 atKey, bytes32 val) = at(map._inner, index);\n        return (address(uint160(uint256(atKey))), uint256(val));\n    }\n\n    /**\n     * @dev Tries to return the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(AddressToUintMap storage map, address key) internal view returns (bool exists, uint256 value) {\n        (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));\n        return (success, uint256(val));\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(AddressToUintMap storage map, address key) internal view returns (uint256) {\n        return uint256(get(map._inner, bytes32(uint256(uint160(key)))));\n    }\n\n    /**\n     * @dev Returns an array containing all the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(AddressToUintMap storage map) internal view returns (address[] memory) {\n        bytes32[] memory store = keys(map._inner);\n        address[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Returns an array containing a slice of the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(AddressToUintMap storage map, uint256 start, uint256 end) internal view returns (address[] memory) {\n        bytes32[] memory store = keys(map._inner, start, end);\n        address[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    // AddressToAddressMap\n\n    struct AddressToAddressMap {\n        Bytes32ToBytes32Map _inner;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(AddressToAddressMap storage map, address key, address value) internal returns (bool) {\n        return set(map._inner, bytes32(uint256(uint160(key))), bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(AddressToAddressMap storage map, address key) internal returns (bool) {\n        return remove(map._inner, bytes32(uint256(uint160(key))));\n    }\n\n    /**\n     * @dev Removes all the entries from a map. O(n).\n     *\n     * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that\n     * using it may render the function uncallable if the map grows to the point where clearing it consumes too much\n     * gas to fit in a block.\n     */\n    function clear(AddressToAddressMap storage map) internal {\n        clear(map._inner);\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(AddressToAddressMap storage map, address key) internal view returns (bool) {\n        return contains(map._inner, bytes32(uint256(uint160(key))));\n    }\n\n    /**\n     * @dev Returns the number of elements in the map. O(1).\n     */\n    function length(AddressToAddressMap storage map) internal view returns (uint256) {\n        return length(map._inner);\n    }\n\n    /**\n     * @dev Returns the element stored at position `index` in the map. O(1).\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(AddressToAddressMap storage map, uint256 index) internal view returns (address key, address value) {\n        (bytes32 atKey, bytes32 val) = at(map._inner, index);\n        return (address(uint160(uint256(atKey))), address(uint160(uint256(val))));\n    }\n\n    /**\n     * @dev Tries to return the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(AddressToAddressMap storage map, address key) internal view returns (bool exists, address value) {\n        (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));\n        return (success, address(uint160(uint256(val))));\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(AddressToAddressMap storage map, address key) internal view returns (address) {\n        return address(uint160(uint256(get(map._inner, bytes32(uint256(uint160(key)))))));\n    }\n\n    /**\n     * @dev Returns an array containing all the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(AddressToAddressMap storage map) internal view returns (address[] memory) {\n        bytes32[] memory store = keys(map._inner);\n        address[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Returns an array containing a slice of the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(\n        AddressToAddressMap storage map,\n        uint256 start,\n        uint256 end\n    ) internal view returns (address[] memory) {\n        bytes32[] memory store = keys(map._inner, start, end);\n        address[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    // AddressToBytes32Map\n\n    struct AddressToBytes32Map {\n        Bytes32ToBytes32Map _inner;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(AddressToBytes32Map storage map, address key, bytes32 value) internal returns (bool) {\n        return set(map._inner, bytes32(uint256(uint160(key))), value);\n    }\n\n    /**\n     * @dev Removes a value from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(AddressToBytes32Map storage map, address key) internal returns (bool) {\n        return remove(map._inner, bytes32(uint256(uint160(key))));\n    }\n\n    /**\n     * @dev Removes all the entries from a map. O(n).\n     *\n     * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that\n     * using it may render the function uncallable if the map grows to the point where clearing it consumes too much\n     * gas to fit in a block.\n     */\n    function clear(AddressToBytes32Map storage map) internal {\n        clear(map._inner);\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(AddressToBytes32Map storage map, address key) internal view returns (bool) {\n        return contains(map._inner, bytes32(uint256(uint160(key))));\n    }\n\n    /**\n     * @dev Returns the number of elements in the map. O(1).\n     */\n    function length(AddressToBytes32Map storage map) internal view returns (uint256) {\n        return length(map._inner);\n    }\n\n    /**\n     * @dev Returns the element stored at position `index` in the map. O(1).\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(AddressToBytes32Map storage map, uint256 index) internal view returns (address key, bytes32 value) {\n        (bytes32 atKey, bytes32 val) = at(map._inner, index);\n        return (address(uint160(uint256(atKey))), val);\n    }\n\n    /**\n     * @dev Tries to return the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(AddressToBytes32Map storage map, address key) internal view returns (bool exists, bytes32 value) {\n        (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));\n        return (success, val);\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(AddressToBytes32Map storage map, address key) internal view returns (bytes32) {\n        return get(map._inner, bytes32(uint256(uint160(key))));\n    }\n\n    /**\n     * @dev Returns an array containing all the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(AddressToBytes32Map storage map) internal view returns (address[] memory) {\n        bytes32[] memory store = keys(map._inner);\n        address[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Returns an array containing a slice of the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(\n        AddressToBytes32Map storage map,\n        uint256 start,\n        uint256 end\n    ) internal view returns (address[] memory) {\n        bytes32[] memory store = keys(map._inner, start, end);\n        address[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    // Bytes32ToUintMap\n\n    struct Bytes32ToUintMap {\n        Bytes32ToBytes32Map _inner;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {\n        return set(map._inner, key, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {\n        return remove(map._inner, key);\n    }\n\n    /**\n     * @dev Removes all the entries from a map. O(n).\n     *\n     * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that\n     * using it may render the function uncallable if the map grows to the point where clearing it consumes too much\n     * gas to fit in a block.\n     */\n    function clear(Bytes32ToUintMap storage map) internal {\n        clear(map._inner);\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {\n        return contains(map._inner, key);\n    }\n\n    /**\n     * @dev Returns the number of elements in the map. O(1).\n     */\n    function length(Bytes32ToUintMap storage map) internal view returns (uint256) {\n        return length(map._inner);\n    }\n\n    /**\n     * @dev Returns the element stored at position `index` in the map. O(1).\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(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32 key, uint256 value) {\n        (bytes32 atKey, bytes32 val) = at(map._inner, index);\n        return (atKey, uint256(val));\n    }\n\n    /**\n     * @dev Tries to return the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool exists, uint256 value) {\n        (bool success, bytes32 val) = tryGet(map._inner, key);\n        return (success, uint256(val));\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {\n        return uint256(get(map._inner, key));\n    }\n\n    /**\n     * @dev Returns an array containing all the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = keys(map._inner);\n        bytes32[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Returns an array containing a slice of the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(Bytes32ToUintMap storage map, uint256 start, uint256 end) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = keys(map._inner, start, end);\n        bytes32[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    // Bytes32ToAddressMap\n\n    struct Bytes32ToAddressMap {\n        Bytes32ToBytes32Map _inner;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(Bytes32ToAddressMap storage map, bytes32 key, address value) internal returns (bool) {\n        return set(map._inner, key, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(Bytes32ToAddressMap storage map, bytes32 key) internal returns (bool) {\n        return remove(map._inner, key);\n    }\n\n    /**\n     * @dev Removes all the entries from a map. O(n).\n     *\n     * WARNING: This function has an unbounded cost that scales with map size. Developers should keep in mind that\n     * using it may render the function uncallable if the map grows to the point where clearing it consumes too much\n     * gas to fit in a block.\n     */\n    function clear(Bytes32ToAddressMap storage map) internal {\n        clear(map._inner);\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool) {\n        return contains(map._inner, key);\n    }\n\n    /**\n     * @dev Returns the number of elements in the map. O(1).\n     */\n    function length(Bytes32ToAddressMap storage map) internal view returns (uint256) {\n        return length(map._inner);\n    }\n\n    /**\n     * @dev Returns the element stored at position `index` in the map. O(1).\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(Bytes32ToAddressMap storage map, uint256 index) internal view returns (bytes32 key, address value) {\n        (bytes32 atKey, bytes32 val) = at(map._inner, index);\n        return (atKey, address(uint160(uint256(val))));\n    }\n\n    /**\n     * @dev Tries to return the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool exists, address value) {\n        (bool success, bytes32 val) = tryGet(map._inner, key);\n        return (success, address(uint160(uint256(val))));\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (address) {\n        return address(uint160(uint256(get(map._inner, key))));\n    }\n\n    /**\n     * @dev Returns an array containing all the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(Bytes32ToAddressMap storage map) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = keys(map._inner);\n        bytes32[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Returns an array containing a slice of the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(\n        Bytes32ToAddressMap storage map,\n        uint256 start,\n        uint256 end\n    ) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = keys(map._inner, start, end);\n        bytes32[] memory result;\n\n        assembly (\"memory-safe\") {\n            result := store\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Query for a nonexistent map key.\n     */\n    error EnumerableMapNonexistentBytesKey(bytes key);\n\n    struct BytesToBytesMap {\n        // Storage of keys\n        EnumerableSet.BytesSet _keys;\n        mapping(bytes key => bytes) _values;\n    }\n\n    /**\n     * @dev Adds a key-value pair to a map, or updates the value for an existing\n     * key. O(1).\n     *\n     * Returns true if the key was added to the map, that is if it was not\n     * already present.\n     */\n    function set(BytesToBytesMap storage map, bytes memory key, bytes memory value) internal returns (bool) {\n        map._values[key] = value;\n        return map._keys.add(key);\n    }\n\n    /**\n     * @dev Removes a key-value pair from a map. O(1).\n     *\n     * Returns true if the key was removed from the map, that is if it was present.\n     */\n    function remove(BytesToBytesMap storage map, bytes memory key) internal returns (bool) {\n        delete map._values[key];\n        return map._keys.remove(key);\n    }\n\n    /**\n     * @dev Removes all the entries from a map. 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 map grows to the point where clearing it consumes too much gas to fit in a block.\n     */\n    function clear(BytesToBytesMap storage map) internal {\n        uint256 len = length(map);\n        for (uint256 i = 0; i < len; ++i) {\n            delete map._values[map._keys.at(i)];\n        }\n        map._keys.clear();\n    }\n\n    /**\n     * @dev Returns true if the key is in the map. O(1).\n     */\n    function contains(BytesToBytesMap storage map, bytes memory key) internal view returns (bool) {\n        return map._keys.contains(key);\n    }\n\n    /**\n     * @dev Returns the number of key-value pairs in the map. O(1).\n     */\n    function length(BytesToBytesMap storage map) internal view returns (uint256) {\n        return map._keys.length();\n    }\n\n    /**\n     * @dev Returns the key-value pair stored at position `index` in the map. O(1).\n     *\n     * Note that there are no guarantees on the ordering of entries inside the\n     * array, and it may change when more entries are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(\n        BytesToBytesMap storage map,\n        uint256 index\n    ) internal view returns (bytes memory key, bytes memory value) {\n        key = map._keys.at(index);\n        value = map._values[key];\n    }\n\n    /**\n     * @dev Tries to return the value associated with `key`. O(1).\n     * Does not revert if `key` is not in the map.\n     */\n    function tryGet(\n        BytesToBytesMap storage map,\n        bytes memory key\n    ) internal view returns (bool exists, bytes memory value) {\n        value = map._values[key];\n        exists = bytes(value).length != 0 || contains(map, key);\n    }\n\n    /**\n     * @dev Returns the value associated with `key`. O(1).\n     *\n     * Requirements:\n     *\n     * - `key` must be in the map.\n     */\n    function get(BytesToBytesMap storage map, bytes memory key) internal view returns (bytes memory value) {\n        bool exists;\n        (exists, value) = tryGet(map, key);\n        if (!exists) {\n            revert EnumerableMapNonexistentBytesKey(key);\n        }\n    }\n\n    /**\n     * @dev Returns an array containing all the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(BytesToBytesMap storage map) internal view returns (bytes[] memory) {\n        return map._keys.values();\n    }\n\n    /**\n     * @dev Returns an array containing a slice of the keys\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 map grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function keys(BytesToBytesMap storage map, uint256 start, uint256 end) internal view returns (bytes[] memory) {\n        return map._keys.values(start, end);\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":[{"internalType":"bytes32","name":"assetKey","type":"bytes32"}],"name":"AssetKeysDuplicate","type":"error"},{"inputs":[{"internalType":"bytes32","name":"assetKey","type":"bytes32"}],"name":"AssetNotSupported","type":"error"},{"inputs":[{"internalType":"uint256","name":"newLpValue","type":"uint256"},{"internalType":"uint256","name":"newReserveValue","type":"uint256"}],"name":"BaselineLpValueExceedsReserveValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BelowMinimumCombinationAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"customMessageId","type":"uint256"}],"name":"CustomMessageIdIsUsed","type":"error"},{"inputs":[],"name":"DepositRedeemDisabled","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"EnumerableMapNonexistentKey","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FeeRateTooHigh","type":"error"},{"inputs":[{"internalType":"uint256","name":"initialLpValue","type":"uint256"},{"internalType":"uint256","name":"initialReserveValue","type":"uint256"}],"name":"InitialLpValueExceedsReserveValue","type":"error"},{"inputs":[],"name":"InvalidAdjustmentFactor","type":"error"},{"inputs":[],"name":"InvalidArrayLength","type":"error"},{"inputs":[{"internalType":"bytes","name":"encodedAddress","type":"bytes"}],"name":"InvalidEVMAddress","type":"error"},{"inputs":[],"name":"InvalidFeeType","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"uint256","name":"ratio","type":"uint256"}],"name":"InvalidLpShareRatio","type":"error"},{"inputs":[],"name":"InvalidNativeTokenSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"effectiveLpPrice","type":"uint256"},{"internalType":"uint256","name":"oneCombinationValue","type":"uint256"},{"internalType":"uint256","name":"adjustmentFactor","type":"uint256"}],"name":"InvalidRevenueAdjustmentInputs","type":"error"},{"inputs":[{"internalType":"uint256","name":"totalRatio","type":"uint256"}],"name":"InvalidTotalRatio","type":"error"},{"inputs":[],"name":"NewExchangeRateIsZero","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"bytes32","name":"assetKey","type":"bytes32"}],"name":"RatioIsZero","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"RefundFailed","type":"error"},{"inputs":[],"name":"RequiredReserveExchangeRateIsZero","type":"error"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"}],"name":"ReserveAddressDuplicate","type":"error"},{"inputs":[{"internalType":"bytes32","name":"assetKey","type":"bytes32"}],"name":"ReserveAmountTooSmall","type":"error"},{"inputs":[{"internalType":"bytes32","name":"assetKey","type":"bytes32"},{"internalType":"uint256","name":"trackedAmount","type":"uint256"},{"internalType":"uint256","name":"treasuryAmount","type":"uint256"}],"name":"ReserveTreasuryAmountBelowTrackedAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"reserveDrop","type":"uint256"},{"internalType":"uint256","name":"oldLpValue","type":"uint256"}],"name":"ReserveValueDropExceedsLpValue","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"RevenueRecipientCannotBeReserveTreasury","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"RevenueRecipientCannotBeSelf","type":"error"},{"inputs":[{"internalType":"bytes32","name":"assetKey","type":"bytes32"},{"internalType":"uint256","name":"requiredAmount","type":"uint256"},{"internalType":"uint256","name":"treasuryAmount","type":"uint256"}],"name":"RevenueReserveDeficit","type":"error"},{"inputs":[],"name":"RevenueSyncAlreadyInitialized","type":"error"},{"inputs":[],"name":"RevenueSyncDisabled","type":"error"},{"inputs":[],"name":"RevenueSyncNotInitialized","type":"error"},{"inputs":[{"internalType":"int256","name":"value","type":"int256"}],"name":"SafeCastOverflowedIntToUint","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintToInt","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"SyncRevenueCallerIsNotValid","type":"error"},{"inputs":[{"internalType":"uint256","name":"newLpValue","type":"uint256"},{"internalType":"uint256","name":"currentReserveValue","type":"uint256"}],"name":"SyncedLpValueExceedsReserveValue","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroFeeToAddress","type":"error"},{"inputs":[],"name":"ZeroShares","type":"error"},{"inputs":[],"name":"ZeroTreasuryAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"bytes32","name":"toBytes32","type":"bytes32"},{"indexed":false,"internalType":"bytes32[]","name":"assetKeys","type":"bytes32[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"destinationChainIdOrSelector","type":"uint64"}],"name":"AssetsDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"bytes32","name":"toBytes32","type":"bytes32"},{"indexed":false,"internalType":"bytes32[]","name":"assetKeys","type":"bytes32[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"AssetsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"DepositFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"oldStatus","type":"bool"},{"indexed":false,"internalType":"bool","name":"newStatus","type":"bool"}],"name":"DepositRedeemStatusUpdated","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":false,"internalType":"uint256","name":"oldAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAmount","type":"uint256"}],"name":"MinimumCombinationAmountUpdated","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":true,"internalType":"bytes32","name":"assetKey","type":"bytes32"},{"indexed":true,"internalType":"address","name":"oldFeed","type":"address"},{"indexed":true,"internalType":"address","name":"newFeed","type":"address"}],"name":"PriceFeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldBase","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBase","type":"uint256"}],"name":"RatioPrecisionMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"RedeemFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"assetKey","type":"bytes32"},{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"}],"name":"ReserveAssetSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"assetKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"oldTrackedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTrackedAmount","type":"uint256"}],"name":"ReserveBalanceSynced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"assetKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"newRatio","type":"uint256"}],"name":"ReserveRatioUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldTreasury","type":"address"},{"indexed":true,"internalType":"address","name":"newTreasury","type":"address"}],"name":"ReserveTreasuryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldLpValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLpValue","type":"uint256"}],"name":"RevenueBaselineRefreshed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRatio","type":"uint256"}],"name":"RevenueLpShareRatioUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newRecipient","type":"address"}],"name":"RevenueRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldCaller","type":"address"},{"indexed":true,"internalType":"address","name":"newCaller","type":"address"}],"name":"RevenueSyncCallerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"oldEnabled","type":"bool"},{"indexed":false,"internalType":"bool","name":"newEnabled","type":"bool"}],"name":"RevenueSyncEnabledUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"revenueRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"revenueSyncCaller","type":"address"},{"indexed":false,"internalType":"uint256","name":"initialReserveValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"initialLpValue","type":"uint256"}],"name":"RevenueSyncInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldLpValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLpValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"revenueAdjustmentFactor","type":"uint256"}],"name":"RevenueSynced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"assetKey","type":"bytes32"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount18","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountRaw","type":"uint256"}],"name":"RevenueTransferred","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":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","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":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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 IFUSDLP.FeeType","name":"feeType","type":"uint8"}],"name":"calculateFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"toBytes32","type":"bytes32"},{"internalType":"uint256","name":"combinationAmounts","type":"uint256"},{"internalType":"uint64","name":"destinationChainIdOrSelector","type":"uint64"}],"name":"deposit","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"depositRedeemEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAssetKeysAndAddress","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"},{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCCIPAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExchangeRateWithAdjustment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"assetKey","type":"bytes32"}],"name":"getReserveAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"assetKey","type":"bytes32"}],"name":"getReservePriceFeed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"assetKey","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getReserveValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"assetKeys","type":"bytes32[]"}],"name":"getReservesRatio","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"assetKeys","type":"bytes32[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"getReservesValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRevenueAdjustmentFactor","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":[],"name":"getTotalReservesInfo","outputs":[{"internalType":"bytes32[]","name":"assetKeys","type":"bytes32[]"},{"internalType":"address[]","name":"assetAddresses","type":"address[]"},{"internalType":"uint256[]","name":"ratios","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"uint256","name":"totalValue","type":"uint256"},{"internalType":"uint256","name":"updateAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"assetKey","type":"bytes32"}],"name":"getTrackedReserveAmount","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"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":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address","name":"_reserveTreasury","type":"address"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"_kycModule","type":"address"},{"internalType":"uint256","name":"_depositFee","type":"uint256"},{"internalType":"uint256","name":"_redeemFee","type":"uint256"},{"internalType":"address","name":"_feeTo","type":"address"},{"internalType":"address","name":"_bridgeSender","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"revenueRecipient","type":"address"},{"internalType":"address","name":"revenueSyncCaller","type":"address"},{"internalType":"uint256","name":"revenueLpShareRatio","type":"uint256"}],"name":"initializeRevenueSync","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":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"customMessageIdBytes32","type":"bytes32"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintWithCustomMessageId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","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":"uint256","name":"combinationAmounts","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"bytes32[]","name":"assetKeys","type":"bytes32[]"},{"internalType":"address[]","name":"assetAddresses","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"netShares","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"bytes32[]","name":"assetKeys","type":"bytes32[]"},{"internalType":"address[]","name":"assetAddresses","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"toBytes32","type":"bytes32"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"redeem","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":[],"name":"resetRevenueBaseline","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":"bool","name":"enabled","type":"bool"}],"name":"setDepositRedeemEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeTo","type":"address"}],"name":"setFeeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minimumCombinationAmount","type":"uint256"}],"name":"setMinimumCombinationAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_reserveTreasury","type":"address"}],"name":"setReserveTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"assetKeys","type":"bytes32[]"},{"internalType":"address[]","name":"assetAddresses","type":"address[]"},{"internalType":"uint256[]","name":"ratio","type":"uint256[]"},{"internalType":"address[]","name":"priceFeed","type":"address[]"}],"name":"setReservesInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRatio","type":"uint256"}],"name":"setRevenueLpShareRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRecipient","type":"address"}],"name":"setRevenueRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newCaller","type":"address"}],"name":"setRevenueSyncCaller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setRevenueSyncEnabled","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"assetKey","type":"bytes32"}],"name":"syncReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"syncRevenue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"factor","type":"uint256"}],"name":"syncRevenueAdjustmentFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositFee","type":"uint256"}],"name":"updateDepositFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_redeemFee","type":"uint256"}],"name":"updateRedeemFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":null}