{"file_path":"src/protocol/ResupplyPair.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\n/**\n * @title ResupplyPair\n * @notice Based on code from Drake Evans and Frax Finance's lending pair contract (https://github.com/FraxFinance/fraxlend), adapted for Resupply Finance\n */\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { ResupplyPairConstants } from \"./pair/ResupplyPairConstants.sol\";\nimport { ResupplyPairCore } from \"./pair/ResupplyPairCore.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { VaultAccount, VaultAccountingLibrary } from \"../libraries/VaultAccount.sol\";\nimport { IRateCalculator } from \"../interfaces/IRateCalculator.sol\";\nimport { ISwapper } from \"../interfaces/ISwapper.sol\";\nimport { IFeeDeposit } from \"../interfaces/IFeeDeposit.sol\";\nimport { IResupplyRegistry } from \"../interfaces/IResupplyRegistry.sol\";\nimport { IConvexStaking } from \"../interfaces/IConvexStaking.sol\";\nimport { EpochTracker } from \"../dependencies/EpochTracker.sol\";\n\ncontract ResupplyPair is ResupplyPairCore, EpochTracker {\n    using VaultAccountingLibrary for VaultAccount;\n    using SafeERC20 for IERC20;\n    using SafeCast for uint256;\n\n    uint256 public lastFeeEpoch;\n    address public constant CRV = 0xD533a949740bb3306d119CC777fa900bA034cd52;\n    address public constant CVX = 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B;\n\n    // Staking Info\n    address public immutable convexBooster;\n    uint256 public convexPid;\n    \n    error FeesAlreadyDistributed();\n    error IncorrectStakeBalance();\n\n    /// @param _core Core contract address\n    /// @param _configData config data\n    /// @param _immutables immutable data\n    /// @param _customConfigData extras\n    constructor(\n        address _core,\n        bytes memory _configData,\n        bytes memory _immutables,\n        bytes memory _customConfigData\n    ) ResupplyPairCore(_core, _configData, _immutables, _customConfigData) EpochTracker(_core) {\n\n        (, address _govToken, address _convexBooster, uint256 _convexpid) = abi.decode(\n            _customConfigData,\n            (string, address, address, uint256)\n        );\n        //add gov token rewards\n        _insertRewardToken(_govToken);\n\n        //convex info\n        if(_convexBooster != address(0)){\n            convexBooster = _convexBooster;\n            convexPid = _convexpid;\n            //approve\n            collateral.forceApprove(convexBooster, type(uint256).max);\n            //add rewards for curve staking\n            _insertRewardToken(CRV);\n            _insertRewardToken(CVX);\n\n            emit SetConvexPool(_convexpid);\n        }\n    }\n\n\n    // ============================================================================================\n    // Functions: Helpers\n    // ============================================================================================\n\n    function getConstants()\n        external\n        pure\n        returns (\n            uint256 _LTV_PRECISION,\n            uint256 _LIQ_PRECISION,\n            uint256 _EXCHANGE_PRECISION,\n            uint256 _RATE_PRECISION\n        )\n    {\n        _LTV_PRECISION = LTV_PRECISION;\n        _LIQ_PRECISION = LIQ_PRECISION;\n        _EXCHANGE_PRECISION = EXCHANGE_PRECISION;\n        _RATE_PRECISION = RATE_PRECISION;\n    }\n\n    /// @notice The ```getUserSnapshot``` function gets user level accounting data\n    /// @param _address The user address\n    /// @return _borrowShares The user borrow shares\n    /// @return _collateralBalance The user collateral balance\n    function getUserSnapshot(\n        address _address\n    ) external returns (uint256 _borrowShares, uint256 _collateralBalance) {\n        _collateralBalance = userCollateralBalance(_address);\n        _borrowShares = userBorrowShares(_address);\n    }\n\n    /// @notice The ```getPairAccounting``` function gets all pair level accounting numbers\n    /// @return _claimableFees Total claimable fees\n    /// @return _totalBorrowAmount Total borrows\n    /// @return _totalBorrowShares Total borrow shares\n    /// @return _totalCollateral Total collateral\n    function getPairAccounting()\n        external\n        view\n        returns (\n            uint256 _claimableFees,\n            uint128 _totalBorrowAmount,\n            uint128 _totalBorrowShares,\n            uint256 _totalCollateral\n        )\n    {\n        VaultAccount memory _totalBorrow;\n        (, , _claimableFees, _totalBorrow) = previewAddInterest();\n        _totalBorrowAmount = _totalBorrow.amount;\n        _totalBorrowShares = _totalBorrow.shares;\n        _totalCollateral = totalCollateral();\n    }\n\n    /// @notice The ```toBorrowShares``` function converts a given amount of borrow debt into the number of shares\n    /// @param _amount Amount of borrow\n    /// @param _roundUp Whether to roundup during division\n    /// @param _previewInterest Whether to simulate interest accrual\n    /// @return _shares The number of shares\n    function toBorrowShares(\n        uint256 _amount,\n        bool _roundUp,\n        bool _previewInterest\n    ) external view returns (uint256 _shares) {\n        if (_previewInterest) {\n            (, , , VaultAccount memory _totalBorrow) = previewAddInterest();\n            _shares = _totalBorrow.toShares(_amount, _roundUp);\n        } else {\n            _shares = totalBorrow.toShares(_amount, _roundUp);\n        }\n    }\n\n    /// @notice The ```toBorrowAmount``` function converts a given amount of borrow debt into the number of shares\n    /// @param _shares Shares of borrow\n    /// @param _roundUp Whether to roundup during division\n    /// @param _previewInterest Whether to simulate interest accrual\n    /// @return _amount The amount of asset\n    function toBorrowAmount(\n        uint256 _shares,\n        bool _roundUp,\n        bool _previewInterest\n    ) external view returns (uint256 _amount) {\n        if (_previewInterest) {\n            (, , , VaultAccount memory _totalBorrow) = previewAddInterest();\n            _amount = _totalBorrow.toAmount(_shares, _roundUp);\n        } else {\n            _amount = totalBorrow.toAmount(_shares, _roundUp);\n        }\n    }\n    // ============================================================================================\n    // Functions: Configuration\n    // ============================================================================================\n\n\n    /// @notice The ```SetOracleInfo``` event is emitted when the oracle info is set\n    /// @param oldOracle The old oracle address\n    /// @param newOracle The new oracle address\n    event SetOracleInfo(\n        address oldOracle,\n        address newOracle\n    );\n\n    /// @notice The ```setOracleInfo``` function sets the oracle data\n    /// @param _newOracle The new oracle address\n    function setOracle(address _newOracle) external onlyOwner{\n        ExchangeRateInfo memory _exchangeRateInfo = exchangeRateInfo;\n        emit SetOracleInfo(\n            _exchangeRateInfo.oracle,\n            _newOracle\n        );\n        _exchangeRateInfo.oracle = _newOracle;\n        exchangeRateInfo = _exchangeRateInfo;\n    }\n\n    /// @notice The ```SetMaxLTV``` event is emitted when the max LTV is set\n    /// @param oldMaxLTV The old max LTV\n    /// @param newMaxLTV The new max LTV\n    event SetMaxLTV(uint256 oldMaxLTV, uint256 newMaxLTV);\n\n    /// @notice The ```setMaxLTV``` function sets the max LTV\n    /// @param _newMaxLTV The new max LTV\n    function setMaxLTV(uint256 _newMaxLTV) external onlyOwner{\n        if (_newMaxLTV > LTV_PRECISION) revert InvalidParameter();\n        emit SetMaxLTV(maxLTV, _newMaxLTV);\n        maxLTV = _newMaxLTV;\n    }\n\n \n    /// @notice The ```SetRateCalculator``` event is emitted when the rate contract is set\n    /// @param oldRateCalculator The old rate contract\n    /// @param newRateCalculator The new rate contract\n    event SetRateCalculator(address oldRateCalculator, address newRateCalculator);\n\n    /// @notice The ```setRateCalculator``` function sets the rate contract address\n    /// @param _newRateCalculator The new rate contract address\n    /// @param _updateInterest Whether to update interest before setting new rate calculator\n    function setRateCalculator(address _newRateCalculator, bool _updateInterest) external onlyOwner{\n        //should add interest before changing rate calculator\n        //however if there is an intrinsic problem with the current rate calculate, need to be able\n        //to update without calling addInterest\n        if(_updateInterest){\n            _addInterest();\n        }\n        emit SetRateCalculator(address(rateCalculator), _newRateCalculator);\n        rateCalculator = IRateCalculator(_newRateCalculator);\n    }\n\n\n    /// @notice The ```SetLiquidationFees``` event is emitted when the liquidation fees are set\n    /// @param oldLiquidationFee The old clean liquidation fee\n    /// @param newLiquidationFee The new clean liquidation fee\n    event SetLiquidationFees(\n        uint256 oldLiquidationFee,\n        uint256 newLiquidationFee\n    );\n\n    /// @notice The ```setLiquidationFees``` function sets the liquidation fees\n    /// @param _newLiquidationFee The new clean liquidation fee\n    function setLiquidationFees(\n        uint256 _newLiquidationFee\n    ) external onlyOwner{\n        if (_newLiquidationFee > LIQ_PRECISION) revert InvalidParameter();\n        emit SetLiquidationFees(\n            liquidationFee,\n            _newLiquidationFee\n        );\n        liquidationFee = _newLiquidationFee;\n    }\n\n    /// @notice The ```SetMintFees``` event is emitted when the liquidation fees are set\n    /// @param oldMintFee The old mint fee\n    /// @param newMintFee The new mint fee\n    event SetMintFees(\n        uint256 oldMintFee,\n        uint256 newMintFee\n    );\n\n    /// @notice The ```setMintFees``` function sets the mint\n    /// @param _newMintFee The new mint fee\n    function setMintFees(\n        uint256 _newMintFee\n    ) external onlyOwner{\n        emit SetMintFees(\n            mintFee,\n            _newMintFee\n        );\n        mintFee = _newMintFee;\n    }\n\n    function setBorrowLimit(uint256 _limit) external onlyOwner{\n        _setBorrowLimit(_limit);\n    }\n\n    /// @notice The ```SetBorrowLimit``` event is emitted when the borrow limit is set\n    /// @param limit The new borrow limit\n    event SetBorrowLimit(uint256 limit);\n\n    function _setBorrowLimit(uint256 _limit) internal {\n        if(_limit > type(uint128).max){\n            revert InvalidParameter();\n        }\n        borrowLimit = _limit;\n        emit SetBorrowLimit(_limit);\n    }\n\n    event SetMinimumRedemption(uint256 min);\n\n    function setMinimumRedemption(uint256 _min) external onlyOwner{\n        if(_min < 100 * PAIR_DECIMALS ){\n            revert InvalidParameter();\n        }\n        minimumRedemption = _min;\n        emit SetMinimumRedemption(_min);\n    }\n\n    event SetMinimumLeftover(uint256 min);\n\n    function setMinimumLeftoverDebt(uint256 _min) external onlyOwner{\n        minimumLeftoverDebt = _min;\n        emit SetMinimumLeftover(_min);\n    }\n\n    event SetMinimumBorrowAmount(uint256 min);\n\n    function setMinimumBorrowAmount(uint256 _min) external onlyOwner{\n        minimumBorrowAmount = _min;\n        emit SetMinimumBorrowAmount(_min);\n    }\n\n    event SetProtocolRedemptionFee(uint256 fee);\n\n    /// @notice Sets the redemption fee percentage for this specific pair\n    /// @dev The fee is 1e18 precision (1e16 = 1%) and taken from redemptions and sent to the protocol.\n    /// @param _fee The new redemption fee percentage. Must be less than or equal to 1e18 (100%)\n    function setProtocolRedemptionFee(uint256 _fee) external onlyOwner{\n        if(_fee > EXCHANGE_PRECISION) revert InvalidParameter();\n\n        protocolRedemptionFee = _fee;\n        emit SetProtocolRedemptionFee(_fee);\n    }\n\n    /// @notice The ```WithdrawFees``` event fires when the fees are withdrawn\n    /// @param recipient To whom the assets were sent\n    /// @param interestFees the amount of interest based fees claimed\n    /// @param otherFees the amount of other fees claimed(mint/redemption)\n    event WithdrawFees(address recipient, uint256 interestFees, uint256 otherFees);\n\n    /// @notice The ```withdrawFees``` function withdraws fees accumulated\n    /// @return _fees the amount of interest based fees claimed\n    /// @return _otherFees the amount of other fees claimed(mint/redemption)\n    function withdrawFees() external nonReentrant returns (uint256 _fees, uint256 _otherFees) {\n\n        // Accrue interest if necessary\n        _addInterest();\n\n        //get deposit contract\n        address feeDeposit = IResupplyRegistry(registry).feeDeposit();\n        uint256 lastDistributedEpoch = IFeeDeposit(feeDeposit).lastDistributedEpoch();\n        uint256 currentEpoch = getEpoch();\n\n        //current epoch must be greater than last claimed epoch\n        //current epoch must be equal to the FeeDeposit prev distributed epoch (FeeDeposit must distribute first)\n        if(currentEpoch <= lastFeeEpoch || currentEpoch != lastDistributedEpoch){\n            revert FeesAlreadyDistributed();\n        }\n\n        lastFeeEpoch = currentEpoch;\n\n        //get fees and clear\n        _fees = claimableFees;\n        _otherFees = claimableOtherFees;\n        claimableFees = 0;\n        claimableOtherFees = 0;\n        //mint new stables to the receiver\n        IResupplyRegistry(registry).mint(feeDeposit,_fees+_otherFees);\n        //inform deposit contract of this pair's contribution\n        IFeeDeposit(feeDeposit).incrementPairRevenue(_fees,_otherFees);\n        emit WithdrawFees(feeDeposit, _fees, _otherFees);\n    }\n\n    /// @notice The ```SetSwapper``` event fires whenever a swapper is black or whitelisted\n    /// @param swapper The swapper address\n    /// @param approval The approval\n    event SetSwapper(address swapper, bool approval);\n\n    /// @notice The ```setSwapper``` function is called to black or whitelist a given swapper address\n    /// @dev\n    /// @param _swapper The swapper address\n    /// @param _approval The approval\n    function setSwapper(address _swapper, bool _approval) external{\n        if(msg.sender == owner() || msg.sender == registry){\n            swappers[_swapper] = _approval;\n            emit SetSwapper(_swapper, _approval);\n        }else{\n            revert OnlyProtocolOrOwner();\n        }\n    }\n\n    /// @notice The ```SetConvexPool``` event fires when convex pool id is updated\n    /// @param pid the convex pool id\n    event SetConvexPool(uint256 pid);\n\n    /// @notice The ```setConvexPool``` function is called update the underlying convex pool\n    /// @dev\n    /// @param pid the convex pool id\n    function setConvexPool(uint256 pid) external onlyOwner{\n        _updateConvexPool(pid);\n        emit SetConvexPool(pid);\n    }\n\n    function _updateConvexPool(uint256 _pid) internal{\n        uint256 currentPid = convexPid;\n        if(currentPid != _pid){\n            //get previous staking\n            (,,,address _rewards,,) = IConvexStaking(convexBooster).poolInfo(currentPid);\n            //get balance\n            uint256 stakedBalance = IConvexStaking(_rewards).balanceOf(address(this));\n            \n            if(stakedBalance > 0){\n                //withdraw\n                IConvexStaking(_rewards).withdrawAndUnwrap(stakedBalance,false);\n                if(collateral.balanceOf(address(this)) < stakedBalance){\n                    revert IncorrectStakeBalance();\n                }\n            }\n\n            //stake in new pool\n            IConvexStaking(convexBooster).deposit(_pid, stakedBalance, true);\n\n            //update pid\n            convexPid = _pid;\n        }\n    }\n\n    function _stakeUnderlying(uint256 _amount) internal override{\n        uint256 currentPid = convexPid;\n        if(currentPid != 0){\n            IConvexStaking(convexBooster).deposit(currentPid, _amount, true);\n        }\n    }\n\n    function _unstakeUnderlying(uint256 _amount) internal override{\n        uint256 currentPid = convexPid;\n        if(currentPid != 0){\n            (,,,address _rewards,,) = IConvexStaking(convexBooster).poolInfo(currentPid);\n            IConvexStaking(_rewards).withdrawAndUnwrap(_amount, false);\n        }\n    }\n\n    function totalCollateral() public view override returns(uint256 _totalCollateralBalance){\n        uint256 currentPid = convexPid;\n        if(currentPid != 0){\n            //get staking\n            (,,,address _rewards,,) = IConvexStaking(convexBooster).poolInfo(currentPid);\n            //get balance\n            _totalCollateralBalance = IConvexStaking(_rewards).balanceOf(address(this));\n        }else{\n            _totalCollateralBalance = collateral.balanceOf(address(this));   \n        }\n    }\n\n    // ============================================================================================\n    // Functions: Access Control\n    // ============================================================================================\n\n    uint256 previousBorrowLimit;\n    /// @notice The ```pause``` function is called to pause all contract functionality\n    function pause() external onlyOwner{\n        if (borrowLimit > 0) {\n            previousBorrowLimit = borrowLimit;\n            _setBorrowLimit(0);\n        }\n    }\n\n    /// @notice The ```unpause``` function is called to unpause all contract functionality\n    function unpause() external onlyOwner{\n        if (borrowLimit == 0) _setBorrowLimit(previousBorrowLimit);\n    }\n}","deployed_bytecode":"0x60806040526004361015610011575f80fd5b5f5f3560e01c80628cc2621461382357806302ce728f146137f557806306b6f7e91461377657806306fdde031461365957806308a0c375146135c157806308c7e366146135a45780630cab937d146130385780630df8dfac1461300f57806313966db514612ff1578063146a29eb14612fd15780631c6c959714612f505780632164e85b14612f325780632b3ba681146110be5780632cdacb5014612eed5780632f86556814612a9e57806333fd6f7414612a4b5780633f2617cb146129575780633f4ba83a146128fc57806342f43d0b146128b7578063476343ee1461264357806348741376146125795780634ac8eb5f1461255e5780634cae6513146124e45780634fd422df146124c057806354fd4d501461249757806356ecf28b1461247957806357d775f81461243e5780635e43c47b1461240957806360c52d05146123c05780636551f16c146123365780636b091695146122725780636f307dc31461222d578063730a7514146121a2578063757991a81461213b578063759cb53b1461210c57806375a410141461208c57806378e97925146120515780637adbf97314611f635780637b10399914611f1e5780637e92968414611bbb5780637ec4b57114611b7a5780638049d97114611afd5780638214ba4814611a835780638285ef4014611a5457806383d4433914611a1b5780638456cb591461199657806386993bef146119785780638cad7fbe146119395780638da5cb5b146109d85780638f50ea921461191b57806391ebebbd146118bc57806392bbcaed1461189e57806393ae0df91461187757806393f46f6414611831578063945c91421461180257806395d14ca8146117c05780639a295e731461177a5780639fe34bdc14611158578063a053db68146112af578063a36a363014611291578063ab7cfaf914611273578063acb70815146111f5578063b5af3062146111d1578063b5b5454714611198578063b68d0a091461115d578063b78294dd14611158578063b95c57461461113a578063c00007b0146110e1578063c0a7e892146110be578063c3192f14146110c3578063c49bb2d1146110be578063ca51bb59146110a0578063cacf3b5814611074578063cadac47914610f86578063cdd72d5214610f2c578063d41ddc9614610dee578063d619658b14610dd2578063d6bda0c014610bf4578063d870ce6614610b5a578063d8dfeb4514610b15578063e509b9d914610ad4578063e551d11d14610ab6578063e69bc27114610a71578063e7a3317414610a1d578063f2f4eb26146109d8578063f301af4214610982578063f384bd0514610964578063f5c7f89914610927578063f8112eed146108e6578063fbbbf94c146108ac578063fd6d0526146104325763fff5d9da1461040d575f80fd5b3461042f578060031936011261042f5760206104276140ee565b604051908152f35b80fd5b503461042f57608036600319011261042f5761044c6139b7565b90606435906024356001600160a01b0383168084036108a85761046d614145565b60405163e8673ef560e01b81526020816004817f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b03165afa90811561089d57849161085f575b506001600160a01b03163303610850578015908115610846575b5061083757600e548110610828576104ea6144d9565b505050604435670de0b6b3a764000003670de0b6b3a764000081116108145761051c670de0b6b3a76400009183613d36565b0493670de0b6b3a764000061053d6105348785613b9b565b600d5490613d36565b04946105498684613b9b565b90610552613c9e565b6001600160801b03815116838181119182156107ff575b50506107f0576001600160801b03610586818516828451166140ce565b169081815264e8d4a5100082029180830464e8d4a5100014901517156107525760208101916001600160801b0383511611610766575b51905160801b6001600160801b0319166001600160801b039190911617601755670de0b6b3a764000090610608905b6105f789601954613d67565b601955610602614163565b90613d36565b0495610613876157e2565b7f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa29826001600160a01b03169561064a908890886158e3565b6001600160a01b037f000000000000000000000000128403d60ef83a0d1ebf945cce9af02ef5f7c8d916620186a088810290898204148915171561075257813b1561074e57869160248392604051948593849263140e25ad60e31b845260048401525af180156107435761072a575b5060408051948552602085018890528401526060830152600192916001600160a01b03909116907f76cd0cedf979345ca241ce6de696a520a8efc860c6c10d9db2a7953307c237fc90608090a255604080516001600160a01b039092168252602082019290925290819081015b0390f35b610735868092613a57565b61073f575f6106b9565b8480fd5b6040513d88823e3d90fd5b8680fd5b634e487b7160e01b87526011600452602487fd5b61076e615160565b600254600181018091116107dc576001600160801b036106089381670de0b6b3a76400009694846105eb956002557febad8099c467528a56c98b63c8d476d251cf1ffb4c75db94b4d23fa2b6a1e3358d80a28164e8d4a51000818551160416835294965050935050506105bc565b634e487b7160e01b88526011600452602488fd5b6316c6823f60e01b8652600486fd5b6108099250613b9b565b600f5411835f610569565b634e487b7160e01b83526011600452602483fd5b6362171e8f60e01b8252600482fd5b631e4ec46b60e01b8252600482fd5b905030145f6104d4565b63d520e5ad60e01b8352600483fd5b90506020813d602011610895575b8161087a60209383613a57565b810103126108915761088b90613d22565b5f6104ba565b8380fd5b3d915061086d565b6040513d86823e3d90fd5b8280fd5b503461042f578060031936011261042f57601554601654604080516001600160a01b038416815260a09390931c6020840152820152606090f35b503461042f57602036600319011261042f576109206109036139b7565b61091361090e61496f565b613f6e565b61091b614145565b615736565b6001815580f35b503461042f57604036600319011261042f576001906109586109476139b7565b61094f614145565b60243590615012565b55602060405160018152f35b503461042f578060031936011261042f576020600954604051908152f35b503461042f57602036600319011261042f576004359060015482101561042f5760606109ad83613b63565b506001815491015460ff6040519260018060a01b038116845260a01c16151560208301526040820152f35b503461042f578060031936011261042f576040517f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b03168152602090f35b503461042f57602036600319011261042f57610a63337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b610a6e600435614930565b80f35b503461042f57604036600319011261042f576040610a8d6139cd565b9160043581526004602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461042f578060031936011261042f576020600a54604051908152f35b503461042f57602036600319011261042f576020906001600160a01b03610af96139b7565b16815260088252604060018060a01b0391205416604051908152f35b503461042f578060031936011261042f576040517f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa29826001600160a01b03168152602090f35b503461042f57602036600319011261042f57600435610ba3337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b68056bc75e2d631000008110610be5576020817febc3aac103344d02f2e1b3fb50ca740929143c84082dd6e7698963e902aa636992600e55604051908152a180f35b630309cb8760e51b8252600482fd5b503461042f57606036600319011261042f57602435610c116139e3565b610c19614145565b610c22336142a5565b6001600160a01b03811615610dc357610c396144d9565b505050610c44614163565b5081610cd3575b610c609150610c5b60043561473e565b6152af565b906040610c6b613c70565b01610c77815133614335565b15610c8b5760208360018455604051908152f35b60649250610cad610c9a613c9e565b338452601b6020526040842054906143d7565b90338352601a6020526040832054905191633b49de0f60e21b8452600452602452604452fd5b602082610d05610d2c9430337f000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e61524b565b604051636e553f6560e01b8152600481019190915230602482015292839081906044820190565b0381867f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa29826001600160a01b03165af1918215610db8578392610d7e575b50610d79610c6092339030614be4565b610c4b565b91506020823d602011610db0575b81610d9960209383613a57565b81010312610dac57905190610d79610d69565b5f80fd5b3d9150610d8c565b6040513d85823e3d90fd5b631e4ec46b60e01b8352600483fd5b503461042f578060031936011261042f576020604051600f8152f35b503461042f57604036600319011261042f57600435610e0b6139cd565b610e13614145565b610e1c336142a5565b6001600160a01b03168015610dc357610e336144d9565b505050338352601b6020526040832054610f1e575b610e53333084614659565b604051635d043b2960e11b815260048101929092526024820152306044820152602081606481857f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa29826001600160a01b03165af18015610f1357610ee4575b506040610ebc613c70565b01610ec8815133614335565b15610ed557506001815580f35b90606491610cad610c9a613c9e565b610f059060203d602011610f0c575b610efd8183613a57565b810190613ce8565b505f610eb1565b503d610ef3565b6040513d84823e3d90fd5b610f26614163565b50610e48565b503461042f578060031936011261042f57610f45613ba8565b506080610f5061402c565b915091506001600160801b0360208183511692015116610f6e613dcc565b91604051938452602084015260408301526060820152f35b503461042f57604036600319011261042f57600435610fa36139cd565b90610fac614145565b6001600160a01b03821615610dc357906020610ff992610fca6144d9565b505050610d058130337f000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e61524b565b0381867f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa29826001600160a01b03165af18015610db8578390611040575b610920925030614be4565b506020823d60201161106c575b8161105a60209383613a57565b81010312610dac576109209151611035565b3d915061104d565b503461042f578060031936011261042f5761072661109061402c565b9060409492945194859485613a87565b503461042f578060031936011261042f576020601c54604051908152f35b613ae1565b503461042f578060031936011261042f576020601854604051908152f35b503461042f57602036600319011261042f576110fb6139b7565b611103614145565b6001600160a01b0381811683526008602052604083205416801561112a5761092091614eab565b508061113591614eab565b610920565b503461042f578060031936011261042f576020600154604051908152f35b613b2f565b503461042f57602036600319011261042f5760406111796139b7565b61118b61118582613fab565b91613f10565b9082519182526020820152f35b503461042f57602036600319011261042f576020906040906001600160a01b036111c06139b7565b168152600383522054604051908152f35b503461042f57602036600319011261042f5760206104276111f06139b7565b613fab565b503461042f57604036600319011261042f576004356112126139cd565b61121a614145565b6001600160a01b03811615610dc35760209261126a60019261123a6144d9565b505050611245613c9e565b61124f86826143d7565b9561126261125c8861473e565b9161473e565b90339261476f565b55604051908152f35b503461042f578060031936011261042f576020600d54604051908152f35b503461042f578060031936011261042f576020600c54604051908152f35b503461042f5760a036600319011261042f576112c96139b7565b60243591906064356044356084356001600160401b03811161073f573660238201121561073f5780600401356112fe81613b4c565b9161130c6040519384613a57565b818352602083016024819360051b8301019136831161177657602401905b82821061175e5750505061133c614145565b611345336142a5565b859061134f6144d9565b50505061135a614163565b506001600160a01b0386168088526012602052604088205490969060ff161561174f576001600160a01b0361138e85613c1b565b517f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b03169116819003611739575083515f198101908111611725576001600160a01b03906113e39086613c28565b517f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa29826001600160a01b03169291168290036116e9578561163e575b61142b90610c5b8b61473e565b93604051926370a0823160e01b8452306004850152602084602481865afa938415611633578a946115ff575b50883b156115fb57604051634b4ecc5560e11b8152336004820152602481018c9052608060448201529151608483018190528a90839060a4820190835b8181106115d6575050819293503060648301520381838c5af180156115cb579089916115b2575b5050906020602492604051938480926370a0823160e01b82523060048301525afa80156115a7578890611573575b6114f39250613b9b565b9380851061155c5750836115119161150c338330614be4565b613d67565b9560405194855260208501526040840152606083015260808201527fb19ca0df3f3a01af950d8e6ad62aeff167cf14c73e98af6c52afef1add5c97ed60a03392a26040610c6b613c70565b633b5d56ed60e11b87526004526024849052604486fd5b506020823d60201161159f575b8161158d60209383613a57565b81010312610dac576114f391516114e9565b3d9150611580565b6040513d8a823e3d90fd5b816115bc91613a57565b6115c757875f6114bb565b8780fd5b6040513d8b823e3d90fd5b85516001600160a01b031683526020958601958f955087945090920191600101611494565b8980fd5b9093506020813d60201161162b575b8161161b60209383613a57565b81010312610dac5751925f611457565b3d915061160e565b6040513d8c823e3d90fd5b925061166c8530337f000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e61524b565b604051636e553f6560e01b8152600481018690523060248201526020816044818c865af180156115cb5789906116b5575b61142b91506116ad338230614be4565b93905061141e565b506020813d6020116116e1575b816116cf60209383613a57565b81010312610dac5761142b905161169d565b3d91506116c2565b8489838251925f198401938411610814576044936001600160a01b03916117109190613c28565b51169063b0b3262d60e01b8352600452602452fd5b634e487b7160e01b89526011600452602489fd5b60449089906001600160a01b0361171088613c1b565b631311dc6d60e01b8852600488fd5b6020809161176b846139f9565b81520191019061132a565b8880fd5b503461042f578060031936011261042f576080906040519050620186a08152620186a06020820152670de0b6b3a76400006040820152670de0b6b3a76400006060820152f35b503461042f578060031936011261042f576060601454604051906001600160401b03811682526001600160401b038160401c16602083015260801c6040820152f35b503461042f578060031936011261042f57602060405173d533a949740bb3306d119cc777fa900ba034cd528152f35b503461042f5760209061184336613b03565b9192509015611861576104279161185861402c565b925050506146f8565b6118729161186d613c9e565b6146f8565b610427565b503461042f578060031936011261042f57602061042761189561402c565b92505050615209565b503461042f578060031936011261042f576020600f54604051908152f35b503461042f57606036600319011261042f576118d66139cd565b60406118e06139e3565b9260043581526005602052209060018060a01b03165f5260205260405f209060018060a01b03165f52602052602060405f2054604051908152f35b503461042f578060031936011261042f576020600e54604051908152f35b503461042f57602036600319011261042f5760209060ff906040906001600160a01b036119646139b7565b168152601284522054166040519015158152f35b503461042f578060031936011261042f576020601d54604051908152f35b503461042f578060031936011261042f576119db337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b600a54806119e7575080f35b601e5580600a557fbf1ce7fb3a8e648b70ea830f99b52f7ea31554186d29763280751f42e77f63866020604051838152a180f35b503461042f57602036600319011261042f576020906040906001600160a01b03611a436139b7565b168152600783522054604051908152f35b503461042f578060031936011261042f5760406017548151906001600160801b038116825260801c6020820152f35b503461042f57602036600319011261042f577fc98711414b05c67ac27ffb415026d97ad5094c5490747891a834cb44f64940d96020600435611aef337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b80600f55604051908152a180f35b503461042f57604036600319011261042f57611b176139cd565b611b1f614145565b611b28336142a5565b6001600160a01b0381161561083757611b6290611b436144d9565b505050338352601b6020526040832054611b6c575b3390600435614659565b6040610ebc613c70565b611b74614163565b50611b58565b503461042f57602090611b8c36613b03565b9192509015611baa5761042791611ba161402c565b92505050614475565b61187291611bb6613c9e565b614475565b503461042f57602036600319011261042f57600435611c04337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b81601d54828103611c3f575b507fa83ced135f4f6135be6fb52ae9183bf190452765f5b75b36caa332537c3ca7e5602083604051908152a180f35b604051631526fe2760e01b815260048101919091527f000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae316001600160a01b03169060c081602481855afa908115610db8578391611ee9575b506040516370a0823160e01b8152306004820152906001600160a01b0316602082602481845afa91821561089d578492611eb2575b5081611d95575b5090606460209260405194859384926321d0683360e11b84528860048501526024840152600160448401525af18015610db857611d37575b50601d819055817fa83ced135f4f6135be6fb52ae9183bf190452765f5b75b36caa332537c3ca7e5611c10565b6020813d602011611d8d575b81611d5060209383613a57565b810103126108a8577fa83ced135f4f6135be6fb52ae9183bf190452765f5b75b36caa332537c3ca7e591611d85602092613cf7565b509150611d0a565b3d9150611d43565b60209060446040959394955180948193636197390160e11b83528760048401528160248401525af18015611e7057611e7b575b506040516370a0823160e01b81523060048201526020816024817f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa29826001600160a01b03165afa8015611e705782918691611e3b575b5010611e2c579083915f611cd2565b6346bc68ed60e01b8452600484fd5b9150506020813d602011611e68575b81611e5760209383613a57565b81010312610dac578190515f611e1d565b3d9150611e4a565b6040513d87823e3d90fd5b6020813d602011611eaa575b81611e9460209383613a57565b8101031261073f57611ea590613cf7565b611dc8565b3d9150611e87565b935090506020833d602011611ee1575b81611ecf60209383613a57565b81010312610dac57849251905f611ccb565b3d9150611ec2565b611f0b915060c03d60c011611f17575b611f038183613a57565b810190613d74565b5050925050505f611c96565b503d611ef9565b503461042f578060031936011261042f576040517f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b03168152602090f35b503461042f57602036600319011261042f576040611f7f6139b7565b611fb3337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b612021611fbe613c70565b805184516001600160a01b03918216815290841660208201529092907fb9d23ad01dc54c1fad84c770708fbe314a369b505c073949334dad786229805e90604090a16001600160a01b0316808352601580546001600160a01b0319169091179055565b6020810151601580546001600160a01b031660a09290921b6001600160a01b031916919091179055015160165580f35b503461042f578060031936011261042f5760206040517f0000000000000000000000000000000000000000000000000000000067d220008152f35b503461042f57602036600319011261042f576120a66139b7565b6120ae614145565b3380835260086020908152604080852080546001600160a01b0319166001600160a01b039590951694851790555192835290917ff4239ad0860f93469699dd4be8040b8838c5e25bb6cf24a1dfb381b937ff078c9190a26001815580f35b503461042f578060031936011261042f576020604051734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b8152f35b503461042f578060031936011261042f57602061042761217b7f0000000000000000000000000000000000000000000000000000000067d2200042613b9b565b7f0000000000000000000000000000000000000000000000000000000000093a8090613d49565b503461042f57602036600319011261042f576004356121eb337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b620186a08111610be5577f1f93e1cc6afaef2ddc4d7ef7b0f45ac3278d548338c839e9be18695732a662746040600c548151908152836020820152a1600c5580f35b503461042f578060031936011261042f576040517f000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e6001600160a01b03168152602090f35b503461042f57604036600319011261042f5761228c6139b7565b6122946139cd565b61229c614145565b6001600160a01b0382163303612309576001600160a01b038116156122c45761092091614eab565b60405162461bcd60e51b815260206004820152601760248201527f66776420616464726573732063616e6e6f7420626520300000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152600560248201526410b9b2b63360d91b6044820152606490fd5b503461042f57602036600319011261042f5760043561237f337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b670de0b6b3a76400008111610be5576020817f3e0c428758b3ad6ab4fd85e8257e4eee404fb36e80c0251143635b549cd70b8892600d55604051908152a180f35b503461042f57604036600319011261042f576123da6139cd565b6123e2614145565b6001600160a01b0381161561083757610920906123fd6144d9565b50505060043533614be4565b503461042f57602036600319011261042f576109206124266139b7565b61243161090e61496f565b612439614145565b614a3b565b503461042f578060031936011261042f5760206040517f0000000000000000000000000000000000000000000000000000000000093a808152f35b503461042f578060031936011261042f576020600254604051908152f35b503461042f578060031936011261042f5760609060405190600382528060208301526040820152f35b503461042f57602036600319011261042f5760206104276124df6139b7565b613f10565b503461042f57602036600319011261042f577f18e1a8f58cc03bc99f69c27336072db255c3f01827f2923f654ddc209e2b8db56020600435612550337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b80601055604051908152a180f35b503461042f578060031936011261042f576020610427613dcc565b503461042f57604036600319011261042f576125936139b7565b61259b613a78565b6125cf337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b612633575b601154604080516001600160a01b038084168252841660208201529192917f74cd8ef76f78382ae0f3ee4e21117be974af0041a24dc98f7aa8ddabb0b2960c9190a16001600160a01b03166001600160a01b0319919091161760115580f35b61263b6144d9565b5050506125d4565b503461042f578060031936011261042f5761265c614145565b6126646144d9565b5050604051630abca72960e41b81527f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b03169150602081600481855afa908115610db857839161287d575b506040516379bd9e4160e01b81526001600160a01b03821690602081600481855afa908115611e7057859161284b575b5061271461217b7f0000000000000000000000000000000000000000000000000000000067d2200042613b9b565b90601c54821190811591612840575b5061283157601c5583601854936019549382601855826019556127468587613d67565b823b15610891576040516340c10f1960e01b81526001600160a01b0392909216600483015260248201529082908290604490829084905af18015610f135761281c575b5050803b15610891576040516362f2221960e01b8152836004820152826024820152848160448183865af18015611e7057612807575b506040937f9cc800ba322ea82ab3e1e911dd4ccd84129687c4952f4ee2f937e3ac68755131606060019387519081528660208201528588820152a15582519182526020820152f35b612812858092613a57565b610891575f6127bf565b8161282691613a57565b61089157835f612789565b630e1b248d60e01b8552600485fd5b90508114155f612723565b90506020813d602011612875575b8161286660209383613a57565b81010312610dac57515f6126e6565b3d9150612859565b90506020813d6020116128af575b8161289860209383613a57565b810103126108a8576128a990613d22565b5f6126b6565b3d915061288b565b503461042f578060031936011261042f576040517f000000000000000000000000128403d60ef83a0d1ebf945cce9af02ef5f7c8d96001600160a01b03168152602090f35b503461042f578060031936011261042f57612941337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b600a541561294c5780f35b610a6e601e54614930565b503461042f57604036600319011261042f576129716139b7565b612979613a78565b90337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b0316148015612a19575b15612a0a577fea1eefb4fd58778d7b274fe54045a9feeec8f2847899c2e71126d3a74d486da59160409160018060a01b03169081855260126020528285209015159060ff1981541660ff831617905582519182526020820152a180f35b631d1e647b60e01b8352600483fd5b50337f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b0316146129ad565b503461042f57604036600319011261042f576040612a676139b7565b91612a706139cd565b9260018060a01b031681526006602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461042f57602036600319011261042f57612ab86139b7565b612ac0614145565b60405163d25adeb360e01b8152906020826004817f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b03165afa918215610db8578392612eb1575b506001600160a01b0382169133839003612ea2576001600160a01b0382168015612e9357612b3a6144d9565b505050612b45614163565b612b4e846142a5565b612b588185614335565b612e8457612b64613c9e565b90828752601a602052604087205490838852601b602052612b88604089205461473e565b926001600160801b0384169260208201926001600160801b03845116155f14612ded57612bbe670de0b6b3a76400009186613d36565b04600c54620186a0019081620186a011612dd9576001600160801b0398969492620186a0612bf5612c739d9c9a9896948c94613d36565b0481811115612dcf57509a8b955b877f158ba9ab7bbbd08eeffa4753bad41f4d450e24831d293427308badf3eadd8c766060612c39612c348a896143d7565b61473e565b9d8e6040519b8c528a60208d015216998a6040820152a2612c598a614d44565b82612c678c828751166140ce565b168452828551166140ce565b168252848b52601b602052612c8c8360408d2054613b9b565b858c52601b6020528060408d20558015159081612dba575b50612dab5751905160801b6001600160801b0319166001600160801b03919091161760175588969594612d109490939092909188917fe4a1ae657f49cb1fb1c7d3a94ae6093565c4c8c0e03de488f79c377c3c3a24e0916040919082519182526020820152a386614659565b813b156108a857604051632be71c5f60e11b81526001600160a01b037f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa2982166004820152602481018590526001600160801b0391909116604482015291908290606490829084905af18015610db857612d92575b50600160209255604051908152f35b612d9d838092613a57565b612da7575f612d83565b5080fd5b631abfe8a760e01b8b5260048bfd5b612dc59150826143d7565b601054115f612ca4565b90509a8b95612c03565b634e487b7160e01b8c52601160045260248cfd5b612e15612e046001600160801b0385511687613d36565b6001600160801b0386511690613d49565b8b80612e54575b612e34575b670de0b6b3a764000091612bbe91613d36565b6001810180911115612e2157634e487b7160e01b8c52601160045260248cfd5b5085612e7e612e6d6001600160801b0388511684613d36565b6001600160801b0387511690613d49565b10612e1c565b633af2cafd60e11b8652600486fd5b631e4ec46b60e01b8552600485fd5b6387e9041360e01b8452600484fd5b9091506020813d602011612ee5575b81612ecd60209383613a57565b810103126108a857612ede90613d22565b905f612b0e565b3d9150612ec0565b503461042f578060031936011261042f576040517f000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae316001600160a01b03168152602090f35b503461042f578060031936011261042f576020601954604051908152f35b503461042f57602036600319011261042f576004358015158103612da757612f76613d04565b50610726604051612f8681613a0d565b5f81525f6020820152612f97614145565b83612fa06144d9565b96915094612fb9575b6001905560405194859485613a87565b9150506018546001612fc9613c9e565b929050612fa9565b503461042f578060031936011261042f57602060405164e8d4a510008152f35b503461042f578060031936011261042f576020600b54604051908152f35b503461042f578060031936011261042f576011546040516001600160a01b039091168152602090f35b5034610dac576080366003190112610dac576130526139b7565b60443591906064356024356001600160401b038211610dac5736602383011215610dac578160040135926001600160401b038411610dac576024830192602436918660051b010111610dac576130a6614145565b6130af336142a5565b6130b76144d9565b5050506130c2614163565b506130cb613c9e565b9260018060a01b03821694855f52601260205260ff60405f20541615613595578015613581576130fa82613cd4565b6001600160a01b037f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa29828116911681900361357857505f198101928184116135645761314e613149858486613cc4565b613cd4565b6001600160a01b037f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec811695911685900361353257506001600160801b0386511615613523576131a090339086614659565b6040516370a0823160e01b815230600482015291602083602481875afa9283156134b6575f936134ef575b50863b15610dac57604051634b4ecc5560e11b815233600482015260248101869052608060448201526084810183905291829160a48301915f5b8181106134c15750505090805f923060648301520381838a5af180156134b6576134a1575b506040516370a0823160e01b8152306004820152602081602481865afa80156133ed578290889061346b575b6132609250613b9b565b968088106134545750856001600160801b03855116155f14613410575086935b338752601b60205260408720548086116133f8575b506132b6906132a38961473e565b339130916132b08961473e565b9161476f565b6040516370a0823160e01b8152306004820152602081602481865afa9081156133ed57908793929184916133b4575b50906132f091613b9b565b8061333f575b505050604051928352602083015283604083015260608201527f6b2b212085c14b2dc48ec56d19c05084e5d8ef233539cdd3dc0d70a4ec7f4f9e60803392a26040610c6b613c70565b60405163a9059cbb60e01b815233600482015260248101919091529160209183916044918391905af18015611e705761337b575b8085916132f6565b6020813d6020116133ac575b8161339460209383613a57565b8101031261073f576133a590613cf7565b505f613373565b3d9150613387565b919350506020813d6020116133e5575b816133d160209383613a57565b81010312610dac57518692906132f06132e5565b3d91506133c4565b6040513d89823e3d90fd5b945096506132b661340985896143d7565b9790613295565b9361343c61342b6001600160801b036020840151168a613d36565b6001600160801b0383511690613d49565b94156132805793600181018091116107525793613280565b633b5d56ed60e11b87526004526024879052604486fd5b50506020813d602011613499575b8161348660209383613a57565b81010312610dac57816132609151613256565b3d9150613479565b6134ae9196505f90613a57565b5f945f61322a565b6040513d5f823e3d90fd5b9193509160019060209081906001600160a01b036134de886139f9565b168152019401910191849392613205565b9092506020813d60201161351b575b8161350b60209383613a57565b81010312610dac5751915f6131cb565b3d91506134fe565b631abfe8a760e01b5f5260045ffd5b90506131499161354193613cc4565b63b0b3262d60e01b5f9081526004929092526001600160a01b0316602452604490fd5b634e487b7160e01b5f52601160045260245ffd5b61354183613cd4565b634e487b7160e01b5f52603260045260245ffd5b631311dc6d60e01b5f5260045ffd5b34610dac575f366003190112610dac576020601054604051908152f35b34610dac576020366003190112610dac57600435613609337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b620186a0811161364a577fe796e9ae748449310fcd1cc6718aab236c9b8d2e0e04dacb232ba564d5b338cc60406009548151908152836020820152a1600955005b630309cb8760e51b5f5260045ffd5b34610dac575f366003190112610dac576040515f90601354918260011c6001841693841561376c575b60208210851461375857818452602084019490811561373d57506001146136df575b50906136b4816040930382613a57565b8151928391602083525180918160208501528484015e5f828201840152601f01601f19168101030190f35b91905060135f527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a090915f905b808210613723575090915081016020016136b46136a4565b91926001816020925483858801015201910190929161370b565b60ff1916855250151560051b820160200190506136b46136a4565b634e487b7160e01b5f52602260045260245ffd5b90607f1690613682565b34610dac576020366003190112610dac576004356137be337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614613c3c565b7f388cba11a61d4b31467a533c88eef75abfb6097ff2ab4652d086560fffcc2f836040600b548151908152836020820152a1600b55005b34610dac575f366003190112610dac5761380d614145565b6020613817614163565b60015f55604051908152f35b34610dac576020366003190112610dac5761383c6139b7565b613844614145565b61384d81614d44565b60015461385981613bc0565b916001600160a01b03165f5b8281106139405760015f5583515f19810190859082116135645761388882613bc0565b9160015b818111156138ee57836040518091602082016020835281518091526020604084019201905f5b8181106138c0575050500390f35b825180516001600160a01b0316855260209081015181860152869550604090940193909201916001016138b2565b60206138fa8285613c28565b510151905f1981018181116135645760019260206139188389613c28565b510152613938838060a01b0361392e8488613c28565b5151169187613c28565b51520161388c565b8061394c600192613b63565b5054828060a01b0381169081159081156139a9575b506139a157805f52600660205260405f20845f5260205260405f205460206139898489613c28565b5101526139968287613c28565b515201915b91613865565b50019161399b565b60ff915060a01c1687613961565b600435906001600160a01b0382168203610dac57565b602435906001600160a01b0382168203610dac57565b604435906001600160a01b0382168203610dac57565b35906001600160a01b0382168203610dac57565b604081019081106001600160401b03821117613a2857604052565b634e487b7160e01b5f52604160045260245ffd5b606081019081106001600160401b03821117613a2857604052565b90601f801991011681019081106001600160401b03821117613a2857604052565b602435908115158203610dac57565b926001600160801b0391959460209183604060c09660e089019a89526001600160401b03815116868a01526001600160401b038682015116828a0152015116606087015260808601528281511660a0860152015116910152565b34610dac575f366003190112610dac576020604051670de0b6b3a76400008152f35b6060906003190112610dac57600435906024358015158103610dac57906044358015158103610dac5790565b34610dac575f366003190112610dac576020604051620186a08152f35b6001600160401b038111613a285760051b60200190565b6001548110156135815760015f81815291901b7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60191565b9190820391821161356457565b60405190613bb582613a0d565b5f6020838281520152565b90613bca82613b4c565b613bd76040519182613a57565b8281528092613be8601f1991613b4c565b01905f5b828110613bf857505050565b602090604051613c0781613a0d565b5f81525f8382015282828501015201613bec565b8051156135815760200190565b80518210156135815760209160051b010190565b15613c4357565b60405162461bcd60e51b815260206004820152600560248201526421636f726560d81b6044820152606490fd5b60405190613c7d82613a3c565b6015546001600160a01b038116835260a01c60208301526016546040830152565b60405190613cab82613a0d565b6017546001600160801b038116835260801c6020830152565b91908110156135815760051b0190565b356001600160a01b0381168103610dac5790565b90816020910312610dac575190565b51908115158203610dac57565b60405190613d1182613a3c565b5f6040838281528260208201520152565b51906001600160a01b0382168203610dac57565b8181029291811591840414171561356457565b8115613d53570490565b634e487b7160e01b5f52601260045260245ffd5b9190820180921161356457565b91908260c0910312610dac57613d8982613d22565b91613d9660208201613d22565b91613da360408301613d22565b91613db060608201613d22565b91613dc960a0613dc260808501613d22565b9301613cf7565b90565b601d548015613eb957604051631526fe2760e01b8152600481019190915260c0816024817f000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae316001600160a01b03165afa9081156134b6576024916020915f91613e94575b506040516370a0823160e01b815230600482015292839182906001600160a01b03165afa9081156134b6575f91613e65575090565b90506020813d602011613e8c575b81613e8060209383613a57565b81010312610dac575190565b3d9150613e73565b613ead915060c03d60c011611f1757611f038183613a57565b5050925050505f613e30565b506040516370a0823160e01b81523060048201526020816024817f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa29826001600160a01b03165afa9081156134b6575f91613e65575090565b6001600160a01b03165f908152601b6020908152604080832054600254600390935292205491929190808210613f44575050565b909264e8d4a510006001915b04930192818414613f695764e8d4a51000600191613f50565b925050565b15613f7557565b60405162461bcd60e51b815260206004820152600e60248201526d10b932bbb0b93226b0b730b3b2b960911b6044820152606490fd5b613fb3614145565b613fbc816142a5565b6001600160a01b03165f908152601a6020526040902054613fdb613dcc565b9081811115613fed57505b9060015f55565b9050613fe6565b6040519061400182613a3c565b8160406014546001600160401b03811683526001600160401b0381831c16602084015260801c910152565b5f614035613d04565b5060405161404281613a0d565b5f81525f602082015250614054613ff4565b906001600160401b034216825261406a82615507565b8051909190156140bf57506060810151926001600160401b0360208301511660208401526001600160801b03604083015116604084015260806140b96018546001600160801b03871690613d67565b92015190565b92905060185490613dc9613c9e565b906001600160801b03809116911603906001600160801b03821161356457565b600a548015614138576001600160801b0361410761402c565b92505050511690670de0b6b3a7640000820291808304670de0b6b3a7640000149015171561356457613dc991613d49565b50670de0b6b3a764000090565b60025f54146141545760025f55565b633ee5aeb560e01b5f5260045ffd5b61416b613c70565b9060208201916001600160601b038351164214155f1461429d5780516040516315caaba160e21b81526001600160a01b037f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa29828116600483015290929160209184916024918391165afa9182156134b6575f92614269575b508115613d53576001600160601b03429081169094526ec097ce7bc90715b34b9f1000000000919091046040808301829052915160a09490941b6001600160a01b0319166001600160a01b03909416939093176015556016839055518281527f4fc1b45960547ee95894b08a284c3c066cf5aca706a7420639c42c3ec2e118a490602090a1565b9091506020813d602011614295575b8161428560209383613a57565b81010312610dac5751905f6141e2565b3d9150614278565b604001519150565b6142ae81614d44565b6001600160a01b037f000000000000000000000000128403d60ef83a0d1ebf945cce9af02ef5f7c8d981165f90815260066020908152604080832094909316808352938152828220805490839055601a9091529190205490620186a0900480821061432c5761431c91613b9b565b905b5f52601a60205260405f2055565b50505f9061431e565b906009549182156143cf5761436b61434b613c9e565b6001600160a01b039092165f818152601b602052604090205490926143d7565b9081156143c6575f52601a60205260405f20549182156143be5761438e91613d36565b90620186a0820291808304620186a0149015171561356457670de0b6b3a76400006143b99204613d49565b111590565b505050505f90565b50505050600190565b505050600190565b6020810180516001600160801b03166143f0575050905b565b90929161441b61440a6001600160801b0386511683613d36565b6001600160801b0384511690613d49565b936001600160801b0381511615159283614448575b50505061443957565b90600181018091116135645790565b61446c9293506144636001600160801b038092511687613d36565b91511690613d49565b105f8080614430565b909160208201916001600160801b03835116155f146144945750505090565b6144b0612e6d6001600160801b03839796949597511684613d36565b94836144c5575b836144485750505061443957565b81516001600160801b0316151593506144b7565b5f905f906144e5613d04565b506144ee613ff4565b906144f882615507565b8051151580614505575050565b9194509250926143ee6001600160801b03602060806060870151968287016001600160401b0381511690604089019186835116907f6b9ef8676ff86d806b7a7bd7a9b0266910c9fce560c26289d7ed7cd7743127c786888701926001600160401b038451169460408901958c875116916040519384528c84015260408301526060820152a17f939dcec711228d083924a0db6cecbb66bb8403ea7cdbfe2f928901cbac2cdfc160408d6001600160401b0384511682519182528a820152a151916001600160401b0383169052519186831690526001600160401b034216808a526fffffffffffffffff00000000000000006014549260401b169187191617176014558460145491811990821990861b161691161760145561462888601854613d67565b601855015182815116831960175416176017550151166001600160801b036017549181199060801b16911617601755565b9160207fba68c7a8c8efbddb7e938ee32ecc28a68930c18105a3a0ab9563eac7f051cf5a9160018060a01b031693845f52601a825260405f2061469d828254613b9b565b90556146a8816157e2565b6001600160a01b03841693813086036146c7575b5050604051908152a3565b6146f1917f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa29826158e3565b5f816146bc565b90916001600160801b03825116155f1461471157505090565b9092916020840161472f612e6d6001600160801b0383511684613d36565b94836144485750505061443957565b6001600160801b038111614758576001600160801b031690565b6306dfcc6560e41b5f52608060045260245260445ffd5b9391909161477c81614d44565b6001600160801b0361479184828851166140ce565b16855260208501906001600160801b036147ae84828551166140ce565b16825260018060a01b031694855f52601b6020526147db6001600160801b0360405f205494168094613b9b565b865f52601b6020528060405f2055801515908161491b575b506135235751905160801b6001600160801b0319166001600160801b0391909116176017556001600160a01b0383169283614865575b507fe4a1ae657f49cb1fb1c7d3a94ae6093565c4c8c0e03de488f79c377c3c3a24e0916040916001600160801b038351921682526020820152a3565b917f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b0316803b15610dac57604051632770a7eb60e21b81526001600160a01b039490941660048501526001600160801b03821660248501525f908490604490829084905af19182156134b6577fe4a1ae657f49cb1fb1c7d3a94ae6093565c4c8c0e03de488f79c377c3c3a24e09360409361490b575b50915091614829565b5f61491591613a57565b5f614902565b6149269150826143d7565b601054115f6147f3565b6001600160801b03811161364a576020817fbf1ce7fb3a8e648b70ea830f99b52f7ea31554186d29763280751f42e77f638692600a55604051908152a1565b337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b03161480156149a45790565b5060405163670fb82160e01b81526020816004817f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b03165afa9081156134b6575f91614a01575b506001600160a01b0316331490565b90506020813d602011614a33575b81614a1c60209383613a57565b81010312610dac57614a2d90613d22565b5f6149f2565b3d9150614a0f565b6001600160a01b038116903082148015614bdc575b8015614bcc575b614b9257815f52600760205260405f2054155f14614b5e57600154600f811015614b2b5768010000000000000000811015613a2857806001614a9c9201600155613b63565b50826001600160601b0360a01b825416179055600154825f52600760205260405f2055817fb13fd610fe4e1b384966826794a9b2f6100ad031f352cc5ec6f22667f60749805f80a2803b15614b2157506143ee906040519063a9059cbb60e01b60208301523060248301525f604483015260448252614b1c606483613a57565b615ce8565b6143ee9150615736565b60405162461bcd60e51b815260206004820152600b60248201526a6d6178207265776172647360a81b6044820152606490fd5b50805f52600760205260405f20545f19810190811161356457614b8090613b63565b5080546001600160a01b031615614b96575b5050565b80546001600160a01b031916821790557fb13fd610fe4e1b384966826794a9b2f6100ad031f352cc5ec6f22667f60749805f80a2565b50614bd68161591f565b15614a57565b508115614a50565b9160018060a01b031691825f52601a60205260405f20614c05838254613d67565b905581306001600160a01b03831603614d11575b5050601d5480614c52575b5060207f2ac90482c3b6bea30a2c085cf093016bad7f970d91c5fd233e6b848d3e231dc391604051908152a2565b6040516321d0683360e11b8152600481019190915260248101829052600160448201526020816064815f7f000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae316001600160a01b03165af180156134b65715614c24576020813d602011614d09575b81614ccc60209383613a57565b81010312610dac577f2ac90482c3b6bea30a2c085cf093016bad7f970d91c5fd233e6b848d3e231dc391614d01602092613cf7565b509150614c24565b3d9150614cbf565b614d3d9130907f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa298261524b565b5f81614c19565b5f907f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b0316803b15610dac575f8091602460405180948193633bd73ee360e21b83523060048401525af180156134b657614e96575b506002549060015490835b5f198110614dba575050505050565b836001600160a01b03831680614e4d575b865b858110614e26575085821015614e1d57808752601b60205264e8d4a51000604088205404818852601b60205260408820556001820180921161075257865260036020526040862055600101614dab565b50505050505050565b80614e3e89876001948b889c999d9e9a979b98615990565b01919490939796929591614dcd565b8087526003602052604087205491508582141580614e82575b15614dcb57905084908087526003602052856040882055614dcb565b50808752601b602052604087205415614e66565b614ea39192505f90613a57565b5f905f614da0565b7f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b031691823b15610dac57604051633bd73ee360e21b81525f816024818380983060048401525af180156134b657614ffd575b506002549160015492845b5f198110614f2057505050505050565b816001600160a01b03841680614fb4575b875b878110614f8d575083821015614f8357808852601b60205264e8d4a51000604089205404818952601b6020526040892055600182018092116107dc57875260036020526040872055600101614f10565b5050505050505050565b80614fa5888860019489889d999e9f9b979c98615990565b01929691959094989792614f33565b8088526003602052604088205491508382141580614fe9575b15614f3157905082908088526003602052836040892055614f31565b50808852601b602052604088205415614fcd565b61500a9193505f90613a57565b5f915f614f05565b5f91907f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b0316803b15610dac575f8091602460405180948193633bd73ee360e21b83523060048401525af180156134b65761514b575b506002549060015491845b84811061508957505050505050565b816001600160a01b03841680615102575b875b8681106150ec575083821015614f8357808852601b60205264e8d4a51000604089205404818952601b6020526040892055600182018092116107dc5787526003602052604087205560010161507a565b806150fc8a886001948988615990565b0161509c565b8088526003602052604088205491508382141580615137575b1561509a5790508290808852600360205283604089205561509a565b50808852601b60205260408820541561511b565b6151589193505f90613a57565b5f915f61506f565b5f7f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b0316803b15610dac575f8091602460405180948193633bd73ee360e21b83523060048401525af180156134b6576151f6575b5060025460015491905f1982106151d157505050565b815b8381106151e05750505050565b806151f084806001948680615990565b016151d3565b61520291505f90613a57565b5f5f6151bb565b600a5490516001600160801b0316808211156152435761522891613b9b565b6001600160801b03811115613dc957506001600160801b0390565b50505f615228565b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526143ee91614b1c608483613a57565b906001600160801b03809116911601906001600160801b03821161356457565b9190916152ba613c9e565b92601054916001600160801b03811692831061352357600b54620186a00180620186a011613564576152f0620186a09185613d36565b046152fa86615209565b8181106154f2575085516001600160801b031661549357805b61537b82976001600160801b036020820191816153546153368883875116613d67565b8261534c6153438a61473e565b8287511661528f565b16845261473e565b1692839052516001600160801b0391161660809190911b6001600160801b03191617601755565b335f52601b60205260405f20615392838254613d67565b9055848082111561548a576153a691613b9b565b915b82615476575b7f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b0316803b15610dac576040516340c10f1960e01b81526001600160a01b03861660048201526001600160801b039290921660248301525f908290604490829084905af180156134b657615466575b506040519384526020840152604083015260018060a01b0316907f10a0132d3bf8c82a7fb93a86160f3074ca5c3e5706fa2bcdf0e2b5fd495af09b60603392a3565b5f61547091613a57565b5f615424565b61548283601954613d67565b6019556153ae565b50505f916153a8565b6020860190806154da6154c46154b36001600160801b0386511684613d36565b6001600160801b038b511690613d49565b936001600160801b03614463818c511687613d36565b10156153135790600181018091116135645790615313565b63586ce21f60e11b5f5260045260245260445ffd5b9060405160a081018181106001600160401b03821117613a28576040525f8152602081015f815260408201935f855260608301915f8352608084019360405161554f81613a0d565b5f81525f6020820152855280966001600160401b038451164211615576575b505050505050565b600161560d9252615585613c9e565b8652604061559d6001600160401b0386511642613b9b565b6011549582015182516356fb8f2d60e01b81526001600160a01b037f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa298281166004830152602482018490526001600160801b0390921660448201529196919485929190911690829081906064820190565b03915afa80156134b6575f925f916156cf575b50670de0b6b3a7640000946001600160401b03615667959481946001600160801b0361565e951690521684526001600160801b038851511690613d36565b91511690613d36565b0480825280151590816156ae575b50156156a5576156966001600160801b03809251169251928284511661528f565b1690525b5f808080808061556e565b5f91505261569a565b6001600160801b0391506156c790828551511690613d67565b11155f615675565b939250506040833d60401161572e575b816156ec60409383613a57565b81010312610dac578251926001600160401b0384168403610dac5760200151906001600160801b0382168203610dac5791929190670de0b6b3a7640000615620565b3d91506156df565b6001600160a01b03165f8181526007602052604090205480615756575050565b5f1981019081116135645761576a90613b63565b5080546001600160a01b03168290036157b15780546001600160a01b03191690557f646cfe9445aed85f4853d501d1924d2bdabb1bbf12531df29f929f07ba4169e05f80a2565b60405162461bcd60e51b8152602060048201526009602482015268042dad2e6dac2e8c6d60bb1b6044820152606490fd5b601d54806157ee575050565b604051631526fe2760e01b8152600481019190915260c0816024817f000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae316001600160a01b03165afa80156134b6575f9260209284926158b9575b50604051636197390160e11b815260048101919091526024810184905292839160449183916001600160a01b03165af180156134b6576158845750565b6020813d6020116158b1575b8161589d60209383613a57565b81010312610dac576158ae90613cf7565b50565b3d9150615890565b60449192506158d69060c03d60c011611f1757611f038183613a57565b5050925050509190615847565b60405163a9059cbb60e01b60208201526001600160a01b039290921660248301526044808301939093529181526143ee91614b1c606483613a57565b6001600160a01b03908116907f0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa298216811461598b577f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b03161461598757600190565b5f90565b505f90565b93929161599c90613b63565b5080546001600160a01b03169290831561556e576040516370a0823160e01b815230600482015293602085602481845afa9485156134b6575f95615cb4575b508496600183019687549582149686888099615ca6575b80615c9d575b615c1c575b50505f8281526004602090815260408083206001600160a01b03878116855292529091205495169384615a4e575b50505050505081615a43575b50615a40575050565b55565b90508214155f615a37565b825f52600560205260405f2060018060a01b0385165f5260205260405f20855f5260205260405f20548860018060a01b03841692831580158091615c13575b615a9b575b50505050615a2b565b82615c0b575b5081615bfb575b5015615b9b57615af690855f52600660205260405f20875f5260205269021e19e0c9bab2400000615aef60405f205492895f52601b60205261060260405f2054918c613b9b565b0490613d67565b9182615b38575b5050505b5f52600560205260405f209060018060a01b03165f5260205260405f20905f5260205260405f20555f808080808080888180615a92565b90615b6183615b92959c93875f52600660205260405f20895f526020525f6040812055876158e3565b84867fce405e67b4d6e56e438257e15f160ae28b450e6e7659bbc4c1f4e09a1ac846cb6020604051878152a4613b9b565b965f8080615afd565b9050615bdf9150835f52600660205260405f20855f5260205269021e19e0c9bab2400000615aef60405f205492875f52601b60205261060260405f2054918a613b9b565b825f52600660205260405f20845f5260205260405f2055615b01565b60ff91505460a01c16155f615aa8565b91505f615aa1565b50898410615a8d565b615c2591613b9b565b69021e19e0c9bab240000081029080820469021e19e0c9bab2400000149015171561356457615c5a9060175460801c90613d49565b8015615c9357825f52600460205260405f2060018060a01b0385165f52602052615c8960405f20918254613d67565b90555b5f866159fd565b5097508497615c8c565b508082116159f8565b5060175460801c15156159f2565b9094506020813d602011615ce0575b81615cd060209383613a57565b81010312610dac5751935f6159db565b3d9150615cc3565b905f602091828151910182855af1156134b6575f513d615d3757506001600160a01b0381163b155b615d175750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415615d1056fea164736f6c634300081c000a","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{},"metadata":{"bytecodeHash":"none"},"optimizer":{"enabled":true,"runs":200},"remappings":[":@axelar-network/=node_modules/@axelar-network/",":@chainlink/=node_modules/@chainlink/",":@eth-optimism/=node_modules/@eth-optimism/",":@layerzerolabs/=node_modules/@layerzerolabs/",":@mean-finance/=node_modules/@mean-finance/",":@openzeppelin/=node_modules/@openzeppelin/",":@rari-capital/=node_modules/@rari-capital/",":@uniswap/=node_modules/@uniswap/",":base64-sol/=node_modules/base64-sol/",":ds-test/=node_modules/ds-test/src/",":forge-std/=node_modules/forge-std/src/",":frax-standard-solidity/=node_modules/frax-standard-solidity/",":frax-std/=node_modules/frax-standard-solidity/src/",":hardhat-deploy/=node_modules/hardhat-deploy/",":hardhat/=node_modules/hardhat/",":solidity-bytes-utils/=node_modules/solidity-bytes-utils/",":solidity-stringutils/=lib/surl/lib/solidity-stringutils/",":surl/=lib/surl/"],"viaIR":true},"optimization_runs":200,"sourcify_repo_url":"https://repo.sourcify.dev/contracts/partial_match/1/0xC5184cccf85b81EDdc661330acB3E41bd89F34A1/","decoded_constructor_args":[["0xc07e000044F95655c11fda4cD37F70A94d7e0a7d",{"internalType":"address","name":"_core","type":"address"}],["0x0000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa2982000000000000000000000000cb7e25fbbd8afe4ce73d7dac647dbc3d847f3c8200000000000000000000000077777777729c405efb6ac823493e6111f0070d67000000000000000000000000000000000000000000000000000000000001731800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001388000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f05b59d3b20000",{"internalType":"bytes","name":"_configData","type":"bytes"}],["0x00000000000000000000000010101010e0c3171d894b71b3400668af311e7d94",{"internalType":"bytes","name":"_immutables","type":"bytes"}],["0x0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f726000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae3100000000000000000000000000000000000000000000000000000000000001b6000000000000000000000000000000000000000000000000000000000000002d5265737570706c792050616972202843757276654c656e643a206372765553442f7366727855534429202d203100000000000000000000000000000000000000",{"internalType":"bytes","name":"_customConfigData","type":"bytes"}]],"compiler_version":"0.8.28+commit.7893614a","is_verified_via_verifier_alliance":false,"verified_at":"2025-04-29T12:41:32.345919Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x6101a0806040523461088057617916803803809161001d8285610e6f565b83398101906080818303126108805761003581610e92565b60208201519091906001600160401b0381116108805783610057918301610eeb565b60408201519091906001600160401b0381116108805784610079918301610eeb565b60608201519094906001600160401b038111610880576100999201610eeb565b9160018060a01b0316928360805260015f5568056bc75e2d63100000600e5569021e19e0c9bab2400000600f55683635c9adc5dea00000601055602081805181010312610880576004906020906001600160a01b03906100fa908301610e92565b168060a05260405192838092637e062a3560e11b82525afa90811561088c575f91610dff575b506001600160a01b031660c0528051610100908201829003126108805761014960208201610e92565b61015560408301610e92565b9161016260608201610e92565b9260808201519360a08301519060c08401519261010060e08601519501519560018060a01b03168060e05260405163313ce56760e01b8152602081600481855afa90811561088c5760129160ff915f91610de0575b501603610d63576040516338d52e0f60e01b8152602081600481855afa90811561088c575f91610da1575b506001600160a01b031661010081905260405163313ce56760e01b815290602090829060049082905afa90811561088c5760129160ff915f91610d72575b501603610d6357610100516024916020916102459082906001600160a01b031661166b565b6040516363737ac960e11b8152670de0b6b3a7640000600482015292839182905afa90811561088c575f91610d31575b50601480546001600160801b031660809290921b6001600160801b031916919091179055601580546001600160a01b03199081166001600160a01b03938416179091556011805490911692909116919091179055600a55600c55600b55600d55600955604051610330808201906001600160401b03821183831017610c1a57602091839161750683393081520301905ff0801561088c57610120819052610324906001600160a01b03166114cb565b60015415610d1d5760015f525f5160206178b65f395f51905f52805460ff60a01b1916600160a01b179055805160208281019291610366919083010183610f08565b5050815191949190506001600160401b038111610c1a57601354600181811c91168015610d13575b6020821014610cff57601f8111610c9c575b50602094601f8211600114610c39579481929394955f92610c2e575b50508160011b915f199060031b1c1916176013555b5f604080516103df81610e39565b82815282602082015201526040516103f681610e39565b6014546001600160401b038082168352604082811c821660208501908152608084901c858301908152915190949093909290919060a0850190811185821017610c1a576040525f845260208401915f835260408501935f855260608601965f8852608087019660405161046881610e54565b5f8082526020820152885282516001600160401b03164211610a56575b511515958661091d575b5050505050505050506040516104a481610e39565b6015546001600160a01b03811680835260a09190911c60208301818152601654604085018181529194919242146109125750602060018060a01b0360e051166024604051809681936315caaba160e21b835260048301525afa92831561088c575f936108de575b5082156108ca57426001600160601b0381169094526ec097ce7bc90715b34b9f10000000009290920490819052905160a09290921b6001600160a01b0319166001600160a01b03929092169190911760155560168190556040519081527f4fc1b45960547ee95894b08a284c3c066cf5aca706a7420639c42c3ec2e118a490602090a15b6040516378e9792560e01b8152602081600481855afa90811561088c575f91610897575b5061014052604051630afaeebf60e31b815290602090829060049082905afa90811561088c575f91610853575b509160206105fa9261060f94610160528051010190610f08565b936001600160a01b03918216935091166114cb565b806107f4575b604051615d4d90816117b982396080518181816109ee01528181610a3501528181610b75015281816119ad01528181611ac101528181611bd601528181611f85015281816121bd0152818161235101528181612522015281816125a1015281816129130152818161297d015281816135db015281816137900152614972015260a05181818161048201528181611f340152818161267501528181612a1d01528181612ad6015281816149ba01528181614d4801528181614ead015281816150170152818161516301526153b0015260c05181818161139101528181613158015281816148680152615955015260e05181818161061501528181610b2b01528181610d3101528181610e7c01528181610ffe015281816113e601528181611de401528181612d2e0152818161310401528181613ed50152818161419e015281816146cd01528181614d19015281816155ba015261592d015261010051818181610ce101528181610fd5015281816116480152612243015261012051818181610654015281816128cd01526142b80152610140518181816120690152818161215601526126ef01526101605181818161217d0152612456015261018051818181611c5601528181612f0301528181613df201528181614c7e015261580b0152f35b7fa83ced135f4f6135be6fb52ae9183bf190452765f5b75b36caa332537c3ca7e591610835826020936101805282601d5560018060a01b0360e0511661166b565b61083d610fb3565b610845611277565b604051908152a15f80610615565b9290506020833d602011610884575b8161086f60209383610e6f565b8101031261088057915160206105e0565b5f80fd5b3d9150610862565b6040513d5f823e3d90fd5b90506020813d6020116108c2575b816108b260209383610e6f565b81010312610880575160046105b3565b3d91506108a5565b634e487b7160e01b5f52601260045260245ffd5b9092506020813d60201161090a575b816108fa60209383610e6f565b810103126108805751915f61050b565b3d91506108ed565b93505050505061058f565b97518151855187518b51604080516001600160401b0395861681526001600160801b039485166020828101919091529390951690850152909116606083015299610a2298509196907f6b9ef8676ff86d806b7a7bd7a9b0266910c9fce560c26289d7ed7cd7743127c790608090a18051604080518981526001600160401b039092168c8301527f939dcec711228d083924a0db6cecbb66bb8403ea7cdbfe2f928901cbac2cdfc191a1516001600160401b0380821690935290516001600160801b038116909552429091169182905260401b6fffffffffffffffff0000000000000000161760809290921b6001600160801b031916919091176014555060185461171e565b60185551805191015160801b6001600160801b0319166001600160801b0391909116176017555f808080808080808061048f565b60018152604051610a6681610e54565b6017546001600160801b038116825260801c6020820152885282516001600160401b031642908103908111610b795760115460e0518751604080516356fb8f2d60e01b81526001600160a01b039384166004820152602481018690526001600160801b0390921660448301529092909183916064918391165afa801561088c575f915f91610bb7575b506001600160801b039081168a526001600160401b039091168852895151670de0b6b3a764000092610b3792610b26921690610f62565b88516001600160401b031690610f62565b04808a528015159081610b95575b5015610b8d5788518851805190916001600160801b0391821690821601908111610b79576001600160801b03169052610485565b634e487b7160e01b5f52601160045260245ffd5b5f8952610485565b8951516001600160801b039250610baf919083169061171e565b11155f610b45565b9150506040813d604011610c12575b81610bd360409383610e6f565b81010312610880578051906001600160401b03821682036108805760200151906001600160801b03821682036108805790670de0b6b3a7640000610aef565b3d9150610bc6565b634e487b7160e01b5f52604160045260245ffd5b015190505f806103bc565b601f1982169560135f52805f20915f5b888110610c8457508360019596979810610c6c575b505050811b016013556103d1565b01515f1960f88460031b161c191690555f8080610c5e565b91926020600181928685015181550194019201610c49565b60135f527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a090601f830160051c81019160208410610cf5575b601f0160051c01905b818110610cea57506103a0565b5f8155600101610cdd565b9091508190610cd4565b634e487b7160e01b5f52602260045260245ffd5b90607f169061038e565b634e487b7160e01b5f52603260045260245ffd5b90506020813d602011610d5b575b81610d4c60209383610e6f565b8101031261088057515f610275565b3d9150610d3f565b630309cb8760e51b5f5260045ffd5b610d94915060203d602011610d9a575b610d8c8183610e6f565b810190610f75565b5f610220565b503d610d82565b90506020813d602011610dd8575b81610dbc60209383610e6f565b81010312610880576020610dd1600492610e92565b91506101e2565b3d9150610daf565b610df9915060203d602011610d9a57610d8c8183610e6f565b5f6101b7565b90506020813d602011610e31575b81610e1a60209383610e6f565b8101031261088057610e2b90610e92565b5f610120565b3d9150610e0d565b606081019081106001600160401b03821117610c1a57604052565b604081019081106001600160401b03821117610c1a57604052565b601f909101601f19168101906001600160401b03821190821017610c1a57604052565b51906001600160a01b038216820361088057565b9192916001600160401b038211610c1a5760405191610ecf601f8201601f191660200184610e6f565b829481845281830111610880578281602093845f96015e010152565b9080601f83011215610880578151610f0592602001610ea6565b90565b91906080838203126108805782516001600160401b0381116108805783019080601f83011215610880578151610f4092602001610ea6565b91610f4d60208201610e92565b916060610f5c60408401610e92565b92015190565b81810292918115918404141715610b7957565b90816020910312610880575160ff811681036108805790565b600154811015610d1d5760015f81815291901b5f5160206178b65f395f51905f520191565b305f5160206178765f395f51905f52148015611270575b8015611253575b6110d8575f5160206178765f395f51905f525f5260076020525f5160206178d65f395f51905f52546111d457600154600f8110156111a15768010000000000000000811015610c1a5780600161102a9201600155610f8e565b5080546001600160a01b0319165f5160206178765f395f51905f529081179091556001545f82815260076020525f5160206178d65f395f51905f52919091555f5160206178565f395f51905f529080a25f5160206178765f395f51905f523b156110da5760405163a9059cbb60e01b60208201523060248201525f60448201526110d8906110c581606481015b03601f198101835282610e6f565b5f5160206178765f395f51905f52611760565b565b5f5160206178765f395f51905f525f5260076020525f5160206178d65f395f51905f5254806111065750565b5f198101908111610b795761111a90610f8e565b5080546001600160a01b031673d533a949740bb3306d119cc777fa900ba034cd5119016111705780546001600160a01b03191690555f5160206178765f395f51905f525f5160206178965f395f51905f525f80a2565b60405162461bcd60e51b8152602060048201526009602482015268042dad2e6dac2e8c6d60bb1b6044820152606490fd5b60405162461bcd60e51b815260206004820152600b60248201526a6d6178207265776172647360a81b6044820152606490fd5b5f5160206178765f395f51905f525f5260076020525f5160206178d65f395f51905f52545f198101908111610b795761120c90610f8e565b5080546001600160a01b0316156112205750565b80546001600160a01b0319165f5160206178765f395f51905f529081179091555f5160206178565f395f51905f525f80a2565b5061126a5f5160206178765f395f51905f5261172b565b15610fd1565b505f610fca565b305f5160206178f65f395f51905f521480156114c4575b80156114a7575b6110d8575f5160206178f65f395f51905f525f5260076020525f5160206178365f395f51905f525461142857600154600f8110156111a15768010000000000000000811015610c1a578060016112ee9201600155610f8e565b5080546001600160a01b0319165f5160206178f65f395f51905f529081179091556001545f82815260076020525f5160206178365f395f51905f52919091555f5160206178565f395f51905f529080a25f5160206178f65f395f51905f523b156113925760405163a9059cbb60e01b60208201523060248201525f60448201526110d89061137f81606481016110b7565b5f5160206178f65f395f51905f52611760565b5f5160206178f65f395f51905f525f5260076020525f5160206178365f395f51905f5254806113be5750565b5f198101908111610b79576113d290610f8e565b5080546001600160a01b0316734e3fbd56cd56c3e72c1403e103b45db9da5b9d2a19016111705780546001600160a01b03191690555f5160206178f65f395f51905f525f5160206178965f395f51905f525f80a2565b5f5160206178f65f395f51905f525f5260076020525f5160206178365f395f51905f52545f198101908111610b795761146090610f8e565b5080546001600160a01b0316156114745750565b80546001600160a01b0319165f5160206178f65f395f51905f529081179091555f5160206178565f395f51905f525f80a2565b506114be5f5160206178f65f395f51905f5261172b565b15611295565b505f61128e565b6001600160a01b038116903082148015611663575b8015611653575b6115ad57815f52600760205260405f2054155f146115f957600154600f8110156111a15768010000000000000000811015610c1a5780600161152c9201600155610f8e565b508260018060a01b0319825416179055600154825f52600760205260405f2055815f5160206178565f395f51905f525f80a23b1561159a5760405163a9059cbb60e01b60208201523060248201525f60448083019190915281526110d891611595606483610e6f565b611760565b805f52600760205260405f2054806115b1575b5050565b5f198101908111610b79576115c590610f8e565b5080546001600160a01b03168290036111705780546001600160a01b03191690555f5160206178965f395f51905f525f80a2565b50805f52600760205260405f20545f198101908111610b795761161b90610f8e565b5080546001600160a01b031615611630575050565b80546001600160a01b031916821790555f5160206178565f395f51905f525f80a2565b5061165d8161172b565b156114e7565b5081156114e0565b6040519060205f8184019463095ea7b360e01b865260018060a01b03169485602486015281196044860152604485526116a5606486610e6f565b84519082855af15f513d826116f9575b5050156116c157505050565b6115956110d8936040519063095ea7b360e01b602083015260248201525f6044820152604481526116f3606482610e6f565b82611760565b90915061171657506001600160a01b0381163b15155b5f806116b5565b60011461170f565b91908201809211610b7957565b60e0516001600160a01b039182169116811461175b5760c0516001600160a01b03161461175757600190565b5f90565b505f90565b905f602091828151910182855af11561088c575f513d6117af57506001600160a01b0381163b155b61178f5750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b6001141561178856fe60806040526004361015610011575f80fd5b5f5f3560e01c80628cc2621461382357806302ce728f146137f557806306b6f7e91461377657806306fdde031461365957806308a0c375146135c157806308c7e366146135a45780630cab937d146130385780630df8dfac1461300f57806313966db514612ff1578063146a29eb14612fd15780631c6c959714612f505780632164e85b14612f325780632b3ba681146110be5780632cdacb5014612eed5780632f86556814612a9e57806333fd6f7414612a4b5780633f2617cb146129575780633f4ba83a146128fc57806342f43d0b146128b7578063476343ee1461264357806348741376146125795780634ac8eb5f1461255e5780634cae6513146124e45780634fd422df146124c057806354fd4d501461249757806356ecf28b1461247957806357d775f81461243e5780635e43c47b1461240957806360c52d05146123c05780636551f16c146123365780636b091695146122725780636f307dc31461222d578063730a7514146121a2578063757991a81461213b578063759cb53b1461210c57806375a410141461208c57806378e97925146120515780637adbf97314611f635780637b10399914611f1e5780637e92968414611bbb5780637ec4b57114611b7a5780638049d97114611afd5780638214ba4814611a835780638285ef4014611a5457806383d4433914611a1b5780638456cb591461199657806386993bef146119785780638cad7fbe146119395780638da5cb5b146109d85780638f50ea921461191b57806391ebebbd146118bc57806392bbcaed1461189e57806393ae0df91461187757806393f46f6414611831578063945c91421461180257806395d14ca8146117c05780639a295e731461177a5780639fe34bdc14611158578063a053db68146112af578063a36a363014611291578063ab7cfaf914611273578063acb70815146111f5578063b5af3062146111d1578063b5b5454714611198578063b68d0a091461115d578063b78294dd14611158578063b95c57461461113a578063c00007b0146110e1578063c0a7e892146110be578063c3192f14146110c3578063c49bb2d1146110be578063ca51bb59146110a0578063cacf3b5814611074578063cadac47914610f86578063cdd72d5214610f2c578063d41ddc9614610dee578063d619658b14610dd2578063d6bda0c014610bf4578063d870ce6614610b5a578063d8dfeb4514610b15578063e509b9d914610ad4578063e551d11d14610ab6578063e69bc27114610a71578063e7a3317414610a1d578063f2f4eb26146109d8578063f301af4214610982578063f384bd0514610964578063f5c7f89914610927578063f8112eed146108e6578063fbbbf94c146108ac578063fd6d0526146104325763fff5d9da1461040d575f80fd5b3461042f578060031936011261042f5760206104276140ee565b604051908152f35b80fd5b503461042f57608036600319011261042f5761044c6139b7565b90606435906024356001600160a01b0383168084036108a85761046d614145565b60405163e8673ef560e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561089d57849161085f575b506001600160a01b03163303610850578015908115610846575b5061083757600e548110610828576104ea6144d9565b505050604435670de0b6b3a764000003670de0b6b3a764000081116108145761051c670de0b6b3a76400009183613d36565b0493670de0b6b3a764000061053d6105348785613b9b565b600d5490613d36565b04946105498684613b9b565b90610552613c9e565b6001600160801b03815116838181119182156107ff575b50506107f0576001600160801b03610586818516828451166140ce565b169081815264e8d4a5100082029180830464e8d4a5100014901517156107525760208101916001600160801b0383511611610766575b51905160801b6001600160801b0319166001600160801b039190911617601755670de0b6b3a764000090610608905b6105f789601954613d67565b601955610602614163565b90613d36565b0495610613876157e2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169561064a908890886158e3565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016620186a088810290898204148915171561075257813b1561074e57869160248392604051948593849263140e25ad60e31b845260048401525af180156107435761072a575b5060408051948552602085018890528401526060830152600192916001600160a01b03909116907f76cd0cedf979345ca241ce6de696a520a8efc860c6c10d9db2a7953307c237fc90608090a255604080516001600160a01b039092168252602082019290925290819081015b0390f35b610735868092613a57565b61073f575f6106b9565b8480fd5b6040513d88823e3d90fd5b8680fd5b634e487b7160e01b87526011600452602487fd5b61076e615160565b600254600181018091116107dc576001600160801b036106089381670de0b6b3a76400009694846105eb956002557febad8099c467528a56c98b63c8d476d251cf1ffb4c75db94b4d23fa2b6a1e3358d80a28164e8d4a51000818551160416835294965050935050506105bc565b634e487b7160e01b88526011600452602488fd5b6316c6823f60e01b8652600486fd5b6108099250613b9b565b600f5411835f610569565b634e487b7160e01b83526011600452602483fd5b6362171e8f60e01b8252600482fd5b631e4ec46b60e01b8252600482fd5b905030145f6104d4565b63d520e5ad60e01b8352600483fd5b90506020813d602011610895575b8161087a60209383613a57565b810103126108915761088b90613d22565b5f6104ba565b8380fd5b3d915061086d565b6040513d86823e3d90fd5b8280fd5b503461042f578060031936011261042f57601554601654604080516001600160a01b038416815260a09390931c6020840152820152606090f35b503461042f57602036600319011261042f576109206109036139b7565b61091361090e61496f565b613f6e565b61091b614145565b615736565b6001815580f35b503461042f57604036600319011261042f576001906109586109476139b7565b61094f614145565b60243590615012565b55602060405160018152f35b503461042f578060031936011261042f576020600954604051908152f35b503461042f57602036600319011261042f576004359060015482101561042f5760606109ad83613b63565b506001815491015460ff6040519260018060a01b038116845260a01c16151560208301526040820152f35b503461042f578060031936011261042f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461042f57602036600319011261042f57610a63337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b610a6e600435614930565b80f35b503461042f57604036600319011261042f576040610a8d6139cd565b9160043581526004602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461042f578060031936011261042f576020600a54604051908152f35b503461042f57602036600319011261042f576020906001600160a01b03610af96139b7565b16815260088252604060018060a01b0391205416604051908152f35b503461042f578060031936011261042f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461042f57602036600319011261042f57600435610ba3337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b68056bc75e2d631000008110610be5576020817febc3aac103344d02f2e1b3fb50ca740929143c84082dd6e7698963e902aa636992600e55604051908152a180f35b630309cb8760e51b8252600482fd5b503461042f57606036600319011261042f57602435610c116139e3565b610c19614145565b610c22336142a5565b6001600160a01b03811615610dc357610c396144d9565b505050610c44614163565b5081610cd3575b610c609150610c5b60043561473e565b6152af565b906040610c6b613c70565b01610c77815133614335565b15610c8b5760208360018455604051908152f35b60649250610cad610c9a613c9e565b338452601b6020526040842054906143d7565b90338352601a6020526040832054905191633b49de0f60e21b8452600452602452604452fd5b602082610d05610d2c9430337f000000000000000000000000000000000000000000000000000000000000000061524b565b604051636e553f6560e01b8152600481019190915230602482015292839081906044820190565b0381867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1918215610db8578392610d7e575b50610d79610c6092339030614be4565b610c4b565b91506020823d602011610db0575b81610d9960209383613a57565b81010312610dac57905190610d79610d69565b5f80fd5b3d9150610d8c565b6040513d85823e3d90fd5b631e4ec46b60e01b8352600483fd5b503461042f578060031936011261042f576020604051600f8152f35b503461042f57604036600319011261042f57600435610e0b6139cd565b610e13614145565b610e1c336142a5565b6001600160a01b03168015610dc357610e336144d9565b505050338352601b6020526040832054610f1e575b610e53333084614659565b604051635d043b2960e11b815260048101929092526024820152306044820152602081606481857f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015610f1357610ee4575b506040610ebc613c70565b01610ec8815133614335565b15610ed557506001815580f35b90606491610cad610c9a613c9e565b610f059060203d602011610f0c575b610efd8183613a57565b810190613ce8565b505f610eb1565b503d610ef3565b6040513d84823e3d90fd5b610f26614163565b50610e48565b503461042f578060031936011261042f57610f45613ba8565b506080610f5061402c565b915091506001600160801b0360208183511692015116610f6e613dcc565b91604051938452602084015260408301526060820152f35b503461042f57604036600319011261042f57600435610fa36139cd565b90610fac614145565b6001600160a01b03821615610dc357906020610ff992610fca6144d9565b505050610d058130337f000000000000000000000000000000000000000000000000000000000000000061524b565b0381867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015610db8578390611040575b610920925030614be4565b506020823d60201161106c575b8161105a60209383613a57565b81010312610dac576109209151611035565b3d915061104d565b503461042f578060031936011261042f5761072661109061402c565b9060409492945194859485613a87565b503461042f578060031936011261042f576020601c54604051908152f35b613ae1565b503461042f578060031936011261042f576020601854604051908152f35b503461042f57602036600319011261042f576110fb6139b7565b611103614145565b6001600160a01b0381811683526008602052604083205416801561112a5761092091614eab565b508061113591614eab565b610920565b503461042f578060031936011261042f576020600154604051908152f35b613b2f565b503461042f57602036600319011261042f5760406111796139b7565b61118b61118582613fab565b91613f10565b9082519182526020820152f35b503461042f57602036600319011261042f576020906040906001600160a01b036111c06139b7565b168152600383522054604051908152f35b503461042f57602036600319011261042f5760206104276111f06139b7565b613fab565b503461042f57604036600319011261042f576004356112126139cd565b61121a614145565b6001600160a01b03811615610dc35760209261126a60019261123a6144d9565b505050611245613c9e565b61124f86826143d7565b9561126261125c8861473e565b9161473e565b90339261476f565b55604051908152f35b503461042f578060031936011261042f576020600d54604051908152f35b503461042f578060031936011261042f576020600c54604051908152f35b503461042f5760a036600319011261042f576112c96139b7565b60243591906064356044356084356001600160401b03811161073f573660238201121561073f5780600401356112fe81613b4c565b9161130c6040519384613a57565b818352602083016024819360051b8301019136831161177657602401905b82821061175e5750505061133c614145565b611345336142a5565b859061134f6144d9565b50505061135a614163565b506001600160a01b0386168088526012602052604088205490969060ff161561174f576001600160a01b0361138e85613c1b565b517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169116819003611739575083515f198101908111611725576001600160a01b03906113e39086613c28565b517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169291168290036116e9578561163e575b61142b90610c5b8b61473e565b93604051926370a0823160e01b8452306004850152602084602481865afa938415611633578a946115ff575b50883b156115fb57604051634b4ecc5560e11b8152336004820152602481018c9052608060448201529151608483018190528a90839060a4820190835b8181106115d6575050819293503060648301520381838c5af180156115cb579089916115b2575b5050906020602492604051938480926370a0823160e01b82523060048301525afa80156115a7578890611573575b6114f39250613b9b565b9380851061155c5750836115119161150c338330614be4565b613d67565b9560405194855260208501526040840152606083015260808201527fb19ca0df3f3a01af950d8e6ad62aeff167cf14c73e98af6c52afef1add5c97ed60a03392a26040610c6b613c70565b633b5d56ed60e11b87526004526024849052604486fd5b506020823d60201161159f575b8161158d60209383613a57565b81010312610dac576114f391516114e9565b3d9150611580565b6040513d8a823e3d90fd5b816115bc91613a57565b6115c757875f6114bb565b8780fd5b6040513d8b823e3d90fd5b85516001600160a01b031683526020958601958f955087945090920191600101611494565b8980fd5b9093506020813d60201161162b575b8161161b60209383613a57565b81010312610dac5751925f611457565b3d915061160e565b6040513d8c823e3d90fd5b925061166c8530337f000000000000000000000000000000000000000000000000000000000000000061524b565b604051636e553f6560e01b8152600481018690523060248201526020816044818c865af180156115cb5789906116b5575b61142b91506116ad338230614be4565b93905061141e565b506020813d6020116116e1575b816116cf60209383613a57565b81010312610dac5761142b905161169d565b3d91506116c2565b8489838251925f198401938411610814576044936001600160a01b03916117109190613c28565b51169063b0b3262d60e01b8352600452602452fd5b634e487b7160e01b89526011600452602489fd5b60449089906001600160a01b0361171088613c1b565b631311dc6d60e01b8852600488fd5b6020809161176b846139f9565b81520191019061132a565b8880fd5b503461042f578060031936011261042f576080906040519050620186a08152620186a06020820152670de0b6b3a76400006040820152670de0b6b3a76400006060820152f35b503461042f578060031936011261042f576060601454604051906001600160401b03811682526001600160401b038160401c16602083015260801c6040820152f35b503461042f578060031936011261042f57602060405173d533a949740bb3306d119cc777fa900ba034cd528152f35b503461042f5760209061184336613b03565b9192509015611861576104279161185861402c565b925050506146f8565b6118729161186d613c9e565b6146f8565b610427565b503461042f578060031936011261042f57602061042761189561402c565b92505050615209565b503461042f578060031936011261042f576020600f54604051908152f35b503461042f57606036600319011261042f576118d66139cd565b60406118e06139e3565b9260043581526005602052209060018060a01b03165f5260205260405f209060018060a01b03165f52602052602060405f2054604051908152f35b503461042f578060031936011261042f576020600e54604051908152f35b503461042f57602036600319011261042f5760209060ff906040906001600160a01b036119646139b7565b168152601284522054166040519015158152f35b503461042f578060031936011261042f576020601d54604051908152f35b503461042f578060031936011261042f576119db337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b600a54806119e7575080f35b601e5580600a557fbf1ce7fb3a8e648b70ea830f99b52f7ea31554186d29763280751f42e77f63866020604051838152a180f35b503461042f57602036600319011261042f576020906040906001600160a01b03611a436139b7565b168152600783522054604051908152f35b503461042f578060031936011261042f5760406017548151906001600160801b038116825260801c6020820152f35b503461042f57602036600319011261042f577fc98711414b05c67ac27ffb415026d97ad5094c5490747891a834cb44f64940d96020600435611aef337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b80600f55604051908152a180f35b503461042f57604036600319011261042f57611b176139cd565b611b1f614145565b611b28336142a5565b6001600160a01b0381161561083757611b6290611b436144d9565b505050338352601b6020526040832054611b6c575b3390600435614659565b6040610ebc613c70565b611b74614163565b50611b58565b503461042f57602090611b8c36613b03565b9192509015611baa5761042791611ba161402c565b92505050614475565b61187291611bb6613c9e565b614475565b503461042f57602036600319011261042f57600435611c04337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b81601d54828103611c3f575b507fa83ced135f4f6135be6fb52ae9183bf190452765f5b75b36caa332537c3ca7e5602083604051908152a180f35b604051631526fe2760e01b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169060c081602481855afa908115610db8578391611ee9575b506040516370a0823160e01b8152306004820152906001600160a01b0316602082602481845afa91821561089d578492611eb2575b5081611d95575b5090606460209260405194859384926321d0683360e11b84528860048501526024840152600160448401525af18015610db857611d37575b50601d819055817fa83ced135f4f6135be6fb52ae9183bf190452765f5b75b36caa332537c3ca7e5611c10565b6020813d602011611d8d575b81611d5060209383613a57565b810103126108a8577fa83ced135f4f6135be6fb52ae9183bf190452765f5b75b36caa332537c3ca7e591611d85602092613cf7565b509150611d0a565b3d9150611d43565b60209060446040959394955180948193636197390160e11b83528760048401528160248401525af18015611e7057611e7b575b506040516370a0823160e01b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015611e705782918691611e3b575b5010611e2c579083915f611cd2565b6346bc68ed60e01b8452600484fd5b9150506020813d602011611e68575b81611e5760209383613a57565b81010312610dac578190515f611e1d565b3d9150611e4a565b6040513d87823e3d90fd5b6020813d602011611eaa575b81611e9460209383613a57565b8101031261073f57611ea590613cf7565b611dc8565b3d9150611e87565b935090506020833d602011611ee1575b81611ecf60209383613a57565b81010312610dac57849251905f611ccb565b3d9150611ec2565b611f0b915060c03d60c011611f17575b611f038183613a57565b810190613d74565b5050925050505f611c96565b503d611ef9565b503461042f578060031936011261042f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461042f57602036600319011261042f576040611f7f6139b7565b611fb3337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b612021611fbe613c70565b805184516001600160a01b03918216815290841660208201529092907fb9d23ad01dc54c1fad84c770708fbe314a369b505c073949334dad786229805e90604090a16001600160a01b0316808352601580546001600160a01b0319169091179055565b6020810151601580546001600160a01b031660a09290921b6001600160a01b031916919091179055015160165580f35b503461042f578060031936011261042f5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461042f57602036600319011261042f576120a66139b7565b6120ae614145565b3380835260086020908152604080852080546001600160a01b0319166001600160a01b039590951694851790555192835290917ff4239ad0860f93469699dd4be8040b8838c5e25bb6cf24a1dfb381b937ff078c9190a26001815580f35b503461042f578060031936011261042f576020604051734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b8152f35b503461042f578060031936011261042f57602061042761217b7f000000000000000000000000000000000000000000000000000000000000000042613b9b565b7f000000000000000000000000000000000000000000000000000000000000000090613d49565b503461042f57602036600319011261042f576004356121eb337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b620186a08111610be5577f1f93e1cc6afaef2ddc4d7ef7b0f45ac3278d548338c839e9be18695732a662746040600c548151908152836020820152a1600c5580f35b503461042f578060031936011261042f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461042f57604036600319011261042f5761228c6139b7565b6122946139cd565b61229c614145565b6001600160a01b0382163303612309576001600160a01b038116156122c45761092091614eab565b60405162461bcd60e51b815260206004820152601760248201527f66776420616464726573732063616e6e6f7420626520300000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152600560248201526410b9b2b63360d91b6044820152606490fd5b503461042f57602036600319011261042f5760043561237f337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b670de0b6b3a76400008111610be5576020817f3e0c428758b3ad6ab4fd85e8257e4eee404fb36e80c0251143635b549cd70b8892600d55604051908152a180f35b503461042f57604036600319011261042f576123da6139cd565b6123e2614145565b6001600160a01b0381161561083757610920906123fd6144d9565b50505060043533614be4565b503461042f57602036600319011261042f576109206124266139b7565b61243161090e61496f565b612439614145565b614a3b565b503461042f578060031936011261042f5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461042f578060031936011261042f576020600254604051908152f35b503461042f578060031936011261042f5760609060405190600382528060208301526040820152f35b503461042f57602036600319011261042f5760206104276124df6139b7565b613f10565b503461042f57602036600319011261042f577f18e1a8f58cc03bc99f69c27336072db255c3f01827f2923f654ddc209e2b8db56020600435612550337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b80601055604051908152a180f35b503461042f578060031936011261042f576020610427613dcc565b503461042f57604036600319011261042f576125936139b7565b61259b613a78565b6125cf337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b612633575b601154604080516001600160a01b038084168252841660208201529192917f74cd8ef76f78382ae0f3ee4e21117be974af0041a24dc98f7aa8ddabb0b2960c9190a16001600160a01b03166001600160a01b0319919091161760115580f35b61263b6144d9565b5050506125d4565b503461042f578060031936011261042f5761265c614145565b6126646144d9565b5050604051630abca72960e41b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169150602081600481855afa908115610db857839161287d575b506040516379bd9e4160e01b81526001600160a01b03821690602081600481855afa908115611e7057859161284b575b5061271461217b7f000000000000000000000000000000000000000000000000000000000000000042613b9b565b90601c54821190811591612840575b5061283157601c5583601854936019549382601855826019556127468587613d67565b823b15610891576040516340c10f1960e01b81526001600160a01b0392909216600483015260248201529082908290604490829084905af18015610f135761281c575b5050803b15610891576040516362f2221960e01b8152836004820152826024820152848160448183865af18015611e7057612807575b506040937f9cc800ba322ea82ab3e1e911dd4ccd84129687c4952f4ee2f937e3ac68755131606060019387519081528660208201528588820152a15582519182526020820152f35b612812858092613a57565b610891575f6127bf565b8161282691613a57565b61089157835f612789565b630e1b248d60e01b8552600485fd5b90508114155f612723565b90506020813d602011612875575b8161286660209383613a57565b81010312610dac57515f6126e6565b3d9150612859565b90506020813d6020116128af575b8161289860209383613a57565b810103126108a8576128a990613d22565b5f6126b6565b3d915061288b565b503461042f578060031936011261042f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461042f578060031936011261042f57612941337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b600a541561294c5780f35b610a6e601e54614930565b503461042f57604036600319011261042f576129716139b7565b612979613a78565b90337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316148015612a19575b15612a0a577fea1eefb4fd58778d7b274fe54045a9feeec8f2847899c2e71126d3a74d486da59160409160018060a01b03169081855260126020528285209015159060ff1981541660ff831617905582519182526020820152a180f35b631d1e647b60e01b8352600483fd5b50337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146129ad565b503461042f57604036600319011261042f576040612a676139b7565b91612a706139cd565b9260018060a01b031681526006602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461042f57602036600319011261042f57612ab86139b7565b612ac0614145565b60405163d25adeb360e01b8152906020826004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa918215610db8578392612eb1575b506001600160a01b0382169133839003612ea2576001600160a01b0382168015612e9357612b3a6144d9565b505050612b45614163565b612b4e846142a5565b612b588185614335565b612e8457612b64613c9e565b90828752601a602052604087205490838852601b602052612b88604089205461473e565b926001600160801b0384169260208201926001600160801b03845116155f14612ded57612bbe670de0b6b3a76400009186613d36565b04600c54620186a0019081620186a011612dd9576001600160801b0398969492620186a0612bf5612c739d9c9a9896948c94613d36565b0481811115612dcf57509a8b955b877f158ba9ab7bbbd08eeffa4753bad41f4d450e24831d293427308badf3eadd8c766060612c39612c348a896143d7565b61473e565b9d8e6040519b8c528a60208d015216998a6040820152a2612c598a614d44565b82612c678c828751166140ce565b168452828551166140ce565b168252848b52601b602052612c8c8360408d2054613b9b565b858c52601b6020528060408d20558015159081612dba575b50612dab5751905160801b6001600160801b0319166001600160801b03919091161760175588969594612d109490939092909188917fe4a1ae657f49cb1fb1c7d3a94ae6093565c4c8c0e03de488f79c377c3c3a24e0916040919082519182526020820152a386614659565b813b156108a857604051632be71c5f60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166004820152602481018590526001600160801b0391909116604482015291908290606490829084905af18015610db857612d92575b50600160209255604051908152f35b612d9d838092613a57565b612da7575f612d83565b5080fd5b631abfe8a760e01b8b5260048bfd5b612dc59150826143d7565b601054115f612ca4565b90509a8b95612c03565b634e487b7160e01b8c52601160045260248cfd5b612e15612e046001600160801b0385511687613d36565b6001600160801b0386511690613d49565b8b80612e54575b612e34575b670de0b6b3a764000091612bbe91613d36565b6001810180911115612e2157634e487b7160e01b8c52601160045260248cfd5b5085612e7e612e6d6001600160801b0388511684613d36565b6001600160801b0387511690613d49565b10612e1c565b633af2cafd60e11b8652600486fd5b631e4ec46b60e01b8552600485fd5b6387e9041360e01b8452600484fd5b9091506020813d602011612ee5575b81612ecd60209383613a57565b810103126108a857612ede90613d22565b905f612b0e565b3d9150612ec0565b503461042f578060031936011261042f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461042f578060031936011261042f576020601954604051908152f35b503461042f57602036600319011261042f576004358015158103612da757612f76613d04565b50610726604051612f8681613a0d565b5f81525f6020820152612f97614145565b83612fa06144d9565b96915094612fb9575b6001905560405194859485613a87565b9150506018546001612fc9613c9e565b929050612fa9565b503461042f578060031936011261042f57602060405164e8d4a510008152f35b503461042f578060031936011261042f576020600b54604051908152f35b503461042f578060031936011261042f576011546040516001600160a01b039091168152602090f35b5034610dac576080366003190112610dac576130526139b7565b60443591906064356024356001600160401b038211610dac5736602383011215610dac578160040135926001600160401b038411610dac576024830192602436918660051b010111610dac576130a6614145565b6130af336142a5565b6130b76144d9565b5050506130c2614163565b506130cb613c9e565b9260018060a01b03821694855f52601260205260ff60405f20541615613595578015613581576130fa82613cd4565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911681900361357857505f198101928184116135645761314e613149858486613cc4565b613cd4565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811695911685900361353257506001600160801b0386511615613523576131a090339086614659565b6040516370a0823160e01b815230600482015291602083602481875afa9283156134b6575f936134ef575b50863b15610dac57604051634b4ecc5560e11b815233600482015260248101869052608060448201526084810183905291829160a48301915f5b8181106134c15750505090805f923060648301520381838a5af180156134b6576134a1575b506040516370a0823160e01b8152306004820152602081602481865afa80156133ed578290889061346b575b6132609250613b9b565b968088106134545750856001600160801b03855116155f14613410575086935b338752601b60205260408720548086116133f8575b506132b6906132a38961473e565b339130916132b08961473e565b9161476f565b6040516370a0823160e01b8152306004820152602081602481865afa9081156133ed57908793929184916133b4575b50906132f091613b9b565b8061333f575b505050604051928352602083015283604083015260608201527f6b2b212085c14b2dc48ec56d19c05084e5d8ef233539cdd3dc0d70a4ec7f4f9e60803392a26040610c6b613c70565b60405163a9059cbb60e01b815233600482015260248101919091529160209183916044918391905af18015611e705761337b575b8085916132f6565b6020813d6020116133ac575b8161339460209383613a57565b8101031261073f576133a590613cf7565b505f613373565b3d9150613387565b919350506020813d6020116133e5575b816133d160209383613a57565b81010312610dac57518692906132f06132e5565b3d91506133c4565b6040513d89823e3d90fd5b945096506132b661340985896143d7565b9790613295565b9361343c61342b6001600160801b036020840151168a613d36565b6001600160801b0383511690613d49565b94156132805793600181018091116107525793613280565b633b5d56ed60e11b87526004526024879052604486fd5b50506020813d602011613499575b8161348660209383613a57565b81010312610dac57816132609151613256565b3d9150613479565b6134ae9196505f90613a57565b5f945f61322a565b6040513d5f823e3d90fd5b9193509160019060209081906001600160a01b036134de886139f9565b168152019401910191849392613205565b9092506020813d60201161351b575b8161350b60209383613a57565b81010312610dac5751915f6131cb565b3d91506134fe565b631abfe8a760e01b5f5260045ffd5b90506131499161354193613cc4565b63b0b3262d60e01b5f9081526004929092526001600160a01b0316602452604490fd5b634e487b7160e01b5f52601160045260245ffd5b61354183613cd4565b634e487b7160e01b5f52603260045260245ffd5b631311dc6d60e01b5f5260045ffd5b34610dac575f366003190112610dac576020601054604051908152f35b34610dac576020366003190112610dac57600435613609337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b620186a0811161364a577fe796e9ae748449310fcd1cc6718aab236c9b8d2e0e04dacb232ba564d5b338cc60406009548151908152836020820152a1600955005b630309cb8760e51b5f5260045ffd5b34610dac575f366003190112610dac576040515f90601354918260011c6001841693841561376c575b60208210851461375857818452602084019490811561373d57506001146136df575b50906136b4816040930382613a57565b8151928391602083525180918160208501528484015e5f828201840152601f01601f19168101030190f35b91905060135f527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a090915f905b808210613723575090915081016020016136b46136a4565b91926001816020925483858801015201910190929161370b565b60ff1916855250151560051b820160200190506136b46136a4565b634e487b7160e01b5f52602260045260245ffd5b90607f1690613682565b34610dac576020366003190112610dac576004356137be337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613c3c565b7f388cba11a61d4b31467a533c88eef75abfb6097ff2ab4652d086560fffcc2f836040600b548151908152836020820152a1600b55005b34610dac575f366003190112610dac5761380d614145565b6020613817614163565b60015f55604051908152f35b34610dac576020366003190112610dac5761383c6139b7565b613844614145565b61384d81614d44565b60015461385981613bc0565b916001600160a01b03165f5b8281106139405760015f5583515f19810190859082116135645761388882613bc0565b9160015b818111156138ee57836040518091602082016020835281518091526020604084019201905f5b8181106138c0575050500390f35b825180516001600160a01b0316855260209081015181860152869550604090940193909201916001016138b2565b60206138fa8285613c28565b510151905f1981018181116135645760019260206139188389613c28565b510152613938838060a01b0361392e8488613c28565b5151169187613c28565b51520161388c565b8061394c600192613b63565b5054828060a01b0381169081159081156139a9575b506139a157805f52600660205260405f20845f5260205260405f205460206139898489613c28565b5101526139968287613c28565b515201915b91613865565b50019161399b565b60ff915060a01c1687613961565b600435906001600160a01b0382168203610dac57565b602435906001600160a01b0382168203610dac57565b604435906001600160a01b0382168203610dac57565b35906001600160a01b0382168203610dac57565b604081019081106001600160401b03821117613a2857604052565b634e487b7160e01b5f52604160045260245ffd5b606081019081106001600160401b03821117613a2857604052565b90601f801991011681019081106001600160401b03821117613a2857604052565b602435908115158203610dac57565b926001600160801b0391959460209183604060c09660e089019a89526001600160401b03815116868a01526001600160401b038682015116828a0152015116606087015260808601528281511660a0860152015116910152565b34610dac575f366003190112610dac576020604051670de0b6b3a76400008152f35b6060906003190112610dac57600435906024358015158103610dac57906044358015158103610dac5790565b34610dac575f366003190112610dac576020604051620186a08152f35b6001600160401b038111613a285760051b60200190565b6001548110156135815760015f81815291901b7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60191565b9190820391821161356457565b60405190613bb582613a0d565b5f6020838281520152565b90613bca82613b4c565b613bd76040519182613a57565b8281528092613be8601f1991613b4c565b01905f5b828110613bf857505050565b602090604051613c0781613a0d565b5f81525f8382015282828501015201613bec565b8051156135815760200190565b80518210156135815760209160051b010190565b15613c4357565b60405162461bcd60e51b815260206004820152600560248201526421636f726560d81b6044820152606490fd5b60405190613c7d82613a3c565b6015546001600160a01b038116835260a01c60208301526016546040830152565b60405190613cab82613a0d565b6017546001600160801b038116835260801c6020830152565b91908110156135815760051b0190565b356001600160a01b0381168103610dac5790565b90816020910312610dac575190565b51908115158203610dac57565b60405190613d1182613a3c565b5f6040838281528260208201520152565b51906001600160a01b0382168203610dac57565b8181029291811591840414171561356457565b8115613d53570490565b634e487b7160e01b5f52601260045260245ffd5b9190820180921161356457565b91908260c0910312610dac57613d8982613d22565b91613d9660208201613d22565b91613da360408301613d22565b91613db060608201613d22565b91613dc960a0613dc260808501613d22565b9301613cf7565b90565b601d548015613eb957604051631526fe2760e01b8152600481019190915260c0816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156134b6576024916020915f91613e94575b506040516370a0823160e01b815230600482015292839182906001600160a01b03165afa9081156134b6575f91613e65575090565b90506020813d602011613e8c575b81613e8060209383613a57565b81010312610dac575190565b3d9150613e73565b613ead915060c03d60c011611f1757611f038183613a57565b5050925050505f613e30565b506040516370a0823160e01b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156134b6575f91613e65575090565b6001600160a01b03165f908152601b6020908152604080832054600254600390935292205491929190808210613f44575050565b909264e8d4a510006001915b04930192818414613f695764e8d4a51000600191613f50565b925050565b15613f7557565b60405162461bcd60e51b815260206004820152600e60248201526d10b932bbb0b93226b0b730b3b2b960911b6044820152606490fd5b613fb3614145565b613fbc816142a5565b6001600160a01b03165f908152601a6020526040902054613fdb613dcc565b9081811115613fed57505b9060015f55565b9050613fe6565b6040519061400182613a3c565b8160406014546001600160401b03811683526001600160401b0381831c16602084015260801c910152565b5f614035613d04565b5060405161404281613a0d565b5f81525f602082015250614054613ff4565b906001600160401b034216825261406a82615507565b8051909190156140bf57506060810151926001600160401b0360208301511660208401526001600160801b03604083015116604084015260806140b96018546001600160801b03871690613d67565b92015190565b92905060185490613dc9613c9e565b906001600160801b03809116911603906001600160801b03821161356457565b600a548015614138576001600160801b0361410761402c565b92505050511690670de0b6b3a7640000820291808304670de0b6b3a7640000149015171561356457613dc991613d49565b50670de0b6b3a764000090565b60025f54146141545760025f55565b633ee5aeb560e01b5f5260045ffd5b61416b613c70565b9060208201916001600160601b038351164214155f1461429d5780516040516315caaba160e21b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015290929160209184916024918391165afa9182156134b6575f92614269575b508115613d53576001600160601b03429081169094526ec097ce7bc90715b34b9f1000000000919091046040808301829052915160a09490941b6001600160a01b0319166001600160a01b03909416939093176015556016839055518281527f4fc1b45960547ee95894b08a284c3c066cf5aca706a7420639c42c3ec2e118a490602090a1565b9091506020813d602011614295575b8161428560209383613a57565b81010312610dac5751905f6141e2565b3d9150614278565b604001519150565b6142ae81614d44565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081165f90815260066020908152604080832094909316808352938152828220805490839055601a9091529190205490620186a0900480821061432c5761431c91613b9b565b905b5f52601a60205260405f2055565b50505f9061431e565b906009549182156143cf5761436b61434b613c9e565b6001600160a01b039092165f818152601b602052604090205490926143d7565b9081156143c6575f52601a60205260405f20549182156143be5761438e91613d36565b90620186a0820291808304620186a0149015171561356457670de0b6b3a76400006143b99204613d49565b111590565b505050505f90565b50505050600190565b505050600190565b6020810180516001600160801b03166143f0575050905b565b90929161441b61440a6001600160801b0386511683613d36565b6001600160801b0384511690613d49565b936001600160801b0381511615159283614448575b50505061443957565b90600181018091116135645790565b61446c9293506144636001600160801b038092511687613d36565b91511690613d49565b105f8080614430565b909160208201916001600160801b03835116155f146144945750505090565b6144b0612e6d6001600160801b03839796949597511684613d36565b94836144c5575b836144485750505061443957565b81516001600160801b0316151593506144b7565b5f905f906144e5613d04565b506144ee613ff4565b906144f882615507565b8051151580614505575050565b9194509250926143ee6001600160801b03602060806060870151968287016001600160401b0381511690604089019186835116907f6b9ef8676ff86d806b7a7bd7a9b0266910c9fce560c26289d7ed7cd7743127c786888701926001600160401b038451169460408901958c875116916040519384528c84015260408301526060820152a17f939dcec711228d083924a0db6cecbb66bb8403ea7cdbfe2f928901cbac2cdfc160408d6001600160401b0384511682519182528a820152a151916001600160401b0383169052519186831690526001600160401b034216808a526fffffffffffffffff00000000000000006014549260401b169187191617176014558460145491811990821990861b161691161760145561462888601854613d67565b601855015182815116831960175416176017550151166001600160801b036017549181199060801b16911617601755565b9160207fba68c7a8c8efbddb7e938ee32ecc28a68930c18105a3a0ab9563eac7f051cf5a9160018060a01b031693845f52601a825260405f2061469d828254613b9b565b90556146a8816157e2565b6001600160a01b03841693813086036146c7575b5050604051908152a3565b6146f1917f00000000000000000000000000000000000000000000000000000000000000006158e3565b5f816146bc565b90916001600160801b03825116155f1461471157505090565b9092916020840161472f612e6d6001600160801b0383511684613d36565b94836144485750505061443957565b6001600160801b038111614758576001600160801b031690565b6306dfcc6560e41b5f52608060045260245260445ffd5b9391909161477c81614d44565b6001600160801b0361479184828851166140ce565b16855260208501906001600160801b036147ae84828551166140ce565b16825260018060a01b031694855f52601b6020526147db6001600160801b0360405f205494168094613b9b565b865f52601b6020528060405f2055801515908161491b575b506135235751905160801b6001600160801b0319166001600160801b0391909116176017556001600160a01b0383169283614865575b507fe4a1ae657f49cb1fb1c7d3a94ae6093565c4c8c0e03de488f79c377c3c3a24e0916040916001600160801b038351921682526020820152a3565b917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610dac57604051632770a7eb60e21b81526001600160a01b039490941660048501526001600160801b03821660248501525f908490604490829084905af19182156134b6577fe4a1ae657f49cb1fb1c7d3a94ae6093565c4c8c0e03de488f79c377c3c3a24e09360409361490b575b50915091614829565b5f61491591613a57565b5f614902565b6149269150826143d7565b601054115f6147f3565b6001600160801b03811161364a576020817fbf1ce7fb3a8e648b70ea830f99b52f7ea31554186d29763280751f42e77f638692600a55604051908152a1565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480156149a45790565b5060405163670fb82160e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156134b6575f91614a01575b506001600160a01b0316331490565b90506020813d602011614a33575b81614a1c60209383613a57565b81010312610dac57614a2d90613d22565b5f6149f2565b3d9150614a0f565b6001600160a01b038116903082148015614bdc575b8015614bcc575b614b9257815f52600760205260405f2054155f14614b5e57600154600f811015614b2b5768010000000000000000811015613a2857806001614a9c9201600155613b63565b50826001600160601b0360a01b825416179055600154825f52600760205260405f2055817fb13fd610fe4e1b384966826794a9b2f6100ad031f352cc5ec6f22667f60749805f80a2803b15614b2157506143ee906040519063a9059cbb60e01b60208301523060248301525f604483015260448252614b1c606483613a57565b615ce8565b6143ee9150615736565b60405162461bcd60e51b815260206004820152600b60248201526a6d6178207265776172647360a81b6044820152606490fd5b50805f52600760205260405f20545f19810190811161356457614b8090613b63565b5080546001600160a01b031615614b96575b5050565b80546001600160a01b031916821790557fb13fd610fe4e1b384966826794a9b2f6100ad031f352cc5ec6f22667f60749805f80a2565b50614bd68161591f565b15614a57565b508115614a50565b9160018060a01b031691825f52601a60205260405f20614c05838254613d67565b905581306001600160a01b03831603614d11575b5050601d5480614c52575b5060207f2ac90482c3b6bea30a2c085cf093016bad7f970d91c5fd233e6b848d3e231dc391604051908152a2565b6040516321d0683360e11b8152600481019190915260248101829052600160448201526020816064815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af180156134b65715614c24576020813d602011614d09575b81614ccc60209383613a57565b81010312610dac577f2ac90482c3b6bea30a2c085cf093016bad7f970d91c5fd233e6b848d3e231dc391614d01602092613cf7565b509150614c24565b3d9150614cbf565b614d3d9130907f000000000000000000000000000000000000000000000000000000000000000061524b565b5f81614c19565b5f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610dac575f8091602460405180948193633bd73ee360e21b83523060048401525af180156134b657614e96575b506002549060015490835b5f198110614dba575050505050565b836001600160a01b03831680614e4d575b865b858110614e26575085821015614e1d57808752601b60205264e8d4a51000604088205404818852601b60205260408820556001820180921161075257865260036020526040862055600101614dab565b50505050505050565b80614e3e89876001948b889c999d9e9a979b98615990565b01919490939796929591614dcd565b8087526003602052604087205491508582141580614e82575b15614dcb57905084908087526003602052856040882055614dcb565b50808752601b602052604087205415614e66565b614ea39192505f90613a57565b5f905f614da0565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691823b15610dac57604051633bd73ee360e21b81525f816024818380983060048401525af180156134b657614ffd575b506002549160015492845b5f198110614f2057505050505050565b816001600160a01b03841680614fb4575b875b878110614f8d575083821015614f8357808852601b60205264e8d4a51000604089205404818952601b6020526040892055600182018092116107dc57875260036020526040872055600101614f10565b5050505050505050565b80614fa5888860019489889d999e9f9b979c98615990565b01929691959094989792614f33565b8088526003602052604088205491508382141580614fe9575b15614f3157905082908088526003602052836040892055614f31565b50808852601b602052604088205415614fcd565b61500a9193505f90613a57565b5f915f614f05565b5f91907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610dac575f8091602460405180948193633bd73ee360e21b83523060048401525af180156134b65761514b575b506002549060015491845b84811061508957505050505050565b816001600160a01b03841680615102575b875b8681106150ec575083821015614f8357808852601b60205264e8d4a51000604089205404818952601b6020526040892055600182018092116107dc5787526003602052604087205560010161507a565b806150fc8a886001948988615990565b0161509c565b8088526003602052604088205491508382141580615137575b1561509a5790508290808852600360205283604089205561509a565b50808852601b60205260408820541561511b565b6151589193505f90613a57565b5f915f61506f565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610dac575f8091602460405180948193633bd73ee360e21b83523060048401525af180156134b6576151f6575b5060025460015491905f1982106151d157505050565b815b8381106151e05750505050565b806151f084806001948680615990565b016151d3565b61520291505f90613a57565b5f5f6151bb565b600a5490516001600160801b0316808211156152435761522891613b9b565b6001600160801b03811115613dc957506001600160801b0390565b50505f615228565b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526143ee91614b1c608483613a57565b906001600160801b03809116911601906001600160801b03821161356457565b9190916152ba613c9e565b92601054916001600160801b03811692831061352357600b54620186a00180620186a011613564576152f0620186a09185613d36565b046152fa86615209565b8181106154f2575085516001600160801b031661549357805b61537b82976001600160801b036020820191816153546153368883875116613d67565b8261534c6153438a61473e565b8287511661528f565b16845261473e565b1692839052516001600160801b0391161660809190911b6001600160801b03191617601755565b335f52601b60205260405f20615392838254613d67565b9055848082111561548a576153a691613b9b565b915b82615476575b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610dac576040516340c10f1960e01b81526001600160a01b03861660048201526001600160801b039290921660248301525f908290604490829084905af180156134b657615466575b506040519384526020840152604083015260018060a01b0316907f10a0132d3bf8c82a7fb93a86160f3074ca5c3e5706fa2bcdf0e2b5fd495af09b60603392a3565b5f61547091613a57565b5f615424565b61548283601954613d67565b6019556153ae565b50505f916153a8565b6020860190806154da6154c46154b36001600160801b0386511684613d36565b6001600160801b038b511690613d49565b936001600160801b03614463818c511687613d36565b10156153135790600181018091116135645790615313565b63586ce21f60e11b5f5260045260245260445ffd5b9060405160a081018181106001600160401b03821117613a28576040525f8152602081015f815260408201935f855260608301915f8352608084019360405161554f81613a0d565b5f81525f6020820152855280966001600160401b038451164211615576575b505050505050565b600161560d9252615585613c9e565b8652604061559d6001600160401b0386511642613b9b565b6011549582015182516356fb8f2d60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018490526001600160801b0390921660448201529196919485929190911690829081906064820190565b03915afa80156134b6575f925f916156cf575b50670de0b6b3a7640000946001600160401b03615667959481946001600160801b0361565e951690521684526001600160801b038851511690613d36565b91511690613d36565b0480825280151590816156ae575b50156156a5576156966001600160801b03809251169251928284511661528f565b1690525b5f808080808061556e565b5f91505261569a565b6001600160801b0391506156c790828551511690613d67565b11155f615675565b939250506040833d60401161572e575b816156ec60409383613a57565b81010312610dac578251926001600160401b0384168403610dac5760200151906001600160801b0382168203610dac5791929190670de0b6b3a7640000615620565b3d91506156df565b6001600160a01b03165f8181526007602052604090205480615756575050565b5f1981019081116135645761576a90613b63565b5080546001600160a01b03168290036157b15780546001600160a01b03191690557f646cfe9445aed85f4853d501d1924d2bdabb1bbf12531df29f929f07ba4169e05f80a2565b60405162461bcd60e51b8152602060048201526009602482015268042dad2e6dac2e8c6d60bb1b6044820152606490fd5b601d54806157ee575050565b604051631526fe2760e01b8152600481019190915260c0816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156134b6575f9260209284926158b9575b50604051636197390160e11b815260048101919091526024810184905292839160449183916001600160a01b03165af180156134b6576158845750565b6020813d6020116158b1575b8161589d60209383613a57565b81010312610dac576158ae90613cf7565b50565b3d9150615890565b60449192506158d69060c03d60c011611f1757611f038183613a57565b5050925050509190615847565b60405163a9059cbb60e01b60208201526001600160a01b039290921660248301526044808301939093529181526143ee91614b1c606483613a57565b6001600160a01b03908116907f000000000000000000000000000000000000000000000000000000000000000016811461598b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461598757600190565b5f90565b505f90565b93929161599c90613b63565b5080546001600160a01b03169290831561556e576040516370a0823160e01b815230600482015293602085602481845afa9485156134b6575f95615cb4575b508496600183019687549582149686888099615ca6575b80615c9d575b615c1c575b50505f8281526004602090815260408083206001600160a01b03878116855292529091205495169384615a4e575b50505050505081615a43575b50615a40575050565b55565b90508214155f615a37565b825f52600560205260405f2060018060a01b0385165f5260205260405f20855f5260205260405f20548860018060a01b03841692831580158091615c13575b615a9b575b50505050615a2b565b82615c0b575b5081615bfb575b5015615b9b57615af690855f52600660205260405f20875f5260205269021e19e0c9bab2400000615aef60405f205492895f52601b60205261060260405f2054918c613b9b565b0490613d67565b9182615b38575b5050505b5f52600560205260405f209060018060a01b03165f5260205260405f20905f5260205260405f20555f808080808080888180615a92565b90615b6183615b92959c93875f52600660205260405f20895f526020525f6040812055876158e3565b84867fce405e67b4d6e56e438257e15f160ae28b450e6e7659bbc4c1f4e09a1ac846cb6020604051878152a4613b9b565b965f8080615afd565b9050615bdf9150835f52600660205260405f20855f5260205269021e19e0c9bab2400000615aef60405f205492875f52601b60205261060260405f2054918a613b9b565b825f52600660205260405f20845f5260205260405f2055615b01565b60ff91505460a01c16155f615aa8565b91505f615aa1565b50898410615a8d565b615c2591613b9b565b69021e19e0c9bab240000081029080820469021e19e0c9bab2400000149015171561356457615c5a9060175460801c90613d49565b8015615c9357825f52600460205260405f2060018060a01b0385165f52602052615c8960405f20918254613d67565b90555b5f866159fd565b5097508497615c8c565b508082116159f8565b5060175460801c15156159f2565b9094506020813d602011615ce0575b81615cd060209383613a57565b81010312610dac5751935f6159db565b3d9150615cc3565b905f602091828151910182855af1156134b6575f513d615d3757506001600160a01b0381163b155b615d175750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415615d1056fea164736f6c634300081c000a60a034606c57601f61033038819003918201601f19168301916001600160401b03831184841017607057808492602094604052833981010312606c57516001600160a01b0381168103606c576080526040516102ab9081610085823960805181818160ae015261017e0152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c806306fdde031461020a57806318160ddd146101ee578063313ce567146101d357806370a08231146101ad5780638da5cb5b1461016957806395d89b4114610103578063a0712d681461009a5763a9059cbb14610071575f80fd5b346100965760403660031901126100965761008a610288565b50602060405160018152f35b5f80fd5b3461009657602036600319011261009657337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146100dd57005b5f5460043581018091116100ef575f55005b634e487b7160e01b5f52601160045260245ffd5b34610096575f36600319011261009657604051604081019080821067ffffffffffffffff8311176101555761015191604052600381526215d3d560ea1b60208201526040519182918261025e565b0390f35b634e487b7160e01b5f52604160045260245ffd5b34610096575f366003190112610096576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610096576020366003190112610096576101c6610288565b5060205f54604051908152f35b34610096575f36600319011261009657602060405160128152f35b34610096575f3660031901126100965760205f54604051908152f35b34610096575f36600319011261009657604051604081019080821067ffffffffffffffff8311176101555761015191604052600d81526c2bb934ba32a7b3332a37b5b2b760991b6020820152604051918291825b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b03821682036100965756fea164736f6c634300081c000af3af3b9da6ac33569932110b27324f490cadff82974ce0ccd88561c89e289b4ab13fd610fe4e1b384966826794a9b2f6100ad031f352cc5ec6f22667f6074980000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd52646cfe9445aed85f4853d501d1924d2bdabb1bbf12531df29f929f07ba4169e0b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6ed4c9b3ad13d2bf45175455fec325ef1713cf4b0f709952687da6d7332a081ba0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001000000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa2982000000000000000000000000cb7e25fbbd8afe4ce73d7dac647dbc3d847f3c8200000000000000000000000077777777729c405efb6ac823493e6111f0070d67000000000000000000000000000000000000000000000000000000000001731800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001388000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f05b59d3b20000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000010101010e0c3171d894b71b3400668af311e7d9400000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f726000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae3100000000000000000000000000000000000000000000000000000000000001b6000000000000000000000000000000000000000000000000000000000000002d5265737570706c792050616972202843757276654c656e643a206372765553442f7366727855534429202d203100000000000000000000000000000000000000","name":"ResupplyPair","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"cancun","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":true,"additional_sources":[{"file_path":"src/interfaces/IOracle.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface IOracle {\n    function decimals() external view returns (uint8);\n\n    function getPrices(address _vault) external view returns (uint256 _price);\n\n    function name() external view returns (string memory);\n}\n"},{"file_path":"src/protocol/WriteOffToken.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\n/*\nA token-like contract to track write offs via erc20 interfaces to be used\nin reward distribution logic\n\ninterfaces needed:\n- balanceOf\n- transfer\n- mint\n\n*/\ncontract WriteOffToken {\n\n    address public immutable owner;\n    uint256 public totalSupply;\n\n    constructor(address _owner)\n    {\n        owner = _owner;\n    }\n\n    function name() external pure returns (string memory){\n        return \"WriteOffToken\";\n    }\n\n    function symbol() external pure returns (string memory){\n        return \"WOT\";\n    }\n\n    function decimals() external pure returns (uint8){\n        return 18;\n    }\n\n    function mint(uint256 _amount) external{\n        if(msg.sender == owner){\n            totalSupply += _amount;\n        }\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool){\n        return true;\n    }\n\n    function balanceOf(address) external view returns (uint256){\n        //just return total supply\n        return totalSupply;\n    }\n}"},{"file_path":"src/interfaces/IResupplyRegistry.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface IResupplyRegistry {\n    event AddPair(address pairAddress);\n    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n    event SetDeployer(address deployer, bool _bool);\n\n    function acceptOwnership() external;\n\n    function addPair(address _pairAddress) external;\n\n    function registeredPairs(uint256) external view returns (address);\n\n    function pairsByName(string memory) external view returns (address);\n\n    function defaultSwappersLength() external view returns (uint256);\n    function registeredPairsLength() external view returns (uint256);\n\n    function getAllPairAddresses() external view returns (address[] memory _deployedPairsArray);\n    \n    function getAllDefaultSwappers() external view returns (address[] memory _defaultSwappers);\n\n    function owner() external view returns (address);\n\n    function pendingOwner() external view returns (address);\n\n    function renounceOwnership() external;\n\n    function transferOwnership(address newOwner) external;\n\n    function claimFees(address _pair) external;\n    function claimRewards(address _pair) external;\n    function claimInsuranceRewards() external;\n    function withdrawTo(address _asset, uint256 _amount, address _to) external;\n    function mint( address receiver, uint256 amount) external;\n    function burn( address target, uint256 amount) external;\n    function liquidationHandler() external view returns(address);\n    function feeDeposit() external view returns(address);\n    function redemptionHandler() external view returns(address);\n    function rewardHandler() external view returns(address);\n    function insurancePool() external view returns(address);\n    function setRewardClaimer(address _newAddress) external;\n    function setRedemptionHandler(address _newAddress) external;\n    function setFeeDeposit(address _newAddress) external;\n    function setLiquidationHandler(address _newAddress) external;\n    function setInsurancePool(address _newAddress) external;\n    function setStaker(address _newAddress) external;\n    function setTreasury(address _newAddress) external;\n    function staker() external view returns(address);\n    function token() external view returns(address);\n    function treasury() external view returns(address);\n    function govToken() external view returns(address);\n    function l2manager() external view returns(address);\n    function setRewardHandler(address _newAddress) external;\n    function setVestManager(address _newAddress) external;\n    function setDefaultSwappers(address[] memory _swappers) external;\n    function collateralId(address _collateral) external view returns(uint256);\n}"},{"file_path":"node_modules/@openzeppelin/contracts/interfaces/draft-IERC6093.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)\npragma solidity ^0.8.20;\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":"src/interfaces/IRateCalculator.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface IRateCalculator {\n    function name() external view returns (string memory);\n\n    function version() external view returns (uint256, uint256, uint256);\n\n    function getNewRate(\n        address _vault,\n        uint256 _deltaTime,\n        uint256 _previousShares\n    ) external view returns (uint64 _newRatePerSec, uint128 _newShares);\n}\n"},{"file_path":"src/dependencies/CoreOwnable.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport {ICore} from \"../interfaces/ICore.sol\";\n\n/**\n    @title Core Ownable\n    @author Prisma Finance (with edits by Resupply Finance)\n    @notice Contracts inheriting `CoreOwnable` have the same owner as `Core`.\n            The ownership cannot be independently modified or renounced.\n */\ncontract CoreOwnable {\n    ICore public immutable core;\n\n    constructor(address _core) {\n        core = ICore(_core);\n    }\n\n    modifier onlyOwner() {\n        require(msg.sender == address(core), \"!core\");\n        _;\n    }\n\n    function owner() public view returns (address) {\n        return address(core);\n    }\n}"},{"file_path":"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC20Metadata} from \"./extensions/IERC20Metadata.sol\";\nimport {Context} from \"../../utils/Context.sol\";\nimport {IERC20Errors} from \"../../interfaces/draft-IERC6093.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 ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {\n    mapping(address account => uint256) private _balances;\n\n    mapping(address account => mapping(address spender => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\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        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        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    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual returns (uint256) {\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    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual returns (uint256) {\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        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        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":"node_modules/@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":"node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\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":"node_modules/@openzeppelin/contracts/interfaces/IERC1363.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity ^0.8.20;\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":"src/protocol/RewardDistributorMultiEpoch.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n\n//abstract reward handling to attach to another contract\n//supports an epoch system for supply changes\nabstract contract RewardDistributorMultiEpoch is ReentrancyGuard{\n    using SafeERC20 for IERC20;\n\n    struct EarnedData {\n        address token;\n        uint256 amount;\n    }\n\n    struct RewardType {\n        address reward_token;\n        bool is_non_claimable; //a bit unothrodox setting but need to block claims on our redemption tokens as they will be processed differently\n        uint256 reward_remaining;\n    }\n\n    //rewards\n    RewardType[] public rewards;\n    uint256 public currentRewardEpoch;\n    mapping(address => uint256) public userRewardEpoch; //account -> epoch\n    mapping(uint256 => mapping(address => uint256)) public global_reward_integral; //epoch -> token -> integral\n    mapping(uint256 => mapping(address => mapping(address => uint256))) public reward_integral_for;// epoch -> token -> account -> integral\n    mapping(address => mapping(address => uint256)) public claimable_reward;//token -> account -> claimable\n    mapping(address => uint256) public rewardMap;\n    mapping(address => address) public rewardRedirect;\n    \n    uint256 constant private PRECISION = 1e22;\n\n    //events\n    event RewardPaid(address indexed _user, address indexed _rewardToken, address indexed _receiver, uint256 _rewardAmount);\n    event RewardAdded(address indexed _rewardToken);\n    event RewardInvalidated(address indexed _rewardToken);\n    event RewardRedirected(address indexed _account, address _forward);\n    event NewEpoch(uint256 indexed _epoch);\n\n    constructor() {\n\n    }\n\n    modifier onlyRewardManager() {\n        require(_isRewardManager(), \"!rewardManager\");\n        _;\n    }\n\n/////////\n//  Abstract functions\n////////\n\n    function _isRewardManager() internal view virtual returns(bool);\n\n    function _fetchIncentives() internal virtual;\n\n    function _totalRewardShares() internal view virtual returns(uint256);\n\n    function _userRewardShares(address _account) internal view virtual returns(uint256);\n\n    function _increaseUserRewardEpoch(address _account, uint256 _currentUserEpoch) internal virtual;\n\n    function _checkAddToken(address _address) internal view virtual returns(bool);\n//////////\n\n    function maxRewards() public pure virtual returns(uint256){\n        return 15;\n    }\n\n    //register an extra reward token to be handled\n    function addExtraReward(address _token) external onlyRewardManager nonReentrant{\n        //add to reward list\n        _insertRewardToken(_token);\n    }\n\n    //insert a new reward, ignore if already registered or invalid\n    function _insertRewardToken(address _token) internal{\n        if(_token == address(this) || _token == address(0) || !_checkAddToken(_token)){\n            //dont allow reward tracking of the staking token or invalid address\n            return;\n        }\n\n        //add to reward list if new\n        if(rewardMap[_token] == 0){\n            //check reward count for new additions\n            require(rewards.length < maxRewards(), \"max rewards\");\n\n            //set token\n            RewardType storage r = rewards.push();\n            r.reward_token = _token;\n            \n            //set map index after push (mapped value is +1 of real index)\n            rewardMap[_token] = rewards.length;\n\n            emit RewardAdded(_token);\n            //workaround: transfer 0 to self so that earned() reports correctly\n            //with new tokens\n            if(_token.code.length > 0){\n                IERC20(_token).safeTransfer(address(this), 0);\n            }else{\n                //non contract address added? invalidate\n                _invalidateReward(_token);\n            }\n        }else{\n            //get previous used index of given token\n            //this ensures that reviving can only be done on the previous used slot\n            uint256 index = rewardMap[_token];\n            //index is rewardMap minus one\n            RewardType storage reward = rewards[index-1];\n            //check if it was invalidated\n            if(reward.reward_token == address(0)){\n                //revive\n                reward.reward_token = _token;\n                emit RewardAdded(_token);\n            }\n        }\n    }\n\n    //allow invalidating a reward if the token causes trouble in calcRewardIntegral\n    function invalidateReward(address _token) external onlyRewardManager nonReentrant{\n        _invalidateReward(_token);\n    }\n\n    function _invalidateReward(address _token) internal{\n        uint256 index = rewardMap[_token];\n        if(index > 0){\n            //index is registered rewards minus one\n            RewardType storage reward = rewards[index-1];\n            require(reward.reward_token == _token, \"!mismatch\");\n            //set reward token address to 0, integral calc will now skip\n            reward.reward_token = address(0);\n            emit RewardInvalidated(_token);\n        }\n    }\n\n    //get reward count\n    function rewardLength() external view returns(uint256) {\n        return rewards.length;\n    }\n\n    //calculate and record an account's earnings of the given reward.  if _claimTo is given it will also claim.\n    function _calcRewardIntegral(uint256 _epoch, uint256 _currentEpoch, uint256 _index, address _account, address _claimTo) internal{\n        RewardType storage reward = rewards[_index];\n        address rewardToken = reward.reward_token;\n        //skip invalidated rewards\n        //if a reward token starts throwing an error, calcRewardIntegral needs a way to exit\n        if(rewardToken == address(0)){\n           return;\n        }\n\n        //get difference in balance and remaining rewards\n        //getReward is unguarded so we use reward_remaining to keep track of how much was actually claimed since last checkpoint\n        uint256 bal = IERC20(rewardToken).balanceOf(address(this));\n        uint256 remainingRewards = reward.reward_remaining;\n        \n        //update the global integral but only for the current epoch\n        if (_epoch == _currentEpoch && _totalRewardShares() > 0 && bal > remainingRewards) {\n            uint256 rewardPerToken = ((bal - remainingRewards) * PRECISION / _totalRewardShares());\n            if(rewardPerToken > 0){\n                //increase integral\n                global_reward_integral[_epoch][rewardToken] += rewardPerToken;\n            }else{\n                //set balance as current reward_remaining to let dust grow\n                bal = remainingRewards;\n            }\n        }\n\n        uint256 reward_global = global_reward_integral[_epoch][rewardToken];\n\n        if(_account != address(0)){\n            //update user integrals\n            uint userI = reward_integral_for[_epoch][rewardToken][_account];\n            if(_claimTo != address(0) || userI < reward_global){\n                //_claimTo address non-zero means its a claim \n                // only allow claims if current epoch and if the reward allows it\n                if(_epoch == _currentEpoch && _claimTo != address(0) && !reward.is_non_claimable){\n                    uint256 receiveable = claimable_reward[rewardToken][_account] + (_userRewardShares(_account) * (reward_global - userI) / PRECISION);\n                    if(receiveable > 0){\n                        claimable_reward[rewardToken][_account] = 0;\n                        IERC20(rewardToken).safeTransfer(_claimTo, receiveable);\n                        emit RewardPaid(_account, rewardToken, _claimTo, receiveable);\n                        //remove what was claimed from balance\n                        bal -= receiveable;\n                    }\n                }else{\n                    claimable_reward[rewardToken][_account] = claimable_reward[rewardToken][_account] + ( _userRewardShares(_account) * (reward_global - userI) / PRECISION);\n                }\n                reward_integral_for[_epoch][rewardToken][_account] = reward_global;\n            }\n        }\n\n\n        //update remaining reward so that next claim can properly calculate the balance change\n        //claims and tracking new rewards should only happen on current epoch\n        if(_epoch == _currentEpoch && bal != remainingRewards){\n            reward.reward_remaining = bal;\n        }\n    }\n\n    function _increaseRewardEpoch() internal{\n        //final checkpoint for this epoch\n        _checkpoint(address(0), address(0), type(uint256).max);\n\n        //move epoch up\n        uint256 newEpoch = currentRewardEpoch + 1;\n        currentRewardEpoch = newEpoch;\n\n        emit NewEpoch(newEpoch);\n    }\n\n    //checkpoint without claiming\n    function _checkpoint(address _account) internal {\n        //checkpoint without claiming by passing address(0)\n        //default to max as most operations such as deposit/withdraw etc needs to fully sync beforehand\n        _checkpoint(_account, address(0), type(uint256).max);\n    }\n\n    //checkpoint with claim\n    function _checkpoint(address _account, address _claimTo, uint256 _maxloops) internal {\n        //claim rewards first\n        _fetchIncentives();\n\n        uint256 globalEpoch = currentRewardEpoch;\n        uint256 rewardCount = rewards.length;\n\n        for (uint256 loops = 0; loops < _maxloops;) {\n            uint256 userEpoch = globalEpoch;\n\n            if(_account != address(0)){\n                //take user epoch\n                userEpoch = userRewardEpoch[_account];\n\n                //if no shares then jump to current epoch\n                if(userEpoch != globalEpoch && _userRewardShares(_account) == 0){\n                    userEpoch = globalEpoch;\n                    userRewardEpoch[_account] = userEpoch;\n                }\n            }\n            \n            //calc reward integrals\n            for(uint256 i = 0; i < rewardCount;){\n                _calcRewardIntegral(userEpoch, globalEpoch, i,_account,_claimTo);\n                unchecked { i += 1; }\n            }\n            if(userEpoch < globalEpoch){\n                _increaseUserRewardEpoch(_account, userEpoch);\n            }else{\n                return;\n            }\n            unchecked { loops += 1; }\n        }\n    }\n\n    //manually checkpoint a user account\n    function user_checkpoint(address _account, uint256 _epochloops) external nonReentrant returns(bool) {\n        _checkpoint(_account, address(0), _epochloops);\n        return true;\n    }\n\n    //get earned token info\n    //change ABI to view to use this off chain\n    function earned(address _account) public nonReentrant virtual returns(EarnedData[] memory claimable) {\n        \n        //because this is a state mutative function\n        //we can simplify the earned() logic of all rewards (internal and external)\n        //and allow this contract to be agnostic to outside reward contract design\n        //by just claiming everything and updating state via _checkpoint()\n        _checkpoint(_account);\n        uint256 rewardCount = rewards.length;\n        claimable = new EarnedData[](rewardCount);\n\n        for (uint256 i = 0; i < rewardCount;) {\n            RewardType storage reward = rewards[i];\n\n            //skip invalidated and non claimable rewards\n            if(reward.reward_token == address(0) || reward.is_non_claimable){\n                unchecked{ i += 1; }\n                continue;\n            }\n    \n            claimable[i].amount = claimable_reward[reward.reward_token][_account];\n            claimable[i].token = reward.reward_token;\n\n            unchecked{ i += 1; }\n        }\n        return claimable;\n    }\n\n    //set any claimed rewards to automatically go to a different address\n    //set address to zero to disable\n    function setRewardRedirect(address _to) external nonReentrant{\n        rewardRedirect[msg.sender] = _to;\n        emit RewardRedirected(msg.sender, _to);\n    }\n\n    //claim reward for given account (unguarded)\n    function getReward(address _account) public virtual nonReentrant {\n        //check if there is a redirect address\n        address redirect = rewardRedirect[_account];\n        if(redirect != address(0)){\n            _checkpoint(_account, redirect, type(uint256).max);\n        }else{\n            //claim directly in checkpoint logic to save a bit of gas\n            _checkpoint(_account, _account, type(uint256).max);\n        }\n    }\n\n    //claim reward for given account and forward (guarded)\n    function getReward(address _account, address _forwardTo) public virtual nonReentrant{\n        //in order to forward, must be called by the account itself\n        require(msg.sender == _account, \"!self\");\n        require(_forwardTo != address(0), \"fwd address cannot be 0\");\n        //use _forwardTo address instead of _account\n        _checkpoint(_account, _forwardTo, type(uint256).max);\n    }\n}"},{"file_path":"src/interfaces/ILiquidationHandler.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface ILiquidationHandler {\n    function operator() external view returns(address);\n    function setOperator(address _newAddress) external;\n    function processLiquidationDebt(address _collateral, uint256 _collateralAmount, uint256 _debtAmount) external;\n    function processCollateral(address _collateral) external;\n    function liquidate(\n        address _pair,\n        address _borrower\n    ) external returns (uint256 _collateralForLiquidator);\n}"},{"file_path":"node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.20;\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":"src/protocol/pair/ResupplyPairConstants.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\n/**\n * @title ResupplyPairConstants\n * @notice Based on code from Drake Evans and Frax Finance's pair constants (https://github.com/FraxFinance/fraxlend), adapted for Resupply Finance\n */\n\nabstract contract ResupplyPairConstants {\n\n    // Precision settings\n    uint256 public constant LTV_PRECISION = 1e5; // 5 decimals\n    uint256 public constant LIQ_PRECISION = 1e5;\n    uint256 public constant EXCHANGE_PRECISION = 1e18;\n    uint256 public constant RATE_PRECISION = 1e18;\n    uint256 public constant SHARE_REFACTOR_PRECISION = 1e12;\n    uint256 public constant PAIR_DECIMALS = 1e18;\n    error Insolvent(uint256 _borrow, uint256 _collateral, uint256 _exchangeRate);\n    error BorrowerSolvent();\n    error InsufficientDebtAvailable(uint256 _assets, uint256 _request);\n    error SlippageTooHigh(uint256 _minOut, uint256 _actual);\n    error BadSwapper();\n    error InvalidPath(address _expected, address _actual);\n    error InvalidReceiver();\n    error InvalidLiquidator();\n    error InvalidRedemptionHandler();\n    error InvalidParameter();\n    error InsufficientDebtToRedeem();\n    error MinimumRedemption();\n    error InsufficientBorrowAmount();\n    error OnlyProtocolOrOwner();\n}\n"},{"file_path":"src/interfaces/ICore.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport { IAuthHook } from './IAuthHook.sol';\n\ninterface ICore {\n    struct OperatorAuth {\n        bool authorized;\n        IAuthHook hook;\n    }\n\n    event VoterSet(address indexed newVoter);\n    event OperatorExecuted(address indexed caller, address indexed target, bytes data);\n    event OperatorSet(address indexed caller, address indexed target, bool authorized, bytes4 selector, IAuthHook authHook);\n\n    function execute(address target, bytes calldata data) external returns (bytes memory);\n    function epochLength() external view returns (uint256);\n    function startTime() external view returns (uint256);\n    function voter() external view returns (address);\n    function ownershipTransferDeadline() external view returns (uint256);\n    function pendingOwner() external view returns (address);\n    function setOperatorPermissions(\n        address caller,\n        address target,\n        bytes4 selector,\n        bool authorized,\n        IAuthHook authHook\n    ) external;\n    function setVoter(address newVoter) external;\n    function operatorPermissions(address caller, address target, bytes4 selector) external view returns (bool authorized, IAuthHook hook);\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\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"},{"file_path":"node_modules/@openzeppelin/contracts/utils/Errors.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Collection of common custom errors used in multiple contracts\n *\n * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.\n * It is recommended to avoid relying on the error API for critical functionality.\n *\n * _Available since v5.1._\n */\nlibrary Errors {\n    /**\n     * @dev The ETH balance of the account is not enough to perform the operation.\n     */\n    error InsufficientBalance(uint256 balance, uint256 needed);\n\n    /**\n     * @dev A call to an address target failed. The target may have reverted.\n     */\n    error FailedCall();\n\n    /**\n     * @dev The deployment failed.\n     */\n    error FailedDeployment();\n\n    /**\n     * @dev A necessary precompile is missing.\n     */\n    error MissingPrecompile(address);\n}\n"},{"file_path":"src/interfaces/IERC4626.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface IERC4626 is IERC20, IERC20Metadata {\n    event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);\n    event Withdraw(\n        address indexed caller,\n        address indexed receiver,\n        address indexed owner,\n        uint256 assets,\n        uint256 shares\n    );\n\n    function asset() external view returns (address);\n\n    function convertToAssets(uint256 shares) external view returns (uint256);\n\n    function convertToShares(uint256 assets) external view returns (uint256);\n\n    function maxDeposit(address) external view returns (uint256);\n\n    function maxMint(address) external view returns (uint256);\n\n    function maxRedeem(address owner) external view returns (uint256);\n\n    function maxWithdraw(address owner) external view returns (uint256);\n\n    function previewDeposit(uint256 assets) external view returns (uint256);\n\n    function previewMint(uint256 shares) external view returns (uint256);\n\n    function previewRedeem(uint256 shares) external view returns (uint256);\n\n    function previewWithdraw(uint256 assets) external view returns (uint256);\n\n    function totalAssets() external view returns (uint256);\n\n    function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n    function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n\n    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n}\n"},{"file_path":"src/interfaces/IMintable.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface IMintable{\n    function mint(address _to, uint256 _amount) external;\n    function burn(address _from, uint256 _amount) external;\n}\n"},{"file_path":"src/dependencies/EpochTracker.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"../interfaces/ICore.sol\";\n\n/**\n    @title EpochTracker\n    @dev Provides a unified `startTime` and `getEpoch`, used for tracking epochs.\n */\ncontract EpochTracker {\n    uint256 public immutable startTime;\n    \n    /// @notice Length of an epoch, in seconds\n    uint256 public immutable epochLength;\n\n    constructor(address _core) {\n        startTime = ICore(_core).startTime();\n        epochLength = ICore(_core).epochLength();\n    }\n\n    function getEpoch() public view returns (uint256 epoch) {\n        return (block.timestamp - startTime) / epochLength;\n    }\n}"},{"file_path":"node_modules/@openzeppelin/contracts/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},{"file_path":"src/interfaces/IAuthHook.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface IAuthHook {\n    function preHook(address operator, address target, bytes calldata data) external returns (bool);\n    function postHook(bytes memory result, address operator, address target, bytes calldata data) external returns (bool);\n}\n"},{"file_path":"src/libraries/VaultAccount.sol","source_code":"// SPDX-License-Identifier: ISC\npragma solidity ^0.8.19;\n\nstruct VaultAccount {\n    uint128 amount; // Total amount, analogous to market cap\n    uint128 shares; // Total shares, analogous to shares outstanding\n}\n\n/// @title VaultAccount Library\n/// @author Drake Evans (Frax Finance) github.com/drakeevans, modified from work by @Boring_Crypto github.com/boring_crypto\n/// @notice Provides a library for use with the VaultAccount struct, provides convenient math implementations\n/// @dev Uses uint128 to save on storage\nlibrary VaultAccountingLibrary {\n    /// @notice Calculates the shares value in relationship to `amount` and `total`\n    /// @dev Given an amount, return the appropriate number of shares\n    function toShares(VaultAccount memory total, uint256 amount, bool roundUp) internal pure returns (uint256 shares) {\n        if (total.amount == 0) {\n            shares = amount;\n        } else {\n            shares = (amount * total.shares) / total.amount;\n            if (roundUp && (shares * total.amount) / total.shares < amount) {\n                shares = shares + 1;\n            }\n        }\n    }\n\n    /// @notice Calculates the amount value in relationship to `shares` and `total`\n    /// @dev Given a number of shares, returns the appropriate amount\n    function toAmount(VaultAccount memory total, uint256 shares, bool roundUp) internal pure returns (uint256 amount) {\n        if (total.shares == 0) {\n            amount = shares;\n        } else {\n            amount = (shares * total.amount) / total.shares;\n            if (roundUp && total.amount > 0 && (amount * total.shares) / total.amount < shares) {\n                amount = amount + 1;\n            }\n        }\n    }\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/interfaces/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},{"file_path":"src/protocol/pair/ResupplyPairCore.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\n/**\n * @title ResupplyPairCore\n * @notice Based on code from Drake Evans and Frax Finance's lending pair core contract (https://github.com/FraxFinance/fraxlend), adapted for Resupply Finance\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { ResupplyPairConstants } from \"./ResupplyPairConstants.sol\";\nimport { VaultAccount, VaultAccountingLibrary } from \"../../libraries/VaultAccount.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IOracle } from \"../../interfaces/IOracle.sol\";\nimport { IRateCalculator } from \"../../interfaces/IRateCalculator.sol\";\nimport { ISwapper } from \"../../interfaces/ISwapper.sol\";\nimport { IResupplyRegistry } from \"../../interfaces/IResupplyRegistry.sol\";\nimport { ILiquidationHandler } from \"../../interfaces/ILiquidationHandler.sol\";\nimport { RewardDistributorMultiEpoch } from \"../RewardDistributorMultiEpoch.sol\";\nimport { WriteOffToken } from \"../WriteOffToken.sol\";\nimport { IERC4626 } from \"../../interfaces/IERC4626.sol\";\nimport { CoreOwnable } from \"../../dependencies/CoreOwnable.sol\";\nimport { IMintable } from \"../../interfaces/IMintable.sol\";\n\n\nabstract contract ResupplyPairCore is CoreOwnable, ResupplyPairConstants, RewardDistributorMultiEpoch {\n    using VaultAccountingLibrary for VaultAccount;\n    using SafeERC20 for IERC20;\n    using SafeCast for uint256;\n\n    //forked fraxlend at version 3,0,0\n    function version() external pure returns (uint256 _major, uint256 _minor, uint256 _patch) {\n        _major = 3;\n        _minor = 0;\n        _patch = 0;\n    }\n\n    // ============================================================================================\n    // Settings set by constructor()\n    // ============================================================================================\n\n    // Asset and collateral contracts\n    address public immutable registry;\n    IERC20 internal immutable debtToken;\n    IERC20 public immutable collateral;\n    IERC20 public immutable underlying;\n\n    // LTV Settings\n    /// @notice The maximum LTV allowed for this pair\n    /// @dev 1e5 precision\n    uint256 public maxLTV;\n\n    //max borrow\n    uint256 public borrowLimit;\n\n    //Fees\n    /// @notice The liquidation fee, given as a % of repayment amount\n    /// @dev 1e5 precision\n    uint256 public mintFee;\n    uint256 public liquidationFee;\n    /// @dev 1e18 precision\n    uint256 public protocolRedemptionFee;\n    uint256 public minimumRedemption = 100 * PAIR_DECIMALS; //minimum amount of debt to redeem\n    uint256 public minimumLeftoverDebt = 10000 * PAIR_DECIMALS; //minimum amount of assets left over via redemptions\n    uint256 public minimumBorrowAmount = 1000 * PAIR_DECIMALS; //minimum amount of assets to borrow\n    \n\n    // Interest Rate Calculator Contract\n    IRateCalculator public rateCalculator; // For complex rate calculations\n\n    // Swapper\n    mapping(address => bool) public swappers; // approved swapper addresses\n\n    // Metadata\n    string public name;\n    \n    // ============================================================================================\n    // Storage\n    // ============================================================================================\n\n    /// @notice Stores information about the current interest rate\n    CurrentRateInfo public currentRateInfo;\n\n    struct CurrentRateInfo {\n        uint64 lastTimestamp;\n        uint64 ratePerSec;\n        uint128 lastShares;\n    }\n\n    /// @notice Stores information about the current exchange rate. Collateral:Asset ratio\n    /// @dev Struct packed to save SLOADs. Amount of Collateral Token to buy 1e18 Asset Token\n    ExchangeRateInfo public exchangeRateInfo;\n\n    struct ExchangeRateInfo {\n        address oracle;\n        uint96 lastTimestamp;\n        uint256 exchangeRate;\n    }\n\n    // Contract Level Accounting\n    VaultAccount public totalBorrow; // amount = total borrow amount with interest accrued, shares = total shares outstanding\n    uint256 public claimableFees; //amount of interest gained that is claimable as fees\n    uint256 public claimableOtherFees; //amount of redemption/mint fees claimable by protocol\n    WriteOffToken immutable public redemptionWriteOff; //token to keep track of redemption write offs\n\n    // User Level Accounting\n    /// @notice Stores the balance of collateral for each user\n    mapping(address => uint256) internal _userCollateralBalance; // amount of collateral each user is backed\n    /// @notice Stores the balance of borrow shares for each user\n    mapping(address => uint256) internal _userBorrowShares; // represents the shares held by individuals\n\n    \n\n    // ============================================================================================\n    // Constructor\n    // ============================================================================================\n\n    /// @notice The ```constructor``` function is called on deployment\n    /// @param _core Core contract address\n    /// @param _configData abi.encode(address _collateral, address _oracle, address _rateCalculator, uint256 _maxLTV, uint256 _borrowLimit, uint256 _liquidationFee, uint256 _mintFee, uint256 _protocolRedemptionFee)\n    /// @param _immutables abi.encode(address _registry)\n    /// @param _customConfigData abi.encode(address _name, address _govToken, address _underlyingStaking, uint256 _stakingId)\n    constructor(\n        address _core,\n        bytes memory _configData,\n        bytes memory _immutables,\n        bytes memory _customConfigData\n    ) CoreOwnable(_core){\n        (address _registry) = abi.decode(\n            _immutables,\n            (address)\n        );\n        registry = _registry;\n        debtToken = IERC20(IResupplyRegistry(registry).token());\n        {\n            (\n                address _collateral,\n                address _oracle,\n                address _rateCalculator,\n                uint256 _maxLTV,\n                uint256 _initialBorrowLimit,\n                uint256 _liquidationFee,\n                uint256 _mintFee,\n                uint256 _protocolRedemptionFee\n            ) = abi.decode(\n                    _configData,\n                    (address, address, address, uint256, uint256, uint256, uint256, uint256)\n                );\n\n            // Pair Settings\n            collateral = IERC20(_collateral);\n            if(IERC20Metadata(_collateral).decimals() != 18){\n                revert InvalidParameter();\n            }\n            underlying = IERC20(IERC4626(_collateral).asset());\n            if(IERC20Metadata(address(underlying)).decimals() != 18){\n                revert InvalidParameter();\n            }\n            // approve so this contract can deposit\n            underlying.forceApprove(_collateral, type(uint256).max);\n            currentRateInfo.lastShares = uint128(IERC4626(_collateral).convertToShares(PAIR_DECIMALS));\n            exchangeRateInfo.oracle = _oracle;\n            rateCalculator = IRateCalculator(_rateCalculator);\n            borrowLimit = _initialBorrowLimit;\n\n            //Liquidation Fee Settings\n            liquidationFee = _liquidationFee;\n            mintFee = _mintFee;\n            protocolRedemptionFee = _protocolRedemptionFee;\n\n            // set maxLTV\n            maxLTV = _maxLTV;\n        }\n\n        //starting reward types\n        redemptionWriteOff = new WriteOffToken(address(this));\n        _insertRewardToken(address(redemptionWriteOff));//add redemption token as a reward\n        //set the redemption token as non claimable via getReward\n        rewards[0].is_non_claimable = true;\n\n        {\n            (string memory _name,,,) = abi.decode(\n                _customConfigData,\n                (string, address, address, uint256)\n            );\n\n            // Metadata\n            name = _name;\n\n            // Instantiate Interest\n            _addInterest();\n            // Instantiate Exchange Rate\n            _updateExchangeRate();\n        }\n    }\n\n    // ============================================================================================\n    // Helpers\n    // ============================================================================================\n\n\n    //get total collateral, either parked here or staked \n    function totalCollateral() public view virtual returns(uint256 _totalCollateralBalance);\n\n    function userBorrowShares(address _account) public view returns(uint256 borrowShares){\n        borrowShares = _userBorrowShares[_account];\n\n        uint256 globalEpoch = currentRewardEpoch;\n        uint256 userEpoch = userRewardEpoch[_account];\n\n        if(userEpoch < globalEpoch){\n            //need to calculate shares while keeping this as a view function\n            for(;;){\n                //reduce shares by refactoring amount\n                borrowShares /= SHARE_REFACTOR_PRECISION;\n                unchecked {\n                    userEpoch += 1;\n                }\n                if(userEpoch == globalEpoch){\n                    break;\n                }\n            }\n        }\n    }\n\n    //get _userCollateralBalance minus redemption tokens\n    function userCollateralBalance(address _account) public nonReentrant returns(uint256 _collateralAmount){\n        _syncUserRedemptions(_account);\n\n        _collateralAmount = _userCollateralBalance[_account];\n\n        //since there are some very small dust during distribution there could be a few wei\n        //in user collateral that is over total collateral. clamp to total\n        uint256 total = totalCollateral();\n        _collateralAmount = _collateralAmount > total ? total : _collateralAmount;\n    }\n\n    /// @notice The ```totalDebtAvailable``` function returns the total balance of debt tokens in the contract\n    /// @return The balance of debt tokens held by contract\n    function totalDebtAvailable() external view returns (uint256) {\n        (,,, VaultAccount memory _totalBorrow) = previewAddInterest();\n        \n        return _totalDebtAvailable(_totalBorrow);\n    }\n\n    /// @notice The ```_totalDebtAvailable``` function returns the total amount of debt that can be issued on this pair\n    /// @param _totalBorrow Total borrowed amount, inclusive of interest\n    /// @return The amount of debt that can be issued\n    function _totalDebtAvailable(VaultAccount memory _totalBorrow) internal view returns (uint256) {\n        uint256 _borrowLimit = borrowLimit;\n        uint256 borrowable = _borrowLimit > _totalBorrow.amount ? _borrowLimit - _totalBorrow.amount : 0;\n\n        return borrowable > type(uint128).max ? type(uint128).max : borrowable; \n    }\n\n    function currentUtilization() external view returns (uint256) {\n        uint256 _borrowLimit = borrowLimit;\n        if(_borrowLimit == 0){\n            return PAIR_DECIMALS;\n        }\n        (,,, VaultAccount memory _totalBorrow) = previewAddInterest();\n        return _totalBorrow.amount * PAIR_DECIMALS / _borrowLimit;\n    }\n\n    /// @notice The ```_isSolvent``` function determines if a given borrower is solvent given an exchange rate\n    /// @param _borrower The borrower address to check\n    /// @param _exchangeRate The exchange rate, i.e. the amount of collateral to buy 1e18 asset\n    /// @return Whether borrower is solvent\n    function _isSolvent(address _borrower, uint256 _exchangeRate) internal view returns (bool) {\n        uint256 _maxLTV = maxLTV;\n        if (_maxLTV == 0) return true;\n        //must look at borrow shares of current epoch so user helper function\n        //user borrow shares should be synced before _isSolvent is called\n        uint256 _borrowerAmount = totalBorrow.toAmount(_userBorrowShares[_borrower], true);\n        if (_borrowerAmount == 0) return true;\n        \n        //anything that calls _isSolvent will call _syncUserRedemptions beforehand\n        uint256 _collateralAmount = _userCollateralBalance[_borrower];\n        if (_collateralAmount == 0) return false;\n\n        uint256 _ltv = ((_borrowerAmount * _exchangeRate * LTV_PRECISION) / EXCHANGE_PRECISION) / _collateralAmount;\n        return _ltv <= _maxLTV;\n    }\n\n    function _isSolventSync(address _borrower, uint256 _exchangeRate) internal returns (bool){\n         //checkpoint rewards and sync _userCollateralBalance\n        _syncUserRedemptions(_borrower);\n        return _isSolvent(_borrower, _exchangeRate);\n    }\n\n    // ============================================================================================\n    // Modifiers\n    // ============================================================================================\n\n    /// @notice Checks for solvency AFTER executing contract code\n    /// @param _borrower The borrower whose solvency we will check\n    modifier isSolvent(address _borrower) {\n        //checkpoint rewards and sync _userCollateralBalance before doing other actions\n        _syncUserRedemptions(_borrower);\n        _;\n        ExchangeRateInfo memory _exchangeRateInfo = exchangeRateInfo;\n\n        if (!_isSolvent(_borrower, _exchangeRateInfo.exchangeRate)) {\n            revert Insolvent(\n                totalBorrow.toAmount(_userBorrowShares[_borrower], true),\n                _userCollateralBalance[_borrower], //_issolvent sync'd so take base _userCollateral\n                _exchangeRateInfo.exchangeRate\n            );\n        }\n    }\n\n    // ============================================================================================\n    // Reward Implementation\n    // ============================================================================================\n\n    function _isRewardManager() internal view override returns(bool){\n        return msg.sender == address(core) || msg.sender == IResupplyRegistry(registry).rewardHandler();\n    }\n\n    function _fetchIncentives() internal override{\n        IResupplyRegistry(registry).claimRewards(address(this));\n    }\n\n    function _totalRewardShares() internal view override returns(uint256){\n        return totalBorrow.shares;\n    }\n\n    function _userRewardShares(address _account) internal view override returns(uint256){\n        return _userBorrowShares[_account];\n    }\n\n    function _increaseUserRewardEpoch(address _account, uint256 _currentUserEpoch) internal override{\n        //convert shares to next epoch shares\n        //share refactoring will never be 0\n        _userBorrowShares[_account] = _userBorrowShares[_account] / SHARE_REFACTOR_PRECISION;\n        //update user reward epoch\n        userRewardEpoch[_account] = _currentUserEpoch + 1;\n    }\n\n    function earned(address _account) public override returns(EarnedData[] memory claimable){\n        EarnedData[] memory earneddata = super.earned(_account);\n        uint256 rewardCount = earneddata.length - 1;\n        claimable = new EarnedData[](rewardCount);\n\n        //remove index 0 as we dont need to report the write off tokens\n        for (uint256 i = 1; i <= rewardCount; ) {\n            claimable[i-1].amount = earneddata[i].amount;\n            claimable[i-1].token = earneddata[i].token;\n            unchecked{ i += 1; }\n        }\n    }\n\n    function _checkAddToken(address _address) internal view virtual override returns(bool){\n        if(_address == address(collateral)) return false;\n        if(_address == address(debtToken)) return false;\n        return true;\n    }\n\n    // ============================================================================================\n    // Underlying Staking\n    // ============================================================================================\n\n    function _stakeUnderlying(uint256 _amount) internal virtual;\n\n    function _unstakeUnderlying(uint256 _amount) internal virtual;\n\n    // ============================================================================================\n    // Functions: Interest Accumulation and Adjustment\n    // ============================================================================================\n\n    /// @notice The ```AddInterest``` event is emitted when interest is accrued by borrowers\n    /// @param interestEarned The total interest accrued by all borrowers\n    /// @param rate The interest rate used to calculate accrued interest\n    event AddInterest(uint256 interestEarned, uint256 rate);\n\n    /// @notice The ```UpdateRate``` event is emitted when the interest rate is updated\n    /// @param oldRatePerSec The old interest rate (per second)\n    /// @param oldShares previous used shares\n    /// @param newRatePerSec The new interest rate (per second)\n    /// @param newShares new shares\n    event UpdateRate(\n        uint256 oldRatePerSec,\n        uint128 oldShares,\n        uint256 newRatePerSec,\n        uint128 newShares\n    );\n\n    /// @notice The ```addInterest``` function is a public implementation of _addInterest and allows 3rd parties to trigger interest accrual\n    /// @param _returnAccounting Whether to return additional accounting data\n    /// @return _interestEarned The amount of interest accrued by all borrowers\n    /// @return _currentRateInfo The new rate info struct\n    /// @return _claimableFees The new total of fees that are claimable\n    /// @return _totalBorrow The new total borrow struct\n    function addInterest(\n        bool _returnAccounting\n    )\n        external\n        nonReentrant\n        returns (\n            uint256 _interestEarned,\n            CurrentRateInfo memory _currentRateInfo,\n            uint256 _claimableFees,\n            VaultAccount memory _totalBorrow\n        )\n    {\n        (, _interestEarned, _currentRateInfo) = _addInterest();\n        if (_returnAccounting) {\n            _claimableFees = claimableFees;\n            _totalBorrow = totalBorrow;\n        }\n    }\n\n    /// @notice The ```previewAddInterest``` function\n    /// @return _interestEarned The amount of interest accrued by all borrowers\n    /// @return _newCurrentRateInfo The new rate info struct\n    /// @return _claimableFees The new total of fees that are claimable\n    /// @return _totalBorrow The new total borrow struct\n    function previewAddInterest()\n        public\n        view\n        returns (\n            uint256 _interestEarned,\n            CurrentRateInfo memory _newCurrentRateInfo,\n            uint256 _claimableFees,\n            VaultAccount memory _totalBorrow\n        )\n    {\n        _newCurrentRateInfo = currentRateInfo;\n        _newCurrentRateInfo.lastTimestamp = uint64(block.timestamp);\n\n        // Write return values\n        InterestCalculationResults memory _results = _calculateInterest(_newCurrentRateInfo);\n\n        if (_results.isInterestUpdated) {\n            _interestEarned = _results.interestEarned;\n\n            _newCurrentRateInfo.ratePerSec = _results.newRate;\n            _newCurrentRateInfo.lastShares = _results.newShares;\n\n            _claimableFees = claimableFees + uint128(_interestEarned);\n            _totalBorrow = _results.totalBorrow;\n        } else {\n            _claimableFees = claimableFees;\n            _totalBorrow = totalBorrow;\n        }\n    }\n\n    struct InterestCalculationResults {\n        bool isInterestUpdated;\n        uint64 newRate;\n        uint128 newShares;\n        uint256 interestEarned;\n        VaultAccount totalBorrow;\n    }\n\n    /// @notice The ```_calculateInterest``` function calculates the interest to be accrued and the new interest rate info\n    /// @param _currentRateInfo The current rate info\n    /// @return _results The results of the interest calculation\n    function _calculateInterest(\n        CurrentRateInfo memory _currentRateInfo\n    ) internal view returns (InterestCalculationResults memory _results) {\n        // Short circuit if interest already calculated this block\n        if (_currentRateInfo.lastTimestamp < block.timestamp) {\n            // Indicate that interest is updated and calculated\n            _results.isInterestUpdated = true;\n\n            // Write return values and use these to save gas\n            _results.totalBorrow = totalBorrow;\n\n            // Time elapsed since last interest update\n            uint256 _deltaTime = block.timestamp - _currentRateInfo.lastTimestamp;\n\n            // Request new interest rate and full utilization rate from the rate calculator\n            (_results.newRate, _results.newShares) = IRateCalculator(rateCalculator).getNewRate(\n                address(collateral),\n                _deltaTime,\n                _currentRateInfo.lastShares\n            );\n\n            // Calculate interest accrued\n            _results.interestEarned = (_deltaTime * _results.totalBorrow.amount * _results.newRate) / RATE_PRECISION;\n\n            // Accrue interest (if any) and fees if no overflow\n            if (\n                _results.interestEarned > 0 &&\n                _results.interestEarned + _results.totalBorrow.amount <= type(uint128).max\n            ) {\n                // Increment totalBorrow by interestEarned\n                _results.totalBorrow.amount += uint128(_results.interestEarned);\n            }else{\n                //reset interest earned\n                _results.interestEarned = 0;\n            }\n        }\n    }\n\n    /// @notice The ```_addInterest``` function is invoked prior to every external function and is used to accrue interest and update interest rate\n    /// @dev Can only called once per block\n    /// @return _isInterestUpdated True if interest was calculated\n    /// @return _interestEarned The amount of interest accrued by all borrowers\n    /// @return _currentRateInfo The new rate info struct\n    function _addInterest()\n        internal\n        returns (\n            bool _isInterestUpdated,\n            uint256 _interestEarned,\n            CurrentRateInfo memory _currentRateInfo\n        )\n    {\n        // Pull from storage and set default return values\n        _currentRateInfo = currentRateInfo;\n\n        // Calc interest\n        InterestCalculationResults memory _results = _calculateInterest(_currentRateInfo);\n\n        // Write return values only if interest was updated and calculated\n        if (_results.isInterestUpdated) {\n            _isInterestUpdated = _results.isInterestUpdated;\n            _interestEarned = _results.interestEarned;\n\n            // emit here so that we have access to the old values\n            emit UpdateRate(\n                _currentRateInfo.ratePerSec,\n                _currentRateInfo.lastShares,\n                _results.newRate,\n                _results.newShares\n            );\n            emit AddInterest(_interestEarned, _results.newRate);\n\n            // overwrite original values\n            _currentRateInfo.ratePerSec = _results.newRate;\n            _currentRateInfo.lastShares = _results.newShares;\n            _currentRateInfo.lastTimestamp = uint64(block.timestamp);\n\n            // Effects: write to state\n            currentRateInfo = _currentRateInfo;\n            claimableFees += _interestEarned; //increase claimable fees by interest earned\n            totalBorrow = _results.totalBorrow;\n        }\n    }\n\n    // ============================================================================================\n    // Functions: ExchangeRate\n    // ============================================================================================\n\n    /// @notice The ```UpdateExchangeRate``` event is emitted when the Collateral:Asset exchange rate is updated\n    /// @param exchangeRate The exchange rate\n    event UpdateExchangeRate(uint256 exchangeRate);\n\n    /// @notice The ```updateExchangeRate``` function is the external implementation of _updateExchangeRate.\n    /// @dev This function is invoked at most once per block as these queries can be expensive\n    /// @return _exchangeRate The exchange rate\n    function updateExchangeRate()\n        external\n        nonReentrant\n        returns (uint256 _exchangeRate)\n    {\n        return _updateExchangeRate();\n    }\n\n    /// @notice The ```_updateExchangeRate``` function retrieves the latest exchange rate. i.e how much collateral to buy 1e18 asset.\n    /// @dev This function is invoked at most once per block as these queries can be expensive\n    /// @return _exchangeRate The exchange rate\n    function _updateExchangeRate()\n        internal\n        returns (uint256 _exchangeRate)\n    {\n        // Pull from storage to save gas and set default return values\n        ExchangeRateInfo memory _exchangeRateInfo = exchangeRateInfo;\n\n        // Short circuit if already updated this block\n        if (_exchangeRateInfo.lastTimestamp != block.timestamp) {\n            // Get the latest exchange rate from the oracle\n            _exchangeRate = IOracle(_exchangeRateInfo.oracle).getPrices(address(collateral));\n            //convert price of collateral as debt is priced in terms of collateral amount (inverse)\n            _exchangeRate = 1e36 / _exchangeRate;\n\n\n            // Effects: Bookkeeping and write to storage\n            _exchangeRateInfo.lastTimestamp = uint96(block.timestamp);\n            _exchangeRateInfo.exchangeRate = _exchangeRate;\n            exchangeRateInfo = _exchangeRateInfo;\n            emit UpdateExchangeRate(_exchangeRate);\n        } else {\n            // Use default return values if already updated this block\n            _exchangeRate = _exchangeRateInfo.exchangeRate;\n        }\n\n    }\n\n    // ============================================================================================\n    // Functions: Lending\n    // ============================================================================================\n\n    // ONLY Protocol can lend\n\n    // ============================================================================================\n    // Functions: Borrowing\n    // ============================================================================================\n\n    //sync user collateral by removing account of userCollateralBalance based on\n    //how many \"claimable\" redemption tokens are available to the user\n    //should be called before anything with userCollateralBalance is used\n    function _syncUserRedemptions(address _account) internal{\n        //sync rewards first\n        _checkpoint(_account);\n\n        //get token count (divide by LTV_PRECISION as precision is padded)\n        uint256 rTokens = claimable_reward[address(redemptionWriteOff)][_account] / LTV_PRECISION;\n        //reset claimables\n        claimable_reward[address(redemptionWriteOff)][_account] = 0;\n\n        //remove from collateral balance the number of rtokens the user has\n        uint256 currentUserBalance = _userCollateralBalance[_account];\n        _userCollateralBalance[_account] = currentUserBalance >= rTokens ? currentUserBalance - rTokens : 0;\n    }\n\n    /// @notice The ```Borrow``` event is emitted when a borrower increases their position\n    /// @param _borrower The borrower whose account was debited\n    /// @param _receiver The address to which the Asset Tokens were transferred\n    /// @param _borrowAmount The amount of Asset Tokens transferred\n    /// @param _sharesAdded The number of Borrow Shares the borrower was debited\n    /// @param _mintFees The amount of mint fees incurred\n    event Borrow(\n        address indexed _borrower,\n        address indexed _receiver,\n        uint256 _borrowAmount,\n        uint256 _sharesAdded,\n        uint256 _mintFees\n    );\n\n    /// @notice The ```_borrow``` function is the internal implementation for borrowing assets\n    /// @param _borrowAmount The amount of the Asset Token to borrow\n    /// @param _receiver The address to receive the Asset Tokens\n    /// @return _sharesAdded The amount of borrow shares the msg.sender will be debited\n    function _borrow(uint128 _borrowAmount, address _receiver) internal returns (uint256 _sharesAdded) {\n        // Get borrow accounting from storage to save gas\n        VaultAccount memory _totalBorrow = totalBorrow;\n\n        if(_borrowAmount < minimumBorrowAmount){\n            revert InsufficientBorrowAmount();\n        }\n\n        //mint fees\n        uint256 debtForMint = (_borrowAmount * (LIQ_PRECISION + mintFee) / LIQ_PRECISION);\n\n        // Check available capital\n        uint256 _assetsAvailable = _totalDebtAvailable(_totalBorrow);\n        if (_assetsAvailable < debtForMint) {\n            revert InsufficientDebtAvailable(_assetsAvailable, debtForMint);\n        }\n        \n        // Calculate the number of shares to add based on the amount to borrow\n        _sharesAdded = _totalBorrow.toShares(debtForMint, true);\n\n        //combine current shares and new shares\n        uint256 newTotalShares = _totalBorrow.shares + _sharesAdded;\n\n        // Effects: Bookkeeping to add shares & amounts to total Borrow accounting\n        _totalBorrow.amount += debtForMint.toUint128();\n        _totalBorrow.shares = newTotalShares.toUint128();\n\n        // Effects: write back to storage\n        totalBorrow = _totalBorrow;\n        _userBorrowShares[msg.sender] += _sharesAdded;\n\n        uint256 otherFees = debtForMint > _borrowAmount ? debtForMint - _borrowAmount : 0;\n        if (otherFees > 0) claimableOtherFees += otherFees;\n\n        // Interactions\n        IResupplyRegistry(registry).mint(_receiver, _borrowAmount);\n        \n        emit Borrow(msg.sender, _receiver, _borrowAmount, _sharesAdded, otherFees);\n    }\n\n    /// @notice The ```borrow``` function allows a user to open/increase a borrow position\n    /// @dev Borrower must call ```ERC20.approve``` on the Collateral Token contract if applicable\n    /// @param _borrowAmount The amount to borrow\n    /// @param _underlyingAmount The amount of underlying tokens to transfer to Pair\n    /// @param _receiver The address which will receive the Asset Tokens\n    /// @return _shares The number of borrow Shares the msg.sender will be debited\n    function borrow(\n        uint256 _borrowAmount,\n        uint256 _underlyingAmount,\n        address _receiver\n    ) external nonReentrant isSolvent(msg.sender) returns (uint256 _shares) {\n        if (_receiver == address(0)) revert InvalidReceiver();\n\n        // Accrue interest if necessary\n        _addInterest();\n\n        // Update _exchangeRate\n        _updateExchangeRate();\n\n        // Only add collateral if necessary\n        if (_underlyingAmount > 0) {\n            //pull underlying and deposit in vault\n            underlying.safeTransferFrom(msg.sender, address(this), _underlyingAmount);\n            uint256 collateralShares = IERC4626(address(collateral)).deposit(_underlyingAmount, address(this));\n            //add collateral to msg.sender\n            _addCollateral(address(this), collateralShares, msg.sender);\n        }\n\n        // Effects: Call internal borrow function\n        _shares = _borrow(_borrowAmount.toUint128(), _receiver);\n    }\n\n    /// @notice The ```AddCollateral``` event is emitted when a borrower adds collateral to their position\n    /// @param borrower The borrower account for which the collateral should be credited\n    /// @param collateralAmount The amount of Collateral Token to be transferred\n    event AddCollateral(address indexed borrower, uint256 collateralAmount);\n\n    /// @notice The ```_addCollateral``` function is an internal implementation for adding collateral to a borrowers position\n    /// @param _sender The source of funds for the new collateral\n    /// @param _collateralAmount The amount of Collateral Token to be transferred\n    /// @param _borrower The borrower account for which the collateral should be credited\n    function _addCollateral(address _sender, uint256 _collateralAmount, address _borrower) internal {\n        _userCollateralBalance[_borrower] += _collateralAmount;\n        if (_sender != address(this)) {\n            collateral.safeTransferFrom(_sender, address(this), _collateralAmount);\n        }\n        //stake underlying\n        _stakeUnderlying(_collateralAmount);\n\n        emit AddCollateral(_borrower, _collateralAmount);\n    }\n\n    /// @notice The ```addCollateral``` function allows the caller to add Collateral Token to a borrowers position\n    /// @dev msg.sender must call ERC20.approve() on the Collateral Token contract prior to invocation\n    /// @param _collateralAmount The amount of Collateral Token to be added to borrower's position\n    /// @param _borrower The account to be credited\n    function addCollateralVault(uint256 _collateralAmount, address _borrower) external nonReentrant {\n        if (_borrower == address(0)) revert InvalidReceiver();\n\n        _addInterest();\n        _addCollateral(msg.sender, _collateralAmount, _borrower);\n    }\n\n    /// @notice Allows depositing in terms of underlying asset, and have it converted to collateral shares to the borrower's position.\n    /// @param _amount The amount of the underlying asset to deposit.\n    /// @param _borrower The address of the borrower whose collateral balance will be credited.\n    function addCollateral(uint256 _amount, address _borrower) external nonReentrant {\n        if (_borrower == address(0)) revert InvalidReceiver();\n\n        _addInterest();\n\n        underlying.safeTransferFrom(msg.sender, address(this), _amount);\n        uint256 collateralShares = IERC4626(address(collateral)).deposit(_amount, address(this));\n        _addCollateral(address(this), collateralShares, _borrower);\n    }\n\n    /// @notice The ```RemoveCollateral``` event is emitted when collateral is removed from a borrower's position\n    /// @param _collateralAmount The amount of Collateral Token to be transferred\n    /// @param _receiver The address to which Collateral Tokens will be transferred\n    /// @param _borrower The address of the account in which collateral is being removed\n    event RemoveCollateral(\n        uint256 _collateralAmount,\n        address indexed _receiver,\n        address indexed _borrower\n    );\n\n    /// @notice The ```_removeCollateral``` function is the internal implementation for removing collateral from a borrower's position\n    /// @param _collateralAmount The amount of Collateral Token to remove from the borrower's position\n    /// @param _receiver The address to receive the Collateral Token transferred\n    /// @param _borrower The borrower whose account will be debited the Collateral amount\n    function _removeCollateral(uint256 _collateralAmount, address _receiver, address _borrower) internal {\n\n        // Effects: write to state\n        // NOTE: Following line will revert on underflow if _collateralAmount > userCollateralBalance\n        _userCollateralBalance[_borrower] -= _collateralAmount;\n\n        //unstake underlying\n        //NOTE: following will revert on underflow if total collateral < _collateralAmount\n        _unstakeUnderlying(_collateralAmount);\n\n        // Interactions\n        if (_receiver != address(this)) {\n            collateral.safeTransfer(_receiver, _collateralAmount);\n        }\n        emit RemoveCollateral(_collateralAmount, _receiver, _borrower);\n    }\n\n    /// @notice The ```removeCollateralVault``` function is used to remove collateral from msg.sender's borrow position\n    /// @dev msg.sender must be solvent after invocation or transaction will revert\n    /// @param _collateralAmount The amount of Collateral Token to transfer\n    /// @param _receiver The address to receive the transferred funds\n    function removeCollateralVault(\n        uint256 _collateralAmount,\n        address _receiver\n    ) external nonReentrant isSolvent(msg.sender) {\n        //note: isSolvent checkpoints msg.sender via _syncUserRedemptions\n\n        if (_receiver == address(0)) revert InvalidReceiver();\n\n        _addInterest();\n        // Note: exchange rate is irrelevant when borrower has no debt shares\n        if (_userBorrowShares[msg.sender] > 0) {\n            _updateExchangeRate();\n        }\n        _removeCollateral(_collateralAmount, _receiver, msg.sender);\n    }\n\n    /// @notice The ```removeCollateral``` function is used to remove collateral from msg.sender's borrow position and redeem it for underlying tokens\n    /// @dev msg.sender must be solvent after invocation or transaction will revert\n    /// @param _collateralAmount The amount of Collateral Token to redeem\n    /// @param _receiver The address to receive the redeemed underlying tokens\n    function removeCollateral(\n        uint256 _collateralAmount,\n        address _receiver\n    ) external nonReentrant isSolvent(msg.sender) {\n        //note: isSolvent checkpoints msg.sender via _syncUserRedemptions\n\n        if (_receiver == address(0)) revert InvalidReceiver();\n\n        _addInterest();\n        // Note: exchange rate is irrelevant when borrower has no debt shares\n        if (_userBorrowShares[msg.sender] > 0) {\n            _updateExchangeRate();\n        }\n        _removeCollateral(_collateralAmount, address(this), msg.sender);\n        IERC4626(address(collateral)).redeem(_collateralAmount, _receiver, address(this));\n    }\n\n    /// @notice The ```Repay``` event is emitted whenever a debt position is repaid\n    /// @param payer The address paying for the repayment\n    /// @param borrower The borrower whose account will be credited\n    /// @param amountToRepay The amount of Asset token to be transferred\n    /// @param shares The amount of Borrow Shares which will be debited from the borrower after repayment\n    event Repay(address indexed payer, address indexed borrower, uint256 amountToRepay, uint256 shares);\n\n    /// @notice The ```_repay``` function is the internal implementation for repaying a borrow position\n    /// @dev The payer must have called ERC20.approve() on the Asset Token contract prior to invocation\n    /// @param _totalBorrow An in memory copy of the totalBorrow VaultAccount struct\n    /// @param _amountToRepay The amount of Asset Token to transfer\n    /// @param _shares The number of Borrow Shares the sender is repaying\n    /// @param _payer The address from which funds will be transferred\n    /// @param _borrower The borrower account which will be credited\n    function _repay(\n        VaultAccount memory _totalBorrow,\n        uint128 _amountToRepay,\n        uint128 _shares,\n        address _payer,\n        address _borrower\n    ) internal {\n        //checkpoint rewards for borrower before adjusting borrow shares\n        _checkpoint(_borrower);\n\n        // Effects: Bookkeeping\n        _totalBorrow.amount -= _amountToRepay;\n        _totalBorrow.shares -= _shares;\n\n        // Effects: write user state\n        uint256 usershares = _userBorrowShares[_borrower] - _shares;\n        _userBorrowShares[_borrower] = usershares;\n    \n        //check that any remaining user amount is greater than minimumBorrowAmount\n        if(usershares > 0 && _totalBorrow.toAmount(usershares, true) < minimumBorrowAmount){\n            revert InsufficientBorrowAmount();\n        }\n\n        // Effects: write global state\n        totalBorrow = _totalBorrow;\n\n        // Interactions\n        // burn from non-zero address.  zero address is only supplied during liquidations\n        // for liqudations the handler will do the burning\n        if (_payer != address(0)) {\n            IMintable(address(debtToken)).burn(_payer, _amountToRepay);\n        }\n        emit Repay(_payer, _borrower, _amountToRepay, _shares);\n    }\n\n    /// @notice The ```repay``` function allows the caller to pay down the debt for a given borrower.\n    /// @dev Caller must first invoke ```ERC20.approve()``` for the Asset Token contract\n    /// @param _shares The number of Borrow Shares which will be repaid by the call\n    /// @param _borrower The account for which the debt will be reduced\n    /// @return _amountToRepay The amount of Asset Tokens which were burned to repay the Borrow Shares\n    function repay(uint256 _shares, address _borrower) external nonReentrant returns (uint256 _amountToRepay) {\n        if (_borrower == address(0)) revert InvalidReceiver();\n\n        // Accrue interest if necessary\n        _addInterest();\n\n        // Calculate amount to repay based on shares\n        VaultAccount memory _totalBorrow = totalBorrow;\n        _amountToRepay = _totalBorrow.toAmount(_shares, true);\n\n        // Execute repayment effects\n        _repay(_totalBorrow, _amountToRepay.toUint128(), _shares.toUint128(), msg.sender, _borrower);\n    }\n\n    // ============================================================================================\n    // Functions: Redemptions\n    // ============================================================================================\n    event Redeemed(\n        address indexed _caller,\n        uint256 _amount,\n        uint256 _collateralFreed,\n        uint256 _protocolFee,\n        uint256 _debtReduction\n    );\n\n    /// @notice Allows redemption of the debt tokens for collateral\n    /// @dev Only callable by the registry's redeemer contract\n    /// @param _caller The address of the caller\n    /// @param _amount The amount of debt tokens to redeem\n    /// @param _totalFeePct Total fee to charge, expressed as a percentage of the stablecoin input; to be subdivided between protocol and borrowers.\n    /// @param _receiver The address to receive the collateral tokens\n    /// @return _collateralToken The address of the collateral token\n    /// @return _collateralFreed The amount of collateral tokens returned to receiver\n    function redeemCollateral(\n        address _caller,\n        uint256 _amount,\n        uint256 _totalFeePct,\n        address _receiver\n    ) external nonReentrant returns(address _collateralToken, uint256 _collateralFreed){\n        //check sender. must go through the registry's redemptionHandler\n        if(msg.sender != IResupplyRegistry(registry).redemptionHandler()) revert InvalidRedemptionHandler();\n\n        if (_receiver == address(0) || _receiver == address(this)) revert InvalidReceiver();\n\n        if(_amount < minimumRedemption){\n          revert MinimumRedemption();\n        }\n\n        // accrue interest if necessary\n        _addInterest();\n\n        //redemption fees\n        //assuming 1% redemption fee(0.5% to protocol, 0.5% to borrowers) and a redemption of $100\n        // reduce totalBorrow.amount by 99.5$\n        // add 0.5$ to protocol earned fees\n        // return 99$ of collateral\n        // burn $100 of stables\n        uint256 valueToRedeem = _amount * (EXCHANGE_PRECISION - _totalFeePct) / EXCHANGE_PRECISION;\n        uint256 protocolFee = (_amount - valueToRedeem) * protocolRedemptionFee / EXCHANGE_PRECISION;\n        uint256 debtReduction = _amount - protocolFee; // protocol fee portion is not burned\n\n        //check if theres enough debt to write off\n        VaultAccount memory _totalBorrow = totalBorrow;\n        if(debtReduction > _totalBorrow.amount || _totalBorrow.amount - debtReduction < minimumLeftoverDebt ){\n            revert InsufficientDebtToRedeem(); // size of request exceeeds total pair debt\n        }\n\n        _totalBorrow.amount -= uint128(debtReduction);\n\n        //if after many redemptions the amount to shares ratio has deteriorated too far, then refactor\n        //cast to uint256 to reduce chance of overflow\n        if(uint256(_totalBorrow.amount) * SHARE_REFACTOR_PRECISION < _totalBorrow.shares){\n            _increaseRewardEpoch(); //will do final checkpoint on previous total supply\n            _totalBorrow.shares /= uint128(SHARE_REFACTOR_PRECISION);\n        }\n\n        // Effects: write to state\n        totalBorrow = _totalBorrow;\n\n        claimableOtherFees += protocolFee; //increase claimable fees\n\n        // Update exchange rate\n        uint256 _exchangeRate = _updateExchangeRate();\n        //calc collateral units\n        _collateralFreed = ((valueToRedeem * _exchangeRate) / EXCHANGE_PRECISION);\n        \n        _unstakeUnderlying(_collateralFreed);\n        _collateralToken = address(collateral);\n        IERC20(_collateralToken).safeTransfer(_receiver, _collateralFreed);\n\n        //distribute write off tokens to adjust userCollateralbalances\n        //padded with LTV_PRECISION for extra precision\n        redemptionWriteOff.mint(_collateralFreed * LTV_PRECISION);\n\n        emit Redeemed(_caller, _amount, _collateralFreed, protocolFee, debtReduction);\n    }\n\n    // ============================================================================================\n    // Functions: Liquidations\n    // ============================================================================================\n    /// @notice The ```Liquidate``` event is emitted when a liquidation occurs\n    /// @param _borrower The borrower account for which the liquidation occurred\n    /// @param _collateralForLiquidator The amount of collateral token transferred to the liquidator\n    /// @param _sharesLiquidated The number of borrow shares liquidated\n    /// @param _amountLiquidatorToRepay The amount of asset tokens to be repaid by the liquidator\n    event Liquidate(\n        address indexed _borrower,\n        uint256 _collateralForLiquidator,\n        uint256 _sharesLiquidated,\n        uint256 _amountLiquidatorToRepay\n    );\n\n    /// @notice The ```liquidate``` function allows a third party to repay a borrower's debt if they have become insolvent\n    /// @dev Caller must invoke ```ERC20.approve``` on the Asset Token contract prior to calling ```Liquidate()```\n    /// @param _borrower The account for which the repayment is credited and from whom collateral will be taken\n    /// @return _collateralForLiquidator The amount of Collateral Token transferred to the liquidator\n    function liquidate(\n        address _borrower\n    ) external nonReentrant returns (uint256 _collateralForLiquidator) {\n        address liquidationHandler = IResupplyRegistry(registry).liquidationHandler();\n        if(msg.sender != liquidationHandler) revert InvalidLiquidator();\n\n        if (_borrower == address(0)) revert InvalidReceiver();\n\n        // accrue interest if necessary\n        _addInterest();\n\n        // Update exchange rate and use the lower rate for liquidations\n        uint256 _exchangeRate = _updateExchangeRate();\n\n        // Check if borrower is solvent, revert if they are\n        //_isSolventSync calls _syncUserRedemptions which checkpoints rewards and userCollateral\n        if (_isSolventSync(_borrower, _exchangeRate)) {\n            revert BorrowerSolvent();\n        }\n\n        // Read from state\n        VaultAccount memory _totalBorrow = totalBorrow;\n        uint256 _collateralBalance = _userCollateralBalance[_borrower];\n        uint128 _borrowerShares = _userBorrowShares[_borrower].toUint128();\n\n        // Checks & Calculations\n        // Determine the liquidation amount in collateral units (i.e. how much debt liquidator is going to repay)\n        uint256 _liquidationAmountInCollateralUnits = ((_totalBorrow.toAmount(_borrowerShares, false) *\n            _exchangeRate) / EXCHANGE_PRECISION);\n\n        // add fee for liquidation\n        _collateralForLiquidator = (_liquidationAmountInCollateralUnits *\n            (LIQ_PRECISION + liquidationFee)) / LIQ_PRECISION;\n\n        // clamp to user collateral balance as we cant take more than that\n        _collateralForLiquidator = _collateralForLiquidator > _collateralBalance ? _collateralBalance : _collateralForLiquidator;\n\n        // Calculated here for use during repayment, grouped with other calcs before effects start\n        uint128 _amountLiquidatorToRepay = (_totalBorrow.toAmount(_borrowerShares, true)).toUint128();\n\n        emit Liquidate(\n                _borrower,\n                _collateralForLiquidator,\n                _borrowerShares,\n                _amountLiquidatorToRepay\n            );\n\n        // Effects & Interactions\n        // repay using address(0) to skip burning (liquidationHandler will burn from insurance pool)\n        _repay(\n            _totalBorrow,\n            _amountLiquidatorToRepay,\n            _borrowerShares,\n            address(0),\n            _borrower\n        );\n\n        // Collateral is removed on behalf of borrower and sent to liquidationHandler\n        // NOTE: isSolvent above checkpoints user with _syncUserRedemptions before removing collateral\n        _removeCollateral(_collateralForLiquidator, liquidationHandler, _borrower);\n\n        //call liquidation handler to distribute and burn debt\n        ILiquidationHandler(liquidationHandler).processLiquidationDebt(address(collateral), _collateralForLiquidator, _amountLiquidatorToRepay);\n    }\n\n    // ============================================================================================\n    // Functions: Leverage\n    // ============================================================================================\n\n    /// @notice The ```LeveragedPosition``` event is emitted when a borrower takes out a new leveraged position\n    /// @param _borrower The account for which the debt is debited\n    /// @param _swapperAddress The address of the swapper which conforms the FraxSwap interface\n    /// @param _borrowAmount The amount of Asset Token to be borrowed to be borrowed\n    /// @param _borrowShares The number of Borrow Shares the borrower is credited\n    /// @param _initialUnderlyingAmount The amount of initial underlying Tokens supplied by the borrower\n    /// @param _amountCollateralOut The amount of Collateral Token which was received for the Asset Tokens\n    event LeveragedPosition(\n        address indexed _borrower,\n        address _swapperAddress,\n        uint256 _borrowAmount,\n        uint256 _borrowShares,\n        uint256 _initialUnderlyingAmount,\n        uint256 _amountCollateralOut\n    );\n\n    /// @notice The ```leveragedPosition``` function allows a user to enter a leveraged borrow position with minimal upfront Underlying tokens\n    /// @dev Caller must invoke ```ERC20.approve()``` on the Underlying Token contract prior to calling function\n    /// @param _swapperAddress The address of the whitelisted swapper to use to swap borrowed Asset Tokens for Collateral Tokens\n    /// @param _borrowAmount The amount of Asset Tokens borrowed\n    /// @param _initialUnderlyingAmount The initial amount of underlying Tokens supplied by the borrower\n    /// @param _amountCollateralOutMin The minimum amount of Collateral Tokens to be received in exchange for the borrowed Asset Tokens\n    /// @param _path An array containing the addresses of ERC20 tokens to swap.  Adheres to UniV2 style path params.\n    /// @return _totalCollateralBalance The total amount of Collateral Tokens added to a users account (initial + swap)\n    function leveragedPosition(\n        address _swapperAddress,\n        uint256 _borrowAmount,\n        uint256 _initialUnderlyingAmount,\n        uint256 _amountCollateralOutMin,\n        address[] memory _path\n    ) external nonReentrant isSolvent(msg.sender) returns (uint256 _totalCollateralBalance) {\n        // Accrue interest if necessary\n        _addInterest();\n\n        // Update exchange rate\n        _updateExchangeRate();\n\n        IERC20 _debtToken = debtToken;\n        IERC20 _collateral = collateral;\n\n        if (!swappers[_swapperAddress]) {\n            revert BadSwapper();\n        }\n        if (_path[0] != address(_debtToken)) {\n            revert InvalidPath(address(_debtToken), _path[0]);\n        }\n        if (_path[_path.length - 1] != address(_collateral)) {\n            revert InvalidPath(address(_collateral), _path[_path.length - 1]);\n        }\n\n        // Add initial underlying\n        if (_initialUnderlyingAmount > 0) {\n            underlying.safeTransferFrom(msg.sender, address(this), _initialUnderlyingAmount);\n            uint256 collateralShares = IERC4626(address(collateral)).deposit(_initialUnderlyingAmount, address(this));\n            _addCollateral(address(this), collateralShares, msg.sender);\n            _totalCollateralBalance = collateralShares;\n        }\n\n        // Debit borrowers account\n        // setting recipient to _swapperAddress allows us to skip a transfer (debt still goes to msg.sender)\n        uint256 _borrowShares = _borrow(_borrowAmount.toUint128(), _swapperAddress);\n\n        // Even though swappers are trusted, we verify the balance before and after swap\n        uint256 _initialCollateralBalance = _collateral.balanceOf(address(this));\n        ISwapper(_swapperAddress).swap(\n            msg.sender,\n            _borrowAmount,\n            _path,\n            address(this)\n        );\n        uint256 _finalCollateralBalance = _collateral.balanceOf(address(this));\n\n        // Note: VIOLATES CHECKS-EFFECTS-INTERACTION pattern, make sure function is NONREENTRANT\n        // Effects: bookkeeping & write to state\n        uint256 _amountCollateralOut = _finalCollateralBalance - _initialCollateralBalance;\n        if (_amountCollateralOut < _amountCollateralOutMin) {\n            revert SlippageTooHigh(_amountCollateralOutMin, _amountCollateralOut);\n        }\n\n        // address(this) as _sender means no transfer occurs as the pair has already received the collateral during swap\n        _addCollateral(address(this), _amountCollateralOut, msg.sender);\n\n        _totalCollateralBalance += _amountCollateralOut;\n        emit LeveragedPosition(\n            msg.sender,\n            _swapperAddress,\n            _borrowAmount,\n            _borrowShares,\n            _initialUnderlyingAmount,\n            _amountCollateralOut\n        );\n    }\n\n    /// @notice The ```RepayWithCollateral``` event is emitted whenever ```repayWithCollateral()``` is invoked\n    /// @param _borrower The borrower account for which the repayment is taking place\n    /// @param _swapperAddress The address of the whitelisted swapper to use for token swaps\n    /// @param _collateralToSwap The amount of Collateral Token to swap and use for repayment\n    /// @param _amountAssetOut The amount of Asset Token which was repaid\n    /// @param _sharesRepaid The number of Borrow Shares which were repaid\n    event RepayWithCollateral(\n        address indexed _borrower,\n        address _swapperAddress,\n        uint256 _collateralToSwap,\n        uint256 _amountAssetOut,\n        uint256 _sharesRepaid\n    );\n\n    /// @notice The ```repayWithCollateral``` function allows a borrower to repay their debt using existing collateral in contract\n    /// @param _swapperAddress The address of the whitelisted swapper to use for token swaps\n    /// @param _collateralToSwap The amount of Collateral Tokens to swap for Asset Tokens\n    /// @param _amountOutMin The minimum amount of Asset Tokens to receive during the swap\n    /// @param _path An array containing the addresses of ERC20 tokens to swap.  Adheres to UniV2 style path params.\n    /// @return _amountOut The amount of Asset Tokens received for the Collateral Tokens, the amount the borrowers account was credited\n    function repayWithCollateral(\n        address _swapperAddress,\n        uint256 _collateralToSwap,\n        uint256 _amountOutMin,\n        address[] calldata _path\n    ) external nonReentrant isSolvent(msg.sender) returns (uint256 _amountOut) {\n        // Accrue interest if necessary\n        _addInterest();\n\n        // Update exchange rate\n        _updateExchangeRate();\n\n        IERC20 _debtToken = debtToken;\n        IERC20 _collateral = collateral;\n        VaultAccount memory _totalBorrow = totalBorrow;\n\n        if (!swappers[_swapperAddress]) {\n            revert BadSwapper();\n        }\n        if (_path[0] != address(_collateral)) {\n            revert InvalidPath(address(_collateral), _path[0]);\n        }\n        if (_path[_path.length - 1] != address(_debtToken)) {\n            revert InvalidPath(address(_debtToken), _path[_path.length - 1]);\n        }\n        //in case of a full redemption/shutdown via protocol,\n        //all user debt should be 0 and thus swapping to repay is unnecessary.\n        //toShares below will also return an incorrect value.\n        //in case of a full redemption, users can use the normal repayAsset with 0 cost\n        //or just withdraw collateral via removeCollateral\n        if(_totalBorrow.amount == 0){\n            revert InsufficientBorrowAmount();\n        }\n\n        // Effects: bookkeeping & write to state\n        // Debit users collateral balance and sends directly to the swapper\n        // NOTE: isSolvent checkpoints msg.sender with _syncUserRedemptions\n        _removeCollateral(_collateralToSwap, _swapperAddress, msg.sender);\n\n        // Even though swappers are trusted, we verify the balance before and after swap\n        uint256 _initialBalance = _debtToken.balanceOf(address(this));\n        ISwapper(_swapperAddress).swap(\n            msg.sender,\n            _collateralToSwap,\n            _path,\n            address(this)\n        );\n\n        // Note: VIOLATES CHECKS-EFFECTS-INTERACTION pattern, make sure function is NONREENTRANT\n        // Effects: bookkeeping\n        _amountOut = _debtToken.balanceOf(address(this)) - _initialBalance;\n        if (_amountOut < _amountOutMin) {\n            revert SlippageTooHigh(_amountOutMin, _amountOut);\n        }\n\n        \n        uint256 _sharesToRepay = _totalBorrow.toShares(_amountOut, false);\n\n        //check if over user borrow shares or will revert\n        uint256 currentUserBorrowShares = _userBorrowShares[msg.sender];\n        if(_sharesToRepay > currentUserBorrowShares){\n            //clamp\n            _sharesToRepay = currentUserBorrowShares;\n\n            //readjust token amount since shares changed\n            _amountOut = _totalBorrow.toAmount(_sharesToRepay, true);\n        }\n        \n\n        // Effects: write to state\n        _repay(_totalBorrow, _amountOut.toUint128(), _sharesToRepay.toUint128(), address(this), msg.sender);\n\n        //check for leftover stables that didnt go toward repaying debt\n        uint256 leftover = debtToken.balanceOf(address(this)) - _initialBalance;\n        if(leftover > 0){\n            //send change back to user\n            debtToken.transfer(msg.sender, leftover);\n        }\n\n        emit RepayWithCollateral(msg.sender, _swapperAddress, _collateralToSwap, _amountOut, _sharesToRepay);\n    }\n}"},{"file_path":"node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\nimport {Address} from \"../../../utils/Address.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 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":"src/interfaces/IFeeDeposit.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface IFeeDeposit {\n    function operator() external view returns(address);\n    function lastDistributedEpoch() external view returns(uint256);\n    function setOperator(address _newAddress) external;\n    function distributeFees() external;\n    function incrementPairRevenue(uint256 _fees, uint256 _otherFees) external;\n}"},{"file_path":"node_modules/@openzeppelin/contracts/utils/Context.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\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 Context {\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":"src/interfaces/ISwapper.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface ISwapper {\n    function swap(\n        address account,\n        uint256 amountIn,\n        address[] calldata path,\n        address to\n    ) external;\n\n    function swapPools(address tokenIn, address tokenOut) external view returns(address swappool, int32 tokenInIndex, int32 tokenOutIndex, uint32 swaptype);\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/utils/Address.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol)\n\npragma solidity ^0.8.20;\n\nimport {Errors} from \"./Errors.sol\";\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev There's no code at `target` (it is not a contract).\n     */\n    error AddressEmptyCode(address target);\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        if (address(this).balance < amount) {\n            revert Errors.InsufficientBalance(address(this).balance, amount);\n        }\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        if (!success) {\n            revert Errors.FailedCall();\n        }\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason or custom error, it is bubbled\n     * up by this function (like regular Solidity function calls). However, if\n     * the call reverted with no returned reason, this function reverts with a\n     * {Errors.FailedCall} error.\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        if (address(this).balance < value) {\n            revert Errors.InsufficientBalance(address(this).balance, value);\n        }\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n     * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case\n     * of an unsuccessful call.\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata\n    ) internal view returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            // only check if target is a contract if the call was successful and the return data is empty\n            // otherwise we already know that it was a contract\n            if (returndata.length == 0 && target.code.length == 0) {\n                revert AddressEmptyCode(target);\n            }\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n     * revert reason or with a default {Errors.FailedCall} error.\n     */\n    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.\n     */\n    function _revert(bytes memory returndata) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            assembly (\"memory-safe\") {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert Errors.FailedCall();\n        }\n    }\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/utils/ReentrancyGuard.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\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 ReentrancyGuard {\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    uint256 private _status;\n\n    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\n\n    constructor() {\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        // 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        // 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        return _status == ENTERED;\n    }\n}\n"},{"file_path":"src/interfaces/IConvexStaking.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface IConvexStaking {\n    function poolInfo(uint256 _pid) external view returns(\n        address lptoken,\n        address token,\n        address gauge,\n        address crvRewards,\n        address stash,\n        bool shutdown\n    );\n    function deposit(uint256 _pid, uint256 _amount, bool _stake) external returns(bool);\n    function depositAll(uint256 _pid, bool _stake) external returns(bool);\n    function withdrawAndUnwrap(uint256 amount, bool claim) external returns(bool);\n    function withdrawAllAndUnwrap(bool claim) external;\n    function getReward() external returns(bool);\n    function getReward(address _account, bool _claimExtras) external returns(bool);\n    function totalSupply() external view returns (uint256);\n    function extraRewardsLength() external view returns (uint256);\n    function extraRewards(uint256 _rid) external view returns (address _rewardContract);\n    function rewardToken() external view returns (address _rewardToken);\n    function token() external view returns (address _token);\n    function balanceOf(address account) external view returns (uint256);\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"_core","type":"address"},{"internalType":"bytes","name":"_configData","type":"bytes"},{"internalType":"bytes","name":"_immutables","type":"bytes"},{"internalType":"bytes","name":"_customConfigData","type":"bytes"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadSwapper","type":"error"},{"inputs":[],"name":"BorrowerSolvent","type":"error"},{"inputs":[],"name":"FeesAlreadyDistributed","type":"error"},{"inputs":[],"name":"IncorrectStakeBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"_borrow","type":"uint256"},{"internalType":"uint256","name":"_collateral","type":"uint256"},{"internalType":"uint256","name":"_exchangeRate","type":"uint256"}],"name":"Insolvent","type":"error"},{"inputs":[],"name":"InsufficientBorrowAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"uint256","name":"_request","type":"uint256"}],"name":"InsufficientDebtAvailable","type":"error"},{"inputs":[],"name":"InsufficientDebtToRedeem","type":"error"},{"inputs":[],"name":"InvalidLiquidator","type":"error"},{"inputs":[],"name":"InvalidParameter","type":"error"},{"inputs":[{"internalType":"address","name":"_expected","type":"address"},{"internalType":"address","name":"_actual","type":"address"}],"name":"InvalidPath","type":"error"},{"inputs":[],"name":"InvalidReceiver","type":"error"},{"inputs":[],"name":"InvalidRedemptionHandler","type":"error"},{"inputs":[],"name":"MinimumRedemption","type":"error"},{"inputs":[],"name":"OnlyProtocolOrOwner","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"uint256","name":"_minOut","type":"uint256"},{"internalType":"uint256","name":"_actual","type":"uint256"}],"name":"SlippageTooHigh","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"AddCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"interestEarned","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"AddInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"_borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_sharesAdded","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_mintFees","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"address","name":"_swapperAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_borrowShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_initialUnderlyingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amountCollateralOut","type":"uint256"}],"name":"LeveragedPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"_collateralForLiquidator","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_sharesLiquidated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amountLiquidatorToRepay","type":"uint256"}],"name":"Liquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"NewEpoch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_collateralFreed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_protocolFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_debtReduction","type":"uint256"}],"name":"Redeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_collateralAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":true,"internalType":"address","name":"_borrower","type":"address"}],"name":"RemoveCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountToRepay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"address","name":"_swapperAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_collateralToSwap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amountAssetOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_sharesRepaid","type":"uint256"}],"name":"RepayWithCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_rewardToken","type":"address"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_rewardToken","type":"address"}],"name":"RewardInvalidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_rewardToken","type":"address"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"_rewardAmount","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"},{"indexed":false,"internalType":"address","name":"_forward","type":"address"}],"name":"RewardRedirected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"SetBorrowLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pid","type":"uint256"}],"name":"SetConvexPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLiquidationFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLiquidationFee","type":"uint256"}],"name":"SetLiquidationFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMaxLTV","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxLTV","type":"uint256"}],"name":"SetMaxLTV","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"min","type":"uint256"}],"name":"SetMinimumBorrowAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"min","type":"uint256"}],"name":"SetMinimumLeftover","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"min","type":"uint256"}],"name":"SetMinimumRedemption","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMintFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMintFee","type":"uint256"}],"name":"SetMintFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOracle","type":"address"},{"indexed":false,"internalType":"address","name":"newOracle","type":"address"}],"name":"SetOracleInfo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"SetProtocolRedemptionFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldRateCalculator","type":"address"},{"indexed":false,"internalType":"address","name":"newRateCalculator","type":"address"}],"name":"SetRateCalculator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"swapper","type":"address"},{"indexed":false,"internalType":"bool","name":"approval","type":"bool"}],"name":"SetSwapper","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"name":"UpdateExchangeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRatePerSec","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"oldShares","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"newRatePerSec","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"newShares","type":"uint128"}],"name":"UpdateRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"interestFees","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"otherFees","type":"uint256"}],"name":"WithdrawFees","type":"event"},{"inputs":[],"name":"CRV","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CVX","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXCHANGE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIQ_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LTV_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAIR_DECIMALS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARE_REFACTOR_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_borrower","type":"address"}],"name":"addCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collateralAmount","type":"uint256"},{"internalType":"address","name":"_borrower","type":"address"}],"name":"addCollateralVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"addExtraReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_returnAccounting","type":"bool"}],"name":"addInterest","outputs":[{"internalType":"uint256","name":"_interestEarned","type":"uint256"},{"components":[{"internalType":"uint64","name":"lastTimestamp","type":"uint64"},{"internalType":"uint64","name":"ratePerSec","type":"uint64"},{"internalType":"uint128","name":"lastShares","type":"uint128"}],"internalType":"struct ResupplyPairCore.CurrentRateInfo","name":"_currentRateInfo","type":"tuple"},{"internalType":"uint256","name":"_claimableFees","type":"uint256"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"shares","type":"uint128"}],"internalType":"struct VaultAccount","name":"_totalBorrow","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_borrowAmount","type":"uint256"},{"internalType":"uint256","name":"_underlyingAmount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimableFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimableOtherFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"claimable_reward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"convexBooster","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"convexPid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"core","outputs":[{"internalType":"contract ICore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentRateInfo","outputs":[{"internalType":"uint64","name":"lastTimestamp","type":"uint64"},{"internalType":"uint64","name":"ratePerSec","type":"uint64"},{"internalType":"uint128","name":"lastShares","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentRewardEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentUtilization","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"earned","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct RewardDistributorMultiEpoch.EarnedData[]","name":"claimable","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"epochLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRateInfo","outputs":[{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint96","name":"lastTimestamp","type":"uint96"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConstants","outputs":[{"internalType":"uint256","name":"_LTV_PRECISION","type":"uint256"},{"internalType":"uint256","name":"_LIQ_PRECISION","type":"uint256"},{"internalType":"uint256","name":"_EXCHANGE_PRECISION","type":"uint256"},{"internalType":"uint256","name":"_RATE_PRECISION","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getEpoch","outputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPairAccounting","outputs":[{"internalType":"uint256","name":"_claimableFees","type":"uint256"},{"internalType":"uint128","name":"_totalBorrowAmount","type":"uint128"},{"internalType":"uint128","name":"_totalBorrowShares","type":"uint128"},{"internalType":"uint256","name":"_totalCollateral","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_forwardTo","type":"address"}],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"getUserSnapshot","outputs":[{"internalType":"uint256","name":"_borrowShares","type":"uint256"},{"internalType":"uint256","name":"_collateralBalance","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"global_reward_integral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"invalidateReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastFeeEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_swapperAddress","type":"address"},{"internalType":"uint256","name":"_borrowAmount","type":"uint256"},{"internalType":"uint256","name":"_initialUnderlyingAmount","type":"uint256"},{"internalType":"uint256","name":"_amountCollateralOutMin","type":"uint256"},{"internalType":"address[]","name":"_path","type":"address[]"}],"name":"leveragedPosition","outputs":[{"internalType":"uint256","name":"_totalCollateralBalance","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"liquidate","outputs":[{"internalType":"uint256","name":"_collateralForLiquidator","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidationFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLTV","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"minimumBorrowAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumLeftoverDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumRedemption","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"previewAddInterest","outputs":[{"internalType":"uint256","name":"_interestEarned","type":"uint256"},{"components":[{"internalType":"uint64","name":"lastTimestamp","type":"uint64"},{"internalType":"uint64","name":"ratePerSec","type":"uint64"},{"internalType":"uint128","name":"lastShares","type":"uint128"}],"internalType":"struct ResupplyPairCore.CurrentRateInfo","name":"_newCurrentRateInfo","type":"tuple"},{"internalType":"uint256","name":"_claimableFees","type":"uint256"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"shares","type":"uint128"}],"internalType":"struct VaultAccount","name":"_totalBorrow","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolRedemptionFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rateCalculator","outputs":[{"internalType":"contract IRateCalculator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_caller","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_totalFeePct","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"redeemCollateral","outputs":[{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"uint256","name":"_collateralFreed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redemptionWriteOff","outputs":[{"internalType":"contract WriteOffToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collateralAmount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"removeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collateralAmount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"removeCollateralVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_borrower","type":"address"}],"name":"repay","outputs":[{"internalType":"uint256","name":"_amountToRepay","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_swapperAddress","type":"address"},{"internalType":"uint256","name":"_collateralToSwap","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"address[]","name":"_path","type":"address[]"}],"name":"repayWithCollateral","outputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardMap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardRedirect","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"reward_integral_for","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewards","outputs":[{"internalType":"address","name":"reward_token","type":"address"},{"internalType":"bool","name":"is_non_claimable","type":"bool"},{"internalType":"uint256","name":"reward_remaining","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"setBorrowLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"}],"name":"setConvexPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newLiquidationFee","type":"uint256"}],"name":"setLiquidationFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMaxLTV","type":"uint256"}],"name":"setMaxLTV","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_min","type":"uint256"}],"name":"setMinimumBorrowAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_min","type":"uint256"}],"name":"setMinimumLeftoverDebt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_min","type":"uint256"}],"name":"setMinimumRedemption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMintFee","type":"uint256"}],"name":"setMintFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOracle","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setProtocolRedemptionFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newRateCalculator","type":"address"},{"internalType":"bool","name":"_updateInterest","type":"bool"}],"name":"setRateCalculator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"setRewardRedirect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_swapper","type":"address"},{"internalType":"bool","name":"_approval","type":"bool"}],"name":"setSwapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"swappers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"bool","name":"_roundUp","type":"bool"},{"internalType":"bool","name":"_previewInterest","type":"bool"}],"name":"toBorrowAmount","outputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_roundUp","type":"bool"},{"internalType":"bool","name":"_previewInterest","type":"bool"}],"name":"toBorrowShares","outputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrow","outputs":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"shares","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCollateral","outputs":[{"internalType":"uint256","name":"_totalCollateralBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDebtAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateExchangeRate","outputs":[{"internalType":"uint256","name":"_exchangeRate","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"userBorrowShares","outputs":[{"internalType":"uint256","name":"borrowShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"userCollateralBalance","outputs":[{"internalType":"uint256","name":"_collateralAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRewardEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_epochloops","type":"uint256"}],"name":"user_checkpoint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"_major","type":"uint256"},{"internalType":"uint256","name":"_minor","type":"uint256"},{"internalType":"uint256","name":"_patch","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"withdrawFees","outputs":[{"internalType":"uint256","name":"_fees","type":"uint256"},{"internalType":"uint256","name":"_otherFees","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":"0x000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001000000000000000000000000008e3009b59200668e1efda0a2f2ac42b24baa2982000000000000000000000000cb7e25fbbd8afe4ce73d7dac647dbc3d847f3c8200000000000000000000000077777777729c405efb6ac823493e6111f0070d67000000000000000000000000000000000000000000000000000000000001731800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001388000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f05b59d3b20000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000010101010e0c3171d894b71b3400668af311e7d9400000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f726000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae3100000000000000000000000000000000000000000000000000000000000001b6000000000000000000000000000000000000000000000000000000000000002d5265737570706c792050616972202843757276654c656e643a206372765553442f7366727855534429202d203100000000000000000000000000000000000000"}