Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: TW deploy script #939

Open
wants to merge 43 commits into
base: feat/withdrawal-credentials
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
483b442
feat: initial deploy to local devnet
eddort Dec 11, 2024
e5aa190
feat: speed up scratch deployment for local-devnet
eddort Dec 11, 2024
ee55926
refactor: add deployed-local-devnet.json to gitignore
eddort Dec 11, 2024
ce8c268
chore: add default pk for local devnet
tamtamchik Dec 12, 2024
2983d01
feat: decrease voting time for devnet
eddort Dec 17, 2024
e879318
fix: consensusVersion in VEBO defaults
eddort Dec 19, 2024
ce1e448
feat: update default params for devnet
eddort Dec 19, 2024
e622b3b
feat: custom SLOTS_PER_EPOCH support
eddort Dec 22, 2024
6c8bab8
fix: change the module type on curated-onchain-v1 for SimpleDVT in th…
Amuhar Dec 24, 2024
7232f9f
Merge branch 'feat/withdrawal-credentials' into feat/val-1556-move-ve…
mkurayan Jan 13, 2025
9ca0832
feat: exit request data hash storage, triggerExitHashVerify method, h…
Amuhar Jan 13, 2025
b0b402c
Use of withdrawal vault contract in veb
Amuhar Jan 16, 2025
96962ec
fix: tests after changing ReportData
Amuhar Jan 19, 2025
2c5f189
Merge commit '2d11786ebc1f06165c501fa8e9fecef053e12ab9' into feat/loc…
mkurayan Jan 30, 2025
2488ef7
feat: add block explorer verify params to hh config
eddort Feb 9, 2025
be1e2d8
Merge branch 'feat/local-devnet' of github.com:lidofinance/core into …
eddort Feb 9, 2025
b5d240c
Merge branch 'feat/withdrawal-credentials' into feat/val-1456-tw-vebo…
Amuhar Feb 10, 2025
2e1a0d1
feat: add tw deploy script
F4ever Feb 10, 2025
4d8e5f3
feat: update tw script
F4ever Feb 11, 2025
83777fc
Merge branch 'feat/local-devnet' of github.com:lidofinance/core into …
eddort Feb 12, 2025
5cff88e
fix: read GENESIS_TIME from env
eddort Feb 12, 2025
5c3647d
fix: deploy tw script
eddort Feb 12, 2025
7feab5d
feat: tw deploy
eddort Feb 13, 2025
46b3c40
fix: vebo tw unit tests
Amuhar Feb 17, 2025
e8eb1b5
Merge branch 'develop' into feat/val-1456-tw-vebo-part
Amuhar Feb 17, 2025
30ff891
Merge branch 'feat/withdrawal-credentials' into feat/val-1456-tw-vebo…
Amuhar Feb 17, 2025
8ffcf2b
fix: hardhat config types
eddort Feb 17, 2025
72a4628
Revert "feat: speed up scratch deployment for local-devnet"
eddort Feb 17, 2025
965cd4c
Merge branch 'develop' of github.com:lidofinance/core into feat/local…
eddort Feb 17, 2025
6e7c60e
fix: integration tests
eddort Feb 17, 2025
d1fc7ec
fix: IDepositContract format
eddort Feb 17, 2025
f22a7a9
refactor: reset defaults
eddort Feb 17, 2025
4d78142
feat: merge tw vebo
F4ever Feb 18, 2025
f4d128f
refactor: env vars
eddort Feb 18, 2025
9492d8f
refactor: env example
eddort Feb 18, 2025
62d8fbc
Merge branch 'feat/local-devnet' of github.com:lidofinance/core into …
eddort Feb 18, 2025
5e7e304
fix: initialize WithdrawalVault
eddort Feb 18, 2025
b403164
fix: hh etherscan config
eddort Feb 18, 2025
6089070
fix: wv initialize
eddort Feb 18, 2025
25b4eda
Merge pull request #896 from lidofinance/feat/local-devnet
tamtamchik Feb 18, 2025
3deea15
Merge branch 'develop' of github.com:lidofinance/core into feat/tw-de…
eddort Feb 18, 2025
2285502
fix: hash ReportData.data separatly
Amuhar Feb 20, 2025
9b2ef2e
feat: merge tw vebo
F4ever Feb 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ lib/abi/*.json
accounts.json
deployed-local.json
deployed-hardhat.json
deployed-local-devnet.json

# MacOS
.DS_Store
115 changes: 115 additions & 0 deletions contracts/0.8.9/oracle/ValidatorsExitBus.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// SPDX-FileCopyrightText: 2023 Lido <[email protected]>
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.9;

import { AccessControlEnumerable } from "../utils/access/AccessControlEnumerable.sol";
import { UnstructuredStorage } from "../lib/UnstructuredStorage.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 KeyWasNotUnpacked(uint256 keyIndex, uint256 lastUnpackedKeyIndex);
error ZeroAddress();
error FeeNotEnough(uint256 minFeePerRequest, uint256 requestCount, uint256 msgValue);
error TriggerableWithdrawalRefundFailed();

// TODO: make type optimization
struct DeliveryHistory {
uint256 blockNumber;
/// @dev Key index in exit request array
uint256 lastDeliveredKeyIndex;

// TODO: timestamp
}
// TODO: make type optimization
struct RequestStatus {
// Total items count in report (by default type(uint32).max, update on first report unpack)
uint256 totalItemsCount;
// Total processed items in report (by default 0)
uint256 deliveredItemsCount;
// Vebo contract version at the time of hash submittion
uint256 contractVersion;
DeliveryHistory[] deliverHistory;
}

/// Length in bytes of packed request
uint256 internal constant PACKED_REQUEST_LENGTH = 64;

uint256 internal constant PUBLIC_KEY_LENGTH = 48;

/// Hash constant for mapping exit requests storage
bytes32 internal constant EXIT_REQUESTS_HASHES_POSITION =
keccak256("lido.ValidatorsExitBus.reportHashes");

bytes32 private constant LOCATOR_CONTRACT_POSITION = keccak256("lido.ValidatorsExitBus.locatorContract");

function _initialize_v2(address locatorAddr) internal {
_setLocatorAddress(locatorAddr);
}

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

LOCATOR_CONTRACT_POSITION.setStorageAddress(addr);
}

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

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

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

uint256 refund = msg.value - requestsFee;

uint256 lastDeliveredKeyIndex = requestStatus.deliveredItemsCount - 1;

bytes memory pubkeys = new bytes(keyIndexes.length * PUBLIC_KEY_LENGTH);

for (uint256 i = 0; i < keyIndexes.length; i++) {
if (keyIndexes[i] > lastDeliveredKeyIndex) {
revert KeyWasNotUnpacked(keyIndexes[i], lastDeliveredKeyIndex);
}
uint256 requestOffset = keyIndexes[i] * PACKED_REQUEST_LENGTH + 16;

for (uint256 j = 0; j < PUBLIC_KEY_LENGTH; j++) {
pubkeys[i * PUBLIC_KEY_LENGTH + j] = data[requestOffset + j];

}
}

IWithdrawalVault(withdrawalVaultAddr).addFullWithdrawalRequests{value: requestsFee}(pubkeys);

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

}

/// Storage helpers
function _storageExitRequestsHashes() internal pure returns (
mapping(bytes32 => RequestStatus) storage r
) {
bytes32 position = EXIT_REQUESTS_HASHES_POSITION;
assembly {
r.slot := position
}
}
}
39 changes: 34 additions & 5 deletions contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ import { PausableUntil } from "../utils/PausableUntil.sol";
import { UnstructuredStorage } from "../lib/UnstructuredStorage.sol";

import { BaseOracle } from "./BaseOracle.sol";
import { ValidatorsExitBus } from "./ValidatorsExitBus.sol";


interface IOracleReportSanityChecker {
function checkExitBusOracleReport(uint256 _exitRequestsCount) external view;
}


contract ValidatorsExitBusOracle is BaseOracle, PausableUntil {
contract ValidatorsExitBusOracle is BaseOracle, PausableUntil, ValidatorsExitBus {
using UnstructuredStorage for bytes32;
using SafeCast for uint256;

Expand Down Expand Up @@ -109,6 +110,11 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil {
_initialize(consensusContract, consensusVersion, lastProcessingRefSlot);
}

function finalizeUpgrade_v2() external {
_updateContractVersion(2);
_initialize_v2(address(LOCATOR));
}

/// @notice Resume accepting validator exit requests
///
/// @dev Reverts with `PausedExpected()` if contract is already resumed
Expand Down Expand Up @@ -192,9 +198,6 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil {
///
uint256 public constant DATA_FORMAT_LIST = 1;

/// Length in bytes of packed request
uint256 internal constant PACKED_REQUEST_LENGTH = 64;

/// @notice Submits report data for processing.
///
/// @param data The data. See the `ReportData` structure's docs for details.
Expand All @@ -216,10 +219,21 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil {
{
_checkMsgSenderIsAllowedToSubmitData();
_checkContractVersion(contractVersion);
bytes32 dataHash = keccak256(abi.encode(data.data));
// it's a waste of gas to copy the whole calldata into mem but seems there's no way around
_checkConsensusData(data.refSlot, data.consensusVersion, keccak256(abi.encode(data)));
bytes32 reportDataHash = keccak256(
abi.encode(
data.consensusVersion,
data.refSlot,
data.requestsCount,
data.dataFormat,
dataHash
)
);
_checkConsensusData(data.refSlot, data.consensusVersion, reportDataHash);
_startProcessing();
_handleConsensusReportData(data);
_storeOracleExitRequestHash(dataHash, data, contractVersion);
}

/// @notice Returns the total number of validator exit requests ever processed
Expand Down Expand Up @@ -336,6 +350,7 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil {
revert InvalidRequestsDataLength();
}

// TODO: next iteration will check ref slot deliveredReportAmount
IOracleReportSanityChecker(LOCATOR.oracleReportSanityChecker())
.checkExitBusOracleReport(data.requestsCount);

Expand Down Expand Up @@ -439,6 +454,20 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil {
return (moduleId << 40) | nodeOpId;
}

function _storeOracleExitRequestHash(bytes32 exitRequestHash, ReportData calldata report, uint256 contractVersion) internal {
if (report.requestsCount == 0) {
return;
}

mapping(bytes32 => RequestStatus) storage hashes = _storageExitRequestsHashes();

RequestStatus storage request = hashes[exitRequestHash];
request.totalItemsCount = report.requestsCount;
request.deliveredItemsCount = report.requestsCount;
request.contractVersion = contractVersion;
request.deliverHistory.push(DeliveryHistory({blockNumber: block.number, lastDeliveredKeyIndex: report.requestsCount - 1}));
}

///
/// Storage helpers
///
Expand Down
2 changes: 1 addition & 1 deletion deployed-holesky.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@
"app:simple-dvt": {
"stakingRouterModuleParams": {
"moduleName": "SimpleDVT",
"moduleType": "simple-dvt-onchain-v1",
"moduleType": "curated-onchain-v1",
"targetShare": 50,
"moduleFee": 800,
"treasuryFee": 200,
Expand Down
6 changes: 6 additions & 0 deletions globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,11 @@ declare namespace NodeJS {

/* for contract sourcecode verification with `hardhat-verify` */
ETHERSCAN_API_KEY?: string;

