Skip to content

Commit

Permalink
Add third native staking strategy (#2304)
Browse files Browse the repository at this point in the history
* Deployed proxy for third native staking strategy

* Added deploy script for third native staking strategy

* Updated deploy file of NativeStakingSSVStrategy3Proxy

* Added fork tests for 3rd Native Staking Strategy

* Update comment on how to transfer proxy governance
  • Loading branch information
naddison36 authored Nov 12, 2024
1 parent 1373a0c commit de0cf23
Show file tree
Hide file tree
Showing 5 changed files with 538 additions and 1 deletion.
18 changes: 18 additions & 0 deletions contracts/contracts/proxies/Proxies.sol
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,24 @@ contract NativeStakingFeeAccumulator2Proxy is

}

/**
* @notice NativeStakingSSVStrategy3Proxy delegates calls to NativeStakingSSVStrategy implementation
*/
contract NativeStakingSSVStrategy3Proxy is
InitializeGovernedUpgradeabilityProxy
{

}

/**
* @notice NativeStakingFeeAccumulator3Proxy delegates calls to FeeAccumulator implementation
*/
contract NativeStakingFeeAccumulator3Proxy is
InitializeGovernedUpgradeabilityProxy
{

}

/**
* @notice LidoWithdrawalStrategyProxy delegates calls to a LidoWithdrawalStrategy implementation
*/
Expand Down
218 changes: 218 additions & 0 deletions contracts/deploy/mainnet/109_3rd_native_ssv_staking.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
const { deploymentWithGovernanceProposal } = require("../../utils/deploy");
const addresses = require("../../utils/addresses");
const { isFork } = require("../../test/helpers.js");
const { impersonateAccount } = require("../../utils/signers");

