Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x679D4C1cC6855C57726BEA1784F578315d6431f6
Balance 0 ETH
Nonce 1
Code Size 8525 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

8525 bytes
0x6080604052600436106101bc575f3560e01c806375421af3116100f2578063c00f60c411610092578063db2296cd11610062578063db2296cd146104c1578063e00bfe50146104dd578063eea94dab146104fc578063fd92bff214610510575f80fd5b8063c00f60c414610472578063caa648b414610486578063d0e30db01461049a578063d9fb643a146104a2575f80fd5b80639e354677116100cd5780639e354677146103f4578063ab033ea914610413578063ac33a27314610432578063b9a5e71914610453575f80fd5b806375421af3146103885780637ca9c0f9146103b157806383b39e23146103d3575f80fd5b80632e1a7d4d1161015d57806352efea6e1161013857806352efea6e146103235780635aa6e675146103375780636c23ab4c14610355578063709d039d14610369575f80fd5b80632e1a7d4d1461029a578063481c6a75146102b95780634aa4a4fc14610304575f80fd5b80630d25a957116101985780630d25a95714610223578063162275f4146102375780631b63a9ec1461024b5780631c2ca2fd14610277575f80fd5b80621a5597146101c757806303f112e5146101ee57806306fdde0314610202575f80fd5b366101c357005b5f80fd5b3480156101d2575f80fd5b506101db61052f565b6040519081526020015b60405180910390f35b3480156101f9575f80fd5b506101db61053f565b34801561020d575f80fd5b5061021661054f565b6040516101e59190611afb565b34801561022e575f80fd5b506101db606481565b348015610242575f80fd5b506101db6105db565b348015610256575f80fd5b5061026a610265366004611c26565b6105fe565b6040516101e59190611cda565b348015610282575f80fd5b5061028b610676565b6040516101e593929190611d1a565b3480156102a5575f80fd5b506101db6102b4366004611d3e565b61069d565b3480156102c4575f80fd5b506102ec7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd881565b6040516001600160a01b0390911681526020016101e5565b34801561030f575f80fd5b506004546102ec906001600160a01b031681565b34801561032e575f80fd5b506101db61099a565b348015610342575f80fd5b505f546102ec906001600160a01b031681565b348015610360575f80fd5b506101db610bf6565b348015610374575f80fd5b506002546102ec906001600160a01b031681565b348015610393575f80fd5b5061039c610c60565b604080519283526020830191909152016101e5565b3480156103bc575f80fd5b506103c5610c73565b6040516101e5929190611d55565b3480156103de575f80fd5b506103f26103ed366004611d82565b610d5c565b005b3480156103ff575f80fd5b5061028b61040e366004611c26565b610e8e565b34801561041e575f80fd5b506103f261042d366004611df6565b610e9b565b34801561043d575f80fd5b50610446610f50565b6040516101e59190611e11565b34801561045e575f80fd5b506006546102ec906001600160a01b031681565b34801561047d575f80fd5b506101db610f5c565b348015610491575f80fd5b506101db610f6c565b6103f2610f87565b3480156104ad575f80fd5b506005546102ec906001600160a01b031681565b3480156104cc575f80fd5b506101db683635c9adc5dea0000081565b3480156104e8575f80fd5b506003546102ec906001600160a01b031681565b348015610507575f80fd5b506103f2611084565b34801561051b575f80fd5b506101db61052a366004611d3e565b611146565b5f610538610676565b9392505050565b5f61054a60076111a7565b905090565b6001805461055c90611e23565b80601f016020809104026020016040519081016040528092919081815260200182805461058890611e23565b80156105d35780601f106105aa576101008083540402835291602001916105d3565b820191905f5260205f20905b8154815290600101906020018083116105b657829003601f168201915b505050505081565b5f805f6105e6610676565b925092505080826105f79190611e6f565b9250505090565b600654604051635c625c2d60e11b81526060916001600160a01b03169063b8c4b85a9061062f908590600401611e11565b5f60405180830381865afa158015610649573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526106709190810190611e91565b92915050565b60605f805f61068560076111b0565b9050610690816111bc565b9196909550909350915050565b5f7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b031633146106e757604051631db8f31760e31b815260040160405180910390fd5b815f03610707576040516348d0b82d60e01b815260040160405180910390fd5b6003546040516370a0823160e01b815230600482015283916001600160a01b0316906370a0823190602401602060405180830381865afa15801561074d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107719190611f7e565b10156107905760405163171a6e5960e11b815260040160405180910390fd5b60648210156107a057505f919050565b6003546006546107bd916001600160a01b03908116911684611352565b815f683635c9adc5dea000006107d4600184611f95565b6107de9190611fa8565b6107e9906001611e6f565b90505f8167ffffffffffffffff81111561080557610805611b2d565b60405190808252806020026020018201604052801561082e578160200160208202803683370190505b5090505f5b83156108a157683635c9adc5dea00000841161084f578361085a565b683635c9adc5dea000005b82828151811061086c5761086c611fc7565b60200260200101818152505081818151811061088a5761088a611fc7565b602090810291909101015190930392600101610833565b600654604051636b34082160e11b81525f916001600160a01b03169063d6681042906108d39086903090600401611fdb565b5f604051808303815f875af11580156108ee573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526109159190810190612004565b80519091505f5b8181101561095a5761095183828151811061093957610939611fc7565b6020026020010151600761145290919063ffffffff16565b5060010161091c565b50879650471561098e5761098e7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd84761145d565b5050505050505b919050565b5f7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b031633146109e457604051631db8f31760e31b815260040160405180910390fd5b6003546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa158015610a2a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a4e9190611f7e565b9050805f03610a5e575f91505090565b610a67816114fc565b600354604051633d7ad0b760e21b81523060048201529193505f916001600160a01b039091169063f5eb42dc90602401602060405180830381865afa158015610ab2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ad69190611f7e565b90508015610bf15760035f9054906101000a90046001600160a01b03166001600160a01b0316638fcb4e5b7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b0316637b0c1f296040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b5d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b819190612090565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303815f875af1158015610bcb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bef9190611f7e565b505b505090565b6003546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa158015610c3c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061054a9190611f7e565b5f80610c6a610676565b94909350915050565b600654604051637d031b6560e01b815230600482015260609182916001600160a01b0390911690637d031b65906024015f60405180830381865afa158015610cbd573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ce49190810190612004565b600654604051635c625c2d60e11b81529193506001600160a01b03169063b8c4b85a90610d15908590600401611e11565b5f60405180830381865afa158015610d2f573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610d569190810190611e91565b90509091565b60065460405163e3afe0a360e01b81526001600160a01b039091169063e3afe0a390610d8e90859085906004016120ab565b5f604051808303815f87803b158015610da5575f80fd5b505af1158015610db7573d5f803e3d5ffd5b5050835191505f90505b81811015610dff57610df6848281518110610dde57610dde611fc7565b6020026020010151600761153290919063ffffffff16565b50600101610dc1565b50610e897f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b0316637b0c1f296040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e5f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e839190612090565b4761145d565b505050565b60605f80610690846111bc565b5f546001600160a01b03163314610ec557604051630be1411f60e31b815260040160405180910390fd5b6001600160a01b038116610eec576040516372f5fcdf60e11b815260040160405180910390fd5b5f546040516001600160a01b038381168252909116907f2276211a3f2c7bc1943fe83cc63f8f970204ff6a4b83c690df2bc54d8f2792ad9060200160405180910390a25f80546001600160a01b0319166001600160a01b0392909216919091179055565b606061054a60076111b0565b5f610f65610676565b5092915050565b5f610f756105db565b610f7d610bf6565b61054a9190611e6f565b7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b03163314610fd057604051631db8f31760e31b815260040160405180910390fd5b345f03610ff0576040516348d0b82d60e01b815260040160405180910390fd5b60035460405163a1903eab60e01b81525f60048201819052916001600160a01b03169063a1903eab90349060240160206040518083038185885af115801561103a573d5f803e3d5ffd5b50505050506040513d601f19601f8201168201806040525081019061105f9190611f7e565b9050805f036110815760405163b6acf41560e01b815260040160405180910390fd5b50565b5f61108f60076111b0565b90505f61109b82610e8e565b505080519091505f5b81811015610dff5760065483516001600160a01b039091169063f8444436908590849081106110d5576110d5611fc7565b60200260200101516040518263ffffffff1660e01b81526004016110fb91815260200190565b5f604051808303815f87803b158015611112575f80fd5b505af1158015611124573d5f803e3d5ffd5b5050505061113d838281518110610dde57610dde611fc7565b506001016110a4565b5f7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b0316331461119057604051631db8f31760e31b815260040160405180910390fd5b815f0361119e57505f919050565b610670826114fc565b5f610670825490565b60605f6105388361153d565b60605f805f84519050805f036111d857505f915081905061134b565b8067ffffffffffffffff8111156111f1576111f1611b2d565b60405190808252806020026020018201604052801561121a578160200160208202803683370190505b50600654604051635c625c2d60e11b81529195505f916001600160a01b039091169063b8c4b85a90611250908990600401611e11565b5f60405180830381865afa15801561126a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526112919190810190611e91565b80519091505f90815b81811015611344575f8482815181106112b5576112b5611fc7565b602002602001015190508060a00151156112d2575060010161129a565b80608001511561132c578982815181106112ee576112ee611fc7565b602002602001015189858060010196508151811061130e5761130e611fc7565b602090810291909101015280516113259089611e6f565b975061133b565b80516113389088611e6f565b96505b5060010161129a565b5050855250505b9193909250565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291515f928392908716916113ad91906120cf565b5f604051808303815f865af19150503d805f81146113e6576040519150601f19603f3d011682016040523d82523d5f602084013e6113eb565b606091505b509150915081801561141557508051158061141557508080602001905181019061141591906120ea565b61144b5760405162461bcd60e51b8152602060048201526002602482015261534160f01b60448201526064015b60405180910390fd5b5050505050565b5f6105388383611596565b604080515f808252602082019092526001600160a01b03841690839060405161148691906120cf565b5f6040518083038185875af1925050503d805f81146114c0576040519150601f19603f3d011682016040523d82523d5f602084013e6114c5565b606091505b5050905080610e895760405162461bcd60e51b815260206004820152600360248201526253544560e81b6044820152606401611442565b5f611506826115e2565b90506109957f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd84761145d565b5f61053883836119f6565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561158a57602002820191905f5260205f20905b815481526020019060010190808311611576575b50505050509050919050565b5f8181526001830160205260408120546115db57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610670565b505f610670565b60055460405162b0e38960e81b8152600481018390525f9182916001600160a01b039091169063b0e3890090602401602060405180830381865afa15801561162c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116509190611f7e565b6002546005546004805460405163650fc20d60e11b81526fffffffffffffffffffffffffffffffff8616928101929092526001600160a01b039283166024830152821660448201529293505f9291169063ca1f841a90606401602060405180830381865afa1580156116c4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116e89190611f7e565b60025460035460405163373033eb60e21b8152600481018890526001600160a01b0391821660248201529293505f9291169063dcc0cfac90604401602060405180830381865afa15801561173e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117629190611f7e565b905081158015611770575080155b1561178e576040516356d6a99560e01b815260040160405180910390fd5b5f81831161179c578161179e565b825b6002546004805460405163a74984c760e01b81526001600160a01b0391821692810192909252602482018490529293505f929091169063a74984c790604401602060405180830381865afa1580156117f8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061181c9190611f7e565b90505f8385111561194f57506005546003546001600160a01b03918216916118469116828a611352565b600554604051630ea598cb60e41b8152600481018a90526001600160a01b039091169063ea598cb0906024016020604051808303815f875af115801561188e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118b29190611f7e565b6002549098506118cd9082906001600160a01b03168a611352565b6002546040516386b3abbb60e01b81526001600160a01b038381166004830152602482018b905260448201859052909116906386b3abbb906064016020604051808303815f875af1158015611924573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119489190611f7e565b965061098e565b506003546002546001600160a01b039182169161196f918391168a611352565b600254604051631818888b60e21b81526001600160a01b038381166004830152602482018b90526044820185905290911690636062222c906064016020604051808303815f875af11580156119c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ea9190611f7e565b98975050505050505050565b5f8181526001830160205260408120548015611ad0575f611a18600183611f95565b85549091505f90611a2b90600190611f95565b9050808214611a8a575f865f018281548110611a4957611a49611fc7565b905f5260205f200154905080875f018481548110611a6957611a69611fc7565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080611a9b57611a9b612103565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610670565b5f915050610670565b5f5b83811015611af3578181015183820152602001611adb565b50505f910152565b602081525f8251806020840152611b19816040850160208701611ad9565b601f01601f19169190910160400192915050565b634e487b7160e01b5f52604160045260245ffd5b60405160c0810167ffffffffffffffff81118282101715611b6457611b64611b2d565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611b9357611b93611b2d565b604052919050565b5f67ffffffffffffffff821115611bb457611bb4611b2d565b5060051b60200190565b5f82601f830112611bcd575f80fd5b81356020611be2611bdd83611b9b565b611b6a565b82815260059290921b84018101918181019086841115611c00575f80fd5b8286015b84811015611c1b5780358352918301918301611c04565b509695505050505050565b5f60208284031215611c36575f80fd5b813567ffffffffffffffff811115611c4c575f80fd5b611c5884828501611bbe565b949350505050565b5f8151808452602080850194508084015f5b83811015611ccf5781518051885283810151848901526040808201516001600160a01b0316908901526060808201519089015260808082015115159089015260a09081015115159088015260c09096019590820190600101611c72565b509495945050505050565b602081525f6105386020830184611c60565b5f8151808452602080850194508084015f5b83811015611ccf57815187529582019590820190600101611cfe565b606081525f611d2c6060830186611cec565b60208301949094525060400152919050565b5f60208284031215611d4e575f80fd5b5035919050565b604081525f611d676040830185611cec565b8281036020840152611d798185611c60565b95945050505050565b5f8060408385031215611d93575f80fd5b823567ffffffffffffffff80821115611daa575f80fd5b611db686838701611bbe565b93506020850135915080821115611dcb575f80fd5b50611dd885828601611bbe565b9150509250929050565b6001600160a01b0381168114611081575f80fd5b5f60208284031215611e06575f80fd5b813561053881611de2565b602081525f6105386020830184611cec565b600181811c90821680611e3757607f821691505b602082108103611e5557634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561067057610670611e5b565b80518015158114610995575f80fd5b5f6020808385031215611ea2575f80fd5b825167ffffffffffffffff811115611eb8575f80fd5b8301601f81018513611ec8575f80fd5b8051611ed6611bdd82611b9b565b81815260c09182028301840191848201919088841115611ef4575f80fd5b938501935b83851015611f725780858a031215611f10575f8081fd5b611f18611b41565b855181528686015187820152604080870151611f3381611de2565b90820152606086810151908201526080611f4e818801611e82565b9082015260a0611f5f878201611e82565b9082015283529384019391850191611ef9565b50979650505050505050565b5f60208284031215611f8e575f80fd5b5051919050565b8181038181111561067057610670611e5b565b5f82611fc257634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b604081525f611fed6040830185611cec565b905060018060a01b03831660208301529392505050565b5f6020808385031215612015575f80fd5b825167ffffffffffffffff81111561202b575f80fd5b8301601f8101851361203b575f80fd5b8051612049611bdd82611b9b565b81815260059190911b82018301908381019087831115612067575f80fd5b928401925b828410156120855783518252928401929084019061206c565b979650505050505050565b5f602082840312156120a0575f80fd5b815161053881611de2565b604081525f6120bd6040830185611cec565b8281036020840152611d798185611cec565b5f82516120e0818460208701611ad9565b9190910192915050565b5f602082840312156120fa575f80fd5b61053882611e82565b634e487b7160e01b5f52603160045260245ffdfea2646970667358221220612627996a8c74d967f9f193429e8739aeef0243444108089ebee8508244ed6b64736f6c63430008150033

