{"file_path":"src/dao/staking/GovStaker.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport { MultiRewardsDistributor } from 'src/dao/staking/MultiRewardsDistributor.sol';\nimport { IERC20, SafeERC20 } from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport { EpochTracker } from 'src/dependencies/EpochTracker.sol';\nimport { DelegatedOps } from 'src/dependencies/DelegatedOps.sol';\nimport { GovStakerEscrow } from 'src/dao/staking/GovStakerEscrow.sol';\nimport { IResupplyRegistry } from \"src/interfaces/IResupplyRegistry.sol\";\nimport { IGovStaker } from \"src/interfaces/IGovStaker.sol\";\n\ncontract GovStaker is MultiRewardsDistributor, EpochTracker, DelegatedOps {\n    using SafeERC20 for IERC20;\n\n    uint24 public constant MAX_COOLDOWN_DURATION = 90 days;\n    address private immutable _stakeToken;\n    GovStakerEscrow public immutable escrow;\n    IResupplyRegistry public immutable registry;\n\n    // Account tracking state vars.\n    mapping(address account => AccountData data) public accountData;\n    mapping(address account => mapping(uint epoch => uint weight)) private accountWeightAt;\n\n    // Global weight tracking state vars.\n    uint112 public totalPending;\n    uint16 public totalLastUpdateEpoch;\n    mapping(uint epoch => uint weight) private totalWeightAt;\n\n    // Cooldown tracking vars.\n    uint public cooldownEpochs;\n    mapping(address => UserCooldown) public cooldowns;\n\n    // Generic token interface.\n    uint private _totalSupply;\n\n    struct AccountData {\n        uint112 realizedStake; // Amount of stake that has fully realized weight.\n        uint112 pendingStake; // Amount of stake that has not yet fully realized weight.\n        uint16 lastUpdateEpoch;\n        bool isPermaStaker;\n    }\n\n    struct UserCooldown {\n        uint104 end;\n        uint152 amount;\n    }\n\n    error InvalidAmount();\n    error InsufficientRealizedStake();\n    error InvalidCooldown();\n    error InvalidDuration();\n    error OldEpoch();\n\n    /* ========== EVENTS ========== */\n\n    event Staked(address indexed account, uint indexed epoch, uint amount);\n    event Unstaked(address indexed account, uint amount);\n    event Cooldown(address indexed account, uint amount, uint end);\n    event CooldownEpochsUpdated(uint24 newDuration);\n    event PermaStakerSet(address indexed account);\n\n\n    /* ========== CONSTRUCTOR ========== */\n\n    /**\n        @param _core            Core contract address.\n        @param _registry        Registry contract address.\n        @param _token           Token to be staked.\n        @param _cooldownEpochs  Number of epochs to cooldown for.\n    */\n    constructor(\n        address _core,\n        address _registry,\n        address _token,\n        uint24 _cooldownEpochs\n    ) MultiRewardsDistributor(_core) EpochTracker(_core) {\n        escrow = new GovStakerEscrow(address(this), _token);\n        _stakeToken = _token;\n        cooldownEpochs = _cooldownEpochs;\n        registry = IResupplyRegistry(_registry);\n        emit CooldownEpochsUpdated(_cooldownEpochs);\n    }\n\n    function stake(uint _amount) external returns (uint) {\n        return _stake(msg.sender, _amount);\n    }\n\n    function stake(address _account, uint _amount) external returns (uint) {\n        return _stake(_account, _amount);\n    }\n\n    function _stake(address _account, uint _amount) internal updateReward(_account) returns (uint) {\n        if (_amount == 0 || _amount >= type(uint112).max) revert InvalidAmount();\n\n        // Before going further, let's sync our account and total weights\n        uint systemEpoch = getEpoch();\n        (AccountData memory acctData, ) = _checkpointAccount(_account, systemEpoch);\n        _checkpointTotal(systemEpoch);\n\n        acctData.pendingStake += uint112(_amount);\n        totalPending += uint112(_amount);\n\n        accountData[_account] = acctData;\n        _totalSupply += _amount;\n\n        IERC20(_stakeToken).safeTransferFrom(msg.sender, address(this), _amount);\n        emit Staked(_account, systemEpoch, _amount);\n\n        return _amount;\n    }\n\n    /**\n        @notice Request a cooldown tokens from the contract.\n    */\n    function cooldown(address _account, uint _amount) external callerOrDelegated(_account) returns (uint) {\n        uint systemEpoch = getEpoch();\n        (AccountData memory acctData, ) = _checkpointAccount(_account, systemEpoch);\n        require(!acctData.isPermaStaker, \"perma staker account\");\n        return _cooldown(_account, _amount, acctData, systemEpoch); // triggers updateReward\n    }\n\n    /**\n     * @notice Initiate cooldown and claim any outstanding rewards.\n     */\n    function exit(address _account) external nonReentrant callerOrDelegated(_account) returns (uint) {\n        uint systemEpoch = getEpoch();\n        (AccountData memory acctData, ) = _checkpointAccount(_account, systemEpoch);\n        require(!acctData.isPermaStaker, \"perma staker account\");\n        _cooldown(_account, acctData.realizedStake, acctData, systemEpoch); // triggers updateReward\n        _getRewardFor(_account);\n        return acctData.realizedStake;\n    }\n\n    function _cooldown(address _account, uint _amount, AccountData memory acctData, uint systemEpoch) internal updateReward(_account) returns (uint) {\n        if (_amount == 0 || _amount > type(uint112).max) revert InvalidAmount();\n        if (acctData.realizedStake < _amount) revert InsufficientRealizedStake();\n        _checkpointTotal(systemEpoch);\n\n        acctData.realizedStake -= uint112(_amount);\n        accountData[_account] = acctData;\n\n        totalWeightAt[systemEpoch] -= _amount;\n        accountWeightAt[_account][systemEpoch] -= _amount;\n\n        _totalSupply -= _amount;\n\n        UserCooldown memory userCooldown = cooldowns[_account];\n        userCooldown.end = uint104(block.timestamp + (cooldownEpochs * epochLength));\n        userCooldown.amount += uint152(_amount);\n        cooldowns[_account] = userCooldown;\n\n        emit Cooldown(_account, userCooldown.amount, userCooldown.end);\n        IERC20(_stakeToken).safeTransfer(address(escrow), _amount);\n\n        return _amount;\n    }\n\n    function unstake(address _account, address _receiver) external callerOrDelegated(_account) returns (uint) {\n        return _unstake(_account, _receiver);\n    }\n\n    function _unstake(address _account, address _receiver) internal returns (uint) {\n        UserCooldown storage userCooldown = cooldowns[_account];\n        uint256 amount = userCooldown.amount;\n        if(amount == 0) return 0;\n        if(block.timestamp < userCooldown.end && cooldownEpochs != 0) revert InvalidCooldown();\n        delete cooldowns[_account];\n        escrow.withdraw(_receiver, amount);\n        emit Unstaked(_account, amount);\n        return amount;\n    }\n\n    /**\n        @notice Get the current realized weight for an account\n        @param _account Account to checkpoint.\n        @return acctData Most recent account data written to storage.\n        @return weight Most current account weight.\n        @dev Prefer to use this function over it's view counterpart for\n             contract -> contract interactions.\n    */\n    function checkpointAccount(address _account) external returns (AccountData memory acctData, uint weight) {\n        (acctData, weight) = _checkpointAccount(_account, getEpoch());\n        accountData[_account] = acctData;\n    }\n\n    /**\n        @notice Checkpoint an account using a specified epoch limit.\n        @dev    To use in the event that significant number of epochs have passed since last \n                heckpoint and single call becomes too expensive.\n        @param _account Account to checkpoint.\n        @param _epoch epoch number which we want to checkpoint up to.\n        @return acctData Most recent account data written to storage.\n        @return weight Account weight for provided epoch.\n    */\n    function checkpointAccountWithLimit(\n        address _account,\n        uint _epoch\n    ) external returns (AccountData memory acctData, uint weight) {\n        uint systemEpoch = getEpoch();\n        if (_epoch >= systemEpoch) _epoch = systemEpoch;\n        (acctData, weight) = _checkpointAccount(_account, _epoch);\n        accountData[_account] = acctData;\n    }\n\n    function _checkpointAccount(\n        address _account,\n        uint _systemEpoch\n    ) internal returns (AccountData memory acctData, uint weight) {\n        acctData = accountData[_account];\n        uint lastUpdateEpoch = acctData.lastUpdateEpoch;\n\n        if (_systemEpoch == lastUpdateEpoch) {\n            return (acctData, accountWeightAt[_account][lastUpdateEpoch]);\n        }\n\n        if (_systemEpoch <= lastUpdateEpoch) revert OldEpoch();\n\n        uint pending = uint(acctData.pendingStake);\n        uint realized = acctData.realizedStake;\n\n        if (pending == 0) {\n            if (realized != 0) {\n                weight = accountWeightAt[_account][lastUpdateEpoch];\n                while (lastUpdateEpoch < _systemEpoch) {\n                    unchecked { lastUpdateEpoch++; }\n                    accountWeightAt[_account][lastUpdateEpoch] = weight;\n                }\n            }\n            accountData[_account].lastUpdateEpoch = uint16(_systemEpoch);\n            acctData.lastUpdateEpoch = uint16(_systemEpoch);\n            return (acctData, weight);\n        }\n\n        weight = accountWeightAt[_account][lastUpdateEpoch];\n\n        // Add pending to realized weight\n        weight += pending;\n        realized = weight;\n\n        // Fill in any missed epochs.\n        while (lastUpdateEpoch < _systemEpoch) {\n            unchecked { lastUpdateEpoch++; }\n            accountWeightAt[_account][lastUpdateEpoch] = weight;\n        }\n\n        // Write new account data to storage.\n        acctData = AccountData({\n            pendingStake: 0,\n            realizedStake: uint112(weight),\n            lastUpdateEpoch: uint16(_systemEpoch),\n            isPermaStaker: acctData.isPermaStaker\n        });\n    }\n\n    /**\n        @notice Get the current total system weight\n        @dev Also updates local storage values for total weights. Using\n             this function over it's `view` counterpart is preferred for\n             contract -> contract interactions.\n    */\n    function checkpointTotal() external returns (uint) {\n        uint systemEpoch = getEpoch();\n        return _checkpointTotal(systemEpoch);\n    }\n\n    /**\n        @notice Get the current total system weight\n        @dev Also updates local storage values for total weights. Using\n             this function over it's `view` counterpart is preferred for\n             contract -> contract interactions.\n    */\n    function _checkpointTotal(uint systemEpoch) internal returns (uint) {\n        // These two share a storage slot.\n        uint16 lastUpdateEpoch = totalLastUpdateEpoch;\n        uint pending = totalPending;\n\n        uint weight = totalWeightAt[lastUpdateEpoch];\n\n        if (lastUpdateEpoch == systemEpoch) {\n            return weight;\n        }\n\n        totalLastUpdateEpoch = uint16(systemEpoch);\n        weight += pending;\n        totalPending = 0;\n\n        while (lastUpdateEpoch < systemEpoch) {\n            unchecked { lastUpdateEpoch++; }\n            totalWeightAt[lastUpdateEpoch] = weight;\n        }\n\n        return weight;\n    }\n\n    /* ========== RESTRICTED FUNCTIONS ========== */\n\n    function setCooldownEpochs(uint24 _epochs) external onlyOwner {\n        if (_epochs * epochLength > MAX_COOLDOWN_DURATION) revert InvalidDuration();\n        cooldownEpochs = _epochs;\n        emit CooldownEpochsUpdated(_epochs);\n    }\n\n    function stakeToken() public view override returns (address) {\n        return _stakeToken;\n    }\n\n    /* ========== OVERRIDES ========== */\n\n    /**\n        @notice Returns the balance of underlying staked tokens for an account\n        @param _account Account to query balance.\n        @return balance of account.\n    */\n    function balanceOf(address _account) public view override returns (uint) {\n        AccountData memory acctData = accountData[_account];\n        return acctData.pendingStake + acctData.realizedStake;\n    }\n\n    function totalSupply() public view override returns (uint) {\n        return _totalSupply;\n    }\n\n    /* ========== VIEWS ========== */\n\n    /**\n        @notice View function to get the current weight for an account\n    */\n    function getAccountWeight(address account) external view returns (uint) {\n        return getAccountWeightAt(account, getEpoch());\n    }\n\n    /**\n        @notice Get the weight for an account in a given epoch\n    */\n    function getAccountWeightAt(address _account, uint _epoch) public view returns (uint) {\n        if (_epoch > getEpoch()) return 0;\n\n        AccountData memory acctData = accountData[_account];\n\n        uint16 lastUpdateEpoch = acctData.lastUpdateEpoch;\n\n        if (lastUpdateEpoch >= _epoch) return accountWeightAt[_account][_epoch];\n\n        uint weight = accountWeightAt[_account][lastUpdateEpoch];\n\n        uint pending = uint(acctData.pendingStake);\n        if (pending == 0) return weight;\n\n        return pending + weight;\n    }\n\n    /**\n        @notice Get the system weight for current epoch.\n    */\n    function getTotalWeight() external view returns (uint) {\n        return getTotalWeightAt(getEpoch());\n    }\n\n    /**\n        @notice Get the system weight for a specified epoch in the past.\n        @dev querying a epoch in the future will always return 0.\n        @param epoch the epoch number to query total weight for.\n    */\n    function getTotalWeightAt(uint epoch) public view returns (uint) {\n        uint systemEpoch = getEpoch();\n        if (epoch > systemEpoch) return 0;\n\n        // Read these together since they are packed in the same slot.\n        uint16 lastUpdateEpoch = totalLastUpdateEpoch;\n        uint pending = totalPending;\n\n        if (epoch <= lastUpdateEpoch) return totalWeightAt[epoch];\n\n        return totalWeightAt[lastUpdateEpoch] + pending;\n    }\n\n    /// @notice Get the amount of tokens that have passed cooldown.\n    /// @param _account The account to query.\n    /// @return . amount of tokens that have passed cooldown.\n    function getUnstakableAmount(address _account) external view returns (uint) {\n        UserCooldown memory userCooldown = cooldowns[_account];\n        if (isCooldownEnabled() && block.timestamp < userCooldown.end) return 0;\n        return userCooldown.amount;\n    }\n\n    function isCooldownEnabled() public view returns (bool) {\n        return cooldownEpochs > 0;\n    }\n\n    function isPermaStaker(address _account) external view returns (bool) {\n        return accountData[_account].isPermaStaker;\n    }\n\n    /* ========== PERMA STAKER FUNCTIONS ========== */\n\n    /**\n     * @notice  Set account as a permanent staker, preventing them from ever unstaking their staked tokens. \n     *          This action cannot be undone, and is irreversible.\n     */\n    function irreversiblyCommitAccountAsPermanentStaker(address _account) external callerOrDelegated(_account) {\n        require(!accountData[_account].isPermaStaker, \"already perma staker account\");\n        accountData[_account].isPermaStaker = true;\n        emit PermaStakerSet(_account);\n    }\n\n    /**\n     * @notice Migrates a perma staker's stake to a new staking contract\n     * @dev Only callable when cooldown epochs are set to 0\n     * @dev The new staking contract must be set in the registry\n     * @dev Will claim any pending rewards before migrating\n     * @dev The new staking contract must have delegate approval from this contract\n     * @return amount The amount of tokens that were migrated to the new staking contract\n     */\n    function migrateStake() external returns (uint amount) {\n        require(cooldownEpochs == 0, \"cooldownEpochs != 0\");\n        IGovStaker staker = IGovStaker(registry.staker());\n        require(address(this) != address(staker), \"!migrate\");\n        uint systemEpoch = getEpoch();\n        (AccountData memory acctData, ) = _checkpointAccount(msg.sender, systemEpoch);\n        require(acctData.isPermaStaker, \"not perma staker account\");\n        if (acctData.realizedStake > 0) {\n            _cooldown(msg.sender, acctData.realizedStake, acctData, systemEpoch); // triggers updateReward\n            amount = _unstake(msg.sender, address(this));\n            _getRewardFor(msg.sender);\n            IERC20(_stakeToken).approve(address(staker), amount);\n            staker.stake(msg.sender, amount);\n        }\n        staker.onPermaStakeMigrate(msg.sender);\n        return amount;\n    }\n\n    function onPermaStakeMigrate(address _account) external virtual {}\n}\n","deployed_bytecode":"0x6080806040526004361015610012575f80fd5b5f905f3560e01c90816301320fe2146120515750806306aba0e11461200a57806307f93a3814611fe35780630aed7b0d14611cab57806312cf9dad14611c385780631491496f14611bf057806318160ddd14611bd25780631930e82514611b7a5780631e9049cf14611b5c578063211dc32d14611b2f5780632378bea614611a2b5780633d18b912146119505780633ea01b34146118fe5780633f695b451461181f5780633f90916a146117f857806348e5d9f81461177f57806350735f6f1461176057806351ed6a301461171b57806357d775f8146116e0578063638634ee146116bc5780636889d9ae146115c45780636ca541e5146115a45780637035ab981461155157806370a082311461152d578063757991a8146114ed57806375a410141461147657806378e979251461143b5780637b103999146113f65780637bb7bed1146113b25780638980f11f146113555780638da5cb5b146103965780639d716bc6146113315780639e94080e146111f3578063a694fc3a146111d3578063aaf5eb68146111b0578063adc9772e14611188578063b42652e9146110ab578063b66503cf14610ddf578063bcd1101414610d92578063bf199e6214610d74578063c00007b014610c7e578063c3c854b614610bef578063c950ba7f14610bd1578063d0ed26ae14610989578063d6e5085f146108bb578063deb906e71461084b578063e2fdcc1714610806578063e509b9d9146107c5578063e70b9e2714610772578063e7805809146105bc578063e7a6bc44146104dc578063eb8f4f70146104be578063ebae46701461047c578063f122977714610458578063f21f3c08146103db578063f2f4eb2614610396578063fbeb4336146103715763ff342e091461029c575f80fd5b3461036e57602036600319011261036e576102b5612097565b6102bd612505565b9081516102c981612809565b916102d7604051938461213b565b8183526102e382612809565b602084019490601f1901368637855b83811061033d57868587604051928392602084019060208552518091526040840192915b818110610324575050500390f35b8251845285945060209384019390920191600101610316565b60019061035d6001600160a01b036103558386612558565b5116856122ea565b6103678288612558565b52016102f2565b80fd5b503461036e578060031936011261036e57602061ffff60095460701c16604051908152f35b503461036e578060031936011261036e576040517f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b03168152602090f35b503461036e57604036600319011261036e5761042a6020916103fb612097565b6104036120ad565b916001600160a01b03821633811491908215610432575b505061042590612441565b612d7a565b604051908152f35b815260068652604090819020335f9081529087529081205460ff1691506104259061041a565b503461036e57602036600319011261036e57602061042a610477612097565b612758565b503461036e57602036600319011261036e5760209060ff906040906001600160a01b036104a7612097565b16815260078452205460f01c166040519015158152f35b503461036e578060031936011261036e576020600b54604051908152f35b503461036e57604036600319011261036e5761042a6020916104fc612097565b906001600160a01b03821633811491908215610596575b505061051e90612441565b61057261054b7f0000000000000000000000000000000000000000000000000000000067d22000426122ac565b7f0000000000000000000000000000000000000000000000000000000000093a80906122cc565b9061057d8282612821565b509061058d606083015115612715565b60243590612a03565b815260068552604090819020335f9081529086529081205460ff16915061051e90610513565b503461036e57604036600319011261036e576105d6612097565b6105de6120ad565b6105e6613010565b6001546001600160a01b03831690811515855b8281106106c95750505080845260036020526040842060018060a01b0383165f5260205260405f20549283610631575b846001815580f35b8185526003602090815260408087206001600160a01b038681165f9081529184529082902088905584885260058352908720547fce405e67b4d6e56e438257e15f160ae28b450e6e7659bbc4c1f4e09a1ac846cb9391169081156106c15750935b6001600160a01b0316936106a786828761302e565b6040519586526001600160a01b031694a45f808080610629565b905093610692565b806106d56001926120c3565b838060a01b0391549060031b1c166106ec81612758565b90808a52600260205281600560408c200155846107088261241c565b828c526002602052600460408d200155610725575b5050016105f9565b61072f818a6122ea565b878b52600360205260408b20858060a01b0383165f5260205260405f2055868a52600460205260408a2090848060a01b03165f5260205260405f20555f8061071d565b503461036e57604036600319011261036e57604061078e612097565b916107976120ad565b9260018060a01b031681526003602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461036e57602036600319011261036e576020906001600160a01b036107ea612097565b16815260058252604060018060a01b0391205416604051908152f35b503461036e578060031936011261036e576040517f0000000000000000000000009b44e63fc1a252861bf6d4150b58f2de84b5c1356001600160a01b03168152602090f35b503461036e57602036600319011261036e576080906040906001600160a01b03610873612097565b1681526007602052205460ff604051916001600160701b03811683526001600160701b038160701c16602084015261ffff8160e01c16604084015260f01c1615156060820152f35b503461036e57602036600319011261036e5760043562ffffff811680910361098557610911337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614612369565b6276a70061093f7f0000000000000000000000000000000000000000000000000000000000093a80836122b9565b11610976576020817fc7a3b172868cdcc74bbcf808a3d5a3e88aa94454cae07ab3c27fe138d3210d2992600b55604051908152a180f35b637616640160e01b8252600482fd5b5080fd5b503461036e57606036600319011261036e576109a3612097565b6109ab6120ad565b604435916109e3337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614612369565b6001600160a01b03169081158015610bc0575b610bb1578215610ba25781845260026020526001604085200154610b935760405163313ce56760e01b8152602081600481865afa908115610b88578591610b47575b5060ff6012911603610b38577f000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f7266001600160a01b03168214610b295760015468010000000000000000811015610b15577f8ab68562a70a02d12b0bbb803d106d670bb6660d060e8cc535baee4fcb04598b91610abc826001602094016001556120c3565b81546001600160a01b0360039290921b82811b199091169087901b179091558487526002808452604080892080546001600160a01b0319169490931693841790925585885283528087206001018690555194855293a380f35b634e487b7160e01b85526041600452602485fd5b633f7bbeb960e21b8452600484fd5b63568fc68760e11b8452600484fd5b90506020813d602011610b80575b81610b626020938361213b565b81010312610b7c575160ff81168103610b7c5760ff610a38565b8480fd5b3d9150610b55565b6040513d87823e3d90fd5b6311ae984360e21b8452600484fd5b633019509960e21b8452600484fd5b63d92e233d60e01b8452600484fd5b506001600160a01b038116156109f6565b503461036e57602036600319011261036e57610beb612097565b5080f35b503461036e57604036600319011261036e57610c09612097565b60243590811515809203610c7a5733835260066020526040832060018060a01b0382165f5260205260405f2060ff1981541660ff841617905560405191825260018060a01b0316907f92d241afb0a1a9b3441bf1bd6bea0f9164cf5a2562cbe4bcc34ab943b246560860203392a380f35b8280fd5b503461036e57602036600319011261036e57610c98612097565b610ca0613010565b6001546001600160a01b03821680151590845b838110610ccb5785610cc486612e8f565b6001815580f35b80610cd76001926120c3565b838060a01b0391549060031b1c16610cee81612758565b90808952600260205281600560408b20015585610d0a8261241c565b828b526002602052600460408c200155610d27575b505001610cb3565b610d3181896122ea565b858a52600360205260408a20858060a01b0383165f5260205260405f205584895260046020526040892090848060a01b03165f5260205260405f20555f80610d1f565b503461036e578060031936011261036e576020600154604051908152f35b503461036e57602036600319011261036e5760209061042a90600160406001600160a01b03610dbf612097565b1692838152600286526003828220015493815260028652200154906122b9565b503461036e57604036600319011261036e57610df9612097565b60243590600154835b8181106110595750506001600160a01b03168083526002602052604080842090519192919060c0820167ffffffffffffffff8111838210176110455760405260018060a01b03815416908183526001810154602084019081526002820154604085019081526003830154916060860192835260056004850154946080880195865201549460a08701958652330361103757861561102857600d541561101957610ead8730338b6132c9565b8151428111610fea5750610ec28151886122cc565b6040516370a0823160e01b81523060048201526020816024818d5afa8015610fdf578b90610fa7575b610ef891508351906122cc565b8111610f9857927fac24935fd910bc682b5ccb1a07b718cadf8cf2f6d1404c4f3ddc3662dae40e2997959260209795926005958352428452610f3b81514261215d565b82528a8c526002895260408c209660018060a01b039060018060a01b03905116166bffffffffffffffffffffffff60a01b88541617875551600187015551600286015551600385015551600484015551910155604051908152a280f35b63474c247160e01b8a5260048afd5b506020813d602011610fd7575b81610fc16020938361213b565b81010312610fd357610ef89051610eeb565b5f80fd5b3d9150610fb4565b6040513d8d823e3d90fd5b61100c611006610ffe6110149342906122ac565b8651906122b9565b8961215d565b8251906122cc565b610ec2565b6347fc732760e11b8952600489fd5b633019509960e21b8952600489fd5b6282b42960e81b8952600489fd5b634e487b7160e01b86526041600452602486fd5b806110656001926120c3565b838060a01b0391549060031b1c1661107c81612758565b818852600260205260056040892001556110958161241c565b9087526002602052600460408820015501610e02565b503461036e57602036600319011261036e5760209060016001600160701b036110d2612097565b6110da613010565b828060a01b0381168033148015611161575b6110f69150612441565b61115561112661054b7f0000000000000000000000000000000000000000000000000000000067d22000426122ac565b9161114f6111348483612821565b5093611144606086015115612715565b848681511684612a03565b50612e8f565b51169155604051908152f35b5084526006855260408420838060a01b0333165f5285526110f660ff60405f2054166110ec565b503461036e57604036600319011261036e57602061042a6111a7612097565b6024359061306f565b503461036e578060031936011261036e576020604051670de0b6b3a76400008152f35b503461036e57602036600319011261036e57602061042a6004353361306f565b503461036e57602036600319011261036e5761120d612097565b611215612288565b506112da604061125161124b61054b7f0000000000000000000000000000000000000000000000000000000067d22000426122ac565b84612821565b6001600160a01b0390941685526007602090815291909420845181549286015160408701516001600160f01b03199094166001600160701b03929092169190911760709190911b600160701b600160e01b03161760e09290921b61ffff60e01b169190911781559192916060830151815460ff60f01b191690151560f01b60ff60f01b16179055565b61132d6040519283928360809093929193606060a08201956001600160701b0381511683526001600160701b03602082015116602084015261ffff60408201511660408401520151151560608201520152565b0390f35b503461036e57602036600319011261036e57602061042a611350612097565b6126bd565b503461036e57604036600319011261036e576113af611372612097565b6113a6337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614612369565b6024359061256c565b80f35b503461036e57602036600319011261036e576004359060015482101561036e5760206113dd836120c3565b905460405160039290921b1c6001600160a01b03168152f35b503461036e578060031936011261036e576040517f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b03168152602090f35b503461036e578060031936011261036e5760206040517f0000000000000000000000000000000000000000000000000000000067d220008152f35b503461036e57602036600319011261036e57611490612097565b611498613010565b3380835260056020526040832080546001600160a01b0319166001600160a01b039390931692831790557ff4239ad0860f93469699dd4be8040b8838c5e25bb6cf24a1dfb381b937ff078c8380a36001815580f35b503461036e578060031936011261036e57602061042a61054b7f0000000000000000000000000000000000000000000000000000000067d22000426122ac565b503461036e57602036600319011261036e57602061042a61154c612097565b6124a2565b503461036e57604036600319011261036e57604061156d612097565b916115766120ad565b9260018060a01b031681526004602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461036e578060031936011261036e576020600b541515604051908152f35b503461036e57602036600319011261036e576001600160a01b036115e6612097565b16803314801561169a575b6115fa90612441565b808252600760205260ff604083205460f01c1661165557808252600760205260408220805460ff60f01b1916600160f01b1790557fd9a2231c15b3bfce8e444b3bcc1a7e724c5368ab52f965679e17bac8abbf101a8280a280f35b60405162461bcd60e51b815260206004820152601c60248201527f616c7265616479207065726d61207374616b6572206163636f756e74000000006044820152606490fd5b50808252600660209081526040808420335f908152925290205460ff166115f1565b503461036e57602036600319011261036e57602061042a6116db612097565b61241c565b503461036e578060031936011261036e5760206040517f0000000000000000000000000000000000000000000000000000000000093a808152f35b503461036e578060031936011261036e576040517f000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f7266001600160a01b03168152602090f35b503461036e57602036600319011261036e57602061042a60043561239d565b503461036e57602036600319011261036e5760c0906040906001600160a01b036117a7612097565b16815260026020522060018060a01b038154169060018101549060028101546003820154906005600484015493015493604051958652602086015260408501526060840152608083015260a0820152f35b503461036e578060031936011261036e5760206001600160701b0360095416604051908152f35b503461036e57604036600319011261036e57611839612097565b6118416120ad565b90611876337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614612369565b6001600160a01b031690811580156118ed575b6118de5781835260026020526040832080546001600160a01b0319166001600160a01b03929092169182179055907f8a6fe46a7bcc5ff8e08e5e4d7bf80b812df26f8f800f7a815ccfea20e852b0ec8380a380f35b63d92e233d60e01b8352600483fd5b506001600160a01b03811615611889565b503461036e57602036600319011261036e57602061042a61191d612097565b61194a61054b7f0000000000000000000000000000000000000000000000000000000067d22000426122ac565b9061217e565b503461036e578060031936011261036e57611969613010565b600154331515825b8281106119825783610cc433612e8f565b8061198e6001926120c3565b838060a01b0391549060031b1c166119a581612758565b908087526002602052816005604089200155846119c18261241c565b8289526002602052600460408a2001556119de575b505001611971565b6119e881336122ea565b338852600360205260408820858060a01b0383165f5260205260405f205533875260046020526040872090848060a01b03165f5260205260405f20555f806119d6565b503461036e57604036600319011261036e57611a45612097565b6001600160a01b03168082526002602081905260408320015460243590421115611b2057818352600260205260408320546001600160a01b031633141580611aed575b611adf578015611ad05760207fad2f86b01ed93b4b3a150d448c61a4f5d8d38075d3c0c64cc0a26fd6e1f495459183855260028252806001604087200155604051908152a280f35b633019509960e21b8352600483fd5b6282b42960e81b8352600483fd5b50337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b03161415611a88565b633f1609d560e21b8352600483fd5b503461036e57604036600319011261036e57602061042a611b4e612097565b611b566120ad565b906122ea565b503461036e578060031936011261036e5760206040516276a7008152f35b503461036e57604036600319011261036e576040611b96612097565b91611b9f6120ad565b9260018060a01b031681526006602052209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b503461036e578060031936011261036e576020600d54604051908152f35b503461036e578060031936011261036e57602061042a611c3361054b7f0000000000000000000000000000000000000000000000000000000067d22000426122ac565b612f7f565b503461036e57604036600319011261036e57611c52612097565b6112da6040611251602435611c65612288565b50611c9361054b7f0000000000000000000000000000000000000000000000000000000067d22000426122ac565b80821015611ca3575b5084612821565b90505f611c9c565b34610fd3575f366003190112610fd3575f600b54611fa857604051635ebaf1db60e01b81526020816004817f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b03165afa908115611dc5575f91611f66575b506001600160a01b031690308214611f3657611d4f61054b7f0000000000000000000000000000000000000000000000000000000067d22000426122ac565b611d598133612821565b50606081015115611ef1576001600160701b0381511680611dd0575b505050813b15610fd3575f809260246040518095819363c950ba7f60e01b83523360048401525af1918215611dc557602092611db5575b50604051908152f35b5f611dbf9161213b565b5f611dac565b6040513d5f823e3d90fd5b611ddb935033612a03565b50611de63033612d7a565b611def33612e8f565b60405163095ea7b360e01b81526001600160a01b038316600482015260248101829052602081806044810103815f7f000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f7266001600160a01b03165af18015611dc557611eba575b506040516356e4bb9760e11b8152336004820152602481018290526020816044815f875af18015611dc557611e8b575b8080611d75565b611eac9060203d602011611eb3575b611ea4818361213b565b810190612279565b5082611e84565b503d611e9a565b6020813d602011611ee9575b81611ed36020938361213b565b81010312610fd357518015158114611e54575f80fd5b3d9150611ec6565b60405162461bcd60e51b815260206004820152601860248201527f6e6f74207065726d61207374616b6572206163636f756e7400000000000000006044820152606490fd5b60405162461bcd60e51b8152602060048201526008602482015267216d69677261746560c01b6044820152606490fd5b90506020813d602011611fa0575b81611f816020938361213b565b81010312610fd357516001600160a01b0381168103610fd35782611d10565b3d9150611f74565b60405162461bcd60e51b81526020600482015260136024820152720636f6f6c646f776e45706f63687320213d203606c1b6044820152606490fd5b34610fd3576040366003190112610fd357602061042a612001612097565b6024359061217e565b34610fd3575f366003190112610fd357602061042a61204c61054b7f0000000000000000000000000000000000000000000000000000000067d22000426122ac565b61239d565b34610fd3576020366003190112610fd3576040906001600160a01b03612075612097565b165f52600c602052815f20546001600160681b038116825260681c6020820152f35b600435906001600160a01b0382168203610fd357565b602435906001600160a01b0382168203610fd357565b6001548110156120db5760015f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b6080810190811067ffffffffffffffff82111761210b57604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761210b57604052565b90601f8019910116810190811067ffffffffffffffff82111761210b57604052565b9190820180921161216a57565b634e487b7160e01b5f52601160045260245ffd5b6121ab61054b7f0000000000000000000000000000000000000000000000000000000067d22000426122ac565b8211612273576001600160a01b03165f818152600760205260409081902090519291906121d7846120ef565b54916001600160701b038316845260208401936001600160701b038460701c168552606060ff61ffff8660e01c169586604085015260f01c1615159101528083101561225657505f52600860205260405f20905f526020526001600160701b0360405f20549151168015612252579061224f9161215d565b90565b5090565b925090505f52600860205260405f20905f5260205260405f205490565b50505f90565b90816020910312610fd3575190565b60405190612295826120ef565b5f6060838281528260208201528260408201520152565b9190820391821161216a57565b8181029291811591840414171561216a57565b81156122d6570490565b634e487b7160e01b5f52601260045260245ffd5b61224f91670de0b6b3a7640000612343612303846124a2565b61233d61230f85612758565b6001600160a01b039687165f8181526004602090815260408083209a8a1683529990529790972054906122ac565b906122b9565b04915f52600360205260405f209060018060a01b03165f5260205260405f20549061215d565b1561237057565b60405162461bcd60e51b815260206004820152600560248201526421636f726560d81b6044820152606490fd5b6123ca61054b7f0000000000000000000000000000000000000000000000000000000067d22000426122ac565b8111612417576009549061ffff8260701c169081811115612405575061224f916001600160701b03915f52600a6020521660405f205461215d565b9150505f52600a60205260405f205490565b505f90565b60018060a01b03165f526002602052600260405f2001548042105f1461224f57504290565b1561244857565b60405162461bcd60e51b81526020600482015260126024820152710850d85b1b195c93dc91195b1959d85d195960721b6044820152606490fd5b906001600160701b03809116911601906001600160701b03821161216a57565b60018060a01b03165f5260076020526001600160701b0361250160405f20604051906124cd826120ef565b5483811691828152606060ff868460701c169384602085015261ffff8160e01c16604085015260f01c161515910152612482565b1690565b60405190600154808352826020810160015f5260205f20925f5b8181106125365750506125349250038361213b565b565b84546001600160a01b031683526001948501948794506020909301920161251f565b80518210156120db5760209160051b010190565b6001600160a01b03908116907f000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f726168114612612576125a8612505565b5f5b81518110156125db57826001600160a01b036125c68385612558565b5116146125d5576001016125aa565b50505050565b5061253492917f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b0316915061302e565b6040516370a0823160e01b8152306004820152909150602081602481855afa8015611dc5575f90612689575b61264c9150600d54906122ac565b80612655575050565b612534917f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b03169061302e565b506020813d6020116126b5575b816126a36020938361213b565b81010312610fd35761264c905161263e565b3d9150612696565b60018060a01b03165f52600c602052602060405f20604051906126df8261211f565b54906001600160681b0382169182825260681c9283910152600b541515908161270b575b506124175790565b905042105f612703565b1561271c57565b60405162461bcd60e51b81526020600482015260146024820152731c195c9b58481cdd185ad95c881858d8dbdd5b9d60621b6044820152606490fd5b600d549081156127ea576127b660018060a01b038216805f5260026020526127a061278a600560405f2001549461241c565b825f526002602052600460405f200154906122ac565b905f526002602052600360405f200154906122b9565b670de0b6b3a7640000810290808204670de0b6b3a7640000149015171561216a5761224f926127e4916122cc565b9061215d565b6001600160a01b03165f90815260026020526040902060050154919050565b67ffffffffffffffff811161210b5760051b60200190565b9061282a612288565b506001600160a01b039091165f818152600760205260408082209051939290612852856120ef565b546001600160701b03811685526001600160701b038160701c16602086015260ff61ffff8260e01c169182604088015260f01c1615156060860152849281958286146129e25750818511156129d3576001600160701b03602085015116916001600160701b038551168315612945575050506128e490825f52600860205260405f20865f5260205260405f205461215d565b935b83811061292557505060600151151561ffff60405192612905846120ef565b6001600160701b03851684525f6020850152166040830152606082015291565b600101815f52600860205260405f20815f526020528460405f20556128e6565b9091979692509492939461298a575b50505f91825260076020526040909120805461ffff60e01b191660e083901b61ffff60e01b1617905561ffff1660408201529190565b909550825f52600860205260405f20905f5260205260405f2054945b8181106129b35780612954565b600101825f52600860205260405f20815f526020528560405f20556129a6565b63252fc9b360e21b5f5260045ffd5b96955050925090505f52600860205260405f20905f5260205260405f205490565b9290926001545f5b818110612cc857505083158015612cb8575b612ca957836001600160701b0384511610612c9a57612a3b82612f7f565b506001600160701b0384166001600160701b0384511603906001600160701b03821161216a576001600160701b0391821684526001600160a01b03165f818152600760209081526040918290208651815492880151938801516001600160f01b031990931695169490941760709290921b600160701b600160e01b03169190911760e09190911b61ffff60e01b1617825592612af291906060905b0151815460ff60f01b191690151560f01b60ff60f01b16179055565b805f52600a60205260405f20612b098482546122ac565b9055815f52600860205260405f20905f5260205260405f20612b2c8382546122ac565b9055612b3a82600d546122ac565b600d55805f52600c60205260405f2060405190612b568261211f565b54906001600160681b0382168152602081019160681c82526001600160681b03612bac612ba6600b547f0000000000000000000000000000000000000000000000000000000000093a80906122b9565b4261215d565b1681526001600160981b0384166001600160981b0383511601906001600160981b03821161216a577fa345023a4eda421d4dbe108023f197e12ac173da60a22f9c5a82765eff7f4bf9926001600160981b03604093168152845f52600c6020526001600160681b03835f209251169051916001600160681b03198360681b16821790556001600160981b038351921682526020820152a261224f816001600160a01b037f0000000000000000000000009b44e63fc1a252861bf6d4150b58f2de84b5c1358116907f000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f7261661302e565b63ae9bbc7360e01b5f5260045ffd5b63162908e360e11b5f5260045ffd5b506001600160701b038411612a1d565b80612cd46001926120c3565b838060a01b0391549060031b1c16612ceb81612758565b90805f52600260205281600560405f200155612d068161241c565b815f526002602052600460405f200155838060a01b03861680612d2d575b50505001612a0b565b612d3782886122ea565b815f52600360205260405f20868060a01b0384165f5260205260405f20555f52600460205260405f2090848060a01b03165f5260205260405f20555f8080612d24565b6001600160a01b03165f818152600c6020526040902054606881901c92908315612e87576001600160681b0316421080612e7c575b612e6d575f828152600c60205260408120557f0000000000000000000000009b44e63fc1a252861bf6d4150b58f2de84b5c1356001600160a01b0316803b15610fd35760405163f3fef3a360e01b81526001600160a01b03929092166004830152602482018490525f908290604490829084905af18015611dc557612e5d575b507f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f756020604051848152a290565b5f612e679161213b565b5f612e2f565b637475d84d60e11b5f5260045ffd5b50600b541515612daf565b505050505f90565b6001546001600160a01b038083165f8181526005602052604090205492939092909116908115612f775750905b5f5b838110612ecb5750505050565b80612ed76001926120c3565b838060a01b0391549060031b1c16835f52600360205260405f20838060a01b0382165f5260205260405f20549081612f12575b505001612ebe565b845f52600360205260405f20848060a01b0382165f526020525f6040812055612f3c82878361302e565b604051918252847fce405e67b4d6e56e438257e15f160ae28b450e6e7659bbc4c1f4e09a1ac846cb6020868060a01b03891694a45f80612f0a565b905090612ebc565b6009549061ffff8260701c1690815f52600a60205260405f205481831461300957612fb7906001600160701b0385949394169061215d565b6fffffffffffffffffffffffffffffffff19909316607083901b61ffff60701b16176009555b8161ffff821610612fed57505090565b60010161ffff165f818152600a60205260409020839055612fdd565b9250505090565b60025f541461301f5760025f55565b633ee5aeb560e01b5f5260045ffd5b60405163a9059cbb60e01b60208201526001600160a01b039290921660248301526044808301939093529181526125349161306a60648361213b565b61330d565b6001545f5b81811061321757505081158015613206575b612ca9576130b761054b7f0000000000000000000000000000000000000000000000000000000067d22000426122ac565b906131956130c58383612821565b50916130d084612f7f565b5060606001600160701b0386169160208501926001600160701b036130f88282875116612482565b1684526001600160701b0361311260095492828416612482565b6dffffffffffffffffffffffffffff199092169116176009556001600160a01b03165f8181526007602052604090819020865181549551928801516001600160f01b03199096166001600160701b03919091161760709290921b600160701b600160e01b03169190911760e09490941b61ffff60e01b1693909317835593612ad6565b6131a183600d5461215d565b600d556131d98330337f000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f7266001600160a01b03166132c9565b7f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee906020604051858152a390565b506001600160701b03821015613086565b806132236001926120c3565b838060a01b0391549060031b1c1661323a81612758565b90805f52600260205281600560405f2001556132558161241c565b815f526002602052600460405f200155838060a01b0386168061327c575b50505001613074565b61328682886122ea565b815f52600360205260405f20868060a01b0384165f5260205260405f20555f52600460205260405f2090848060a01b03165f5260205260405f20555f8080613273565b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526125349161306a60848361213b565b905f602091828151910182855af115611dc5575f513d61335c57506001600160a01b0381163b155b61333c5750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b6001141561333556fea164736f6c634300081c000a","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{},"metadata":{"bytecodeHash":"none"},"optimizer":{"enabled":true,"runs":200},"remappings":[":@axelar-network/=node_modules/@axelar-network/",":@chainlink/=node_modules/@chainlink/",":@eth-optimism/=node_modules/@eth-optimism/",":@layerzerolabs/=node_modules/@layerzerolabs/",":@mean-finance/=node_modules/@mean-finance/",":@openzeppelin/=node_modules/@openzeppelin/",":@rari-capital/=node_modules/@rari-capital/",":@uniswap/=node_modules/@uniswap/",":base64-sol/=node_modules/base64-sol/",":ds-test/=node_modules/ds-test/src/",":forge-std/=node_modules/forge-std/src/",":frax-standard-solidity/=node_modules/frax-standard-solidity/",":frax-std/=node_modules/frax-standard-solidity/src/",":hardhat-deploy/=node_modules/hardhat-deploy/",":hardhat/=node_modules/hardhat/",":solidity-bytes-utils/=node_modules/solidity-bytes-utils/",":solidity-stringutils/=lib/surl/lib/solidity-stringutils/",":surl/=lib/surl/"],"viaIR":true},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":[["0xc07e000044F95655c11fda4cD37F70A94d7e0a7d",{"internalType":"address","name":"_core","type":"address"}],["0x10101010E0C3171D894B71B3400668aF311e7D94",{"internalType":"address","name":"_registry","type":"address"}],["0x419905009e4656fdC02418C7Df35B1E61Ed5F726",{"internalType":"address","name":"_token","type":"address"}],["2",{"internalType":"uint24","name":"_cooldownEpochs","type":"uint24"}]],"compiler_version":"0.8.28+commit.7893614a","is_verified_via_verifier_alliance":true,"verified_at":"2025-08-02T14:29:50.099371Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x61014080604052346102ae576080816138be803803809161002082856102ed565b8339810103126102ae5761003381610310565b61003f60208301610310565b90606061004e60408501610310565b9301519062ffffff82168092036102ae5760015f556001600160a01b031660808190526040516378e9792560e01b8152602081600481855afa908115610265575f916102ba575b5060a052604051630afaeebf60e31b815290602090829060049082905afa908115610265575f91610284575b5060c052604051610227808201906001600160401b0382118383101761027057604091839161369783393081526001600160a01b03871660208201520301905ff0918215610265577fc7a3b172868cdcc74bbcf808a3d5a3e88aa94454cae07ab3c27fe138d3210d29936020936101005260e05281600b5560018060a01b031661012052604051908152a1604051613372908161032582396080518181816103ac015281816108e3015281816109b5015281816113780152818161184801528181611af1015281816125e3015261265b015260a051818181610526015281816111010152818161122601528181611453015281816115080152818161192501528181611c0e01528181611c6e01528181611d2a0152818161202701528181612186015281816123a50152613092015260c05181818161054d0152818161091a015281816116f80152612b81015260e051818181610a460152818161173101528181611e1f0152818161257a01528181612c7501526131ac01526101005181818161081c01528181612c510152612dc301526101205181818161140c0152611cd80152f35b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b90506020813d6020116102b2575b8161029f602093836102ed565b810103126102ae57515f6100c1565b5f80fd5b3d9150610292565b90506020813d6020116102e5575b816102d5602093836102ed565b810103126102ae57516004610095565b3d91506102c8565b601f909101601f19168101906001600160401b0382119082101761027057604052565b51906001600160a01b03821682036102ae5756fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301320fe2146120515750806306aba0e11461200a57806307f93a3814611fe35780630aed7b0d14611cab57806312cf9dad14611c385780631491496f14611bf057806318160ddd14611bd25780631930e82514611b7a5780631e9049cf14611b5c578063211dc32d14611b2f5780632378bea614611a2b5780633d18b912146119505780633ea01b34146118fe5780633f695b451461181f5780633f90916a146117f857806348e5d9f81461177f57806350735f6f1461176057806351ed6a301461171b57806357d775f8146116e0578063638634ee146116bc5780636889d9ae146115c45780636ca541e5146115a45780637035ab981461155157806370a082311461152d578063757991a8146114ed57806375a410141461147657806378e979251461143b5780637b103999146113f65780637bb7bed1146113b25780638980f11f146113555780638da5cb5b146103965780639d716bc6146113315780639e94080e146111f3578063a694fc3a146111d3578063aaf5eb68146111b0578063adc9772e14611188578063b42652e9146110ab578063b66503cf14610ddf578063bcd1101414610d92578063bf199e6214610d74578063c00007b014610c7e578063c3c854b614610bef578063c950ba7f14610bd1578063d0ed26ae14610989578063d6e5085f146108bb578063deb906e71461084b578063e2fdcc1714610806578063e509b9d9146107c5578063e70b9e2714610772578063e7805809146105bc578063e7a6bc44146104dc578063eb8f4f70146104be578063ebae46701461047c578063f122977714610458578063f21f3c08146103db578063f2f4eb2614610396578063fbeb4336146103715763ff342e091461029c575f80fd5b3461036e57602036600319011261036e576102b5612097565b6102bd612505565b9081516102c981612809565b916102d7604051938461213b565b8183526102e382612809565b602084019490601f1901368637855b83811061033d57868587604051928392602084019060208552518091526040840192915b818110610324575050500390f35b8251845285945060209384019390920191600101610316565b60019061035d6001600160a01b036103558386612558565b5116856122ea565b6103678288612558565b52016102f2565b80fd5b503461036e578060031936011261036e57602061ffff60095460701c16604051908152f35b503461036e578060031936011261036e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461036e57604036600319011261036e5761042a6020916103fb612097565b6104036120ad565b916001600160a01b03821633811491908215610432575b505061042590612441565b612d7a565b604051908152f35b815260068652604090819020335f9081529087529081205460ff1691506104259061041a565b503461036e57602036600319011261036e57602061042a610477612097565b612758565b503461036e57602036600319011261036e5760209060ff906040906001600160a01b036104a7612097565b16815260078452205460f01c166040519015158152f35b503461036e578060031936011261036e576020600b54604051908152f35b503461036e57604036600319011261036e5761042a6020916104fc612097565b906001600160a01b03821633811491908215610596575b505061051e90612441565b61057261054b7f0000000000000000000000000000000000000000000000000000000000000000426122ac565b7f0000000000000000000000000000000000000000000000000000000000000000906122cc565b9061057d8282612821565b509061058d606083015115612715565b60243590612a03565b815260068552604090819020335f9081529086529081205460ff16915061051e90610513565b503461036e57604036600319011261036e576105d6612097565b6105de6120ad565b6105e6613010565b6001546001600160a01b03831690811515855b8281106106c95750505080845260036020526040842060018060a01b0383165f5260205260405f20549283610631575b846001815580f35b8185526003602090815260408087206001600160a01b038681165f9081529184529082902088905584885260058352908720547fce405e67b4d6e56e438257e15f160ae28b450e6e7659bbc4c1f4e09a1ac846cb9391169081156106c15750935b6001600160a01b0316936106a786828761302e565b6040519586526001600160a01b031694a45f808080610629565b905093610692565b806106d56001926120c3565b838060a01b0391549060031b1c166106ec81612758565b90808a52600260205281600560408c200155846107088261241c565b828c526002602052600460408d200155610725575b5050016105f9565b61072f818a6122ea565b878b52600360205260408b20858060a01b0383165f5260205260405f2055868a52600460205260408a2090848060a01b03165f5260205260405f20555f8061071d565b503461036e57604036600319011261036e57604061078e612097565b916107976120ad565b9260018060a01b031681526003602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461036e57602036600319011261036e576020906001600160a01b036107ea612097565b16815260058252604060018060a01b0391205416604051908152f35b503461036e578060031936011261036e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461036e57602036600319011261036e576080906040906001600160a01b03610873612097565b1681526007602052205460ff604051916001600160701b03811683526001600160701b038160701c16602084015261ffff8160e01c16604084015260f01c1615156060820152f35b503461036e57602036600319011261036e5760043562ffffff811680910361098557610911337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614612369565b6276a70061093f7f0000000000000000000000000000000000000000000000000000000000000000836122b9565b11610976576020817fc7a3b172868cdcc74bbcf808a3d5a3e88aa94454cae07ab3c27fe138d3210d2992600b55604051908152a180f35b637616640160e01b8252600482fd5b5080fd5b503461036e57606036600319011261036e576109a3612097565b6109ab6120ad565b604435916109e3337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614612369565b6001600160a01b03169081158015610bc0575b610bb1578215610ba25781845260026020526001604085200154610b935760405163313ce56760e01b8152602081600481865afa908115610b88578591610b47575b5060ff6012911603610b38577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168214610b295760015468010000000000000000811015610b15577f8ab68562a70a02d12b0bbb803d106d670bb6660d060e8cc535baee4fcb04598b91610abc826001602094016001556120c3565b81546001600160a01b0360039290921b82811b199091169087901b179091558487526002808452604080892080546001600160a01b0319169490931693841790925585885283528087206001018690555194855293a380f35b634e487b7160e01b85526041600452602485fd5b633f7bbeb960e21b8452600484fd5b63568fc68760e11b8452600484fd5b90506020813d602011610b80575b81610b626020938361213b565b81010312610b7c575160ff81168103610b7c5760ff610a38565b8480fd5b3d9150610b55565b6040513d87823e3d90fd5b6311ae984360e21b8452600484fd5b633019509960e21b8452600484fd5b63d92e233d60e01b8452600484fd5b506001600160a01b038116156109f6565b503461036e57602036600319011261036e57610beb612097565b5080f35b503461036e57604036600319011261036e57610c09612097565b60243590811515809203610c7a5733835260066020526040832060018060a01b0382165f5260205260405f2060ff1981541660ff841617905560405191825260018060a01b0316907f92d241afb0a1a9b3441bf1bd6bea0f9164cf5a2562cbe4bcc34ab943b246560860203392a380f35b8280fd5b503461036e57602036600319011261036e57610c98612097565b610ca0613010565b6001546001600160a01b03821680151590845b838110610ccb5785610cc486612e8f565b6001815580f35b80610cd76001926120c3565b838060a01b0391549060031b1c16610cee81612758565b90808952600260205281600560408b20015585610d0a8261241c565b828b526002602052600460408c200155610d27575b505001610cb3565b610d3181896122ea565b858a52600360205260408a20858060a01b0383165f5260205260405f205584895260046020526040892090848060a01b03165f5260205260405f20555f80610d1f565b503461036e578060031936011261036e576020600154604051908152f35b503461036e57602036600319011261036e5760209061042a90600160406001600160a01b03610dbf612097565b1692838152600286526003828220015493815260028652200154906122b9565b503461036e57604036600319011261036e57610df9612097565b60243590600154835b8181106110595750506001600160a01b03168083526002602052604080842090519192919060c0820167ffffffffffffffff8111838210176110455760405260018060a01b03815416908183526001810154602084019081526002820154604085019081526003830154916060860192835260056004850154946080880195865201549460a08701958652330361103757861561102857600d541561101957610ead8730338b6132c9565b8151428111610fea5750610ec28151886122cc565b6040516370a0823160e01b81523060048201526020816024818d5afa8015610fdf578b90610fa7575b610ef891508351906122cc565b8111610f9857927fac24935fd910bc682b5ccb1a07b718cadf8cf2f6d1404c4f3ddc3662dae40e2997959260209795926005958352428452610f3b81514261215d565b82528a8c526002895260408c209660018060a01b039060018060a01b03905116166bffffffffffffffffffffffff60a01b88541617875551600187015551600286015551600385015551600484015551910155604051908152a280f35b63474c247160e01b8a5260048afd5b506020813d602011610fd7575b81610fc16020938361213b565b81010312610fd357610ef89051610eeb565b5f80fd5b3d9150610fb4565b6040513d8d823e3d90fd5b61100c611006610ffe6110149342906122ac565b8651906122b9565b8961215d565b8251906122cc565b610ec2565b6347fc732760e11b8952600489fd5b633019509960e21b8952600489fd5b6282b42960e81b8952600489fd5b634e487b7160e01b86526041600452602486fd5b806110656001926120c3565b838060a01b0391549060031b1c1661107c81612758565b818852600260205260056040892001556110958161241c565b9087526002602052600460408820015501610e02565b503461036e57602036600319011261036e5760209060016001600160701b036110d2612097565b6110da613010565b828060a01b0381168033148015611161575b6110f69150612441565b61115561112661054b7f0000000000000000000000000000000000000000000000000000000000000000426122ac565b9161114f6111348483612821565b5093611144606086015115612715565b848681511684612a03565b50612e8f565b51169155604051908152f35b5084526006855260408420838060a01b0333165f5285526110f660ff60405f2054166110ec565b503461036e57604036600319011261036e57602061042a6111a7612097565b6024359061306f565b503461036e578060031936011261036e576020604051670de0b6b3a76400008152f35b503461036e57602036600319011261036e57602061042a6004353361306f565b503461036e57602036600319011261036e5761120d612097565b611215612288565b506112da604061125161124b61054b7f0000000000000000000000000000000000000000000000000000000000000000426122ac565b84612821565b6001600160a01b0390941685526007602090815291909420845181549286015160408701516001600160f01b03199094166001600160701b03929092169190911760709190911b600160701b600160e01b03161760e09290921b61ffff60e01b169190911781559192916060830151815460ff60f01b191690151560f01b60ff60f01b16179055565b61132d6040519283928360809093929193606060a08201956001600160701b0381511683526001600160701b03602082015116602084015261ffff60408201511660408401520151151560608201520152565b0390f35b503461036e57602036600319011261036e57602061042a611350612097565b6126bd565b503461036e57604036600319011261036e576113af611372612097565b6113a6337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614612369565b6024359061256c565b80f35b503461036e57602036600319011261036e576004359060015482101561036e5760206113dd836120c3565b905460405160039290921b1c6001600160a01b03168152f35b503461036e578060031936011261036e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461036e578060031936011261036e5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461036e57602036600319011261036e57611490612097565b611498613010565b3380835260056020526040832080546001600160a01b0319166001600160a01b039390931692831790557ff4239ad0860f93469699dd4be8040b8838c5e25bb6cf24a1dfb381b937ff078c8380a36001815580f35b503461036e578060031936011261036e57602061042a61054b7f0000000000000000000000000000000000000000000000000000000000000000426122ac565b503461036e57602036600319011261036e57602061042a61154c612097565b6124a2565b503461036e57604036600319011261036e57604061156d612097565b916115766120ad565b9260018060a01b031681526004602052209060018060a01b03165f52602052602060405f2054604051908152f35b503461036e578060031936011261036e576020600b541515604051908152f35b503461036e57602036600319011261036e576001600160a01b036115e6612097565b16803314801561169a575b6115fa90612441565b808252600760205260ff604083205460f01c1661165557808252600760205260408220805460ff60f01b1916600160f01b1790557fd9a2231c15b3bfce8e444b3bcc1a7e724c5368ab52f965679e17bac8abbf101a8280a280f35b60405162461bcd60e51b815260206004820152601c60248201527f616c7265616479207065726d61207374616b6572206163636f756e74000000006044820152606490fd5b50808252600660209081526040808420335f908152925290205460ff166115f1565b503461036e57602036600319011261036e57602061042a6116db612097565b61241c565b503461036e578060031936011261036e5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461036e578060031936011261036e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461036e57602036600319011261036e57602061042a60043561239d565b503461036e57602036600319011261036e5760c0906040906001600160a01b036117a7612097565b16815260026020522060018060a01b038154169060018101549060028101546003820154906005600484015493015493604051958652602086015260408501526060840152608083015260a0820152f35b503461036e578060031936011261036e5760206001600160701b0360095416604051908152f35b503461036e57604036600319011261036e57611839612097565b6118416120ad565b90611876337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614612369565b6001600160a01b031690811580156118ed575b6118de5781835260026020526040832080546001600160a01b0319166001600160a01b03929092169182179055907f8a6fe46a7bcc5ff8e08e5e4d7bf80b812df26f8f800f7a815ccfea20e852b0ec8380a380f35b63d92e233d60e01b8352600483fd5b506001600160a01b03811615611889565b503461036e57602036600319011261036e57602061042a61191d612097565b61194a61054b7f0000000000000000000000000000000000000000000000000000000000000000426122ac565b9061217e565b503461036e578060031936011261036e57611969613010565b600154331515825b8281106119825783610cc433612e8f565b8061198e6001926120c3565b838060a01b0391549060031b1c166119a581612758565b908087526002602052816005604089200155846119c18261241c565b8289526002602052600460408a2001556119de575b505001611971565b6119e881336122ea565b338852600360205260408820858060a01b0383165f5260205260405f205533875260046020526040872090848060a01b03165f5260205260405f20555f806119d6565b503461036e57604036600319011261036e57611a45612097565b6001600160a01b03168082526002602081905260408320015460243590421115611b2057818352600260205260408320546001600160a01b031633141580611aed575b611adf578015611ad05760207fad2f86b01ed93b4b3a150d448c61a4f5d8d38075d3c0c64cc0a26fd6e1f495459183855260028252806001604087200155604051908152a280f35b633019509960e21b8352600483fd5b6282b42960e81b8352600483fd5b50337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161415611a88565b633f1609d560e21b8352600483fd5b503461036e57604036600319011261036e57602061042a611b4e612097565b611b566120ad565b906122ea565b503461036e578060031936011261036e5760206040516276a7008152f35b503461036e57604036600319011261036e576040611b96612097565b91611b9f6120ad565b9260018060a01b031681526006602052209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b503461036e578060031936011261036e576020600d54604051908152f35b503461036e578060031936011261036e57602061042a611c3361054b7f0000000000000000000000000000000000000000000000000000000000000000426122ac565b612f7f565b503461036e57604036600319011261036e57611c52612097565b6112da6040611251602435611c65612288565b50611c9361054b7f0000000000000000000000000000000000000000000000000000000000000000426122ac565b80821015611ca3575b5084612821565b90505f611c9c565b34610fd3575f366003190112610fd3575f600b54611fa857604051635ebaf1db60e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115611dc5575f91611f66575b506001600160a01b031690308214611f3657611d4f61054b7f0000000000000000000000000000000000000000000000000000000000000000426122ac565b611d598133612821565b50606081015115611ef1576001600160701b0381511680611dd0575b505050813b15610fd3575f809260246040518095819363c950ba7f60e01b83523360048401525af1918215611dc557602092611db5575b50604051908152f35b5f611dbf9161213b565b5f611dac565b6040513d5f823e3d90fd5b611ddb935033612a03565b50611de63033612d7a565b611def33612e8f565b60405163095ea7b360e01b81526001600160a01b038316600482015260248101829052602081806044810103815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015611dc557611eba575b506040516356e4bb9760e11b8152336004820152602481018290526020816044815f875af18015611dc557611e8b575b8080611d75565b611eac9060203d602011611eb3575b611ea4818361213b565b810190612279565b5082611e84565b503d611e9a565b6020813d602011611ee9575b81611ed36020938361213b565b81010312610fd357518015158114611e54575f80fd5b3d9150611ec6565b60405162461bcd60e51b815260206004820152601860248201527f6e6f74207065726d61207374616b6572206163636f756e7400000000000000006044820152606490fd5b60405162461bcd60e51b8152602060048201526008602482015267216d69677261746560c01b6044820152606490fd5b90506020813d602011611fa0575b81611f816020938361213b565b81010312610fd357516001600160a01b0381168103610fd35782611d10565b3d9150611f74565b60405162461bcd60e51b81526020600482015260136024820152720636f6f6c646f776e45706f63687320213d203606c1b6044820152606490fd5b34610fd3576040366003190112610fd357602061042a612001612097565b6024359061217e565b34610fd3575f366003190112610fd357602061042a61204c61054b7f0000000000000000000000000000000000000000000000000000000000000000426122ac565b61239d565b34610fd3576020366003190112610fd3576040906001600160a01b03612075612097565b165f52600c602052815f20546001600160681b038116825260681c6020820152f35b600435906001600160a01b0382168203610fd357565b602435906001600160a01b0382168203610fd357565b6001548110156120db5760015f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b6080810190811067ffffffffffffffff82111761210b57604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761210b57604052565b90601f8019910116810190811067ffffffffffffffff82111761210b57604052565b9190820180921161216a57565b634e487b7160e01b5f52601160045260245ffd5b6121ab61054b7f0000000000000000000000000000000000000000000000000000000000000000426122ac565b8211612273576001600160a01b03165f818152600760205260409081902090519291906121d7846120ef565b54916001600160701b038316845260208401936001600160701b038460701c168552606060ff61ffff8660e01c169586604085015260f01c1615159101528083101561225657505f52600860205260405f20905f526020526001600160701b0360405f20549151168015612252579061224f9161215d565b90565b5090565b925090505f52600860205260405f20905f5260205260405f205490565b50505f90565b90816020910312610fd3575190565b60405190612295826120ef565b5f6060838281528260208201528260408201520152565b9190820391821161216a57565b8181029291811591840414171561216a57565b81156122d6570490565b634e487b7160e01b5f52601260045260245ffd5b61224f91670de0b6b3a7640000612343612303846124a2565b61233d61230f85612758565b6001600160a01b039687165f8181526004602090815260408083209a8a1683529990529790972054906122ac565b906122b9565b04915f52600360205260405f209060018060a01b03165f5260205260405f20549061215d565b1561237057565b60405162461bcd60e51b815260206004820152600560248201526421636f726560d81b6044820152606490fd5b6123ca61054b7f0000000000000000000000000000000000000000000000000000000000000000426122ac565b8111612417576009549061ffff8260701c169081811115612405575061224f916001600160701b03915f52600a6020521660405f205461215d565b9150505f52600a60205260405f205490565b505f90565b60018060a01b03165f526002602052600260405f2001548042105f1461224f57504290565b1561244857565b60405162461bcd60e51b81526020600482015260126024820152710850d85b1b195c93dc91195b1959d85d195960721b6044820152606490fd5b906001600160701b03809116911601906001600160701b03821161216a57565b60018060a01b03165f5260076020526001600160701b0361250160405f20604051906124cd826120ef565b5483811691828152606060ff868460701c169384602085015261ffff8160e01c16604085015260f01c161515910152612482565b1690565b60405190600154808352826020810160015f5260205f20925f5b8181106125365750506125349250038361213b565b565b84546001600160a01b031683526001948501948794506020909301920161251f565b80518210156120db5760209160051b010190565b6001600160a01b03908116907f0000000000000000000000000000000000000000000000000000000000000000168114612612576125a8612505565b5f5b81518110156125db57826001600160a01b036125c68385612558565b5116146125d5576001016125aa565b50505050565b5061253492917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316915061302e565b6040516370a0823160e01b8152306004820152909150602081602481855afa8015611dc5575f90612689575b61264c9150600d54906122ac565b80612655575050565b612534917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169061302e565b506020813d6020116126b5575b816126a36020938361213b565b81010312610fd35761264c905161263e565b3d9150612696565b60018060a01b03165f52600c602052602060405f20604051906126df8261211f565b54906001600160681b0382169182825260681c9283910152600b541515908161270b575b506124175790565b905042105f612703565b1561271c57565b60405162461bcd60e51b81526020600482015260146024820152731c195c9b58481cdd185ad95c881858d8dbdd5b9d60621b6044820152606490fd5b600d549081156127ea576127b660018060a01b038216805f5260026020526127a061278a600560405f2001549461241c565b825f526002602052600460405f200154906122ac565b905f526002602052600360405f200154906122b9565b670de0b6b3a7640000810290808204670de0b6b3a7640000149015171561216a5761224f926127e4916122cc565b9061215d565b6001600160a01b03165f90815260026020526040902060050154919050565b67ffffffffffffffff811161210b5760051b60200190565b9061282a612288565b506001600160a01b039091165f818152600760205260408082209051939290612852856120ef565b546001600160701b03811685526001600160701b038160701c16602086015260ff61ffff8260e01c169182604088015260f01c1615156060860152849281958286146129e25750818511156129d3576001600160701b03602085015116916001600160701b038551168315612945575050506128e490825f52600860205260405f20865f5260205260405f205461215d565b935b83811061292557505060600151151561ffff60405192612905846120ef565b6001600160701b03851684525f6020850152166040830152606082015291565b600101815f52600860205260405f20815f526020528460405f20556128e6565b9091979692509492939461298a575b50505f91825260076020526040909120805461ffff60e01b191660e083901b61ffff60e01b1617905561ffff1660408201529190565b909550825f52600860205260405f20905f5260205260405f2054945b8181106129b35780612954565b600101825f52600860205260405f20815f526020528560405f20556129a6565b63252fc9b360e21b5f5260045ffd5b96955050925090505f52600860205260405f20905f5260205260405f205490565b9290926001545f5b818110612cc857505083158015612cb8575b612ca957836001600160701b0384511610612c9a57612a3b82612f7f565b506001600160701b0384166001600160701b0384511603906001600160701b03821161216a576001600160701b0391821684526001600160a01b03165f818152600760209081526040918290208651815492880151938801516001600160f01b031990931695169490941760709290921b600160701b600160e01b03169190911760e09190911b61ffff60e01b1617825592612af291906060905b0151815460ff60f01b191690151560f01b60ff60f01b16179055565b805f52600a60205260405f20612b098482546122ac565b9055815f52600860205260405f20905f5260205260405f20612b2c8382546122ac565b9055612b3a82600d546122ac565b600d55805f52600c60205260405f2060405190612b568261211f565b54906001600160681b0382168152602081019160681c82526001600160681b03612bac612ba6600b547f0000000000000000000000000000000000000000000000000000000000000000906122b9565b4261215d565b1681526001600160981b0384166001600160981b0383511601906001600160981b03821161216a577fa345023a4eda421d4dbe108023f197e12ac173da60a22f9c5a82765eff7f4bf9926001600160981b03604093168152845f52600c6020526001600160681b03835f209251169051916001600160681b03198360681b16821790556001600160981b038351921682526020820152a261224f816001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116907f00000000000000000000000000000000000000000000000000000000000000001661302e565b63ae9bbc7360e01b5f5260045ffd5b63162908e360e11b5f5260045ffd5b506001600160701b038411612a1d565b80612cd46001926120c3565b838060a01b0391549060031b1c16612ceb81612758565b90805f52600260205281600560405f200155612d068161241c565b815f526002602052600460405f200155838060a01b03861680612d2d575b50505001612a0b565b612d3782886122ea565b815f52600360205260405f20868060a01b0384165f5260205260405f20555f52600460205260405f2090848060a01b03165f5260205260405f20555f8080612d24565b6001600160a01b03165f818152600c6020526040902054606881901c92908315612e87576001600160681b0316421080612e7c575b612e6d575f828152600c60205260408120557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610fd35760405163f3fef3a360e01b81526001600160a01b03929092166004830152602482018490525f908290604490829084905af18015611dc557612e5d575b507f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f756020604051848152a290565b5f612e679161213b565b5f612e2f565b637475d84d60e11b5f5260045ffd5b50600b541515612daf565b505050505f90565b6001546001600160a01b038083165f8181526005602052604090205492939092909116908115612f775750905b5f5b838110612ecb5750505050565b80612ed76001926120c3565b838060a01b0391549060031b1c16835f52600360205260405f20838060a01b0382165f5260205260405f20549081612f12575b505001612ebe565b845f52600360205260405f20848060a01b0382165f526020525f6040812055612f3c82878361302e565b604051918252847fce405e67b4d6e56e438257e15f160ae28b450e6e7659bbc4c1f4e09a1ac846cb6020868060a01b03891694a45f80612f0a565b905090612ebc565b6009549061ffff8260701c1690815f52600a60205260405f205481831461300957612fb7906001600160701b0385949394169061215d565b6fffffffffffffffffffffffffffffffff19909316607083901b61ffff60701b16176009555b8161ffff821610612fed57505090565b60010161ffff165f818152600a60205260409020839055612fdd565b9250505090565b60025f541461301f5760025f55565b633ee5aeb560e01b5f5260045ffd5b60405163a9059cbb60e01b60208201526001600160a01b039290921660248301526044808301939093529181526125349161306a60648361213b565b61330d565b6001545f5b81811061321757505081158015613206575b612ca9576130b761054b7f0000000000000000000000000000000000000000000000000000000000000000426122ac565b906131956130c58383612821565b50916130d084612f7f565b5060606001600160701b0386169160208501926001600160701b036130f88282875116612482565b1684526001600160701b0361311260095492828416612482565b6dffffffffffffffffffffffffffff199092169116176009556001600160a01b03165f8181526007602052604090819020865181549551928801516001600160f01b03199096166001600160701b03919091161760709290921b600160701b600160e01b03169190911760e09490941b61ffff60e01b1693909317835593612ad6565b6131a183600d5461215d565b600d556131d98330337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166132c9565b7f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee906020604051858152a390565b506001600160701b03821015613086565b806132236001926120c3565b838060a01b0391549060031b1c1661323a81612758565b90805f52600260205281600560405f2001556132558161241c565b815f526002602052600460405f200155838060a01b0386168061327c575b50505001613074565b61328682886122ea565b815f52600360205260405f20868060a01b0384165f5260205260405f20555f52600460205260405f2090848060a01b03165f5260205260405f20555f8080613273565b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526125349161306a60848361213b565b905f602091828151910182855af115611dc5575f513d61335c57506001600160a01b0381163b155b61333c5750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b6001141561333556fea164736f6c634300081c000a60c034607c57601f61022738819003918201601f19168301916001600160401b038311848410176080578084926040948552833981010312607c57604b60206045836094565b92016094565b6080919091526001600160a01b031660a05260405161017f90816100a8823960805181604e015260a0518160a30152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203607c5756fe6080806040526004361015610012575f80fd5b5f3560e01c63f3fef3a314610025575f80fd5b3461011c57604036600319011261011c576004356001600160a01b038116919082900361011c577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303610146575060405163a9059cbb60e01b8152600481019190915260248035908201526020816044815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1801561013b576100d957005b60203d602011610134575b601f8101601f1916820167ffffffffffffffff8111838210176101205760209183916040528101031261011c57518015150361011c57005b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b503d6100e4565b6040513d5f823e3d90fd5b62461bcd60e51b815260206004820152600760248201526610a9ba30b5b2b960c91b6044820152606490fdfea164736f6c634300081c000a000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d00000000000000000000000010101010e0c3171d894b71b3400668af311e7d94000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f7260000000000000000000000000000000000000000000000000000000000000002","name":"GovStaker","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"cancun","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"node_modules/@openzeppelin/contracts/interfaces/IERC1363.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n    /*\n     * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n     * 0xb0202a11 ===\n     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n     */\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @param data Additional data with no specified format, sent in call to `spender`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/interfaces/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},{"file_path":"node_modules/@openzeppelin/contracts/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},{"file_path":"node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\nimport {Address} from \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    /**\n     * @dev An operation with an ERC-20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     *\n     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n     * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n     * set here.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            safeTransfer(token, to, value);\n        } else if (!token.transferAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferFromAndCallRelaxed(\n        IERC1363 token,\n        address from,\n        address to,\n        uint256 value,\n        bytes memory data\n    ) internal {\n        if (to.code.length == 0) {\n            safeTransferFrom(token, from, to, value);\n        } else if (!token.transferFromAndCall(from, to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n     * once without retrying, and relies on the returned value to be true.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            forceApprove(token, to, value);\n        } else if (!token.approveAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            // bubble errors\n            if iszero(success) {\n                let ptr := mload(0x40)\n                returndatacopy(ptr, 0, returndatasize())\n                revert(ptr, returndatasize())\n            }\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n\n        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        bool success;\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n    }\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/utils/Address.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol)\n\npragma solidity ^0.8.20;\n\nimport {Errors} from \"./Errors.sol\";\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev There's no code at `target` (it is not a contract).\n     */\n    error AddressEmptyCode(address target);\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        if (address(this).balance < amount) {\n            revert Errors.InsufficientBalance(address(this).balance, amount);\n        }\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        if (!success) {\n            revert Errors.FailedCall();\n        }\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason or custom error, it is bubbled\n     * up by this function (like regular Solidity function calls). However, if\n     * the call reverted with no returned reason, this function reverts with a\n     * {Errors.FailedCall} error.\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        if (address(this).balance < value) {\n            revert Errors.InsufficientBalance(address(this).balance, value);\n        }\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n     * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case\n     * of an unsuccessful call.\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata\n    ) internal view returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            // only check if target is a contract if the call was successful and the return data is empty\n            // otherwise we already know that it was a contract\n            if (returndata.length == 0 && target.code.length == 0) {\n                revert AddressEmptyCode(target);\n            }\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n     * revert reason or with a default {Errors.FailedCall} error.\n     */\n    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.\n     */\n    function _revert(bytes memory returndata) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            assembly (\"memory-safe\") {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert Errors.FailedCall();\n        }\n    }\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/utils/Errors.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Collection of common custom errors used in multiple contracts\n *\n * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.\n * It is recommended to avoid relying on the error API for critical functionality.\n *\n * _Available since v5.1._\n */\nlibrary Errors {\n    /**\n     * @dev The ETH balance of the account is not enough to perform the operation.\n     */\n    error InsufficientBalance(uint256 balance, uint256 needed);\n\n    /**\n     * @dev A call to an address target failed. The target may have reverted.\n     */\n    error FailedCall();\n\n    /**\n     * @dev The deployment failed.\n     */\n    error FailedDeployment();\n\n    /**\n     * @dev A necessary precompile is missing.\n     */\n    error MissingPrecompile(address);\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/utils/ReentrancyGuard.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,\n * consider using {ReentrancyGuardTransient} instead.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant NOT_ENTERED = 1;\n    uint256 private constant ENTERED = 2;\n\n    uint256 private _status;\n\n    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\n\n    constructor() {\n        _status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be NOT_ENTERED\n        if (_status == ENTERED) {\n            revert ReentrancyGuardReentrantCall();\n        }\n\n        // Any calls to nonReentrant after this point will fail\n        _status = ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == ENTERED;\n    }\n}\n"},{"file_path":"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"src/dao/staking/GovStakerEscrow.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport '@openzeppelin/contracts/token/ERC20/IERC20.sol';\n\ncontract GovStakerEscrow {\n    address immutable staker;\n    IERC20 immutable token;\n\n    constructor(address _staker, address _token) {\n        staker = _staker;\n        token = IERC20(_token);\n    }\n\n    modifier onlyStaker() {\n        require(msg.sender == staker, \"!Staker\");\n        _;\n    }\n\n    function withdraw(address to, uint256 amount) external onlyStaker {\n        token.transfer(to, amount);\n    }\n}"},{"file_path":"src/dao/staking/MultiRewardsDistributor.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport { IERC20, SafeERC20 } from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport { ReentrancyGuard } from '@openzeppelin/contracts/utils/ReentrancyGuard.sol';\nimport { CoreOwnable } from '../../dependencies/CoreOwnable.sol';\nimport { IERC20Decimals } from '../../interfaces/IERC20Decimals.sol';\n\nabstract contract MultiRewardsDistributor is ReentrancyGuard, CoreOwnable {\n    using SafeERC20 for IERC20;\n\n    address[] public rewardTokens;\n    mapping(address => Reward) public rewardData;\n    mapping(address => mapping(address => uint256)) public rewards;\n    mapping(address => mapping(address => uint256)) public userRewardPerTokenPaid;\n    mapping(address => address) public rewardRedirect;\n\n    uint256 public constant PRECISION = 1e18;\n\n    function stakeToken() public view virtual returns (address);\n    function balanceOf(address account) public view virtual returns (uint256);\n    function totalSupply() public view virtual returns (uint256);\n\n    struct Reward {\n        address rewardsDistributor; // address with permission to update reward amount.\n        uint256 rewardsDuration;\n        uint256 periodFinish;\n        uint256 rewardRate;\n        uint256 lastUpdateTime;\n        uint256 rewardPerTokenStored;\n    }\n\n    // Add these error declarations at the contract level, after the state variables\n    error ZeroAddress();\n    error MustBeGreaterThanZero();\n    error RewardAlreadyAdded();\n    error Unauthorized();\n    error SupplyMustBeGreaterThanZero();\n    error RewardTooHigh();\n    error RewardsStillActive();\n    error DecimalsMustBe18();\n    error CannotAddStakeToken();\n    \n    /* ========== EVENTS ========== */\n\n    event RewardAdded(address indexed rewardToken, uint256 amount);\n    event RewardTokenAdded(address indexed rewardsToken, address indexed rewardsDistributor, uint256 rewardsDuration);\n    event RewardsDurationUpdated(address indexed rewardsToken, uint256 duration);\n    event RewardPaid(address indexed user, address indexed rewardToken, address indexed recipient, uint256 reward);\n    event RewardsDistributorSet(address indexed rewardsToken, address indexed rewardsDistributor);\n    event RewardRedirected(address indexed user, address indexed redirect);\n\n    /* ========== MODIFIERS ========== */\n\n    modifier updateReward(address _account) {\n        uint256 length = rewardTokens.length;\n        for (uint256 i; i < length; ++i) {\n            address token = rewardTokens[i];\n            uint256 rewardPerToken = rewardPerToken(token);\n            rewardData[token].rewardPerTokenStored = rewardPerToken;\n            rewardData[token].lastUpdateTime = lastTimeRewardApplicable(token);\n            if (_account != address(0)) {\n                rewards[_account][token] = earned(_account, token);\n                userRewardPerTokenPaid[_account][token] = rewardPerToken;\n            }\n        }\n        _;\n    }\n\n    /* ========== CONSTRUCTOR ========== */\n\n    constructor(address _core) CoreOwnable(_core) {}\n\n    /* ========== EXTERNAL STATE CHANGE FUNCTIONS ========== */\n\n    /**\n     * @notice Claim any (and all) earned reward tokens.\n     * @dev Can claim rewards even if no tokens still staked.\n     * @param _account Address of the account to claim rewards for.\n     */\n    function getReward(address _account) external nonReentrant updateReward(_account) {\n        _getRewardFor(_account);\n    }\n\n    /**\n     * @notice Claim any (and all) earned reward tokens for the caller.\n     * @dev Can claim rewards even if no tokens still staked.\n     */\n    function getReward() external nonReentrant updateReward(msg.sender) {\n        _getRewardFor(msg.sender);\n    }\n\n    /**\n     * @notice Claim any one earned reward token.\n     * @dev Can claim rewards even if no tokens still staked.\n     * @param _account Address of the account to claim rewards for.\n     * @param _rewardsToken Address of the rewards token to claim.\n     */\n    function getOneReward(address _account, address _rewardsToken) external nonReentrant updateReward(_account) {\n        uint256 reward = rewards[_account][_rewardsToken];\n        if (reward > 0) {\n            rewards[_account][_rewardsToken] = 0;\n            address _recipient = rewardRedirect[_account];\n            _recipient = _recipient != address(0) ? _recipient : _account;\n            IERC20(_rewardsToken).safeTransfer(_recipient, reward);\n            emit RewardPaid(_account, _rewardsToken, _recipient, reward);\n        }\n    }\n\n    /* ========== EXTERNAL RESTRICTED FUNCTIONS ========== */\n\n    /**\n     * @notice Add a new reward token to the staking contract.\n     * @dev May only be called by owner, and can't be set to zero address. Add reward tokens sparingly, as each new one\n     *  will increase gas costs. This must be set before notifyRewardAmount can be used.\n     * @param _rewardsToken Address of the rewards token.\n     * @param _rewardsDistributor Address of the rewards distributor.\n     * @param _rewardsDuration The duration of our rewards distribution for staking in seconds.\n     * @dev To avoid precision loss, reward tokens must have 18 decimals.\n     */\n    function addReward(\n        address _rewardsToken,\n        address _rewardsDistributor,\n        uint256 _rewardsDuration\n    ) external onlyOwner {\n        if (_rewardsToken == address(0) || _rewardsDistributor == address(0)) revert ZeroAddress();\n        if (_rewardsDuration == 0) revert MustBeGreaterThanZero();\n        if (rewardData[_rewardsToken].rewardsDuration != 0) revert RewardAlreadyAdded();\n        if (IERC20Decimals(_rewardsToken).decimals() != 18) revert DecimalsMustBe18();\n        if (_rewardsToken == stakeToken()) revert CannotAddStakeToken();\n\n        rewardTokens.push(_rewardsToken);\n        rewardData[_rewardsToken].rewardsDistributor = _rewardsDistributor;\n        rewardData[_rewardsToken].rewardsDuration = _rewardsDuration;\n\n        emit RewardTokenAdded(_rewardsToken, _rewardsDistributor, _rewardsDuration);\n    }\n\n    /**\n     * @notice Notify staking contract that it has more reward to account for.\n     * @dev May only be called by rewards distribution role. Set up token first via addReward().\n     * @param _rewardsToken Address of the rewards token.\n     * @param _rewardAmount Amount of reward tokens to add.\n     */\n    function notifyRewardAmount(address _rewardsToken, uint256 _rewardAmount) external updateReward(address(0)) {\n        Reward memory _rewardData = rewardData[_rewardsToken];\n        if (_rewardData.rewardsDistributor != msg.sender) revert Unauthorized();\n        if (_rewardAmount == 0) revert MustBeGreaterThanZero();\n        if (totalSupply() == 0) revert SupplyMustBeGreaterThanZero();\n\n        // handle the transfer of reward tokens via `transferFrom` to reduce the number\n        // of transactions required and ensure correctness of the reward amount\n        IERC20(_rewardsToken).safeTransferFrom(msg.sender, address(this), _rewardAmount);\n\n        // store locally to save gas\n        uint256 newRewardRate;\n\n        if (block.timestamp >= _rewardData.periodFinish) {\n            newRewardRate = _rewardAmount / _rewardData.rewardsDuration;\n        } else {\n            newRewardRate =\n                (_rewardAmount + (_rewardData.periodFinish - block.timestamp) * _rewardData.rewardRate) /\n                _rewardData.rewardsDuration;\n        }\n\n        // Ensure the provided reward amount is not more than the balance in the contract.\n        // This keeps the reward rate in the right range, preventing overflows due to\n        // very high values of rewardRate in the earned and rewardsPerToken functions;\n        // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.\n        if (newRewardRate > (IERC20(_rewardsToken).balanceOf(address(this)) / _rewardData.rewardsDuration)) {\n            revert RewardTooHigh();\n        }\n\n        _rewardData.rewardRate = newRewardRate;\n        _rewardData.lastUpdateTime = block.timestamp;\n        _rewardData.periodFinish = block.timestamp + _rewardData.rewardsDuration;\n        rewardData[_rewardsToken] = _rewardData; // Write to storage\n\n        emit RewardAdded(_rewardsToken, _rewardAmount);\n    }\n\n    /**\n     * @notice Set rewards distributor address for a given reward token.\n     * @dev May only be called by owner, and can't be set to zero address.\n     * @param _rewardsToken Address of the rewards token.\n     * @param _rewardsDistributor Address of the rewards distributor. This is the only address that can add new rewards\n     *  for this token.\n     */\n    function setRewardsDistributor(address _rewardsToken, address _rewardsDistributor) external onlyOwner {\n        if (_rewardsToken == address(0) || _rewardsDistributor == address(0)) revert ZeroAddress();\n        rewardData[_rewardsToken].rewardsDistributor = _rewardsDistributor;\n        emit RewardsDistributorSet(_rewardsToken, _rewardsDistributor);\n    }\n\n    /**\n     * @notice Set the duration of our rewards period.\n     * @dev May only be called by rewards distributor, and must be done after most recent period ends.\n     * @param _rewardsToken Address of the rewards token.\n     * @param _rewardsDuration New length of period in seconds.\n     */\n    function setRewardsDuration(address _rewardsToken, uint256 _rewardsDuration) external {\n        if (block.timestamp <= rewardData[_rewardsToken].periodFinish) revert RewardsStillActive();\n        if (msg.sender != rewardData[_rewardsToken].rewardsDistributor && msg.sender != owner()) revert Unauthorized();\n        if (_rewardsDuration == 0) revert MustBeGreaterThanZero();\n        rewardData[_rewardsToken].rewardsDuration = _rewardsDuration;\n        emit RewardsDurationUpdated(_rewardsToken, _rewardsDuration);\n    }\n\n    /**\n     * @notice Sweep out tokens accidentally sent here.\n     * @dev May only be called by owner. If a pool has multiple tokens to sweep out, call this once for each.\n     * @param _tokenAddress Address of token to sweep.\n     * @param _tokenAmount Amount of tokens to sweep.\n     */\n    function recoverERC20(address _tokenAddress, uint256 _tokenAmount) external onlyOwner {\n        if (_tokenAddress == stakeToken()) {\n            _tokenAmount = IERC20(_tokenAddress).balanceOf(address(this)) - totalSupply();\n            if (_tokenAmount > 0) {\n                IERC20(_tokenAddress).safeTransfer(owner(), _tokenAmount);\n            }\n            return;\n        }\n\n        address[] memory _rewardTokens = rewardTokens;\n\n        for (uint256 i; i < _rewardTokens.length; ++i) {\n            if (_rewardTokens[i] == _tokenAddress) {\n                return; // Can't recover reward token\n            }\n        }\n\n        IERC20(_tokenAddress).safeTransfer(owner(), _tokenAmount);\n    }\n\n\n    /* ========== INTERNAL FUNCTIONS ========== */\n\n    // internal function to get rewards.\n    function _getRewardFor(address _account) internal {\n        uint256 length = rewardTokens.length;\n        address _recipient = rewardRedirect[_account];\n        _recipient = _recipient != address(0) ? _recipient : _account;\n        for (uint256 i; i < length; ++i) {\n            address _rewardsToken = rewardTokens[i];\n            uint256 reward = rewards[_account][_rewardsToken];\n            if (reward > 0) {\n                rewards[_account][_rewardsToken] = 0;\n                IERC20(_rewardsToken).safeTransfer(_recipient, reward);\n                emit RewardPaid(_account, _rewardsToken, _recipient, reward);\n            }\n        }\n    }\n\n    function min(uint a, uint b) internal pure returns (uint) {\n        return a < b ? a : b;\n    }\n\n    /* ========== VIEWS ========== */\n\n    /**\n     * @notice Amount of reward token pending claim by an account.\n     * @param _account Account to check earned balance for.\n     * @param _rewardsToken Rewards token to check.\n     * @return pending Amount of reward token pending claim.\n     */\n    function earned(address _account, address _rewardsToken) public view returns (uint256 pending) {\n        pending = (\n                balanceOf(_account) \n                * (\n                    rewardPerToken(_rewardsToken) \n                    - userRewardPerTokenPaid[_account][_rewardsToken]\n                )\n            ) \n            / PRECISION \n            + rewards[_account][_rewardsToken];\n    }\n\n    /**\n     * @notice Amount of reward token(s) pending claim by an account.\n     * @dev Checks for all rewardTokens.\n     * @param _account Account to check earned balance for.\n     * @return pending Amount of reward token(s) pending claim.\n     */\n    function earnedMulti(address _account) external view returns (uint256[] memory pending) {\n        address[] memory _rewardTokens = rewardTokens;\n        uint256 length = _rewardTokens.length;\n        pending = new uint256[](length);\n\n        for (uint256 i; i < length; ++i) {\n            pending[i] = earned(_account, _rewardTokens[i]);\n        }\n    }\n\n    /**\n     * @notice Reward paid out per whole token.\n     * @param _rewardsToken Reward token to check.\n     * @return rewardAmount Reward paid out per whole token.\n     */\n    function rewardPerToken(address _rewardsToken) public view returns (uint256 rewardAmount) {\n        uint256 _totalSupply = totalSupply();\n        if (_totalSupply == 0) {\n            return rewardData[_rewardsToken].rewardPerTokenStored;\n        }\n\n        rewardAmount =\n            rewardData[_rewardsToken].rewardPerTokenStored +\n            (((lastTimeRewardApplicable(_rewardsToken) - rewardData[_rewardsToken].lastUpdateTime) *\n                rewardData[_rewardsToken].rewardRate *\n                PRECISION) / _totalSupply);\n    }\n\n    function lastTimeRewardApplicable(address _rewardsToken) public view returns (uint256) {\n        return min(block.timestamp, rewardData[_rewardsToken].periodFinish);\n    }\n\n    /// @notice Number reward tokens we currently have.\n    function rewardTokensLength() external view returns (uint256) {\n        return rewardTokens.length;\n    }\n\n    /**\n     * @notice Total reward that will be paid out over the reward duration.\n     * @dev These values are only updated when notifying, adding, or adjust duration of rewards.\n     * @param _rewardsToken Reward token to check.\n     * @return Total reward tokens paid out over the reward duration.\n     */\n    function getRewardForDuration(address _rewardsToken) external view returns (uint256) {\n        return rewardData[_rewardsToken].rewardRate * rewardData[_rewardsToken].rewardsDuration;\n    }\n\n    /**\n     * @notice Sets new target address for staker's rewards.\n     * @param _to Address to redirect rewards to. Set to address(0) to clear redirect.\n     */\n    function setRewardRedirect(address _to) external nonReentrant{\n        rewardRedirect[msg.sender] = _to;\n        emit RewardRedirected(msg.sender, _to);\n    }\n}"},{"file_path":"src/dependencies/CoreOwnable.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport {ICore} from \"../interfaces/ICore.sol\";\n\n/**\n    @title Core Ownable\n    @author Prisma Finance (with edits by Resupply Finance)\n    @notice Contracts inheriting `CoreOwnable` have the same owner as `Core`.\n            The ownership cannot be independently modified or renounced.\n */\ncontract CoreOwnable {\n    ICore public immutable core;\n\n    constructor(address _core) {\n        core = ICore(_core);\n    }\n\n    modifier onlyOwner() {\n        require(msg.sender == address(core), \"!core\");\n        _;\n    }\n\n    function owner() public view returns (address) {\n        return address(core);\n    }\n}"},{"file_path":"src/dependencies/DelegatedOps.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\n/**\n    @title Delegated Operations\n    @author Prisma Finance (with edits by Resupply Finance)\n    @notice Allows delegation to specific contract functionality. Useful for creating\n            wrapper contracts to bundle multiple interactions into a single call.\n */\ncontract DelegatedOps {\n    event DelegateApprovalSet(address indexed account, address indexed delegate, bool isApproved);\n\n    mapping(address owner => mapping(address caller => bool isApproved)) public isApprovedDelegate;\n\n    modifier callerOrDelegated(address _account) {\n        require(msg.sender == _account || isApprovedDelegate[_account][msg.sender], \"!CallerOrDelegated\");\n        _;\n    }\n\n    function setDelegateApproval(address _delegate, bool _isApproved) external {\n        isApprovedDelegate[msg.sender][_delegate] = _isApproved;\n        emit DelegateApprovalSet(msg.sender, _delegate, _isApproved);\n    }\n}\n"},{"file_path":"src/dependencies/EpochTracker.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport \"../interfaces/ICore.sol\";\n\n/**\n    @title EpochTracker\n    @dev Provides a unified `startTime` and `getEpoch`, used for tracking epochs.\n */\ncontract EpochTracker {\n    uint256 public immutable startTime;\n    \n    /// @notice Length of an epoch, in seconds\n    uint256 public immutable epochLength;\n\n    constructor(address _core) {\n        startTime = ICore(_core).startTime();\n        epochLength = ICore(_core).epochLength();\n    }\n\n    function getEpoch() public view returns (uint256 epoch) {\n        return (block.timestamp - startTime) / epochLength;\n    }\n}"},{"file_path":"src/interfaces/IAuthHook.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface IAuthHook {\n    function preHook(address operator, address target, bytes calldata data) external returns (bool);\n    function postHook(bytes memory result, address operator, address target, bytes calldata data) external returns (bool);\n}\n"},{"file_path":"src/interfaces/ICore.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport { IAuthHook } from './IAuthHook.sol';\n\ninterface ICore {\n    struct OperatorAuth {\n        bool authorized;\n        IAuthHook hook;\n    }\n\n    event VoterSet(address indexed newVoter);\n    event OperatorExecuted(address indexed caller, address indexed target, bytes data);\n    event OperatorSet(address indexed caller, address indexed target, bool authorized, bytes4 selector, IAuthHook authHook);\n\n    function execute(address target, bytes calldata data) external returns (bytes memory);\n    function epochLength() external view returns (uint256);\n    function startTime() external view returns (uint256);\n    function voter() external view returns (address);\n    function ownershipTransferDeadline() external view returns (uint256);\n    function pendingOwner() external view returns (address);\n    function setOperatorPermissions(\n        address caller,\n        address target,\n        bytes4 selector,\n        bool authorized,\n        IAuthHook authHook\n    ) external;\n    function setVoter(address newVoter) external;\n    function operatorPermissions(address caller, address target, bytes4 selector) external view returns (bool authorized, IAuthHook hook);\n}\n"},{"file_path":"src/interfaces/IERC20Decimals.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface IERC20Decimals {\n    function decimals() external view returns (uint8);\n}"},{"file_path":"src/interfaces/IGovStaker.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface IGovStaker {\n    /* ========== EVENTS ========== */\n    event RewardAdded(address indexed rewardToken, uint256 amount);\n    event RewardTokenAdded(address indexed rewardsToken, address indexed rewardsDistributor, uint256 rewardsDuration);\n    event Recovered(address indexed token, uint256 amount);\n    event RewardsDurationUpdated(address indexed rewardsToken, uint256 duration);\n    event RewardPaid(address indexed user, address indexed rewardToken, uint256 reward);\n    event Staked(address indexed account, uint indexed epoch, uint amount);\n    event Unstaked(address indexed account, uint amount);\n    event Cooldown(address indexed account, uint amount, uint end);\n    event CooldownEpochsUpdated(uint24 newDuration);\n\n    /* ========== STRUCTS ========== */\n    struct Reward {\n        address rewardsDistributor;\n        uint256 rewardsDuration;\n        uint256 periodFinish;\n        uint256 rewardRate;\n        uint256 lastUpdateTime;\n        uint256 rewardPerTokenStored;\n    }\n\n    struct AccountData {\n        uint120 realizedStake; // Amount of stake that has fully realized weight.\n        uint120 pendingStake; // Amount of stake that has not yet fully realized weight.\n        uint16 lastUpdateEpoch;\n    }\n\n    struct UserCooldown {\n        uint104 end;\n        uint152 amount;\n    }\n\n    enum ApprovalStatus {\n        None, // 0. Default value, indicating no approval\n        StakeOnly, // 1. Approved for stake only\n        UnstakeOnly, // 2. Approved for unstake only\n        StakeAndUnstake // 3. Approved for both stake and unstake\n    }\n\n    /* ========== STATE VARIABLES ========== */\n    function rewardTokens(uint256 index) external view returns (address);\n    function rewardData(address token) external view returns (Reward memory);\n    function rewards(address account, address token) external view returns (uint256);\n    function userRewardPerTokenPaid(address account, address token) external view returns (uint256);\n    function CORE() external view returns (address);\n    function PRECISION() external view returns (uint256);\n    function ESCROW() external view returns (address);\n    function MAX_COOLDOWN_DURATION() external view returns (uint24);\n    function totalPending() external view returns (uint120);\n    function totalLastUpdateEpoch() external view returns (uint16);\n    function cooldownEpochs() external view returns (uint256);\n    function decimals() external view returns (uint8);\n    function approvedCaller(address account, address caller) external view returns (ApprovalStatus);\n\n    /* ========== EXTERNAL FUNCTIONS ========== */\n    function accountData(address account) external view returns (AccountData memory);\n    function stakeToken() external view returns (address);\n    function balanceOf(address account) external view returns (uint256);\n    function totalSupply() external view returns (uint256);\n    function getReward() external;\n    function getOneReward(address rewardsToken) external;\n    function addReward(address rewardsToken, address rewardsDistributor, uint256 rewardsDuration) external;\n    function notifyRewardAmount(address rewardsToken, uint256 rewardAmount) external;\n    function setRewardsDistributor(address rewardsToken, address rewardsDistributor) external;\n    function setRewardsDuration(address rewardsToken, uint256 rewardsDuration) external;\n    function recoverERC20(address tokenAddress, uint256 tokenAmount) external;\n    function stake(address account, uint amount) external returns (uint);\n    function stakeFor(address account, uint amount) external returns (uint);\n    function cooldown(address account, uint amount) external returns (uint);\n    function cooldowns(address account) external view returns (UserCooldown memory);\n    function cooldownFor(address account, uint amount) external returns (uint);\n    function exit(address account) external returns (uint);\n    function exitFor(address account) external returns (uint);\n    function unstake(address account, address receiver) external returns (uint);\n    function unstakeFor(address account, address receiver) external returns (uint);\n    function checkpointAccount(address account) external returns (AccountData memory, uint weight);\n    function checkpointAccountWithLimit(address account, uint epoch) external returns (AccountData memory, uint weight);\n    function checkpointTotal() external returns (uint);\n    function setApprovedCaller(address caller, ApprovalStatus status) external;\n    function setCooldownEpochs(uint24 epochs) external;\n    function getAccountWeight(address account) external view returns (uint);\n    function getAccountWeightAt(address account, uint epoch) external view returns (uint);\n    function getTotalWeight() external view returns (uint);\n    function getTotalWeightAt(uint epoch) external view returns (uint);\n    function getUnstakableAmount(address account) external view returns (uint);\n    function isCooldownEnabled() external view returns (bool);\n    function rewardTokensLength() external view returns (uint256);\n    function earned(address account, address rewardsToken) external view returns (uint256 pending);\n    function earnedMulti(address account) external view returns (uint256[] memory pending);\n    function rewardPerToken(address rewardsToken) external view returns (uint256 rewardAmount);\n    function lastTimeRewardApplicable(address rewardsToken) external view returns (uint256);\n    function getRewardForDuration(address rewardsToken) external view returns (uint256);\n    function owner() external view returns (address);\n    function guardian() external view returns (address);\n    function getEpoch() external view returns (uint);\n    function epochLength() external view returns (uint);\n    function startTime() external view returns (uint);\n    function irreversiblyCommitAccountAsPermanentStaker(address account) external;\n    function onPermaStakeMigrate(address account) external;\n    function migrateStake() external returns (uint amount);\n    function setDelegateApproval(address delegate, bool approved) external;\n}\n"},{"file_path":"src/interfaces/IResupplyRegistry.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\ninterface IResupplyRegistry {\n    event AddPair(address pairAddress);\n    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n    event SetDeployer(address deployer, bool _bool);\n\n    function acceptOwnership() external;\n\n    function addPair(address _pairAddress) external;\n\n    function registeredPairs(uint256) external view returns (address);\n\n    function pairsByName(string memory) external view returns (address);\n\n    function defaultSwappersLength() external view returns (uint256);\n    function registeredPairsLength() external view returns (uint256);\n\n    function getAllPairAddresses() external view returns (address[] memory _deployedPairsArray);\n    \n    function getAllDefaultSwappers() external view returns (address[] memory _defaultSwappers);\n\n    function owner() external view returns (address);\n\n    function pendingOwner() external view returns (address);\n\n    function renounceOwnership() external;\n\n    function transferOwnership(address newOwner) external;\n\n    function claimFees(address _pair) external;\n    function claimRewards(address _pair) external;\n    function claimInsuranceRewards() external;\n    function withdrawTo(address _asset, uint256 _amount, address _to) external;\n    function mint( address receiver, uint256 amount) external;\n    function burn( address target, uint256 amount) external;\n    function liquidationHandler() external view returns(address);\n    function feeDeposit() external view returns(address);\n    function redemptionHandler() external view returns(address);\n    function rewardHandler() external view returns(address);\n    function insurancePool() external view returns(address);\n    function setRewardClaimer(address _newAddress) external;\n    function setRedemptionHandler(address _newAddress) external;\n    function setFeeDeposit(address _newAddress) external;\n    function setLiquidationHandler(address _newAddress) external;\n    function setInsurancePool(address _newAddress) external;\n    function setStaker(address _newAddress) external;\n    function setTreasury(address _newAddress) external;\n    function staker() external view returns(address);\n    function token() external view returns(address);\n    function treasury() external view returns(address);\n    function govToken() external view returns(address);\n    function l2manager() external view returns(address);\n    function setRewardHandler(address _newAddress) external;\n    function setVestManager(address _newAddress) external;\n    function setDefaultSwappers(address[] memory _swappers) external;\n    function collateralId(address _collateral) external view returns(uint256);\n}"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"_core","type":"address"},{"internalType":"address","name":"_registry","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint24","name":"_cooldownEpochs","type":"uint24"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotAddStakeToken","type":"error"},{"inputs":[],"name":"DecimalsMustBe18","type":"error"},{"inputs":[],"name":"InsufficientRealizedStake","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidCooldown","type":"error"},{"inputs":[],"name":"InvalidDuration","type":"error"},{"inputs":[],"name":"MustBeGreaterThanZero","type":"error"},{"inputs":[],"name":"OldEpoch","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"RewardAlreadyAdded","type":"error"},{"inputs":[],"name":"RewardTooHigh","type":"error"},{"inputs":[],"name":"RewardsStillActive","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SupplyMustBeGreaterThanZero","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"}],"name":"Cooldown","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint24","name":"newDuration","type":"uint24"}],"name":"CooldownEpochsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"DelegateApprovalSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"PermaStakerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"redirect","type":"address"}],"name":"RewardRedirected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewardsToken","type":"address"},{"indexed":true,"internalType":"address","name":"rewardsDistributor","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardsDuration","type":"uint256"}],"name":"RewardTokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewardsToken","type":"address"},{"indexed":true,"internalType":"address","name":"rewardsDistributor","type":"address"}],"name":"RewardsDistributorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewardsToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"RewardsDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"epoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Unstaked","type":"event"},{"inputs":[],"name":"MAX_COOLDOWN_DURATION","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"accountData","outputs":[{"internalType":"uint112","name":"realizedStake","type":"uint112"},{"internalType":"uint112","name":"pendingStake","type":"uint112"},{"internalType":"uint16","name":"lastUpdateEpoch","type":"uint16"},{"internalType":"bool","name":"isPermaStaker","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"},{"internalType":"address","name":"_rewardsDistributor","type":"address"},{"internalType":"uint256","name":"_rewardsDuration","type":"uint256"}],"name":"addReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"checkpointAccount","outputs":[{"components":[{"internalType":"uint112","name":"realizedStake","type":"uint112"},{"internalType":"uint112","name":"pendingStake","type":"uint112"},{"internalType":"uint16","name":"lastUpdateEpoch","type":"uint16"},{"internalType":"bool","name":"isPermaStaker","type":"bool"}],"internalType":"struct GovStaker.AccountData","name":"acctData","type":"tuple"},{"internalType":"uint256","name":"weight","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"checkpointAccountWithLimit","outputs":[{"components":[{"internalType":"uint112","name":"realizedStake","type":"uint112"},{"internalType":"uint112","name":"pendingStake","type":"uint112"},{"internalType":"uint16","name":"lastUpdateEpoch","type":"uint16"},{"internalType":"bool","name":"isPermaStaker","type":"bool"}],"internalType":"struct GovStaker.AccountData","name":"acctData","type":"tuple"},{"internalType":"uint256","name":"weight","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"checkpointTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"cooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cooldownEpochs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"cooldowns","outputs":[{"internalType":"uint104","name":"end","type":"uint104"},{"internalType":"uint152","name":"amount","type":"uint152"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"core","outputs":[{"internalType":"contract ICore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"earnedMulti","outputs":[{"internalType":"uint256[]","name":"pending","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epochLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"escrow","outputs":[{"internalType":"contract GovStakerEscrow","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"exit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"getAccountWeightAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEpoch","outputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"getOneReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"getRewardForDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getTotalWeightAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getUnstakableAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"irreversiblyCommitAccountAsPermanentStaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"caller","type":"address"}],"name":"isApprovedDelegate","outputs":[{"internalType":"bool","name":"isApproved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isCooldownEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isPermaStaker","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrateStake","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"},{"internalType":"uint256","name":"_rewardAmount","type":"uint256"}],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"onPermaStakeMigrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract IResupplyRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardData","outputs":[{"internalType":"address","name":"rewardsDistributor","type":"address"},{"internalType":"uint256","name":"rewardsDuration","type":"uint256"},{"internalType":"uint256","name":"periodFinish","type":"uint256"},{"internalType":"uint256","name":"rewardRate","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"},{"internalType":"uint256","name":"rewardPerTokenStored","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"rewardAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardRedirect","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardTokensLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint24","name":"_epochs","type":"uint24"}],"name":"setCooldownEpochs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"},{"internalType":"bool","name":"_isApproved","type":"bool"}],"name":"setDelegateApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"setRewardRedirect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"},{"internalType":"address","name":"_rewardsDistributor","type":"address"}],"name":"setRewardsDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"},{"internalType":"uint256","name":"_rewardsDuration","type":"uint256"}],"name":"setRewardsDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLastUpdateEpoch","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPending","outputs":[{"internalType":"uint112","name":"","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"unstake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userRewardPerTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":"0x000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d00000000000000000000000010101010e0c3171d894b71b3400668af311e7d94000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f7260000000000000000000000000000000000000000000000000000000000000002"}