Skip to content

Commit

Permalink
Merge branch 'master' into feat/vaults
Browse files Browse the repository at this point in the history
# Conflicts:
#	.github/workflows/tests-integration-mainnet.yml
#	test/integration/accounting.integration.ts
#	test/integration/protocol-happy-path.integration.ts
  • Loading branch information
tamtamchik committed Feb 11, 2025
2 parents 31bf140 + 9a5a20a commit b3bc8d7
Show file tree
Hide file tree
Showing 16 changed files with 195 additions and 172 deletions.
8 changes: 2 additions & 6 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# CODEOWNERS: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners

# Any PR to `master` branch with changes to production contracts notifies the protocol team
/contracts/ @lidofinance/lido-eth-protocol

# Any PR to `master` branch with changes to GitHub workflows notifies the workflow review team
/.github/workflows/ @lidofinance/review-gh-workflows
* @lidofinance/lido-eth-protocol
.github @lidofinance/review-gh-workflows
65 changes: 36 additions & 29 deletions .github/workflows/tests-integration-mainnet.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
name: Integration Tests
#on: [push]
#
#jobs:
# test_hardhat_integration_fork:
# name: Hardhat / Mainnet
# runs-on: ubuntu-latest
# timeout-minutes: 120
#
# services:
# hardhat-node:
# image: ghcr.io/lidofinance/hardhat-node:2.22.18
# ports:
# - 8545:8545
# env:
# ETH_RPC_URL: "${{ secrets.ETH_RPC_URL }}"
#
# steps:
# - uses: actions/checkout@v4
#
# - name: Common setup
# uses: ./.github/workflows/setup
#
# - name: Set env
# run: cp .env.example .env
#
# - name: Run integration tests
# run: yarn test:integration:fork:mainnet
# env:
# LOG_LEVEL: debug

on: workflow_dispatch

# TODO: uncomment
#on:
# push:
# schedule:
# - cron: "0 10 */2 * *"

jobs:
test_hardhat_integration_fork:
name: Hardhat / Mainnet
runs-on: ubuntu-latest
timeout-minutes: 120

services:
hardhat-node:
image: ghcr.io/lidofinance/hardhat-node:2.22.18
ports:
- 8545:8545
env:
ETH_RPC_URL: "${{ secrets.ETH_RPC_URL }}"

steps:
- uses: actions/checkout@v4

- name: Common setup
uses: ./.github/workflows/setup

- name: Set env
run: cp .env.example .env

- name: Run integration tests
run: yarn test:integration:fork:mainnet
env:
LOG_LEVEL: debug
2 changes: 1 addition & 1 deletion lib/protocol/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { unpauseStaking, ensureStakeLimit } from "./staking";
export { unpauseStaking, ensureStakeLimit, depositAndReportValidators } from "./staking";

export { unpauseWithdrawalQueue, finalizeWithdrawalQueue } from "./withdrawal";

Expand Down
20 changes: 15 additions & 5 deletions lib/protocol/helpers/nor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { certainAddress, log, trace } from "lib";

import { ProtocolContext, StakingModuleName } from "../types";

import { depositAndReportValidators } from "./staking";

const NOR_MODULE_ID = 1n;
const MIN_OPS_COUNT = 3n;
const MIN_OP_KEYS_COUNT = 10n;

Expand All @@ -16,10 +19,9 @@ export const norEnsureOperators = async (
minOperatorsCount = MIN_OPS_COUNT,
minOperatorKeysCount = MIN_OP_KEYS_COUNT,
) => {
await norEnsureOperatorsHaveMinKeys(ctx, minOperatorsCount, minOperatorKeysCount);

const { nor } = ctx.contracts;

const newOperatorsCount = await norEnsureOperatorsHaveMinKeys(ctx, minOperatorsCount, minOperatorKeysCount);
for (let operatorId = 0n; operatorId < minOperatorsCount; operatorId++) {
const nodeOperatorBefore = await nor.getNodeOperator(operatorId, false);

Expand All @@ -39,6 +41,10 @@ export const norEnsureOperators = async (
"Min operators count": minOperatorsCount,
"Min keys count": minOperatorKeysCount,
});

if (newOperatorsCount > 0) {
await depositAndReportValidators(ctx, NOR_MODULE_ID, newOperatorsCount);
}
};

