Skip to content

Commit

Permalink
Merge pull request #882 from lidofinance/fix/lido-upgrade-version
Browse files Browse the repository at this point in the history
feat: add proper upgrade to version 3 in Lido
  • Loading branch information
folkyatina authored Nov 28, 2024
2 parents 6286561 + 038e2bd commit b2b413e
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 154 deletions.
34 changes: 13 additions & 21 deletions contracts/0.4.24/Lido.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}

/**
Expand Down
17 changes: 3 additions & 14 deletions test/0.4.24/contracts/Lido__HarnessForFinalizeUpgradeV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
118 changes: 0 additions & 118 deletions test/0.4.24/lido/lido.finalizeUpgrade_v2.test.ts

This file was deleted.

101 changes: 101 additions & 0 deletions test/0.4.24/lido/lido.finalizeUpgrade_v3.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
});
3 changes: 2 additions & 1 deletion test/0.4.24/lido/lido.initialize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 () => {
Expand Down

0 comments on commit b2b413e

Please sign in to comment.