creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/periphery/StakingETH.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.19;\n\n/// Import from Utils /////\nimport {Ownable} from \"src/utils/Ownable.sol\";\n\n/// Import from Interfaces /////\n\nimport {IERC20} from \"openzeppelin-contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol\";\n\n///@title StakingETH\n///@notice This contract allow for staking ETH and staker earn points that will be used\n///        to distribute future airdrops farmed by the strategies.\n///        WARNING : This contract do not allow withdraw of ETH, only deposit, withdraw will be\n/// allow later once\n///        the strategies will be done.\ncontract StakingETH is Ownable {\n  using SafeERC20 for IERC20;\n  /*//////////////////////////////////////////////////////////////\n                            EVENTS\n  //////////////////////////////////////////////////////////////*/\n\n  event Staked(address indexed user, uint256 amount);\n\n  /*//////////////////////////////////////////////////////////////\n                            ERRORs\n  //////////////////////////////////////////////////////////////*/\n\n  error ZeroAmount();\n  error NotAllowed();\n\n  /*//////////////////////////////////////////////////////////////\n                            STORAGE VAR \n  //////////////////////////////////////////////////////////////*/\n\n  uint256 constant PRECISION = 1e30;\n\n  /// @notice The per-second rate at which rewardPerToken increases (1e18 is 1 point per second)\n  uint256 public constant REWARD_RATE = 10e18;\n\n  ///@notice The fee rate for depositing ETH\n  uint256 public constant FEE_RATE = 1e18;\n\n  ///@notice The fee that can be collected by owner\n  uint256 public feeToCollect;\n\n  ///@notice The ETH that can be collected by multisig\n  uint256 public ethToCollect;\n\n  /// @notice WETH interface\n  IERC20 public immutable WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n\n  /// @notice The address of the multisig that is allow to withdraw to deploy capital in strategies\n  address public multisig;\n\n  /// @notice The Unix timestamp (in seconds) at which staking begins\n  uint64 public start_date;\n\n  /// @notice The Unix timestamp (in seconds) at which the current reward period ends\n  uint64 public period_finish;\n\n  /// @notice The last Unix timestamp (in seconds) when rewardPerTokenStored was updated\n  uint64 public lastUpdateTime;\n\n  /// @notice The last stored rewardPerToken value\n  uint256 public rewardPerTokenStored;\n\n  /// @notice The last stored rewardPerToken value\n  uint256 public rewardPerTokenStoredFyde;\n\n  /// @notice The total tokens staked in the pool\n  uint256 public totalSupply;\n\n  /// @notice The amount of tokens staked by an account\n  mapping(address => uint256) public balanceOf;\n\n  /// @notice The rewardPerToken value when an account last staked/withdrew\n  mapping(address => uint256) public userRewardPerTokenPaid;\n\n  /// @notice The rewardPerToken value when an account last staked/withdrew\n  mapping(address => uint256) public userRewardPerTokenPaidFyde;\n\n  /// @notice The earned() value when an account last staked/withdrew\n  mapping(address => uint256) public rewards;\n\n  /// @notice The earned() value when an account last staked/withdrew\n  mapping(address => uint256) public rewardsFyde;\n\n  struct BoostPeriod {\n    uint32 timeStamp; // timestamp when boost starts\n    uint16 multiplier; // 1000 = 1x\n  }\n\n  /// @notice Periods in which the fyde points are boosted by a multiplier\n  /// @dev populate highest timestamp first\n  BoostPeriod[] public boostPeriods;\n\n  /*//////////////////////////////////////////////////////////////\n                            ADMIN FUNCTIONS\n  //////////////////////////////////////////////////////////////*/\n\n  ///@notice Collect the WETH fees from the staking contract and send it to the recipient\n  ///@param _recipient The address of the recipient\n  function collectFee(address _recipient) external onlyOwner {\n    uint256 feeToTransfer = feeToCollect;\n    feeToCollect = 0;\n    WETH.safeTransfer(_recipient, feeToTransfer);\n  }\n\n  ///@notice Collect the ETH from the staking contract and send it to the multisig\n  function collectEth() external {\n    require(msg.sender == multisig, \"Not multisig\");\n    uint256 ethToTransfer = ethToCollect;\n    ethToCollect = 0;\n    WETH.safeTransfer(multisig, ethToTransfer);\n  }\n\n  ///@notice set the boost periods for extra fyde points\n  function setBoostPeriods(BoostPeriod[] calldata _boostPeriods) external onlyOwner {\n    delete boostPeriods;\n    for (uint256 i; i < _boostPeriods.length; ++i) {\n      boostPeriods.push(_boostPeriods[i]);\n    }\n  }\n\n  /*//////////////////////////////////////////////////////////////\n                            USER FUNCTIONS\n  //////////////////////////////////////////////////////////////*/\n\n  constructor(address _owner, address _multisig) Ownable(_owner) {\n    lastUpdateTime = uint64(block.timestamp);\n    multisig = _multisig;\n  }\n\n  function setStartAndEndTime(uint64 _start_date, uint64 _period_finish) external onlyOwner {\n    start_date = _start_date;\n    period_finish = _period_finish;\n  }\n\n  /// @notice Stake WETH\n  /// @param amount The amount of WETH tokens to stake\n  function stake(uint256 amount) external {\n    if (block.timestamp < start_date || block.timestamp > period_finish) revert NotAllowed();\n    if (amount == 0) revert ZeroAmount();\n\n    // Apply fees\n    uint256 fee = amount * FEE_RATE / 100e18;\n    uint256 amountAfterFee = amount - fee;\n\n    // We load var\n    uint256 rewardPerETH = rewardPerToken();\n    uint256 rewardPerETHFyde = rewardPerTokenFyde();\n\n    // Perform state update for eth points\n    rewardPerTokenStored = rewardPerETH;\n    rewards[msg.sender] =\n      earned(msg.sender, balanceOf[msg.sender], rewardPerETH, rewards[msg.sender]);\n    userRewardPerTokenPaid[msg.sender] = rewardPerETH;\n\n    // Perform state update for fyde points\n    rewardPerTokenStoredFyde = rewardPerETHFyde;\n    rewardsFyde[msg.sender] =\n      earnedFyde(msg.sender, balanceOf[msg.sender], rewardPerETHFyde, rewardsFyde[msg.sender]);\n    userRewardPerTokenPaidFyde[msg.sender] = rewardPerETHFyde;\n\n    // general\n    lastUpdateTime = lastTimeRewardApplicable();\n    totalSupply += amountAfterFee;\n    balanceOf[msg.sender] += amountAfterFee;\n    feeToCollect += fee;\n    ethToCollect += amountAfterFee;\n\n    // Transfer WETH\n    WETH.safeTransferFrom(msg.sender, address(this), amount);\n    emit Staked(msg.sender, amount);\n  }\n\n  /*//////////////////////////////////////////////////////////////\n                            VIEW FUNCTIONS\n  //////////////////////////////////////////////////////////////*/\n\n  /// @notice The latest time at which stakers are earning rewards.\n  function lastTimeRewardApplicable() public view returns (uint64) {\n    return block.timestamp < period_finish ? uint64(block.timestamp) : period_finish;\n  }\n\n  /// @notice The amount of reward tokens each staked token has earned so far\n  function rewardPerToken() public view returns (uint256) {\n    return totalSupply == 0\n      ? rewardPerTokenStored\n      : rewardPerTokenStored\n        + (PRECISION * (lastTimeRewardApplicable() - lastUpdateTime) * REWARD_RATE / 1e18);\n  }\n\n  function earned(address _user, uint256 _userBalance, uint256 _rewardPerToken, uint256 _userReward)\n    public\n    view\n    returns (uint256)\n  {\n    return\n      _userReward + _userBalance * (_rewardPerToken - userRewardPerTokenPaid[_user]) / PRECISION;\n  }\n\n  function getReward(address user) external view returns (uint256) {\n    return earned(user, balanceOf[user], rewardPerToken(), rewards[user]);\n  }\n\n  /// @notice The amount of reward tokens each staked token has earned so far\n  function rewardPerTokenFyde() public view returns (uint256) {\n    return totalSupply == 0\n      ? rewardPerTokenStoredFyde\n      : rewardPerTokenStoredFyde\n        + (PRECISION * (lastTimeRewardApplicable() - lastUpdateTime) * rewardRateFyde() / totalSupply);\n  }\n\n  function earnedFyde(\n    address _user,\n    uint256 _userBalance,\n    uint256 _rewardPerToken,\n    uint256 _userReward\n  ) public view returns (uint256) {\n    return\n      _userReward + _userBalance * (_rewardPerToken - userRewardPerTokenPaidFyde[_user]) / PRECISION;\n  }\n\n  function getRewardFyde(address user) external view returns (uint256) {\n    return earnedFyde(user, balanceOf[user], rewardPerTokenFyde(), rewardsFyde[user]);\n  }\n\n  function rewardRateFyde() public view returns (uint256) {\n    uint256 rateMultiplier;\n    uint256 totalTime;\n    uint256 timeInPeriod;\n    uint256 currTime = block.timestamp;\n    for (uint256 i; i < boostPeriods.length; ++i) {\n      currTime = currTime - timeInPeriod;\n      uint256 nextTimeStamp =\n        currTime > boostPeriods[i].timeStamp ? currTime : boostPeriods[i].timeStamp;\n      uint256 lastUpdate =\n        boostPeriods[i].timeStamp > lastUpdateTime ? boostPeriods[i].timeStamp : lastUpdateTime;\n      timeInPeriod = nextTimeStamp - lastUpdate;\n      totalTime += timeInPeriod;\n\n      rateMultiplier += timeInPeriod * boostPeriods[i].multiplier;\n      if (lastUpdateTime > boostPeriods[i].timeStamp) break;\n    }\n    return totalTime == 0 ? 0 : REWARD_RATE * rateMultiplier / totalTime / 1000;\n  }\n}\n"
      },
      "src/utils/Ownable.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.19;\n\n///@title Ownable contract\n/// @notice Simple 2step owner authorization combining solmate and OZ implementation\nabstract contract Ownable {\n  /*//////////////////////////////////////////////////////////////\n                             STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n  ///@notice Address of the owner\n  address public owner;\n\n  ///@notice Address of the pending owner\n  address public pendingOwner;\n\n  /*//////////////////////////////////////////////////////////////\n                                 EVENTS\n    //////////////////////////////////////////////////////////////*/\n\n  event OwnershipTransferred(address indexed user, address indexed newOner);\n  event OwnershipTransferStarted(address indexed user, address indexed newOwner);\n  event OwnershipTransferCanceled(address indexed pendingOwner);\n\n  /*//////////////////////////////////////////////////////////////\n                                 ERROR\n    //////////////////////////////////////////////////////////////*/\n\n  error Unauthorized();\n\n  /*//////////////////////////////////////////////////////////////\n                               CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n  constructor(address _owner) {\n    owner = _owner;\n\n    emit OwnershipTransferred(address(0), _owner);\n  }\n\n  /*//////////////////////////////////////////////////////////////\n                             OWNERSHIP LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n  ///@notice Transfer ownership to a new address\n  ///@param newOwner address of the new owner\n  ///@dev newOwner have to acceptOwnership\n  function transferOwnership(address newOwner) external onlyOwner {\n    pendingOwner = newOwner;\n    emit OwnershipTransferStarted(msg.sender, pendingOwner);\n  }\n\n  ///@notice NewOwner accept the ownership, it transfer the ownership to newOwner\n  function acceptOwnership() external {\n    if (msg.sender != pendingOwner) revert Unauthorized();\n    address oldOwner = owner;\n    owner = pendingOwner;\n    delete pendingOwner;\n    emit OwnershipTransferred(oldOwner, owner);\n  }\n\n  ///@notice Cancel the ownership transfer\n  function cancelTransferOwnership() external onlyOwner {\n    emit OwnershipTransferCanceled(pendingOwner);\n    delete pendingOwner;\n  }\n\n  modifier onlyOwner() {\n    if (msg.sender != owner) revert Unauthorized();\n    _;\n  }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/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"
      },
      "lib/openzeppelin-contracts/contracts/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"
      },
      "lib/openzeppelin-contracts/contracts/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"
      },
      "lib/openzeppelin-contracts/contracts/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"
      }
    },
    "settings": {
      "remappings": [
        "@uniswap/v3-core/=lib/v3-core/",
        "@uniswap/v3-periphery/=lib/v3-periphery/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
        "forge-std/=lib/forge-std/src/",
        "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
        "openzeppelin/=lib/openzeppelin-contracts/contracts/",
        "solmate/=lib/solmate/src/",
        "synthetix-v3/=lib/synthetix-v3/",
        "v3-core/=lib/v3-core/contracts/",
        "v3-periphery/=lib/v3-periphery/contracts/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "libraries": {}
    }
  }}