Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 73 additions & 1 deletion script/curated/DeployBase.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pragma solidity 0.8.33;

import { Script } from "forge-std/Script.sol";

import { UpgradeableBeacon } from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";

import { HashConsensus } from "../../src/lib/base-oracle/HashConsensus.sol";
import { OssifiableProxy } from "../../src/lib/proxy/OssifiableProxy.sol";
import { CuratedModule } from "../../src/CuratedModule.sol";
Expand All @@ -19,6 +21,8 @@ import { ExitPenalties } from "../../src/ExitPenalties.sol";
import { MetaRegistry } from "../../src/MetaRegistry.sol";
import { AdditionalBondRegistry } from "../../src/AdditionalBondRegistry.sol";
import { BoostStep } from "../../src/interfaces/IAdditionalBondRegistry.sol";
import { ERC20LockBoostProvider } from "../../src/ERC20LockBoostProvider.sol";
import { LidoGovernanceLockVault } from "../../src/LidoGovernanceLockVault.sol";
import { CuratedGate } from "../../src/CuratedGate.sol";
import { MerkleGateFactory } from "../../src/MerkleGateFactory.sol";

Expand All @@ -28,6 +32,7 @@ import { BaseOracle } from "../../src/lib/base-oracle/BaseOracle.sol";
import { IVerifier } from "../../src/interfaces/IVerifier.sol";
import { IParametersRegistry } from "../../src/interfaces/IParametersRegistry.sol";
import { IBondCurve } from "../../src/interfaces/IBondCurve.sol";
import { IERC20LockBoostProvider } from "../../src/interfaces/IERC20LockBoostProvider.sol";
import { IMetaRegistry } from "../../src/interfaces/IMetaRegistry.sol";
import { IWeightBoostProvider } from "../../src/interfaces/IWeightBoostProvider.sol";

Expand Down Expand Up @@ -68,6 +73,16 @@ struct AdditionalBondRegistryConfig {
uint256[2][] boostSteps;
}

struct ERC20LockBoostProviderConfig {
address token;
address votingContract;
address snapshotDelegation;
uint256 minLockPeriod;
uint256 maxLockPeriod;
uint256 lockPeriod;
IERC20LockBoostProvider.LockBoostStep[] lockBoostSteps;
}