Verified Source Code Full Match

Compiler: v0.8.21+commit.d9974bed EVM: shanghai Optimization: Yes (200 runs)
IStETH.sol 48 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity =0.8.21;

import {IERC20} from "oz/token/ERC20/IERC20.sol";
import {IERC20Permit} from "oz/token/ERC20/extensions/IERC20Permit.sol";

/// @notice Interface defining a Lido liquid staking pool
/// @dev see also [Lido liquid staking pool core contract](https://docs.lido.fi/contracts/lido)
interface IStETH is IERC20, IERC20Permit {
    /**
     * @notice Send funds to the pool with optional _referral parameter
     * @dev This function is alternative way to submit funds. Supports optional referral address.
     * @return Amount of StETH shares generated
     */
    function submit(address _referral) external payable returns (uint256);

    /**
     * @return the amount of shares owned by `_account`.
     */
    function sharesOf(address _account) external view returns (uint256);

    /**
     * @notice Moves `_sharesAmount` token shares from the caller's account to the `_recipient` account.
     *
     * @return amount of transferred tokens.
     * Emits a `TransferShares` event.
     * Emits a `Transfer` event.
     *
     * Requirements:
     *
     * - `_recipient` cannot be the zero address.
     * - the caller must have at least `_sharesAmount` shares.
     * - the contract must not be paused.
     *
     * @dev The `_sharesAmount` argument is the amount of shares, not tokens.
     */
    function transferShares(address _recipient, uint256 _sharesAmount) external returns (uint256);

