Skip to content

Commit

Permalink
Use of withdrawal vault contract in veb
Browse files Browse the repository at this point in the history
  • Loading branch information
Amuhar committed Jan 16, 2025
1 parent 9ca0832 commit b0b402c
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 29 deletions.
5 changes: 0 additions & 5 deletions contracts/0.8.9/oracle/IWithdrawalVault.sol

This file was deleted.

44 changes: 31 additions & 13 deletions contracts/0.8.9/oracle/ValidatorsExitBus.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@ pragma solidity 0.8.9;

import { AccessControlEnumerable } from "../utils/access/AccessControlEnumerable.sol";
import { UnstructuredStorage } from "../lib/UnstructuredStorage.sol";
import { IWithdrawalVault } from "./IWithdrawalVault.sol";
import { ILidoLocator } from "../../common/interfaces/ILidoLocator.sol";

interface IWithdrawalVault {
function addFullWithdrawalRequests(bytes[] calldata pubkeys) external payable;

function getWithdrawalRequestFee() external view returns (uint256);
}


contract ValidatorsExitBus is AccessControlEnumerable {
using UnstructuredStorage for bytes32;

/// @dev Errors
// error DuplicateExitRequest();
error KeyWasNotUnpacked(uint256 keyIndex, uint256 lastUnpackedKeyIndex);
error ZeroAddress();
error FeeNotEnough(uint256 minFeePerRequest, uint256 requestCount, uint256 msgValue);

/// Part of report data
struct ExitRequestData {
Expand Down Expand Up @@ -71,27 +78,33 @@ contract ValidatorsExitBus is AccessControlEnumerable {
bytes32 internal constant EXIT_REQUESTS_HASHES_POSITION =
keccak256("lido.ValidatorsExitBus.reportHashes");

/// @dev Storage slot: address withdrawalVaultContract
bytes32 internal constant WITHDRAWAL_VAULT_CONTRACT_POSITION =
keccak256("lido.ValidatorsExitBus.withdrawalVaultContract");
bytes32 private constant LOCATOR_CONTRACT_POSITION = keccak256("lido.ValidatorsExitBus.locatorContract");

// ILidoLocator internal immutable LOCATOR;

// TODO: read WV via locator
function _initialize_v2(address withdrawalVaultAddr) internal {
_setWithdrawalVault(withdrawalVaultAddr);
function _initialize_v2(address locatorAddr) internal {
_setLocatorAddress(locatorAddr);
}

function _setWithdrawalVault(address addr) internal {
function _setLocatorAddress(address addr) internal {
if (addr == address(0)) revert ZeroAddress();

WITHDRAWAL_VAULT_CONTRACT_POSITION.setStorageAddress(addr);
LOCATOR_CONTRACT_POSITION.setStorageAddress(addr);
}

function triggerExitHashVerify(ExitRequestData calldata exitRequestData, uint256[] calldata keyIndexes) external payable {
bytes32 dataHash = keccak256(abi.encode(exitRequestData));
RequestStatus storage requestStatus = _storageExitRequestsHashes()[dataHash];

address locatorAddr = LOCATOR_CONTRACT_POSITION.getStorageAddress();
address withdrawalVaultAddr = ILidoLocator(locatorAddr).withdrawalVault();
uint256 fee = IWithdrawalVault(withdrawalVaultAddr).getWithdrawalRequestFee();
uint requestsFee = keyIndexes.length * fee;

if (msg.value < requestsFee) {
revert FeeNotEnough(fee, keyIndexes.length, msg.value);
}

uint256 refund = msg.value - requestsFee;

uint256 lastDeliveredKeyIndex = requestStatus.deliveredItemsCount - 1;

uint256 offset;
Expand All @@ -118,8 +131,13 @@ contract ValidatorsExitBus is AccessControlEnumerable {

}

address withdrawalVaultAddr = WITHDRAWAL_VAULT_CONTRACT_POSITION.getStorageAddress();
IWithdrawalVault(withdrawalVaultAddr).addFullWithdrawalRequests(pubkeys);

if (refund > 0) {
(bool success, ) = msg.sender.call{value: refund}("");
require(success, "Refund failed");
}

}

/// Storage helpers
Expand Down
6 changes: 2 additions & 4 deletions contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,9 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil, ValidatorsExitBus
_initialize(consensusContract, consensusVersion, lastProcessingRefSlot);
}

// TODO: replace with locator
function finalizeUpgrade_v2(address withdrawalVaultAddress) external {
function finalizeUpgrade_v2() external {
_updateContractVersion(2);
_initialize_v2(withdrawalVaultAddress);
_initialize_v2(address(LOCATOR));
}

/// @notice Resume accepting validator exit requests
Expand Down Expand Up @@ -420,7 +419,6 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil, ValidatorsExitBus

function _storeOracleExitRequestHash(bytes32 exitRequestHash, ReportData calldata report, uint256 contractVersion) internal {
mapping(bytes32 => RequestStatus) storage hashes = _storageExitRequestsHashes();
// if (hashes[hash].itemsCount > 0 ) revert DuplicateExitRequest();

RequestStatus storage request = hashes[exitRequestHash];
request.totalItemsCount = report.exitRequestData.requestsCount;
Expand Down
4 changes: 4 additions & 0 deletions test/0.8.9/contracts/WithdrawalValut_MockForVebo.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ contract WithdrawalVault__MockForVebo {
function addFullWithdrawalRequests(bytes[] calldata pubkeys) external {
emit AddFullWithdrawalRequestsCalled(pubkeys);
}

function getWithdrawalRequestFee() external view returns (uint256) {
return 1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ describe("ValidatorsExitBusOracle.sol:triggerExitHashVerify", () => {
let member1: HardhatEthersSigner;
let member2: HardhatEthersSigner;
let member3: HardhatEthersSigner;
let stranger: HardhatEthersSigner;

const LAST_PROCESSING_REF_SLOT = 1;

Expand Down Expand Up @@ -108,7 +107,7 @@ describe("ValidatorsExitBusOracle.sol:triggerExitHashVerify", () => {
};

before(async () => {
[admin, member1, member2, member3, stranger] = await ethers.getSigners();
[admin, member1, member2, member3] = await ethers.getSigners();

await deploy();
});
Expand Down Expand Up @@ -229,10 +228,16 @@ describe("ValidatorsExitBusOracle.sol:triggerExitHashVerify", () => {
});

it("someone submitted exit report data and triggered exit", async () => {
const tx = await oracle.triggerExitHashVerify(reportFields.exitRequestData, [0, 1, 2]);
const tx = await oracle.triggerExitHashVerify(reportFields.exitRequestData, [0, 1, 2], { value: 3 });

await expect(tx)
.to.emit(withdrawalVault, "AddFullWithdrawalRequestsCalled")
.withArgs([PUBKEYS[0], PUBKEYS[1], PUBKEYS[2]]);
});

it("someone submitted exit report data and triggered exit again", async () => {
const tx = await oracle.triggerExitHashVerify(reportFields.exitRequestData, [0, 1], { value: 2 });

await expect(tx).to.emit(withdrawalVault, "AddFullWithdrawalRequestsCalled").withArgs([PUBKEYS[0], PUBKEYS[1]]);
});
});
8 changes: 4 additions & 4 deletions test/deploy/validatorExitBusOracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,12 @@ export async function deployVEBO(

const { ao, lido } = await deployMockAccountingOracle(secondsPerSlot, genesisTime);

const withdrawalVault = await deployWithdrawalVault();

await updateLidoLocatorImplementation(locatorAddr, {
lido: await lido.getAddress(),
accountingOracle: await ao.getAddress(),
withdrawalVault,
});

const oracleReportSanityChecker = await deployOracleReportSanityCheckerForExitBus(locatorAddr, admin);
Expand All @@ -81,8 +84,6 @@ export async function deployVEBO(

await consensus.setTime(genesisTime + initialEpoch * slotsPerEpoch * secondsPerSlot);

const withdrawalVault = await deployWithdrawalVault();

return {
locatorAddr,
oracle,
Expand All @@ -107,15 +108,14 @@ export async function initVEBO({
admin,
oracle,
consensus,
withdrawalVault,
dataSubmitter = undefined,
consensusVersion = CONSENSUS_VERSION,
lastProcessingRefSlot = 0,
resumeAfterDeploy = false,
}: VEBOConfig) {
const initTx = await oracle.initialize(admin, await consensus.getAddress(), consensusVersion, lastProcessingRefSlot);

await oracle.finalizeUpgrade_v2(withdrawalVault);
await oracle.finalizeUpgrade_v2();

await oracle.grantRole(await oracle.MANAGE_CONSENSUS_CONTRACT_ROLE(), admin);
await oracle.grantRole(await oracle.MANAGE_CONSENSUS_VERSION_ROLE(), admin);
Expand Down

0 comments on commit b0b402c

Please sign in to comment.