/**
Expand All @@ -48,8 +54,8 @@ const norEnsureOperatorsHaveMinKeys = async (
ctx: ProtocolContext,
minOperatorsCount = MIN_OPS_COUNT,
minKeysCount = MIN_OP_KEYS_COUNT,
) => {
await norEnsureMinOperators(ctx, minOperatorsCount);
): Promise<bigint> => {
const newOperatorsCount = await norEnsureMinOperators(ctx, minOperatorsCount);

const { nor } = ctx.contracts;

Expand All @@ -67,12 +73,14 @@ const norEnsureOperatorsHaveMinKeys = async (

expect(keysCountAfter).to.be.gte(minKeysCount);
}

return newOperatorsCount;
};

/**
* Fills the NOR with some operators in case there are not enough of them.
*/
const norEnsureMinOperators = async (ctx: ProtocolContext, minOperatorsCount = MIN_OPS_COUNT) => {
const norEnsureMinOperators = async (ctx: ProtocolContext, minOperatorsCount = MIN_OPS_COUNT): Promise<bigint> => {
const { nor } = ctx.contracts;

const before = await nor.getNodeOperatorsCount();
Expand All @@ -96,6 +104,8 @@ const norEnsureMinOperators = async (ctx: ProtocolContext, minOperatorsCount = M

expect(after).to.equal(before + count);
expect(after).to.be.gte(minOperatorsCount);

return count;
};

/**
Expand Down
21 changes: 15 additions & 6 deletions lib/protocol/helpers/sdvt.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { expect } from "chai";
import { randomBytes } from "ethers";

import { impersonate, log, streccak, trace } from "lib";
import { ether, impersonate, log, streccak, trace } from "lib";

import { ether } from "../../units";
import { ProtocolContext } from "../types";

import { getOperatorManagerAddress, getOperatorName, getOperatorRewardAddress } from "./nor";
import { depositAndReportValidators } from "./staking";

const SDVT_MODULE_ID = 2n;
const MIN_OPS_COUNT = 3n;
const MIN_OP_KEYS_COUNT = 10n;

Expand All @@ -21,7 +22,7 @@ export const sdvtEnsureOperators = async (
minOperatorsCount = MIN_OPS_COUNT,
minOperatorKeysCount = MIN_OP_KEYS_COUNT,
) => {
await sdvtEnsureOperatorsHaveMinKeys(ctx, minOperatorsCount, minOperatorKeysCount);
const newOperatorsCount = await sdvtEnsureOperatorsHaveMinKeys(ctx, minOperatorsCount, minOperatorKeysCount);

const { sdvt } = ctx.contracts;

Expand All @@ -39,6 +40,10 @@ export const sdvtEnsureOperators = async (

expect(nodeOperatorAfter.totalVettedValidators).to.equal(nodeOperatorBefore.totalAddedValidators);
}

if (newOperatorsCount > 0) {
await depositAndReportValidators(ctx, SDVT_MODULE_ID, newOperatorsCount);
}
};

/**
Expand All @@ -48,8 +53,8 @@ const sdvtEnsureOperatorsHaveMinKeys = async (
ctx: ProtocolContext,
minOperatorsCount = MIN_OPS_COUNT,
minKeysCount = MIN_OP_KEYS_COUNT,
) => {
await sdvtEnsureMinOperators(ctx, minOperatorsCount);
): Promise<bigint> => {
const newOperatorsCount = await sdvtEnsureMinOperators(ctx, minOperatorsCount);

const { sdvt } = ctx.contracts;

Expand All @@ -74,12 +79,14 @@ const sdvtEnsureOperatorsHaveMinKeys = async (
"Min operators count": minOperatorsCount,
"Min keys count": minKeysCount,
});

return newOperatorsCount;
};

/**
* Fills the Simple DVT with some operators in case there are not enough of them.
*/
const sdvtEnsureMinOperators = async (ctx: ProtocolContext, minOperatorsCount = MIN_OPS_COUNT) => {
const sdvtEnsureMinOperators = async (ctx: ProtocolContext, minOperatorsCount = MIN_OPS_COUNT): Promise<bigint> => {
const { sdvt } = ctx.contracts;

const before = await sdvt.getNodeOperatorsCount();
Expand Down Expand Up @@ -110,6 +117,8 @@ const sdvtEnsureMinOperators = async (ctx: ProtocolContext, minOperatorsCount =
"Min operators count": minOperatorsCount,
"Operators count": after,
});

return count;
};

/**
Expand Down
43 changes: 42 additions & 1 deletion lib/protocol/helpers/staking.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
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";

/**
* Unpauses the staking contract.
*/
Expand Down Expand Up @@ -35,3 +41,38 @@ export const ensureStakeLimit = async (ctx: ProtocolContext) => {
log.success("Staking limit set");
}
};

export const depositAndReportValidators = async (ctx: ProtocolContext, moduleId: bigint, depositsCount: bigint) => {
const { lido, depositSecurityModule } = ctx.contracts;
const ethHolder = await impersonate(certainAddress("provision:eth:whale"), ether("100000"));

await lido.connect(ethHolder).submit(ZeroAddress, { value: ether("10000") });

// Deposit validators
const dsmSigner = await impersonate(depositSecurityModule.address, ether("100000"));
await lido.connect(dsmSigner).deposit(depositsCount, moduleId, ZERO_HASH);

const before = await lido.getBeaconStat();

log.debug("Validators on beacon chain before provisioning", {
"Module ID to deposit": moduleId,
"Deposited": before.depositedValidators,
"Total": before.beaconValidators,
"Balance": before.beaconBalance,
});

// Add new validators to beacon chain
await report(ctx, {
clDiff: ether("32") * depositsCount,
clAppearedValidators: depositsCount,
});

const after = await lido.getBeaconStat();

log.debug("Validators on beacon chain after depositing", {
"Module ID deposited": moduleId,
"Deposited": after.depositedValidators,
"Total": after.beaconValidators,
"Balance": after.beaconBalance,
});
};
19 changes: 4 additions & 15 deletions lib/protocol/helpers/withdrawal.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
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";

Expand Down Expand Up @@ -32,25 +29,17 @@ 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 ethHolder = await impersonate(certainAddress("withdrawalQueue:eth:whale"), ether("100000"));
const stEthHolder = await impersonate(certainAddress("withdrawalQueue:stEth:whale"), ether("100000"));
const stEthHolderAmount = ether("10000");

// Here sendTransaction is used to validate native way of submitting ETH for stETH
const tx = await stEthHolder.sendTransaction({ to: lido.address, value: stEthHolderAmount });
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();
let lastRequestId = await withdrawalQueue.getLastRequestId();

Expand Down
15 changes: 14 additions & 1 deletion lib/protocol/provision.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,41 @@
import { log } from "lib";

import {
ensureHashConsensusInitialEpoch,
ensureOracleCommitteeMembers,
ensureStakeLimit,
finalizeWithdrawalQueue,
norEnsureOperators,
sdvtEnsureOperators,
unpauseStaking,
unpauseWithdrawalQueue,
} 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 finalizeWithdrawalQueue(ctx);

await ensureStakeLimit(ctx);

alreadyProvisioned = true;
};
Loading

0 comments on commit b3bc8d7

Please sign in to comment.