Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add proper upgrade to version 3 in Lido #882

Merged
merged 2 commits into from
Nov 28, 2024
Merged
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
34 changes: 13 additions & 21 deletions contracts/0.4.24/Lido.sol
Original file line number Diff line number Diff line change
Expand Up @@ -209,17 +209,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 @@ -230,27 +222,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
Loading