    /**
     * @return the amount of shares that corresponds to `_ethAmount` protocol-controlled Ether.
     */
    function getSharesByPooledEth(uint256 _pooledEthAmount) external view returns (uint256);

    /**
     * @return the amount of Ether that corresponds to `_sharesAmount` token shares.
     */
    function getPooledEthByShares(uint256 _sharesAmount) external view returns (uint256);
}
Strategy.sol 102 lines
// SPDX-License-Identifier: MIT
pragma solidity =0.8.21;

import {IStrategyManager} from "../interfaces/IStrategyManager.sol";

error Strategy__ZeroAddress();
error Strategy__NotManager();
error Strategy__NotGovernance();

abstract contract Strategy {
    address payable public immutable manager;
    address public governance;
    string public name;

    modifier onlyGovernance() {
        if (governance != msg.sender) revert Strategy__NotGovernance();
        _;
    }

    event TransferGovernance(address indexed oldOwner, address newOwner);

    constructor(address payable _manager, string memory _name) {
        if (_manager == address(0)) revert Strategy__NotManager();

        governance = msg.sender;
        manager = _manager;
        name = _name;
    }

    /**
     * @dev Throws if the caller is not the manager address.
     */
    modifier onlyManager() {
        if (manager != msg.sender) revert Strategy__NotManager();
        _;
    }

    /**
     * @dev Deposit function to deposit funds into the strategy.
     */
    function deposit() external payable virtual onlyManager {}

    /**
     * @dev Withdraw function to withdraw funds from the strategy.
     * @param _amount The amount of funds to withdraw.
     * @return actualAmount The actual amount withdrawn.
     */
    function withdraw(uint256 _amount) external virtual onlyManager returns (uint256 actualAmount) {}

    /**
     * @dev Instant withdraw function to immediately withdraw funds from the strategy.
     * @param _amount The amount of funds to withdraw.
     * @return actualAmount The actual amount withdrawn.
     */
    function instantWithdraw(uint256 _amount) external virtual onlyManager returns (uint256 actualAmount) {}

    /**
     * @dev Clear function to clear any allocated funds or assets in the strategy.
     * @return amount The amount of funds cleared.
     */
    function clear() external virtual onlyManager returns (uint256 amount) {}

    /**
     * @dev Execute pending request function to execute any pending transactions in the strategy.
     */
    function claimAllPendingAssets() external virtual;

    /**
     * @dev Get all value function to get the total value of assets held in the strategy.
     * @return value The total value of assets held in the strategy.
     */
    function getTotalValue() public virtual returns (uint256 value);

    /**
     * @dev Get pending value function to get the pending value of assets in the strategy.
     * @return value The pending value of assets in the strategy.
     */
    function getPendingValue() public virtual returns (uint256 value);

    /**
     * @dev Get invested value function to get the currently invested value of assets in the strategy.
     * @return value The currently invested value of assets in the strategy.
     */
    function getInvestedValue() public virtual returns (uint256 value);

    /**
     * @dev Check pending status function to check the status of pending transactions in the strategy.
     * @return pending The amount of pending transactions.
     * @return executable The claimable amount of transactions ready to be executed.
     */
    function checkPendingStatus() external virtual returns (uint256 pending, uint256 executable);

    /**
     * @dev Sets the governance address.
     * @param _governance The address to set as the new governance.
     */
    function setGovernance(address _governance) external onlyGovernance {
        if (_governance == address(0)) revert Strategy__ZeroAddress();
        emit TransferGovernance(governance, _governance);
        governance = _governance;
    }
}
IWStETH.sol 48 lines
// SPDX-License-Identifier: MIT
pragma solidity =0.8.21;

