creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "YBSRewardFactory.sol": {
        "content": "// SPDX-License-Identifier: GNU AGPLv3\npragma solidity ^0.8.22;\n\nimport {IERC20, SingleTokenRewardDistributor, IYearnBoostedStaker} from \"../SingleTokenRewardDistributor.sol\";\n\n\n/// @title Deploys Rewards Distributor Contract\ncontract YBSRewardFactory{\n\n    string public constant VERSION = \"1.0.0\";\n\n    /**\n        @notice Deploy new YBS Reward contract.\n        @dev We use CREATE2 to generate deterministic deployments based on msg.sender.\n    */\n    function deploy(\n        address _ybs,\n        address _reward_token\n    ) external returns (address distributor) {\n\n        uint256 salt = uint256(uint160(address(msg.sender)));\n        bytes memory bytecode = type(SingleTokenRewardDistributor).creationCode;\n        bytes memory bytecodeWithArgs = abi.encodePacked(\n            bytecode,\n            abi.encode(_ybs, _reward_token)\n        );\n        address deployedAddress;\n        assembly {\n            deployedAddress := create2(0, add(bytecodeWithArgs, 0x20), mload(bytecodeWithArgs), salt)\n        }\n        require(deployedAddress != address(0), \"Failed to deploy contract\");\n\n        return deployedAddress;\n    }\n}"
      },
      "SingleTokenRewardDistributor.sol": {
        "content": "// SPDX-License-Identifier: GNU AGPLv3\npragma solidity ^0.8.22;\n\nimport {WeekStart, IYearnBoostedStaker} from \"utils/WeekStart.sol\";\nimport {IERC20, SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n\ncontract SingleTokenRewardDistributor is WeekStart {\n    using SafeERC20 for IERC20;\n\n    uint constant PRECISION = 1e18;\n    IYearnBoostedStaker public immutable staker;\n    IERC20 public immutable rewardToken;\n    uint public immutable START_WEEK;\n    uint immutable MAX_STAKE_GROWTH_WEEKS;\n\n    struct AccountInfo {\n        address recipient; // Who rewards will be sent to. Cheaper to store here than in dedicated mapping.\n        uint96 lastClaimWeek;\n    }\n\n    mapping(uint week => uint amount) public weeklyRewardAmount;\n    mapping(address account => AccountInfo info) public accountInfo;\n    mapping(address account => mapping(address claimer => bool approved)) public approvedClaimer;\n    \n    event RewardDeposited(uint indexed week, address indexed depositor, uint rewardAmount);\n    event RewardsClaimed(address indexed account, uint indexed week, uint rewardAmount);\n    event RecipientConfigured(address indexed account, address indexed recipient);\n    event ClaimerApproved(address indexed account, address indexed, bool approved);\n    event RewardPushed(uint indexed fromWeek, uint indexed toWeek, uint amount);\n\n    /**\n        @param _staker the staking contract to use for weight calculations.\n        @param _rewardToken address of reward token to be used.\n    */\n    constructor(\n        IYearnBoostedStaker _staker,\n        IERC20 _rewardToken\n    )\n        WeekStart(_staker) {\n        staker = _staker;\n        rewardToken = _rewardToken;\n        START_WEEK = staker.getWeek();\n        MAX_STAKE_GROWTH_WEEKS = staker.MAX_STAKE_GROWTH_WEEKS();\n    }\n\n    /**\n        @notice Allow permissionless deposits to the current week.\n        @param _amount the amount of reward token to deposit.\n    */\n    function depositReward(uint _amount) external {\n        _depositReward(msg.sender, _amount);\n    }\n\n    /**\n        @notice Allow permissionless deposits to the current week from any address with approval.\n        @param _target the address to pull tokens from.\n        @param _amount the amount of reward token to deposit.\n    */\n    function depositRewardFrom(address _target, uint _amount) external {\n        _depositReward(_target, _amount);\n    }\n\n    function _depositReward(address _target, uint _amount) internal {\n        if (_amount > 0) {\n            uint week = getWeek();\n            weeklyRewardAmount[week] += _amount;\n            rewardToken.safeTransferFrom(_target, address(this), _amount);\n            emit RewardDeposited(week, _target, _amount);\n        }\n    }\n\n    /**\n        @notice Push inaccessible rewards to current week.\n        @dev    In rare circumstances, rewards may have been deposited to a week where no adjusted weight exists.\n                This function allows us to recover rewards to the current week.\n        @param _week the week to push rewards from.\n        @return true if operation was successful.\n    */\n    function pushRewards(uint _week) external returns (bool) {\n        uint week = getWeek();\n        uint amount = pushableRewards(_week);\n        if(amount == 0) return false;\n        weeklyRewardAmount[_week] = 0;\n        weeklyRewardAmount[week] += amount;\n        emit RewardPushed(_week, week, amount);\n        return true;\n    }\n\n    /**\n        @notice Helper view function to check if any rewards are pushable.\n        @param _week the week to push rewards from.\n        @return uint representing rewards amount that is pushable.\n    */\n    function pushableRewards(uint _week) public view returns (uint) {\n        uint week = getWeek();\n        if(_week >= week) return 0;\n        if(adjustedGlobalWeightAt(_week) != 0) return 0;\n        return weeklyRewardAmount[_week];\n    }\n\n    /**\n        @notice Claim all owed rewards since the last week touched by the user.\n        @dev    It is not suggested to use this function directly. Rather `claimWithRange` \n                will tend to be more gas efficient when used with values from `getSuggestedClaimRange`.\n    */\n    function claim() external returns (uint amountClaimed) {\n        uint currentWeek = getWeek();\n        currentWeek = currentWeek == 0 ? 0 : currentWeek - 1;\n        return _claimWithRange(msg.sender, 0, currentWeek);\n    }\n\n    /**\n        @notice Claim on behalf of another account. Retrieves all owed rewards since the last week touched by the user.\n        @dev    It is not suggested to use this function directly. Rather `claimWithRange` \n                will tend to be more gas efficient when used with values from `getSuggestedClaimRange`.\n    */\n    function claimFor(address _account) external returns (uint amountClaimed) {\n        require(_onlyClaimers(_account), \"!approvedClaimer\");\n        uint currentWeek = getWeek();\n        currentWeek = currentWeek == 0 ? 0 : currentWeek - 1;\n        return _claimWithRange(_account, 0, currentWeek);\n    }\n\n    /**\n        @notice Claim rewards within a range of specified past weeks.\n        @param _claimStartWeek the min week to search and rewards.\n        @param _claimEndWeek the max week in which to search for and claim rewards.\n        @dev    IMPORTANT: Choosing a `_claimStartWeek` that is greater than the earliest week in which a user\n                may claim. Will result in the user being locked out (total loss) of rewards for any weeks prior.\n    */\n    function claimWithRange(\n        uint _claimStartWeek,\n        uint _claimEndWeek\n    ) external returns (uint amountClaimed) {\n        return _claimWithRange(msg.sender, _claimStartWeek, _claimEndWeek);\n    }\n\n    /**\n        @notice Claim on behalf of another account for a range of specified past weeks.\n        @param _account Account of which to make the claim on behalf of.\n        @param _claimStartWeek The min week to search and rewards.\n        @param _claimEndWeek The max week in which to search for and claim rewards.\n        @dev    WARNING: Choosing a `_claimStartWeek` that is greater than the earliest week in which a user\n                may claim will result in the user being locked out (total loss) of rewards for any weeks prior.\n        @dev    Useful to target specific weeks with known reward amounts. Claiming via this function will tend \n                to be more gas efficient when used with values from `getSuggestedClaimRange`.\n    */\n    function claimWithRangeFor(\n        address _account,\n        uint _claimStartWeek,\n        uint _claimEndWeek\n    ) external returns (uint amountClaimed) {\n        require(_onlyClaimers(_account), \"!approvedClaimer\");\n        return _claimWithRange(_account, _claimStartWeek, _claimEndWeek);\n    }\n\n    function _claimWithRange(\n        address _account,\n        uint _claimStartWeek,\n        uint _claimEndWeek\n    ) internal returns (uint amountClaimed) {\n        uint currentWeek = getWeek();\n        if(_claimEndWeek >= currentWeek) return 0;\n\n        AccountInfo storage info = accountInfo[_account];\n        \n        // Sanitize inputs\n        uint _minStartWeek = info.lastClaimWeek == 0 ? START_WEEK : info.lastClaimWeek;\n        _claimStartWeek = max(_minStartWeek, _claimStartWeek);\n        if(_claimStartWeek > _claimEndWeek) return 0;\n        \n        amountClaimed = _getTotalClaimableByRange(_account, _claimStartWeek, _claimEndWeek);\n        \n        _claimEndWeek += 1;\n        info.lastClaimWeek = uint96(_claimEndWeek);\n        \n        if (amountClaimed > 0) {\n            address recipient = info.recipient == address(0) ? _account : info.recipient;\n            rewardToken.safeTransfer(recipient, amountClaimed);\n            emit RewardsClaimed(_account, _claimEndWeek, amountClaimed);\n        }\n    }\n\n    /**\n        @notice Helper function used to determine overall share of rewards at a particular week.\n        @dev    IMPORTANT: This calculation cannot be relied upon to return strictly the users weight\n                against global weight as it implements custom logic to ignore the first week of each deposit.\n        @dev    Computing shares in past weeks is accurate. However, current week computations will not \n                be accurate until week is finalized.\n        @dev    Results scaled to PRECSION.\n    */\n    function computeSharesAt(address _account, uint _week) public view returns (uint) {\n        require(_week <= getWeek(), \"Invalid week\");\n        // As a security measure, we don't distribute rewards to YBS deposits on their first full week of staking.\n        // To acheive this, we lookup the weight that was added in the target week and ignore it.\n        uint adjAcctWeight = adjustedAccountWeightAt(_account, _week);\n        if (adjAcctWeight == 0) return 0;\n        \n        uint adjGlobalWeight = adjustedGlobalWeightAt(_week);\n        if (adjGlobalWeight == 0) return 0;\n\n        return adjAcctWeight * PRECISION / adjGlobalWeight;\n    }\n\n    function adjustedAccountWeightAt(address _account, uint _week) public view returns (uint) {\n        uint acctWeight = staker.getAccountWeightAt(_account, _week);\n        if (acctWeight == 0) return 0;\n        return acctWeight - staker.accountWeeklyToRealize(_account, _week + MAX_STAKE_GROWTH_WEEKS).weightPersistent;\n    }\n\n    function adjustedGlobalWeightAt(uint _week) public view returns (uint) {\n        uint globalWeight = staker.getGlobalWeightAt(_week);\n        if (globalWeight == 0) return 0;\n        return globalWeight - staker.globalWeeklyToRealize(_week + MAX_STAKE_GROWTH_WEEKS).weightPersistent;\n    }\n\n    /**\n        @notice Get the sum total number of claimable tokens for a user across all his claimable weeks.\n    */\n    function getClaimable(address _account) external view returns (uint claimable) {\n        (uint claimStartWeek, uint claimEndWeek) = getSuggestedClaimRange(_account);\n        return _getTotalClaimableByRange(_account, claimStartWeek, claimEndWeek);\n    }\n\n    /**\n        @notice Returns sum of tokens earned with a specified range of weeks.\n        @param _account Account to query.\n        @param _claimStartWeek Week to begin querying from.\n        @param _claimEndWeek Week to end querying at.\n    */\n    function getTotalClaimableByRange(\n        address _account,\n        uint _claimStartWeek,\n        uint _claimEndWeek\n    ) external view returns (uint claimable) {\n        uint currentWeek = getWeek();\n        if (_claimEndWeek >= currentWeek) _claimEndWeek = currentWeek - 1;\n        return _getTotalClaimableByRange(_account, _claimStartWeek, _claimEndWeek);\n    }\n\n    function _getTotalClaimableByRange(\n        address _account,\n        uint _claimStartWeek,\n        uint _claimEndWeek\n    ) internal view returns (uint claimableAmount) {\n        for (uint i = _claimStartWeek; i <= _claimEndWeek; ++i) {\n            claimableAmount += _getClaimableAt(_account, i);\n        }\n    }\n\n    /**\n        @notice Helper function returns suggested start and end range for claim weeks.\n        @dev    This function is designed to be called prior to ranged claims to shorted the number of iterations\n                required to loop if possible.\n    */\n    function getSuggestedClaimRange(address _account) public view returns (uint claimStartWeek, uint claimEndWeek) {\n        uint currentWeek = getWeek();\n        if (currentWeek == 0) return (0, 0);\n        bool canClaim;\n        uint lastClaimWeek = accountInfo[_account].lastClaimWeek;\n        \n        claimStartWeek = START_WEEK > lastClaimWeek ? START_WEEK : lastClaimWeek;\n\n        // Loop from old towards recent.\n        for (claimStartWeek; claimStartWeek <= currentWeek; claimStartWeek++) {\n            if (_getClaimableAt(_account, claimStartWeek) > 0) {\n                canClaim = true;\n                break;\n            }\n        }\n\n        if (!canClaim) return (0,0);\n\n        // Loop backwards from recent week towards old. Skip current week.\n        for (claimEndWeek = currentWeek - 1; claimEndWeek > claimStartWeek; claimEndWeek--) {\n            if (_getClaimableAt(_account, claimEndWeek) > 0) {\n                break;\n            }\n        }\n\n        return (claimStartWeek, claimEndWeek);\n    }\n\n    /**\n        @notice Get the reward amount available at a given week index.\n        @param _account The account to check.\n        @param _week The past week to check.\n    */\n    function getClaimableAt(\n        address _account, \n        uint _week\n    ) external view returns (uint rewardAmount) {\n        if(_week >= getWeek()) return 0;\n        return _getClaimableAt(_account, _week);\n    }\n\n    function _getClaimableAt(\n        address _account, \n        uint _week\n    ) internal view returns (uint rewardAmount) {\n        if(_week < accountInfo[_account].lastClaimWeek) return 0;\n        uint rewardShare = computeSharesAt(_account, _week);\n        uint totalWeeklyAmount = weeklyRewardAmount[_week];\n        rewardAmount = rewardShare * totalWeeklyAmount / PRECISION;\n    }\n\n    function _onlyClaimers(address _account) internal view returns (bool approved) {\n        return approvedClaimer[_account][msg.sender] || _account == msg.sender;\n    }\n\n    /**\n        @notice User may configure their account to set a custom reward recipient.\n        @param _recipient   Wallet to receive rewards on behalf of the account. Zero address will result in all \n                            rewards being transferred directly to the account holder.\n    */\n    function configureRecipient(address _recipient) external {\n        accountInfo[msg.sender].recipient = _recipient;\n        emit RecipientConfigured(msg.sender, _recipient);\n    }\n\n    /**\n        @notice Allow account to specify addresses to claim on their behalf.\n        @param _claimer Claimer to approve or revoke\n        @param _approved True to approve, False to revoke.\n    */\n    function approveClaimer(address _claimer, bool _approved) external {\n        approvedClaimer[msg.sender][_claimer] = _approved;\n        emit ClaimerApproved(msg.sender, _claimer, _approved);\n    }\n\n    function max(uint a, uint b) internal pure returns (uint) {\n        return a < b ? b : a;\n    }\n}"
      },
      "utils/WeekStart.sol": {
        "content": "// SPDX-License-Identifier: GNU AGPLv3\npragma solidity ^0.8.22;\nimport {IYearnBoostedStaker} from \"../interfaces/IYearnBoostedStaker.sol\";\n\n/**\n    @title Week Start\n    @dev Provides a unified `START_TIME` and `getWeek` aligned with the staker.\n */\ncontract WeekStart {\n    uint256 public immutable START_TIME;\n\n    constructor(IYearnBoostedStaker staker) {\n        START_TIME = staker.START_TIME();\n    }\n\n    function getWeek() public view returns (uint256 week) {\n        return (block.timestamp - START_TIME) / 1 weeks;\n    }\n}"
      },
      "interfaces/IYearnBoostedStaker.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.22;\n\nimport {IERC20, SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ninterface IYearnBoostedStaker {\n    struct AccountData {\n        uint112 realizedStake;\n        uint112 pendingStake;\n        uint16 lastUpdateWeek;\n        uint8 updateWeeksBitmap;\n    }\n\n    struct ToRealize {\n        uint112 weightPersistent;\n        uint112 weight;\n    }\n\n    enum ApprovalStatus {\n        None,\n        StakeOnly,\n        UnstakeOnly,\n        StakeAndUnstake\n    }\n\n    // State variables\n    function MAX_STAKE_GROWTH_WEEKS() external view returns (uint);\n    function MAX_WEEK_BIT() external view returns (uint8);\n    function START_TIME() external view returns (uint);\n    function stakeToken() external view returns (IERC20);\n    function globalGrowthRate() external view returns (uint112);\n    function globalLastUpdateWeek() external view returns (uint16);\n    function totalSupply() external view returns (uint);\n    function decimals() external view returns (uint8);\n    function owner() external view returns (address);\n    function pendingOwner() external view returns (address);\n    function approvedCaller(address account, address caller) external view returns (ApprovalStatus);\n    function approvedWeightedStaker(address staker) external view returns (bool);\n    function accountWeeklyToRealize(address account, uint week) external view returns (ToRealize memory);\n    function globalWeeklyToRealize(uint week) external view returns (ToRealize memory);\n    function accountWeeklyMaxStake(address account, uint week) external view returns (uint);\n    function globalWeeklyMaxStake(uint week) external view returns (uint);\n\n    // Events\n    event Stake(address indexed account, uint indexed week, uint amount, uint newUserWeight, uint weightAdded);\n    event Unstake(address indexed account, uint indexed week, uint amount, uint newUserWeight, uint weightRemoved);\n    event ApprovedCallerSet(address indexed account, address indexed caller, ApprovalStatus status);\n    event WeightedStakerSet(address indexed staker, bool approved);\n    event OwnershipTransferred(address indexed newOwner);\n\n    // Functions\n    function stake(uint _amount) external returns (uint);\n    function stakeFor(address _account, uint _amount) external returns (uint);\n    function stakeAsWeighted(address _account, uint _amount, uint _idx) external returns (uint);\n    function unstake(uint _amount, address _receiver) external returns (uint);\n    function unstakeFor(address _account, uint _amount, address _receiver) external returns (uint);\n\n    function checkpointAccount(address _account) external returns (AccountData memory acctData, uint weight);\n    function checkpointAccountWithLimit(address _account, uint _week) external returns (AccountData memory acctData, uint weight);\n\n    function getAccountWeight(address account) external view returns (uint);\n    function getAccountWeightAt(address _account, uint _week) external view returns (uint);\n\n    function checkpointGlobal() external returns (uint);\n    function getGlobalWeight() external view returns (uint);\n    function getGlobalWeightAt(uint week) external view returns (uint);\n\n    function getAccountWeightRatio(address _account) external view returns (uint);\n    function getAccountWeightRatioAt(address _account, uint _week) external view returns (uint);\n\n    function balanceOf(address _account) external view returns (uint);\n    function setApprovedCaller(address _caller, ApprovalStatus _status) external;\n    function setWeightedStaker(address _staker, bool _approved) external;\n\n    function transferOwnership(address _pendingOwner) external;\n    function acceptOwnership() external;\n\n    function sweep(address _token) external;\n    function getWeek() external view returns (uint);\n}"
      },
      ".cache/OpenZeppelin/v4.9.3/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 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    using Address for address;\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.encodeWithSelector(token.transfer.selector, 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.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20 token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 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    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease 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    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\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    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20Permit token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\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    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\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 silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));\n    }\n}\n"
      },
      ".cache/OpenZeppelin/v4.9.3/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) 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            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"
      },
      ".cache/OpenZeppelin/v4.9.3/token/ERC20/extensions/IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
      },
      ".cache/OpenZeppelin/v4.9.3/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "remappings": [
        "@openzeppelin/contracts=.cache/OpenZeppelin/v4.9.3"
      ]
    }
  }}