Skip to content

Commit

Permalink
chore: finish scratch with simple dvt
Browse files Browse the repository at this point in the history
  • Loading branch information
tamtamchik committed Oct 7, 2024
1 parent 19165ca commit a66bf6d
Show file tree
Hide file tree
Showing 13 changed files with 68 additions and 102 deletions.
3 changes: 0 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ MAINNET_RPC_URL=http://localhost:8545
# https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#forking-other-networks
HARDHAT_FORKING_URL=

# Chain ID for the network on Hardhat Network
HARDHAT_CHAIN_ID=

# https://docs.lido.fi/deployed-contracts
MAINNET_LOCATOR_ADDRESS=0xC1d0b3DE6792Bf6b4b37EccdcC24e45978Cfd2Eb
MAINNET_AGENT_ADDRESS=0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c
Expand Down
29 changes: 15 additions & 14 deletions contracts/0.4.24/template/LidoTemplate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ contract LidoTemplate is IsContract {
Lido lido;
LegacyOracle oracle;
NodeOperatorsRegistry operators;
NodeOperatorsRegistry sdvt;
address stakingRouter;
}

Expand Down Expand Up @@ -360,6 +361,7 @@ contract LidoTemplate is IsContract {

function createSimpleDVTApp(
uint16[3] _initialSemanticVersion,
address _proxy,
address _impl,
address _stakingRouter,

Check failure on line 366 in contracts/0.4.24/template/LidoTemplate.sol

View workflow job for this annotation

GitHub Actions / Solhint

Variable "_stakingRouter" is unused
bytes _contentURI
Expand All @@ -378,20 +380,7 @@ contract LidoTemplate is IsContract {

bytes32 appId = _getAppId(SIMPLE_DVT_APP_NAME, deployState.lidoRegistryEnsNode);
dao.setApp(dao.APP_BASES_NAMESPACE(), appId, _impl);

bytes32 stakingRouterRole = deployState.operators.STAKING_ROUTER_ROLE();
address app = address(apmRepos.simpleDVT);

// grant perm for staking router
// https://github.com/lidofinance/lido-dao/blob/291ea9e191f62692f0a17d6af77b66de0abe0a53/scripts/simpledvt/02-clone-nor.js#L220
acl.createPermission(_stakingRouter, app,stakingRouterRole,this);
acl.grantPermission(deployState.agent, app, stakingRouterRole);
_transferPermissionFromTemplate(acl, app, deployState.voting, stakingRouterRole);

// grant perm for agent to manage signing keys and set node operator limit
// https://github.com/lidofinance/lido-dao/blob/291ea9e191f62692f0a17d6af77b66de0abe0a53/scripts/simpledvt/02-clone-nor.js#L228
acl.createPermission(deployState.agent, app, deployState.operators.MANAGE_SIGNING_KEYS(), deployState.voting);
acl.createPermission(deployState.agent, app, deployState.operators.SET_NODE_OPERATOR_LIMIT_ROLE(), deployState.voting);
deployState.sdvt = NodeOperatorsRegistry(_proxy);
}

function issueTokens(
Expand Down Expand Up @@ -651,6 +640,18 @@ contract LidoTemplate is IsContract {
acl.createPermission(_state.stakingRouter, _state.operators, _state.operators.STAKING_ROUTER_ROLE(), voting);
acl.createPermission(_state.agent, _state.operators, _state.operators.MANAGE_NODE_OPERATOR_ROLE(), voting);

// SimpleDVT
perms[0] = _state.operators.MANAGE_SIGNING_KEYS();
perms[1] = _state.operators.SET_NODE_OPERATOR_LIMIT_ROLE();
perms[2] = _state.operators.MANAGE_NODE_OPERATOR_ROLE();
for (i = 0; i < 3; ++i) {
_createPermissionForVoting(acl, _state.sdvt, perms[i], voting);
}
acl.createPermission(_state.stakingRouter, _state.sdvt,_state.sdvt.STAKING_ROUTER_ROLE(), this);
acl.grantPermission(_state.agent, _state.sdvt, _state.sdvt.STAKING_ROUTER_ROLE());

_transferPermissionFromTemplate(acl, _state.sdvt, voting, _state.sdvt.STAKING_ROUTER_ROLE());

// Lido
perms[0] = _state.lido.PAUSE_ROLE();
perms[1] = _state.lido.RESUME_ROLE();
Expand Down
6 changes: 1 addition & 5 deletions globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,13 @@ declare namespace NodeJS {

/* RPC URL for Hardhat Network forking, required for running tests on mainnet fork with tracing */
HARDHAT_FORKING_URL?: string;
/* Chain ID for Hardhat Network forking, required for running tests on different networks */
HARDHAT_CHAIN_ID?: string;

/**
* Flags for changing the behavior of the integration tests
*/

/* if "on" the integration tests will deploy the contracts to the empty Hardhat Network node using scratch deploy */
INTEGRATION_WITH_SCRATCH_DEPLOY?: "on" | "off"; // default: "off"
/* if "on" the integration tests will enable assertions and checks for the simple DVT module */
INTEGRATION_WITH_SIMPLE_DVT_MODULE?: "on" | "off"; // default: "on"
INTEGRATION_ON_SCRATCH?: "on" | "off"; // default: "off"

/**
* Network configuration for the protocol discovery.
Expand Down
4 changes: 0 additions & 4 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ import "./tasks";
const RPC_URL: string = process.env.RPC_URL || "";
const ACCOUNTS_PATH = "./accounts.json";

const HARDHAT_CHAIN_ID_DEFAULT = 31337;
const HARDHAT_FORKING_URL = process.env.HARDHAT_FORKING_URL || "";
const HARDHAT_CHAIN_ID = process.env.HARDHAT_CHAIN_ID || HARDHAT_CHAIN_ID_DEFAULT;

const INTEGRATION_WITH_SCRATCH_DEPLOY = process.env.INTEGRATION_WITH_SCRATCH_DEPLOY || "off";

Expand Down Expand Up @@ -55,7 +53,6 @@ const config: HardhatUserConfig = {
networks: {
"local": {
url: process.env.LOCAL_RPC_URL || RPC_URL,
chainId: HARDHAT_CHAIN_ID_DEFAULT,
},
"mainnet-fork": {
url: process.env.MAINNET_RPC_URL || RPC_URL,
Expand All @@ -74,7 +71,6 @@ const config: HardhatUserConfig = {
count: 30,
accountsBalance: "100000000000000000000000",
},
chainId: parseInt(HARDHAT_CHAIN_ID.toString()),
forking: getHardhatForkingConfig(),
},
"sepolia": {
Expand Down
5 changes: 2 additions & 3 deletions lib/protocol/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@ export const getProtocolContext = async (): Promise<ProtocolContext> => {

// By default, all flags are "on"
const flags = {
isScratchDeploy: process.env.INTEGRATION_WITH_SCRATCH_DEPLOY === "on",
withSimpleDvtModule: process.env.INTEGRATION_WITH_SIMPLE_DVT_MODULE !== "off",
onScratch: process.env.INTEGRATION_ON_SCRATCH === "on",
} as ProtocolContextFlags;

log.debug("Protocol context flags", {
"With simple DVT module": flags.withSimpleDvtModule,
"On scratch": flags.onScratch,
});

const context = {
Expand Down
3 changes: 1 addition & 2 deletions lib/protocol/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ async function getLocalNetworkConfig(network: string, source: string): Promise<P
locator: config["lidoLocator"].proxy.address,
agentAddress: config["app:aragon-agent"].proxy.address,
votingAddress: config["app:aragon-voting"].proxy.address,
easyTrackAddress: config["app:aragon-agent"].proxy.address,
sdvt: config["app:node-operators-registry"].proxy.address,
easyTrackAddress: config["app:aragon-voting"].proxy.address,
};
return new ProtocolNetworkConfig(getPrefixedEnv(network.toUpperCase(), defaultEnv), defaults, `${network}-${source}`);
}
Expand Down
2 changes: 2 additions & 0 deletions lib/protocol/provision.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ensureOracleCommitteeMembers,
ensureStakeLimit,
norEnsureOperators,
sdvtEnsureOperators,
unpauseStaking,
unpauseWithdrawalQueue,
} from "./helpers";
Expand All @@ -21,6 +22,7 @@ export const provision = async (ctx: ProtocolContext) => {
await unpauseWithdrawalQueue(ctx);

await norEnsureOperators(ctx, 3n, 5n);
await sdvtEnsureOperators(ctx, 3n, 5n);

await ensureStakeLimit(ctx);
};
3 changes: 1 addition & 2 deletions lib/protocol/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,7 @@ export type ProtocolSigners = {
export type Signer = keyof ProtocolSigners;

export type ProtocolContextFlags = {
isScratchDeploy: boolean;
withSimpleDvtModule: boolean;
onScratch: boolean;
};

export type ProtocolContext = {
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
"test:integration": "hardhat test test/integration/**/*.ts --bail",
"test:integration:trace": "hardhat test test/integration/**/*.ts --trace --disabletracer --bail",
"test:integration:fulltrace": "hardhat test test/integration/**/*.ts --fulltrace --disabletracer --bail",
"test:integration:scratch": "INTEGRATION_WITH_SCRATCH_DEPLOY=on INTEGRATION_WITH_SIMPLE_DVT_MODULE=off hardhat test test/integration/**/*.ts --bail",
"test:integration:scratch:trace": "INTEGRATION_WITH_SCRATCH_DEPLOY=on INTEGRATION_WITH_SIMPLE_DVT_MODULE=off hardhat test test/integration/**/*.ts --trace --disabletracer --bail",
"test:integration:scratch:fulltrace": "INTEGRATION_WITH_SCRATCH_DEPLOY=on INTEGRATION_WITH_SIMPLE_DVT_MODULE=off hardhat test test/integration/**/*.ts --fulltrace --disabletracer --bail",
"test:integration:fork:local": "INTEGRATION_WITH_SIMPLE_DVT_MODULE=off hardhat test test/integration/**/*.ts --network local --bail",
"test:integration:scratch": "INTEGRATION_WITH_SCRATCH_DEPLOY=on hardhat test test/integration/**/*.ts --bail",
"test:integration:scratch:trace": "INTEGRATION_WITH_SCRATCH_DEPLOY=on hardhat test test/integration/**/*.ts --trace --disabletracer --bail",
"test:integration:scratch:fulltrace": "INTEGRATION_WITH_SCRATCH_DEPLOY=on hardhat test test/integration/**/*.ts --fulltrace --disabletracer --bail",
"test:integration:fork:local": "hardhat test test/integration/**/*.ts --network local --bail",
"test:integration:fork:mainnet": "hardhat test test/integration/**/*.ts --network mainnet-fork --bail",
"typecheck": "tsc --noEmit",
"prepare": "husky",
Expand Down
8 changes: 2 additions & 6 deletions scripts/scratch/steps/0100-deploy-simple-dvt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,7 @@ async function deployEmptyAppProxy(deployer: string, appName: string) {
async function deploySimpleDvt(deployer: string) {
const state = readNetworkState({ deployer });

if (state[Sk.appSimpleDvt]?.implementation) {
log(`Simple DVT app already deployed at ${state[Sk.appSimpleDvt].implementation.address}`);
return;
}

const proxyAddress = state[Sk.appSimpleDvt].proxy.address;
const lidoLocatorAddress = state[Sk.lidoLocator].proxy.address;
const norImplAddress = state[Sk.appNodeOperatorsRegistry].implementation.address;

Expand All @@ -69,7 +65,7 @@ async function deploySimpleDvt(deployer: string) {
const receipt = await makeTx(
template,
"createSimpleDVTApp",
[[1, 0, 0], norImplAddress, state[Sk.stakingRouter].proxy.address, NULL_CONTENT_URI],
[[1, 0, 0], proxyAddress, norImplAddress, state[Sk.stakingRouter].proxy.address, NULL_CONTENT_URI],
{
from: deployer,
},
Expand Down
9 changes: 2 additions & 7 deletions scripts/scratch/steps/0150-plug-staking-modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ export async function main() {

// Get contract instances
const stakingRouter = await loadContract("StakingRouter", state.stakingRouter.proxy.address);
const nodeOperatorsRegistry = await loadContract(
"NodeOperatorsRegistry",
state[Sk.appNodeOperatorsRegistry].proxy.address,
);
const simpleDvt = await loadContract("NodeOperatorsRegistry", state[Sk.appSimpleDvt].proxy.address);

// Grant STAKING_MODULE_MANAGE_ROLE to deployer
await makeTx(stakingRouter, "grantRole", [STAKING_MODULE_MANAGE_ROLE, deployer], { from: deployer });
Expand All @@ -36,7 +31,7 @@ export async function main() {
"addStakingModule",
[
state.nodeOperatorsRegistry.deployParameters.stakingModuleTypeId,
nodeOperatorsRegistry.address,
state[Sk.appNodeOperatorsRegistry].proxy.address,
NOR_STAKING_MODULE_TARGET_SHARE_BP,
NOR_STAKING_MODULE_MODULE_FEE_BP,
NOR_STAKING_MODULE_TREASURY_FEE_BP,
Expand All @@ -49,7 +44,7 @@ export async function main() {
"addStakingModule",
[
state.simpleDvt.deployParameters.stakingModuleTypeId,
simpleDvt.address,
state[Sk.appSimpleDvt].proxy.address,
SDVT_STAKING_MODULE_TARGET_SHARE_BP,
SDVT_STAKING_MODULE_MODULE_FEE_BP,
SDVT_STAKING_MODULE_TREASURY_FEE_BP,
Expand Down
16 changes: 8 additions & 8 deletions test/integration/accounting.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,16 @@ describe("Accounting", () => {
await finalizeWithdrawalQueue(ctx, stEthHolder, ethHolder);

await norEnsureOperators(ctx, 3n, 5n);
if (ctx.flags.withSimpleDvtModule) {
await sdvtEnsureOperators(ctx, 3n, 5n);
}
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);

await report(ctx, {
clDiff: ether("32") * 3n, // 32 ETH * 3 validators
clAppearedValidators: 3n,
clDiff: ether("32") * 6n, // 32 ETH * (3 + 3) validators
clAppearedValidators: 6n,
excludeVaultsBalances: true,
});
});
Expand Down Expand Up @@ -325,7 +325,7 @@ describe("Accounting", () => {
const norSharesAsFees = transferSharesEvents[hasWithdrawals ? 1 : 0];

// if withdrawals processed goes after burner and NOR, if no withdrawals processed goes after NOR
const sdvtSharesAsFees = ctx.flags.withSimpleDvtModule ? transferSharesEvents[hasWithdrawals ? 2 : 1] : null;
const sdvtSharesAsFees = transferSharesEvents[hasWithdrawals ? 2 : 1];

expect(transferSharesEvents.length).to.equal(
hasWithdrawals ? 2n : 1n + stakingModulesCount,
Expand Down Expand Up @@ -668,7 +668,7 @@ describe("Accounting", () => {
const norSharesAsFees = transferSharesEvents[hasWithdrawals ? 1 : 0];

// if withdrawals processed goes after burner and NOR, if no withdrawals processed goes after NOR
const sdvtSharesAsFees = ctx.flags.withSimpleDvtModule ? transferSharesEvents[hasWithdrawals ? 2 : 1] : null;
const sdvtSharesAsFees = transferSharesEvents[hasWithdrawals ? 2 : 1];

expect(transferSharesEvents.length).to.equal(
hasWithdrawals ? 2n : 1n + stakingModulesCount,
Expand Down Expand Up @@ -768,7 +768,7 @@ describe("Accounting", () => {
const norSharesAsFees = transferSharesEvents[hasWithdrawals ? 1 : 0];

// if withdrawals processed goes after burner and NOR, if no withdrawals processed goes after NOR
const sdvtSharesAsFees = ctx.flags.withSimpleDvtModule ? transferSharesEvents[hasWithdrawals ? 2 : 1] : null;
const sdvtSharesAsFees = transferSharesEvents[hasWithdrawals ? 2 : 1];

expect(transferSharesEvents.length).to.equal(
hasWithdrawals ? 2n : 1n + stakingModulesCount,
Expand Down
74 changes: 30 additions & 44 deletions test/integration/protocol-happy-path.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,8 @@ describe("Protocol Happy Path", () => {
await norEnsureOperators(ctx, 3n, 5n);
expect(await ctx.contracts.nor.getNodeOperatorsCount()).to.be.at.least(3n);

if (ctx.flags.withSimpleDvtModule) {
await sdvtEnsureOperators(ctx, 3n, 5n);
expect(await ctx.contracts.sdvt.getNodeOperatorsCount()).to.be.at.least(3n);
}
await sdvtEnsureOperators(ctx, 3n, 5n);
expect(await ctx.contracts.sdvt.getNodeOperatorsCount()).to.be.at.least(3n);
});

it("Should allow ETH holders to submit 100 ETH stake", async () => {
Expand Down Expand Up @@ -222,25 +220,23 @@ describe("Protocol Happy Path", () => {
const depositCountsNor = unbufferedAmountNor / ether("32");
let expectedBufferedEtherAfterDeposit = bufferedEtherBeforeDeposit - unbufferedAmountNor;

if (ctx.flags.withSimpleDvtModule) {
const depositSdvtTx = await lido.connect(dsmSigner).deposit(MAX_DEPOSIT, SIMPLE_DVT_MODULE_ID, ZERO_HASH);
const depositSdvtReceipt = await trace<ContractTransactionReceipt>("lido.deposit (Simple DVT)", depositSdvtTx);
const depositSdvtTx = await lido.connect(dsmSigner).deposit(MAX_DEPOSIT, SIMPLE_DVT_MODULE_ID, ZERO_HASH);
const depositSdvtReceipt = await trace<ContractTransactionReceipt>("lido.deposit (Simple DVT)", depositSdvtTx);

const unbufferedEventSdvt = ctx.getEvents(depositSdvtReceipt, "Unbuffered")[0];
const depositedValidatorsChangedEventSdvt = ctx.getEvents(depositSdvtReceipt, "DepositedValidatorsChanged")[0];
const unbufferedEventSdvt = ctx.getEvents(depositSdvtReceipt, "Unbuffered")[0];
const depositedValidatorsChangedEventSdvt = ctx.getEvents(depositSdvtReceipt, "DepositedValidatorsChanged")[0];

const unbufferedAmountSdvt = unbufferedEventSdvt.args[0];
const newValidatorsCountSdvt = depositedValidatorsChangedEventSdvt.args[0];
const unbufferedAmountSdvt = unbufferedEventSdvt.args[0];
const newValidatorsCountSdvt = depositedValidatorsChangedEventSdvt.args[0];

const depositCountsTotal = depositCountsNor + unbufferedAmountSdvt / ether("32");
expectedBufferedEtherAfterDeposit -= unbufferedAmountSdvt;
const depositCountsTotal = depositCountsNor + unbufferedAmountSdvt / ether("32");
expectedBufferedEtherAfterDeposit -= unbufferedAmountSdvt;

expect(depositCountsTotal).to.be.gt(0n, "Deposit counts");
expect(newValidatorsCountSdvt).to.equal(
depositedValidatorsBefore + depositCountsTotal,
"New validators count after deposit",
);
}
expect(depositCountsTotal).to.be.gt(0n, "Deposit counts");
expect(newValidatorsCountSdvt).to.equal(
depositedValidatorsBefore + depositCountsTotal,
"New validators count after deposit",
);

const bufferedEtherAfterDeposit = await lido.getBufferedEther();

Expand Down Expand Up @@ -287,23 +283,16 @@ describe("Protocol Happy Path", () => {
let expectedBurnerTransfers = norStatus.hasPenalizedOperators ? 1n : 0n;
let expectedTransfers = norStatus.activeOperators;

let sdvtStatusLog = {};
if (ctx.flags.withSimpleDvtModule) {
const sdvtStatus = await getNodeOperatorsStatus(sdvt);
const sdvtStatus = await getNodeOperatorsStatus(sdvt);

expectedBurnerTransfers += sdvtStatus.hasPenalizedOperators ? 1n : 0n;
expectedTransfers += sdvtStatus.activeOperators;

sdvtStatusLog = {
"SDVT active operators": sdvtStatus.activeOperators,
"SDVT (transfer to burner)": sdvtStatus.hasPenalizedOperators,
};
}
expectedBurnerTransfers += sdvtStatus.hasPenalizedOperators ? 1n : 0n;
expectedTransfers += sdvtStatus.activeOperators;

log.debug("Expected distributions", {
"NOR active operators": norStatus.activeOperators,
"NOR (transfer to burner)": norStatus.hasPenalizedOperators,
...sdvtStatusLog,
"SDVT active operators": sdvtStatus.activeOperators,
"SDVT (transfer to burner)": sdvtStatus.hasPenalizedOperators,
});

const treasuryBalanceBeforeRebase = await lido.sharesOf(treasuryAddress);
Expand Down Expand Up @@ -339,10 +328,9 @@ describe("Protocol Happy Path", () => {

const toBurnerTransfer = transferEvents[0];
const toNorTransfer = transferEvents[1];
const toSdvtTransfer = ctx.flags.withSimpleDvtModule ? transferEvents[2] : undefined;
const toTreasuryTransfer = ctx.flags.withSimpleDvtModule ? transferEvents[3] : transferEvents[2];

const expectedTransferEvents = ctx.flags.withSimpleDvtModule ? 4 : 3;
const toSdvtTransfer = transferEvents[2];
const toTreasuryTransfer = transferEvents[3];
const expectedTransferEvents = 4;

expect(transferEvents.length).to.equal(expectedTransferEvents, "Transfer events count");

Expand All @@ -362,15 +350,13 @@ describe("Protocol Happy Path", () => {
"Transfer to NOR",
);

if (ctx.flags.withSimpleDvtModule) {
expect(toSdvtTransfer?.args.toObject()).to.include(
{
from: ZeroAddress,
to: sdvt.address,
},
"Transfer to SDVT",
);
}
expect(toSdvtTransfer?.args.toObject()).to.include(
{
from: ZeroAddress,
to: sdvt.address,
},
"Transfer to SDVT",
);

expect(toTreasuryTransfer?.args.toObject()).to.include(
{
Expand Down

0 comments on commit a66bf6d

Please sign in to comment.