diff --git a/lib/protocol/helpers/index.ts b/lib/protocol/helpers/index.ts index 66c854bbb..00aa6633c 100644 --- a/lib/protocol/helpers/index.ts +++ b/lib/protocol/helpers/index.ts @@ -1,4 +1,4 @@ -export { unpauseStaking, ensureStakeLimit } from "./staking"; +export { unpauseStaking, ensureStakeLimit, depositAndReportValidators } from "./staking"; export { unpauseWithdrawalQueue, finalizeWithdrawalQueue } from "./withdrawal"; diff --git a/lib/protocol/helpers/staking.ts b/lib/protocol/helpers/staking.ts index e482f3b54..82a7039e6 100644 --- a/lib/protocol/helpers/staking.ts +++ b/lib/protocol/helpers/staking.ts @@ -1,7 +1,18 @@ -import { ether, log, trace } from "lib"; +import { ZeroAddress } from "ethers"; + +import { certainAddress, ether, impersonate, log, trace } from "lib"; + +import { ZERO_HASH } from "test/deploy"; import { ProtocolContext } from "../types"; +import { report } from "./accounting"; + +const AMOUNT = ether("100"); +const MAX_DEPOSIT = 150n; +const CURATED_MODULE_ID = 1n; +const SIMPLE_DVT_MODULE_ID = 2n; + /** * Unpauses the staking contract. */ @@ -35,3 +46,37 @@ export const ensureStakeLimit = async (ctx: ProtocolContext) => { log.success("Staking limit set"); } }; + +export const depositAndReportValidators = async (ctx: ProtocolContext) => { + const { lido, depositSecurityModule } = ctx.contracts; + const ethHolder = await impersonate(certainAddress("provision:eht:whale"), ether("100000")); + + await lido.connect(ethHolder).submit(ZeroAddress, { value: ether("10000") }); + + // Deposit node operators + const dsmSigner = await impersonate(depositSecurityModule.address, AMOUNT); + await lido.connect(dsmSigner).deposit(MAX_DEPOSIT, CURATED_MODULE_ID, ZERO_HASH); + await lido.connect(dsmSigner).deposit(MAX_DEPOSIT, SIMPLE_DVT_MODULE_ID, ZERO_HASH); + + const before = await lido.getBeaconStat(); + + log.debug("Validators on beacon chain before provisioning", { + depositedValidators: before.depositedValidators, + beaconValidators: before.beaconValidators, + beaconBalance: before.beaconBalance, + }); + + // Add new validators to beacon chain + await report(ctx, { + clDiff: ether("32") * before.depositedValidators, + clAppearedValidators: before.depositedValidators, + }); + + const after = await lido.getBeaconStat(); + + log.debug("Validators on beacon chain after provisioning", { + depositedValidators: after.depositedValidators, + beaconValidators: after.beaconValidators, + beaconBalance: after.beaconBalance, + }); +}; diff --git a/lib/protocol/helpers/withdrawal.ts b/lib/protocol/helpers/withdrawal.ts index 43315298b..329ed913d 100644 --- a/lib/protocol/helpers/withdrawal.ts +++ b/lib/protocol/helpers/withdrawal.ts @@ -1,9 +1,7 @@ import { expect } from "chai"; import { ZeroAddress } from "ethers"; -import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; - -import { ether, log, trace, updateBalance } from "lib"; +import { certainAddress, ether, impersonate, log, trace } from "lib"; import { ProtocolContext } from "../types"; @@ -32,16 +30,13 @@ export const unpauseWithdrawalQueue = async (ctx: ProtocolContext) => { } }; -export const finalizeWithdrawalQueue = async ( - ctx: ProtocolContext, - stEthHolder: HardhatEthersSigner, - ethHolder: HardhatEthersSigner, -) => { +export const finalizeWithdrawalQueue = async (ctx: ProtocolContext) => { const { lido, withdrawalQueue } = ctx.contracts; - await updateBalance(ethHolder.address, ether("1000000")); - await updateBalance(stEthHolder.address, ether("1000000")); + const seed = Math.random() * 1000000; + const ethHolder = await impersonate(certainAddress(`withdrawalQueue:eth:whale:${seed}`), ether("100000")); + const stEthHolder = await impersonate(certainAddress(`withdrawalQueue:stEth:whale:${seed}`), ether("100000")); const stEthHolderAmount = ether("10000"); // Here sendTransaction is used to validate native way of submitting ETH for stETH @@ -49,6 +44,7 @@ export const finalizeWithdrawalQueue = async ( await trace("stEthHolder.sendTransaction", tx); const stEthHolderBalance = await lido.balanceOf(stEthHolder.address); + expect(stEthHolderBalance).to.approximately(stEthHolderAmount, 10n, "stETH balance increased"); let lastFinalizedRequestId = await withdrawalQueue.getLastFinalizedRequestId(); diff --git a/lib/protocol/provision.ts b/lib/protocol/provision.ts index 29a0d7681..76ce732b7 100644 --- a/lib/protocol/provision.ts +++ b/lib/protocol/provision.ts @@ -1,7 +1,11 @@ +import { log } from "lib"; + import { + depositAndReportValidators, ensureHashConsensusInitialEpoch, ensureOracleCommitteeMembers, ensureStakeLimit, + finalizeWithdrawalQueue, norEnsureOperators, sdvtEnsureOperators, unpauseStaking, @@ -9,20 +13,30 @@ import { } from "./helpers"; import { ProtocolContext } from "./types"; +let alreadyProvisioned = false; + /** * In order to make the protocol fully operational from scratch deploy, the additional steps are required: */ export const provision = async (ctx: ProtocolContext) => { + if (alreadyProvisioned) { + log.success("Already provisioned"); + return; + } + await ensureHashConsensusInitialEpoch(ctx); await ensureOracleCommitteeMembers(ctx, 5n); await unpauseStaking(ctx); - await unpauseWithdrawalQueue(ctx); await norEnsureOperators(ctx, 3n, 5n); await sdvtEnsureOperators(ctx, 3n, 5n); + await depositAndReportValidators(ctx); + await finalizeWithdrawalQueue(ctx); await ensureStakeLimit(ctx); + + alreadyProvisioned = true; }; diff --git a/test/integration/accounting.integration.ts b/test/integration/accounting.integration.ts index e058d327e..916314310 100644 --- a/test/integration/accounting.integration.ts +++ b/test/integration/accounting.integration.ts @@ -7,13 +7,7 @@ import { setBalance } from "@nomicfoundation/hardhat-network-helpers"; import { ether, impersonate, log, ONE_GWEI, trace, updateBalance } from "lib"; import { getProtocolContext, ProtocolContext } from "lib/protocol"; -import { - finalizeWithdrawalQueue, - getReportTimeElapsed, - norEnsureOperators, - report, - sdvtEnsureOperators, -} from "lib/protocol/helpers"; +import { getReportTimeElapsed, report } from "lib/protocol/helpers"; import { Snapshot } from "test/suite"; @@ -22,18 +16,11 @@ const LIMITER_PRECISION_BASE = BigInt(10 ** 9); const SHARE_RATE_PRECISION = BigInt(10 ** 27); const ONE_DAY = 86400n; const MAX_BASIS_POINTS = 10000n; -const AMOUNT = ether("100"); -const MAX_DEPOSIT = 150n; -const CURATED_MODULE_ID = 1n; -const SIMPLE_DVT_MODULE_ID = 2n; - -const ZERO_HASH = new Uint8Array(32).fill(0); describe("Accounting", () => { let ctx: ProtocolContext; let ethHolder: HardhatEthersSigner; - let stEthHolder: HardhatEthersSigner; let snapshot: string; let originalState: string; @@ -41,38 +28,9 @@ describe("Accounting", () => { before(async () => { ctx = await getProtocolContext(); - [stEthHolder, ethHolder] = await ethers.getSigners(); + [ethHolder] = await ethers.getSigners(); snapshot = await Snapshot.take(); - - const { lido, depositSecurityModule } = ctx.contracts; - - await finalizeWithdrawalQueue(ctx, stEthHolder, ethHolder); - - const addedToNor = await norEnsureOperators(ctx, 3n, 5n); - const addedToSdvt = await sdvtEnsureOperators(ctx, 3n, 5n); - - // Deposit node operators - const dsmSigner = await impersonate(depositSecurityModule.address, AMOUNT); - await lido.connect(dsmSigner).deposit(MAX_DEPOSIT, CURATED_MODULE_ID, ZERO_HASH); - await lido.connect(dsmSigner).deposit(MAX_DEPOSIT, SIMPLE_DVT_MODULE_ID, ZERO_HASH); - - const newOperators = addedToNor + addedToSdvt; - - if (newOperators) { - log.debug("New operators added", { - NOR: addedToNor, - SDVT: addedToSdvt, - }); - } else { - log("No new operators added"); - } - - await report(ctx, { - clDiff: ether("32") * newOperators, - clAppearedValidators: newOperators, - excludeVaultsBalances: true, - }); }); beforeEach(async () => (originalState = await Snapshot.take())); diff --git a/test/integration/burn-shares.integration.ts b/test/integration/burn-shares.integration.ts index 53dfa1ea3..0effa7dc5 100644 --- a/test/integration/burn-shares.integration.ts +++ b/test/integration/burn-shares.integration.ts @@ -14,8 +14,6 @@ describe("Burn Shares", () => { let ctx: ProtocolContext; let snapshot: string; - let ethHolder: HardhatEthersSigner; - let stEthHolder: HardhatEthersSigner; let stranger: HardhatEthersSigner; const amount = ether("1"); @@ -26,7 +24,7 @@ describe("Burn Shares", () => { before(async () => { ctx = await getProtocolContext(); - [stEthHolder, ethHolder, stranger] = await ethers.getSigners(); + [stranger] = await ethers.getSigners(); snapshot = await Snapshot.take(); }); @@ -38,7 +36,7 @@ describe("Burn Shares", () => { it("Should finalize withdrawal queue", async () => { const { withdrawalQueue } = ctx.contracts; - await finalizeWithdrawalQueue(ctx, stEthHolder, ethHolder); + await finalizeWithdrawalQueue(ctx); const lastFinalizedRequestId = await withdrawalQueue.getLastFinalizedRequestId(); const lastRequestId = await withdrawalQueue.getLastRequestId(); diff --git a/test/integration/protocol-happy-path.integration.ts b/test/integration/protocol-happy-path.integration.ts index 161c40b6a..590f38527 100644 --- a/test/integration/protocol-happy-path.integration.ts +++ b/test/integration/protocol-happy-path.integration.ts @@ -25,7 +25,6 @@ describe("Protocol Happy Path", () => { let ctx: ProtocolContext; let snapshot: string; - let ethHolder: HardhatEthersSigner; let stEthHolder: HardhatEthersSigner; let stranger: HardhatEthersSigner; @@ -35,7 +34,7 @@ describe("Protocol Happy Path", () => { before(async () => { ctx = await getProtocolContext(); - [stEthHolder, ethHolder, stranger] = await ethers.getSigners(); + [stEthHolder, stranger] = await ethers.getSigners(); snapshot = await Snapshot.take(); }); @@ -55,7 +54,16 @@ describe("Protocol Happy Path", () => { it("Should finalize withdrawal queue", async () => { const { lido, withdrawalQueue } = ctx.contracts; - await finalizeWithdrawalQueue(ctx, stEthHolder, ethHolder); + const stEthHolderAmount = ether("10000"); + + // Deposit some eth + const tx = await lido.submit(ZeroAddress, { value: stEthHolderAmount }); + await trace("lido.submit", tx); + + const stEthHolderBalance = await lido.balanceOf(stEthHolder.address); + expect(stEthHolderBalance).to.approximately(stEthHolderAmount, 10n, "stETH balance increased"); + + await finalizeWithdrawalQueue(ctx); const lastFinalizedRequestId = await withdrawalQueue.getLastFinalizedRequestId(); const lastRequestId = await withdrawalQueue.getLastRequestId(); diff --git a/test/integration/second-opinion.integration.ts b/test/integration/second-opinion.integration.ts index 75a7c0242..1e240fde0 100644 --- a/test/integration/second-opinion.integration.ts +++ b/test/integration/second-opinion.integration.ts @@ -1,13 +1,11 @@ import { expect } from "chai"; import { ethers } from "hardhat"; -import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; - import { SecondOpinionOracle__Mock } from "typechain-types"; import { ether, impersonate, log, ONE_GWEI } from "lib"; import { getProtocolContext, ProtocolContext } from "lib/protocol"; -import { finalizeWithdrawalQueue, norEnsureOperators, report, sdvtEnsureOperators } from "lib/protocol/helpers"; +import { report } from "lib/protocol/helpers"; import { bailOnFailure, Snapshot } from "test/suite"; @@ -26,9 +24,6 @@ function getDiffAmount(totalSupply: bigint): bigint { describe("Second opinion", () => { let ctx: ProtocolContext; - let ethHolder: HardhatEthersSigner; - let stEthHolder: HardhatEthersSigner; - let snapshot: string; let originalState: string; @@ -38,17 +33,10 @@ describe("Second opinion", () => { before(async () => { ctx = await getProtocolContext(); - [stEthHolder, ethHolder] = await ethers.getSigners(); - snapshot = await Snapshot.take(); const { lido, depositSecurityModule, oracleReportSanityChecker } = ctx.contracts; - await finalizeWithdrawalQueue(ctx, stEthHolder, ethHolder); - - await norEnsureOperators(ctx, 3n, 5n); - await sdvtEnsureOperators(ctx, 3n, 5n); - const { chainId } = await ethers.provider.getNetwork(); // Sepolia-specific initialization if (chainId === 11155111n) { @@ -63,6 +51,7 @@ describe("Second opinion", () => { const adapterAddr = await ctx.contracts.stakingRouter.DEPOSIT_CONTRACT(); await bepoliaToken.connect(bepiloaSigner).transfer(adapterAddr, BEPOLIA_TO_TRANSFER); } + const dsmSigner = await impersonate(depositSecurityModule.address, AMOUNT); await lido.connect(dsmSigner).deposit(MAX_DEPOSIT, CURATED_MODULE_ID, ZERO_HASH);