diff --git a/.env.example b/.env.example index 5dcda8f6b..6d126f4e1 100644 --- a/.env.example +++ b/.env.example @@ -21,6 +21,8 @@ LOCAL_STAKING_ROUTER_ADDRESS= LOCAL_VALIDATORS_EXIT_BUS_ORACLE_ADDRESS= LOCAL_WITHDRAWAL_QUEUE_ADDRESS= LOCAL_WITHDRAWAL_VAULT_ADDRESS= +LOCAL_STAKING_VAULT_FACTORY_ADDRESS= +LOCAL_STAKING_VAULT_BEACON_ADDRESS= # RPC URL for a separate, non Hardhat Network node (Anvil, Infura, Alchemy, etc.) MAINNET_RPC_URL=http://localhost:8545 @@ -46,6 +48,8 @@ MAINNET_STAKING_ROUTER_ADDRESS= MAINNET_VALIDATORS_EXIT_BUS_ORACLE_ADDRESS= MAINNET_WITHDRAWAL_QUEUE_ADDRESS= MAINNET_WITHDRAWAL_VAULT_ADDRESS= +MAINNET_STAKING_VAULT_FACTORY_ADDRESS= +MAINNET_STAKING_VAULT_BEACON_ADDRESS= HOLESKY_RPC_URL= SEPOLIA_RPC_URL= diff --git a/lib/proxy.ts b/lib/proxy.ts index 52a77123e..fafffca39 100644 --- a/lib/proxy.ts +++ b/lib/proxy.ts @@ -15,7 +15,6 @@ import { import { findEventsWithInterfaces } from "lib"; import { IDelegation } from "../typechain-types/contracts/0.8.25/vaults/VaultFactory.sol/VaultFactory"; -import DelegationInitializationParamsStruct = IDelegation.InitialStateStruct; interface ProxifyArgs { impl: T; @@ -48,26 +47,14 @@ interface CreateVaultResponse { } export async function createVaultProxy( + caller: HardhatEthersSigner, vaultFactory: VaultFactory, - _admin: HardhatEthersSigner, - _owner: HardhatEthersSigner, - _operator: HardhatEthersSigner, - initializationParams: Partial = {}, + delegationParams: IDelegation.InitialStateStruct, + stakingVaultInitializerExtraParams: BytesLike = "0x", ): Promise { - // Define the parameters for the struct - const defaultParams: DelegationInitializationParamsStruct = { - defaultAdmin: await _admin.getAddress(), - curator: await _owner.getAddress(), - funderWithdrawer: await _owner.getAddress(), - minterBurner: await _owner.getAddress(), - nodeOperatorManager: await _operator.getAddress(), - nodeOperatorFeeClaimer: await _owner.getAddress(), - curatorFeeBP: 100n, - nodeOperatorFeeBP: 200n, - }; - const params = { ...defaultParams, ...initializationParams }; - - const tx = await vaultFactory.connect(_owner).createVaultWithDelegation(params, "0x"); + const tx = await vaultFactory + .connect(caller) + .createVaultWithDelegation(delegationParams, stakingVaultInitializerExtraParams); // Get the receipt manually const receipt = (await tx.wait())!; @@ -84,9 +71,9 @@ export async function createVaultProxy( const { delegation: delegationAddress } = delegationEvents[0].args; - const proxy = (await ethers.getContractAt("BeaconProxy", vault, _owner)) as BeaconProxy; - const stakingVault = (await ethers.getContractAt("StakingVault", vault, _owner)) as StakingVault; - const delegation = (await ethers.getContractAt("Delegation", delegationAddress, _owner)) as Delegation; + const proxy = (await ethers.getContractAt("BeaconProxy", vault, caller)) as BeaconProxy; + const stakingVault = (await ethers.getContractAt("StakingVault", vault, caller)) as StakingVault; + const delegation = (await ethers.getContractAt("Delegation", delegationAddress, caller)) as Delegation; return { tx, diff --git a/test/0.8.25/vaults/vaultFactory.test.ts b/test/0.8.25/vaults/vaultFactory.test.ts index 765946c65..7d187d28f 100644 --- a/test/0.8.25/vaults/vaultFactory.test.ts +++ b/test/0.8.25/vaults/vaultFactory.test.ts @@ -25,6 +25,8 @@ import { createVaultProxy, ether } from "lib"; import { deployLidoLocator } from "test/deploy"; import { Snapshot } from "test/suite"; +import { IDelegation } from "../../../typechain-types/contracts/0.8.25/vaults/VaultFactory.sol/VaultFactory"; + describe("VaultFactory.sol", () => { let deployer: HardhatEthersSigner; let admin: HardhatEthersSigner; @@ -55,6 +57,8 @@ describe("VaultFactory.sol", () => { let originalState: string; + let delegationParams: IDelegation.InitialStateStruct; + before(async () => { [deployer, admin, holder, operator, stranger, vaultOwner1, vaultOwner2] = await ethers.getSigners(); @@ -98,14 +102,23 @@ describe("VaultFactory.sol", () => { implOld, "InvalidInitialization", ); + + delegationParams = { + defaultAdmin: await admin.getAddress(), + curator: await vaultOwner1.getAddress(), + minterBurner: await vaultOwner1.getAddress(), + funderWithdrawer: await vaultOwner1.getAddress(), + nodeOperatorManager: await operator.getAddress(), + nodeOperatorFeeClaimer: await vaultOwner1.getAddress(), + curatorFeeBP: 100n, + nodeOperatorFeeBP: 200n, + }; }); beforeEach(async () => (originalState = await Snapshot.take())); afterEach(async () => await Snapshot.restore(originalState)); - context("beacon.constructor", () => {}); - context("constructor", () => { it("reverts if `_owner` is zero address", async () => { await expect(ethers.deployContract("UpgradeableBeacon", [ZeroAddress, admin], { from: deployer })) @@ -131,12 +144,6 @@ describe("VaultFactory.sol", () => { }); it("works and emit `OwnershipTransferred`, `Upgraded` events", async () => { - // const beacon = await ethers.deployContract( - // "VaultFactory", - // [await implOld.getAddress(), await steth.getAddress()], - // { from: deployer }, - // ); - const tx = beacon.deploymentTransaction(); await expect(tx) @@ -150,17 +157,21 @@ describe("VaultFactory.sol", () => { context("createVaultWithDelegation", () => { it("reverts if `curator` is zero address", async () => { - await expect( - createVaultProxy(vaultFactory, admin, vaultOwner1, operator, { - curator: ZeroAddress, - }), - ) + const params = { ...delegationParams, curator: ZeroAddress }; + await expect(createVaultProxy(vaultOwner1, vaultFactory, params)) .to.revertedWithCustomError(vaultFactory, "ZeroArgument") .withArgs("curator"); }); it("works with empty `params`", async () => { - const { tx, vault, delegation: delegation_ } = await createVaultProxy(vaultFactory, admin, vaultOwner1, operator); + console.log({ + delegationParams, + }); + const { + tx, + vault, + delegation: delegation_, + } = await createVaultProxy(vaultOwner1, vaultFactory, delegationParams); await expect(tx) .to.emit(vaultFactory, "VaultCreated") @@ -174,15 +185,12 @@ describe("VaultFactory.sol", () => { }); it("check `version()`", async () => { - const { vault } = await createVaultProxy(vaultFactory, admin, vaultOwner1, operator); + const { vault } = await createVaultProxy(vaultOwner1, vaultFactory, delegationParams); expect(await vault.version()).to.eq(1); }); - - it.skip("works with non-empty `params`", async () => {}); }); context("connect", () => { - it("create vault ", async () => {}); it("connect ", async () => { const vaultsBefore = await accounting.vaultsCount(); expect(vaultsBefore).to.eq(0); @@ -202,16 +210,14 @@ describe("VaultFactory.sol", () => { //create vaults const { vault: vault1, delegation: delegator1 } = await createVaultProxy( - vaultFactory, - admin, vaultOwner1, - operator, + vaultFactory, + delegationParams, ); const { vault: vault2, delegation: delegator2 } = await createVaultProxy( - vaultFactory, - admin, vaultOwner2, - operator, + vaultFactory, + delegationParams, ); //owner of vault is delegator @@ -263,7 +269,7 @@ describe("VaultFactory.sol", () => { expect(implAfter).to.eq(await implNew.getAddress()); //create new vault with new implementation - const { vault: vault3 } = await createVaultProxy(vaultFactory, admin, vaultOwner1, operator); + const { vault: vault3 } = await createVaultProxy(vaultOwner1, vaultFactory, delegationParams); //we upgrade implementation - we do not check implementation, just proxy bytecode await expect( @@ -317,7 +323,7 @@ describe("VaultFactory.sol", () => { context("After upgrade", () => { it("exists vaults - init not works, finalize works ", async () => { - const { vault: vault1 } = await createVaultProxy(vaultFactory, admin, vaultOwner1, operator); + const { vault: vault1 } = await createVaultProxy(vaultOwner1, vaultFactory, delegationParams); await beacon.connect(admin).upgradeTo(implNew); @@ -333,7 +339,7 @@ describe("VaultFactory.sol", () => { it("new vaults - init works, finalize not works ", async () => { await beacon.connect(admin).upgradeTo(implNew); - const { vault: vault2 } = await createVaultProxy(vaultFactory, admin, vaultOwner2, operator); + const { vault: vault2 } = await createVaultProxy(vaultOwner1, vaultFactory, delegationParams); const vault2WithNewImpl = await ethers.getContractAt("StakingVault__HarnessForTestUpgrade", vault2, deployer); diff --git a/test/integration/vaults-happy-path.integration.ts b/test/integration/vaults-happy-path.integration.ts index 7b5ba53e5..b94ac091f 100644 --- a/test/integration/vaults-happy-path.integration.ts +++ b/test/integration/vaults-happy-path.integration.ts @@ -142,14 +142,14 @@ describe("Scenario: Staking Vaults Happy Path", () => { const { stakingVaultFactory, stakingVaultBeacon } = ctx.contracts; const implAddress = await stakingVaultBeacon.implementation(); - const adminContractImplAddress = await stakingVaultFactory.DELEGATION_IMPL(); + const delegationAddress = await stakingVaultFactory.DELEGATION_IMPL(); - const vaultImpl = await ethers.getContractAt("StakingVault", implAddress); - const vaultFactoryAdminContract = await ethers.getContractAt("Delegation", adminContractImplAddress); + const _stakingVault = await ethers.getContractAt("StakingVault", implAddress); + const _delegation = await ethers.getContractAt("Delegation", delegationAddress); - expect(await vaultImpl.vaultHub()).to.equal(ctx.contracts.accounting.address); - expect(await vaultImpl.DEPOSIT_CONTRACT()).to.equal(depositContract); - expect(await vaultFactoryAdminContract.STETH()).to.equal(ctx.contracts.lido.address); + expect(await _stakingVault.vaultHub()).to.equal(ctx.contracts.accounting.address); + expect(await _stakingVault.DEPOSIT_CONTRACT()).to.equal(depositContract); + expect(await _delegation.STETH()).to.equal(ctx.contracts.lido.address); // TODO: check what else should be validated here });