Skip to content

Commit

Permalink
feat: devnet command
Browse files Browse the repository at this point in the history
  • Loading branch information
avsetsin committed Dec 13, 2024
1 parent 58baa2f commit aeb85f9
Show file tree
Hide file tree
Showing 15 changed files with 409 additions and 104 deletions.
90 changes: 90 additions & 0 deletions programs/devnet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { program } from '@command';
import { votingNewVote } from '@scripts';
import { CallScriptActionWithDescription, encodeCallScript, forwardVoteFromTm, splitAddresses, logger } from '@utils';
import chalk from 'chalk';
import {
encodeScriptsAO,
encodeScriptsDSM,
encodeScriptsLidoResumeIfStopped,
encodeScriptsRoles,
encodeScriptsVEBO,
encodeScriptsWQResumeIfPaused,
joinVotingDesc,
DEFAULT_DEVNET_CONFIG,
} from './omnibus-scripts/generators';

const devnet = program.command('devnet').description('scripts for devnet');

const head = chalk.blue.bold;
const bold = chalk.white.bold;

devnet
.command('setup')
.option('-l, --staking-limit <number>', 'staking limit in eth', String(DEFAULT_DEVNET_CONFIG.STAKING_LIMIT))
.option('-m, --oracles-members <string>', 'VEBO and AO members separated by comma', '')
.option('-q, --oracles-quorum <number>', 'VEBO and AO members quorum, should be > 50%', '1')
.option('-e, --oracles-initial-epoch <number>', 'initial epoch for VEBO and AO')
.option('-g, --dsm-guardians <string>', 'DSM guardians separated by comma', '')
.option('-d, --dsm-quorum <number>', 'DSM guardians quorum', '1')
.option('-b, --roles-beneficiary <string>', 'roles beneficiary', DEFAULT_DEVNET_CONFIG.ROLES_BENEFICIARY)
.action(async (options) => {
// Lido
logger.log(head('Lido'));
const stakingLimit = Number(options.stakingLimit);
const lidoResumeScripts = await encodeScriptsLidoResumeIfStopped(stakingLimit);
logger.log();

// Withdrawal Queue
logger.log(head('Withdrawal Queue'));
const wqResumeScripts = await encodeScriptsWQResumeIfPaused();
logger.log();

// Oracles
logger.log(head('Oracles'));

const oraclesInitialEpoch = options.oraclesInitialEpoch ? Number(options.oraclesInitialEpoch) : undefined;
const oraclesMembers = splitAddresses(options.oraclesMembers);
const oraclesQuorum = Number(options.oraclesQuorum);

/**/ logger.log(bold('VEBO'));
/**/ const veboScripts = await encodeScriptsVEBO(oraclesMembers, oraclesQuorum, oraclesInitialEpoch);
/**/ logger.log();

/**/ logger.log(bold('AO'));
/**/ const aoScripts = await encodeScriptsAO(oraclesMembers, oraclesQuorum, oraclesInitialEpoch);
/**/ logger.log();

// DSM
logger.log(head('DSM'));
const guardians = splitAddresses(options.dsmGuardians);
const dsmQuorum = Number(options.dsmQuorum);
const dsmScripts = await encodeScriptsDSM(guardians, dsmQuorum);
logger.log();

// Roles
logger.log(head('Roles'));
const rolesBeneficiary = options.rolesBeneficiary;
const rolesScripts = await encodeScriptsRoles(rolesBeneficiary);
logger.log();

// Voting calls
const votingCalls: CallScriptActionWithDescription[] = [
...lidoResumeScripts,
...wqResumeScripts,
...veboScripts,
...aoScripts,
...dsmScripts,
...rolesScripts,
];

// Voting description
const description = joinVotingDesc(votingCalls);
logger.log(head('Voting description:'));
logger.log(description);
logger.log();

// Voting start
const voteEvmScript = encodeCallScript(votingCalls);
const [newVoteCalldata] = votingNewVote(voteEvmScript, description);
await forwardVoteFromTm(newVoteCalldata);
});
1 change: 1 addition & 0 deletions programs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export * from './csm-oracle';
export * from './csm';
export * from './deposit-contract';
export * from './deposit-data';
export * from './devnet';
export * from './dsm';
export * from './eth';
export * from './etherscan';
Expand Down
103 changes: 6 additions & 97 deletions programs/omnibus-scripts/devnet-start.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,24 @@
import {
consensusForAccountingContract,
consensusForExitBusContract,
norContract,
oracleConfigContract,
sanityCheckerContract,
stakingRouterContract,
} from '@contracts';
import { wallet } from '@providers';
import { votingNewVote } from '@scripts';
import { CallScriptActionWithDescription, encodeCallScript, forwardVoteFromTm, logger } from '@utils';
import {
encodeFromVotingGrantRolesAragonWithConfirm,
encodeFromAgentGrantRolesAccessControlWithConfirmed,
encodeScriptsVEBOResumeIfPaused,
encodeScriptsWQResumeIfPaused,
promptScriptsAddingGuardiansFromAgentIfEmpty,
promptScriptsAOInitialEpoch,
promptScriptsAOMembers,
promptScriptsLidoResumeIfStopped,
promptScriptsVEBOInitialEpoch,
promptScriptsVEBOMembers,
promptRolesBeneficiary,
joinVotingDesc,
DEFAULT_DEVNET_CONFIG,
promptScriptsVEBO,
promptScriptsAO,
promptScriptsDSM,
promptScriptsRoles,
} from './generators';
import chalk from 'chalk';