module.exports = deploymentWithGovernanceProposal(
{
deployName: "109_3rd_native_ssv_staking",
forceDeploy: false,
//forceSkip: true,
reduceQueueTime: true,
deployerIsProposer: false,
// proposalId: "",
},
async ({ deployWithConfirmation, ethers, getTxOpts, withConfirmation }) => {
const { deployerAddr } = await getNamedAccounts();
const sDeployer = await ethers.provider.getSigner(deployerAddr);
console.log(`Using deployer account: ${deployerAddr}`);

// Current contracts
const cVaultProxy = await ethers.getContract("OETHVaultProxy");
const cVaultAdmin = await ethers.getContractAt(
"OETHVaultAdmin",
cVaultProxy.address
);

const cHarvesterProxy = await ethers.getContract("OETHHarvesterProxy");
const cHarvester = await ethers.getContractAt(
"OETHHarvester",
cHarvesterProxy.address
);

// Deployer Actions
// ----------------

// 1. Fetch the strategy proxy deployed by Defender Relayer
const cNativeStakingStrategyProxy = await ethers.getContract(
"NativeStakingSSVStrategy3Proxy"
);
console.log(
`Native Staking Strategy 3 Proxy: ${cNativeStakingStrategyProxy.address}`
);

// 2. Deploy the new FeeAccumulator proxy
console.log(`About to deploy FeeAccumulator proxy`);
const dFeeAccumulatorProxy = await deployWithConfirmation(
"NativeStakingFeeAccumulator3Proxy"
);
const cFeeAccumulatorProxy = await ethers.getContractAt(
"NativeStakingFeeAccumulator3Proxy",
dFeeAccumulatorProxy.address
);

// 3. Deploy the new FeeAccumulator implementation
console.log(`About to deploy FeeAccumulator implementation`);
const dFeeAccumulator = await deployWithConfirmation("FeeAccumulator", [
cNativeStakingStrategyProxy.address, // _collector
]);
const cFeeAccumulator = await ethers.getContractAt(
"FeeAccumulator",
dFeeAccumulator.address
);

// 4. Init the third FeeAccumulator proxy to point at the implementation, set the governor
console.log(`About to initialize FeeAccumulator`);
const proxyInitFunction = "initialize(address,address,bytes)";
await withConfirmation(
cFeeAccumulatorProxy.connect(sDeployer)[proxyInitFunction](
cFeeAccumulator.address, // implementation address
addresses.mainnet.Timelock, // governance
"0x", // do not call any initialize functions
await getTxOpts()
)
);

// 5. Deploy the new Native Staking Strategy implementation
console.log(`About to deploy NativeStakingSSVStrategy implementation`);
const dNativeStakingStrategyImpl = await deployWithConfirmation(
"NativeStakingSSVStrategy",
[
[addresses.zero, cVaultProxy.address], //_baseConfig
addresses.mainnet.WETH, // wethAddress
addresses.mainnet.SSV, // ssvToken
addresses.mainnet.SSVNetwork, // ssvNetwork
500, // maxValidators
dFeeAccumulatorProxy.address, // feeAccumulator
addresses.mainnet.beaconChainDepositContract, // beacon chain deposit contract
]
);
const cNativeStakingStrategyImpl = await ethers.getContractAt(
"NativeStakingSSVStrategy",
dNativeStakingStrategyImpl.address
);

const cNativeStakingStrategy = await ethers.getContractAt(
"NativeStakingSSVStrategy",
cNativeStakingStrategyProxy.address
);

// 6. Initialize Native Staking Proxy with new implementation and strategy initialization
console.log(`About to initialize NativeStakingSSVStrategy`);
const initData = cNativeStakingStrategyImpl.interface.encodeFunctionData(
"initialize(address[],address[],address[])",
[
[addresses.mainnet.WETH], // reward token addresses
/* no need to specify WETH as an asset, since we have that overriden in the "supportsAsset"
* function on the strategy
*/
[], // asset token addresses
[], // platform tokens addresses
]
);

const proxyGovernor = await cNativeStakingStrategyProxy.governor();
if (isFork && proxyGovernor != deployerAddr) {
const relayerSigner = await impersonateAccount(
addresses.mainnet.validatorRegistrator
);
await withConfirmation(
cNativeStakingStrategyProxy
.connect(relayerSigner)
.transferGovernance(deployerAddr, await getTxOpts())
);
} else {
/* Before kicking off the deploy script make sure the Defender relayer transfers the governance
* of the proxy to the deployer account that shall be deploying this script so it will be able
* to initialize the proxy contract
*
* Run the following to make it happen, and comment this error block out:
* yarn run hardhat transferGovernanceNativeStakingProxy --index 3 --deployer 0xdeployerAddress --network mainnet
*/
if (proxyGovernor != deployerAddr) {
throw new Error(
`Native Staking Strategy proxy's governor: ${proxyGovernor} does not match current deployer ${deployerAddr}`
);
}
}

// 7. Transfer governance of the Native Staking Strategy proxy to the deployer
console.log(`About to claimGovernance of NativeStakingStrategyProxy`);
await withConfirmation(
cNativeStakingStrategyProxy
.connect(sDeployer)
.claimGovernance(await getTxOpts())
);

// 8. Init the proxy to point at the implementation, set the governor, and call initialize
console.log(`About to initialize of NativeStakingStrategy2`);
await withConfirmation(
cNativeStakingStrategyProxy.connect(sDeployer)[proxyInitFunction](
cNativeStakingStrategyImpl.address, // implementation address
addresses.mainnet.Timelock, // governance
initData, // data for call to the initialize function on the strategy
await getTxOpts()
)
);

// 9. Safe approve SSV token spending
console.log(`About to safeApproveAllTokens of NativeStakingStrategy`);
await cNativeStakingStrategy.connect(sDeployer).safeApproveAllTokens();

// Governance Actions
// ----------------
return {
name: `Deploy a third OETH Native Staking Strategy.`,
actions: [
// 1. Add new strategy to vault
{
contract: cVaultAdmin,
signature: "approveStrategy(address)",
args: [cNativeStakingStrategyProxy.address],
},
// 2. configure Harvester to support the strategy
{
contract: cHarvester,
signature: "setSupportedStrategy(address,bool)",
args: [cNativeStakingStrategyProxy.address, true],
},
// 3. set harvester to the strategy
{
contract: cNativeStakingStrategy,
signature: "setHarvesterAddress(address)",
args: [cHarvesterProxy.address],
},
// 4. configure the fuse interval
{
contract: cNativeStakingStrategy,
signature: "setFuseInterval(uint256,uint256)",
args: [
ethers.utils.parseEther("21.6"),
ethers.utils.parseEther("25.6"),
],
},
// 5. set validator registrator to the Defender Relayer
{
contract: cNativeStakingStrategy,
signature: "setRegistrator(address)",
// The Defender Relayer
args: [addresses.mainnet.validatorRegistrator],
},
// 6. set staking threshold
{
contract: cNativeStakingStrategy,
signature: "setStakeETHThreshold(uint256)",
// 16 validators before the 5/8 multisig has to call resetStakeETHTally
args: [ethers.utils.parseEther("512")], // 16 * 32ETH
},
// 7. set staking monitor
{
contract: cNativeStakingStrategy,
signature: "setStakingMonitor(address)",
// The 5/8 multisig
args: [addresses.mainnet.Guardian],
},
],
};
}
);
Loading

0 comments on commit de0cf23

Please sign in to comment.