🌱
Dev Compendium
  • Ethereum
    • Solidity
      • EVM
      • Architecture
      • Execution Context
      • Transactions
      • Gas
      • Calldata, Memory & Storage
      • Gas Optimisation
      • Function Declarations
      • receive() & fallback()
      • CALL vs. DELEGATE CALL
    • Yul
      • Introduction
      • Types
      • Basic Operations
      • Storage
      • Memory
        • Arrays
        • Structs
        • Tuples, revert, keccak256
        • Logs and Events
        • Gotchas
        • abi.encode
      • Calldata
        • External Calls
        • Dynamic Length Inputs
        • Transferring Value
        • Receiving Contract Calls
      • Contracts in Yul
      • Other Yul Functions
    • Foundry
    • Security
      • Common Vulnerabilities
      • Best Practices
      • Development Workflow
      • Contract Migration
    • Auditing Tools
      • Slither
      • Mythril
      • Fuzzing
    • Upgradable Contracts
      • Upgrade Patterns
      • ERC-1967 Implementation
      • Deployment
    • MEV
    • Tooling
      • Chainlink
      • IPFS
      • Radicle
    • Frontend
      • Contract Hooks
      • Wallet Connection
        • wagmi.sh
        • Rainbow Kit
      • thirdweb
    • Protocol Research
      • Uniswap v2
      • Uniswap v3
      • Curve
      • GMX
  • Starkware
    • Fundamentals
    • Account Abstraction
    • Universal Deployer
    • Cairo 1.0
    • starknet.js
    • Security Model
  • Zero Knowledge
    • Group Theory
    • ECDSA
  • Rust
    • Basic Operations
    • Set up
    • Primitives
    • Control Flow
    • Mutability & Shadowing
    • Adding Behavior
    • Lifetimes
    • Std Library
  • SUI
    • Architecture
    • Consensus Mechanism
    • Local Node Setup
    • Sui Client CLI
    • Move Contracts
      • Move
      • Move.toml
      • Move.lock
      • Accessing Time in Sui Move
      • Set up Development Framework
      • Debug & Publish
      • Package Upgrades
      • Sui Move Library
      • Difference from Core Move
    • Object Programming
      • Object Basics
      • Using Objects
      • Immutable Objects
      • Object Wrapping
      • Dynamic Fields
      • Collections
      • Unit Testing
      • Deployment with CLI
  • NEAR
    • Architecture
    • Contract Standards
      • Fungible Token (NEP-141)
      • Non-Fungible Token (NEP-171)
      • Storage Management (NEP-145)
      • Events (NEP-297)
      • Meta-Transactions
    • Rust Contracts
      • Development Workflow
      • Smart Contract Layout
      • Storage Management
      • Events & Meta-transactions
      • Method Types
      • Upgrading Contracts
      • Unit Testing
    • NEAR Libraries
    • Environment Variables
    • Serialisation
    • Security Concepts
    • Collections
    • JS SDK
Powered by GitBook
On this page
  • Step 1: Data Recovery
  • Step 2: Data Writing
  • General Recommendations
  1. Ethereum
  2. Security

Contract Migration

PreviousDevelopment WorkflowNextAuditing Tools

Last updated 1 year ago

In attacks where private keys are compromised, it may be impossible to fix the deployed smart contract, even if the contract has an upgradability mechanism. A new instance of the contract will need to be deployed and properly initialized to restore functionality to your users.

Hence, smart contract developers should integrate a migration procedure during the contract design phase.

A migration has two steps:

  1. Recovering the data to migrate

  2. Writing the data to the new contract

Step 1: Data Recovery

Retrieval methods by data type

  • Public variables - use public getter functions

  • Private variables - use events, or compute the location in memory of the variable, then retrieve its value using: await provider.getStorageAt(address, slot)

  • Arrays - number of elements is known; use methods above

  • Mappings - keys are not stored, but are required to access mapping values. To simplify off-chain tracking, emit events when a value is stored in a mapping.

Holders and Balances

  • For token contracts, often we can find the list of all the holders by tracking the addresses of the Transfer events.

  • Once holder addresses are obtained, query the function to recover the balance associated to each holder.

Step 2: Data Writing

For simple variables, set the values through the constructor of the contract.

If there is a large amount of data that cannot be sent with one transaction, the migration has to be split into several. To do this, add an initialisation state to the contract where only the owner can change the state variables, and users can’t take any action.

To reduce the cost, the migration of the balances can be implemented with a batch transfer function that lets you set multiple accounts in a single transaction.

General Recommendations

  • Using the data separation pattern over the delegatecallproxy one. If your project has a clear abstraction separation, upgradeability using data separation will necessitate only a few adjustments. The delegatecallproxy requires EVM expertise and is highly error-prone.

  • Document the migration/upgrade procedure before the deployment. If you have to react under stress without any guidelines, you will make mistakes. Write the procedure to follow ahead of time. It should include:

    • The calls that initiate the new contracts

    • Where are stored the keys and how to access them

    • How to check the deployment! Develop and test a post-deployment script.

References:

The initialization state can be implemented with a and a boolean indicating the initialization state.

Favoring over upgradeability. Migration system have many of the same advantages than upgradeable, without their drawbacks.

balanceOf
Pausable feature
contract migration
https://blog.trailofbits.com/2018/10/29/how-contract-migration-works/