struct CuratedDeployParams {
// Lido addresses
address lidoLocatorAddress;
Expand Down Expand Up @@ -133,6 +148,8 @@ struct CuratedDeployParams {
address secondAdminAddress;
// AdditionalBondRegistry
AdditionalBondRegistryConfig additionalBondRegistryConfig;
// LDO lock boost provider
ERC20LockBoostProviderConfig ldoLockBoostProviderConfig;
}

abstract contract DeployBase is Script {
Expand All @@ -156,6 +173,10 @@ abstract contract DeployBase is Script {
ParametersRegistry public parametersRegistry;
MetaRegistry public metaRegistry;
AdditionalBondRegistry public additionalBondRegistry;
ERC20LockBoostProvider public ldoLockBoostProvider;
ERC20LockBoostProvider public ldoLockBoostProviderImpl;
LidoGovernanceLockVault public ldoLockVaultImpl;
UpgradeableBeacon public ldoLockVaultBeacon;
MerkleGateFactory public curatedGateFactory;
address[] public curatedGateInstances;
address internal curatedGateImpl;
Expand Down Expand Up @@ -245,6 +266,7 @@ abstract contract DeployBase is Script {
oracle = FeeOracle(_deployProxy(deployer, address(dummyImpl)));
metaRegistry = MetaRegistry(_deployProxy(deployer, address(dummyImpl)));
additionalBondRegistry = AdditionalBondRegistry(_deployProxy(deployer, address(dummyImpl)));
ldoLockBoostProvider = ERC20LockBoostProvider(_deployProxy(deployer, address(dummyImpl)));

FeeDistributor feeDistributorImpl = new FeeDistributor({
stETH: locator.lido(),
Expand Down Expand Up @@ -354,12 +376,46 @@ abstract contract DeployBase is Script {
additionalBondRegistryProxy.proxy__changeAdmin(config.proxyAdmin);
}

// LDO lock boost provider
{
ERC20LockBoostProviderConfig storage ldoConfig = config.ldoLockBoostProviderConfig;

ldoLockVaultImpl = new LidoGovernanceLockVault({
token: ldoConfig.token,
provider: address(ldoLockBoostProvider),
module: address(curatedModule),
votingContract: ldoConfig.votingContract,
snapshotDelegation_: ldoConfig.snapshotDelegation
});
ldoLockVaultBeacon = new UpgradeableBeacon(address(ldoLockVaultImpl), deployer);

ldoLockBoostProviderImpl = new ERC20LockBoostProvider({
module: address(curatedModule),
token: ldoConfig.token,
vaultBeacon: address(ldoLockVaultBeacon),
minLockPeriod: ldoConfig.minLockPeriod,
maxLockPeriod: ldoConfig.maxLockPeriod
});

OssifiableProxy ldoLockBoostProviderProxy = OssifiableProxy(payable(address(ldoLockBoostProvider)));
ldoLockBoostProviderProxy.proxy__upgradeToAndCall(
address(ldoLockBoostProviderImpl),
abi.encodeCall(ERC20LockBoostProvider.initialize, (deployer, ldoConfig.lockPeriod))
);
ldoLockBoostProviderProxy.proxy__changeAdmin(config.proxyAdmin);
}

accounting.grantRole(accounting.MANAGE_BOND_CURVES_ROLE(), address(deployer));
accounting.grantRole(accounting.SET_BOND_CURVE_MULTIPLIER_ROLE(), address(additionalBondRegistry));
metaRegistry.addWeightBoostProvider(
IWeightBoostProvider(address(additionalBondRegistry)),
IMetaRegistry.WeightBoostProviderMode.NodeOperator
IMetaRegistry.WeightBoostProviderMode.PerNodeOperator
);
metaRegistry.addWeightBoostProvider(
IWeightBoostProvider(address(ldoLockBoostProvider)),
IMetaRegistry.WeightBoostProviderMode.MaxPerGroup
);
ldoLockBoostProvider.setLockBoostSteps(config.ldoLockBoostProviderConfig.lockBoostSteps);
metaRegistry.grantRole(metaRegistry.SET_BOND_CURVE_WEIGHT_ROLE(), deployer);

for (uint256 i = 0; i < gatesCount; i++) {
Expand Down Expand Up @@ -560,6 +616,11 @@ abstract contract DeployBase is Script {
additionalBondRegistry.grantRole(additionalBondRegistry.DEFAULT_ADMIN_ROLE(), config.aragonAgent);
additionalBondRegistry.revokeRole(additionalBondRegistry.DEFAULT_ADMIN_ROLE(), deployer);

ldoLockBoostProvider.grantRole(ldoLockBoostProvider.DEFAULT_ADMIN_ROLE(), config.aragonAgent);
ldoLockBoostProvider.revokeRole(ldoLockBoostProvider.DEFAULT_ADMIN_ROLE(), deployer);

ldoLockVaultBeacon.transferOwnership(config.aragonAgent);

verifier.grantRole(verifier.DEFAULT_ADMIN_ROLE(), config.aragonAgent);
verifier.revokeRole(verifier.DEFAULT_ADMIN_ROLE(), deployer);

Expand All @@ -586,6 +647,10 @@ abstract contract DeployBase is Script {
deployJson.set("MetaRegistryImpl", address(metaRegistryImpl));
deployJson.set("AdditionalBondRegistry", address(additionalBondRegistry));
deployJson.set("AdditionalBondRegistryImpl", address(additionalBondRegistryImpl));
deployJson.set("LDOLockBoostProvider", address(ldoLockBoostProvider));
deployJson.set("LDOLockBoostProviderImpl", address(ldoLockBoostProviderImpl));
deployJson.set("LDOLockVaultImpl", address(ldoLockVaultImpl));
deployJson.set("LDOLockVaultBeacon", address(ldoLockVaultBeacon));
deployJson.set("ParametersRegistry", address(parametersRegistry));
deployJson.set("ParametersRegistryImpl", address(parametersRegistryImpl));
deployJson.set("Accounting", address(accounting));
Expand Down Expand Up @@ -654,6 +719,12 @@ abstract contract DeployBase is Script {
return gates;
}

function _addLDOLockBoostStep(uint128 minAmount, uint32 multiplierBP) internal {
config.ldoLockBoostProviderConfig.lockBoostSteps.push(
IERC20LockBoostProvider.LockBoostStep({ minAmount: minAmount, multiplierBP: multiplierBP })
);
}

function _deployProxy(address admin, address implementation) internal returns (address) {
return _deployProxy(admin, implementation, new bytes(0));
}
Expand Down Expand Up @@ -682,6 +753,7 @@ abstract contract DeployBase is Script {
parametersRegistry.grantRole(parametersRegistry.DEFAULT_ADMIN_ROLE(), config.secondAdminAddress);
metaRegistry.grantRole(metaRegistry.DEFAULT_ADMIN_ROLE(), config.secondAdminAddress);
additionalBondRegistry.grantRole(additionalBondRegistry.DEFAULT_ADMIN_ROLE(), config.secondAdminAddress);
ldoLockBoostProvider.grantRole(ldoLockBoostProvider.DEFAULT_ADMIN_ROLE(), config.secondAdminAddress);
for (uint256 i = 0; i < curatedGateInstances.length; i++) {
CuratedGate gate = CuratedGate(curatedGateInstances[i]);
gate.grantRole(gate.DEFAULT_ADMIN_ROLE(), config.secondAdminAddress);
Expand Down
10 changes: 10 additions & 0 deletions script/curated/DeployHoodi.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,16 @@ contract DeployHoodi is DeployBase {
config.additionalBondRegistryConfig.boostSteps.push([uint256(5_000), 2_000]);
config.additionalBondRegistryConfig.boostSteps.push([uint256(10_000), 8_000]);

// LDO lock boost provider
config.ldoLockBoostProviderConfig.token = 0xEf2573966D009CcEA0Fc74451dee2193564198dc;
config.ldoLockBoostProviderConfig.votingContract = 0x49B3512c44891bef83F8967d075121Bd1b07a01B;
config.ldoLockBoostProviderConfig.snapshotDelegation = address(1); // TODO: Fill in before deployment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Replace the Hoodi snapshot placeholder before deploying

In Hoodi deployments this placeholder is copied into the Lido lock vault implementation as the immutable Snapshot delegation registry address, and every vault created from that beacon will call it from assignSnapshotDelegate/unassignSnapshotDelegate. With address(1) deployed, Hoodi operators cannot actually delegate their locked LDO voting power for Snapshot without a vault implementation upgrade, so the deploy script should use the real Hoodi delegation registry or fail fast until it is known.

Useful? React with 👍 / 👎.

config.ldoLockBoostProviderConfig.minLockPeriod = 30 days;
config.ldoLockBoostProviderConfig.maxLockPeriod = 365 days;
config.ldoLockBoostProviderConfig.lockPeriod = 30 days;
_addLDOLockBoostStep(100_000 ether, 11_000);
_addLDOLockBoostStep(200_000 ether, 11_500);

_setUp();
}
}
10 changes: 10 additions & 0 deletions script/curated/DeployLocalDevNet.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,16 @@ contract DeployLocalDevNet is DeployBase {
config.additionalBondRegistryConfig.boostSteps.push([uint256(5_000), 2_000]);
config.additionalBondRegistryConfig.boostSteps.push([uint256(10_000), 8_000]);

// LDO lock boost provider
config.ldoLockBoostProviderConfig.token = vm.envAddress("CSM_LDO_TOKEN_ADDRESS");
config.ldoLockBoostProviderConfig.votingContract = vm.envAddress("CSM_LDO_VOTING_ADDRESS");
config.ldoLockBoostProviderConfig.snapshotDelegation = vm.envAddress("CSM_SNAPSHOT_DELEGATION_ADDRESS");
config.ldoLockBoostProviderConfig.minLockPeriod = 1 days;
config.ldoLockBoostProviderConfig.maxLockPeriod = 365 days;
config.ldoLockBoostProviderConfig.lockPeriod = 1 days;
_addLDOLockBoostStep(100_000 ether, 11_000);
_addLDOLockBoostStep(200_000 ether, 11_500);

_setUp();
}

Expand Down
10 changes: 10 additions & 0 deletions script/curated/DeployMainnet.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,16 @@ contract DeployMainnet is DeployBase {
config.additionalBondRegistryConfig.boostSteps.push([uint256(5_000), 2_000]);
config.additionalBondRegistryConfig.boostSteps.push([uint256(10_000), 8_000]);

// LDO lock boost provider
config.ldoLockBoostProviderConfig.token = 0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32;
config.ldoLockBoostProviderConfig.votingContract = 0x2e59A20f205bB85a89C53f1936454680651E618e;
config.ldoLockBoostProviderConfig.snapshotDelegation = 0x469788fE6E9E9681C6ebF3bF78e7Fd26Fc015446;
config.ldoLockBoostProviderConfig.minLockPeriod = 30 days;
config.ldoLockBoostProviderConfig.maxLockPeriod = 365 days;
config.ldoLockBoostProviderConfig.lockPeriod = 30 days;
_addLDOLockBoostStep(100_000 ether, 11_000);
_addLDOLockBoostStep(200_000 ether, 11_500);

_setUp();
}
}
6 changes: 3 additions & 3 deletions src/AdditionalBondRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { ICuratedModule } from "./interfaces/ICuratedModule.sol";
import { IMetaRegistry } from "./interfaces/IMetaRegistry.sol";
import { IAdditionalBondRegistry, BoostStep, PendingCurveMultiplierReduction } from "./interfaces/IAdditionalBondRegistry.sol";
import { IWeightBoostProvider } from "./interfaces/IWeightBoostProvider.sol";
import { MAX_BP } from "./lib/Constants.sol";
import { MAX_BP, MAX_EFFECTIVE_MULTIPLIER_BP } from "./lib/Constants.sol";

/// @notice Maps an operator's curve multiplier to a weight multiplier via governance-set boost steps.
contract AdditionalBondRegistry is IAdditionalBondRegistry, Initializable, AccessControlEnumerableUpgradeable {
Expand All @@ -23,8 +23,8 @@ contract AdditionalBondRegistry is IAdditionalBondRegistry, Initializable, Acces
}

// Sanity guard: effective multiplier <= 10x.
uint256 public constant MAX_CURVE_MULTIPLIER = 9 * MAX_BP;
uint256 public constant MAX_WEIGHT_MULTIPLIER = 9 * MAX_BP;
uint256 public constant MAX_CURVE_MULTIPLIER = MAX_EFFECTIVE_MULTIPLIER_BP - MAX_BP;
uint256 public constant MAX_WEIGHT_MULTIPLIER = MAX_EFFECTIVE_MULTIPLIER_BP - MAX_BP;
// Requested curve multiplier must be a multiple of this (1%).
uint256 public constant CURVE_MULTIPLIER_STEP = MAX_BP / 100;

Expand Down
Loading
Loading