Address Contract Verified
Address
0x170618936cd96B1eD8112eC3D3778374B38DFe5e
Balance
0 ETH
Nonce
33
Code Size
2334 bytes
Creator
0x229f53eF...f65d at tx 0x3c2aceb8...8b174c
Indexed Transactions
0
Contract Bytecode
2334 bytes
0x6080604081815260049182361015610015575f80fd5b5f925f3560e01c9182635c60da1b14610339575081636f4fa30f146103125781639a0d79ad14610079575063e7f6f2251461004e575f80fd5b3461007557816003193601126100755760015490516001600160a01b039091168152602090f35b5080fd5b918091506003193601126102925781359267ffffffffffffffff928385116102925736602386011215610292578481013594848611610292576024928382019184883692010111610292578335928315158403610292578551946102c895868101968188108a891117610300576103c3823960608160018060a01b0398897f000000000000000000000000b53a6c402b0d4fb6c7aa59b7d8fbd2e884fbf3bc1681528a60208201525f8b8201520301905ff080156102e45786869116985f96610296575b506bffffffffffffffffffffffff60a01b9033826001541617600155893b15610292576101885f878c8e8d5180958194829363439fab9160e01b845260208d8501528b8401916103a2565b039134905af1801561028857610275575b5061026a575b60015416600155857f0000000000000000000000003a0008a588772446f6e656133c2d5029cc4fc20e1691823b156102665783918991838a5195869485936312b5ad0160e11b85528401525af1801561025c57610245575b505084926020969261023c7f0d606510f33b5e566ed1ca2b9e88d388ab81cea532909665d725b33134516aff938751938493168352878a8401523395888401916103a2565b0390a351908152f35b61024f829161037a565b61025957806101f7565b80fd5b86513d84823e3d90fd5b8380fd5b80845416845561019f565b61028091955061037a565b5f935f610199565b8a513d5f823e3d90fd5b5f80fd5b885191965061025e808301918211838310176102ee57602091839161068b83398b81520301905ff080156102e457861694856bffffffffffffffffffffffff60a01b5f5416175f555f61013d565b87513d5f823e3d90fd5b83604186634e487b7160e01b5f52525ffd5b82604185634e487b7160e01b5f52525ffd5b8234610292575f366003190112610292575f5490516001600160a01b039091168152602090f35b34610292575f366003190112610292577f000000000000000000000000b53a6c402b0d4fb6c7aa59b7d8fbd2e884fbf3bc6001600160a01b03168152602090f35b67ffffffffffffffff811161038e57604052565b634e487b7160e01b5f52604160045260245ffd5b908060209392818452848401375f828201840152601f01601f191601019056fe60806040526102c8803803806100148161018e565b92833981019060408183031261018a5780516001600160a01b03811680820361018a5760208381015190936001600160401b03821161018a570184601f8201121561018a5780519061006d610068836101c7565b61018e565b9582875285838301011161018a5784905f5b8381106101765750505f9186010152813b1561015e577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191682179055604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a283511561014057505f80848461012796519101845af4903d15610137573d610118610068826101c7565b9081525f81943d92013e6101e2565b505b604051608290816102468239f35b606092506101e2565b925050503461014f5750610129565b63b398979f60e01b8152600490fd5b60249060405190634c9c8ce360e01b82526004820152fd5b81810183015188820184015286920161007f565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101b357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101b357601f01601f191660200190565b9061020957508051156101f757805190602001fd5b604051630a12f52160e11b8152600490fd5b8151158061023c575b61021a575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1561021256fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220590de6162af1aca5f7d380e459394ce97dc6a2e4a2575dd7c58d5d1cb01c826d64736f6c6343000816003360a03461007157601f61025e38819003918201601f19168301916001600160401b038311848410176100755780849260209460405283398101031261007157516001600160a01b03811690819003610071576080526040516101d4908161008a82396080518181816073015260ca0152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610044575b3615610018575f80fd5b7f7cb3607a76b32d6d17ca5d1aeb444650b19ac0fabbb1f24c93a0da57346b56106020604051348152a1005b5f3560e01c80634641257d146100a65763fbfa77cf0361000e57346100a2575f3660031901126100a2576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5f80fd5b346100a2575f3660031901126100a25760206100c06100c8565b604051908152f35b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361018c5747908115610187577f8e55ccfc9778ff8eba1646d765cf1982537ce0f9257054a17b48aad7452501836020604051848152a1333b156100a257604051630a62ade560e31b81525f8160048186335af1801561017c576101545750565b67ffffffffffffffff811161016857604052565b634e487b7160e01b5f52604160045260245ffd5b6040513d5f823e3d90fd5b5f9150565b604051630d599dd960e11b8152600490fdfea2646970667358221220d619b98571e571c794168db3e6f87328e3cc06e55b5467159fa6ab0e831142cf64736f6c63430008160033a264697066735822122043bb239fda363c71e4069a8e199017947bd8ca3413385ed6020a0b82d50e582e64736f6c63430008160033
Verified Source Code Full Match
Compiler: v0.8.22+commit.4fc1097e
EVM: shanghai
Optimization: Yes (200 runs)
Errors.sol 57 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
/**
* @title Errors
* @author StakeWise
* @notice Contains all the custom errors
*/
library Errors {
error AccessDenied();
error InvalidShares();
error InvalidAssets();
error ZeroAddress();
error InsufficientAssets();
error CapacityExceeded();
error InvalidCapacity();
error InvalidSecurityDeposit();
error InvalidFeeRecipient();
error InvalidFeePercent();
error NotHarvested();
error NotCollateralized();
error Collateralized();
error InvalidProof();
error LowLtv();
error RedemptionExceeded();
error InvalidPosition();
error InvalidLtv();
error InvalidHealthFactor();
error InvalidReceivedAssets();
error InvalidTokenMeta();
error UpgradeFailed();
error InvalidValidator();
error InvalidValidators();
error WhitelistAlreadyUpdated();
error DeadlineExpired();
error PermitInvalidSigner();
error InvalidValidatorsRegistryRoot();
error InvalidVault();
error AlreadyAdded();
error AlreadyRemoved();
error InvalidOracles();
error NotEnoughSignatures();
error InvalidOracle();
error TooEarlyUpdate();
error InvalidAvgRewardPerSecond();
error InvalidRewardsRoot();
error HarvestFailed();
error InvalidRedeemFromLtvPercent();
error InvalidLiqThresholdPercent();
error InvalidLiqBonusPercent();
error InvalidLtvPercent();
error InvalidCheckpointIndex();
error InvalidCheckpointValue();
error MaxOraclesExceeded();
error ClaimTooEarly();
}
IEthVault.sol 50 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IVaultAdmin} from './IVaultAdmin.sol';
import {IVaultVersion} from './IVaultVersion.sol';
import {IVaultFee} from './IVaultFee.sol';
import {IVaultState} from './IVaultState.sol';
import {IVaultValidators} from './IVaultValidators.sol';
import {IVaultEnterExit} from './IVaultEnterExit.sol';
import {IVaultOsToken} from './IVaultOsToken.sol';
import {IVaultMev} from './IVaultMev.sol';
import {IVaultEthStaking} from './IVaultEthStaking.sol';
import {IMulticall} from './IMulticall.sol';
/**
* @title IEthVault
* @author StakeWise
* @notice Defines the interface for the EthVault contract
*/
interface IEthVault is
IVaultAdmin,
IVaultVersion,
IVaultFee,
IVaultState,
IVaultValidators,
IVaultEnterExit,
IVaultOsToken,
IVaultMev,
IVaultEthStaking,
IMulticall
{
/**
* @dev Struct for initializing the EthVault contract
* @param capacity The Vault stops accepting deposits after exceeding the capacity
* @param feePercent The fee percent that is charged by the Vault
* @param metadataIpfsHash The IPFS hash of the Vault's metadata file
*/
struct EthVaultInitParams {
uint256 capacity;
uint16 feePercent;
string metadataIpfsHash;
}
/**
* @notice Initializes the EthVault contract. Must transfer security deposit together with a call.
* @param params The encoded parameters for initializing the EthVault contract
*/
function initialize(bytes calldata params) external payable;
}
IVaultFee.sol 37 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IVaultAdmin} from './IVaultAdmin.sol';
/**
* @title IVaultFee
* @author StakeWise
* @notice Defines the interface for the VaultFee contract
*/
interface IVaultFee is IVaultAdmin {
/**
* @notice Event emitted on fee recipient update
* @param caller The address of the function caller
* @param feeRecipient The address of the new fee recipient
*/
event FeeRecipientUpdated(address indexed caller, address indexed feeRecipient);
/**
* @notice The Vault's fee recipient
* @return The address of the Vault's fee recipient
*/
function feeRecipient() external view returns (address);
/**
* @notice The Vault's fee percent in BPS
* @return The fee percent applied by the Vault on the rewards
*/
function feePercent() external view returns (uint16);
/**
* @notice Function for updating the fee recipient address. Can only be called by the admin.
* @param _feeRecipient The address of the new fee recipient
*/
function setFeeRecipient(address _feeRecipient) external;
}
IVaultMev.sol 18 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IVaultState} from './IVaultState.sol';
/**
* @title IVaultMev
* @author StakeWise
* @notice Common interface for the VaultMev contracts
*/
interface IVaultMev is IVaultState {
/**
* @notice The contract that accumulates MEV rewards
* @return The MEV escrow contract address
*/
function mevEscrow() external view returns (address);
}
IMulticall.sol 18 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.8.22;
/**
* @title Multicall
* @author Uniswap
* @notice Adopted from https://github.com/Uniswap/v3-periphery/blob/1d69caf0d6c8cfeae9acd1f34ead30018d6e6400/contracts/base/Multicall.sol
* @notice Enables calling multiple methods in a single call to the contract
*/
interface IMulticall {
/**
* @notice Call multiple functions in the current contract and return the data from all of them if they all succeed
* @param data The encoded function data for each of the calls to make to this contract
* @return results The results from each of the calls passed in via data
*/
function multicall(bytes[] calldata data) external returns (bytes[] memory results);
}
IVaultAdmin.sol 29 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
/**
* @title IVaultState
* @author StakeWise
* @notice Defines the interface for the VaultAdmin contract
*/
interface IVaultAdmin {
/**
* @notice Event emitted on metadata ipfs hash update
* @param caller The address of the function caller
* @param metadataIpfsHash The new metadata IPFS hash
*/
event MetadataUpdated(address indexed caller, string metadataIpfsHash);
/**
* @notice The Vault admin
* @return The address of the Vault admin
*/
function admin() external view returns (address);
/**
* @notice Function for updating the metadata IPFS hash. Can only be called by Vault admin.
* @param metadataIpfsHash The new metadata IPFS hash
*/
function setMetadata(string calldata metadataIpfsHash) external;
}
IVaultState.sol 91 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IKeeperRewards} from './IKeeperRewards.sol';
import {IVaultFee} from './IVaultFee.sol';
/**
* @title IVaultState
* @author StakeWise
* @notice Defines the interface for the VaultState contract
*/
interface IVaultState is IVaultFee {
/**
* @notice Event emitted on checkpoint creation
* @param shares The number of burned shares
* @param assets The amount of exited assets
*/
event CheckpointCreated(uint256 shares, uint256 assets);
/**
* @notice Event emitted on minting fee recipient shares
* @param receiver The address of the fee recipient
* @param shares The number of minted shares
* @param assets The amount of minted assets
*/
event FeeSharesMinted(address receiver, uint256 shares, uint256 assets);
/**
* @notice Total assets in the Vault
* @return The total amount of the underlying asset that is "managed" by Vault
*/
function totalAssets() external view returns (uint256);
/**
* @notice Function for retrieving total shares
* @return The amount of shares in existence
*/
function totalShares() external view returns (uint256);
/**
* @notice The Vault's capacity
* @return The amount after which the Vault stops accepting deposits
*/
function capacity() external view returns (uint256);
/**
* @notice Total assets available in the Vault. They can be staked or withdrawn.
* @return The total amount of withdrawable assets
*/
function withdrawableAssets() external view returns (uint256);
/**
* @notice Queued Shares
* @return The total number of shares queued for exit
*/
function queuedShares() external view returns (uint128);
/**
* @notice Returns the number of shares held by an account
* @param account The account for which to look up the number of shares it has, i.e. its balance
* @return The number of shares held by the account
*/
function getShares(address account) external view returns (uint256);
/**
* @notice Converts shares to assets
* @param assets The amount of assets to convert to shares
* @return shares The amount of shares that the Vault would exchange for the amount of assets provided
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @notice Converts assets to shares
* @param shares The amount of shares to convert to assets
* @return assets The amount of assets that the Vault would exchange for the amount of shares provided
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @notice Check whether state update is required
* @return `true` if state update is required, `false` otherwise
*/
function isStateUpdateRequired() external view returns (bool);
/**
* @notice Updates the total amount of assets in the Vault and its exit queue
* @param harvestParams The parameters for harvesting Keeper rewards
*/
function updateState(IKeeperRewards.HarvestParams calldata harvestParams) external;
}
IOwnMevEscrow.sol 37 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
/**
* @title IOwnMevEscrow
* @author StakeWise
* @notice Defines the interface for the OwnMevEscrow contract
*/
interface IOwnMevEscrow {
/**
* @notice Event emitted on received MEV
* @param assets The amount of MEV assets received
*/
event MevReceived(uint256 assets);
/**
* @notice Event emitted on harvest
* @param assets The amount of assets withdrawn
*/
event Harvested(uint256 assets);
/**
* @notice Vault address
* @return The address of the vault that owns the escrow
*/
function vault() external view returns (address payable);
/**
* @notice Withdraws MEV accumulated in the escrow. Can be called only by the Vault.
* @dev IMPORTANT: because control is transferred to the Vault, care must be
* taken to not create reentrancy vulnerabilities. The Vault must follow the checks-effects-interactions pattern:
* https://docs.soliditylang.org/en/v0.8.22/security-considerations.html#use-the-checks-effects-interactions-pattern
* @return assets The amount of assets withdrawn
*/
function harvest() external returns (uint256 assets);
}
IVaultOsToken.sol 127 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IVaultState} from './IVaultState.sol';
import {IVaultEnterExit} from './IVaultEnterExit.sol';
/**
* @title IVaultOsToken
* @author StakeWise
* @notice Defines the interface for the VaultOsToken contract
*/
interface IVaultOsToken is IVaultState, IVaultEnterExit {
/**
* @notice Event emitted on minting osToken
* @param caller The address of the function caller
* @param receiver The address of the osToken receiver
* @param assets The amount of minted assets
* @param shares The amount of minted shares
* @param referrer The address of the referrer
*/
event OsTokenMinted(
address indexed caller,
address receiver,
uint256 assets,
uint256 shares,
address referrer
);
/**
* @notice Event emitted on burning OsToken
* @param caller The address of the function caller
* @param assets The amount of burned assets
* @param shares The amount of burned shares
*/
event OsTokenBurned(address indexed caller, uint256 assets, uint256 shares);
/**
* @notice Event emitted on osToken position liquidation
* @param caller The address of the function caller
* @param user The address of the user liquidated
* @param receiver The address of the receiver of the liquidated assets
* @param osTokenShares The amount of osToken shares to liquidate
* @param shares The amount of vault shares burned
* @param receivedAssets The amount of assets received
*/
event OsTokenLiquidated(
address indexed caller,
address indexed user,
address receiver,
uint256 osTokenShares,
uint256 shares,
uint256 receivedAssets
);
/**
* @notice Event emitted on osToken position redemption
* @param caller The address of the function caller
* @param user The address of the position owner to redeem from
* @param receiver The address of the receiver of the redeemed assets
* @param osTokenShares The amount of osToken shares to redeem
* @param shares The amount of vault shares burned
* @param assets The amount of assets received
*/
event OsTokenRedeemed(
address indexed caller,
address indexed user,
address receiver,
uint256 osTokenShares,
uint256 shares,
uint256 assets
);
/**
* @notice Struct of osToken position
* @param shares The total number of minted osToken shares. Will increase based on the treasury fee.
* @param cumulativeFeePerShare The cumulative fee per share
*/
struct OsTokenPosition {
uint128 shares;
uint128 cumulativeFeePerShare;
}
/**
* @notice Get total amount of minted osToken shares
* @param user The address of the user
* @return shares The number of minted osToken shares
*/
function osTokenPositions(address user) external view returns (uint128 shares);
/**
* @notice Mints OsToken shares
* @param receiver The address that will receive the minted OsToken shares
* @param osTokenShares The number of OsToken shares to mint to the receiver
* @param referrer The address of the referrer
* @return assets The number of assets minted to the receiver
*/
function mintOsToken(
address receiver,
uint256 osTokenShares,
address referrer
) external returns (uint256 assets);
/**
* @notice Burns osToken shares
* @param osTokenShares The number of shares to burn
* @return assets The number of assets burned
*/
function burnOsToken(uint128 osTokenShares) external returns (uint256 assets);
/**
* @notice Liquidates a user position and returns the number of received assets.
* Can only be called when health factor is below 1.
* @param osTokenShares The number of shares to cover
* @param owner The address of the position owner to liquidate
* @param receiver The address of the receiver of the liquidated assets
*/
function liquidateOsToken(uint256 osTokenShares, address owner, address receiver) external;
/**
* @notice Redeems osToken shares for assets. Can only be called when health factor is above redeemFromHealthFactor.
* @param osTokenShares The number of osToken shares to redeem
* @param owner The address of the position owner to redeem from
* @param receiver The address of the receiver of the redeemed assets
*/
function redeemOsToken(uint256 osTokenShares, address owner, address receiver) external;
}
IVaultVersion.sol 31 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IERC1822Proxiable} from '@openzeppelin/contracts/interfaces/draft-IERC1822.sol';
import {IVaultAdmin} from './IVaultAdmin.sol';
/**
* @title IVaultVersion
* @author StakeWise
* @notice Defines the interface for VaultVersion contract
*/
interface IVaultVersion is IERC1822Proxiable, IVaultAdmin {
/**
* @notice Vault Unique Identifier
* @return The unique identifier of the Vault
*/
function vaultId() external pure returns (bytes32);
/**
* @notice Version
* @return The version of the Vault implementation contract
*/
function version() external pure returns (uint8);
/**
* @notice Implementation
* @return The address of the Vault implementation contract
*/
function implementation() external view returns (address);
}
Proxy.sol 69 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)
pragma solidity ^0.8.20;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback
* function and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
}
IKeeperOracles.sol 61 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IERC5267} from '@openzeppelin/contracts/interfaces/IERC5267.sol';
/**
* @title IKeeperOracles
* @author StakeWise
* @notice Defines the interface for the KeeperOracles contract
*/
interface IKeeperOracles is IERC5267 {
/**
* @notice Event emitted on the oracle addition
* @param oracle The address of the added oracle
*/
event OracleAdded(address indexed oracle);
/**
* @notice Event emitted on the oracle removal
* @param oracle The address of the removed oracle
*/
event OracleRemoved(address indexed oracle);
/**
* @notice Event emitted on oracles config update
* @param configIpfsHash The IPFS hash of the new config
*/
event ConfigUpdated(string configIpfsHash);
/**
* @notice Function for verifying whether oracle is registered or not
* @param oracle The address of the oracle to check
* @return `true` for the registered oracle, `false` otherwise
*/
function isOracle(address oracle) external view returns (bool);
/**
* @notice Total Oracles
* @return The total number of oracles registered
*/
function totalOracles() external view returns (uint256);
/**
* @notice Function for adding oracle to the set
* @param oracle The address of the oracle to add
*/
function addOracle(address oracle) external;
/**
* @notice Function for removing oracle from the set
* @param oracle The address of the oracle to remove
*/
function removeOracle(address oracle) external;
/**
* @notice Function for updating the config IPFS hash
* @param configIpfsHash The new config IPFS hash
*/
function updateConfig(string calldata configIpfsHash) external;
}
IKeeperRewards.sol 202 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IKeeperOracles} from './IKeeperOracles.sol';
/**
* @title IKeeperRewards
* @author StakeWise
* @notice Defines the interface for the Keeper contract rewards
*/
interface IKeeperRewards is IKeeperOracles {
/**
* @notice Event emitted on rewards update
* @param caller The address of the function caller
* @param rewardsRoot The new rewards merkle tree root
* @param avgRewardPerSecond The new average reward per second
* @param updateTimestamp The update timestamp used for rewards calculation
* @param nonce The nonce used for verifying signatures
* @param rewardsIpfsHash The new rewards IPFS hash
*/
event RewardsUpdated(
address indexed caller,
bytes32 indexed rewardsRoot,
uint256 avgRewardPerSecond,
uint64 updateTimestamp,
uint64 nonce,
string rewardsIpfsHash
);
/**
* @notice Event emitted on Vault harvest
* @param vault The address of the Vault
* @param rewardsRoot The rewards merkle tree root
* @param totalAssetsDelta The Vault total assets delta since last sync. Can be negative in case of penalty/slashing.
* @param unlockedMevDelta The Vault execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults.
*/
event Harvested(
address indexed vault,
bytes32 indexed rewardsRoot,
int256 totalAssetsDelta,
uint256 unlockedMevDelta
);
/**
* @notice Event emitted on rewards min oracles number update
* @param oracles The new minimum number of oracles required to update rewards
*/
event RewardsMinOraclesUpdated(uint256 oracles);
/**
* @notice A struct containing the last synced Vault's cumulative reward
* @param assets The Vault cumulative reward earned since the start. Can be negative in case of penalty/slashing.
* @param nonce The nonce of the last sync
*/
struct Reward {
int192 assets;
uint64 nonce;
}
/**
* @notice A struct containing the last unlocked Vault's cumulative execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults.
* @param assets The shared MEV Vault's cumulative execution reward that can be withdrawn
* @param nonce The nonce of the last sync
*/
struct UnlockedMevReward {
uint192 assets;
uint64 nonce;
}
/**
* @notice A struct containing parameters for rewards update
* @param rewardsRoot The new rewards merkle root
* @param avgRewardPerSecond The new average reward per second
* @param updateTimestamp The update timestamp used for rewards calculation
* @param rewardsIpfsHash The new IPFS hash with all the Vaults' rewards for the new root
* @param signatures The concatenation of the Oracles' signatures
*/
struct RewardsUpdateParams {
bytes32 rewardsRoot;
uint256 avgRewardPerSecond;
uint64 updateTimestamp;
string rewardsIpfsHash;
bytes signatures;
}
/**
* @notice A struct containing parameters for harvesting rewards. Can only be called by Vault.
* @param rewardsRoot The rewards merkle root
* @param reward The Vault cumulative reward earned since the start. Can be negative in case of penalty/slashing.
* @param unlockedMevReward The Vault cumulative execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults.
* @param proof The proof to verify that Vault's reward is correct
*/
struct HarvestParams {
bytes32 rewardsRoot;
int160 reward;
uint160 unlockedMevReward;
bytes32[] proof;
}
/**
* @notice Previous Rewards Root
* @return The previous merkle tree root of the rewards accumulated by the Vaults
*/
function prevRewardsRoot() external view returns (bytes32);
/**
* @notice Rewards Root
* @return The latest merkle tree root of the rewards accumulated by the Vaults
*/
function rewardsRoot() external view returns (bytes32);
/**
* @notice Rewards Nonce
* @return The nonce used for updating rewards merkle tree root
*/
function rewardsNonce() external view returns (uint64);
/**
* @notice The last rewards update
* @return The timestamp of the last rewards update
*/
function lastRewardsTimestamp() external view returns (uint64);
/**
* @notice The minimum number of oracles required to update rewards
* @return The minimum number of oracles
*/
function rewardsMinOracles() external view returns (uint256);
/**
* @notice The rewards delay
* @return The delay in seconds between rewards updates
*/
function rewardsDelay() external view returns (uint256);
/**
* @notice Get last synced Vault cumulative reward
* @param vault The address of the Vault
* @return assets The last synced reward assets
* @return nonce The last synced reward nonce
*/
function rewards(address vault) external view returns (int192 assets, uint64 nonce);
/**
* @notice Get last unlocked shared MEV Vault cumulative reward
* @param vault The address of the Vault
* @return assets The last synced reward assets
* @return nonce The last synced reward nonce
*/
function unlockedMevRewards(address vault) external view returns (uint192 assets, uint64 nonce);
/**
* @notice Checks whether Vault must be harvested
* @param vault The address of the Vault
* @return `true` if the Vault requires harvesting, `false` otherwise
*/
function isHarvestRequired(address vault) external view returns (bool);
/**
* @notice Checks whether the Vault can be harvested
* @param vault The address of the Vault
* @return `true` if Vault can be harvested, `false` otherwise
*/
function canHarvest(address vault) external view returns (bool);
/**
* @notice Checks whether rewards can be updated
* @return `true` if rewards can be updated, `false` otherwise
*/
function canUpdateRewards() external view returns (bool);
/**
* @notice Checks whether the Vault has registered validators
* @param vault The address of the Vault
* @return `true` if Vault is collateralized, `false` otherwise
*/
function isCollateralized(address vault) external view returns (bool);
/**
* @notice Update rewards data
* @param params The struct containing rewards update parameters
*/
function updateRewards(RewardsUpdateParams calldata params) external;
/**
* @notice Harvest rewards. Can be called only by Vault.
* @param params The struct containing rewards harvesting parameters
* @return totalAssetsDelta The total reward/penalty accumulated by the Vault since the last sync
* @return unlockedMevDelta The Vault execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults.
* @return harvested `true` when the rewards were harvested, `false` otherwise
*/
function harvest(
HarvestParams calldata params
) external returns (int256 totalAssetsDelta, uint256 unlockedMevDelta, bool harvested);
/**
* @notice Set min number of oracles for confirming rewards update. Can only be called by the owner.
* @param _rewardsMinOracles The new min number of oracles for confirming rewards update
*/
function setRewardsMinOracles(uint256 _rewardsMinOracles) external;
}
IVaultEnterExit.sol 124 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IVaultState} from './IVaultState.sol';
/**
* @title IVaultEnterExit
* @author StakeWise
* @notice Defines the interface for the VaultEnterExit contract
*/
interface IVaultEnterExit is IVaultState {
/**
* @notice Event emitted on deposit
* @param caller The address that called the deposit function
* @param receiver The address that received the shares
* @param assets The number of assets deposited by the caller
* @param shares The number of shares received
* @param referrer The address of the referrer
*/
event Deposited(
address indexed caller,
address indexed receiver,
uint256 assets,
uint256 shares,
address referrer
);
/**
* @notice Event emitted on redeem
* @param owner The address that owns the shares
* @param receiver The address that received withdrawn assets
* @param assets The total number of withdrawn assets
* @param shares The total number of withdrawn shares
*/
event Redeemed(address indexed owner, address indexed receiver, uint256 assets, uint256 shares);
/**
* @notice Event emitted on shares added to the exit queue
* @param owner The address that owns the shares
* @param receiver The address that will receive withdrawn assets
* @param positionTicket The exit queue ticket that was assigned to the position
* @param shares The number of shares that queued for the exit
*/
event ExitQueueEntered(
address indexed owner,
address indexed receiver,
uint256 positionTicket,
uint256 shares
);
/**
* @notice Event emitted on claim of the exited assets
* @param receiver The address that has received withdrawn assets
* @param prevPositionTicket The exit queue ticket received after the `enterExitQueue` call
* @param newPositionTicket The new exit queue ticket in case not all the shares were withdrawn. Otherwise 0.
* @param withdrawnAssets The total number of assets withdrawn
*/
event ExitedAssetsClaimed(
address indexed receiver,
uint256 prevPositionTicket,
uint256 newPositionTicket,
uint256 withdrawnAssets
);
/**
* @notice Locks shares to the exit queue. The shares continue earning rewards until they will be burned by the Vault.
* @param shares The number of shares to lock
* @param receiver The address that will receive assets upon withdrawal
* @return positionTicket The position ticket of the exit queue
*/
function enterExitQueue(
uint256 shares,
address receiver
) external returns (uint256 positionTicket);
/**
* @notice Get the exit queue index to claim exited assets from
* @param positionTicket The exit queue position ticket to get the index for
* @return The exit queue index that should be used to claim exited assets.
* Returns -1 in case such index does not exist.
*/
function getExitQueueIndex(uint256 positionTicket) external view returns (int256);
/**
* @notice Calculates the number of shares and assets that can be claimed from the exit queue.
* @param receiver The address that will receive assets upon withdrawal
* @param positionTicket The exit queue ticket received after the `enterExitQueue` call
* @param timestamp The timestamp when the shares entered the exit queue
* @param exitQueueIndex The exit queue index at which the shares were burned. It can be looked up by calling `getExitQueueIndex`.
* @return leftShares The number of shares that are still in the queue
* @return claimedShares The number of claimed shares
* @return claimedAssets The number of claimed assets
*/
function calculateExitedAssets(
address receiver,
uint256 positionTicket,
uint256 timestamp,
uint256 exitQueueIndex
) external view returns (uint256 leftShares, uint256 claimedShares, uint256 claimedAssets);
/**
* @notice Claims assets that were withdrawn by the Vault. It can be called only after the `enterExitQueue` call by the `receiver`.
* @param positionTicket The exit queue ticket received after the `enterExitQueue` call
* @param timestamp The timestamp when the shares entered the exit queue
* @param exitQueueIndex The exit queue index at which the shares were burned. It can be looked up by calling `getExitQueueIndex`.
* @return newPositionTicket The new exit queue ticket in case not all the shares were burned. Otherwise 0.
* @return claimedShares The number of shares claimed
* @return claimedAssets The number of assets claimed
*/
function claimExitedAssets(
uint256 positionTicket,
uint256 timestamp,
uint256 exitQueueIndex
) external returns (uint256 newPositionTicket, uint256 claimedShares, uint256 claimedAssets);
/**
* @notice Redeems assets from the Vault by utilising what has not been staked yet. Can only be called when vault is not collateralized.
* @param shares The number of shares to burn
* @param receiver The address that will receive assets
* @return assets The number of assets withdrawn
*/
function redeem(uint256 shares, address receiver) external returns (uint256 assets);
}
IVaultsRegistry.sol 98 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
/**
* @title IVaultsRegistry
* @author StakeWise
* @notice Defines the interface for the VaultsRegistry
*/
interface IVaultsRegistry {
/**
* @notice Event emitted on a Vault addition
* @param caller The address that has added the Vault
* @param vault The address of the added Vault
*/
event VaultAdded(address indexed caller, address indexed vault);
/**
* @notice Event emitted on adding Vault implementation contract
* @param impl The address of the new implementation contract
*/
event VaultImplAdded(address indexed impl);
/**
* @notice Event emitted on removing Vault implementation contract
* @param impl The address of the removed implementation contract
*/
event VaultImplRemoved(address indexed impl);
/**
* @notice Event emitted on whitelisting the factory
* @param factory The address of the whitelisted factory
*/
event FactoryAdded(address indexed factory);
/**
* @notice Event emitted on removing the factory from the whitelist
* @param factory The address of the factory removed from the whitelist
*/
event FactoryRemoved(address indexed factory);
/**
* @notice Registered Vaults
* @param vault The address of the vault to check whether it is registered
* @return `true` for the registered Vault, `false` otherwise
*/
function vaults(address vault) external view returns (bool);
/**
* @notice Registered Vault implementations
* @param impl The address of the vault implementation
* @return `true` for the registered implementation, `false` otherwise
*/
function vaultImpls(address impl) external view returns (bool);
/**
* @notice Registered Factories
* @param factory The address of the factory to check whether it is whitelisted
* @return `true` for the whitelisted Factory, `false` otherwise
*/
function factories(address factory) external view returns (bool);
/**
* @notice Function for adding Vault to the registry. Can only be called by the whitelisted Factory.
* @param vault The address of the Vault to add
*/
function addVault(address vault) external;
/**
* @notice Function for adding Vault implementation contract
* @param newImpl The address of the new implementation contract
*/
function addVaultImpl(address newImpl) external;
/**
* @notice Function for removing Vault implementation contract
* @param impl The address of the removed implementation contract
*/
function removeVaultImpl(address impl) external;
/**
* @notice Function for adding the factory to the whitelist
* @param factory The address of the factory to add to the whitelist
*/
function addFactory(address factory) external;
/**
* @notice Function for removing the factory from the whitelist
* @param factory The address of the factory to remove from the whitelist
*/
function removeFactory(address factory) external;
/**
* @notice Function for initializing the registry. Can only be called once during the deployment.
* @param _owner The address of the owner of the contract
*/
function initialize(address _owner) external;
}
Address.sol 159 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
IEthVaultFactory.sol 53 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
/**
* @title IEthVaultFactory
* @author StakeWise
* @notice Defines the interface for the ETH Vault Factory contract
*/
interface IEthVaultFactory {
/**
* @notice Event emitted on a Vault creation
* @param admin The address of the Vault admin
* @param vault The address of the created Vault
* @param ownMevEscrow The address of the own MEV escrow contract. Zero address if shared MEV escrow is used.
* @param params The encoded parameters for initializing the Vault contract
*/
event VaultCreated(
address indexed admin,
address indexed vault,
address ownMevEscrow,
bytes params
);
/**
* @notice The address of the Vault implementation contract used for proxy creation
* @return The address of the Vault implementation contract
*/
function implementation() external view returns (address);
/**
* @notice The address of the own MEV escrow contract used for Vault creation
* @return The address of the MEV escrow contract
*/
function ownMevEscrow() external view returns (address);
/**
* @notice The address of the Vault admin used for Vault creation
* @return The address of the Vault admin
*/
function vaultAdmin() external view returns (address);
/**
* @notice Create Vault. Must transfer security deposit together with a call.
* @param params The encoded parameters for initializing the Vault contract
* @param isOwnMevEscrow Whether to deploy own escrow contract or connect to a smoothing pool for priority fees and MEV rewards
* @return vault The address of the created Vault
*/
function createVault(
bytes calldata params,
bool isOwnMevEscrow
) external payable returns (address vault);
}
IVaultEthStaking.sol 42 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IVaultState} from './IVaultState.sol';
import {IVaultValidators} from './IVaultValidators.sol';
import {IVaultEnterExit} from './IVaultEnterExit.sol';
import {IKeeperRewards} from './IKeeperRewards.sol';
import {IVaultMev} from './IVaultMev.sol';
/**
* @title IVaultEthStaking
* @author StakeWise
* @notice Defines the interface for the VaultEthStaking contract
*/
interface IVaultEthStaking is IVaultState, IVaultValidators, IVaultEnterExit, IVaultMev {
/**
* @notice Deposit ETH to the Vault
* @param receiver The address that will receive Vault's shares
* @param referrer The address of the referrer. Set to zero address if not used.
* @return shares The number of shares minted
*/
function deposit(address receiver, address referrer) external payable returns (uint256 shares);
/**
* @notice Used by MEV escrow to transfer ETH.
*/
function receiveFromMevEscrow() external payable;
/**
* @notice Updates Vault state and deposits ETH to the Vault
* @param receiver The address that will receive Vault's shares
* @param referrer The address of the referrer. Set to zero address if not used.
* @param harvestParams The parameters for harvesting Keeper rewards
* @return shares The number of shares minted
*/
function updateStateAndDeposit(
address receiver,
address referrer,
IKeeperRewards.HarvestParams calldata harvestParams
) external payable returns (uint256 shares);
}
IVaultValidators.sol 88 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IKeeperValidators} from './IKeeperValidators.sol';
import {IVaultAdmin} from './IVaultAdmin.sol';
import {IVaultState} from './IVaultState.sol';
/**
* @title IVaultValidators
* @author StakeWise
* @notice Defines the interface for VaultValidators contract
*/
interface IVaultValidators is IVaultAdmin, IVaultState {
/**
* @notice Event emitted on validator registration
* @param publicKey The public key of the validator that was registered
*/
event ValidatorRegistered(bytes publicKey);
/**
* @notice Event emitted on keys manager address update
* @param caller The address of the function caller
* @param keysManager The address of the new keys manager
*/
event KeysManagerUpdated(address indexed caller, address indexed keysManager);
/**
* @notice Event emitted on validators merkle tree root update
* @param caller The address of the function caller
* @param validatorsRoot The new validators merkle tree root
*/
event ValidatorsRootUpdated(address indexed caller, bytes32 indexed validatorsRoot);
/**
* @notice The Vault keys manager address
* @return The address that can update validators merkle tree root
*/
function keysManager() external view returns (address);
/**
* @notice The Vault validators root
* @return The merkle tree root to use for verifying validators deposit data
*/
function validatorsRoot() external view returns (bytes32);
/**
* @notice The Vault validator index
* @return The index of the next validator to be registered in the current deposit data file
*/
function validatorIndex() external view returns (uint256);
/**
* @notice Function for registering single validator
* @param keeperParams The parameters for getting approval from Keeper oracles
* @param proof The proof used to verify that the validator is part of the validators merkle tree
*/
function registerValidator(
IKeeperValidators.ApprovalParams calldata keeperParams,
bytes32[] calldata proof
) external;
/**
* @notice Function for registering multiple validators
* @param keeperParams The parameters for getting approval from Keeper oracles
* @param indexes The indexes of the leaves for the merkle tree multi proof verification
* @param proofFlags The multi proof flags for the merkle tree verification
* @param proof The proof used for the merkle tree verification
*/
function registerValidators(
IKeeperValidators.ApprovalParams calldata keeperParams,
uint256[] calldata indexes,
bool[] calldata proofFlags,
bytes32[] calldata proof
) external;
/**
* @notice Function for updating the keys manager. Can only be called by the admin.
* @param _keysManager The new keys manager address
*/
function setKeysManager(address _keysManager) external;
/**
* @notice Function for updating the validators merkle tree root. Can only be called by the keys manager.
* @param _validatorsRoot The new validators merkle tree root
*/
function setValidatorsRoot(bytes32 _validatorsRoot) external;
}
IKeeperValidators.sol 95 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IKeeperRewards} from './IKeeperRewards.sol';
import {IKeeperOracles} from './IKeeperOracles.sol';
/**
* @title IKeeperValidators
* @author StakeWise
* @notice Defines the interface for the Keeper validators
*/
interface IKeeperValidators is IKeeperOracles, IKeeperRewards {
/**
* @notice Event emitted on validators approval
* @param vault The address of the Vault
* @param exitSignaturesIpfsHash The IPFS hash with the validators' exit signatures
*/
event ValidatorsApproval(address indexed vault, string exitSignaturesIpfsHash);
/**
* @notice Event emitted on exit signatures update
* @param caller The address of the function caller
* @param vault The address of the Vault
* @param nonce The nonce used for verifying Oracles' signatures
* @param exitSignaturesIpfsHash The IPFS hash with the validators' exit signatures
*/
event ExitSignaturesUpdated(
address indexed caller,
address indexed vault,
uint256 nonce,
string exitSignaturesIpfsHash
);
/**
* @notice Event emitted on validators min oracles number update
* @param oracles The new minimum number of oracles required to approve validators
*/
event ValidatorsMinOraclesUpdated(uint256 oracles);
/**
* @notice Get nonce for the next vault exit signatures update
* @param vault The address of the Vault to get the nonce for
* @return The nonce of the Vault for updating signatures
*/
function exitSignaturesNonces(address vault) external view returns (uint256);
/**
* @notice Struct for approving registration of one or more validators
* @param validatorsRegistryRoot The deposit data root used to verify that oracles approved validators
* @param deadline The deadline for submitting the approval
* @param validators The concatenation of the validators' public key, signature and deposit data root
* @param signatures The concatenation of Oracles' signatures
* @param exitSignaturesIpfsHash The IPFS hash with the validators' exit signatures
*/
struct ApprovalParams {
bytes32 validatorsRegistryRoot;
uint256 deadline;
bytes validators;
bytes signatures;
string exitSignaturesIpfsHash;
}
/**
* @notice The minimum number of oracles required to update validators
* @return The minimum number of oracles
*/
function validatorsMinOracles() external view returns (uint256);
/**
* @notice Function for approving validators registration
* @param params The parameters for approving validators registration
*/
function approveValidators(ApprovalParams calldata params) external;
/**
* @notice Function for updating exit signatures for every hard fork
* @param vault The address of the Vault to update signatures for
* @param deadline The deadline for submitting signatures update
* @param exitSignaturesIpfsHash The IPFS hash with the validators' exit signatures
* @param oraclesSignatures The concatenation of Oracles' signatures
*/
function updateExitSignatures(
address vault,
uint256 deadline,
string calldata exitSignaturesIpfsHash,
bytes calldata oraclesSignatures
) external;
/**
* @notice Function for updating validators min oracles number
* @param _validatorsMinOracles The new minimum number of oracles required to approve validators
*/
function setValidatorsMinOracles(uint256 _validatorsMinOracles) external;
}
StorageSlot.sol 135 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}
EthVaultFactory.sol 72 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {ERC1967Proxy} from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol';
import {IEthVaultFactory} from '../../interfaces/IEthVaultFactory.sol';
import {IEthVault} from '../../interfaces/IEthVault.sol';
import {IVaultsRegistry} from '../../interfaces/IVaultsRegistry.sol';
import {OwnMevEscrow} from './mev/OwnMevEscrow.sol';
/**
* @title EthVaultFactory
* @author StakeWise
* @notice Factory for deploying Ethereum staking Vaults
*/
contract EthVaultFactory is IEthVaultFactory {
IVaultsRegistry internal immutable _vaultsRegistry;
/// @inheritdoc IEthVaultFactory
address public immutable override implementation;
/// @inheritdoc IEthVaultFactory
address public override ownMevEscrow;
/// @inheritdoc IEthVaultFactory
address public override vaultAdmin;
/**
* @dev Constructor
* @param _implementation The implementation address of Vault
* @param vaultsRegistry The address of the VaultsRegistry contract
*/
constructor(address _implementation, IVaultsRegistry vaultsRegistry) {
implementation = _implementation;
_vaultsRegistry = vaultsRegistry;
}
/// @inheritdoc IEthVaultFactory
function createVault(
bytes calldata params,
bool isOwnMevEscrow
) external payable override returns (address vault) {
// create vault
vault = address(new ERC1967Proxy(implementation, ''));
// create MEV escrow contract if needed
address _mevEscrow;
if (isOwnMevEscrow) {
_mevEscrow = address(new OwnMevEscrow(vault));
// set MEV escrow contract so that it can be initialized in the Vault
ownMevEscrow = _mevEscrow;
}
// set admin so that it can be initialized in the Vault
vaultAdmin = msg.sender;
// initialize Vault
IEthVault(vault).initialize{value: msg.value}(params);
// cleanup MEV escrow contract
if (isOwnMevEscrow) delete ownMevEscrow;
// cleanup admin
delete vaultAdmin;
// add vault to the registry
_vaultsRegistry.addVault(vault);
// emit event
emit VaultCreated(msg.sender, vault, _mevEscrow, params);
}
}
OwnMevEscrow.sol 40 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.22;
import {IOwnMevEscrow} from '../../../interfaces/IOwnMevEscrow.sol';
import {IVaultEthStaking} from '../../../interfaces/IVaultEthStaking.sol';
import {Errors} from '../../../libraries/Errors.sol';
/**
* @title OwnMevEscrow
* @author StakeWise
* @notice Accumulates received MEV. The escrow is owned by the Vault.
*/
contract OwnMevEscrow is IOwnMevEscrow {
address payable public immutable override vault;
/// @dev Constructor
constructor(address _vault) {
vault = payable(_vault);
}
/// @inheritdoc IOwnMevEscrow
function harvest() external returns (uint256 assets) {
if (msg.sender != vault) revert Errors.HarvestFailed();
assets = address(this).balance;
if (assets == 0) return 0;
emit Harvested(assets);
// slither-disable-next-line arbitrary-send-eth
IVaultEthStaking(msg.sender).receiveFromMevEscrow{value: assets}();
}
/**
* @dev Function for receiving MEV
*/
receive() external payable {
emit MevReceived(msg.value);
}
}
IERC5267.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.20;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}
IBeacon.sol 16 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}
draft-IERC1822.sol 20 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}
ERC1967Proxy.sol 40 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol)
pragma solidity ^0.8.20;
import {Proxy} from "../Proxy.sol";
import {ERC1967Utils} from "./ERC1967Utils.sol";
/**
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
* implementation address that can be changed. This address is stored in storage in the location specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
* implementation behind the proxy.
*/
contract ERC1967Proxy is Proxy {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
*
* If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
* encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
*
* Requirements:
*
* - If `data` is empty, `msg.value` must be zero.
*/
constructor(address implementation, bytes memory _data) payable {
ERC1967Utils.upgradeToAndCall(implementation, _data);
}
/**
* @dev Returns the current implementation address.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
*/
function _implementation() internal view virtual override returns (address) {
return ERC1967Utils.getImplementation();
}
}
ERC1967Utils.sol 193 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}
Read Contract
implementation 0x5c60da1b → address
ownMevEscrow 0x6f4fa30f → address
vaultAdmin 0xe7f6f225 → address
Write Contract 1 functions
These functions modify contract state and require a wallet transaction to execute.
createVault 0x9a0d79ad
bytes params
bool isOwnMevEscrow
returns: address
Recent Transactions
No transactions found for this address