/**
 * @title Wrapped stETH Interface
 * @dev Interface for a contract representing wrapped staked Ether (wstETH).
 */
abstract contract IWStETH {
    /**
     * @dev Unwraps a specified amount of wstETH tokens into stETH tokens.
     * @param _wstETHAmount The amount of wstETH tokens to unwrap.
     * @return The amount of stETH tokens received.
     */
    function unwrap(uint256 _wstETHAmount) external virtual returns (uint256);

    /**
     * @notice Exchanges stETH to wstETH
     * @param _stETHAmount amount of stETH to wrap in exchange for wstETH
     * @dev Requirements:
     *  - `_stETHAmount` must be non-zero
     *  - msg.sender must approve at least `_stETHAmount` stETH to this
     *    contract.
     *  - msg.sender must have at least `_stETHAmount` of stETH.
     * User should first approve _stETHAmount to the WstETH contract
     * @return Amount of wstETH user receives after wrap
     */
    function wrap(uint256 _stETHAmount) external virtual returns (uint256);

    /**
     * @dev Converts a specified amount of stETH tokens into wstETH tokens.
     * @param _stETHAmount The amount of stETH tokens to convert.
     * @return The amount of wstETH tokens received.
     */
    function getWstETHByStETH(uint256 _stETHAmount) external view virtual returns (uint256);

    /**
     * @dev Converts a specified amount of wstETH tokens into stETH tokens.
     * @param _wstETHAmount The amount of wstETH tokens to convert.
     * @return The amount of stETH tokens received.
     */
    function getStETHByWstETH(uint256 _wstETHAmount) external view virtual returns (uint256);

    /**
     * @dev Retrieves the current exchange rate of stETH to wstETH.
     * @return The current exchange rate of stETH to wstETH.
     */
    function stEthPerToken() external view virtual returns (uint256);
}
ISwapManager.sol 76 lines
// SPDX-License-Identifier: MIT
pragma solidity =0.8.21;

/**
 * @title SwapManager Interface
 * @dev Interface for a contract managing token swaps.
 */
interface ISwapManager {
    /**
     * @dev Swaps a specified amount of input tokens for output tokens.
     * @param tokenIn The address of the input token.
     * @param amountIn The amount of input tokens to swap.
     * @return amountOut  The amount of output tokens received.
     */
    function swap(address tokenIn, uint256 amountIn) external returns (uint256 amountOut);

    /**
     * @dev Sets a Uniswap V3 pool address on the whitelist for a specific token.
     * @param token The address of the token.
     * @param pool The address of the V3 pool.
     */
    function setWhitelistV3Pool(address token, address pool) external;

    /**
     * @dev Sets a Curve pool address on the whitelist for a specific token.
     * @param token The address of the token.
     * @param pool The address of the Curve pool.
     */
    function setWhitelistCurvePool(address token, address pool) external;

    /**
     * @dev Sets the fee for a specific pool.
     * @param token The address of the token.
     * @param fees The fee to be set.
     */
    function setPoolFee(address token, uint24 fees) external;
    function transferETH() external;

    /**
     * @dev Estimates the output amount of a token swap using the fair quote method.
     * @param tokenIn The address of the input token.
     * @param amountIn The amount of input tokens.
     * @return amountOut The estimated amount of output tokens.
     */
    function getFairQuote(address tokenIn, uint256 amountIn) external returns (uint256 amountOut);

    function swapUinv3(address tokenIn, uint256 amountIn, uint256 amountOutMinimum)
        external
        returns (uint256 amountOut);

    function swapCurve(address tokenIn, uint256 amountIn, uint256 amountOutMinimum)
        external
        returns (uint256 amountOut);

    function getMinimumAmount(address token, uint256 amount) external view returns (uint256);

    /**
     * @dev Estimates the output amount of a token swap in a Curve pool.
     * @param amountIn The amount of input tokens.
     * @param tokenIn The address of the input token.
     * @return amountOut The estimated amount of output tokens.
     */
    function estimateCurveAmountOut(uint256 amountIn, address tokenIn) external view returns (uint256 amountOut);

    /**
     * @dev Estimates the output amount of a token swap in a V3 pool.
     * @param amountIn The amount of input tokens.
     * @param tokenIn The address of the input token.
     * @param tokenOut The address of the output token.
     * @return amountOut The estimated amount of output tokens.
     */
    function estimateV3AmountOut(uint128 amountIn, address tokenIn, address tokenOut)
        external
        view
        returns (uint256 amountOut);
}
LidoStEthStrategy.sol 430 lines
// SPDX-License-Identifier: MIT
pragma solidity =0.8.21;

import {EnumerableSet} from "oz/utils/structs/EnumerableSet.sol";
import {Strategy} from "./Strategy.sol";

import {IStETH} from "../interfaces/IStETH.sol";
import {IWStETH} from "../interfaces/IWStETH.sol";
import {ISwapManager} from "../interfaces/ISwapManager.sol";
import {IStrategyManager} from "../interfaces/IStrategyManager.sol";
import {TransferHelper} from "v3-periphery/libraries/TransferHelper.sol";
import {IWithdrawalQueueERC721} from "../interfaces/IWithdrawalQueueERC721.sol";

error Strategy__ZeroAmount();
error Strategy__LidoDeposit();
error Strategy__ZeroAddress();
error Strategy__ZeroPoolLiquidity();
error Strategy__InsufficientBalance();

/**
 * @title LidoStEthStrategy
 * @author Mavvverick
 * @dev A strategy contract for generating eth yield by managing Lido staked ETH (stETH)
 */
