Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 785 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Update Rewards | 21247467 | 6 hrs ago | IN | 0 ETH | 0.00138107 | ||||
Update Rewards | 21243869 | 18 hrs ago | IN | 0 ETH | 0.0020832 | ||||
Update Rewards | 21240273 | 30 hrs ago | IN | 0 ETH | 0.0012454 | ||||
Update Rewards | 21236670 | 42 hrs ago | IN | 0 ETH | 0.00462743 | ||||
Update Rewards | 21233080 | 2 days ago | IN | 0 ETH | 0.00134423 | ||||
Update Rewards | 21229486 | 2 days ago | IN | 0 ETH | 0.00293713 | ||||
Update Rewards | 21225886 | 3 days ago | IN | 0 ETH | 0.00137095 | ||||
Update Rewards | 21222282 | 3 days ago | IN | 0 ETH | 0.00275051 | ||||
Update Rewards | 21218679 | 4 days ago | IN | 0 ETH | 0.00136235 | ||||
Update Rewards | 21215077 | 4 days ago | IN | 0 ETH | 0.0020183 | ||||
Update Rewards | 21211470 | 5 days ago | IN | 0 ETH | 0.00137958 | ||||
Update Rewards | 21207866 | 5 days ago | IN | 0 ETH | 0.00122847 | ||||
Update Rewards | 21204272 | 6 days ago | IN | 0 ETH | 0.00147144 | ||||
Update Rewards | 21200666 | 6 days ago | IN | 0 ETH | 0.00173833 | ||||
Update Rewards | 21197064 | 7 days ago | IN | 0 ETH | 0.00176108 | ||||
Update Rewards | 21193466 | 7 days ago | IN | 0 ETH | 0.00402205 | ||||
Update Rewards | 21189875 | 8 days ago | IN | 0 ETH | 0.00228088 | ||||
Update Rewards | 21186276 | 8 days ago | IN | 0 ETH | 0.00359527 | ||||
Update Rewards | 21182681 | 9 days ago | IN | 0 ETH | 0.00375919 | ||||
Update Rewards | 21179083 | 9 days ago | IN | 0 ETH | 0.00655869 | ||||
Update Rewards | 21175490 | 10 days ago | IN | 0 ETH | 0.00400328 | ||||
Update Rewards | 21171884 | 10 days ago | IN | 0 ETH | 0.00310436 | ||||
Update Rewards | 21168292 | 11 days ago | IN | 0 ETH | 0.00383818 | ||||
Update Rewards | 21164690 | 11 days ago | IN | 0 ETH | 0.00235038 | ||||
Update Rewards | 21161087 | 12 days ago | IN | 0 ETH | 0.0016015 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Keeper
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.22; import {IValidatorsRegistry} from '../interfaces/IValidatorsRegistry.sol'; import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol'; import {IKeeper} from '../interfaces/IKeeper.sol'; import {KeeperValidators} from './KeeperValidators.sol'; import {KeeperRewards} from './KeeperRewards.sol'; import {KeeperOracles} from './KeeperOracles.sol'; import {Errors} from '../libraries/Errors.sol'; /** * @title Keeper * @author StakeWise * @notice Defines the functionality for updating Vaults' rewards and approving validators registrations */ contract Keeper is KeeperOracles, KeeperRewards, KeeperValidators, IKeeper { bool private _initialized; /** * @dev Constructor * @param sharedMevEscrow The address of the shared MEV escrow contract * @param vaultsRegistry The address of the VaultsRegistry contract * @param osTokenVaultController The address of the OsTokenVaultController contract * @param _rewardsDelay The delay in seconds between rewards updates * @param maxAvgRewardPerSecond The maximum possible average reward per second * @param validatorsRegistry The address of the beacon chain validators registry contract */ constructor( address sharedMevEscrow, IVaultsRegistry vaultsRegistry, IOsTokenVaultController osTokenVaultController, uint256 _rewardsDelay, uint256 maxAvgRewardPerSecond, IValidatorsRegistry validatorsRegistry ) KeeperOracles() KeeperRewards( sharedMevEscrow, vaultsRegistry, osTokenVaultController, _rewardsDelay, maxAvgRewardPerSecond ) KeeperValidators(validatorsRegistry) {} /// @inheritdoc IKeeper function initialize(address _owner) external override onlyOwner { if (_owner == address(0)) revert Errors.ZeroAddress(); if (_initialized) revert Errors.AccessDenied(); // transfer ownership _transferOwnership(_owner); _initialized = true; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol) pragma solidity ^0.8.20; import {Ownable} from "./Ownable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is specified at deployment time in the constructor for `Ownable`. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2Step is Ownable { address private _pendingOwner; event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { return _pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { _pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { delete _pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); if (pendingOwner() != sender) { revert OwnableUnauthorizedAccount(sender); } _transferOwnership(sender); } }
// 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 ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.20; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS } /** * @dev The signature derives the `address(0)`. */ error ECDSAInvalidSignature(); /** * @dev The signature has an invalid length. */ error ECDSAInvalidSignatureLength(uint256 length); /** * @dev The signature has an S value that is in the upper half order. */ error ECDSAInvalidSignatureS(bytes32 s); /** * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not * return address(0) without also returning an error description. Errors are documented using an enum (error type) * and a bytes32 providing additional information about the error. * * If no error is returned, then the address can be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { unchecked { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); // We do not check for an overflow here since the shift operation results in 0 or 1. uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError, bytes32) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS, s); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature, bytes32(0)); } return (signer, RecoverError.NoError, bytes32(0)); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); _throwError(error, errorArg); return recovered; } /** * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. */ function _throwError(RecoverError error, bytes32 errorArg) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert ECDSAInvalidSignature(); } else if (error == RecoverError.InvalidSignatureLength) { revert ECDSAInvalidSignatureLength(uint256(errorArg)); } else if (error == RecoverError.InvalidSignatureS) { revert ECDSAInvalidSignatureS(errorArg); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.20; import {MessageHashUtils} from "./MessageHashUtils.sol"; import {ShortStrings, ShortString} from "../ShortStrings.sol"; import {IERC5267} from "../../interfaces/IERC5267.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * @custom:oz-upgrades-unsafe-allow state-variable-immutable */ abstract contract EIP712 is IERC5267 { using ShortStrings for *; bytes32 private constant TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; uint256 private immutable _cachedChainId; address private immutable _cachedThis; bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; ShortString private immutable _name; ShortString private immutable _version; string private _nameFallback; string private _versionFallback; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { _name = name.toShortStringWithFallback(_nameFallback); _version = version.toShortStringWithFallback(_versionFallback); _hashedName = keccak256(bytes(name)); _hashedVersion = keccak256(bytes(version)); _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); _cachedThis = address(this); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _cachedThis && block.chainid == _cachedChainId) { return _cachedDomainSeparator; } else { return _buildDomainSeparator(); } } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {IERC-5267}. */ function eip712Domain() public view virtual returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { return ( hex"0f", // 01111 _EIP712Name(), _EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: By default this function reads _name which is an immutable value. * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). */ // solhint-disable-next-line func-name-mixedcase function _EIP712Name() internal view returns (string memory) { return _name.toStringWithFallback(_nameFallback); } /** * @dev The version parameter for the EIP712 domain. * * NOTE: By default this function reads _version which is an immutable value. * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). */ // solhint-disable-next-line func-name-mixedcase function _EIP712Version() internal view returns (string memory) { return _version.toStringWithFallback(_versionFallback); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.20; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The tree and the proofs can be generated using our * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. * You will find a quickstart guide in the readme. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the Merkle tree could be reinterpreted as a leaf value. * OpenZeppelin's JavaScript library generates Merkle trees that are safe * against this attack out of the box. */ library MerkleProof { /** *@dev The multiproof provided is not valid. */ error MerkleProofInvalidMultiproof(); /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} */ function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. */ function multiProofVerify( bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false * respectively. * * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the Merkle tree. uint256 leavesLen = leaves.length; uint256 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. if (leavesLen + proofLen != totalHashes + 1) { revert MerkleProofInvalidMultiproof(); } // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { if (proofPos != proofLen) { revert MerkleProofInvalidMultiproof(); } unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the Merkle tree. uint256 leavesLen = leaves.length; uint256 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. if (leavesLen + proofLen != totalHashes + 1) { revert MerkleProofInvalidMultiproof(); } // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { if (proofPos != proofLen) { revert MerkleProofInvalidMultiproof(); } unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Sorts the pair (a, b) and hashes the result. */ function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } /** * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory. */ function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) pragma solidity ^0.8.20; import {Strings} from "../Strings.sol"; /** * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. * * The library provides methods for generating a hash of a message that conforms to the * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] * specifications. */ library MessageHashUtils { /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing a bytes32 `messageHash` with * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with * keccak256, although any bytes32 value can be safely used because the final digest will * be re-hashed. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) } } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing an arbitrary `message` with * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { return keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x00` (data with intended validator). * * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended * `validator` address. Then hashing the result. * * See {ECDSA-recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked(hex"19_00", validator, data)); } /** * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`). * * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with * `\x19\x01` and hashing the result. It corresponds to the hash signed by the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. * * See {ECDSA-recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, hex"19_01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) digest := keccak256(ptr, 0x42) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol) pragma solidity ^0.8.20; import {StorageSlot} from "./StorageSlot.sol"; // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. * * Strings of arbitrary length can be optimized using this library if * they are short enough (up to 31 bytes) by packing them with their * length (1 byte) in a single EVM word (32 bytes). Additionally, a * fallback mechanism can be used for every other case. * * Usage example: * * ```solidity * contract Named { * using ShortStrings for *; * * ShortString private immutable _name; * string private _nameFallback; * * constructor(string memory contractName) { * _name = contractName.toShortStringWithFallback(_nameFallback); * } * * function name() external view returns (string memory) { * return _name.toStringWithFallback(_nameFallback); * } * } * ``` */ library ShortStrings { // Used as an identifier for strings longer than 31 bytes. bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. * * This will trigger a `StringTooLong` error is the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); if (bstr.length > 31) { revert StringTooLong(str); } return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); } /** * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); /// @solidity memory-safe-assembly assembly { mstore(str, len) mstore(add(str, 0x20), sstr) } return str; } /** * @dev Return the length of a `ShortString`. */ function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); } return result; } /** * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. */ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { if (bytes(value).length < 32) { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; return ShortString.wrap(FALLBACK_SENTINEL); } } /** * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { if (ShortString.unwrap(value) != FALLBACK_SENTINEL) { return toString(value); } else { return store; } } /** * @dev Return the length of a string that was encoded to `ShortString` or written to storage using * {setWithFallback}. * * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. */ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { if (ShortString.unwrap(value) != FALLBACK_SENTINEL) { return byteLength(value); } else { return bytes(store).length; } } }
// 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 } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.22; import {IKeeperOracles} from './IKeeperOracles.sol'; import {IKeeperValidators} from './IKeeperValidators.sol'; import {IKeeperRewards} from './IKeeperRewards.sol'; /** * @title IKeeper * @author StakeWise * @notice Defines the interface for the Keeper contract */ interface IKeeper is IKeeperOracles, IKeeperRewards, IKeeperValidators { /** * @notice Initializes the Keeper contract. Can only be called once. * @param _owner The address of the owner */ function initialize(address _owner) external; }
// 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; }
// 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; }
// 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; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.22; /** * @title IOsTokenVaultController * @author StakeWise * @notice Defines the interface for the OsTokenVaultController contract */ interface IOsTokenVaultController { /** * @notice Event emitted on minting shares * @param vault The address of the Vault * @param receiver The address that received the shares * @param assets The number of assets collateralized * @param shares The number of tokens the owner received */ event Mint(address indexed vault, address indexed receiver, uint256 assets, uint256 shares); /** * @notice Event emitted on burning shares * @param vault The address of the Vault * @param owner The address that owns the shares * @param assets The total number of assets withdrawn * @param shares The total number of shares burned */ event Burn(address indexed vault, address indexed owner, uint256 assets, uint256 shares); /** * @notice Event emitted on state update * @param profitAccrued The profit accrued since the last update * @param treasuryShares The number of shares minted for the treasury * @param treasuryAssets The number of assets minted for the treasury */ event StateUpdated(uint256 profitAccrued, uint256 treasuryShares, uint256 treasuryAssets); /** * @notice Event emitted on capacity update * @param capacity The amount after which the OsToken stops accepting deposits */ event CapacityUpdated(uint256 capacity); /** * @notice Event emitted on treasury address update * @param treasury The new treasury address */ event TreasuryUpdated(address indexed treasury); /** * @notice Event emitted on fee percent update * @param feePercent The new fee percent */ event FeePercentUpdated(uint16 feePercent); /** * @notice Event emitted on average reward per second update * @param avgRewardPerSecond The new average reward per second */ event AvgRewardPerSecondUpdated(uint256 avgRewardPerSecond); /** * @notice Event emitted on keeper address update * @param keeper The new keeper address */ event KeeperUpdated(address keeper); /** * @notice The OsToken capacity * @return The amount after which the OsToken stops accepting deposits */ function capacity() external view returns (uint256); /** * @notice The DAO treasury address that receives OsToken fees * @return The address of the treasury */ function treasury() external view returns (address); /** * @notice The fee percent (multiplied by 100) * @return The fee percent applied by the OsToken on the rewards */ function feePercent() external view returns (uint64); /** * @notice The address that can update avgRewardPerSecond * @return The address of the keeper contract */ function keeper() external view returns (address); /** * @notice The average reward per second used to mint OsToken rewards * @return The average reward per second earned by the Vaults */ function avgRewardPerSecond() external view returns (uint256); /** * @notice The fee per share used for calculating the fee for every position * @return The cumulative fee per share */ function cumulativeFeePerShare() external view returns (uint256); /** * @notice The total number of shares controlled by the OsToken * @return The total number of shares */ function totalShares() external view returns (uint256); /** * @notice Total assets controlled by the OsToken * @return The total amount of the underlying asset that is "managed" by OsToken */ function totalAssets() 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 OsToken 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 OsToken would exchange for the amount of shares provided */ function convertToAssets(uint256 shares) external view returns (uint256 assets); /** * @notice Updates rewards and treasury fee checkpoint for the OsToken */ function updateState() external; /** * @notice Mint OsToken shares. Can only be called by the registered vault. * @param receiver The address that will receive the shares * @param shares The amount of shares to mint * @return assets The amount of assets minted */ function mintShares(address receiver, uint256 shares) external returns (uint256 assets); /** * @notice Burn shares for withdrawn assets. Can only be called by the registered vault. * @param owner The address that owns the shares * @param shares The amount of shares to burn * @return assets The amount of assets withdrawn */ function burnShares(address owner, uint256 shares) external returns (uint256 assets); /** * @notice Update treasury address. Can only be called by the owner. * @param _treasury The new treasury address */ function setTreasury(address _treasury) external; /** * @notice Update capacity. Can only be called by the owner. * @param _capacity The amount after which the OsToken stops accepting deposits */ function setCapacity(uint256 _capacity) external; /** * @notice Update fee percent. Can only be called by the owner. Cannot be larger than 10 000 (100%). * @param _feePercent The new fee percent */ function setFeePercent(uint16 _feePercent) external; /** * @notice Update keeper address. Can only be called by the owner. * @param _keeper The new keeper address */ function setKeeper(address _keeper) external; /** * @notice Updates average reward per second. Can only be called by the keeper. * @param _avgRewardPerSecond The new average reward per second */ function setAvgRewardPerSecond(uint256 _avgRewardPerSecond) external; }
// SPDX-License-Identifier: CC0-1.0 pragma solidity =0.8.22; /** * @title IValidatorsRegistry * @author Ethereum Foundation * @notice The validators deposit contract common interface */ interface IValidatorsRegistry { /// @notice A processed deposit event. event DepositEvent( bytes pubkey, bytes withdrawal_credentials, bytes amount, bytes signature, bytes index ); /// @notice Query the current deposit root hash. /// @return The deposit root hash. function get_deposit_root() external view returns (bytes32); }
// 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; }
// 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; }
// 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); }
// 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; }
// 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; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.22; import {Ownable2Step, Ownable} from '@openzeppelin/contracts/access/Ownable2Step.sol'; import {EIP712} from '@openzeppelin/contracts/utils/cryptography/EIP712.sol'; import {ECDSA} from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; import {Errors} from '../libraries/Errors.sol'; import {IKeeperOracles} from '../interfaces/IKeeperOracles.sol'; /** * @title KeeperOracles * @author StakeWise * @notice Defines the functionality for verifying signatures of the whitelisted off-chain oracles */ abstract contract KeeperOracles is Ownable2Step, EIP712, IKeeperOracles { uint256 internal constant _signatureLength = 65; uint256 private constant _maxOracles = 30; /// @inheritdoc IKeeperOracles mapping(address => bool) public override isOracle; /// @inheritdoc IKeeperOracles uint256 public override totalOracles; /** * @dev Constructor */ constructor() Ownable(msg.sender) EIP712('KeeperOracles', '1') {} /// @inheritdoc IKeeperOracles function addOracle(address oracle) external override onlyOwner { if (isOracle[oracle]) revert Errors.AlreadyAdded(); // SLOAD to memory uint256 _totalOracles = totalOracles; unchecked { // capped with _maxOracles _totalOracles += 1; } if (_totalOracles > _maxOracles) revert Errors.MaxOraclesExceeded(); // update state isOracle[oracle] = true; totalOracles = _totalOracles; emit OracleAdded(oracle); } /// @inheritdoc IKeeperOracles function removeOracle(address oracle) external override onlyOwner { if (!isOracle[oracle]) revert Errors.AlreadyRemoved(); // SLOAD to memory uint256 _totalOracles; unchecked { // cannot underflow _totalOracles = totalOracles - 1; } isOracle[oracle] = false; totalOracles = _totalOracles; emit OracleRemoved(oracle); } /// @inheritdoc IKeeperOracles function updateConfig(string calldata configIpfsHash) external override onlyOwner { emit ConfigUpdated(configIpfsHash); } /** * @notice Internal function for verifying oracles' signatures * @param requiredSignatures The number of signatures required for the verification to pass * @param message The message that was signed * @param signatures The concatenation of the oracles' signatures */ function _verifySignatures( uint256 requiredSignatures, bytes32 message, bytes calldata signatures ) internal view { if (requiredSignatures == 0) revert Errors.InvalidOracles(); // check whether enough signatures unchecked { // cannot realistically overflow if (signatures.length < requiredSignatures * _signatureLength) revert Errors.NotEnoughSignatures(); } bytes32 data = _hashTypedDataV4(message); address lastOracle; address currentOracle; uint256 startIndex; for (uint256 i = 0; i < requiredSignatures; i++) { unchecked { // cannot overflow as signatures.length is checked above currentOracle = ECDSA.recover(data, signatures[startIndex:startIndex + _signatureLength]); } // signatures must be sorted by oracles' addresses and not repeat if (currentOracle <= lastOracle || !isOracle[currentOracle]) revert Errors.InvalidOracle(); // update last oracle lastOracle = currentOracle; unchecked { // cannot realistically overflow startIndex += _signatureLength; } } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.22; import {MerkleProof} from '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol'; import {IKeeperRewards} from '../interfaces/IKeeperRewards.sol'; import {IVaultMev} from '../interfaces/IVaultMev.sol'; import {Errors} from '../libraries/Errors.sol'; import {IVaultsRegistry} from '../interfaces/IVaultsRegistry.sol'; import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol'; import {KeeperOracles} from './KeeperOracles.sol'; /** * @title KeeperRewards * @author StakeWise * @notice Defines the functionality for updating Vaults' and OsToken rewards */ abstract contract KeeperRewards is KeeperOracles, IKeeperRewards { bytes32 private constant _rewardsUpdateTypeHash = keccak256( 'KeeperRewards(bytes32 rewardsRoot,string rewardsIpfsHash,uint256 avgRewardPerSecond,uint64 updateTimestamp,uint64 nonce)' ); uint256 private immutable _maxAvgRewardPerSecond; address private immutable _sharedMevEscrow; IOsTokenVaultController private immutable _osTokenVaultController; IVaultsRegistry internal immutable _vaultsRegistry; /// @inheritdoc IKeeperRewards uint256 public immutable override rewardsDelay; /// @inheritdoc IKeeperRewards mapping(address => Reward) public override rewards; /// @inheritdoc IKeeperRewards mapping(address => UnlockedMevReward) public override unlockedMevRewards; /// @inheritdoc IKeeperRewards bytes32 public override prevRewardsRoot; /// @inheritdoc IKeeperRewards bytes32 public override rewardsRoot; /// @inheritdoc IKeeperRewards uint256 public override rewardsMinOracles; /// @inheritdoc IKeeperRewards uint64 public override lastRewardsTimestamp; /// @inheritdoc IKeeperRewards uint64 public override rewardsNonce; /** * @dev Constructor * @param sharedMevEscrow The address of the shared MEV escrow contract * @param vaultsRegistry The address of the VaultsRegistry contract * @param osTokenVaultController The address of the OsTokenVaultController contract * @param _rewardsDelay The delay in seconds between rewards updates * @param maxAvgRewardPerSecond The maximum possible average reward per second */ constructor( address sharedMevEscrow, IVaultsRegistry vaultsRegistry, IOsTokenVaultController osTokenVaultController, uint256 _rewardsDelay, uint256 maxAvgRewardPerSecond ) { _sharedMevEscrow = sharedMevEscrow; _vaultsRegistry = vaultsRegistry; _osTokenVaultController = osTokenVaultController; rewardsDelay = _rewardsDelay; _maxAvgRewardPerSecond = maxAvgRewardPerSecond; // set rewardsNonce to 1 so that vaults collateralized // before first rewards update will not have 0 nonce rewardsNonce = 1; } /// @inheritdoc IKeeperRewards function updateRewards(RewardsUpdateParams calldata params) external override { if (!canUpdateRewards()) revert Errors.TooEarlyUpdate(); if (params.avgRewardPerSecond > _maxAvgRewardPerSecond) { revert Errors.InvalidAvgRewardPerSecond(); } // SLOAD to memory uint64 nonce = rewardsNonce; // verify rewards update signatures _verifySignatures( rewardsMinOracles, keccak256( abi.encode( _rewardsUpdateTypeHash, params.rewardsRoot, keccak256(bytes(params.rewardsIpfsHash)), params.avgRewardPerSecond, params.updateTimestamp, nonce ) ), params.signatures ); // update state prevRewardsRoot = rewardsRoot; rewardsRoot = params.rewardsRoot; // cannot overflow on human timescales lastRewardsTimestamp = uint64(block.timestamp); unchecked { // cannot realistically overflow rewardsNonce = nonce + 1; } _osTokenVaultController.setAvgRewardPerSecond(params.avgRewardPerSecond); emit RewardsUpdated( msg.sender, params.rewardsRoot, params.avgRewardPerSecond, params.updateTimestamp, nonce, params.rewardsIpfsHash ); } /// @inheritdoc IKeeperRewards function canUpdateRewards() public view override returns (bool) { unchecked { // cannot overflow as lastRewardsTimestamp & rewardsDelay are uint64 return lastRewardsTimestamp + rewardsDelay < block.timestamp; } } /// @inheritdoc IKeeperRewards function isHarvestRequired(address vault) external view override returns (bool) { // vault is considered harvested in case it does not have any validators (nonce = 0) // or it is up to 1 rewards update behind uint256 nonce = rewards[vault].nonce; unchecked { // cannot overflow as nonce is uint64 return nonce != 0 && nonce + 1 < rewardsNonce; } } /// @inheritdoc IKeeperRewards function canHarvest(address vault) external view override returns (bool) { uint256 nonce = rewards[vault].nonce; return nonce != 0 && nonce < rewardsNonce; } /// @inheritdoc IKeeperRewards function isCollateralized(address vault) public view override returns (bool) { return rewards[vault].nonce != 0; } /// @inheritdoc IKeeperRewards function harvest( HarvestParams calldata params ) external override returns (int256 totalAssetsDelta, uint256 unlockedMevDelta, bool harvested) { if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.AccessDenied(); // SLOAD to memory uint64 currentNonce = rewardsNonce; // allow harvest for the past two updates if (params.rewardsRoot != rewardsRoot) { if (params.rewardsRoot != prevRewardsRoot) revert Errors.InvalidRewardsRoot(); unchecked { // cannot underflow as after first merkle root update nonce will be "2" currentNonce -= 1; } } // verify the proof if ( !MerkleProof.verifyCalldata( params.proof, params.rewardsRoot, keccak256( bytes.concat(keccak256(abi.encode(msg.sender, params.reward, params.unlockedMevReward))) ) ) ) { revert Errors.InvalidProof(); } // SLOAD to memory Reward storage lastReward = rewards[msg.sender]; // check whether Vault's nonce is smaller that the current, otherwise it's already harvested if (lastReward.nonce >= currentNonce) return (0, 0, false); // calculate total assets delta totalAssetsDelta = params.reward - lastReward.assets; harvested = true; // update state lastReward.nonce = currentNonce; lastReward.assets = params.reward; // check whether Vault has unlocked execution reward if (IVaultMev(msg.sender).mevEscrow() == _sharedMevEscrow) { // calculate execution assets reward unlockedMevDelta = params.unlockedMevReward - unlockedMevRewards[msg.sender].assets; // update state unlockedMevRewards[msg.sender] = UnlockedMevReward({ nonce: currentNonce, assets: params.unlockedMevReward }); } // emit event emit Harvested(msg.sender, params.rewardsRoot, totalAssetsDelta, unlockedMevDelta); } /// @inheritdoc IKeeperRewards function setRewardsMinOracles(uint256 _rewardsMinOracles) external override onlyOwner { _setRewardsMinOracles(_rewardsMinOracles); } /** * @dev Internal function for updating rewardsMinOracles * @param _rewardsMinOracles The new value of rewardsMinOracles */ function _setRewardsMinOracles(uint256 _rewardsMinOracles) private { if (_rewardsMinOracles == 0 || totalOracles < _rewardsMinOracles) { revert Errors.InvalidOracles(); } rewardsMinOracles = _rewardsMinOracles; emit RewardsMinOraclesUpdated(_rewardsMinOracles); } /** * @dev Collateralize Vault so that it must be harvested in future reward updates * @param vault The address of the Vault */ function _collateralize(address vault) internal { // vault is already collateralized if (rewards[vault].nonce != 0) return; rewards[vault] = Reward({nonce: rewardsNonce, assets: 0}); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.22; import {IValidatorsRegistry} from '../interfaces/IValidatorsRegistry.sol'; import {IKeeperValidators} from '../interfaces/IKeeperValidators.sol'; import {Errors} from '../libraries/Errors.sol'; import {KeeperOracles} from './KeeperOracles.sol'; import {KeeperRewards} from './KeeperRewards.sol'; /** * @title KeeperValidators * @author StakeWise * @notice Defines the functionality for approving validators' registrations and updating exit signatures */ abstract contract KeeperValidators is KeeperOracles, KeeperRewards, IKeeperValidators { bytes32 private constant _registerValidatorsTypeHash = keccak256( 'KeeperValidators(bytes32 validatorsRegistryRoot,address vault,bytes validators,string exitSignaturesIpfsHash,uint256 deadline)' ); bytes32 private constant _updateExitSigTypeHash = keccak256( 'KeeperValidators(address vault,string exitSignaturesIpfsHash,uint256 nonce,uint256 deadline)' ); IValidatorsRegistry private immutable _validatorsRegistry; /// @inheritdoc IKeeperValidators mapping(address => uint256) public override exitSignaturesNonces; /// @inheritdoc IKeeperValidators uint256 public override validatorsMinOracles; /** * @dev Constructor * @param validatorsRegistry The address of the beacon chain validators registry contract */ constructor(IValidatorsRegistry validatorsRegistry) { _validatorsRegistry = validatorsRegistry; } /// @inheritdoc IKeeperValidators function setValidatorsMinOracles(uint256 _validatorsMinOracles) external override onlyOwner { _setValidatorsMinOracles(_validatorsMinOracles); } /// @inheritdoc IKeeperValidators function approveValidators(ApprovalParams calldata params) external override { if (params.deadline < block.timestamp) revert Errors.DeadlineExpired(); // verify oracles approved registration for the current validators registry contract state if (_validatorsRegistry.get_deposit_root() != params.validatorsRegistryRoot) { revert Errors.InvalidValidatorsRegistryRoot(); } if (!_vaultsRegistry.vaults(msg.sender)) revert Errors.AccessDenied(); // verify oracles approved registration _verifySignatures( validatorsMinOracles, keccak256( abi.encode( _registerValidatorsTypeHash, params.validatorsRegistryRoot, msg.sender, keccak256(params.validators), keccak256(bytes(params.exitSignaturesIpfsHash)), params.deadline ) ), params.signatures ); _collateralize(msg.sender); emit ValidatorsApproval(msg.sender, params.exitSignaturesIpfsHash); } /// @inheritdoc IKeeperValidators function updateExitSignatures( address vault, uint256 deadline, string calldata exitSignaturesIpfsHash, bytes calldata oraclesSignatures ) external override { if (!(_vaultsRegistry.vaults(vault) && isCollateralized(vault))) revert Errors.InvalidVault(); if (deadline < block.timestamp) revert Errors.DeadlineExpired(); // SLOAD to memory uint256 nonce = exitSignaturesNonces[vault]; // verify oracles approved signatures update _verifySignatures( validatorsMinOracles, keccak256( abi.encode( _updateExitSigTypeHash, vault, keccak256(bytes(exitSignaturesIpfsHash)), nonce, deadline ) ), oraclesSignatures ); // update state unchecked { // cannot realistically overflow exitSignaturesNonces[vault] = nonce + 1; } // emit event emit ExitSignaturesUpdated(msg.sender, vault, nonce, exitSignaturesIpfsHash); } /** * @dev Internal function to set the minimum number of oracles required to approve validators * @param _validatorsMinOracles The new minimum number of oracles required to approve validators */ function _setValidatorsMinOracles(uint256 _validatorsMinOracles) private { if (_validatorsMinOracles == 0 || totalOracles < _validatorsMinOracles) { revert Errors.InvalidOracles(); } validatorsMinOracles = _validatorsMinOracles; emit ValidatorsMinOraclesUpdated(_validatorsMinOracles); } }
// 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(); }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 200, "details": { "yul": true } }, "evmVersion": "shanghai", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"sharedMevEscrow","type":"address"},{"internalType":"contract IVaultsRegistry","name":"vaultsRegistry","type":"address"},{"internalType":"contract IOsTokenVaultController","name":"osTokenVaultController","type":"address"},{"internalType":"uint256","name":"_rewardsDelay","type":"uint256"},{"internalType":"uint256","name":"maxAvgRewardPerSecond","type":"uint256"},{"internalType":"contract IValidatorsRegistry","name":"validatorsRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[],"name":"AlreadyAdded","type":"error"},{"inputs":[],"name":"AlreadyRemoved","type":"error"},{"inputs":[],"name":"DeadlineExpired","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[],"name":"InvalidAvgRewardPerSecond","type":"error"},{"inputs":[],"name":"InvalidOracle","type":"error"},{"inputs":[],"name":"InvalidOracles","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"InvalidRewardsRoot","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidValidatorsRegistryRoot","type":"error"},{"inputs":[],"name":"InvalidVault","type":"error"},{"inputs":[],"name":"MaxOraclesExceeded","type":"error"},{"inputs":[],"name":"NotEnoughSignatures","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"TooEarlyUpdate","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"configIpfsHash","type":"string"}],"name":"ConfigUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"string","name":"exitSignaturesIpfsHash","type":"string"}],"name":"ExitSignaturesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"bytes32","name":"rewardsRoot","type":"bytes32"},{"indexed":false,"internalType":"int256","name":"totalAssetsDelta","type":"int256"},{"indexed":false,"internalType":"uint256","name":"unlockedMevDelta","type":"uint256"}],"name":"Harvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oracle","type":"address"}],"name":"OracleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oracle","type":"address"}],"name":"OracleRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oracles","type":"uint256"}],"name":"RewardsMinOraclesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"bytes32","name":"rewardsRoot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"avgRewardPerSecond","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"updateTimestamp","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":false,"internalType":"string","name":"rewardsIpfsHash","type":"string"}],"name":"RewardsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"string","name":"exitSignaturesIpfsHash","type":"string"}],"name":"ValidatorsApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oracles","type":"uint256"}],"name":"ValidatorsMinOraclesUpdated","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oracle","type":"address"}],"name":"addOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"validatorsRegistryRoot","type":"bytes32"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"validators","type":"bytes"},{"internalType":"bytes","name":"signatures","type":"bytes"},{"internalType":"string","name":"exitSignaturesIpfsHash","type":"string"}],"internalType":"struct IKeeperValidators.ApprovalParams","name":"params","type":"tuple"}],"name":"approveValidators","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"canHarvest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"canUpdateRewards","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"exitSignaturesNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"rewardsRoot","type":"bytes32"},{"internalType":"int160","name":"reward","type":"int160"},{"internalType":"uint160","name":"unlockedMevReward","type":"uint160"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"internalType":"struct IKeeperRewards.HarvestParams","name":"params","type":"tuple"}],"name":"harvest","outputs":[{"internalType":"int256","name":"totalAssetsDelta","type":"int256"},{"internalType":"uint256","name":"unlockedMevDelta","type":"uint256"},{"internalType":"bool","name":"harvested","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"isCollateralized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"isHarvestRequired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isOracle","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRewardsTimestamp","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prevRewardsRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"oracle","type":"address"}],"name":"removeOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewards","outputs":[{"internalType":"int192","name":"assets","type":"int192"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsMinOracles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsNonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardsMinOracles","type":"uint256"}],"name":"setRewardsMinOracles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_validatorsMinOracles","type":"uint256"}],"name":"setValidatorsMinOracles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalOracles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"unlockedMevRewards","outputs":[{"internalType":"uint192","name":"assets","type":"uint192"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"configIpfsHash","type":"string"}],"name":"updateConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"string","name":"exitSignaturesIpfsHash","type":"string"},{"internalType":"bytes","name":"oraclesSignatures","type":"bytes"}],"name":"updateExitSignatures","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"rewardsRoot","type":"bytes32"},{"internalType":"uint256","name":"avgRewardPerSecond","type":"uint256"},{"internalType":"uint64","name":"updateTimestamp","type":"uint64"},{"internalType":"string","name":"rewardsIpfsHash","type":"string"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"internalType":"struct IKeeperRewards.RewardsUpdateParams","name":"params","type":"tuple"}],"name":"updateRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"validatorsMinOracles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
61022034620002bf57601f6200253038819003918201601f19168301926001600160401b039290918385118386101762000294578160c09284926040978852833981010312620002bf5780516001600160a01b0391908281168103620002bf576020820151908382168203620002bf5785830151908482168203620002bf5760608401519360a06080820151910151958087168703620002bf57885190620000a782620002c3565b600d825260208201906c4b65657065724f7261636c657360981b82528a5190620000d182620002c3565b600182526020820190603160f81b82523315620002a85760018060a01b03199081600154166001555f549133908316175f553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a36200013584620002df565b926101209384526200014783620004ae565b94610140958652519020918260e0525190206101009b818d524660a05280519160208301937f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f85528284015260608301524660808301523060a083015260a0825260c082019b828d10908d111762000294578b90525190206080523060c0526101809384526101c09586526101a09485526101e0968752610160928352600b8054600160401b600160801b03191668010000000000000000179055610200978852611ed7998a620006598b396080518a611c76015260a0518a611d31015260c0518a611c40015260e0518a611cc501525189611ceb0152518861065f0152518761068901525186610b3e0152518561151b01525184610c4b0152518381816107f701528181610e27015261134c015251828181610b0e01528181610d840152610fc7015251816107a10152f35b634e487b7160e01b5f52604160045260245ffd5b8c51631e4fbdf760e01b81525f6004820152602490fd5b5f80fd5b604081019081106001600160401b038211176200029457604052565b805160209081811015620003795750601f8251116200031a57808251920151908083106200030c57501790565b825f19910360031b1b161790565b90604051809263305a27a960e01b82528060048301528251908160248401525f935b8285106200035f575050604492505f838284010152601f80199101168101030190fd5b84810182015186860160440152938101938593506200033c565b906001600160401b0382116200029457600254926001938481811c91168015620004a3575b838210146200048f57601f811162000458575b5081601f8411600114620003f057509282939183925f94620003e4575b50501b915f199060031b1c19161760025560ff90565b015192505f80620003ce565b919083601f19811660025f52845f20945f905b888383106200043d575050501062000424575b505050811b0160025560ff90565b01515f1960f88460031b161c191690555f808062000416565b85870151885590960195948501948793509081019062000403565b60025f5284601f845f20920160051c820191601f860160051c015b82811062000483575050620003b1565b5f815501859062000473565b634e487b7160e01b5f52602260045260245ffd5b90607f16906200039e565b805160209190828110156200053c575090601f825111620004dd57808251920151908083106200030c57501790565b90604051809263305a27a960e01b82528060048301528251908160248401525f935b82851062000522575050604492505f838284010152601f80199101168101030190fd5b8481018201518686016044015293810193859350620004ff565b6001600160401b03811162000294576003928354926001938481811c911680156200064d575b838210146200048f57601f811162000617575b5081601f8411600114620005b257509282939183925f94620005a6575b50501b915f1990841b1c191617905560ff90565b015192505f8062000592565b919083601f198116875f52845f20945f905b88838310620005fc5750505010620005e4575b505050811b01905560ff90565b01515f1983861b60f8161c191690555f8080620005d7565b858701518855909601959485019487935090810190620005c4565b855f5284601f845f20920160051c820191601f860160051c015b8281106200064157505062000575565b5f815501859062000631565b90607f16906200056256fe60406080815260049081361015610014575f80fd5b5f915f3560e01c806302ad4d2a146111695780630700037d14611128578063203efb5e1461110a578063217863b7146110ec57806325f56f111461109857806326f9872d146110615780632f0bc1a71461103a57806331b36a5114610ff45780633cf8b6b314610fa05780634a940b7a14610da757806350131d4714610d6d578063556a689914610aeb578063715018a614610a865780637386749e14610a6757806379ba509714610a1d5780637d6359ee146109ba578063837d44411461076657806384b0196e146106485780638a76984d146105cc5780638da5cb5b146105a45780639c3a7bd81461053c5780639da8987f146105135780639fdd305e146104f4578063a97e5c93146104b8578063c4d66de814610448578063d7fc432e146103d3578063df5dd1a51461032c578063e30c397814610303578063f2fbad47146102e4578063f2fde38b14610274578063fb70261a146102115763fdc85fc41461017e575f80fd5b3461020d57602036600319011261020d576101976111a8565b61019f611944565b6001600160a01b031680845260208290528284205490929060ff1615610200575f196005540191838552602052832060ff1981541690556005557f9c8e7d83025bef8a04c664b2f753f64b8814bdb7e27291d7e50935f18cc3c7128280a280f35b516355adf54760e11b8152fd5b8280fd5b5050346102705760203660031901126102705760209181906001600160a01b036102396111a8565b16815260068452205460c01c908115159182610259575b50519015158152f35b600b54821c6001600160401b03161191505f610250565b5080fd5b83346102e15760203660031901126102e15761028e6111a8565b610296611944565b600180546001600160a01b0319166001600160a01b0392831690811790915582549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b80fd5b5050346102705781600319360112610270576020906005549051908152f35b50503461027057816003193601126102705760015490516001600160a01b039091168152602090f35b503461020d57602036600319011261020d576103466111a8565b61034e611944565b6001600160a01b031680845260208290528284205490929060ff166103c65760016005540191601e83116103b8578385526020528320805460ff191660011790556005557e47706786c922d17b39285dc59d696bafea72c0b003d3841ae1202076f4c2e48280a280f35b9051633d2a461160e01b8152fd5b5163f411c32760e01b8152fd5b50903461020d57602036600319011261020d578135916103f1611944565b8215801561043d575b6104305750816020917f2f6ee959bfba5f7019d3c0391efaa73bce31771540b48b0be8240c1ff7f1c2e593600a5551908152a180f35b905162d4297d60e81b8152fd5b5082600554106103fa565b503461020d57602036600319011261020d576104626111a8565b9161046b611944565b6001600160a01b038316156104ab5760ff600e541661049e578361048e8461196f565b600160ff19600e541617600e5580f35b51634ca8886760e01b8152fd5b5163d92e233d60e01b8152fd5b503461020d57602036600319011261020d5760209260ff918391906001600160a01b036104e36111a8565b168252855220541690519015158152f35b5050346102705781600319360112610270576020906008549051908152f35b505034610270578160031936011261027057600b548151911c6001600160401b03168152602090f35b50903461020d57602036600319011261020d5781359161055a611944565b82158015610599575b6104305750816020917f40d0dae231c3912f939945de2019b6769b0b6136e363b3d10a1a9d5eb632e47493600d5551908152a180f35b508260055410610563565b505034610270578160031936011261027057905490516001600160a01b039091168152602090f35b50903461020d57602036600319011261020d578135916001600160401b0383116106445761062161063e917f3f8d0d126f4c7f870ec9de90e2f4aa192e5e721bd3c48a77547fb9a7550eed32943691016111be565b91909261062c611944565b519283926020845260208401916117a2565b0390a180f35b8380fd5b50903461020d578260031936011261020d576106837f0000000000000000000000000000000000000000000000000000000000000000611a43565b926106ad7f0000000000000000000000000000000000000000000000000000000000000000611b6a565b9082519260209260208501958587106001600160401b0388111761075357509260206107098388966106fc998b9996528686528151998a99600f60f81b8b5260e0868c015260e08b019061121c565b91898303908a015261121c565b924660608801523060808801528460a088015286840360c088015251928381520193925b82811061073c57505050500390f35b83518552869550938101939281019260010161072d565b604190634e487b7160e01b5f525260245ffd5b50903461020d57610776366111eb565b9160209283810135914283106109ac57835163c5f2892f60e01b8152906001600160a01b03868383817f000000000000000000000000000000000000000000000000000000000000000085165afa928315610960578893610979575b50833580930361096a5786602491875192838092632988bb9f60e21b825233878301527f0000000000000000000000000000000000000000000000000000000000000000165afa908115610960578891610933575b501561092557507f926dc0536ff09ba1fa0fd4ec449001effeb2a30e74031acf619e5d47ffa518fd939261091f926108fd61090b93600d549061087661086f898601866117c2565b369161175d565b8a8151910120608085019561088e61086f88886117c2565b8c81519101208a51928d8401947f4dc81caa2659eadb78c32372188c14ef1941bf7dac776c2621705d839377aee886528c850152336060850152608084015260a083015260c082015260c081526108e4816112a4565b519020906108f560608501856117c2565b929091611808565b610906336119c2565b6117c2565b9190925192839286845233968401916117a2565b0390a280f35b8451634ca8886760e01b8152fd5b6109539150873d8911610959575b61094b81836112bf565b8101906112e0565b5f610827565b503d610941565b86513d8a823e3d90fd5b50845163df0d12d560e01b8152fd5b9092508681813d83116109a5575b61099181836112bf565b810103126109a15751915f6107d2565b8780fd5b503d610987565b8351631ab7da6b60e01b8152fd5b5050346102705760203660031901126102705760209181906001600160a01b036109e26111a8565b16815260068452205460c01c908115159182610a015750519015158152f35b600b54821c6001600160401b031660019091011091505f610250565b50903461020d578260031936011261020d57600154336001600160a01b0390911603610a505782610a4d3361196f565b80f35b60249250519063118cdaa760e01b82523390820152fd5b505034610270578160031936011261027057602090600a549051908152f35b83346102e157806003193601126102e157610a9f611944565b600180546001600160a01b03199081169091555f80549182168155906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b509034610d4e57610afb366111eb565b610b326001600160401b03600b541642907f0000000000000000000000000000000000000000000000000000000000000000011090565b15610d615760208101357f00000000000000000000000000000000000000000000000000000000000000008111610d5257600b546001600160401b03908181861c1690600a548535976060870192610c0c610b9061086f868b6117c2565b60208151910120938a8c89828d0197610ba8896117f4565b9084519360208501957f6eb991bd3352dc6c8a881d0e563e1f3a06f9f23c2dc0e8fa843e0f60053bd633875285015260608401528c60808401521660a08201528860c082015260c08152610bfb816112a4565b519020906108f560808c018c6117c2565b600980546008558a90556fffffffffffffffffffffffffffffffff19164286161760018501891b6fffffffffffffffff00000000000000001617600b557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690813b15610d4e575f809260248b518095819363a52bbb8960e01b83528c878401525af18015610d4457610d0b575b505091610cdf7ffa453467fa89fc89833cc6e9c06a26a6c6db0fa6df2df5c74e685a27b0c931f296959492610cd9610d05956117f4565b966117c2565b9790928151968796875216602086015284015260806060840152339560808401916117a2565b0390a380f35b90919950848211610753575086525f97610cdf7ffa453467fa89fc89833cc6e9c06a26a6c6db0fa6df2df5c74e685a27b0c931f2610ca2565b89513d5f823e3d90fd5b5f80fd5b50505163e14a450760e01b8152fd5b5051612d2360f21b8152fd5b8234610d4e575f366003190112610d4e57602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b509034610d4e576080366003190112610d4e57610dc26111a8565b6024356001600160401b03604435818111610d4e57610de490369087016111be565b9091606435908111610d4e57610dfd90369088016111be565b9060018060a01b039787518097632988bb9f60e21b82528a81169a8b8484015282602460209b8c937f0000000000000000000000000000000000000000000000000000000000000000165afa918215610f96575f92610f77575b5081610f53575b5015610f4557428610610f37575091610f0e7e864475858b77001993c57b93686a71d9b05afd547263395177b71e912a9cc196959492610f32948a5f52600c8852895f2054968a8c600d5492610eb536898b61175d565b8c81519101208351928d8401947fd79280abbde6cd2998125c578f48df3e826012fd55fe0ef7e873e2c82be852a8865284015260608301528a608083015260a082015260a08152610f0581611289565b51902090611808565b875f52600c855260018401875f2055868051958695865285015233968401916117a2565b0390a3005b8751631ab7da6b60e01b8152fd5b8751630681d31960e51b8152fd5b6001600160a01b03165f9081526006602052604090205460c01c151590508a610e5e565b610f8f919250893d8b116109595761094b81836112bf565b908b610e57565b8a513d5f823e3d90fd5b8234610d4e575f366003190112610d4e57602090610feb6001600160401b03600b541642907f0000000000000000000000000000000000000000000000000000000000000000011090565b90519015158152f35b8234610d4e576020366003190112610d4e576001600160a01b036110166111a8565b165f526007602052805f205481519060018060c01b038116825260c01c6020820152f35b8234610d4e575f366003190112610d4e576020906001600160401b03600b54169051908152f35b8234610d4e576020366003190112610d4e576020906001600160a01b036110866111a8565b165f52600c8252805f20549051908152f35b509034610d4e5760031991602036840112610d4e578035926001600160401b038411610d4e576080908436030112610d4e576060926110d7910161131a565b90839293519384526020840152151590820152f35b8234610d4e575f366003190112610d4e576020906009549051908152f35b8234610d4e575f366003190112610d4e57602090600d549051908152f35b8234610d4e576020366003190112610d4e576001600160a01b0361114a6111a8565b165f526006602052805f20548151908060170b825260c01c6020820152f35b8234610d4e576020366003190112610d4e57602090610feb6111896111a8565b6001600160a01b03165f9081526006602052604090205460c01c151590565b600435906001600160a01b0382168203610d4e57565b9181601f84011215610d4e578235916001600160401b038311610d4e5760208381860195010111610d4e57565b60031990602081830112610d4e57600435916001600160401b038311610d4e578260a092030112610d4e5760040190565b91908251928382525f5b848110611246575050825f602080949584010152601f8019910116010190565b602081830181015184830182015201611226565b604081019081106001600160401b0382111761127557604052565b634e487b7160e01b5f52604160045260245ffd5b60c081019081106001600160401b0382111761127557604052565b60e081019081106001600160401b0382111761127557604052565b90601f801991011681019081106001600160401b0382111761127557604052565b90816020910312610d4e57518015158103610d4e5790565b358060130b8103610d4e5790565b356001600160a01b0381168103610d4e5790565b60408051632988bb9f60e21b815233600480830191909152935f936001600160a01b03939192909160209182816024817f00000000000000000000000000000000000000000000000000000000000000008a165afa908115611753575f91611736575b5015611727576001600160401b039283600b54831c16958135946009548603611702575b6060830135601e1984360301811215610d4e578301998a35828111610d4e5760059080821b3603888e0113610d4e578588019c876113de8f6112f8565b9701966113ea88611306565b90878a51928c84019233845260130b8c850152166060830152606082526080820190828210888311176116ef579060a08d9694959392828d528351902092019182528b81526114388161125a565b519020925f925b8284106116b25750505050036116a457335f5260068652845f20805491838b1692838160c01c101561168f576114748e6112f8565b60179190910b60139190910b036001600160bf1b031981126001600160bf1b0382131761167c5782546001600160c01b031660c09c909c1b6001600160c01b0319169b909b17825560179a909a0b9b60019a906114d0906112f8565b82546001600160c01b0360139290920b82166001600160c01b0319918216179093558751633229fa9560e01b815290919089818381335afa908115610d44575f91611646575b5086167f000000000000000000000000000000000000000000000000000000000000000087161461157a575b5050505050505080867f3f1d24dac9bcd1609d88c0def0340864f36b317d196e522a8a437da375f3d8af9251938985528401523392a3565b9091929394959b5061158b8c611306565b335f52600789528683895f20541691160390828211611633575091816115db7f3f1d24dac9bcd1609d88c0def0340864f36b317d196e522a8a437da375f3d8af989795936116279795169d611306565b948751956115e88761125a565b168552888501928352335f90815260078a528790209451855493516001600160c01b039390941691161716911660c01b6001600160c01b031916179055565b905f8080808080611542565b601190634e487b7160e01b5f525260245ffd5b90508981813d8311611675575b61165d81836112bf565b81010312610d4e57518681168103610d4e575f611516565b503d611653565b601182634e487b7160e01b5f525260245ffd5b505f9c508c9b508b9a50505050505050505050565b84516309bde33960e01b8152fd5b9193909294508a85831b84010135908181105f146116e0575f528a526001895f205b9401918b94939161143f565b905f528a526001895f206116d4565b604187634e487b7160e01b5f525260245ffd5b966008548603611717575f19018716966113a1565b8351636a93088d60e11b81528a90fd5b51634ca8886760e01b81528690fd5b61174d9150833d85116109595761094b81836112bf565b5f61137d565b82513d5f823e3d90fd5b9291926001600160401b0382116112755760405191611786601f8201601f1916602001846112bf565b829481845281830111610d4e578281602093845f960137010152565b908060209392818452848401375f828201840152601f01601f1916010190565b903590601e1981360301821215610d4e57018035906001600160401b038211610d4e57602001918136038313610d4e57565b356001600160401b0381168103610d4e5790565b919290928215611933576041908184028310611921576042611828611c3d565b6040966040519161190160f01b835260028301526022820152205f80925f915b87831061185a57505050505050505050565b85850194858111610d4e57878611610d4e57820190895191608083018381106001600160401b0382111761190e578b528783526020903689820111610d4e5783896118b292846118bb9701375f606182015287611d57565b90949194611d91565b6001600160a01b03918216918316918211801592906118f8575b50506118e75760019290920191611848565b8851639589a27d60e01b8152600490fd5b600492505f525260ff895f205416155f806118d5565b88634e487b7160e01b5f5260045260245ffd5b60405163e246dc6360e01b8152600490fd5b60405162d4297d60e81b8152600490fd5b5f546001600160a01b0316330361195757565b60405163118cdaa760e01b8152336004820152602490fd5b6bffffffffffffffffffffffff60a01b9081600154166001555f5460018060a01b0380921680938216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b6001600160a01b03165f8181526006602052604090205460c01c611a4057611a3e906001600160401b0380600b5460401c1660405192611a018461125a565b5f8085526020808601938452918152600690915260409020925190519190911660c01b6001600160c01b0319166001600160c01b03909116179055565b565b50565b60ff8114611a815760ff811690601f8211611a6f5760405191611a658361125a565b8252602082015290565b604051632cd44ac360e21b8152600490fd5b506040515f600254906001908260011c60018416928315611b60575b6020948583108514611b4c578287528694908115611b2c5750600114611acf575b5050611acc925003826112bf565b90565b9093915060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace935f915b818310611b14575050611acc93508201015f80611abe565b85548784018501529485019486945091830191611afc565b915050611acc94925060ff191682840152151560051b8201015f80611abe565b634e487b7160e01b5f52602260045260245ffd5b90607f1690611a9d565b60ff8114611b8c5760ff811690601f8211611a6f5760405191611a658361125a565b506040515f600354906001908260011c60018416928315611c33575b6020948583108514611b4c578287528694908115611b2c5750600114611bd6575050611acc925003826112bf565b9093915060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b935f915b818310611c1b575050611acc93508201015f80611abe565b85548784018501529485019486945091830191611c03565b90607f1690611ba8565b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480611d2e575b15611c98577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a08152611d2881611289565b51902090565b507f00000000000000000000000000000000000000000000000000000000000000004614611c6f565b8151919060418303611d8757611d809250602082015190606060408401519301515f1a90611e14565b9192909190565b50505f9160029190565b6004811015611e005780611da3575050565b60018103611dbd5760405163f645eedf60e01b8152600490fd5b60028103611dde5760405163fce698f760e01b815260048101839052602490fd5b600314611de85750565b602490604051906335e2f38360e21b82526004820152fd5b634e487b7160e01b5f52602160045260245ffd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411611e96579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15611e8b575f516001600160a01b03811615611e8157905f905f90565b505f906001905f90565b6040513d5f823e3d90fd5b5050505f916003919056fea2646970667358221220806be6512be03514f7921df87a664a6fa75c6351b8a129446e90db372b882fd664736f6c6343000816003300000000000000000000000048319f97e5da1233c21c48b80097c0fb7a20ff860000000000000000000000003a0008a588772446f6e656133c2d5029cc4fc20e0000000000000000000000002a261e60fb14586b474c208b1b7ac6d0f5000306000000000000000000000000000000000000000000000000000000000000a8c0000000000000000000000000000000000000000000000000000000017a029afd00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa
Deployed Bytecode
0x60406080815260049081361015610014575f80fd5b5f915f3560e01c806302ad4d2a146111695780630700037d14611128578063203efb5e1461110a578063217863b7146110ec57806325f56f111461109857806326f9872d146110615780632f0bc1a71461103a57806331b36a5114610ff45780633cf8b6b314610fa05780634a940b7a14610da757806350131d4714610d6d578063556a689914610aeb578063715018a614610a865780637386749e14610a6757806379ba509714610a1d5780637d6359ee146109ba578063837d44411461076657806384b0196e146106485780638a76984d146105cc5780638da5cb5b146105a45780639c3a7bd81461053c5780639da8987f146105135780639fdd305e146104f4578063a97e5c93146104b8578063c4d66de814610448578063d7fc432e146103d3578063df5dd1a51461032c578063e30c397814610303578063f2fbad47146102e4578063f2fde38b14610274578063fb70261a146102115763fdc85fc41461017e575f80fd5b3461020d57602036600319011261020d576101976111a8565b61019f611944565b6001600160a01b031680845260208290528284205490929060ff1615610200575f196005540191838552602052832060ff1981541690556005557f9c8e7d83025bef8a04c664b2f753f64b8814bdb7e27291d7e50935f18cc3c7128280a280f35b516355adf54760e11b8152fd5b8280fd5b5050346102705760203660031901126102705760209181906001600160a01b036102396111a8565b16815260068452205460c01c908115159182610259575b50519015158152f35b600b54821c6001600160401b03161191505f610250565b5080fd5b83346102e15760203660031901126102e15761028e6111a8565b610296611944565b600180546001600160a01b0319166001600160a01b0392831690811790915582549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b80fd5b5050346102705781600319360112610270576020906005549051908152f35b50503461027057816003193601126102705760015490516001600160a01b039091168152602090f35b503461020d57602036600319011261020d576103466111a8565b61034e611944565b6001600160a01b031680845260208290528284205490929060ff166103c65760016005540191601e83116103b8578385526020528320805460ff191660011790556005557e47706786c922d17b39285dc59d696bafea72c0b003d3841ae1202076f4c2e48280a280f35b9051633d2a461160e01b8152fd5b5163f411c32760e01b8152fd5b50903461020d57602036600319011261020d578135916103f1611944565b8215801561043d575b6104305750816020917f2f6ee959bfba5f7019d3c0391efaa73bce31771540b48b0be8240c1ff7f1c2e593600a5551908152a180f35b905162d4297d60e81b8152fd5b5082600554106103fa565b503461020d57602036600319011261020d576104626111a8565b9161046b611944565b6001600160a01b038316156104ab5760ff600e541661049e578361048e8461196f565b600160ff19600e541617600e5580f35b51634ca8886760e01b8152fd5b5163d92e233d60e01b8152fd5b503461020d57602036600319011261020d5760209260ff918391906001600160a01b036104e36111a8565b168252855220541690519015158152f35b5050346102705781600319360112610270576020906008549051908152f35b505034610270578160031936011261027057600b548151911c6001600160401b03168152602090f35b50903461020d57602036600319011261020d5781359161055a611944565b82158015610599575b6104305750816020917f40d0dae231c3912f939945de2019b6769b0b6136e363b3d10a1a9d5eb632e47493600d5551908152a180f35b508260055410610563565b505034610270578160031936011261027057905490516001600160a01b039091168152602090f35b50903461020d57602036600319011261020d578135916001600160401b0383116106445761062161063e917f3f8d0d126f4c7f870ec9de90e2f4aa192e5e721bd3c48a77547fb9a7550eed32943691016111be565b91909261062c611944565b519283926020845260208401916117a2565b0390a180f35b8380fd5b50903461020d578260031936011261020d576106837f4b65657065724f7261636c65730000000000000000000000000000000000000d611a43565b926106ad7f3100000000000000000000000000000000000000000000000000000000000001611b6a565b9082519260209260208501958587106001600160401b0388111761075357509260206107098388966106fc998b9996528686528151998a99600f60f81b8b5260e0868c015260e08b019061121c565b91898303908a015261121c565b924660608801523060808801528460a088015286840360c088015251928381520193925b82811061073c57505050500390f35b83518552869550938101939281019260010161072d565b604190634e487b7160e01b5f525260245ffd5b50903461020d57610776366111eb565b9160209283810135914283106109ac57835163c5f2892f60e01b8152906001600160a01b03868383817f00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa85165afa928315610960578893610979575b50833580930361096a5786602491875192838092632988bb9f60e21b825233878301527f0000000000000000000000003a0008a588772446f6e656133c2d5029cc4fc20e165afa908115610960578891610933575b501561092557507f926dc0536ff09ba1fa0fd4ec449001effeb2a30e74031acf619e5d47ffa518fd939261091f926108fd61090b93600d549061087661086f898601866117c2565b369161175d565b8a8151910120608085019561088e61086f88886117c2565b8c81519101208a51928d8401947f4dc81caa2659eadb78c32372188c14ef1941bf7dac776c2621705d839377aee886528c850152336060850152608084015260a083015260c082015260c081526108e4816112a4565b519020906108f560608501856117c2565b929091611808565b610906336119c2565b6117c2565b9190925192839286845233968401916117a2565b0390a280f35b8451634ca8886760e01b8152fd5b6109539150873d8911610959575b61094b81836112bf565b8101906112e0565b5f610827565b503d610941565b86513d8a823e3d90fd5b50845163df0d12d560e01b8152fd5b9092508681813d83116109a5575b61099181836112bf565b810103126109a15751915f6107d2565b8780fd5b503d610987565b8351631ab7da6b60e01b8152fd5b5050346102705760203660031901126102705760209181906001600160a01b036109e26111a8565b16815260068452205460c01c908115159182610a015750519015158152f35b600b54821c6001600160401b031660019091011091505f610250565b50903461020d578260031936011261020d57600154336001600160a01b0390911603610a505782610a4d3361196f565b80f35b60249250519063118cdaa760e01b82523390820152fd5b505034610270578160031936011261027057602090600a549051908152f35b83346102e157806003193601126102e157610a9f611944565b600180546001600160a01b03199081169091555f80549182168155906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b509034610d4e57610afb366111eb565b610b326001600160401b03600b541642907f000000000000000000000000000000000000000000000000000000000000a8c0011090565b15610d615760208101357f000000000000000000000000000000000000000000000000000000017a029afd8111610d5257600b546001600160401b03908181861c1690600a548535976060870192610c0c610b9061086f868b6117c2565b60208151910120938a8c89828d0197610ba8896117f4565b9084519360208501957f6eb991bd3352dc6c8a881d0e563e1f3a06f9f23c2dc0e8fa843e0f60053bd633875285015260608401528c60808401521660a08201528860c082015260c08152610bfb816112a4565b519020906108f560808c018c6117c2565b600980546008558a90556fffffffffffffffffffffffffffffffff19164286161760018501891b6fffffffffffffffff00000000000000001617600b557f0000000000000000000000002a261e60fb14586b474c208b1b7ac6d0f50003066001600160a01b031690813b15610d4e575f809260248b518095819363a52bbb8960e01b83528c878401525af18015610d4457610d0b575b505091610cdf7ffa453467fa89fc89833cc6e9c06a26a6c6db0fa6df2df5c74e685a27b0c931f296959492610cd9610d05956117f4565b966117c2565b9790928151968796875216602086015284015260806060840152339560808401916117a2565b0390a380f35b90919950848211610753575086525f97610cdf7ffa453467fa89fc89833cc6e9c06a26a6c6db0fa6df2df5c74e685a27b0c931f2610ca2565b89513d5f823e3d90fd5b5f80fd5b50505163e14a450760e01b8152fd5b5051612d2360f21b8152fd5b8234610d4e575f366003190112610d4e57602090517f000000000000000000000000000000000000000000000000000000000000a8c08152f35b509034610d4e576080366003190112610d4e57610dc26111a8565b6024356001600160401b03604435818111610d4e57610de490369087016111be565b9091606435908111610d4e57610dfd90369088016111be565b9060018060a01b039787518097632988bb9f60e21b82528a81169a8b8484015282602460209b8c937f0000000000000000000000003a0008a588772446f6e656133c2d5029cc4fc20e165afa918215610f96575f92610f77575b5081610f53575b5015610f4557428610610f37575091610f0e7e864475858b77001993c57b93686a71d9b05afd547263395177b71e912a9cc196959492610f32948a5f52600c8852895f2054968a8c600d5492610eb536898b61175d565b8c81519101208351928d8401947fd79280abbde6cd2998125c578f48df3e826012fd55fe0ef7e873e2c82be852a8865284015260608301528a608083015260a082015260a08152610f0581611289565b51902090611808565b875f52600c855260018401875f2055868051958695865285015233968401916117a2565b0390a3005b8751631ab7da6b60e01b8152fd5b8751630681d31960e51b8152fd5b6001600160a01b03165f9081526006602052604090205460c01c151590508a610e5e565b610f8f919250893d8b116109595761094b81836112bf565b908b610e57565b8a513d5f823e3d90fd5b8234610d4e575f366003190112610d4e57602090610feb6001600160401b03600b541642907f000000000000000000000000000000000000000000000000000000000000a8c0011090565b90519015158152f35b8234610d4e576020366003190112610d4e576001600160a01b036110166111a8565b165f526007602052805f205481519060018060c01b038116825260c01c6020820152f35b8234610d4e575f366003190112610d4e576020906001600160401b03600b54169051908152f35b8234610d4e576020366003190112610d4e576020906001600160a01b036110866111a8565b165f52600c8252805f20549051908152f35b509034610d4e5760031991602036840112610d4e578035926001600160401b038411610d4e576080908436030112610d4e576060926110d7910161131a565b90839293519384526020840152151590820152f35b8234610d4e575f366003190112610d4e576020906009549051908152f35b8234610d4e575f366003190112610d4e57602090600d549051908152f35b8234610d4e576020366003190112610d4e576001600160a01b0361114a6111a8565b165f526006602052805f20548151908060170b825260c01c6020820152f35b8234610d4e576020366003190112610d4e57602090610feb6111896111a8565b6001600160a01b03165f9081526006602052604090205460c01c151590565b600435906001600160a01b0382168203610d4e57565b9181601f84011215610d4e578235916001600160401b038311610d4e5760208381860195010111610d4e57565b60031990602081830112610d4e57600435916001600160401b038311610d4e578260a092030112610d4e5760040190565b91908251928382525f5b848110611246575050825f602080949584010152601f8019910116010190565b602081830181015184830182015201611226565b604081019081106001600160401b0382111761127557604052565b634e487b7160e01b5f52604160045260245ffd5b60c081019081106001600160401b0382111761127557604052565b60e081019081106001600160401b0382111761127557604052565b90601f801991011681019081106001600160401b0382111761127557604052565b90816020910312610d4e57518015158103610d4e5790565b358060130b8103610d4e5790565b356001600160a01b0381168103610d4e5790565b60408051632988bb9f60e21b815233600480830191909152935f936001600160a01b03939192909160209182816024817f0000000000000000000000003a0008a588772446f6e656133c2d5029cc4fc20e8a165afa908115611753575f91611736575b5015611727576001600160401b039283600b54831c16958135946009548603611702575b6060830135601e1984360301811215610d4e578301998a35828111610d4e5760059080821b3603888e0113610d4e578588019c876113de8f6112f8565b9701966113ea88611306565b90878a51928c84019233845260130b8c850152166060830152606082526080820190828210888311176116ef579060a08d9694959392828d528351902092019182528b81526114388161125a565b519020925f925b8284106116b25750505050036116a457335f5260068652845f20805491838b1692838160c01c101561168f576114748e6112f8565b60179190910b60139190910b036001600160bf1b031981126001600160bf1b0382131761167c5782546001600160c01b031660c09c909c1b6001600160c01b0319169b909b17825560179a909a0b9b60019a906114d0906112f8565b82546001600160c01b0360139290920b82166001600160c01b0319918216179093558751633229fa9560e01b815290919089818381335afa908115610d44575f91611646575b5086167f00000000000000000000000048319f97e5da1233c21c48b80097c0fb7a20ff8687161461157a575b5050505050505080867f3f1d24dac9bcd1609d88c0def0340864f36b317d196e522a8a437da375f3d8af9251938985528401523392a3565b9091929394959b5061158b8c611306565b335f52600789528683895f20541691160390828211611633575091816115db7f3f1d24dac9bcd1609d88c0def0340864f36b317d196e522a8a437da375f3d8af989795936116279795169d611306565b948751956115e88761125a565b168552888501928352335f90815260078a528790209451855493516001600160c01b039390941691161716911660c01b6001600160c01b031916179055565b905f8080808080611542565b601190634e487b7160e01b5f525260245ffd5b90508981813d8311611675575b61165d81836112bf565b81010312610d4e57518681168103610d4e575f611516565b503d611653565b601182634e487b7160e01b5f525260245ffd5b505f9c508c9b508b9a50505050505050505050565b84516309bde33960e01b8152fd5b9193909294508a85831b84010135908181105f146116e0575f528a526001895f205b9401918b94939161143f565b905f528a526001895f206116d4565b604187634e487b7160e01b5f525260245ffd5b966008548603611717575f19018716966113a1565b8351636a93088d60e11b81528a90fd5b51634ca8886760e01b81528690fd5b61174d9150833d85116109595761094b81836112bf565b5f61137d565b82513d5f823e3d90fd5b9291926001600160401b0382116112755760405191611786601f8201601f1916602001846112bf565b829481845281830111610d4e578281602093845f960137010152565b908060209392818452848401375f828201840152601f01601f1916010190565b903590601e1981360301821215610d4e57018035906001600160401b038211610d4e57602001918136038313610d4e57565b356001600160401b0381168103610d4e5790565b919290928215611933576041908184028310611921576042611828611c3d565b6040966040519161190160f01b835260028301526022820152205f80925f915b87831061185a57505050505050505050565b85850194858111610d4e57878611610d4e57820190895191608083018381106001600160401b0382111761190e578b528783526020903689820111610d4e5783896118b292846118bb9701375f606182015287611d57565b90949194611d91565b6001600160a01b03918216918316918211801592906118f8575b50506118e75760019290920191611848565b8851639589a27d60e01b8152600490fd5b600492505f525260ff895f205416155f806118d5565b88634e487b7160e01b5f5260045260245ffd5b60405163e246dc6360e01b8152600490fd5b60405162d4297d60e81b8152600490fd5b5f546001600160a01b0316330361195757565b60405163118cdaa760e01b8152336004820152602490fd5b6bffffffffffffffffffffffff60a01b9081600154166001555f5460018060a01b0380921680938216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b6001600160a01b03165f8181526006602052604090205460c01c611a4057611a3e906001600160401b0380600b5460401c1660405192611a018461125a565b5f8085526020808601938452918152600690915260409020925190519190911660c01b6001600160c01b0319166001600160c01b03909116179055565b565b50565b60ff8114611a815760ff811690601f8211611a6f5760405191611a658361125a565b8252602082015290565b604051632cd44ac360e21b8152600490fd5b506040515f600254906001908260011c60018416928315611b60575b6020948583108514611b4c578287528694908115611b2c5750600114611acf575b5050611acc925003826112bf565b90565b9093915060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace935f915b818310611b14575050611acc93508201015f80611abe565b85548784018501529485019486945091830191611afc565b915050611acc94925060ff191682840152151560051b8201015f80611abe565b634e487b7160e01b5f52602260045260245ffd5b90607f1690611a9d565b60ff8114611b8c5760ff811690601f8211611a6f5760405191611a658361125a565b506040515f600354906001908260011c60018416928315611c33575b6020948583108514611b4c578287528694908115611b2c5750600114611bd6575050611acc925003826112bf565b9093915060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b935f915b818310611c1b575050611acc93508201015f80611abe565b85548784018501529485019486945091830191611c03565b90607f1690611ba8565b307f0000000000000000000000006b5815467da09daa7dc83db21c9239d98bb487b56001600160a01b03161480611d2e575b15611c98577f72c21c5631e3e6a75dff794e3643f61ea145facd2fdeeb1ac36ea20fd98d05b490565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f91c0353c161c2efe241d5da7ab0477d397664f53304e87cdc5ef02748343823e60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a08152611d2881611289565b51902090565b507f00000000000000000000000000000000000000000000000000000000000000014614611c6f565b8151919060418303611d8757611d809250602082015190606060408401519301515f1a90611e14565b9192909190565b50505f9160029190565b6004811015611e005780611da3575050565b60018103611dbd5760405163f645eedf60e01b8152600490fd5b60028103611dde5760405163fce698f760e01b815260048101839052602490fd5b600314611de85750565b602490604051906335e2f38360e21b82526004820152fd5b634e487b7160e01b5f52602160045260245ffd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411611e96579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15611e8b575f516001600160a01b03811615611e8157905f905f90565b505f906001905f90565b6040513d5f823e3d90fd5b5050505f916003919056fea2646970667358221220806be6512be03514f7921df87a664a6fa75c6351b8a129446e90db372b882fd664736f6c63430008160033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000048319f97e5da1233c21c48b80097c0fb7a20ff860000000000000000000000003a0008a588772446f6e656133c2d5029cc4fc20e0000000000000000000000002a261e60fb14586b474c208b1b7ac6d0f5000306000000000000000000000000000000000000000000000000000000000000a8c0000000000000000000000000000000000000000000000000000000017a029afd00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa
-----Decoded View---------------
Arg [0] : sharedMevEscrow (address): 0x48319f97E5Da1233c21c48b80097c0FB7a20Ff86
Arg [1] : vaultsRegistry (address): 0x3a0008a588772446f6e656133C2D5029CC4FC20E
Arg [2] : osTokenVaultController (address): 0x2A261e60FB14586B474C208b1B7AC6D0f5000306
Arg [3] : _rewardsDelay (uint256): 43200
Arg [4] : maxAvgRewardPerSecond (uint256): 6341958397
Arg [5] : validatorsRegistry (address): 0x00000000219ab540356cBB839Cbe05303d7705Fa
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 00000000000000000000000048319f97e5da1233c21c48b80097c0fb7a20ff86
Arg [1] : 0000000000000000000000003a0008a588772446f6e656133c2d5029cc4fc20e
Arg [2] : 0000000000000000000000002a261e60fb14586b474c208b1b7ac6d0f5000306
Arg [3] : 000000000000000000000000000000000000000000000000000000000000a8c0
Arg [4] : 000000000000000000000000000000000000000000000000000000017a029afd
Arg [5] : 00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.