/* for local devnet */
LOCAL_DEVNET_PK?: string;
LOCAL_DEVNET_CHAIN_ID?: string;
LOCAL_DEVNET_EXPLORER_API_URL?: string;
LOCAL_DEVNET_EXPLORER_URL?: string;
}
}
22 changes: 21 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@ import { getHardhatForkingConfig, loadAccounts } from "./hardhat.helpers";

const RPC_URL: string = process.env.RPC_URL || "";

export const ZERO_PK = "0x0000000000000000000000000000000000000000000000000000000000000000";

const config: HardhatUserConfig = {
defaultNetwork: "hardhat",
networks: {
"local": {
url: process.env.LOCAL_RPC_URL || RPC_URL,
},
"local-devnet": {
url: process.env.LOCAL_RPC_URL || RPC_URL,
accounts: [process.env.LOCAL_DEVNET_PK || ZERO_PK],
},
"mainnet-fork": {
url: process.env.MAINNET_RPC_URL || RPC_URL,
timeout: 20 * 60 * 1000, // 20 minutes
Expand Down Expand Up @@ -57,7 +63,21 @@ const config: HardhatUserConfig = {
},
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY || "",
customChains: [
{
network: "local-devnet",
chainId: parseInt(process.env.LOCAL_DEVNET_CHAIN_ID ?? "32382", 10),
urls: {
apiURL: process.env.LOCAL_DEVNET_EXPLORER_API_URL ?? "",
browserURL: process.env.LOCAL_DEVNET_EXPLORER_URL ?? "",
},
},
],
apiKey: process.env.LOCAL_DEVNET_EXPLORER_API_URL
? {
"local-devnet": "local-devnet",
}
: process.env.ETHERSCAN_API_KEY || "",
},
solidity: {
compilers: [
Expand Down
2 changes: 2 additions & 0 deletions lib/state-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export enum Sk {
chainSpec = "chainSpec",
scratchDeployGasUsed = "scratchDeployGasUsed",
minFirstAllocationStrategy = "minFirstAllocationStrategy",
triggerableWithdrawals = "triggerableWithdrawals",
}

export function getAddress(contractKey: Sk, state: DeploymentState): string {
Expand All @@ -108,6 +109,7 @@ export function getAddress(contractKey: Sk, state: DeploymentState): string {
case Sk.withdrawalQueueERC721:
case Sk.withdrawalVault:
return state[contractKey].proxy.address;
case Sk.triggerableWithdrawals:
case Sk.apmRegistryFactory:
case Sk.burner:
case Sk.callsScript:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"typecheck": "tsc --noEmit",
"prepare": "husky",
"abis:extract": "hardhat abis:extract",
"verify:deployed": "hardhat verify:deployed --no-compile"
"verify:deployed": "hardhat verify:deployed"
},
"lint-staged": {
"./**/*.ts": [
Expand Down
4 changes: 2 additions & 2 deletions scripts/scratch/deployed-testnet-defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
},
"validatorsExitBusOracle": {
"deployParameters": {
"consensusVersion": 1
"consensusVersion": 2
}
},
"depositSecurityModule": {
Expand Down Expand Up @@ -137,7 +137,7 @@
},
"simpleDvt": {
"deployParameters": {
"stakingModuleTypeId": "simple-dvt-onchain-v1",
"stakingModuleTypeId": "curated-onchain-v1",
"stuckPenaltyDelay": 432000
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export async function main() {
const deployer = ethers.getAddress(getEnvVariable("DEPLOYER"));
const gateSealFactoryAddress = getEnvVariable("GATE_SEAL_FACTORY", "");
const genesisTime = parseInt(getEnvVariable("GENESIS_TIME"));
const slotsPerEpoch = parseInt(getEnvVariable("SLOTS_PER_EPOCH", "32"), 10);
const depositContractAddress = getEnvVariable("DEPOSIT_CONTRACT", "");
const withdrawalQueueBaseUri = getEnvVariable("WITHDRAWAL_QUEUE_BASE_URI", "");
const dsmPredefinedAddress = getEnvVariable("DSM_PREDEFINED_ADDRESS", "");
Expand All @@ -29,7 +30,7 @@ export async function main() {
state.deployer = deployer;

// Update state with new values from environment variables
state.chainSpec = { ...state.chainSpec, genesisTime };
state.chainSpec = { ...state.chainSpec, genesisTime, slotsPerEpoch };

if (depositContractAddress) {
state.chainSpec.depositContract = ethers.getAddress(depositContractAddress);
Expand Down
9 changes: 9 additions & 0 deletions scripts/triggerable-withdrawals/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Deployer
DEPLOYER=
DEPLOYER_PRIVATE_KEY=
# Chain config
RPC_URL=
NETWORK=
# Deploy transactions gas
GAS_PRIORITY_FEE=
GAS_MAX_FEE=
Loading
Loading