contract LidoStEthStrategy is Strategy {
    using EnumerableSet for EnumerableSet.UintSet;

    /// @notice minimal amount of stETH that is possible to withdraw
    uint256 public constant MIN_STETH_WITHDRAWAL_AMOUNT = 1_00;

    /// @notice maximum amount of stETH that is possible to withdraw by a single request
    /// Prevents accumulating too much funds per single request fulfillment in the future.
    /// @dev To withdraw larger amounts, it's recommended to split it to several requests
    uint256 public constant MAX_STETH_WITHDRAWAL_AMOUNT = 1_000 * 10 ** 18;

    address public swapManager;
    IStETH public STETH; //strategy token
    address public WETH9; //swap token for uniV3
    address public WSTETH; //swap token for uniV3
    IWithdrawalQueueERC721 public stETHWithdrawalQueue;

    EnumerableSet.UintSet private withdrawQueue;

    /**
     * @param _stETHAdress The address of the stETH contract
     * @param _stETHWithdrawal The address of the stETH withdrawal contract
     * @param _wstETHAdress The address of the wrapped stETH (wstETH) contract
     * @param _weth9 The address of the WETH9 contract
     * @param _swapManager The address of the SwapManager contract
     * @param _manager The address of the strategy manager
     * @param _name The name of the strategy
     */
    constructor(
        address _stETHAdress,
        address _stETHWithdrawal,
        address _wstETHAdress,
        address _weth9,
        address _swapManager,
        address payable _manager,
        string memory _name
    ) Strategy(_manager, _name) {
        if (
            _stETHAdress == address(0) || _stETHWithdrawal == address(0) || _wstETHAdress == address(0)
                || _weth9 == address(0) || _swapManager == address(0)
        ) revert Strategy__ZeroAddress();

        STETH = IStETH(_stETHAdress);
        stETHWithdrawalQueue = IWithdrawalQueueERC721(_stETHWithdrawal);
        swapManager = _swapManager;
        WSTETH = _wstETHAdress;
        WETH9 = _weth9;
    }

    /**
     * @dev Internal function to perform an instant withdrawal of stETH using swap pools.
     * @param _amount The amount of stETH to withdraw
     * @return actualAmount The actual amount of ETH withdrawn
     */
    function _instantWithdraw(uint256 _amount) internal returns (uint256 actualAmount) {
        // swap stEth for eth
        actualAmount = _swapUsingFairQuote(_amount);
        TransferHelper.safeTransferETH(manager, address(this).balance);
    }

    /**
     * @dev Internal function to swap stETH for ETH using UniV3 or Curve.
     * @param _amountIn The amount of stETH to swap
     * @return actualAmount The actual amount of ETH received after swapping
     */
    function _swapUsingFairQuote(uint256 _amountIn) internal returns (uint256 actualAmount) {
        uint256 amountInForV3 = IWStETH(WSTETH).getWstETHByStETH(_amountIn);
        uint256 v3Out = ISwapManager(swapManager).estimateV3AmountOut(uint128(amountInForV3), WSTETH, WETH9);
        uint256 curveOut = ISwapManager(swapManager).estimateCurveAmountOut(_amountIn, address(STETH));

        if (v3Out == 0 && curveOut == 0) revert Strategy__ZeroPoolLiquidity();

        uint256 quoteAmount = v3Out > curveOut ? v3Out : curveOut;
        uint256 quoteAmountMin = ISwapManager(swapManager).getMinimumAmount(WETH9, quoteAmount);
        address tokenIn;

        if (v3Out > curveOut) {
            tokenIn = WSTETH;
            // wrap stETH for uniswap pool
            TransferHelper.safeApprove(address(STETH), WSTETH, _amountIn);
            _amountIn = IWStETH(WSTETH).wrap(_amountIn);
            TransferHelper.safeApprove(tokenIn, swapManager, _amountIn);
            actualAmount = ISwapManager(swapManager).swapUinv3(tokenIn, _amountIn, quoteAmountMin);
        } else {
            tokenIn = address(STETH);
            TransferHelper.safeApprove(tokenIn, swapManager, _amountIn);
            actualAmount = ISwapManager(swapManager).swapCurve(tokenIn, _amountIn, quoteAmountMin);
        }
    }

    function _checkPendingAssets(uint256[] memory requestIds)
        internal
        view
        returns (uint256[] memory ids, uint256 totalClaimable, uint256 totalPending)
    {
        uint256 requestLen = requestIds.length;
        if (requestLen == 0) return (ids, 0, 0);
        ids = new uint256[](requestLen);

        IWithdrawalQueueERC721.WithdrawalRequestStatus[] memory statuses =
            stETHWithdrawalQueue.getWithdrawalStatus(requestIds);

        uint256 index = 0;
        uint256 len = statuses.length;

        for (uint256 i = 0; i < len;) {
            IWithdrawalQueueERC721.WithdrawalRequestStatus memory status = statuses[i];
            if (status.isClaimed) {
                unchecked {
                    i++;
                }
                continue;
            }
            if (status.isFinalized) {
                unchecked {
                    ids[index++] = requestIds[i];
                }
                totalClaimable += status.amountOfStETH;
            } else {
                totalPending += status.amountOfStETH;
            }

            unchecked {
                i++;
            }
        }

        assembly {
            mstore(ids, index)
        }
    }

    /**
     * @notice Deposit ETH into the Lido stETH contract.
     * @dev Only the strategy manager can call this function.
     */
    function deposit() external payable override onlyManager {
        if (msg.value == 0) revert Strategy__ZeroAmount();
        uint256 shares = STETH.submit{value: msg.value}(address(0));
        if (shares == 0) revert Strategy__LidoDeposit();
    }

    /**
     * @notice Initiate a withdrawal of a specific amount of stETH.
     * @dev Only the strategy manager can call this function.
     * @param _ethAmount The amount of stETH to withdraw.
     * @return actualAmount The actual amount of stETH withdrawn.
     */
    function withdraw(uint256 _ethAmount) external override onlyManager returns (uint256 actualAmount) {
        if (_ethAmount == 0) revert Strategy__ZeroAmount();
        if (STETH.balanceOf(address(this)) < _ethAmount) revert Strategy__InsufficientBalance();

        // Withdrawing as little as 100 wei from the underlying strategy is not economically viable.
        if (_ethAmount < MIN_STETH_WITHDRAWAL_AMOUNT) return 0;

        //approve steth for WithdrawalQueueERC721
        TransferHelper.safeApprove(address(STETH), address(stETHWithdrawalQueue), _ethAmount);

        uint256 remainingBalance = _ethAmount;
        uint256 batchLen = ((_ethAmount - 1) / MAX_STETH_WITHDRAWAL_AMOUNT) + 1;
        uint256[] memory requestedAmounts = new uint256[](batchLen);
        uint256 index;

        while (remainingBalance != 0) {
            requestedAmounts[index] =
                remainingBalance > MAX_STETH_WITHDRAWAL_AMOUNT ? MAX_STETH_WITHDRAWAL_AMOUNT : remainingBalance;
            unchecked {
                remainingBalance -= requestedAmounts[index];
                index++;
            }
        }

        //raise a withdraw request to WithdrawalQueueERC721
        uint256[] memory ids = stETHWithdrawalQueue.requestWithdrawals(requestedAmounts, address(this));

        uint256 idsLen = ids.length;

        // push the withdraw request id
        for (uint256 i = 0; i < idsLen;) {
            withdrawQueue.add(ids[i]);
            unchecked {
                i++;
            }
        }

        actualAmount = _ethAmount;
        if (address(this).balance > 0) {
            TransferHelper.safeTransferETH(manager, address(this).balance);
        }
    }

    /**
     * @notice Claim all pending withdrawal assets from the stETH withdrawal queue.
     * @dev This function claims all pending withdrawal assets and transfers them to the assets vault.
     * Check claimable pending assets before calling this function.
     * The queue will always stay within bounds since withdrawal is requested once per rebase cycle,
     * which is 365 requests in a year for a 1-day epoch cycle or 52 requests in a year for a 7-day epoch cycle
     * If the queue expands to a level where withdrawQueue consumes excessive gas, use claimAllPendingAssetsByIds instead.
     */
    function claimAllPendingAssets() external override {
        uint256[] memory withdrawIds = withdrawQueue.values();
        (uint256[] memory ids,,) = checkPendingAssets(withdrawIds);

        uint256 len = ids.length;
        for (uint256 i = 0; i < len;) {
            stETHWithdrawalQueue.claimWithdrawal(ids[i]);
            // remove claimed request Ids
            withdrawQueue.remove(ids[i]);
            unchecked {
                i++;
            }
        }

        TransferHelper.safeTransferETH(IStrategyManager(manager).assetsVault(), address(this).balance);
    }

    /**
     * @notice Redeems eth amount and deposit redeemed amount in the bridge
     * NB! Array of request ids should be sorted
     * @param claimableRequestIds An array of withdrawal request IDs that are claimable
     * @param hints Array of hints used to find required checkpoint for the request
     *  Reverts if requestIds and hints arrays length differs
     *  Reverts if any requestId or hint in arguments are not valid
     *  Reverts if any request is not finalized or already claimed
     */
    function claimAllPendingAssetsByIds(uint256[] memory claimableRequestIds, uint256[] memory hints) external {
        // Claim withdrawal amount
        // Reverts if any request is not finalized or already claimed
        stETHWithdrawalQueue.claimWithdrawals(claimableRequestIds, hints);

        // remove claimed request Ids
        uint256 requestsLen = claimableRequestIds.length;
        for (uint256 i = 0; i < requestsLen;) {
            withdrawQueue.remove(claimableRequestIds[i]);
            unchecked {
                i++;
            }
        }

        // Transfer the claimed asset to the assets vault
        TransferHelper.safeTransferETH(IStrategyManager(manager).assetsVault(), address(this).balance);
    }

    /**
     * @notice Initiate an instant withdrawal of stETH using swap pools
     * @dev Only the strategy manager can call this function.
     * @param _amount The amount of stETH to withdraw.
     * @return actualAmount The actual amount of stETH withdrawn.
     */
    function instantWithdraw(uint256 _amount) external override onlyManager returns (uint256 actualAmount) {
        if (_amount == 0) return 0;
        actualAmount = _instantWithdraw(_amount);
    }

    /**
     * @notice Clear the strategy by withdrawing all stETH to the assets vault
     * @dev This function withdraws all stETH from the strategy and transfers them to the strategy manager's assets vault.
     * @return amount The amount of stETH withdrawn.
     */
    function clear() external override onlyManager returns (uint256 amount) {
        uint256 balance = STETH.balanceOf(address(this));
        // if stEth shares is zero return actualAmount = 0
        if (balance == 0) return 0;
        amount = _instantWithdraw(balance);

        // Transfer left over dust shares to the asset vault
        uint256 share = STETH.sharesOf(address(this));
        if (share > 0) {
            STETH.transferShares(IStrategyManager(manager).assetsVault(), share);
        }
    }

    /**
     * @notice Check the pending withdrawal assets from the stETH withdrawal queue.
     * @dev This function retrieves the pending withdrawal assets and returns their IDs, total claimable amount, and total pending amount.
     * @return ids An array of withdrawal request IDs.
     * @return totalClaimable The total amount of claimable stETH.
     * @return totalPending The total amount of pending stETH.
     */
    function checkPendingAssets()
        public
        view
        returns (uint256[] memory ids, uint256 totalClaimable, uint256 totalPending)
    {
        uint256[] memory requestIds = withdrawQueue.values();
        (ids, totalClaimable, totalPending) = _checkPendingAssets(requestIds);
    }

    /**
     * @notice Check the pending withdrawal assets from the stETH withdrawal queue.
     * @dev This function retrieves the pending withdrawal assets and returns their IDs, total claimable amount, and total pending amount.
     * @param requestIds An array of withdrawal request IDs
     * @return ids An array of withdrawal request IDs.
     * @return totalClaimable The total amount of claimable stETH.
     * @return totalPending The total amount of pending stETH.
     */
    function checkPendingAssets(uint256[] memory requestIds)
        public
        view
        returns (uint256[] memory ids, uint256 totalClaimable, uint256 totalPending)
    {
        (ids, totalClaimable, totalPending) = _checkPendingAssets(requestIds);
    }

    /**
     * @notice Get the pending and executable assets amount
     * @dev This function retrieves the pending and executable assets from the stETH withdrawal queue.
     * @return pending The total amount of pending stETH.
     * @return executable The total amount of claimable stETH.
     */
    function checkPendingStatus() external view override returns (uint256 pending, uint256 executable) {
        (, executable, pending) = checkPendingAssets();
    }

    /**
     * @notice Retrieves the withdrawal request ids
     * @return requestIds An array of withdrawal request IDs
     */
    function getRequestIds() public view returns (uint256[] memory requestIds) {
        return withdrawQueue.values();
    }

    /**
     * @notice Retrieves the withdrawal request ids
     * @return requestIdsLength An array size of withdrawal request IDs
     */
    function getRequestIdsLen() public view returns (uint256 requestIdsLength) {
        return withdrawQueue.length();
    }

    /**
     * @notice Retrieves the withdrawal status of stETH requests
     * @return requestIds An array of withdrawal request IDs
     * @return statuses An array of withdrawal request statuses
     */
    function getStETHWithdrawalStatus()
        public
        view
        returns (uint256[] memory requestIds, IWithdrawalQueueERC721.WithdrawalRequestStatus[] memory statuses)
    {
        requestIds = stETHWithdrawalQueue.getWithdrawalRequests(address(this));
        statuses = stETHWithdrawalQueue.getWithdrawalStatus(requestIds);
    }

    /**
     * @notice Retrieves the withdrawal status of stETH requests
     * NB! Array of request ids should be sorted
     * @param requestIds An array of stETH withdrawal request IDs for claim
     * @return statuses An array of withdrawal request statuses
     */
    function getStETHWithdrawalStatusForIds(uint256[] memory requestIds)
        public
        view
        returns (IWithdrawalQueueERC721.WithdrawalRequestStatus[] memory statuses)
    {
        statuses = stETHWithdrawalQueue.getWithdrawalStatus(requestIds);
    }

    /**
     * @notice Get the total value of assets managed by the strategy.
     * @dev This function retrieves the total value of assets managed by the strategy, including invested, claimable, and pending values.
     * @return value The total value of assets managed by the strategy.
     */
    function getTotalValue() public view override returns (uint256 value) {
        value = getInvestedValue() + getClaimableAndPendingValue();
    }

    /**
     * @notice Get the invested value of assets managed by the strategy.
     * @dev This function retrieves the invested value of assets managed by the strategy.
     * @return value The invested value of assets managed by the strategy.
     */
    function getInvestedValue() public view override returns (uint256 value) {
        value = STETH.balanceOf(address(this));
    }

    /**
     * @notice Get the pending value of assets managed by the strategy.
     * @dev This function retrieves the pending value of assets managed by the strategy.
     * @return value The pending value of assets managed by the strategy.
     */
    function getPendingValue() public view override returns (uint256 value) {
        (,, value) = checkPendingAssets();
    }
    /**
     * @notice Get the claimable value of assets managed by the strategy.
     * @dev This function retrieves the claimable value of assets managed by the strategy.
     * @return value The claimable value of assets managed by the strategy.
     */

    function getClaimableValue() public view returns (uint256 value) {
        (, value,) = checkPendingAssets();
    }

    /**
     * @notice Get the total claimable and pending value of assets managed by the strategy.
     * @dev This function retrieves the total claimable and pending value of assets managed by the strategy.
     * @return value The total claimable and pending value of assets managed by the strategy.
     */
    function getClaimableAndPendingValue() public view returns (uint256 value) {
        (, uint256 claimableValue, uint256 pendingValue) = checkPendingAssets();
        value = claimableValue + pendingValue;
    }

    receive() external payable {}
}
IStrategyManager.sol 82 lines
// SPDX-License-Identifier: MIT
pragma solidity =0.8.21;

