由于区块链的不可篡改性,合约在部署至区块链后,其代码无法更改。
常见的情况是,当发现合约有bug,或者需要加入新功能时,则需重新发布合约,而且要将数据进行转移,同时还要通知所有用户使用新的合约地址,整个过程十分繁琐。
可升级智能合约就是为了解决以上问题。
可升级合约采用「代理 - 实现」模式,只需要更改delegatecall所指向的合约地址,就可以做到宛如修改了合约内容一样的效果。
能实现上述代理效果,理解delegatecall非常重要。
Call和delegatecall是Solidity中调用其他合约的两种方法,两者有较大区别。
当合约A使用call调用合约B时,使用的是合约B的上下文,修改的是合约B的内存插槽值。
当合约A使用delegatecall调用合约B时,使用的是合约A的上下文,修改的也是合约A的内存插槽值。
Delegatecall可以被简单理解为将合约B的代码复制粘贴到A中执行,因为只是复制粘贴,因此所有状态和数据都保存在A中。
Transparent Proxy Pattern
UUPS Proxy (Universal Upgradeable Proxy Standard)
下面的部分,首先会通过Transparent Proxy Pattern来进一步理解可升级合约的原理,接下来再指出UUPS Proxy的不同之处。
Transparent Proxy Pattern包含三个部分,「代理合约」,「管理者合约」和「逻辑/实现合约」。
代理合约:EOA是与代理合约进行交互。代理合约在收到交互请求后,通过delegatecall调用逻辑/实现合约内的程式码进行处理。由于delegatecall的特征,所有业务数据(例如合约的state和合约内的财产),都依然保存在代理合约中。
管理者合约:管理者合约是代理合约的管理员,可以对指定代理合约进行逻辑升级。
逻辑/实现合约:逻辑/实现合约包含真正的合约业务逻辑,也是我们能‘修改’的合约内容所在。同一时间代理合约只会指向一个逻辑/实现合约。
Transparent Proxy Pattern和UUPS Proxy的实现基础是一样的,都是使用delegatecall将逻辑合约剥离主合约。
两者最明显的差异是升级逻辑所在的位置:UUPS Proxy的升级逻辑是由逻辑/实现合约完成。而Transparent Proxy的升级逻辑是由代理合约完成,且需要部署额外的管理员合约。
由于UUPS Proxy的升级是由逻辑/实现合约控制,人们可以随时终止合约的可升级性。
UUPS Proxy合約的部署成本低于Transparent Proxy。
当在contract页面看到Read as Proxy和Write as Proxy两个按钮,则说明这是一个可升级合约。
如果你要执行代理合约的函数,则用原本的Read和Write。
如果你要执行逻辑/实现合约的函数,则使用Read as Proxy和Write as Proxy。
在contract name处有时也会标注出是否为代理合约,例如ERC721DropProxy,TransparentUpgradeableProxy,CErc20Delegator等。
当点击Read as Proxy/Write as Proxy,可以看到逻辑/实现合约的地址,以及该可升级合约所用的模式是什么。
最后,你也可以使用Etherscan提供的Proxy Contract Verification来查询该合约是否为可升级合约。
几个可升级合约的例子:
NFT:
https://etherscan.io/address/0x34eebee6942d8def3c125458d1a86e0a897fd6f9
https://etherscan.io/address/0x5d62fb8dcd9b480960f55956fbdd8d9f07f2b402
FT:
https://arbiscan.io/address/0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9
https://etherscan.io/address/0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9
本篇读书笔记是对以下文章的内容摘抄和观点提炼,更详细的内容可以阅读以下文章哇,尤其是具体的合约部署方法~
https://medium.com/taipei-ethereum-meetup/understand-address-and-contract-abi-28caade32e40
https://mirror.xyz/xyyme.eth/RZscMYGkeGTY8z6ccHseY8HKu-ER3pX0mFYoWXRqXQ0