Skip to content

Commit

Permalink
Merge pull request #845 from lidofinance/feat/scratch-simple-dvt
Browse files Browse the repository at this point in the history
feat: add Simple DVT to scratch deploy
  • Loading branch information
tamtamchik authored Oct 9, 2024
2 parents 8ba5b24 + 3057f07 commit 096a4fb
Show file tree
Hide file tree
Showing 22 changed files with 225 additions and 208 deletions.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ LOCAL_WITHDRAWAL_VAULT_ADDRESS=

# RPC URL for a separate, non Hardhat Network node (Anvil, Infura, Alchemy, etc.)
MAINNET_RPC_URL=http://localhost:8545

# RPC URL for Hardhat Network forking, required for running tests on mainnet fork with tracing (Infura, Alchemy, etc.)
# https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#forking-other-networks
MAINNET_FORKING_URL=
HARDHAT_FORKING_URL=

# https://docs.lido.fi/deployed-contracts
MAINNET_LOCATOR_ADDRESS=0xC1d0b3DE6792Bf6b4b37EccdcC24e45978Cfd2Eb
Expand Down
8 changes: 5 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ the [Lido Research Forum](https://research.lido.fi/).
- [Foundry](https://book.getfoundry.sh/) latest available version

> [!TIP]
> On macOS with Homebrew, it is recommended to install Node.js using [`n`](https://github.com/tj/n) or [ > `nvm`](https://github.com/nvm-sh/nvm) version managers.
> On macOS with Homebrew, it is recommended to install Node.js using [`n`](https://github.com/tj/n) or
> [ >`nvm`](https://github.com/nvm-sh/nvm) version managers.
>
> Example setup process using `n` package manager for zsh users:
>
> ```bash
Expand Down Expand Up @@ -325,8 +327,8 @@ This is the most common method for running integration tests. It uses an instanc
mainnet environment, allowing you to run integration tests with trace logging.
> [!NOTE]
> Ensure that `MAINNET_FORKING_URL` and other `MAINNET_*` environment variables are set in the `.env` file (refer to
> `.env.example` for guidance).
> Ensure that `HARDHAT_FORKING_URL` is set to Ethereum Mainnet RPC and `MAINNET_*` environment variables are set in the
> `.env` file (refer to `.env.example` for guidance).
```bash
# Run all integration tests
Expand Down
120 changes: 46 additions & 74 deletions contracts/0.4.24/template/LidoTemplate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ contract LidoTemplate is IsContract {
string private constant LIDO_APP_NAME = "lido";
string private constant ORACLE_APP_NAME = "oracle";
string private constant NODE_OPERATORS_REGISTRY_APP_NAME = "node-operators-registry";
string private constant SIMPLE_DVT_APP_NAME = "simple-dvt";

// DAO config constants
bool private constant TOKEN_TRANSFERABLE = true;
Expand All @@ -85,6 +86,7 @@ contract LidoTemplate is IsContract {
Repo lido;
Repo oracle;
Repo nodeOperatorsRegistry;
Repo simpleDVT;
Repo aragonAgent;
Repo aragonFinance;
Repo aragonTokenManager;
Expand All @@ -104,6 +106,7 @@ contract LidoTemplate is IsContract {
Lido lido;
LegacyOracle oracle;
NodeOperatorsRegistry operators;
NodeOperatorsRegistry sdvt;
address stakingRouter;
}

Expand Down Expand Up @@ -261,7 +264,6 @@ contract LidoTemplate is IsContract {
bytes _nodeOperatorsRegistryContentURI,
address _oracleImplAddress,
bytes _oracleContentURI

) external onlyOwner {
require(deployState.lidoRegistry != address(0), ERROR_REGISTRY_NOT_DEPLOYED);

Expand Down Expand Up @@ -293,14 +295,18 @@ contract LidoTemplate is IsContract {
_oracleContentURI
);

apmRepos.simpleDVT = lidoRegistry.newRepoWithVersion(
SIMPLE_DVT_APP_NAME,
this,
_initialSemanticVersion,
_nodeOperatorsRegistryImplAddress,
_nodeOperatorsRegistryContentURI
);

emit TmplReposCreated();
}

function newDAO(
string _tokenName,
string _tokenSymbol,
uint64[4] _votingSettings
) external onlyOwner {
function newDAO(string _tokenName, string _tokenSymbol, uint64[4] _votingSettings) external onlyOwner {
DeployState memory state = deployState;

require(state.lidoRegistry != address(0), ERROR_REGISTRY_NOT_DEPLOYED);
Expand Down Expand Up @@ -328,7 +334,7 @@ contract LidoTemplate is IsContract {
_votingSettings[0], // support
_votingSettings[1], // acceptance
_votingSettings[2], // duration
_votingSettings[3] // objectionPhaseDuration
_votingSettings[3] // objectionPhaseDuration
);

bytes memory noInit = new bytes(0);
Expand All @@ -345,6 +351,14 @@ contract LidoTemplate is IsContract {
)
);

state.sdvt = NodeOperatorsRegistry(
_installNonDefaultApp(
state.dao,
_getAppId(SIMPLE_DVT_APP_NAME, state.lidoRegistryEnsNode),
noInit
)
);

state.oracle = LegacyOracle(
_installNonDefaultApp(state.dao, _getAppId(ORACLE_APP_NAME, state.lidoRegistryEnsNode), noInit)
);
Expand Down Expand Up @@ -387,13 +401,7 @@ contract LidoTemplate is IsContract {
emit TmplTokensIssued(totalAmount);
}

function finalizeDAO(
string _daoName,
uint256 _unvestedTokensAmount,
address _stakingRouter
)
external onlyOwner
{
function finalizeDAO(string _daoName, uint256 _unvestedTokensAmount, address _stakingRouter) external onlyOwner {
require(_stakingRouter != address(0));
DeployState memory state = deployState;
APMRepos memory repos = apmRepos;
Expand Down Expand Up @@ -474,9 +482,7 @@ contract LidoTemplate is IsContract {
uint64 _acceptance,
uint64 _duration,
uint64 _objectionPhaseDuration
)
private returns (Voting)
{
) private returns (Voting) {
bytes32 appId = _getAppId(ARAGON_VOTING_APP_NAME, _lidoRegistryEnsNode);
bytes memory initializeData = abi.encodeWithSelector(
Voting(0).initialize.selector,
Expand Down Expand Up @@ -511,11 +517,7 @@ contract LidoTemplate is IsContract {

/* TOKEN */

function _createToken(
string memory _name,
string memory _symbol,
uint8 _decimals
) internal returns (MiniMeToken) {
function _createToken(string memory _name, string memory _symbol, uint8 _decimals) internal returns (MiniMeToken) {
MiniMeToken token = miniMeFactory.createCloneToken(MiniMeToken(address(0)), 0, _name, _decimals, _symbol, true);
return token;
}
Expand All @@ -530,10 +532,7 @@ contract LidoTemplate is IsContract {
uint64 _vestingEnd,
bool _vestingRevokable,
uint256 _expectedFinalTotalSupply
)
private
returns (uint256 totalAmount)
{
) private returns (uint256 totalAmount) {
totalAmount = 0;
uint256 i;

Expand Down Expand Up @@ -614,6 +613,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 All @@ -630,38 +641,20 @@ contract LidoTemplate is IsContract {
_createPermissionForTemplate(_acl, _tokenManager, _tokenManager.ASSIGN_ROLE());
}

function _createPermissionForVoting(
ACL _acl,
address _app,
bytes32 perm,
address _voting
) internal {
function _createPermissionForVoting(ACL _acl, address _app, bytes32 perm, address _voting) internal {
_acl.createPermission(_voting, _app, perm, _voting);
}

function _createAgentPermissions(
ACL _acl,
Agent _agent,
address _voting
) internal {
function _createAgentPermissions(ACL _acl, Agent _agent, address _voting) internal {
_createPermissionForVoting(_acl, _agent, _agent.EXECUTE_ROLE(), _voting);
_createPermissionForVoting(_acl, _agent, _agent.RUN_SCRIPT_ROLE(), _voting);
}

function _createVaultPermissions(
ACL _acl,
Vault _vault,
address _finance,
address _voting
) internal {
function _createVaultPermissions(ACL _acl, Vault _vault, address _finance, address _voting) internal {
_acl.createPermission(_finance, _vault, _vault.TRANSFER_ROLE(), _voting);
}

function _createFinancePermissions(
ACL _acl,
Finance _finance,
address _voting
) internal {
function _createFinancePermissions(ACL _acl, Finance _finance, address _voting) internal {
_createPermissionForVoting(_acl, _finance, _finance.EXECUTE_PAYMENTS_ROLE(), _voting);
_createPermissionForVoting(_acl, _finance, _finance.MANAGE_PAYMENTS_ROLE(), _voting);
_createPermissionForVoting(_acl, _finance, _finance.CREATE_PAYMENTS_ROLE(), _voting);
Expand All @@ -673,39 +666,23 @@ contract LidoTemplate is IsContract {
_createPermissionForVoting(_acl, registry, registry.REGISTRY_ADD_EXECUTOR_ROLE(), _voting);
}

function _createVotingPermissions(
ACL _acl,
Voting _voting,
address _tokenManager
) internal {
function _createVotingPermissions(ACL _acl, Voting _voting, address _tokenManager) internal {
_createPermissionForVoting(_acl, _voting, _voting.MODIFY_QUORUM_ROLE(), _voting);
_createPermissionForVoting(_acl, _voting, _voting.MODIFY_SUPPORT_ROLE(), _voting);
_acl.createPermission(_tokenManager, _voting, _voting.CREATE_VOTES_ROLE(), _voting);
}

function _configureTokenManagerPermissions(
ACL _acl,
TokenManager _tokenManager,
address _voting
) internal {
function _configureTokenManagerPermissions(ACL _acl, TokenManager _tokenManager, address _voting) internal {
_removePermissionFromTemplate(_acl, _tokenManager, _tokenManager.ISSUE_ROLE());
_removePermissionFromTemplate(_acl, _tokenManager, _tokenManager.ASSIGN_ROLE());
_createPermissionForVoting(_acl, _tokenManager, _tokenManager.ASSIGN_ROLE(), _voting);
}

function _createPermissionForTemplate(
ACL _acl,
address _app,
bytes32 _permission
) private {
function _createPermissionForTemplate(ACL _acl, address _app, bytes32 _permission) private {
_acl.createPermission(address(this), _app, _permission, address(this));
}

function _removePermissionFromTemplate(
ACL _acl,
address _app,
bytes32 _permission
) private {
function _removePermissionFromTemplate(ACL _acl, address _app, bytes32 _permission) private {
_acl.revokePermission(address(this), _app, _permission);
_acl.removePermissionManager(_app, _permission);
}
Expand All @@ -716,12 +693,7 @@ contract LidoTemplate is IsContract {
_transferPermissionFromTemplate(_acl, _acl, _voting, _acl.CREATE_PERMISSIONS_ROLE(), _voting);
}

function _transferPermissionFromTemplate(
ACL _acl,
address _app,
address _to,
bytes32 _permission
) private {
function _transferPermissionFromTemplate(ACL _acl, address _app, address _to, bytes32 _permission) private {
_transferPermissionFromTemplate(_acl, _app, _to, _permission, _to);
}

Expand Down
16 changes: 9 additions & 7 deletions globals.d.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
declare namespace NodeJS {
export interface ProcessEnv {
/* RPC URL for Hardhat Network forking, required for running tests on mainnet fork with tracing */
MAINNET_FORKING_URL?: string;
/* iternal logging verbosity (used in scratch deploy / integration tests) */
LOG_LEVEL?: "all" | "debug" | "info" | "warn" | "error" | "none"; // default: "info"

/* logging verbosity */
LOG_LEVEL?: "all" | "debug" | "info" | "warn" | "error" | "none";
/**
* Flags for changing the behavior of the Hardhat Network
*/

/* RPC URL for Hardhat Network forking, required for running tests on mainnet fork with tracing */
HARDHAT_FORKING_URL?: 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_SCRATCH_DEPLOY?: "on" | "off";
/* if "on" the integration tests will enable assertions and checks for the simple DVT module */
INTEGRATION_SIMPLE_DVT_MODULE?: "on" | "off";
INTEGRATION_ON_SCRATCH?: "on" | "off"; // default: "off"

/**
* Network configuration for the protocol discovery.
Expand Down
16 changes: 9 additions & 7 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,18 @@ import { mochaRootHooks } from "test/hooks";
import "./tasks";

const RPC_URL: string = process.env.RPC_URL || "";
const MAINNET_FORKING_URL = process.env.MAINNET_FORKING_URL || "";
const INTEGRATION_SCRATCH_DEPLOY = process.env.INTEGRATION_SCRATCH_DEPLOY || "off";
const ACCOUNTS_PATH = "./accounts.json";

/**
* Determines the forking configuration for Hardhat.
* @returns The forking configuration object or undefined.
*/
const HARDHAT_FORKING_URL = process.env.HARDHAT_FORKING_URL || "";

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

/* Determines the forking configuration for Hardhat */
function getHardhatForkingConfig() {
return INTEGRATION_SCRATCH_DEPLOY === "on" || !MAINNET_FORKING_URL ? undefined : { url: MAINNET_FORKING_URL };
if (INTEGRATION_WITH_SCRATCH_DEPLOY === "on" || !HARDHAT_FORKING_URL) {
return undefined;
}
return { url: HARDHAT_FORKING_URL };
}

function loadAccounts(networkName: string) {
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_SCRATCH_DEPLOY === "on",
withSimpleDvtModule: process.env.INTEGRATION_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
5 changes: 2 additions & 3 deletions lib/protocol/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,5 @@ export {
report,
} from "./accounting";

export { sdvtEnsureOperators } from "./sdvt.helper";

export { norEnsureOperators } from "./nor.helper";
export { sdvtEnsureOperators } from "./sdvt";
export { norEnsureOperators } from "./nor";
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { impersonate, log, streccak, trace } from "lib";
import { ether } from "../../units";
import { ProtocolContext } from "../types";

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

const MIN_OPS_COUNT = 3n;
const MIN_OP_KEYS_COUNT = 10n;
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);
};
Loading

0 comments on commit 096a4fb

Please sign in to comment.