/**
 * @title StrategyManager Interface
 * @dev Interface for a contract managing multiple eth investment strategies.
 */
interface IStrategyManager {
    /**
     * @dev Sets a new vault address.
     * @param _vault The address of the new vault.
     */
    function setNewVault(address _vault) external;

    /**
     * @dev Adds a new strategy to be managed.
     * @param _strategy The address of the strategy to add.
     */
    function addStrategy(address _strategy) external;

    /**
     * @dev Destroys a strategy, removing it from management.
     * @param _strategy The address of the strategy to destroy.
     */
    function destroyStrategy(address _strategy) external;

    /**
     * @dev Clears a strategy, potentially withdrawing its funds and resetting parameters.
     * @param _strategy The address of the strategy to clear.
     */
    function clearStrategy(address _strategy) external;

    /**
     * @dev Rebalances the strategies based on incoming and outgoing amounts.
     * @param amountIn The amount of funds to be rebalanced into the strategies.
     * @param amountOut The amount of funds to be rebalanced out of the strategies.
     */
    function rebaseStrategies(uint256 amountIn, uint256 amountOut) external;

    /**
     * @dev Rebalances the strategies without incoming and outgoing amounts.
     */
    function onlyRebaseStrategies() external;

    /**
     * @dev Forces a withdrawal of a specified amount of ETH from the strategies.
     * @param ethAmount The amount of ETH to withdraw.
     * @return actualAmount The actual amount of ETH withdrawn.
     */
    function forceWithdraw(uint256 ethAmount) external returns (uint256 actualAmount);

