{"file_path":"src/contracts/StakedFrax.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.21;\n\n// ====================================================================\n// |     ______                   _______                             |\n// |    / _____________ __  __   / ____(_____  ____ _____  ________   |\n// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \\/ __ `/ __ \\/ ___/ _ \\  |\n// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |\n// | /_/   /_/   \\__,_/_/|_|  /_/   /_/_/ /_/\\__,_/_/ /_/\\___/\\___/   |\n// |                                                                  |\n// ====================================================================\n// ============================ StakedFrax ============================\n// ====================================================================\n// Frax Finance: https://github.com/FraxFinance\n\nimport { Timelock2Step } from \"frax-std/access-control/v2/Timelock2Step.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { SafeCastLib } from \"solmate/utils/SafeCastLib.sol\";\nimport { LinearRewardsErc4626, ERC20 } from \"./LinearRewardsErc4626.sol\";\n\n/// @title Staked Frax\n/// @notice A ERC4626 Vault implementation with linear rewards, rewards can be capped\ncontract StakedFrax is LinearRewardsErc4626, Timelock2Step {\n    using SafeCastLib for *;\n\n    /// @notice The maximum amount of rewards that can be distributed per second per 1e18 asset\n    uint256 public maxDistributionPerSecondPerAsset;\n\n    /// @param _underlying The erc20 asset deposited\n    /// @param _name The name of the vault\n    /// @param _symbol The symbol of the vault\n    /// @param _rewardsCycleLength The length of the rewards cycle in seconds\n    /// @param _maxDistributionPerSecondPerAsset The maximum amount of rewards that can be distributed per second per 1e18 asset\n    /// @param _timelockAddress The address of the timelock/owner contract\n    constructor(\n        IERC20 _underlying,\n        string memory _name,\n        string memory _symbol,\n        uint32 _rewardsCycleLength,\n        uint256 _maxDistributionPerSecondPerAsset,\n        address _timelockAddress\n    )\n        LinearRewardsErc4626(ERC20(address(_underlying)), _name, _symbol, _rewardsCycleLength)\n        Timelock2Step(_timelockAddress)\n    {\n        maxDistributionPerSecondPerAsset = _maxDistributionPerSecondPerAsset;\n    }\n\n    /// @notice The ```SetMaxDistributionPerSecondPerAsset``` event is emitted when the maxDistributionPerSecondPerAsset is set\n    /// @param oldMax The old maxDistributionPerSecondPerAsset value\n    /// @param newMax The new maxDistributionPerSecondPerAsset value\n    event SetMaxDistributionPerSecondPerAsset(uint256 oldMax, uint256 newMax);\n\n    /// @notice The ```setMaxDistributionPerSecondPerAsset``` function sets the maxDistributionPerSecondPerAsset\n    /// @dev This function can only be called by the timelock, caps the value to type(uint64).max\n    /// @param _maxDistributionPerSecondPerAsset The maximum amount of rewards that can be distributed per second per 1e18 asset\n    function setMaxDistributionPerSecondPerAsset(uint256 _maxDistributionPerSecondPerAsset) external {\n        _requireSenderIsTimelock();\n        syncRewardsAndDistribution();\n\n        // NOTE: prevents bricking the contract via overflow\n        if (_maxDistributionPerSecondPerAsset > type(uint64).max) {\n            _maxDistributionPerSecondPerAsset = type(uint64).max;\n        }\n\n        emit SetMaxDistributionPerSecondPerAsset({\n            oldMax: maxDistributionPerSecondPerAsset,\n            newMax: _maxDistributionPerSecondPerAsset\n        });\n\n        maxDistributionPerSecondPerAsset = _maxDistributionPerSecondPerAsset;\n    }\n\n    /// @notice The ```calculateRewardsToDistribute``` function calculates the amount of rewards to distribute based on the rewards cycle data and the time passed\n    /// @param _rewardsCycleData The rewards cycle data\n    /// @param _deltaTime The time passed since the last rewards distribution\n    /// @return _rewardToDistribute The amount of rewards to distribute\n    function calculateRewardsToDistribute(\n        RewardsCycleData memory _rewardsCycleData,\n        uint256 _deltaTime\n    ) public view override returns (uint256 _rewardToDistribute) {\n        _rewardToDistribute = super.calculateRewardsToDistribute({\n            _rewardsCycleData: _rewardsCycleData,\n            _deltaTime: _deltaTime\n        });\n\n        // Cap rewards\n        uint256 _maxDistribution = (maxDistributionPerSecondPerAsset * _deltaTime * storedTotalAssets) / PRECISION;\n        if (_rewardToDistribute > _maxDistribution) {\n            _rewardToDistribute = _maxDistribution;\n        }\n    }\n}\n","deployed_bytecode":"0x6040608081526004908136101561001557600080fd5b600091823560e01c91826301e1d11414611a4c57826306fdde031461198657826307a2d13a146112f0578263090f3f5014611933578263095ea7b3146118985782630a28a4771461185b57826318160ddd1461181e57826323b872dd146117055782632af98d6d146116c8578263313ce5671461166c578263358245fc146116315782633644e515146115f6578263374010a41461155157826338d52e0f146114e2578263402d267d14610787578263450140951461143457826348f76e0f146113805782634bc66f321461132d5782634cdad506146112f05782634f8b4ae71461121c57826356caf605146111c35782635ebae5661461114957826361c1c5e91461110c5782636e553f65146110c757826370a082311461039057826375e077c314610f395782637ecebe0014610ed75782638f765d5914610e5b57826394bf804d14610d7957826395d89b4114610c6357826399530b0614610c07578263a80e754714610bae578263a9059cbb14610b01578263aaf5eb6814610ac0578263b3d7f6b914610a83578263b460af9414610963578263ba087652146107c9578263bd6f36031461078c578263c63d75b614610787578263c6e6f592146102d4578263ce96cb7714610724578263d505accf14610430578263d71356e6146103f6578263d905777e14610390578263dd62ed3e14610318578263ef8b30f7146102d457505063f6ccaad41461022957600080fd5b346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761025f611d66565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600a5416600a55600b54903373ffffffffffffffffffffffffffffffffffffffff83167f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68580a3163317600b5580f35b80fd5b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611dd8565b9051908152f35b91503461038c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c576020928291610355611bd7565b61035d611bff565b9173ffffffffffffffffffffffffffffffffffffffff8092168452865283832091168252845220549051908152f35b8280fd5b8390346103f25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2578060209273ffffffffffffffffffffffffffffffffffffffff6103e2611bd7565b1681526003845220549051908152f35b5080fd5b83346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761042d6123fc565b80f35b8390346103f25760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257610469611bd7565b90610472611bff565b9160443560643592610482611c84565b924285106106c757610492611e9d565b9573ffffffffffffffffffffffffffffffffffffffff8092169586895260209560058752848a209889549960018b01905585519285898501957f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c987528b89870152169a8b606086015288608086015260a085015260c084015260c0835260e0830167ffffffffffffffff948482108683111761069a57818852845190206101008501927f19010000000000000000000000000000000000000000000000000000000000008452610102860152610122850152604281526101608401948186109086111761066e57848752519020835260ff1661018082015260a4356101a082015260c4356101c0909101528780528490889060809060015afa1561066457865116968715158061065b575b156106005786977f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259596975283528087208688528352818188205551908152a380f35b8360649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152fd5b508488146105bd565b81513d88823e3d90fd5b60248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5060248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b60648860208451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152fd5b8390346103f25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576103118160209373ffffffffffffffffffffffffffffffffffffffff610779611bd7565b168152600385522054611dfd565b611c22565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906008549051908152f35b9083346102d1576107d936611c94565b6107e5939291936123fc565b73ffffffffffffffffffffffffffffffffffffffff90818116938433036108f8575b5061081183611dfd565b95861561089b57509282602097959261083d88956108959761083588600954611e61565b6009556127d7565b865191858352898301528316907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db873392a47f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e61283e565b51908152f35b60649060208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600b60248201527f5a45524f5f4153534554530000000000000000000000000000000000000000006044820152fd5b848152866020528781203382526020528780822054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361093e575b505050610807565b61094791611e61565b9186815288602052818120338252602052205587878185610936565b8390346103f25761089560209361097936611c94565b959091926109856123fc565b6109c561099185611e3f565b809873ffffffffffffffffffffffffffffffffffffffff938985831696873303610a1e575b50505061083587600954611e61565b85519084825287898301528316907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db873392a47f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e61283e565b878152828e528181203382528e5281812054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610a60575b50506109b6565b610a6991611e61565b928882528e528181203382528e5220558b89818085610a59565b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611e1e565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25760209051670de0b6b3a76400008152f35b8390346103f257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602091610b3c611bd7565b8273ffffffffffffffffffffffffffffffffffffffff6024359233855260038752828520610b6b858254611e61565b90551692838152600386522081815401905582519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef843392a35160018152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090517f0000000000000000000000000000000000000000000000000de0b6b3a76400008152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906103117f0000000000000000000000000000000000000000000000000de0b6b3a7640000611dfd565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25780519082600190815491610ca683611a92565b918286526020938281169081600014610d395750600114610ce1575b610cdd8686610cd3828b0383611b30565b5191829182611b71565b0390f35b9295508083527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b828410610d265750505082610cdd94610cd3928201019486610cc2565b8054868501880152928601928101610d09565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001687860152505050151560051b8301019250610cd382610cdd86610cc2565b91503461038c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c57602092503590610db7611bff565b91610dc06123fc565b73ffffffffffffffffffffffffffffffffffffffff610dde82611e1e565b93610e0b8530337f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e612707565b610e1583826126a1565b8351928584528684015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7833392a3610e5282600954612199565b60095551908152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257606090610e966121f2565b907affffffffffffffffffffffffffffffffffffffffffffffffffffff8180519364ffffffffff808251168652602082015116602086015201511690820152f35b8390346103f25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2578060209273ffffffffffffffffffffffffffffffffffffffff610f29611bd7565b1681526005845220549051908152f35b83346102d15760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1578235610f73611bff565b916064359081151582036102d157610f89611c84565b91156110c1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e16803b1561038c579060e48884809460ff8b5198899687957fd505accf00000000000000000000000000000000000000000000000000000000875233908701523060248701526044860152604435606486015216608484015260a43560a484015260c43560c48401525af180156110b55761106a575b6020856103118686612598565b67ffffffffffffffff821161108957508352602093506103118561105d565b806041877f4e487b71000000000000000000000000000000000000000000000000000000006024945252fd5b508451903d90823e3d90fd5b82610fb1565b83346102d157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15750610311602092611105611bff565b9035612598565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906009549051908152f35b83346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15750600654600754915164ffffffffff808316825260289290921c90911660208201527affffffffffffffffffffffffffffffffffffffffffffffffffffff9091166040820152606090f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090517f0000000000000000000000000000000000000000000000000000000000093a808152f35b83346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d157611253611cf4565b61125b611d66565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600a5416600a55600b548273ffffffffffffffffffffffffffffffffffffffff821681817f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8280a37f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68280a316600b5580f35b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611dfd565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25760209073ffffffffffffffffffffffffffffffffffffffff600b54169051908152f35b91503461038c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c5735906113bb611cf4565b6113c36123fc565b67ffffffffffffffff80831161140c575b507f05d530f0fd6974b7d995fd3b71870f5301bb9fe086180bdd0bd36526728f5c6b90600c548151908152836020820152a1600c5580f35b91507f05d530f0fd6974b7d995fd3b71870f5301bb9fe086180bdd0bd36526728f5c6b6113d4565b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761146c611bd7565b611474611cf4565b73ffffffffffffffffffffffffffffffffffffffff80911690817fffffffffffffffffffffffff0000000000000000000000000000000000000000600a541617600a55600b54167f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8380a380f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e168152f35b83346102d1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601608081126103f2576060136102d15781519261159584611ae5565b3564ffffffffff90818116810361038c57845260243590811681036103f2576020840152604435907affffffffffffffffffffffffffffffffffffffffffffffffffffff821682036102d15750826103119183602095015260643590612905565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090610311611e9d565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090610311612137565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020905160ff7f0000000000000000000000000000000000000000000000000000000000000012168152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090600c549051908152f35b83346102d15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761173d611bd7565b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef611766611bff565b946044358573ffffffffffffffffffffffffffffffffffffffff80951694858752602098848a958652838920338a52865283892054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036117fb575b505050868852600385528288206117dc858254611e61565b9055169586815260038452208181540190558551908152a35160018152f35b61180491611e61565b90888a528652838920338a528652838920558a80856117c4565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906002549051908152f35b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611e3f565b91503461038c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c576020926118d3611bd7565b9183602435928392338252875273ffffffffffffffffffffffffffffffffffffffff8282209516948582528752205582519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925843392a35160018152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25760209073ffffffffffffffffffffffffffffffffffffffff600a54169051908152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2578051908280546119c581611a92565b908185526020926001918281169081600014610d3957506001146119f457610cdd8686610cd3828b0383611b30565b8080949750527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b828410611a395750505082610cdd94610cd3928201019486610cc2565b8054868501880152928601928101611a1c565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090610311611a8a612137565b600954612199565b90600182811c92168015611adb575b6020831014611aac57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611aa1565b6060810190811067ffffffffffffffff821117611b0157604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611b0157604052565b60208082528251818301819052939260005b858110611bc3575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201611b83565b6004359073ffffffffffffffffffffffffffffffffffffffff82168203611bfa57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff82168203611bfa57565b34611bfa5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112611bfa57611c59611bd7565b5060206040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8152f35b6084359060ff82168203611bfa57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6060910112611bfa576004359073ffffffffffffffffffffffffffffffffffffffff906024358281168103611bfa57916044359081168103611bfa5790565b73ffffffffffffffffffffffffffffffffffffffff600b5416803303611d175750565b6040517f443dc2b400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b73ffffffffffffffffffffffffffffffffffffffff600a5416803303611d895750565b6040517fbe5a953700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b60025480611de4575090565b90611dfa91611df4611a8a612137565b9161207a565b90565b60025480611e09575090565b611dfa91611e18611a8a612137565b9061207a565b60025480611e2a575090565b611dfa91611e39611a8a612137565b906120ae565b60025480611e4b575090565b90611dfa91611e5b611a8a612137565b916120ae565b91908203918211611e6e57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000467f000000000000000000000000000000000000000000000000000000000000000103611eeb57507f9215534876c4f9b64ee9cbc7b70915f8def0270d6a0aacd514b3ccd16f7e1fe490565b60405181548291611efb82611a92565b808252816020948582019460019087828216918260001461203e575050600114611fe5575b50611f2d92500382611b30565b51902091604051918201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f845260408301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a083015260a0825260c082019082821067ffffffffffffffff831117611fb8575060405251902090565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526041600452fd5b87805286915087907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b858310612026575050611f2d935082010138611f20565b8054838801850152869450889390920191810161200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168852611f2d95151560051b8501019250389150611f209050565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215611bfa57020490565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215611bfa570290808204910615150190565b604051906120f782611ae5565b8160065464ffffffffff90818116835260281c16602082015260407affffffffffffffffffffffffffffffffffffffffffffffffffffff60075416910152565b611dfa6121426120ea565b60085461214e42612181565b825164ffffffffff92918316908316811115612177575061217191835116611e61565b90612905565b6121719250611e61565b65010000000000811015611bfa5764ffffffffff1690565b91908201809211611e6e57565b81156121b0570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b81810292918115918404141715611e6e57565b6040516121fe81611ae5565b600090818152816040602092828482015201526122196120ea565b9164ffffffffff91828451164211156123f6576040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152818160248173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e165afa80156123eb5783906123bc575b6122b1915060095490611e61565b7f0000000000000000000000000000000000000000000000000000000000093a80926122f76122f2856122ed816122e88142612199565b6121a6565b6121df565b612181565b9385808616916123074284611e61565b6028820411612370575b5050507b010000000000000000000000000000000000000000000000000000008210156102d157507affffffffffffffffffffffffffffffffffffffffffffffffffffff1660408501528261236542612181565b169084015216815290565b61237d9192939650612181565b160184811161238f5792388581612311565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b508181813d83116123e4575b6123d28183611b30565b8101031261038c576122b190516122a3565b503d6123c8565b6040513d85823e3d90fd5b50505090565b612404612137565b80612558575b50426008556124176121f2565b61242042612181565b602082015164ffffffffff808216928116831480612547575b612444575b50505050565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff60408561253b937fc32a546ed958490e37f30335e501e0a39438cb650a4851bfd4b775490af29dad97511694857fffffffffffffffffffffffffffffffffffffffffffff0000000000000000000069ffffffffff00000000006006549360281b1692161717600655015116807fffffffffff0000000000000000000000000000000000000000000000000000006007541617600755604051938493849193927affffffffffffffffffffffffffffffffffffffffffffffffffffff90604092606085019664ffffffffff809216865216602085015216910152565b0390a13880808061243e565b50828160065460281c161415612439565b6020816125887fb9d196a585c1a894f648393ec7d52cc59ff6d94191579d073ba32b0a74d7f7a693600954612199565b600955604051908152a13861240a565b906125a16123fc565b6125aa82611dd8565b9182156126435761263d916125e18230337f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e612707565b6125eb84826126a1565b73ffffffffffffffffffffffffffffffffffffffff6040519183835285602084015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760403392a3600954612199565b60095590565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f5348415245530000000000000000000000000000000000000000006044820152fd5b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602073ffffffffffffffffffffffffffffffffffffffff6000936126e886600254612199565b60025516938484526003825260408420818154019055604051908152a3565b9160008093602095606494604051947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216600487015216602485015260448401525af13d15601f3d116001600051141617161561277957565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602073ffffffffffffffffffffffffffffffffffffffff6000941692838552600382526040852061282b828254611e61565b90558060025403600255604051908152a3565b6000918260449260209573ffffffffffffffffffffffffffffffffffffffff604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af13d15601f3d11600160005114161716156128a757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b919091612933837affffffffffffffffffffffffffffffffffffffffffffffffffffff6040840151166121df565b64ffffffffff918260208183511692015116900391808311611e6e5761296b61297d9261297492670de0b6b3a76400009516906121a6565b94600c546121df565b600954906121df565b048083116129885750565b915056","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"london","libraries":{},"metadata":{"appendCBOR":false,"bytecodeHash":"none"},"optimizer":{"enabled":true,"runs":99999999},"remappings":[":@openzeppelin/=node_modules/@openzeppelin/",":ds-test/=lib/frax-standard-solidity/lib/forge-std/lib/ds-test/src/",":forge-std/=lib/frax-standard-solidity/lib/forge-std/src/",":frax-standard-solidity/=lib/frax-standard-solidity/src/",":frax-std/=lib/frax-standard-solidity/src/",":solidity-bytes-utils/=lib/frax-standard-solidity/lib/solidity-bytes-utils/",":solmate/=lib/solmate/src/"],"viaIR":true},"optimization_runs":99999999,"sourcify_repo_url":"https://repo.sourcify.dev/contracts/partial_match/1/0xA663B02CF0a4b149d2aD41910CB81e23e1c41c32/","decoded_constructor_args":null,"compiler_version":"0.8.21+commit.d9974bed","is_verified_via_verifier_alliance":false,"verified_at":"2024-04-18T00:24:46.127920Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x61014080604052346200083c576200355b80380380916200002182856200085d565b833981019060c0818303126200083c578051906001600160a01b0380831683036200083c5760208201516001600160401b0381116200083c57846200006891840162000881565b604083015190946001600160401b0382116200083c576200008b91840162000881565b9260608301519463ffffffff86168096036200083c5760a060808501519401519483861686036200083c5760405163313ce56760e01b8152916020836004818789165afa9283156200059e5760009362000804575b508051906001600160401b038211620005aa5781906200010260005462000912565b601f8111620007a1575b50602090601f8311600114620007255760009262000719575b50508160011b916000199060031b1c1916176000555b8051906001600160401b038211620005aa5781906200015c60015462000912565b601f8111620006b5575b50602090601f83116001146200063b576000926200062f575b50508160011b916000199060031b1c1916176001555b6080524660a05260405160009081549181620001b18462000912565b918282526020820194600181169081600014620006115750600114620005c0575b620001e0925003826200085d565b519020906040519160208301907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f825260408401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608401524660808401523060a084015260a0835260c083019183831060018060401b03841117620005aa57600483868193602095836040528851902060c05281811660e0526101009b8c5263313ce56760e01b8352165afa9081156200059e5760ff9260009262000562575b50501692604d84116200054c5761012093600a0a8452620002c3620009f5565b620002ce42620009a7565b60208201519164ffffffffff9283928382169384911614806200053a575b620004b3575b505050620002ff6200095d565b6008546200030d42620009a7565b825190841691908416821115620004a1576200032e91508383511662000999565b915b60408201516000906200034e9085906001600160d81b0316620009e1565b9282602081835116920151169003908282116200048d575091620003799162000383931690620009c0565b91600c54620009e1565b670de0b6b3a76400006200039b6009548093620009e1565b0480831162000484575b508162000442575b5050426008551660018060a01b0319600b541617600b55600c556040519061298c928362000b8f8439608051836116a4015260a05183611ea2015260c05183611ec9015260e051838181610871015281816109fa01528181610de701528181610fc80152818161152d0152818161227401526125bd0152518281816111f901526122b3015251818181610be40152610c3f0152f35b81620004727fb9d196a585c1a894f648393ec7d52cc59ff6d94191579d073ba32b0a74d7f7a6936020936200094f565b600955604051908152a13880620003ad565b915038620003a5565b634e487b7160e01b81526011600452602490fd5b620004ac9162000999565b9162000330565b7fc32a546ed958490e37f30335e501e0a39438cb650a4851bfd4b775490af29dad9282856060945116928369ffffffffff00000000006006549260281b169160018060501b0319161717600655604060018060d81b0391015116908164ffffffffff60d81b600754161760075560405192835260208301526040820152a1388080620002f2565b50828460065460281c161415620002ec565b634e487b7160e01b600052601160045260246000fd5b6200058d925060c0906020903d60201162000595575b6200058482856200085d565b010190620008f7565b3880620002a3565b3d915062000578565b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b50600080805290916000805160206200351b8339815191525b818310620005f4575050906020620001e092820101620001d2565b6020919350806001915483858801015201910190918392620005d9565b60ff1916865250620001e092151560051b82016020019050620001d2565b0151905038806200017f565b600160009081526000805160206200353b8339815191529350601f198516905b8181106200069c575090846001959493921062000682575b505050811b0160015562000195565b015160001960f88460031b161c1916905538808062000673565b929360206001819287860151815501950193016200065b565b60016000529091506000805160206200353b833981519152601f840160051c810191602085106200070e575b90601f859493920160051c01905b818110620006fe575062000166565b60008155849350600101620006ef565b9091508190620006e1565b01519050388062000125565b600080805293506000805160206200351b83398151915291905b601f198416851062000785576001945083601f198116106200076b575b505050811b016000556200013b565b015160001960f88460031b161c191690553880806200075c565b818101518355602094850194600190930192909101906200073f565b600080529091506000805160206200351b833981519152601f840160051c81019160208510620007f9575b90601f859493920160051c01905b818110620007e957506200010c565b60008155849350600101620007da565b9091508190620007cc565b6200082c91935060203d60201162000834575b6200082381836200085d565b810190620008f7565b9138620000e0565b503d62000817565b600080fd5b606081019081106001600160401b03821117620005aa57604052565b601f909101601f19168101906001600160401b03821190821017620005aa57604052565b919080601f840112156200083c5782516001600160401b038111620005aa5760209060405192620008bc83601f19601f85011601856200085d565b8184528282870101116200083c5760005b818110620008e357508260009394955001015290565b8581018301518482018401528201620008cd565b908160209103126200083c575160ff811681036200083c5790565b90600182811c9216801562000944575b60208310146200092e57565b634e487b7160e01b600052602260045260246000fd5b91607f169162000922565b919082018092116200054c57565b604051906200096c8262000841565b60065464ffffffffff808216845260289190911c1660208301526007546001600160d81b03166040830152565b919082039182116200054c57565b650100000000008110156200083c5764ffffffffff1690565b8115620009cb570490565b634e487b7160e01b600052601260045260246000fd5b818102929181159184041417156200054c57565b60405162000a038162000841565b6000908181528160406020928284820152015262000a206200095d565b9164ffffffffff918284511642111562000b885760e0516040516370a0823160e01b8152306004820152908290829060249082906001600160a01b03165afa801562000b7d57839062000b43575b62000a7e91506009549062000999565b6101009262000ab362000aad62000aa462000a9b8751426200094f565b875190620009c0565b865190620009e1565b620009a7565b93858086169162000ac5428462000999565b905190602882041162000b0c575b505050600160d81b82101562000b0957506001600160d81b031660408501528262000afe42620009a7565b169084015216815290565b80fd5b62000b1b9192939650620009a7565b160184811162000b2f579238858162000ad3565b634e487b7160e01b84526011600452602484fd5b508181813d831162000b75575b62000b5c81836200085d565b8101031262000b715762000a7e905162000a6e565b8280fd5b503d62000b50565b6040513d85823e3d90fd5b5050509056fe6040608081526004908136101561001557600080fd5b600091823560e01c91826301e1d11414611a4c57826306fdde031461198657826307a2d13a146112f0578263090f3f5014611933578263095ea7b3146118985782630a28a4771461185b57826318160ddd1461181e57826323b872dd146117055782632af98d6d146116c8578263313ce5671461166c578263358245fc146116315782633644e515146115f6578263374010a41461155157826338d52e0f146114e2578263402d267d14610787578263450140951461143457826348f76e0f146113805782634bc66f321461132d5782634cdad506146112f05782634f8b4ae71461121c57826356caf605146111c35782635ebae5661461114957826361c1c5e91461110c5782636e553f65146110c757826370a082311461039057826375e077c314610f395782637ecebe0014610ed75782638f765d5914610e5b57826394bf804d14610d7957826395d89b4114610c6357826399530b0614610c07578263a80e754714610bae578263a9059cbb14610b01578263aaf5eb6814610ac0578263b3d7f6b914610a83578263b460af9414610963578263ba087652146107c9578263bd6f36031461078c578263c63d75b614610787578263c6e6f592146102d4578263ce96cb7714610724578263d505accf14610430578263d71356e6146103f6578263d905777e14610390578263dd62ed3e14610318578263ef8b30f7146102d457505063f6ccaad41461022957600080fd5b346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761025f611d66565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600a5416600a55600b54903373ffffffffffffffffffffffffffffffffffffffff83167f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68580a3163317600b5580f35b80fd5b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611dd8565b9051908152f35b91503461038c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c576020928291610355611bd7565b61035d611bff565b9173ffffffffffffffffffffffffffffffffffffffff8092168452865283832091168252845220549051908152f35b8280fd5b8390346103f25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2578060209273ffffffffffffffffffffffffffffffffffffffff6103e2611bd7565b1681526003845220549051908152f35b5080fd5b83346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761042d6123fc565b80f35b8390346103f25760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257610469611bd7565b90610472611bff565b9160443560643592610482611c84565b924285106106c757610492611e9d565b9573ffffffffffffffffffffffffffffffffffffffff8092169586895260209560058752848a209889549960018b01905585519285898501957f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c987528b89870152169a8b606086015288608086015260a085015260c084015260c0835260e0830167ffffffffffffffff948482108683111761069a57818852845190206101008501927f19010000000000000000000000000000000000000000000000000000000000008452610102860152610122850152604281526101608401948186109086111761066e57848752519020835260ff1661018082015260a4356101a082015260c4356101c0909101528780528490889060809060015afa1561066457865116968715158061065b575b156106005786977f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259596975283528087208688528352818188205551908152a380f35b8360649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152fd5b508488146105bd565b81513d88823e3d90fd5b60248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5060248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b60648860208451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152fd5b8390346103f25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576103118160209373ffffffffffffffffffffffffffffffffffffffff610779611bd7565b168152600385522054611dfd565b611c22565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906008549051908152f35b9083346102d1576107d936611c94565b6107e5939291936123fc565b73ffffffffffffffffffffffffffffffffffffffff90818116938433036108f8575b5061081183611dfd565b95861561089b57509282602097959261083d88956108959761083588600954611e61565b6009556127d7565b865191858352898301528316907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db873392a47f000000000000000000000000000000000000000000000000000000000000000061283e565b51908152f35b60649060208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600b60248201527f5a45524f5f4153534554530000000000000000000000000000000000000000006044820152fd5b848152866020528781203382526020528780822054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361093e575b505050610807565b61094791611e61565b9186815288602052818120338252602052205587878185610936565b8390346103f25761089560209361097936611c94565b959091926109856123fc565b6109c561099185611e3f565b809873ffffffffffffffffffffffffffffffffffffffff938985831696873303610a1e575b50505061083587600954611e61565b85519084825287898301528316907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db873392a47f000000000000000000000000000000000000000000000000000000000000000061283e565b878152828e528181203382528e5281812054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610a60575b50506109b6565b610a6991611e61565b928882528e528181203382528e5220558b89818085610a59565b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611e1e565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25760209051670de0b6b3a76400008152f35b8390346103f257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602091610b3c611bd7565b8273ffffffffffffffffffffffffffffffffffffffff6024359233855260038752828520610b6b858254611e61565b90551692838152600386522081815401905582519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef843392a35160018152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906103117f0000000000000000000000000000000000000000000000000000000000000000611dfd565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25780519082600190815491610ca683611a92565b918286526020938281169081600014610d395750600114610ce1575b610cdd8686610cd3828b0383611b30565b5191829182611b71565b0390f35b9295508083527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b828410610d265750505082610cdd94610cd3928201019486610cc2565b8054868501880152928601928101610d09565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001687860152505050151560051b8301019250610cd382610cdd86610cc2565b91503461038c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c57602092503590610db7611bff565b91610dc06123fc565b73ffffffffffffffffffffffffffffffffffffffff610dde82611e1e565b93610e0b8530337f0000000000000000000000000000000000000000000000000000000000000000612707565b610e1583826126a1565b8351928584528684015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7833392a3610e5282600954612199565b60095551908152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257606090610e966121f2565b907affffffffffffffffffffffffffffffffffffffffffffffffffffff8180519364ffffffffff808251168652602082015116602086015201511690820152f35b8390346103f25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2578060209273ffffffffffffffffffffffffffffffffffffffff610f29611bd7565b1681526005845220549051908152f35b83346102d15760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1578235610f73611bff565b916064359081151582036102d157610f89611c84565b91156110c1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b1561038c579060e48884809460ff8b5198899687957fd505accf00000000000000000000000000000000000000000000000000000000875233908701523060248701526044860152604435606486015216608484015260a43560a484015260c43560c48401525af180156110b55761106a575b6020856103118686612598565b67ffffffffffffffff821161108957508352602093506103118561105d565b806041877f4e487b71000000000000000000000000000000000000000000000000000000006024945252fd5b508451903d90823e3d90fd5b82610fb1565b83346102d157817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15750610311602092611105611bff565b9035612598565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906009549051908152f35b83346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15750600654600754915164ffffffffff808316825260289290921c90911660208201527affffffffffffffffffffffffffffffffffffffffffffffffffffff9091166040820152606090f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b83346102d157807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d157611253611cf4565b61125b611d66565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600a5416600a55600b548273ffffffffffffffffffffffffffffffffffffffff821681817f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8280a37f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68280a316600b5580f35b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611dfd565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25760209073ffffffffffffffffffffffffffffffffffffffff600b54169051908152f35b91503461038c5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c5735906113bb611cf4565b6113c36123fc565b67ffffffffffffffff80831161140c575b507f05d530f0fd6974b7d995fd3b71870f5301bb9fe086180bdd0bd36526728f5c6b90600c548151908152836020820152a1600c5580f35b91507f05d530f0fd6974b7d995fd3b71870f5301bb9fe086180bdd0bd36526728f5c6b6113d4565b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761146c611bd7565b611474611cf4565b73ffffffffffffffffffffffffffffffffffffffff80911690817fffffffffffffffffffffffff0000000000000000000000000000000000000000600a541617600a55600b54167f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8380a380f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b83346102d1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601608081126103f2576060136102d15781519261159584611ae5565b3564ffffffffff90818116810361038c57845260243590811681036103f2576020840152604435907affffffffffffffffffffffffffffffffffffffffffffffffffffff821682036102d15750826103119183602095015260643590612905565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090610311611e9d565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090610311612137565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020905160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090600c549051908152f35b83346102d15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d15761173d611bd7565b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef611766611bff565b946044358573ffffffffffffffffffffffffffffffffffffffff80951694858752602098848a958652838920338a52865283892054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036117fb575b505050868852600385528288206117dc858254611e61565b9055169586815260038452208181540190558551908152a35160018152f35b61180491611e61565b90888a528652838920338a528652838920558a80856117c4565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2576020906002549051908152f35b83346102d15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d1575061031160209235611e3f565b91503461038c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261038c576020926118d3611bd7565b9183602435928392338252875273ffffffffffffffffffffffffffffffffffffffff8282209516948582528752205582519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925843392a35160018152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f25760209073ffffffffffffffffffffffffffffffffffffffff600a54169051908152f35b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f2578051908280546119c581611a92565b908185526020926001918281169081600014610d3957506001146119f457610cdd8686610cd3828b0383611b30565b8080949750527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b828410611a395750505082610cdd94610cd3928201019486610cc2565b8054868501880152928601928101611a1c565b8390346103f257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103f257602090610311611a8a612137565b600954612199565b90600182811c92168015611adb575b6020831014611aac57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611aa1565b6060810190811067ffffffffffffffff821117611b0157604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611b0157604052565b60208082528251818301819052939260005b858110611bc3575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201611b83565b6004359073ffffffffffffffffffffffffffffffffffffffff82168203611bfa57565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff82168203611bfa57565b34611bfa5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112611bfa57611c59611bd7565b5060206040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8152f35b6084359060ff82168203611bfa57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6060910112611bfa576004359073ffffffffffffffffffffffffffffffffffffffff906024358281168103611bfa57916044359081168103611bfa5790565b73ffffffffffffffffffffffffffffffffffffffff600b5416803303611d175750565b6040517f443dc2b400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b73ffffffffffffffffffffffffffffffffffffffff600a5416803303611d895750565b6040517fbe5a953700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b60025480611de4575090565b90611dfa91611df4611a8a612137565b9161207a565b90565b60025480611e09575090565b611dfa91611e18611a8a612137565b9061207a565b60025480611e2a575090565b611dfa91611e39611a8a612137565b906120ae565b60025480611e4b575090565b90611dfa91611e5b611a8a612137565b916120ae565b91908203918211611e6e57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000467f000000000000000000000000000000000000000000000000000000000000000003611eeb57507f000000000000000000000000000000000000000000000000000000000000000090565b60405181548291611efb82611a92565b808252816020948582019460019087828216918260001461203e575050600114611fe5575b50611f2d92500382611b30565b51902091604051918201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f845260408301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a083015260a0825260c082019082821067ffffffffffffffff831117611fb8575060405251902090565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526041600452fd5b87805286915087907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b858310612026575050611f2d935082010138611f20565b8054838801850152869450889390920191810161200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168852611f2d95151560051b8501019250389150611f209050565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215611bfa57020490565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215611bfa570290808204910615150190565b604051906120f782611ae5565b8160065464ffffffffff90818116835260281c16602082015260407affffffffffffffffffffffffffffffffffffffffffffffffffffff60075416910152565b611dfa6121426120ea565b60085461214e42612181565b825164ffffffffff92918316908316811115612177575061217191835116611e61565b90612905565b6121719250611e61565b65010000000000811015611bfa5764ffffffffff1690565b91908201809211611e6e57565b81156121b0570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b81810292918115918404141715611e6e57565b6040516121fe81611ae5565b600090818152816040602092828482015201526122196120ea565b9164ffffffffff91828451164211156123f6576040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152818160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa80156123eb5783906123bc575b6122b1915060095490611e61565b7f0000000000000000000000000000000000000000000000000000000000000000926122f76122f2856122ed816122e88142612199565b6121a6565b6121df565b612181565b9385808616916123074284611e61565b6028820411612370575b5050507b010000000000000000000000000000000000000000000000000000008210156102d157507affffffffffffffffffffffffffffffffffffffffffffffffffffff1660408501528261236542612181565b169084015216815290565b61237d9192939650612181565b160184811161238f5792388581612311565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b508181813d83116123e4575b6123d28183611b30565b8101031261038c576122b190516122a3565b503d6123c8565b6040513d85823e3d90fd5b50505090565b612404612137565b80612558575b50426008556124176121f2565b61242042612181565b602082015164ffffffffff808216928116831480612547575b612444575b50505050565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff60408561253b937fc32a546ed958490e37f30335e501e0a39438cb650a4851bfd4b775490af29dad97511694857fffffffffffffffffffffffffffffffffffffffffffff0000000000000000000069ffffffffff00000000006006549360281b1692161717600655015116807fffffffffff0000000000000000000000000000000000000000000000000000006007541617600755604051938493849193927affffffffffffffffffffffffffffffffffffffffffffffffffffff90604092606085019664ffffffffff809216865216602085015216910152565b0390a13880808061243e565b50828160065460281c161415612439565b6020816125887fb9d196a585c1a894f648393ec7d52cc59ff6d94191579d073ba32b0a74d7f7a693600954612199565b600955604051908152a13861240a565b906125a16123fc565b6125aa82611dd8565b9182156126435761263d916125e18230337f0000000000000000000000000000000000000000000000000000000000000000612707565b6125eb84826126a1565b73ffffffffffffffffffffffffffffffffffffffff6040519183835285602084015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760403392a3600954612199565b60095590565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5a45524f5f5348415245530000000000000000000000000000000000000000006044820152fd5b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602073ffffffffffffffffffffffffffffffffffffffff6000936126e886600254612199565b60025516938484526003825260408420818154019055604051908152a3565b9160008093602095606494604051947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216600487015216602485015260448401525af13d15601f3d116001600051141617161561277957565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602073ffffffffffffffffffffffffffffffffffffffff6000941692838552600382526040852061282b828254611e61565b90558060025403600255604051908152a3565b6000918260449260209573ffffffffffffffffffffffffffffffffffffffff604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af13d15601f3d11600160005114161716156128a757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b919091612933837affffffffffffffffffffffffffffffffffffffffffffffffffffff6040840151166121df565b64ffffffffff918260208183511692015116900391808311611e6e5761296b61297d9261297492670de0b6b3a76400009516906121a6565b94600c546121df565b600954906121df565b048083116129885750565b915056290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6000000000000000000000000853d955acef822db058eb8505911ed77f175b99e00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000000000000b4241eae000000000000000000000000831822660572bd54ebaa065c2acef662a6277d40000000000000000000000000000000000000000000000000000000000000000b5374616b6564204652415800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057346524158000000000000000000000000000000000000000000000000000000","name":"StakedFrax","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"london","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":true,"additional_sources":[{"file_path":"lib/frax-standard-solidity/src/access-control/v2/Timelock2Step.sol","source_code":"// SPDX-License-Identifier: ISC\npragma solidity >=0.8.0;\n\n// ====================================================================\n// |     ______                   _______                             |\n// |    / _____________ __  __   / ____(_____  ____ _____  ________   |\n// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \\/ __ `/ __ \\/ ___/ _ \\  |\n// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |\n// | /_/   /_/   \\__,_/_/|_|  /_/   /_/_/ /_/\\__,_/_/ /_/\\___/\\___/   |\n// |                                                                  |\n// ====================================================================\n// ========================== Timelock2Step ===========================\n// ====================================================================\n// Frax Finance: https://github.com/FraxFinance\n\n// Primary Author\n// Drake Evans: https://github.com/DrakeEvans\n\n// Reviewers\n// Dennis: https://github.com/denett\n\n// ====================================================================\n\n/// @title Timelock2Step\n/// @author Drake Evans (Frax Finance) https://github.com/drakeevans\n/// @dev Inspired by OpenZeppelin's Ownable2Step contract\n/// @notice  An abstract contract which contains 2-step transfer and renounce logic for a timelock address\nabstract contract Timelock2Step {\n    /// @notice The pending timelock address\n    address public pendingTimelockAddress;\n\n    /// @notice The current timelock address\n    address public timelockAddress;\n\n    constructor(address _timelockAddress) {\n        timelockAddress = _timelockAddress;\n    }\n\n    // ============================================================================================\n    // Functions: External Functions\n    // ============================================================================================\n\n    /// @notice The ```transferTimelock``` function initiates the timelock transfer\n    /// @dev Must be called by the current timelock\n    /// @param _newTimelock The address of the nominated (pending) timelock\n    function transferTimelock(address _newTimelock) external virtual {\n        _requireSenderIsTimelock();\n        _transferTimelock(_newTimelock);\n    }\n\n    /// @notice The ```acceptTransferTimelock``` function completes the timelock transfer\n    /// @dev Must be called by the pending timelock\n    function acceptTransferTimelock() external virtual {\n        _requireSenderIsPendingTimelock();\n        _acceptTransferTimelock();\n    }\n\n    /// @notice The ```renounceTimelock``` function renounces the timelock after setting pending timelock to current timelock\n    /// @dev Pending timelock must be set to current timelock before renouncing, creating a 2-step renounce process\n    function renounceTimelock() external virtual {\n        _requireSenderIsTimelock();\n        _requireSenderIsPendingTimelock();\n        _transferTimelock(address(0));\n        _setTimelock(address(0));\n    }\n\n    // ============================================================================================\n    // Functions: Internal Actions\n    // ============================================================================================\n\n    /// @notice The ```_transferTimelock``` function initiates the timelock transfer\n    /// @dev This function is to be implemented by a public function\n    /// @param _newTimelock The address of the nominated (pending) timelock\n    function _transferTimelock(address _newTimelock) internal {\n        pendingTimelockAddress = _newTimelock;\n        emit TimelockTransferStarted(timelockAddress, _newTimelock);\n    }\n\n    /// @notice The ```_acceptTransferTimelock``` function completes the timelock transfer\n    /// @dev This function is to be implemented by a public function\n    function _acceptTransferTimelock() internal {\n        pendingTimelockAddress = address(0);\n        _setTimelock(msg.sender);\n    }\n\n    /// @notice The ```_setTimelock``` function sets the timelock address\n    /// @dev This function is to be implemented by a public function\n    /// @param _newTimelock The address of the new timelock\n    function _setTimelock(address _newTimelock) internal {\n        emit TimelockTransferred(timelockAddress, _newTimelock);\n        timelockAddress = _newTimelock;\n    }\n\n    // ============================================================================================\n    // Functions: Internal Checks\n    // ============================================================================================\n\n    /// @notice The ```_isTimelock``` function checks if _address is current timelock address\n    /// @param _address The address to check against the timelock\n    /// @return Whether or not msg.sender is current timelock address\n    function _isTimelock(address _address) internal view returns (bool) {\n        return _address == timelockAddress;\n    }\n\n    /// @notice The ```_requireIsTimelock``` function reverts if _address is not current timelock address\n    /// @param _address The address to check against the timelock\n    function _requireIsTimelock(address _address) internal view {\n        if (!_isTimelock(_address)) revert AddressIsNotTimelock(timelockAddress, _address);\n    }\n\n    /// @notice The ```_requireSenderIsTimelock``` function reverts if msg.sender is not current timelock address\n    /// @dev This function is to be implemented by a public function\n    function _requireSenderIsTimelock() internal view {\n        _requireIsTimelock(msg.sender);\n    }\n\n    /// @notice The ```_isPendingTimelock``` function checks if the _address is pending timelock address\n    /// @dev This function is to be implemented by a public function\n    /// @param _address The address to check against the pending timelock\n    /// @return Whether or not _address is pending timelock address\n    function _isPendingTimelock(address _address) internal view returns (bool) {\n        return _address == pendingTimelockAddress;\n    }\n\n    /// @notice The ```_requireIsPendingTimelock``` function reverts if the _address is not pending timelock address\n    /// @dev This function is to be implemented by a public function\n    /// @param _address The address to check against the pending timelock\n    function _requireIsPendingTimelock(address _address) internal view {\n        if (!_isPendingTimelock(_address)) revert AddressIsNotPendingTimelock(pendingTimelockAddress, _address);\n    }\n\n    /// @notice The ```_requirePendingTimelock``` function reverts if msg.sender is not pending timelock address\n    /// @dev This function is to be implemented by a public function\n    function _requireSenderIsPendingTimelock() internal view {\n        _requireIsPendingTimelock(msg.sender);\n    }\n\n    // ============================================================================================\n    // Functions: Events\n    // ============================================================================================\n\n    /// @notice The ```TimelockTransferStarted``` event is emitted when the timelock transfer is initiated\n    /// @param previousTimelock The address of the previous timelock\n    /// @param newTimelock The address of the new timelock\n    event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);\n\n    /// @notice The ```TimelockTransferred``` event is emitted when the timelock transfer is completed\n    /// @param previousTimelock The address of the previous timelock\n    /// @param newTimelock The address of the new timelock\n    event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);\n\n    // ============================================================================================\n    // Functions: Errors\n    // ============================================================================================\n\n    /// @notice Emitted when timelock is transferred\n    error AddressIsNotTimelock(address timelockAddress, address actualAddress);\n\n    /// @notice Emitted when pending timelock is transferred\n    error AddressIsNotPendingTimelock(address pendingTimelockAddress, address actualAddress);\n}\n"},{"file_path":"lib/solmate/src/mixins/ERC4626.sol","source_code":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\nimport {ERC20} from \"../tokens/ERC20.sol\";\nimport {SafeTransferLib} from \"../utils/SafeTransferLib.sol\";\nimport {FixedPointMathLib} from \"../utils/FixedPointMathLib.sol\";\n\n/// @notice Minimal ERC4626 tokenized Vault implementation.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/mixins/ERC4626.sol)\nabstract contract ERC4626 is ERC20 {\n    using SafeTransferLib for ERC20;\n    using FixedPointMathLib for uint256;\n\n    /*//////////////////////////////////////////////////////////////\n                                 EVENTS\n    //////////////////////////////////////////////////////////////*/\n\n    event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);\n\n    event Withdraw(\n        address indexed caller,\n        address indexed receiver,\n        address indexed owner,\n        uint256 assets,\n        uint256 shares\n    );\n\n    /*//////////////////////////////////////////////////////////////\n                               IMMUTABLES\n    //////////////////////////////////////////////////////////////*/\n\n    ERC20 public immutable asset;\n\n    constructor(\n        ERC20 _asset,\n        string memory _name,\n        string memory _symbol\n    ) ERC20(_name, _symbol, _asset.decimals()) {\n        asset = _asset;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        DEPOSIT/WITHDRAWAL LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) {\n        // Check for rounding error since we round down in previewDeposit.\n        require((shares = previewDeposit(assets)) != 0, \"ZERO_SHARES\");\n\n        // Need to transfer before minting or ERC777s could reenter.\n        asset.safeTransferFrom(msg.sender, address(this), assets);\n\n        _mint(receiver, shares);\n\n        emit Deposit(msg.sender, receiver, assets, shares);\n\n        afterDeposit(assets, shares);\n    }\n\n    function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) {\n        assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up.\n\n        // Need to transfer before minting or ERC777s could reenter.\n        asset.safeTransferFrom(msg.sender, address(this), assets);\n\n        _mint(receiver, shares);\n\n        emit Deposit(msg.sender, receiver, assets, shares);\n\n        afterDeposit(assets, shares);\n    }\n\n    function withdraw(\n        uint256 assets,\n        address receiver,\n        address owner\n    ) public virtual returns (uint256 shares) {\n        shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up.\n\n        if (msg.sender != owner) {\n            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.\n\n            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;\n        }\n\n        beforeWithdraw(assets, shares);\n\n        _burn(owner, shares);\n\n        emit Withdraw(msg.sender, receiver, owner, assets, shares);\n\n        asset.safeTransfer(receiver, assets);\n    }\n\n    function redeem(\n        uint256 shares,\n        address receiver,\n        address owner\n    ) public virtual returns (uint256 assets) {\n        if (msg.sender != owner) {\n            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.\n\n            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;\n        }\n\n        // Check for rounding error since we round down in previewRedeem.\n        require((assets = previewRedeem(shares)) != 0, \"ZERO_ASSETS\");\n\n        beforeWithdraw(assets, shares);\n\n        _burn(owner, shares);\n\n        emit Withdraw(msg.sender, receiver, owner, assets, shares);\n\n        asset.safeTransfer(receiver, assets);\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                            ACCOUNTING LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function totalAssets() public view virtual returns (uint256);\n\n    function convertToShares(uint256 assets) public view virtual returns (uint256) {\n        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.\n\n        return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());\n    }\n\n    function convertToAssets(uint256 shares) public view virtual returns (uint256) {\n        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.\n\n        return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply);\n    }\n\n    function previewDeposit(uint256 assets) public view virtual returns (uint256) {\n        return convertToShares(assets);\n    }\n\n    function previewMint(uint256 shares) public view virtual returns (uint256) {\n        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.\n\n        return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply);\n    }\n\n    function previewWithdraw(uint256 assets) public view virtual returns (uint256) {\n        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.\n\n        return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets());\n    }\n\n    function previewRedeem(uint256 shares) public view virtual returns (uint256) {\n        return convertToAssets(shares);\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                     DEPOSIT/WITHDRAWAL LIMIT LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function maxDeposit(address) public view virtual returns (uint256) {\n        return type(uint256).max;\n    }\n\n    function maxMint(address) public view virtual returns (uint256) {\n        return type(uint256).max;\n    }\n\n    function maxWithdraw(address owner) public view virtual returns (uint256) {\n        return convertToAssets(balanceOf[owner]);\n    }\n\n    function maxRedeem(address owner) public view virtual returns (uint256) {\n        return balanceOf[owner];\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                          INTERNAL HOOKS LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {}\n\n    function afterDeposit(uint256 assets, uint256 shares) internal virtual {}\n}\n"},{"file_path":"lib/solmate/src/tokens/ERC20.sol","source_code":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n    /*//////////////////////////////////////////////////////////////\n                                 EVENTS\n    //////////////////////////////////////////////////////////////*/\n\n    event Transfer(address indexed from, address indexed to, uint256 amount);\n\n    event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n    /*//////////////////////////////////////////////////////////////\n                            METADATA STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    string public name;\n\n    string public symbol;\n\n    uint8 public immutable decimals;\n\n    /*//////////////////////////////////////////////////////////////\n                              ERC20 STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 public totalSupply;\n\n    mapping(address => uint256) public balanceOf;\n\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    /*//////////////////////////////////////////////////////////////\n                            EIP-2612 STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal immutable INITIAL_CHAIN_ID;\n\n    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n    mapping(address => uint256) public nonces;\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        uint8 _decimals\n    ) {\n        name = _name;\n        symbol = _symbol;\n        decimals = _decimals;\n\n        INITIAL_CHAIN_ID = block.chainid;\n        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                               ERC20 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function approve(address spender, uint256 amount) public virtual returns (bool) {\n        allowance[msg.sender][spender] = amount;\n\n        emit Approval(msg.sender, spender, amount);\n\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) public virtual returns (bool) {\n        balanceOf[msg.sender] -= amount;\n\n        // Cannot overflow because the sum of all user\n        // balances can't exceed the max uint256 value.\n        unchecked {\n            balanceOf[to] += amount;\n        }\n\n        emit Transfer(msg.sender, to, amount);\n\n        return true;\n    }\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) public virtual returns (bool) {\n        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n        balanceOf[from] -= amount;\n\n        // Cannot overflow because the sum of all user\n        // balances can't exceed the max uint256 value.\n        unchecked {\n            balanceOf[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        return true;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                             EIP-2612 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) public virtual {\n        require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n        // Unchecked because the only math done is incrementing\n        // the owner's nonce which cannot realistically overflow.\n        unchecked {\n            address recoveredAddress = ecrecover(\n                keccak256(\n                    abi.encodePacked(\n                        \"\\x19\\x01\",\n                        DOMAIN_SEPARATOR(),\n                        keccak256(\n                            abi.encode(\n                                keccak256(\n                                    \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n                                ),\n                                owner,\n                                spender,\n                                value,\n                                nonces[owner]++,\n                                deadline\n                            )\n                        )\n                    )\n                ),\n                v,\n                r,\n                s\n            );\n\n            require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n            allowance[recoveredAddress][spender] = value;\n        }\n\n        emit Approval(owner, spender, value);\n    }\n\n    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n    }\n\n    function computeDomainSeparator() internal view virtual returns (bytes32) {\n        return\n            keccak256(\n                abi.encode(\n                    keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n                    keccak256(bytes(name)),\n                    keccak256(\"1\"),\n                    block.chainid,\n                    address(this)\n                )\n            );\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        INTERNAL MINT/BURN LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function _mint(address to, uint256 amount) internal virtual {\n        totalSupply += amount;\n\n        // Cannot overflow because the sum of all user\n        // balances can't exceed the max uint256 value.\n        unchecked {\n            balanceOf[to] += amount;\n        }\n\n        emit Transfer(address(0), to, amount);\n    }\n\n    function _burn(address from, uint256 amount) internal virtual {\n        balanceOf[from] -= amount;\n\n        // Cannot underflow because a user's balance\n        // will never be larger than the total supply.\n        unchecked {\n            totalSupply -= amount;\n        }\n\n        emit Transfer(from, address(0), amount);\n    }\n}\n"},{"file_path":"lib/solmate/src/utils/FixedPointMathLib.sol","source_code":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Arithmetic library with operations for fixed-point numbers.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)\n/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)\nlibrary FixedPointMathLib {\n    /*//////////////////////////////////////////////////////////////\n                    SIMPLIFIED FIXED POINT OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal constant MAX_UINT256 = 2**256 - 1;\n\n    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.\n\n    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.\n    }\n\n    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.\n    }\n\n    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.\n    }\n\n    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                    LOW LEVEL FIXED POINT OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function mulDivDown(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))\n            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {\n                revert(0, 0)\n            }\n\n            // Divide x * y by the denominator.\n            z := div(mul(x, y), denominator)\n        }\n    }\n\n    function mulDivUp(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))\n            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {\n                revert(0, 0)\n            }\n\n            // If x * y modulo the denominator is strictly greater than 0,\n            // 1 is added to round up the division of x * y by the denominator.\n            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))\n        }\n    }\n\n    function rpow(\n        uint256 x,\n        uint256 n,\n        uint256 scalar\n    ) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            switch x\n            case 0 {\n                switch n\n                case 0 {\n                    // 0 ** 0 = 1\n                    z := scalar\n                }\n                default {\n                    // 0 ** n = 0\n                    z := 0\n                }\n            }\n            default {\n                switch mod(n, 2)\n                case 0 {\n                    // If n is even, store scalar in z for now.\n                    z := scalar\n                }\n                default {\n                    // If n is odd, store x in z for now.\n                    z := x\n                }\n\n                // Shifting right by 1 is like dividing by 2.\n                let half := shr(1, scalar)\n\n                for {\n                    // Shift n right by 1 before looping to halve it.\n                    n := shr(1, n)\n                } n {\n                    // Shift n right by 1 each iteration to halve it.\n                    n := shr(1, n)\n                } {\n                    // Revert immediately if x ** 2 would overflow.\n                    // Equivalent to iszero(eq(div(xx, x), x)) here.\n                    if shr(128, x) {\n                        revert(0, 0)\n                    }\n\n                    // Store x squared.\n                    let xx := mul(x, x)\n\n                    // Round to the nearest number.\n                    let xxRound := add(xx, half)\n\n                    // Revert if xx + half overflowed.\n                    if lt(xxRound, xx) {\n                        revert(0, 0)\n                    }\n\n                    // Set x to scaled xxRound.\n                    x := div(xxRound, scalar)\n\n                    // If n is even:\n                    if mod(n, 2) {\n                        // Compute z * x.\n                        let zx := mul(z, x)\n\n                        // If z * x overflowed:\n                        if iszero(eq(div(zx, x), z)) {\n                            // Revert if x is non-zero.\n                            if iszero(iszero(x)) {\n                                revert(0, 0)\n                            }\n                        }\n\n                        // Round to the nearest number.\n                        let zxRound := add(zx, half)\n\n                        // Revert if zx + half overflowed.\n                        if lt(zxRound, zx) {\n                            revert(0, 0)\n                        }\n\n                        // Return properly scaled zxRound.\n                        z := div(zxRound, scalar)\n                    }\n                }\n            }\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        GENERAL NUMBER UTILITIES\n    //////////////////////////////////////////////////////////////*/\n\n    function sqrt(uint256 x) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let y := x // We start y at x, which will help us make our initial estimate.\n\n            z := 181 // The \"correct\" value is 1, but this saves a multiplication later.\n\n            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad\n            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.\n\n            // We check y >= 2^(k + 8) but shift right by k bits\n            // each branch to ensure that if x >= 256, then y >= 256.\n            if iszero(lt(y, 0x10000000000000000000000000000000000)) {\n                y := shr(128, y)\n                z := shl(64, z)\n            }\n            if iszero(lt(y, 0x1000000000000000000)) {\n                y := shr(64, y)\n                z := shl(32, z)\n            }\n            if iszero(lt(y, 0x10000000000)) {\n                y := shr(32, y)\n                z := shl(16, z)\n            }\n            if iszero(lt(y, 0x1000000)) {\n                y := shr(16, y)\n                z := shl(8, z)\n            }\n\n            // Goal was to get z*z*y within a small factor of x. More iterations could\n            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).\n            // We ensured y >= 256 so that the relative difference between y and y+1 is small.\n            // That's not possible if x < 256 but we can just verify those cases exhaustively.\n\n            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.\n            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.\n            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.\n\n            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range\n            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.\n\n            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate\n            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.\n\n            // There is no overflow risk here since y < 2^136 after the first branch above.\n            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.\n\n            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n\n            // If x+1 is a perfect square, the Babylonian method cycles between\n            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.\n            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division\n            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.\n            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.\n            z := sub(z, lt(div(x, z), z))\n        }\n    }\n\n    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Mod x by y. Note this will return\n            // 0 instead of reverting if y is zero.\n            z := mod(x, y)\n        }\n    }\n\n    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Divide x by y. Note this will return\n            // 0 instead of reverting if y is zero.\n            r := div(x, y)\n        }\n    }\n\n    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Add 1 to x * y if x % y > 0. Note this will\n            // return 0 instead of reverting if y is zero.\n            z := add(gt(mod(x, y), 0), div(x, y))\n        }\n    }\n}\n"},{"file_path":"lib/solmate/src/utils/SafeCastLib.sol","source_code":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Safe unsigned integer casting library that reverts on overflow.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol)\n/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol)\nlibrary SafeCastLib {\n    function safeCastTo248(uint256 x) internal pure returns (uint248 y) {\n        require(x < 1 << 248);\n\n        y = uint248(x);\n    }\n\n    function safeCastTo240(uint256 x) internal pure returns (uint240 y) {\n        require(x < 1 << 240);\n\n        y = uint240(x);\n    }\n\n    function safeCastTo232(uint256 x) internal pure returns (uint232 y) {\n        require(x < 1 << 232);\n\n        y = uint232(x);\n    }\n\n    function safeCastTo224(uint256 x) internal pure returns (uint224 y) {\n        require(x < 1 << 224);\n\n        y = uint224(x);\n    }\n\n    function safeCastTo216(uint256 x) internal pure returns (uint216 y) {\n        require(x < 1 << 216);\n\n        y = uint216(x);\n    }\n\n    function safeCastTo208(uint256 x) internal pure returns (uint208 y) {\n        require(x < 1 << 208);\n\n        y = uint208(x);\n    }\n\n    function safeCastTo200(uint256 x) internal pure returns (uint200 y) {\n        require(x < 1 << 200);\n\n        y = uint200(x);\n    }\n\n    function safeCastTo192(uint256 x) internal pure returns (uint192 y) {\n        require(x < 1 << 192);\n\n        y = uint192(x);\n    }\n\n    function safeCastTo184(uint256 x) internal pure returns (uint184 y) {\n        require(x < 1 << 184);\n\n        y = uint184(x);\n    }\n\n    function safeCastTo176(uint256 x) internal pure returns (uint176 y) {\n        require(x < 1 << 176);\n\n        y = uint176(x);\n    }\n\n    function safeCastTo168(uint256 x) internal pure returns (uint168 y) {\n        require(x < 1 << 168);\n\n        y = uint168(x);\n    }\n\n    function safeCastTo160(uint256 x) internal pure returns (uint160 y) {\n        require(x < 1 << 160);\n\n        y = uint160(x);\n    }\n\n    function safeCastTo152(uint256 x) internal pure returns (uint152 y) {\n        require(x < 1 << 152);\n\n        y = uint152(x);\n    }\n\n    function safeCastTo144(uint256 x) internal pure returns (uint144 y) {\n        require(x < 1 << 144);\n\n        y = uint144(x);\n    }\n\n    function safeCastTo136(uint256 x) internal pure returns (uint136 y) {\n        require(x < 1 << 136);\n\n        y = uint136(x);\n    }\n\n    function safeCastTo128(uint256 x) internal pure returns (uint128 y) {\n        require(x < 1 << 128);\n\n        y = uint128(x);\n    }\n\n    function safeCastTo120(uint256 x) internal pure returns (uint120 y) {\n        require(x < 1 << 120);\n\n        y = uint120(x);\n    }\n\n    function safeCastTo112(uint256 x) internal pure returns (uint112 y) {\n        require(x < 1 << 112);\n\n        y = uint112(x);\n    }\n\n    function safeCastTo104(uint256 x) internal pure returns (uint104 y) {\n        require(x < 1 << 104);\n\n        y = uint104(x);\n    }\n\n    function safeCastTo96(uint256 x) internal pure returns (uint96 y) {\n        require(x < 1 << 96);\n\n        y = uint96(x);\n    }\n\n    function safeCastTo88(uint256 x) internal pure returns (uint88 y) {\n        require(x < 1 << 88);\n\n        y = uint88(x);\n    }\n\n    function safeCastTo80(uint256 x) internal pure returns (uint80 y) {\n        require(x < 1 << 80);\n\n        y = uint80(x);\n    }\n\n    function safeCastTo72(uint256 x) internal pure returns (uint72 y) {\n        require(x < 1 << 72);\n\n        y = uint72(x);\n    }\n\n    function safeCastTo64(uint256 x) internal pure returns (uint64 y) {\n        require(x < 1 << 64);\n\n        y = uint64(x);\n    }\n\n    function safeCastTo56(uint256 x) internal pure returns (uint56 y) {\n        require(x < 1 << 56);\n\n        y = uint56(x);\n    }\n\n    function safeCastTo48(uint256 x) internal pure returns (uint48 y) {\n        require(x < 1 << 48);\n\n        y = uint48(x);\n    }\n\n    function safeCastTo40(uint256 x) internal pure returns (uint40 y) {\n        require(x < 1 << 40);\n\n        y = uint40(x);\n    }\n\n    function safeCastTo32(uint256 x) internal pure returns (uint32 y) {\n        require(x < 1 << 32);\n\n        y = uint32(x);\n    }\n\n    function safeCastTo24(uint256 x) internal pure returns (uint24 y) {\n        require(x < 1 << 24);\n\n        y = uint24(x);\n    }\n\n    function safeCastTo16(uint256 x) internal pure returns (uint16 y) {\n        require(x < 1 << 16);\n\n        y = uint16(x);\n    }\n\n    function safeCastTo8(uint256 x) internal pure returns (uint8 y) {\n        require(x < 1 << 8);\n\n        y = uint8(x);\n    }\n}\n"},{"file_path":"lib/solmate/src/utils/SafeTransferLib.sol","source_code":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\nimport {ERC20} from \"../tokens/ERC20.sol\";\n\n/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)\n/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.\n/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.\nlibrary SafeTransferLib {\n    /*//////////////////////////////////////////////////////////////\n                             ETH OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function safeTransferETH(address to, uint256 amount) internal {\n        bool success;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Transfer the ETH and store if it succeeded or not.\n            success := call(gas(), to, amount, 0, 0, 0, 0)\n        }\n\n        require(success, \"ETH_TRANSFER_FAILED\");\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                            ERC20 OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function safeTransferFrom(\n        ERC20 token,\n        address from,\n        address to,\n        uint256 amount\n    ) internal {\n        bool success;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Get a pointer to some free memory.\n            let freeMemoryPointer := mload(0x40)\n\n            // Write the abi-encoded calldata into memory, beginning with the function selector.\n            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)\n            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the \"from\" argument.\n            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the \"to\" argument.\n            mstore(add(freeMemoryPointer, 68), amount) // Append the \"amount\" argument. Masking not required as it's a full 32 byte type.\n\n            success := and(\n                // Set success to whether the call reverted, if not we check it either\n                // returned exactly 1 (can't just be non-zero data), or had no return data.\n                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.\n                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n                // Counterintuitively, this call must be positioned second to the or() call in the\n                // surrounding and() call or else returndatasize() will be zero during the computation.\n                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)\n            )\n        }\n\n        require(success, \"TRANSFER_FROM_FAILED\");\n    }\n\n    function safeTransfer(\n        ERC20 token,\n        address to,\n        uint256 amount\n    ) internal {\n        bool success;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Get a pointer to some free memory.\n            let freeMemoryPointer := mload(0x40)\n\n            // Write the abi-encoded calldata into memory, beginning with the function selector.\n            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the \"to\" argument.\n            mstore(add(freeMemoryPointer, 36), amount) // Append the \"amount\" argument. Masking not required as it's a full 32 byte type.\n\n            success := and(\n                // Set success to whether the call reverted, if not we check it either\n                // returned exactly 1 (can't just be non-zero data), or had no return data.\n                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.\n                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n                // Counterintuitively, this call must be positioned second to the or() call in the\n                // surrounding and() call or else returndatasize() will be zero during the computation.\n                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)\n            )\n        }\n\n        require(success, \"TRANSFER_FAILED\");\n    }\n\n    function safeApprove(\n        ERC20 token,\n        address to,\n        uint256 amount\n    ) internal {\n        bool success;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Get a pointer to some free memory.\n            let freeMemoryPointer := mload(0x40)\n\n            // Write the abi-encoded calldata into memory, beginning with the function selector.\n            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)\n            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the \"to\" argument.\n            mstore(add(freeMemoryPointer, 36), amount) // Append the \"amount\" argument. Masking not required as it's a full 32 byte type.\n\n            success := and(\n                // Set success to whether the call reverted, if not we check it either\n                // returned exactly 1 (can't just be non-zero data), or had no return data.\n                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.\n                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n                // Counterintuitively, this call must be positioned second to the or() call in the\n                // surrounding and() call or else returndatasize() will be zero during the computation.\n                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)\n            )\n        }\n\n        require(success, \"APPROVE_FAILED\");\n    }\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.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 * For a generic mechanism see {ERC20PresetMinterPauser}.\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 ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => 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 override 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 override 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 override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override 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 `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` 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 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\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 `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `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     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` 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    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\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 amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` 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 amount) 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 `amount` as the allowance of `spender` over the 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 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` 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 amount) external returns (bool);\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\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":"node_modules/@openzeppelin/contracts/utils/Context.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\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"},{"file_path":"src/contracts/LinearRewardsErc4626.sol","source_code":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.21;\n\n// ====================================================================\n// |     ______                   _______                             |\n// |    / _____________ __  __   / ____(_____  ____ _____  ________   |\n// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \\/ __ `/ __ \\/ ___/ _ \\  |\n// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |\n// | /_/   /_/   \\__,_/_/|_|  /_/   /_/_/ /_/\\__,_/_/ /_/\\___/\\___/   |\n// |                                                                  |\n// ====================================================================\n// ======================== LinearRewardsErc4626 ======================\n// ====================================================================\n// Frax Finance: https://github.com/FraxFinance\n\nimport { ERC20, ERC4626 } from \"solmate/mixins/ERC4626.sol\";\nimport { SafeCastLib } from \"solmate/utils/SafeCastLib.sol\";\n\n/// @title LinearRewardsErc4626\n/// @notice An ERC4626 Vault implementation with linear rewards\nabstract contract LinearRewardsErc4626 is ERC4626 {\n    using SafeCastLib for *;\n\n    /// @notice The precision of all integer calculations\n    uint256 public constant PRECISION = 1e18;\n\n    /// @notice The rewards cycle length in seconds\n    uint256 public immutable REWARDS_CYCLE_LENGTH;\n\n    /// @notice Information about the current rewards cycle\n    struct RewardsCycleData {\n        uint40 cycleEnd; // Timestamp of the end of the current rewards cycle\n        uint40 lastSync; // Timestamp of the last time the rewards cycle was synced\n        uint216 rewardCycleAmount; // Amount of rewards to be distributed in the current cycle\n    }\n\n    /// @notice The rewards cycle data, stored in a single word to save gas\n    RewardsCycleData public rewardsCycleData;\n\n    /// @notice The timestamp of the last time rewards were distributed\n    uint256 public lastRewardsDistribution;\n\n    /// @notice The total amount of assets that have been distributed and deposited\n    uint256 public storedTotalAssets;\n\n    /// @notice The precision of the underlying asset\n    uint256 public immutable UNDERLYING_PRECISION;\n\n    /// @param _underlying The erc20 asset deposited\n    /// @param _name The name of the vault\n    /// @param _symbol The symbol of the vault\n    /// @param _rewardsCycleLength The length of the rewards cycle in seconds\n    constructor(\n        ERC20 _underlying,\n        string memory _name,\n        string memory _symbol,\n        uint256 _rewardsCycleLength\n    ) ERC4626(_underlying, _name, _symbol) {\n        REWARDS_CYCLE_LENGTH = _rewardsCycleLength;\n        UNDERLYING_PRECISION = 10 ** _underlying.decimals();\n\n        // initialize rewardsCycleEnd value\n        // NOTE: normally distribution of rewards should be done prior to _syncRewards but in this case we know there are no users or rewards yet.\n        _syncRewards();\n\n        // initialize lastRewardsDistribution value\n        _distributeRewards();\n    }\n\n    function pricePerShare() external view returns (uint256 _pricePerShare) {\n        _pricePerShare = convertToAssets(UNDERLYING_PRECISION);\n    }\n\n    /// @notice The ```calculateRewardsToDistribute``` function calculates the amount of rewards to distribute based on the rewards cycle data and the time elapsed\n    /// @param _rewardsCycleData The rewards cycle data\n    /// @param _deltaTime The time elapsed since the last rewards distribution\n    /// @return _rewardToDistribute The amount of rewards to distribute\n    function calculateRewardsToDistribute(\n        RewardsCycleData memory _rewardsCycleData,\n        uint256 _deltaTime\n    ) public view virtual returns (uint256 _rewardToDistribute) {\n        _rewardToDistribute =\n            (_rewardsCycleData.rewardCycleAmount * _deltaTime) /\n            (_rewardsCycleData.cycleEnd - _rewardsCycleData.lastSync);\n    }\n\n    /// @notice The ```previewDistributeRewards``` function is used to preview the rewards distributed at the top of the block\n    /// @return _rewardToDistribute The amount of underlying to distribute\n    function previewDistributeRewards() public view virtual returns (uint256 _rewardToDistribute) {\n        // Cache state for gas savings\n        RewardsCycleData memory _rewardsCycleData = rewardsCycleData;\n        uint256 _lastRewardsDistribution = lastRewardsDistribution;\n        uint40 _timestamp = block.timestamp.safeCastTo40();\n\n        // Calculate the delta time, but only include up to the cycle end in case we are passed it\n        uint256 _deltaTime = _timestamp > _rewardsCycleData.cycleEnd\n            ? _rewardsCycleData.cycleEnd - _lastRewardsDistribution\n            : _timestamp - _lastRewardsDistribution;\n\n        // Calculate the rewards to distribute\n        _rewardToDistribute = calculateRewardsToDistribute({\n            _rewardsCycleData: _rewardsCycleData,\n            _deltaTime: _deltaTime\n        });\n    }\n\n    /// @notice The ```distributeRewards``` function distributes the rewards once per block\n    /// @return _rewardToDistribute The amount of underlying to distribute\n    function _distributeRewards() internal virtual returns (uint256 _rewardToDistribute) {\n        _rewardToDistribute = previewDistributeRewards();\n\n        // Only write to state/emit if we actually distribute rewards\n        if (_rewardToDistribute != 0) {\n            storedTotalAssets += _rewardToDistribute;\n            emit DistributeRewards({ rewardsToDistribute: _rewardToDistribute });\n        }\n\n        lastRewardsDistribution = block.timestamp;\n    }\n\n    /// @notice The ```previewSyncRewards``` function returns the updated rewards cycle data without updating the state\n    /// @return _newRewardsCycleData The updated rewards cycle data\n    function previewSyncRewards() public view virtual returns (RewardsCycleData memory _newRewardsCycleData) {\n        RewardsCycleData memory _rewardsCycleData = rewardsCycleData;\n\n        uint256 _timestamp = block.timestamp;\n\n        // Only sync if the previous cycle has ended\n        if (_timestamp <= _rewardsCycleData.cycleEnd) return _rewardsCycleData;\n\n        // Calculate rewards for next cycle\n        uint256 _newRewards = asset.balanceOf(address(this)) - storedTotalAssets;\n\n        // Calculate the next cycle end, this keeps cycles at the same time regardless of when sync is called\n        uint40 _cycleEnd = (((_timestamp + REWARDS_CYCLE_LENGTH) / REWARDS_CYCLE_LENGTH) * REWARDS_CYCLE_LENGTH)\n            .safeCastTo40();\n\n        // This block prevents big jumps in rewards rate in case the sync happens near the end of the cycle\n        if (_cycleEnd - _timestamp < REWARDS_CYCLE_LENGTH / 40) {\n            _cycleEnd += REWARDS_CYCLE_LENGTH.safeCastTo40();\n        }\n\n        // Write return values\n        _rewardsCycleData.rewardCycleAmount = _newRewards.safeCastTo216();\n        _rewardsCycleData.lastSync = _timestamp.safeCastTo40();\n        _rewardsCycleData.cycleEnd = _cycleEnd;\n\n        return _rewardsCycleData;\n    }\n\n    /// @notice The ```_syncRewards``` function is used to update the rewards cycle data\n    function _syncRewards() internal virtual {\n        RewardsCycleData memory _rewardsCycleData = previewSyncRewards();\n\n        if (\n            block\n                .timestamp\n                // If true, then preview shows a rewards should be processed\n                .safeCastTo40() ==\n            _rewardsCycleData.lastSync &&\n            // Ensures that we don't write to state twice in the same block\n            rewardsCycleData.lastSync != _rewardsCycleData.lastSync\n        ) {\n            rewardsCycleData = _rewardsCycleData;\n            emit SyncRewards({\n                cycleEnd: _rewardsCycleData.cycleEnd,\n                lastSync: _rewardsCycleData.lastSync,\n                rewardCycleAmount: _rewardsCycleData.rewardCycleAmount\n            });\n        }\n    }\n\n    /// @notice The ```syncRewardsAndDistribution``` function is used to update the rewards cycle data and distribute rewards\n    /// @dev rewards must be distributed before the cycle is synced\n    function syncRewardsAndDistribution() public virtual {\n        _distributeRewards();\n        _syncRewards();\n    }\n\n    /// @notice The ```totalAssets``` function returns the total assets available in the vault\n    /// @dev This function simulates the rewards that will be distributed at the top of the block\n    /// @return _totalAssets The total assets available in the vault\n    function totalAssets() public view virtual override returns (uint256 _totalAssets) {\n        uint256 _rewardToDistribute = previewDistributeRewards();\n        _totalAssets = storedTotalAssets + _rewardToDistribute;\n    }\n\n    function afterDeposit(uint256 amount, uint256 shares) internal virtual override {\n        storedTotalAssets += amount;\n    }\n\n    /// @notice The ```deposit``` function allows a user to mint shares by depositing underlying\n    /// @param _assets The amount of underlying to deposit\n    /// @param _receiver The address to send the shares to\n    /// @return _shares The amount of shares minted\n    function deposit(uint256 _assets, address _receiver) public override returns (uint256 _shares) {\n        syncRewardsAndDistribution();\n        _shares = super.deposit({ assets: _assets, receiver: _receiver });\n    }\n\n    /// @notice The ```mint``` function allows a user to mint a given number of shares\n    /// @param _shares The amount of shares to mint\n    /// @param _receiver The address to send the shares to\n    /// @return _assets The amount of underlying deposited\n    function mint(uint256 _shares, address _receiver) public override returns (uint256 _assets) {\n        syncRewardsAndDistribution();\n        _assets = super.mint({ shares: _shares, receiver: _receiver });\n    }\n\n    function beforeWithdraw(uint256 amount, uint256 shares) internal virtual override {\n        storedTotalAssets -= amount;\n    }\n\n    /// @notice The ```withdraw``` function allows a user to withdraw a given amount of underlying\n    /// @param _assets The amount of underlying to withdraw\n    /// @param _receiver The address to send the underlying to\n    /// @param _owner The address of the owner of the shares\n    /// @return _shares The amount of shares burned\n    function withdraw(uint256 _assets, address _receiver, address _owner) public override returns (uint256 _shares) {\n        syncRewardsAndDistribution();\n\n        _shares = super.withdraw({ assets: _assets, receiver: _receiver, owner: _owner });\n    }\n\n    /// @notice The ```redeem``` function allows a user to redeem their shares for underlying\n    /// @param _shares The amount of shares to redeem\n    /// @param _receiver The address to send the underlying to\n    /// @param _owner The address of the owner of the shares\n    /// @return _assets The amount of underlying redeemed\n    function redeem(uint256 _shares, address _receiver, address _owner) public override returns (uint256 _assets) {\n        syncRewardsAndDistribution();\n\n        _assets = super.redeem({ shares: _shares, receiver: _receiver, owner: _owner });\n    }\n\n    /// @notice The ```depositWithSignature``` function allows a user to use signed approvals to deposit\n    /// @param _assets The amount of underlying to deposit\n    /// @param _receiver The address to send the shares to\n    /// @param _deadline The deadline for the signature\n    /// @param _approveMax Whether or not to approve the maximum amount\n    /// @param _v The v value of the signature\n    /// @param _r The r value of the signature\n    /// @param _s The s value of the signature\n    /// @return _shares The amount of shares minted\n    function depositWithSignature(\n        uint256 _assets,\n        address _receiver,\n        uint256 _deadline,\n        bool _approveMax,\n        uint8 _v,\n        bytes32 _r,\n        bytes32 _s\n    ) external returns (uint256 _shares) {\n        uint256 _amount = _approveMax ? type(uint256).max : _assets;\n        asset.permit({\n            owner: msg.sender,\n            spender: address(this),\n            value: _amount,\n            deadline: _deadline,\n            v: _v,\n            r: _r,\n            s: _s\n        });\n        _shares = (deposit({ _assets: _assets, _receiver: _receiver }));\n    }\n\n    //==============================================================================\n    // Events\n    //==============================================================================\n\n    /// @notice The ```SyncRewards``` event is emitted when the rewards cycle is synced\n    /// @param cycleEnd The timestamp of the end of the current rewards cycle\n    /// @param lastSync The timestamp of the last time the rewards cycle was synced\n    /// @param rewardCycleAmount The amount of rewards to be distributed in the current cycle\n    event SyncRewards(uint40 cycleEnd, uint40 lastSync, uint216 rewardCycleAmount);\n\n    /// @notice The ```DistributeRewards``` event is emitted when rewards are distributed to storedTotalAssets\n    /// @param rewardsToDistribute The amount of rewards that were distributed\n    event DistributeRewards(uint256 rewardsToDistribute);\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"contract IERC20","name":"_underlying","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint32","name":"_rewardsCycleLength","type":"uint32"},{"internalType":"uint256","name":"_maxDistributionPerSecondPerAsset","type":"uint256"},{"internalType":"address","name":"_timelockAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"pendingTimelockAddress","type":"address"},{"internalType":"address","name":"actualAddress","type":"address"}],"name":"AddressIsNotPendingTimelock","type":"error"},{"inputs":[{"internalType":"address","name":"timelockAddress","type":"address"},{"internalType":"address","name":"actualAddress","type":"address"}],"name":"AddressIsNotTimelock","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rewardsToDistribute","type":"uint256"}],"name":"DistributeRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMax","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMax","type":"uint256"}],"name":"SetMaxDistributionPerSecondPerAsset","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint40","name":"cycleEnd","type":"uint40"},{"indexed":false,"internalType":"uint40","name":"lastSync","type":"uint40"},{"indexed":false,"internalType":"uint216","name":"rewardCycleAmount","type":"uint216"}],"name":"SyncRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTimelock","type":"address"},{"indexed":true,"internalType":"address","name":"newTimelock","type":"address"}],"name":"TimelockTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTimelock","type":"address"},{"indexed":true,"internalType":"address","name":"newTimelock","type":"address"}],"name":"TimelockTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARDS_CYCLE_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNDERLYING_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptTransferTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint40","name":"cycleEnd","type":"uint40"},{"internalType":"uint40","name":"lastSync","type":"uint40"},{"internalType":"uint216","name":"rewardCycleAmount","type":"uint216"}],"internalType":"struct LinearRewardsErc4626.RewardsCycleData","name":"_rewardsCycleData","type":"tuple"},{"internalType":"uint256","name":"_deltaTime","type":"uint256"}],"name":"calculateRewardsToDistribute","outputs":[{"internalType":"uint256","name":"_rewardToDistribute","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bool","name":"_approveMax","type":"bool"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"depositWithSignature","outputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastRewardsDistribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxDistributionPerSecondPerAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"_assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingTimelockAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"previewDistributeRewards","outputs":[{"internalType":"uint256","name":"_rewardToDistribute","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"previewSyncRewards","outputs":[{"components":[{"internalType":"uint40","name":"cycleEnd","type":"uint40"},{"internalType":"uint40","name":"lastSync","type":"uint40"},{"internalType":"uint216","name":"rewardCycleAmount","type":"uint216"}],"internalType":"struct LinearRewardsErc4626.RewardsCycleData","name":"_newRewardsCycleData","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricePerShare","outputs":[{"internalType":"uint256","name":"_pricePerShare","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"_assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsCycleData","outputs":[{"internalType":"uint40","name":"cycleEnd","type":"uint40"},{"internalType":"uint40","name":"lastSync","type":"uint40"},{"internalType":"uint216","name":"rewardCycleAmount","type":"uint216"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxDistributionPerSecondPerAsset","type":"uint256"}],"name":"setMaxDistributionPerSecondPerAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"storedTotalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"syncRewardsAndDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"timelockAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"_totalAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newTimelock","type":"address"}],"name":"transferTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":null}