合约的代理与升级
合约主要有3种代理模式:
一、透明代理Transparent
contract TransparentAdminUpgradeableProxy { address implementation; address admin; fallback() external payable { require(msg.sender != admin); implementation.delegatecall.value(msg.value)(msg.data); } function upgrade(address newImplementation) external { if (msg.sender != admin) fallback(); implementation = newImplementation; } }
这种模式直观好理解,代理合约负责升级,实现合约负责具体逻辑。
二、UUPS
// 代理合约
contract UUPSProxy { address implementation; fallback() external payable { implementation.delegatecall.value(msg.value)(msg.data); } }
// 实现合约要extend抽象接口 abstract contract UUPSProxiable { address implementation; address admin; function upgrade(address newImplementation) external { require(msg.sender == admin); implementation = newImplementation; } }
代理合约是空的,几乎不包含任何逻辑;实现合约既要有具体业务逻辑,还要有升级逻辑。
升级时,调用代理合约的upgrade方法, 会deletegatecall到实现合约的upgrade方法; 因为delegate实现合约会运行在代理合约的上下文中,所以实现合约的upgrade方法修改implementation属性,实际上就修改了代理合约的implementation属性。
三、钻石模式
1个代理合约,会有多份实现合约
透明代理 | UUPS | 钻石模式 | |
优点 | 容易理解 | gas费用低 | |
缺点 |
运行gas费高,每次函数调用,都要从存储中找admin 代理部署gas费高, |
新代理合约必须记得实现upgrade,否则再也无法升级 | |
openzepplin实现方式 | contract MERC1967Proxy is Proxy, ERC1967Upgrade |
参考:https://blog.openzeppelin.com/the-state-of-smart-contract-upgrades