    /**
     * @dev Sets the strategies and their corresponding ratios.
     * @param _strategies The addresses of the strategies to set.
     * @param _ratios The corresponding ratios for each strategy.
     */
    function setStrategies(address[] memory _strategies, uint256[] memory _ratios) external;

    /**
     * @dev Retrieves the address of the assets vault managed by the strategy manager.
     * @return vault The address of the assets vault.
     */
    function assetsVault() external view returns (address vault);

    /**
     * @dev Retrieves the total value managed by all strategies.
     * @return amount The total value managed by all strategies.
     */
    function getAllStrategiesValue() external view returns (uint256 amount);

    /**
     * @dev Retrieves the total valid value managed by all strategies.
     * @return amount The total valid value managed by all strategies.
     */
    function getTotalInvestedValue() external view returns (uint256 amount);

    /**
     * @dev Retrieves the total pending value managed by all strategies.
     * @return amount The total pending value managed by all strategies.
     */
    function getAllStrategyPendingValue() external view returns (uint256 amount);
}
IWithdrawalQueueERC721.sol 111 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.21;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

interface IWithdrawalQueueERC721 is IERC721 {
    /// @notice output format struct for `_getWithdrawalStatus()` method
    struct WithdrawalRequestStatus {
        /// @notice stETH token amount that was locked on withdrawal queue for this request
        uint256 amountOfStETH;
        /// @notice amount of stETH shares locked on withdrawal queue for this request
        uint256 amountOfShares;
        /// @notice address that can claim or transfer this request
        address owner;
        /// @notice timestamp of when the request was created, in seconds
        uint256 timestamp;
        /// @notice true, if request is finalized
        bool isFinalized;
        /// @notice true, if request is claimed. Request is claimable if (isFinalized && !isClaimed)
        bool isClaimed;
    }

    /// @dev See {IERC721-balanceOf}.
    function balanceOf(address _owner) external view returns (uint256);

    /// @notice Returns all withdrawal requests that belongs to the `_owner` address
    ///
    /// WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
    /// to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
    /// this function has an unbounded cost, and using it as part of a state-changing function may render the function
    /// uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.

    function getWithdrawalRequests(address _owner) external view returns (uint256[] memory requestsIds);
    /// @notice Returns status for requests with provided ids
    /// @param _requestIds array of withdrawal request ids
    function getWithdrawalStatus(uint256[] calldata _requestIds)
        external
        view
        returns (WithdrawalRequestStatus[] memory statuses);

    /// @notice length of the checkpoint array. Last possible value for the hint.
    ///  NB! checkpoints are indexed from 1, so it returns 0 if there is no checkpoints
    function getLastCheckpointIndex() external view returns (uint256);