const DEFAULT_CONFIG = {
STAKING_LIMIT: 150_000,
ORACLE_MEMBERS: 2,
DSM_GUARDIANS_MEMBERS: 2,
ROLES_BENEFICIARY: wallet.address,
};

const NOR_ROLES = [
'STAKING_ROUTER_ROLE',
'MANAGE_SIGNING_KEYS',
'SET_NODE_OPERATOR_LIMIT_ROLE',
'MANAGE_NODE_OPERATOR_ROLE',
];

const HASH_CONSENSUS_ROLES = [
'MANAGE_MEMBERS_AND_QUORUM_ROLE',
'MANAGE_FRAME_CONFIG_ROLE',
'MANAGE_FAST_LANE_CONFIG_ROLE',
];

const ORACLE_CONFIG_ROLES = ['CONFIG_MANAGER_ROLE'];
const STAKING_ROUTER_ROLES = ['STAKING_MODULE_MANAGE_ROLE'];
const SANITY_CHECKER_ROLES = ['ALL_LIMITS_MANAGER_ROLE'];

const head = chalk.blue.bold;
const bold = chalk.white.bold;

export const devnetStart = async () => {
// Lido
logger.log(head('Lido'));
const lidoResumeScripts = await promptScriptsLidoResumeIfStopped(DEFAULT_CONFIG.STAKING_LIMIT);
const lidoResumeScripts = await promptScriptsLidoResumeIfStopped(DEFAULT_DEVNET_CONFIG.STAKING_LIMIT);
logger.log();

// Withdrawal Queue
Expand Down Expand Up @@ -105,57 +68,3 @@ export const devnetStart = async () => {
const [newVoteCalldata] = votingNewVote(voteEvmScript, description);
await forwardVoteFromTm(newVoteCalldata);
};

const promptScriptsVEBO = async () => {
const veboResumeScripts = await encodeScriptsVEBOResumeIfPaused();
const veboMembersScripts = await promptScriptsVEBOMembers(DEFAULT_CONFIG.ORACLE_MEMBERS);
const veboInitialEpochScripts = await promptScriptsVEBOInitialEpoch();
return [...veboResumeScripts, ...veboMembersScripts, ...veboInitialEpochScripts];
};

const promptScriptsAO = async () => {
const aoMembersScripts = await promptScriptsAOMembers(DEFAULT_CONFIG.ORACLE_MEMBERS);
const aoInitialEpochScripts = await promptScriptsAOInitialEpoch();
return [...aoMembersScripts, ...aoInitialEpochScripts];
};

const promptScriptsDSM = async () => {
const guardiansScripts = await promptScriptsAddingGuardiansFromAgentIfEmpty(DEFAULT_CONFIG.DSM_GUARDIANS_MEMBERS);
return [...guardiansScripts];
};

const promptScriptsRoles = async () => {
const beneficiary = await promptRolesBeneficiary(DEFAULT_CONFIG.ROLES_BENEFICIARY);
const srScripts = await encodeFromAgentGrantRolesAccessControlWithConfirmed(
'SR',
STAKING_ROUTER_ROLES,
stakingRouterContract,
beneficiary,
);
const norScripts = await encodeFromVotingGrantRolesAragonWithConfirm('NOR', NOR_ROLES, norContract, beneficiary);
const aoScripts = await encodeFromAgentGrantRolesAccessControlWithConfirmed(
'AO consensus',
HASH_CONSENSUS_ROLES,
consensusForAccountingContract,
beneficiary,
);
const veboScripts = await encodeFromAgentGrantRolesAccessControlWithConfirmed(
'VEBO consensus',
HASH_CONSENSUS_ROLES,
consensusForExitBusContract,
beneficiary,
);
const oracleConfigScripts = await encodeFromAgentGrantRolesAccessControlWithConfirmed(
'Oracle daemon config',
ORACLE_CONFIG_ROLES,
oracleConfigContract,
beneficiary,
);
const sanityCheckerScripts = await encodeFromAgentGrantRolesAccessControlWithConfirmed(
'Sanity checker',
SANITY_CHECKER_ROLES,
sanityCheckerContract,
beneficiary,
);
return [...srScripts, ...norScripts, ...aoScripts, ...veboScripts, ...oracleConfigScripts, ...sanityCheckerScripts];
};
2 changes: 1 addition & 1 deletion programs/omnibus-scripts/generators/access-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const encodeFromAgentGrantRole = async (
});
};

