Considerations for Upgradable Contract Solutions Based on Openzeppelin

Considerations for Upgradable Contract Solutions Based on Openzeppelin

Precautions

Constructor

Please do not use the constructor when writing an upgradeable contract . We contructor()know that the logic and data of the upgradeable contract are separated at runtime, and the contract data is stored in . The data has not been initialized, so it is invalid. Including assigning initial values ​​at declaration time is equivalent to setting those values ​​in the constructor .代理合约逻辑合约逻辑合约contructor()逻辑合约代理合约
全局变量contructor()

Parent class contract initialization

If MyContract inherits from the contract BaseContract, then the modifier (decorator) of the initialization function initialize() of the BaseContract contract must use onlyInitializing, for example:

contract BaseContract is Initializable {
    
    
    uint256 public y;

    function initialize() public onlyInitializing {
    
    
        y = 42;
    }
}
// BaseContract 继承自 Initializable,这里无需重复显式继承 Initializable
contract MyContract is BaseContract {
    
    
    int storageValue;

    // modifier(修饰器) initializer 可以确保initialize只会被调用一次
    function initialize(int initValue) public initializer {
    
    
        BaseContract.initialize();
        storageValue = initValue;
    }
    ......
}

Declare state variables

  • When declaring a state variable, it cannot be assigned an initial value

it's wrong to do it like this

contract MyContract is Initializable {
    
    
    int storageValue = 666; //初始值无效

    function initialize() public initializer {
    
    
    }
    ......
}

Because this practice is equivalent to setting these values ​​​​in the constructor contructor(), it does not apply to the upgradeable contract.

  • Defining constant state variables is still possible

like this is ok

contract MyContract is Initializable {
    
    
    // constant 常量关键字
    int public constant storageValue = 666; //有效

    function initialize() public initializer {
    
    
    }
    ......
}

Create a new contract instance in the contract code

  • Do not create a new contract instance in the contract, the created contract is not upgradeable

Like this, even though MyContract is upgradable, the ERC20 instance is not upgradable

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyContract is Initializable {
    
    
    ERC20 public token;
    
    function initialize() public initializer {
    
    
        token = new ERC20("Test", "TST"); // 这个合约是不可升级的
    }
    ......
}
  • If you want to reference other upgradeable contracts in MyContract, it is a good solution to inject the deployed upgradeable contract instance into MyContract

like this

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";

contract MyContract is Initializable {
    
    
    IERC20Upgradeable public token;

    function initialize(IERC20Upgradeable _token) public initializer {
    
    
        token = _token;
    }
    ......
}

Declare state variables when upgrading a contract

When writing a new version of a contract, whether due to a new feature or a bug fix, there is an additional restriction to respect: the order of declaration of the contract's state variables cannot be changed, nor can their type be changed.

For example, the current version (V1) contract state variable layout

contract MyContractV1 {
    
    
    uint256 private x;
    string private y;
}

So when writing a new version of the contract, please avoid the following mistakes:

  • change the type of variable

This is wrong

contract MyContractV2 {
    
    
    string private x;
    string private y;
}
  • change the order in which they are declared

This is wrong

contract MyContractV2 {
    
    
    string private y;
    uint256 private x;
}
  • Introduce a new variable before an existing variable

This is wrong

contract MyContractV2 {
    
    
    bytes private a;
    uint256 private x;
    string private y;
}

that's right

contract MyContractV2 {
    
    
    uint256 private x;
    string private y;
    bytes private a;
}
  • delete existing variable

This is wrong

contract MyContractV2 {
    
    
    string private y;
}

Reference document:
Openzeppelin writing upgradeable contracts: https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable

Guess you like

Origin blog.csdn.net/Lyon_Nee/article/details/125523306