合约升级

- 1 min

设计一个可升级的合约

在处理可升级合约时,经常使用存储槽来避免存储冲突。 该库有助于在不需要内联汇编的情况下读取和写入此类插槽。

该库中的函数返回包含可用于读取或写入的“值”成员的 Slot 结构。 设置 ERC1967 实现槽的示例用法:

proxy contract

// ERC1967Proxy is Proxy, ERC1967Upgrade
// UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade
// UUPSUpgradeableMock is CountersImpl, UUPSUpgradeable
library StorageSlot{
  function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
      /// @solidity memory-safe-assembly
      assembly {
          r.slot := slot
      }
  }
}

contract ERC1967Proxy{
  // 这是EIP1967的提议,这个位置slot留给代理合约升级,编译器会避免使用这个地址
  bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

  function _setImplementation(address newImplementation) private {
      require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
      StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
  }
}