export const encodeFromAgentGrantRolesAccessControlWithConfirmed = async (
export const encodeFromAgentGrantRolesAccessControlWithConfirm = async (
contractName: string,
rolesToGrant: string[],
contract: Contract,
Expand Down
28 changes: 27 additions & 1 deletion programs/omnibus-scripts/generators/accounting-oracle.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@
import { accountingOracleContract, consensusForAccountingContract } from '@contracts';
import { encodeFromAgentGrantRole } from './access-control';
import { promptScriptsOracleInitialEpochIfNotSet, promptScriptsOracleMembersIfEmpty } from './oracles';
import {
encodeScriptsOracleInitialEpochIfPassed,
encodeScriptsOracleMembers,
promptScriptsOracleInitialEpochIfNotSet,
promptScriptsOracleMembersIfEmpty,
} from './oracles';
import { DEFAULT_DEVNET_CONFIG } from './devnet';

export const encodeScriptsAO = async (oracleMembers: string[], oracleQuorum: number, initialEpoch?: number) => {
const aoMembersScripts = await encodeScriptsAOMembers(oracleMembers, oracleQuorum);
const aoInitialEpochScripts = await encodeScriptsAOInitialEpoch(initialEpoch);
return [...aoMembersScripts, ...aoInitialEpochScripts];
};

export const promptScriptsAO = async () => {
const aoMembersScripts = await promptScriptsAOMembers(DEFAULT_DEVNET_CONFIG.ORACLE_MEMBERS);
const aoInitialEpochScripts = await promptScriptsAOInitialEpoch();
return [...aoMembersScripts, ...aoInitialEpochScripts];
};

export const encodeFromAgentAOGrantRole = async (role: string, account: string) => {
return await encodeFromAgentGrantRole('AO', accountingOracleContract, role, account);
};

export const encodeScriptsAOMembers = async (members: string[], quorum: number) => {
return await encodeScriptsOracleMembers('AO', consensusForAccountingContract, members, quorum);
};

export const encodeScriptsAOInitialEpoch = async (initialEpoch?: number) => {
return await encodeScriptsOracleInitialEpochIfPassed('AO', consensusForAccountingContract, initialEpoch);
};

export const promptScriptsAOMembers = async (initialMembers: number) => {
return await promptScriptsOracleMembersIfEmpty('AO', consensusForAccountingContract, initialMembers);
};
Expand Down
8 changes: 8 additions & 0 deletions programs/omnibus-scripts/generators/devnet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { wallet } from '@providers';

export const DEFAULT_DEVNET_CONFIG = {
STAKING_LIMIT: 150_000,
ORACLE_MEMBERS: 2,
DSM_GUARDIANS_MEMBERS: 2,
ROLES_BENEFICIARY: wallet.address,
};
35 changes: 35 additions & 0 deletions programs/omnibus-scripts/generators/dsm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,41 @@ import { encodeFromAgent } from '@scripts';
import { CallScriptActionWithDescription, logger } from '@utils';
import { isAddress } from 'ethers';
import prompts from 'prompts';
import { DEFAULT_DEVNET_CONFIG } from './devnet';

export const encodeScriptsDSM = async (guardians: string[], quorum: number) => {
const guardiansScripts = await encodeScriptsAddingGuardiansFromAgent(guardians, quorum);
return [...guardiansScripts];
};

export const encodeScriptsAddingGuardiansFromAgent = async (guardians: string[], quorum: number) => {
const total = guardians.length;

if (total === 0) {
logger.warn('No guardians to add. Skipping adding guardians');
return [];
}

logger.log('Preparing scripts to add guardians');

const calls: CallScriptActionWithDescription[] = [];

for (let i = 0; i < total; i++) {
const quorumForIteration = Math.min(i + 1, quorum);
const [, addGuardianCall] = encodeFromAgentAddGuardian(guardians[i], quorumForIteration);

calls.push(addGuardianCall);
}

return calls;
};

export const promptScriptsDSM = async () => {
const guardiansScripts = await promptScriptsAddingGuardiansFromAgentIfEmpty(
DEFAULT_DEVNET_CONFIG.DSM_GUARDIANS_MEMBERS,
);
return [...guardiansScripts];
};

export const promptScriptsAddingGuardiansFromAgentIfEmpty = async (initialTotal: number) => {
const guardians = await dsmContract.getGuardians();
Expand Down
30 changes: 29 additions & 1 deletion programs/omnibus-scripts/generators/exit-bus-oracle.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
import { consensusForExitBusContract, exitBusOracleContract } from '@contracts';
import { encodeUnpauseIfPaused } from './pause-until';
import { promptScriptsOracleInitialEpochIfNotSet, promptScriptsOracleMembersIfEmpty } from './oracles';
import {
encodeScriptsOracleInitialEpochIfPassed,
encodeScriptsOracleMembers,
promptScriptsOracleInitialEpochIfNotSet,
promptScriptsOracleMembersIfEmpty,
} from './oracles';
import { DEFAULT_DEVNET_CONFIG } from './devnet';

export const encodeScriptsVEBO = async (oracleMembers: string[], oracleQuorum: number, initialEpoch?: number) => {
const veboResumeScripts = await encodeScriptsVEBOResumeIfPaused();
const veboMembersScripts = await encodeScriptsVEBOMembers(oracleMembers, oracleQuorum);
const veboInitialEpochScripts = await encodeScriptsVEBOInitialEpoch(initialEpoch);
return [...veboResumeScripts, ...veboMembersScripts, ...veboInitialEpochScripts];
};

export const promptScriptsVEBO = async () => {
const veboResumeScripts = await encodeScriptsVEBOResumeIfPaused();
const veboMembersScripts = await promptScriptsVEBOMembers(DEFAULT_DEVNET_CONFIG.ORACLE_MEMBERS);
const veboInitialEpochScripts = await promptScriptsVEBOInitialEpoch();
return [...veboResumeScripts, ...veboMembersScripts, ...veboInitialEpochScripts];
};

export const encodeScriptsVEBOResumeIfPaused = async () => {
return encodeUnpauseIfPaused('VEBO', exitBusOracleContract);
};

export const encodeScriptsVEBOMembers = async (members: string[], quorum: number) => {
return await encodeScriptsOracleMembers('VEBO', consensusForExitBusContract, members, quorum);
};

export const encodeScriptsVEBOInitialEpoch = async (initialEpoch?: number) => {
return await encodeScriptsOracleInitialEpochIfPassed('VEBO', consensusForExitBusContract, initialEpoch);
};

export const promptScriptsVEBOMembers = async (initialMembers: number) => {
return await promptScriptsOracleMembersIfEmpty('VEBO', consensusForExitBusContract, initialMembers);
};
Expand Down
1 change: 1 addition & 0 deletions programs/omnibus-scripts/generators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './access-control';
export * from './accounting-oracle';
export * from './aragon';
export * from './desc';
export * from './devnet';
export * from './dsm';
export * from './exit-bus-oracle';
export * from './lido';
Expand Down
18 changes: 17 additions & 1 deletion programs/omnibus-scripts/generators/lido.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,23 @@ export const promptScriptsLidoResume = async (initialStakingLimit: number) => {
message: 'Enter daily Lido staking limit',
});

const parsedLimit = parseEther(String(limit));
return await encodeScriptsLidoResume(limit);
};

export const encodeScriptsLidoResumeIfStopped = async (stakingLimit: number) => {
const isLidoStopped = await lidoContract.isStopped();

if (isLidoStopped) {
logger.log('Contract is stopped. Preparing scripts to resume and set staking limit');
return await encodeScriptsLidoResume(stakingLimit);
}

logger.warn('Contract is already running. Skipping resume and staking limit setting');
return [];
};

export const encodeScriptsLidoResume = async (stakingLimit: number | string) => {
const parsedLimit = parseEther(String(stakingLimit));
const [, resumeProtocolCall, resumeStakingCall, setStakingLimitCall] = resumeLidoAndSetStakingLimit(parsedLimit);
return [resumeProtocolCall, resumeStakingCall, setStakingLimitCall];
};
Loading

0 comments on commit aeb85f9

Please sign in to comment.