    /// @notice Request the batch of stETH for withdrawal. Approvals for the passed amounts should be done before.
    /// @param _amounts an array of stETH amount values.
    ///  The standalone withdrawal request will be created for each item in the passed list.
    /// @param _owner address that will be able to manage the created requests.
    ///  If `address(0)` is passed, `msg.sender` will be used as owner.
    /// @return requestIds an array of the created withdrawal request ids
    function requestWithdrawals(uint256[] calldata _amounts, address _owner)
        external
        returns (uint256[] memory requestIds);

    /// @notice Finds the list of hints for the given `_requestIds` searching among the checkpoints with indices
    ///  in the range  `[_firstIndex, _lastIndex]`.
    ///  NB! Array of request ids should be sorted
    ///  NB! `_firstIndex` should be greater than 0, because checkpoint list is 1-based array
    ///  Usage: findCheckpointHints(_requestIds, 1, getLastCheckpointIndex())
    /// @param _requestIds ids of the requests sorted in the ascending order to get hints for
    /// @param _firstIndex left boundary of the search range. Should be greater than 0
    /// @param _lastIndex right boundary of the search range. Should be less than or equal to getLastCheckpointIndex()
    /// @return hintIds array of hints used to find required checkpoint for the request
    function findCheckpointHints(uint256[] calldata _requestIds, uint256 _firstIndex, uint256 _lastIndex)
        external
        view
        returns (uint256[] memory hintIds);

    /// @notice Claim a batch of withdrawal requests if they are finalized sending locked ether to the owner
    /// @param _requestIds array of request ids to claim
    /// @param _hints checkpoint hint for each id. Can be obtained with `findCheckpointHints()`
    /// @dev
    ///  Reverts if requestIds and hints arrays length differs
    ///  Reverts if any requestId or hint in arguments are not valid
    ///  Reverts if any request is not finalized or already claimed
    ///  Reverts if msg sender is not an owner of the requests
    function claimWithdrawals(uint256[] calldata _requestIds, uint256[] calldata _hints) external;

    /// @notice Claim one`_requestId` request once finalized sending locked ether to the owner
    /// @param _requestId request id to claim
    /// @dev use unbounded loop to find a hint, which can lead to OOG
    /// @dev
    ///  Reverts if requestId or hint are not valid
    ///  Reverts if request is not finalized or already claimed
    ///  Reverts if msg sender is not an owner of request
    function claimWithdrawal(uint256 _requestId) external;

    /// @notice Claim a batch of withdrawal requests if they are finalized sending ether to `_recipient`
    /// @param _requestIds array of request ids to claim
    /// @param _hints checkpoint hint for each id. Can be obtained with `findCheckpointHints()`
    /// @param _recipient address where claimed ether will be sent to
    /// @dev
    ///  Reverts if recipient is equal to zero
    ///  Reverts if requestIds and hints arrays length differs
    ///  Reverts if any requestId or hint in arguments are not valid
    ///  Reverts if any request is not finalized or already claimed
    ///  Reverts if msg sender is not an owner of the requests
    function claimWithdrawalsTo(uint256[] calldata _requestIds, uint256[] calldata _hints, address _recipient)
        external;

    function finaliseRequest(uint256 _requestId) external;

    function finalize(uint256 _lastRequestIdToBeFinalized, uint256 _maxShareRate) external payable;

    function getLastRequestId() external view returns (uint256);

    function prefinalize(uint256[] calldata _batches, uint256 _maxShareRate)
        external
        view
        returns (uint256 ethToLock, uint256 sharesToBurn);
}
TransferHelper.sol 60 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.0;

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

library TransferHelper {
    /// @notice Transfers tokens from the targeted address to the given destination
    /// @notice Errors with 'STF' if transfer fails
    /// @param token The contract address of the token to be transferred
    /// @param from The originating address from which the tokens will be transferred
    /// @param to The destination address of the transfer
    /// @param value The amount to be transferred
    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) =
            token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');
    }

    /// @notice Transfers tokens from msg.sender to a recipient
    /// @dev Errors with ST if transfer fails
    /// @param token The contract address of the token which will be transferred
    /// @param to The recipient of the transfer
    /// @param value The value of the transfer
    function safeTransfer(
        address token,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');
    }

    /// @notice Approves the stipulated contract to spend the given allowance in the given token
    /// @dev Errors with 'SA' if transfer fails
    /// @param token The contract address of the token to be approved
    /// @param to The target of the approval
    /// @param value The amount of the given token the target will be allowed to spend
    function safeApprove(
        address token,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA');
    }

    /// @notice Transfers ETH to the recipient address
    /// @dev Fails with `STE`
    /// @param to The destination of the transfer
    /// @param value The value to be transferred
    function safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        require(success, 'STE');
    }
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
IERC721.sol 135 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
EnumerableSet.sol 378 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes32 value => uint256) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._positions[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}
IERC20Permit.sol 90 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

Read Contract

MAX_STETH_WITHDRAWAL_AMOUNT 0xdb2296cd → uint256
MIN_STETH_WITHDRAWAL_AMOUNT 0x0d25a957 → uint256
STETH 0xe00bfe50 → address
WETH9 0x4aa4a4fc → address
WSTETH 0xd9fb643a → address
checkPendingAssets 0x1c2ca2fd → uint256[], uint256, uint256
checkPendingAssets 0x9e354677 → uint256[], uint256, uint256
checkPendingStatus 0x75421af3 → uint256, uint256
getClaimableAndPendingValue 0x162275f4 → uint256
getClaimableValue 0xc00f60c4 → uint256
getInvestedValue 0x6c23ab4c → uint256
getPendingValue 0x001a5597 → uint256
getRequestIds 0xac33a273 → uint256[]
getRequestIdsLen 0x03f112e5 → uint256
getStETHWithdrawalStatus 0x7ca9c0f9 → uint256[], tuple[]
getStETHWithdrawalStatusForIds 0x1b63a9ec → tuple[]
getTotalValue 0xcaa648b4 → uint256
governance 0x5aa6e675 → address
manager 0x481c6a75 → address
name 0x06fdde03 → string
stETHWithdrawalQueue 0xb9a5e719 → address
swapManager 0x709d039d → address

Write Contract 7 functions

These functions modify contract state and require a wallet transaction to execute.

claimAllPendingAssets 0xeea94dab
No parameters
claimAllPendingAssetsByIds 0x83b39e23
uint256[] claimableRequestIds
uint256[] hints
clear 0x52efea6e
No parameters
returns: uint256
deposit 0xd0e30db0
No parameters
instantWithdraw 0xfd92bff2
uint256 _amount
returns: uint256
setGovernance 0xab033ea9
address _governance
withdraw 0x2e1a7d4d
uint256 _ethAmount
returns: uint256

Token Balances (1)

View Transfers →
stETH 0

Recent Transactions

No transactions found for this address