diff --git a/contracts/0.4.24/Lido.sol b/contracts/0.4.24/Lido.sol index ada9e651d..f8c975b42 100644 --- a/contracts/0.4.24/Lido.sol +++ b/contracts/0.4.24/Lido.sol @@ -210,17 +210,9 @@ contract Lido is Versioned, StETHPermit, AragonApp { onlyInit { _bootstrapInitialHolder(); - _initialize_v2(_lidoLocator, _eip712StETH); - initialized(); - } - - /** - * initializer for the Lido version "2" - */ - function _initialize_v2(address _lidoLocator, address _eip712StETH) internal { - _setContractVersion(2); LIDO_LOCATOR_POSITION.setStorageAddress(_lidoLocator); + emit LidoLocatorSet(_lidoLocator); _initializeEIP712StETH(_eip712StETH); // set infinite allowance for burner from withdrawal queue @@ -231,27 +223,27 @@ contract Lido is Versioned, StETHPermit, AragonApp { INFINITE_ALLOWANCE ); - emit LidoLocatorSet(_lidoLocator); + _initialize_v3(); + initialized(); } /** - * @notice A function to finalize upgrade to v2 (from v1). Can be called only once - * @dev Value "1" in CONTRACT_VERSION_POSITION is skipped due to change in numbering - * - * The initial protocol token holder must exist. + * @notice A function to finalize upgrade to v3 (from v2). Can be called only once * * For more details see https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-10.md */ - function finalizeUpgrade_v2(address _lidoLocator, address _eip712StETH) external { - _checkContractVersion(0); + function finalizeUpgrade_v3() external { require(hasInitialized(), "NOT_INITIALIZED"); + _checkContractVersion(2); - require(_lidoLocator != address(0), "LIDO_LOCATOR_ZERO_ADDRESS"); - require(_eip712StETH != address(0), "EIP712_STETH_ZERO_ADDRESS"); - - require(_sharesOf(INITIAL_TOKEN_HOLDER) != 0, "INITIAL_HOLDER_EXISTS"); + _initialize_v3(); + } - _initialize_v2(_lidoLocator, _eip712StETH); + /** + * initializer for the Lido version "3" + */ + function _initialize_v3() internal { + _setContractVersion(3); } /** diff --git a/test/0.4.24/contracts/Lido__HarnessForFinalizeUpgradeV2.sol b/test/0.4.24/contracts/Lido__HarnessForFinalizeUpgradeV2.sol index e928f1374..2035eecc8 100644 --- a/test/0.4.24/contracts/Lido__HarnessForFinalizeUpgradeV2.sol +++ b/test/0.4.24/contracts/Lido__HarnessForFinalizeUpgradeV2.sol @@ -5,19 +5,8 @@ pragma solidity 0.4.24; import {Lido} from "contracts/0.4.24/Lido.sol"; -contract Lido__HarnessForFinalizeUpgradeV2 is Lido { - function harness__initialize(uint256 _initialVersion) external payable { - assert(address(this).balance != 0); - _bootstrapInitialHolder(); - _setContractVersion(_initialVersion); - initialized(); - } - - function harness__mintSharesWithoutChecks(address account, uint256 amount) external returns (uint256) { - return super._mintShares(account, amount); - } - - function harness__burnInitialHoldersShares() external returns (uint256) { - return super._burnShares(INITIAL_TOKEN_HOLDER, _sharesOf(INITIAL_TOKEN_HOLDER)); +contract Lido__HarnessForFinalizeUpgradeV3 is Lido { + function harness_setContractVersion(uint256 _version) external { + _setContractVersion(_version); } } diff --git a/test/0.4.24/lido/lido.finalizeUpgrade_v2.test.ts b/test/0.4.24/lido/lido.finalizeUpgrade_v2.test.ts deleted file mode 100644 index 61bddfa85..000000000 --- a/test/0.4.24/lido/lido.finalizeUpgrade_v2.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { expect } from "chai"; -import { MaxUint256, ZeroAddress } from "ethers"; -import { ethers } from "hardhat"; - -import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; -import { time } from "@nomicfoundation/hardhat-network-helpers"; - -import { Lido__HarnessForFinalizeUpgradeV2, LidoLocator } from "typechain-types"; - -import { certainAddress, INITIAL_STETH_HOLDER, ONE_ETHER, proxify } from "lib"; - -import { deployLidoLocator } from "test/deploy"; -import { Snapshot } from "test/suite"; - -describe("Lido.sol:finalizeUpgrade_v2", () => { - let deployer: HardhatEthersSigner; - let user: HardhatEthersSigner; - - let impl: Lido__HarnessForFinalizeUpgradeV2; - let lido: Lido__HarnessForFinalizeUpgradeV2; - let locator: LidoLocator; - - const initialValue = 1n; - const initialVersion = 0n; - const finalizeVersion = 2n; - - let withdrawalQueueAddress: string; - let burnerAddress: string; - const eip712helperAddress = certainAddress("lido:initialize:eip712helper"); - - let originalState: string; - - before(async () => { - [deployer, user] = await ethers.getSigners(); - impl = await ethers.deployContract("Lido__HarnessForFinalizeUpgradeV2"); - [lido] = await proxify({ impl, admin: deployer }); - - locator = await deployLidoLocator(); - [withdrawalQueueAddress, burnerAddress] = await Promise.all([locator.withdrawalQueue(), locator.burner()]); - }); - - beforeEach(async () => (originalState = await Snapshot.take())); - - afterEach(async () => await Snapshot.restore(originalState)); - - it("Reverts if contract version does not equal zero", async () => { - const unexpectedVersion = 1n; - - await expect(lido.harness__initialize(unexpectedVersion, { value: initialValue })) - .to.emit(lido, "Submitted") - .withArgs(INITIAL_STETH_HOLDER, initialValue, ZeroAddress) - .and.to.emit(lido, "Transfer") - .withArgs(ZeroAddress, INITIAL_STETH_HOLDER, initialValue) - .and.to.emit(lido, "TransferShares") - .withArgs(ZeroAddress, INITIAL_STETH_HOLDER, initialValue) - .and.to.emit(lido, "ContractVersionSet") - .withArgs(unexpectedVersion); - - await expect(lido.finalizeUpgrade_v2(ZeroAddress, eip712helperAddress)).to.be.reverted; - }); - - it("Reverts if not initialized", async () => { - await expect(lido.finalizeUpgrade_v2(locator, eip712helperAddress)).to.be.revertedWith("NOT_INITIALIZED"); - }); - - context("contractVersion equals 0", () => { - before(async () => { - const latestBlock = BigInt(await time.latestBlock()); - - await expect(lido.harness__initialize(initialVersion, { value: initialValue })) - .to.emit(lido, "Submitted") - .withArgs(INITIAL_STETH_HOLDER, initialValue, ZeroAddress) - .and.to.emit(lido, "Transfer") - .withArgs(ZeroAddress, INITIAL_STETH_HOLDER, initialValue) - .and.to.emit(lido, "TransferShares") - .withArgs(ZeroAddress, INITIAL_STETH_HOLDER, initialValue) - .and.to.emit(lido, "ContractVersionSet") - .withArgs(initialVersion); - - expect(await impl.getInitializationBlock()).to.equal(MaxUint256); - expect(await lido.getInitializationBlock()).to.equal(latestBlock + 1n); - }); - - it("Reverts if Locator is zero address", async () => { - await expect(lido.finalizeUpgrade_v2(ZeroAddress, eip712helperAddress)).to.be.reverted; - }); - - it("Reverts if EIP-712 helper is zero address", async () => { - await expect(lido.finalizeUpgrade_v2(locator, ZeroAddress)).to.be.reverted; - }); - - it("Reverts if the balance of initial holder is zero", async () => { - // first get someone else's some tokens to avoid division by 0 error - await lido.harness__mintSharesWithoutChecks(user, ONE_ETHER); - // then burn initial user's tokens - await lido.harness__burnInitialHoldersShares(); - - await expect(lido.finalizeUpgrade_v2(locator, eip712helperAddress)).to.be.revertedWith("INITIAL_HOLDER_EXISTS"); - }); - - it("Bootstraps initial holder, sets the locator and EIP-712 helper", async () => { - await expect(lido.finalizeUpgrade_v2(locator, eip712helperAddress)) - .and.to.emit(lido, "ContractVersionSet") - .withArgs(finalizeVersion) - .and.to.emit(lido, "EIP712StETHInitialized") - .withArgs(eip712helperAddress) - .and.to.emit(lido, "Approval") - .withArgs(withdrawalQueueAddress, burnerAddress, MaxUint256) - .and.to.emit(lido, "LidoLocatorSet") - .withArgs(await locator.getAddress()); - - expect(await lido.getBufferedEther()).to.equal(initialValue); - expect(await lido.getLidoLocator()).to.equal(await locator.getAddress()); - expect(await lido.getEIP712StETH()).to.equal(eip712helperAddress); - expect(await lido.allowance(withdrawalQueueAddress, burnerAddress)).to.equal(MaxUint256); - }); - }); -}); diff --git a/test/0.4.24/lido/lido.finalizeUpgrade_v3.test.ts b/test/0.4.24/lido/lido.finalizeUpgrade_v3.test.ts new file mode 100644 index 000000000..62e2b06d5 --- /dev/null +++ b/test/0.4.24/lido/lido.finalizeUpgrade_v3.test.ts @@ -0,0 +1,101 @@ +import { expect } from "chai"; +import { MaxUint256, ZeroAddress } from "ethers"; +import { ethers } from "hardhat"; + +import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; +import { time } from "@nomicfoundation/hardhat-network-helpers"; + +import { Lido__HarnessForFinalizeUpgradeV3, LidoLocator } from "typechain-types"; + +import { certainAddress, INITIAL_STETH_HOLDER, proxify } from "lib"; + +import { deployLidoLocator } from "test/deploy"; +import { Snapshot } from "test/suite"; + +describe("Lido.sol:finalizeUpgrade_v3", () => { + let deployer: HardhatEthersSigner; + + let impl: Lido__HarnessForFinalizeUpgradeV3; + let lido: Lido__HarnessForFinalizeUpgradeV3; + let locator: LidoLocator; + + const initialValue = 1n; + const initialVersion = 2n; + const finalizeVersion = 3n; + + let withdrawalQueueAddress: string; + let burnerAddress: string; + const eip712helperAddress = certainAddress("lido:initialize:eip712helper"); + + let originalState: string; + + before(async () => { + [deployer] = await ethers.getSigners(); + impl = await ethers.deployContract("Lido__HarnessForFinalizeUpgradeV3"); + [lido] = await proxify({ impl, admin: deployer }); + + locator = await deployLidoLocator(); + [withdrawalQueueAddress, burnerAddress] = await Promise.all([locator.withdrawalQueue(), locator.burner()]); + }); + + beforeEach(async () => (originalState = await Snapshot.take())); + + afterEach(async () => await Snapshot.restore(originalState)); + + it("Reverts if not initialized", async () => { + await expect(lido.harness_setContractVersion(initialVersion)) + .and.to.emit(lido, "ContractVersionSet") + .withArgs(initialVersion); + + await expect(lido.finalizeUpgrade_v3()).to.be.revertedWith("NOT_INITIALIZED"); + }); + + context("initialized", () => { + before(async () => { + const latestBlock = BigInt(await time.latestBlock()); + + await expect(lido.initialize(locator, eip712helperAddress, { value: initialValue })) + .to.emit(lido, "Submitted") + .withArgs(INITIAL_STETH_HOLDER, initialValue, ZeroAddress) + .and.to.emit(lido, "Transfer") + .withArgs(ZeroAddress, INITIAL_STETH_HOLDER, initialValue) + .and.to.emit(lido, "TransferShares") + .withArgs(ZeroAddress, INITIAL_STETH_HOLDER, initialValue) + .and.to.emit(lido, "ContractVersionSet") + .withArgs(finalizeVersion) + .and.to.emit(lido, "EIP712StETHInitialized") + .withArgs(eip712helperAddress) + .and.to.emit(lido, "Approval") + .withArgs(withdrawalQueueAddress, burnerAddress, MaxUint256) + .and.to.emit(lido, "LidoLocatorSet") + .withArgs(await locator.getAddress()); + + expect(await impl.getInitializationBlock()).to.equal(MaxUint256); + expect(await lido.getInitializationBlock()).to.equal(latestBlock + 1n); + }); + + it("Reverts if initialized from scratch", async () => { + await expect(lido.finalizeUpgrade_v3()).to.be.reverted; + }); + + it("Reverts if contract version does not equal 2", async () => { + const unexpectedVersion = 1n; + + await expect(lido.harness_setContractVersion(unexpectedVersion)) + .and.to.emit(lido, "ContractVersionSet") + .withArgs(unexpectedVersion); + + await expect(lido.finalizeUpgrade_v3()).to.be.reverted; + }); + + it("Sets contract version to 3", async () => { + await expect(lido.harness_setContractVersion(initialVersion)) + .and.to.emit(lido, "ContractVersionSet") + .withArgs(initialVersion); + + await expect(lido.finalizeUpgrade_v3()).and.to.emit(lido, "ContractVersionSet").withArgs(finalizeVersion); + + expect(await lido.getContractVersion()).to.equal(finalizeVersion); + }); + }); +}); diff --git a/test/0.4.24/lido/lido.initialize.test.ts b/test/0.4.24/lido/lido.initialize.test.ts index ad949dd8a..2d8cd43a2 100644 --- a/test/0.4.24/lido/lido.initialize.test.ts +++ b/test/0.4.24/lido/lido.initialize.test.ts @@ -33,7 +33,7 @@ describe("Lido.sol:initialize", () => { context("initialize", () => { const initialValue = 1n; - const contractVersion = 2n; + const contractVersion = 3n; let withdrawalQueueAddress: string; let burnerAddress: string; @@ -86,6 +86,7 @@ describe("Lido.sol:initialize", () => { expect(await lido.getEIP712StETH()).to.equal(eip712helperAddress); expect(await lido.allowance(withdrawalQueueAddress, burnerAddress)).to.equal(MaxUint256); expect(await lido.getInitializationBlock()).to.equal(latestBlock + 1n); + expect(await lido.getContractVersion()).to.equal(contractVersion); }); it("Does not bootstrap initial holder if total shares is not zero", async () => {