Liquid Staking

Stakelink
DeFiHardhatOracle
50,000 USDC
View results
Submission Details
Severity: medium
Invalid

Storage layout incompatibility in contract upgrades

Vulnerability Details

Stake Link has deployed CommunityVCS, OperatorVCS, StakingPool, and PriorityPool on mainnet. You can find the contract addresses in the documentation at https://docs.stake.link/resources/contracts-and-integrations. The current contest's scope includes upgraded versions of these contracts. However, an issue arises because some upgraded contracts have differences in their storage layout, which will cause storage collisions when the contracts are upgraded.

Proof of Concept

  1. Insert the test file

  2. Run a local mainnet fork hardhat node --fork <The URL of the JSON-RPC server to fork from> --fork-block-number 20897953

  3. In a separate terminal run hardhat test --grep "upgradability errors POC"

    import { HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signers'
    import { ethers, upgrades } from 'hardhat'
    describe('upgradability errors POC', () => {
    const CommunityVCS_address = '0xAc12290b097f6893322F5430627e472131fBC1B5'
    const OperatorVCS_address = '0x4852e48215A4785eE99B640CACED5378Cc39D2A4'
    const StakingPool_address = '0xb8b295df2cd735b15BE5Eb419517Aa626fc43cD5'
    const PriorityPool_address = '0xDdC796a66E8b83d0BcCD97dF33A6CcFBA8fd60eA'
    let admin: HardhatEthersSigner
    before('upgradability errors POC', async () => {
    const [signer] = await ethers.getSigners()
    admin = await ethers.getImpersonatedSigner('0xB351EC0FEaF4B99FdFD36b484d9EC90D0422493D')
    await signer.sendTransaction({
    to: admin,
    value: ethers.parseEther('1'),
    })
    })
    it('CommunityVCS', async () => await upgradeProxy(CommunityVCS_address, 'CommunityVCS'))
    it('OperatorVCS', async () => await upgradeProxy(OperatorVCS_address, 'OperatorVCS'))
    it('StakingPool', async () => await upgradeProxy(StakingPool_address, 'StakingPool'))
    it('PriorityPool', async () => await upgradeProxy(PriorityPool_address, 'PriorityPool'))
    const upgradeProxy = async (v1ContractAddress: string, v2ContractName: string) => {
    const contractV2Factory = await ethers.getContractFactory(v2ContractName, admin)
    const contractV2 = await upgrades.upgradeProxy(v1ContractAddress, contractV2Factory, {
    unsafeAllow: ['delegatecall'],
    kind: 'uups',
    })
    return contractV2
    }
    })
  4. Result:

    1) upgradability errors POC
    CommunityVCS:
    Error: New storage layout is incompatible
    VaultControllerStrategy: Deleted `indexOfLastFullVault`
    > Keep the variable even if unused
    contracts/linkStaking/base/VaultControllerStrategy.sol:347: Inserted `fundFlowController`
    > New variables should be placed after all existing inherited variables
    2) upgradability errors POC
    OperatorVCS:
    Error: New storage layout is incompatible
    VaultControllerStrategy: Deleted `indexOfLastFullVault`
    > Keep the variable even if unused
    contracts/linkStaking/base/VaultControllerStrategy.sol:347: Inserted `fundFlowController`
    > New variables should be placed after all existing inherited variables
    OperatorVCS: Deleted `preRelease`
    > Keep the variable even if unused
    3) upgradability errors POC
    StakingPool:
    Error: New storage layout is incompatible
    contracts/core/StakingPool.sol:29: Renamed `liquidityBuffer` to `unusedDepositLimit`
    contracts/core/StakingPool.sol:37: Renamed `delegatorPool` to `rebaseController`

Impact

These storage layout differences will lead to collisions, breaking the functionality of the upgraded contracts.

Tools Used

Manual Review

Recommendations

To resolve these storage layout collisions, follow the errors reported by the Hardhat tests.

Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

[INVALID]Storage layout incompatibility in contract upgrades

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.