编译器
0.8.19+commit.7dd6d404
文件 1 的 11:Auth.sol
pragma solidity ^0.8.19;
contract Auth {
error Unauthorized();
error AlreadySet();
error NoAdmin();
event AdminAdded(address indexed newAdmin);
event AdminDeleted(address indexed oldAdmin);
event OperatorAdded(address indexed newOperator);
event OperatorDeleted(address indexed oldOperator);
uint8 adminsCounter;
mapping(address => bool) public operators;
mapping(address => bool) public admins;
constructor(address initialAdmin) {
admins[initialAdmin] = true;
unchecked {
++adminsCounter;
}
operators[initialAdmin] = true;
}
modifier onlyAdmin() {
if (!admins[msg.sender]) {
revert Unauthorized();
}
_;
}
modifier onlyOperator() {
if (!operators[msg.sender]) {
revert Unauthorized();
}
_;
}
function addAdmin(address newAdmin) external onlyAdmin {
if (admins[newAdmin]) revert AlreadySet();
++adminsCounter;
admins[newAdmin] = true;
emit AdminAdded(newAdmin);
}
function deleteAdmin(address oldAdmin) external onlyAdmin {
if (!admins[oldAdmin]) revert AlreadySet();
--adminsCounter;
if (adminsCounter == 0) revert NoAdmin();
admins[oldAdmin] = false;
emit AdminDeleted(oldAdmin);
}
function addOperator(address newOperator) external onlyAdmin {
if (operators[newOperator]) revert AlreadySet();
operators[newOperator] = true;
emit OperatorAdded(newOperator);
}
function deleteOperator(address oldOperator) external onlyAdmin {
if (!operators[oldOperator]) revert AlreadySet();
operators[oldOperator] = false;
emit OperatorDeleted(oldOperator);
}
}
文件 2 的 11:ERC20.sol
pragma solidity >=0.8.0;
abstract contract ERC20 {
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
string public name;
string public symbol;
uint8 public immutable decimals;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender];
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
文件 3 的 11:Errors.sol
pragma solidity ^0.8.19;
interface MevEthErrors {
error StakingPaused();
error NotEnoughEth();
error ZeroValue();
error InvalidOperator();
error DepositTooSmall();
error InvalidSender();
error PrematureStakingModuleUpdateFinalization();
error PrematureMevEthShareVaultUpdateFinalization();
error InvalidPendingStakingModule();
error InvalidPendingMevEthShareVault();
error TransferExceedsAllowance();
error TransferFailed();
error ZeroAddress();
error AlreadyInitialized();
error SendError();
error FeesTooHigh();
error WrongDepositAmount();
error WrongWithdrawAmount();
error UnAuthorizedCaller();
error WithdrawTooSmall();
error NotFinalised();
error AlreadyClaimed();
error AlreadyFinalised();
error IndexExceedsQueueLength();
error DepositWasFrontrun();
error SandwichProtection();
error NonZeroVaultBalance();
error AlreadyDeposited();
error IncorrectWithdrawalCredentials();
}
文件 4 的 11:FixedPointMathLib.sol
pragma solidity >=0.8.0;
library FixedPointMathLib {
uint256 internal constant WAD = 1e18;
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD);
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD);
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y);
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y);
}
function powWad(int256 x, int256 y) internal pure returns (int256) {
return expWad((lnWad(x) * y) / int256(WAD));
}
function expWad(int256 x) internal pure returns (int256 r) {
unchecked {
if (x <= -42139678854452767551) return 0;
if (x >= 135305999368893231589) revert("EXP_OVERFLOW");
x = (x << 78) / 5**18;
int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
x = x - k * 54916777467707473351141471128;
int256 y = x + 1346386616545796478920950773328;
y = ((y * x) >> 96) + 57155421227552351082224309758442;
int256 p = y + x - 94201549194550492254356042504812;
p = ((p * y) >> 96) + 28719021644029726153956944680412240;
p = p * x + (4385272521454847904659076985693276 << 96);
int256 q = x - 2855989394907223263936484059900;
q = ((q * x) >> 96) + 50020603652535783019961831881945;
q = ((q * x) >> 96) - 533845033583426703283633433725380;
q = ((q * x) >> 96) + 3604857256930695427073651918091429;
q = ((q * x) >> 96) - 14423608567350463180887372962807573;
q = ((q * x) >> 96) + 26449188498355588339934803723976023;
assembly {
r := sdiv(p, q)
}
r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
}
}
function lnWad(int256 x) internal pure returns (int256 r) {
unchecked {
require(x > 0, "UNDEFINED");
int256 k = int256(log2(uint256(x))) - 96;
x <<= uint256(159 - k);
x = int256(uint256(x) >> 159);
int256 p = x + 3273285459638523848632254066296;
p = ((p * x) >> 96) + 24828157081833163892658089445524;
p = ((p * x) >> 96) + 43456485725739037958740375743393;
p = ((p * x) >> 96) - 11111509109440967052023855526967;
p = ((p * x) >> 96) - 45023709667254063763336534515857;
p = ((p * x) >> 96) - 14706773417378608786704636184526;
p = p * x - (795164235651350426258249787498 << 96);
int256 q = x + 5573035233440673466300451813936;
q = ((q * x) >> 96) + 71694874799317883764090561454958;
q = ((q * x) >> 96) + 283447036172924575727196451306956;
q = ((q * x) >> 96) + 401686690394027663651624208769553;
q = ((q * x) >> 96) + 204048457590392012362485061816622;
q = ((q * x) >> 96) + 31853899698501571402653359427138;
q = ((q * x) >> 96) + 909429971244387300277376558375;
assembly {
r := sdiv(p, q)
}
r *= 1677202110996718588342820967067443963516166;
r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
r += 600920179829731861736702779321621459595472258049074101567377883020018308;
r >>= 174;
}
}
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
z := mul(x, y)
if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
revert(0, 0)
}
z := div(z, denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
z := mul(x, y)
if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
revert(0, 0)
}
z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
assembly {
switch x
case 0 {
switch n
case 0 {
z := scalar
}
default {
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
z := scalar
}
default {
z := x
}
let half := shr(1, scalar)
for {
n := shr(1, n)
} n {
n := shr(1, n)
} {
if shr(128, x) {
revert(0, 0)
}
let xx := mul(x, x)
let xxRound := add(xx, half)
if lt(xxRound, xx) {
revert(0, 0)
}
x := div(xxRound, scalar)
if mod(n, 2) {
let zx := mul(z, x)
if iszero(eq(div(zx, x), z)) {
if iszero(iszero(x)) {
revert(0, 0)
}
}
let zxRound := add(zx, half)
if lt(zxRound, zx) {
revert(0, 0)
}
z := div(zxRound, scalar)
}
}
}
}
}
function sqrt(uint256 x) internal pure returns (uint256 z) {
assembly {
let y := x
z := 181
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
z := shr(18, mul(z, add(y, 65536)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := sub(z, lt(div(x, z), z))
}
}
function log2(uint256 x) internal pure returns (uint256 r) {
require(x > 0, "UNDEFINED");
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
r := or(r, shl(2, lt(0xf, shr(r, x))))
r := or(r, shl(1, lt(0x3, shr(r, x))))
r := or(r, lt(0x1, shr(r, x)))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}
文件 5 的 11:IERC20Burnable.sol
pragma solidity ^0.8.19;
interface IERC20Burnable {
function burnFrom(address account, uint256 amount) external;
}
文件 6 的 11:IERC4626.sol
pragma solidity ^0.8.19;
interface IERC4626 {
function asset() external view returns (address assetTokenAddress);
function totalAssets() external view returns (uint256 totalManagedAssets);
function convertToShares(uint256 assets) external view returns (uint256 shares);
function convertToAssets(uint256 shares) external view returns (uint256 assets);
function maxDeposit(address reciever) external view returns (uint256 maxAssets);
function previewDeposit(uint256 assets) external view returns (uint256 shares);
function deposit(uint256 assets, address receiver) external payable returns (uint256 shares);
function maxMint(address reciever) external view returns (uint256 maxShares);
function previewMint(uint256 shares) external view returns (uint256 assets);
function mint(uint256 shares, address receiver) external payable returns (uint256 assets);
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
function maxRedeem(address owner) external view returns (uint256 maxShares);
function previewRedeem(uint256 shares) external view returns (uint256 assets);
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);
}
文件 7 的 11:IStakingModule.sol
pragma solidity ^0.8.19;
interface IStakingModule {
struct ValidatorData {
address operator;
bytes pubkey;
bytes32 withdrawal_credentials;
bytes signature;
bytes32 deposit_data_root;
}
function deposit(ValidatorData calldata data, bytes32 latestDepositRoot) external payable;
function validators() external view returns (uint256);
function mevEth() external view returns (address);
function VALIDATOR_DEPOSIT_SIZE() external view returns (uint256);
function payRewards(uint256 rewards) external;
function payValidatorWithdraw() external;
function recoverToken(address token, address recipient, uint256 amount) external;
function record() external returns (uint128, uint128, uint128, uint128);
function registerExit() external;
function batchMigrate(IStakingModule.ValidatorData[] calldata batchData) external;
}
文件 8 的 11:ITinyMevEth.sol
pragma solidity ^0.8.19;
interface ITinyMevEth {
function grantRewards() external payable;
function grantValidatorWithdraw() external payable;
}
文件 9 的 11:MevEth.sol
pragma solidity ^0.8.19;
import { Auth } from "./libraries/Auth.sol";
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol";
import { FixedPointMathLib } from "solmate/utils/FixedPointMathLib.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";
import { IERC4626 } from "./interfaces/IERC4626.sol";
import { WETH } from "solmate/tokens/WETH.sol";
import { MevEthErrors } from "./interfaces/Errors.sol";
import { IStakingModule } from "./interfaces/IStakingModule.sol";
import { IERC20Burnable } from "./interfaces/IERC20Burnable.sol";
import { ITinyMevEth } from "./interfaces/ITinyMevEth.sol";
contract MevEth is Auth, ERC20, IERC4626, ITinyMevEth {
using SafeTransferLib for WETH;
using FixedPointMathLib for uint256;
bool public stakingPaused;
bool public initialized;
uint16 internal constant feeDenominator = 10_000;
uint64 public pendingStakingModuleCommittedTimestamp;
uint64 public pendingMevEthShareVaultCommittedTimestamp;
uint64 internal constant MODULE_UPDATE_TIME_DELAY = 7 days;
uint128 internal constant MAX_DEPOSIT = type(uint128).max;
uint128 public constant MIN_DEPOSIT = 0.01 ether;
uint128 public MIN_WITHDRAWAL;
address public mevEthShareVault;
address public pendingMevEthShareVault;
IStakingModule public stakingModule;
IStakingModule public pendingStakingModule;
WETH public immutable WETH9;
uint256 internal lastRewards;
Fraction public fraction;
uint256 public constant CREAM_TO_MEV_ETH_PERCENT = 1130;
address public constant creamToken = 0x49D72e3973900A195A155a46441F0C08179FdB64;
mapping(address => uint256) lastDeposit;
mapping(bytes => bool) depositedValidators;
struct Fraction {
uint128 elastic;
uint128 base;
}
constructor(address authority, address weth) Auth(authority) ERC20("Mev Liquid Staking Receipt", "mevETH", 18) {
WETH9 = WETH(payable(weth));
MIN_WITHDRAWAL = MIN_DEPOSIT;
}
function calculateNeededEtherBuffer() public view returns (uint256) {
unchecked {
return max(withdrawalAmountQueued, (stakingModule.VALIDATOR_DEPOSIT_SIZE() / 100) * 90);
}
}
event MevEthInitialized(address indexed mevEthShareVault, address indexed stakingModule);
function init(address initialShareVault, address initialStakingModule) external onlyAdmin {
if (initialShareVault == address(0)) {
revert MevEthErrors.ZeroAddress();
}
if (initialStakingModule == address(0)) {
revert MevEthErrors.ZeroAddress();
}
if (initialized) {
revert MevEthErrors.AlreadyInitialized();
}
initialized = true;
mevEthShareVault = initialShareVault;
stakingModule = IStakingModule(initialStakingModule);
emit MevEthInitialized(initialShareVault, initialStakingModule);
}
event StakingPaused();
event StakingUnpaused();
function _stakingUnpaused() internal view {
if (stakingPaused) revert MevEthErrors.StakingPaused();
}
function pauseStaking() external onlyAdmin {
stakingPaused = true;
emit StakingPaused();
}
function unpauseStaking() external onlyAdmin {
stakingPaused = false;
emit StakingUnpaused();
}
event StakingModuleUpdateCommitted(address indexed oldModule, address indexed pendingModule, uint64 indexed eligibleForFinalization);
event StakingModuleUpdateFinalized(address indexed oldModule, address indexed newModule);
event StakingModuleUpdateCanceled(address indexed oldModule, address indexed pendingModule);
function commitUpdateStakingModule(IStakingModule newModule) external onlyAdmin {
if (address(newModule) == address(0)) {
revert MevEthErrors.InvalidPendingStakingModule();
}
pendingStakingModule = newModule;
pendingStakingModuleCommittedTimestamp = uint64(block.timestamp);
emit StakingModuleUpdateCommitted(address(stakingModule), address(newModule), uint64(block.timestamp + MODULE_UPDATE_TIME_DELAY));
}
function finalizeUpdateStakingModule() external onlyAdmin {
uint64 committedTimestamp = pendingStakingModuleCommittedTimestamp;
if (address(pendingStakingModule) == address(0) || committedTimestamp == 0) {
revert MevEthErrors.InvalidPendingStakingModule();
}
if (uint64(block.timestamp) < committedTimestamp + MODULE_UPDATE_TIME_DELAY) {
revert MevEthErrors.PrematureStakingModuleUpdateFinalization();
}
emit StakingModuleUpdateFinalized(address(stakingModule), address(pendingStakingModule));
stakingModule = pendingStakingModule;
pendingStakingModule = IStakingModule(address(0));
pendingStakingModuleCommittedTimestamp = 0;
}
function cancelUpdateStakingModule() external onlyAdmin {
if (address(pendingStakingModule) == address(0) || pendingStakingModuleCommittedTimestamp == 0) {
revert MevEthErrors.InvalidPendingStakingModule();
}
emit StakingModuleUpdateCanceled(address(stakingModule), address(pendingStakingModule));
pendingStakingModule = IStakingModule(address(0));
pendingStakingModuleCommittedTimestamp = 0;
}
event MevEthShareVaultUpdateCommitted(address indexed oldVault, address indexed pendingVault, uint64 indexed eligibleForFinalization);
event MevEthShareVaultUpdateFinalized(address indexed oldVault, address indexed newVault);
event MevEthShareVaultUpdateCanceled(address indexed oldVault, address indexed newVault);
function commitUpdateMevEthShareVault(address newMevEthShareVault) external onlyAdmin {
if (newMevEthShareVault == address(0)) {
revert MevEthErrors.ZeroAddress();
}
pendingMevEthShareVault = newMevEthShareVault;
pendingMevEthShareVaultCommittedTimestamp = uint64(block.timestamp);
emit MevEthShareVaultUpdateCommitted(mevEthShareVault, newMevEthShareVault, uint64(block.timestamp + MODULE_UPDATE_TIME_DELAY));
}
function finalizeUpdateMevEthShareVault() external onlyAdmin {
uint64 committedTimestamp = pendingMevEthShareVaultCommittedTimestamp;
if (pendingMevEthShareVault == address(0) || committedTimestamp == 0) {
revert MevEthErrors.InvalidPendingMevEthShareVault();
}
if (uint64(block.timestamp) < committedTimestamp + MODULE_UPDATE_TIME_DELAY) {
revert MevEthErrors.PrematureMevEthShareVaultUpdateFinalization();
}
emit MevEthShareVaultUpdateFinalized(mevEthShareVault, address(pendingMevEthShareVault));
mevEthShareVault = pendingMevEthShareVault;
pendingMevEthShareVault = address(0);
pendingMevEthShareVaultCommittedTimestamp = 0;
}
function cancelUpdateMevEthShareVault() external onlyAdmin {
if (pendingMevEthShareVault == address(0) || pendingMevEthShareVaultCommittedTimestamp == 0) {
revert MevEthErrors.InvalidPendingMevEthShareVault();
}
emit MevEthShareVaultUpdateCanceled(mevEthShareVault, pendingMevEthShareVault);
pendingMevEthShareVault = address(0);
pendingMevEthShareVaultCommittedTimestamp = 0;
}
event ValidatorCreated(address indexed stakingModule, IStakingModule.ValidatorData newValidator);
function createValidator(IStakingModule.ValidatorData calldata newData, bytes32 latestDepositRoot) external onlyOperator {
_stakingUnpaused();
if (depositedValidators[newData.pubkey]) revert MevEthErrors.AlreadyDeposited();
depositedValidators[newData.pubkey] = true;
IStakingModule _stakingModule = stakingModule;
if (address(_stakingModule) != address(uint160(uint256(newData.withdrawal_credentials)))) revert MevEthErrors.IncorrectWithdrawalCredentials();
uint256 depositSize = _stakingModule.VALIDATOR_DEPOSIT_SIZE();
if (address(this).balance < depositSize + calculateNeededEtherBuffer()) {
revert MevEthErrors.NotEnoughEth();
}
_stakingModule.deposit{ value: depositSize }(newData, latestDepositRoot);
emit ValidatorCreated(address(_stakingModule), newData);
}
event Rewards(address sender, uint256 amount);
function grantRewards() external payable {
if (!(msg.sender == address(stakingModule) || msg.sender == mevEthShareVault)) revert MevEthErrors.UnAuthorizedCaller();
if (msg.value == 0) revert MevEthErrors.ZeroValue();
fraction.elastic += uint128(msg.value);
lastRewards = block.number;
emit Rewards(msg.sender, msg.value);
}
event ValidatorWithdraw(address sender, uint256 amount);
function grantValidatorWithdraw() external payable {
if (!(msg.sender == address(stakingModule) || msg.sender == mevEthShareVault)) revert MevEthErrors.InvalidSender();
if (msg.value != 32 ether) {
revert MevEthErrors.WrongWithdrawAmount();
}
emit ValidatorWithdraw(msg.sender, msg.value);
stakingModule.registerExit();
}
struct WithdrawalTicket {
bool claimed;
address receiver;
uint128 amount;
uint128 accumulatedAmount;
}
event WithdrawalQueueOpened(address indexed recipient, uint256 indexed withdrawalId, uint256 assets);
event WithdrawalQueueClosed(address indexed recipient, uint256 indexed withdrawalId, uint256 assets);
uint256 public queueLength;
uint256 public requestsFinalisedUntil;
uint256 public withdrawalAmountQueued;
mapping(uint256 ticketNumber => WithdrawalTicket ticket) public withdrawalQueue;
function claim(uint256 withdrawalId) external {
if (withdrawalId > requestsFinalisedUntil) revert MevEthErrors.NotFinalised();
WithdrawalTicket storage ticket = withdrawalQueue[withdrawalId];
if (ticket.claimed) revert MevEthErrors.AlreadyClaimed();
withdrawalQueue[withdrawalId].claimed = true;
withdrawalAmountQueued -= uint256(ticket.amount);
emit WithdrawalQueueClosed(ticket.receiver, withdrawalId, uint256(ticket.amount));
WETH9.deposit{ value: uint256(ticket.amount) }();
WETH9.safeTransfer(ticket.receiver, uint256(ticket.amount));
}
function processWithdrawalQueue(uint256 newRequestsFinalisedUntil) external onlyOperator {
if (newRequestsFinalisedUntil > queueLength) revert MevEthErrors.IndexExceedsQueueLength();
uint256 balance = address(this).balance;
if (withdrawalAmountQueued >= balance) revert MevEthErrors.NotEnoughEth();
uint256 available = balance - withdrawalAmountQueued;
uint256 finalised = requestsFinalisedUntil;
if (newRequestsFinalisedUntil < finalised) revert MevEthErrors.AlreadyFinalised();
uint256 delta = uint256(withdrawalQueue[newRequestsFinalisedUntil].accumulatedAmount - withdrawalQueue[finalised].accumulatedAmount);
if (available < delta) revert MevEthErrors.NotEnoughEth();
requestsFinalisedUntil = newRequestsFinalisedUntil;
withdrawalAmountQueued += delta;
}
function setMinWithdrawal(uint128 newMinimum) public onlyAdmin {
MIN_WITHDRAWAL = newMinimum;
}
function asset() external view returns (address assetTokenAddress) {
assetTokenAddress = address(WETH9);
}
function totalAssets() external view returns (uint256 totalManagedAssets) {
totalManagedAssets = uint256(fraction.elastic);
}
function convertToShares(uint256 assets) public view returns (uint256 shares) {
if ((uint256(fraction.elastic) == 0) || (uint256(fraction.base) == 0)) {
shares = assets;
} else {
shares = (assets * uint256(fraction.base)) / uint256(fraction.elastic);
}
}
function convertToAssets(uint256 shares) public view returns (uint256 assets) {
if (uint256(fraction.elastic) == 0 || uint256(fraction.base) == 0) {
assets = shares;
} else {
assets = (shares * uint256(fraction.elastic)) / uint256(fraction.base);
}
}
function maxDeposit(address) external view returns (uint256 maxAssets) {
if (stakingPaused) {
return 0;
}
maxAssets = uint256(MAX_DEPOSIT);
}
function previewDeposit(uint256 assets) external view returns (uint256 shares) {
return convertToShares(assets);
}
function _deposit(address receiver, uint256 assets, uint256 shares) internal {
if (assets < MIN_DEPOSIT) revert MevEthErrors.DepositTooSmall();
fraction.elastic += uint128(assets);
fraction.base += uint128(shares);
lastDeposit[msg.sender] = block.number;
lastDeposit[receiver] = block.number;
if (msg.value == 0) {
WETH9.safeTransferFrom(msg.sender, address(this), assets);
WETH9.withdraw(assets);
} else {
if (msg.value != assets) revert MevEthErrors.WrongDepositAmount();
}
_mint(receiver, shares);
emit Deposit(msg.sender, receiver, assets, shares);
}
function deposit(uint256 assets, address receiver) external payable returns (uint256 shares) {
_stakingUnpaused();
shares = convertToShares(assets);
_deposit(receiver, assets, shares);
}
function maxMint(address) external view returns (uint256 maxShares) {
if (stakingPaused) {
return 0;
}
return MAX_DEPOSIT;
}
function previewMint(uint256 shares) external view returns (uint256 assets) {
return convertToAssets(shares);
}
function mint(uint256 shares, address receiver) external payable returns (uint256 assets) {
_stakingUnpaused();
assets = convertToAssets(shares);
_deposit(receiver, assets, shares);
}
function maxWithdraw(address owner) external view returns (uint256 maxAssets) {
maxAssets = min(address(this).balance, convertToAssets(balanceOf[owner]));
}
function previewWithdraw(uint256 assets) external view returns (uint256 shares) {
uint256 fee = assets / uint256(feeDenominator);
shares = convertToShares(assets + fee);
}
function _withdraw(bool useQueue, address receiver, address owner, uint256 assets, uint256 shares) internal {
if (assets < MIN_WITHDRAWAL) revert MevEthErrors.WithdrawTooSmall();
uint256 blockNumber = block.number;
if (((blockNumber - lastDeposit[msg.sender]) == 0 || (blockNumber - lastDeposit[owner] == 0)) && (blockNumber - lastRewards) == 0) {
revert MevEthErrors.SandwichProtection();
}
_updateAllowance(owner, shares);
fraction.elastic -= uint128(assets);
fraction.base -= uint128(shares);
_burn(owner, shares);
uint256 availableBalance = address(this).balance - withdrawalAmountQueued;
uint256 amountToSend = assets;
if (availableBalance < assets) {
if (!useQueue) revert MevEthErrors.NotEnoughEth();
uint256 amountOwed = assets - availableBalance;
++queueLength;
withdrawalQueue[queueLength] = WithdrawalTicket({
claimed: false,
receiver: receiver,
amount: uint128(amountOwed),
accumulatedAmount: withdrawalQueue[queueLength - 1].accumulatedAmount + uint128(amountOwed)
});
emit WithdrawalQueueOpened(receiver, queueLength, amountOwed);
amountToSend = availableBalance;
}
if (amountToSend != 0) {
emit Withdraw(msg.sender, owner, receiver, assets, shares);
WETH9.deposit{ value: amountToSend }();
WETH9.safeTransfer(receiver, amountToSend);
}
}
function _updateAllowance(address owner, uint256 shares) internal {
uint256 allowed = allowance[owner][msg.sender];
if (owner != msg.sender) {
if (allowed < shares) revert MevEthErrors.TransferExceedsAllowance();
if (allowed != type(uint256).max) {
unchecked {
allowance[owner][msg.sender] -= shares;
}
}
}
}
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares) {
uint256 fee = assets / uint256(feeDenominator);
shares = convertToShares(assets + fee);
_withdraw(false, receiver, owner, assets, shares);
}
function withdrawQueue(uint256 assets, address receiver, address owner) external returns (uint256 shares) {
uint256 fee = assets / uint256(feeDenominator);
if ((fraction.elastic - assets) == 0) fee = 0;
shares = convertToShares(assets + fee);
_withdraw(true, receiver, owner, assets, shares);
}
function maxRedeem(address owner) external view returns (uint256 maxShares) {
maxShares = min(convertToShares(address(this).balance), balanceOf[owner]);
}
function previewRedeem(uint256 shares) external view returns (uint256 assets) {
uint256 fee = shares / uint256(feeDenominator);
assets = convertToAssets(shares - fee);
}
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets) {
uint256 fee = shares / uint256(feeDenominator);
if ((totalSupply - shares) == 0) fee = 0;
assets = convertToAssets(shares - fee);
_withdraw(false, receiver, owner, assets, shares);
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function redeemCream(uint256 creamAmount) external {
_stakingUnpaused();
if (creamAmount == 0) revert MevEthErrors.ZeroValue();
uint256 assets = creamAmount * uint256(CREAM_TO_MEV_ETH_PERCENT) / 1000;
if (assets < MIN_DEPOSIT) revert MevEthErrors.DepositTooSmall();
uint256 shares = convertToShares(assets);
fraction.elastic += uint128(assets);
fraction.base += uint128(shares);
IERC20Burnable(creamToken).burnFrom(msg.sender, creamAmount);
_mint(msg.sender, shares);
emit CreamRedeemed(msg.sender, creamAmount, shares);
}
event CreamRedeemed(address indexed redeemer, uint256 creamAmount, uint256 mevEthAmount);
receive() external payable {
if (msg.sender != address(WETH9)) revert MevEthErrors.InvalidSender();
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
uint256 lastDepositFrom = lastDeposit[msg.sender];
if (lastDepositFrom > lastDeposit[to]) {
lastDeposit[to] = lastDepositFrom;
}
return super.transfer(to, amount);
}
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
uint256 lastDepositFrom = lastDeposit[from];
if (lastDepositFrom > lastDeposit[to]) {
lastDeposit[to] = lastDepositFrom;
}
return super.transferFrom(from, to, amount);
}
}
文件 10 的 11:SafeTransferLib.sol
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
library SafeTransferLib {
function safeTransferETH(address to, uint256 amount) internal {
bool success;
assembly {
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
assembly {
let memPointer := mload(0x40)
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(4, from)
mstore(36, to)
mstore(68, amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, 0, 100, 0, 32)
)
mstore(0x60, 0)
mstore(0x40, memPointer)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
let memPointer := mload(0x40)
mstore(0, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(4, to)
mstore(36, amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, 0, 68, 0, 32)
)
mstore(0x60, 0)
mstore(0x40, memPointer)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
let memPointer := mload(0x40)
mstore(0, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(4, to)
mstore(36, amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, 0, 68, 0, 32)
)
mstore(0x60, 0)
mstore(0x40, memPointer)
}
require(success, "APPROVE_FAILED");
}
}
文件 11 的 11:WETH.sol
pragma solidity >=0.8.0;
import {ERC20} from "./ERC20.sol";
import {SafeTransferLib} from "../utils/SafeTransferLib.sol";
contract WETH is ERC20("Wrapped Ether", "WETH", 18) {
using SafeTransferLib for address;
event Deposit(address indexed from, uint256 amount);
event Withdrawal(address indexed to, uint256 amount);
function deposit() public payable virtual {
_mint(msg.sender, msg.value);
emit Deposit(msg.sender, msg.value);
}
function withdraw(uint256 amount) public virtual {
_burn(msg.sender, amount);
emit Withdrawal(msg.sender, amount);
msg.sender.safeTransferETH(amount);
}
receive() external payable virtual {
deposit();
}
}
{
"compilationTarget": {
"src/MevEth.sol": "MevEth"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"appendCBOR": false,
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 512
},
"remappings": [
":@openzeppelin/=lib/openzeppelin-contracts/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":properties/=lib/properties/contracts/",
":safe-contracts/=lib/safe-tools/lib/safe-contracts/contracts/",
":safe-tools/=lib/safe-tools/src/",
":solady/utils/=lib/solady/src/utils/",
":solmate/=lib/solmate/src/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"authority","type":"address"},{"internalType":"address","name":"weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"AlreadyDeposited","type":"error"},{"inputs":[],"name":"AlreadyFinalised","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AlreadySet","type":"error"},{"inputs":[],"name":"DepositTooSmall","type":"error"},{"inputs":[],"name":"IncorrectWithdrawalCredentials","type":"error"},{"inputs":[],"name":"IndexExceedsQueueLength","type":"error"},{"inputs":[],"name":"InvalidPendingMevEthShareVault","type":"error"},{"inputs":[],"name":"InvalidPendingStakingModule","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"NoAdmin","type":"error"},{"inputs":[],"name":"NotEnoughEth","type":"error"},{"inputs":[],"name":"NotFinalised","type":"error"},{"inputs":[],"name":"PrematureMevEthShareVaultUpdateFinalization","type":"error"},{"inputs":[],"name":"PrematureStakingModuleUpdateFinalization","type":"error"},{"inputs":[],"name":"SandwichProtection","type":"error"},{"inputs":[],"name":"StakingPaused","type":"error"},{"inputs":[],"name":"TransferExceedsAllowance","type":"error"},{"inputs":[],"name":"UnAuthorizedCaller","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"WithdrawTooSmall","type":"error"},{"inputs":[],"name":"WrongDepositAmount","type":"error"},{"inputs":[],"name":"WrongWithdrawAmount","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"}],"name":"AdminDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"creamAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mevEthAmount","type":"uint256"}],"name":"CreamRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"mevEthShareVault","type":"address"},{"indexed":true,"internalType":"address","name":"stakingModule","type":"address"}],"name":"MevEthInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldVault","type":"address"},{"indexed":true,"internalType":"address","name":"newVault","type":"address"}],"name":"MevEthShareVaultUpdateCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldVault","type":"address"},{"indexed":true,"internalType":"address","name":"pendingVault","type":"address"},{"indexed":true,"internalType":"uint64","name":"eligibleForFinalization","type":"uint64"}],"name":"MevEthShareVaultUpdateCommitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldVault","type":"address"},{"indexed":true,"internalType":"address","name":"newVault","type":"address"}],"name":"MevEthShareVaultUpdateFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOperator","type":"address"}],"name":"OperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOperator","type":"address"}],"name":"OperatorDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Rewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldModule","type":"address"},{"indexed":true,"internalType":"address","name":"pendingModule","type":"address"}],"name":"StakingModuleUpdateCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldModule","type":"address"},{"indexed":true,"internalType":"address","name":"pendingModule","type":"address"},{"indexed":true,"internalType":"uint64","name":"eligibleForFinalization","type":"uint64"}],"name":"StakingModuleUpdateCommitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldModule","type":"address"},{"indexed":true,"internalType":"address","name":"newModule","type":"address"}],"name":"StakingModuleUpdateFinalized","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakingModule","type":"address"},{"components":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"bytes32","name":"withdrawal_credentials","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes32","name":"deposit_data_root","type":"bytes32"}],"indexed":false,"internalType":"struct IStakingModule.ValidatorData","name":"newValidator","type":"tuple"}],"name":"ValidatorCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ValidatorWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"uint256","name":"withdrawalId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"WithdrawalQueueClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"uint256","name":"withdrawalId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"WithdrawalQueueOpened","type":"event"},{"inputs":[],"name":"CREAM_TO_MEV_ETH_PERCENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEPOSIT","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_WITHDRAWAL","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"contract WETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"addAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOperator","type":"address"}],"name":"addOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"admins","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"assetTokenAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calculateNeededEtherBuffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelUpdateMevEthShareVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelUpdateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"withdrawalId","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMevEthShareVault","type":"address"}],"name":"commitUpdateMevEthShareVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStakingModule","name":"newModule","type":"address"}],"name":"commitUpdateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creamToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"bytes32","name":"withdrawal_credentials","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes32","name":"deposit_data_root","type":"bytes32"}],"internalType":"struct IStakingModule.ValidatorData","name":"newData","type":"tuple"},{"internalType":"bytes32","name":"latestDepositRoot","type":"bytes32"}],"name":"createValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"oldAdmin","type":"address"}],"name":"deleteAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oldOperator","type":"address"}],"name":"deleteOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"finalizeUpdateMevEthShareVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finalizeUpdateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fraction","outputs":[{"internalType":"uint128","name":"elastic","type":"uint128"},{"internalType":"uint128","name":"base","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"grantRewards","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"grantValidatorWithdraw","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"initialShareVault","type":"address"},{"internalType":"address","name":"initialStakingModule","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mevEthShareVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"operators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingMevEthShareVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingMevEthShareVaultCommittedTimestamp","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingStakingModule","outputs":[{"internalType":"contract IStakingModule","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingStakingModuleCommittedTimestamp","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRequestsFinalisedUntil","type":"uint256"}],"name":"processWithdrawalQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"queueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"creamAmount","type":"uint256"}],"name":"redeemCream","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestsFinalisedUntil","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"newMinimum","type":"uint128"}],"name":"setMinWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingModule","outputs":[{"internalType":"contract IStakingModule","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"totalManagedAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpauseStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdrawQueue","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalAmountQueued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"ticketNumber","type":"uint256"}],"name":"withdrawalQueue","outputs":[{"internalType":"bool","name":"claimed","type":"bool"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"accumulatedAmount","type":"uint128"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]