0x01.可升级的合约组成

可升级的智能合约由3个合约组成:

  • Proxy contract. 用户交互的智能合约. 它将保存数据/状态,这意味着数据存储在这个代理合同帐户的上下文中。这是一份 EIP1967 标准的Proxy合约。
  • Implementation contract. 这个合约提供函功能数和逻辑.注意data也在本合约中定义. 这是创建者正在构建的智能合约.
  • ProxyAdmin contract. 这个合约连接 Proxy and Implementation.作为你所有代理合约的owner。

部署三个合约:

  1. deploy “Implementation contract”
  2. deploy “ProxyAdmin contract”
  3. deploy “Proxy contract”

在 ProxyAdmin 合约中, Implementation and Proxy 连接在一起.

0x02.合约调用

当用户call 代理合约时, 调用将会 delegated实现 implementation contract.

当升级智能合约时,需要进行如下操作:

  1. 部署一个新的 “Implementation contract”
  2. 通过将对代理的所有调用重定向到新的实施合同来升级“ProxyAdmin合约”。

0x03.普通合约和可升级合约的区别

普通合约和可升级合约的最大区别在于可升级合约没有构造函数constructor()

在 Solidity 中,构造函数内的代码或全局变量声明的一部分不是已部署合约的运行时字节码的一部分。此代码仅在部署合约实例时执行一次。因此,逻辑合约的构造函数中的代码永远不会在代理状态的上下文中执行。换句话说,代理完全没有注意到构造函数的存在。

不过问题很容易解决。逻辑合约应该将构造函数中的代码移动到一个常规的“初始化”函数中,并在代理链接到这个逻辑合约时调用这个函数。需要特别注意这个初始化函数,使其只能被调用一次,这是一般编程中构造函数的属性之一。

这就是为什么当我们使用 OpenZeppelin Upgrades 创建代理时,您可以提供初始化函数的名称并传递参数。

为了确保initialize函数只能被调用一次,使用了一个简单的修饰符。OpenZeppelin Upgrades 通过可扩展的合约提供此功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
// contracts/MyContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
contract MyContract is Initializable{
function initialize(
address arg1,
uint256 arg2,
bytes memory arg3
) public payable initializer {
// "constructor" code...
}
}

0x04 如何判断代理合约更新了Implementation contract

在代码tab 选择More Option 再选择Is this a proxy?

他会自动找到你的逻辑合约,点击Verify


此时会弹出impiementation contract 地址