仔细看了遍GUSD的白皮书,把白皮书里的功能和代码结合起来分析下。
分成几个合约,并且可以升级,有几个好处:
Proxy调用Impl,Proxy实现ERC20的标准接口,合约内部不保存逻辑和token数据;
Impl调用Store,Impl是ERC20的真正实现,token数量等都保存在Store合约中。
合约都发布到以太坊上,虽然这三个合约一旦发布就不能修改,但是可以通过修改Proxy中指定的Impl地址,实现Impl和Store合约的更新。
实际部署图在GUSD详解中也分析过,再看下部署图:
对于高风险行为,需要离线审批。
Custodian实现了多重签名。
上图是Impl(1)被Impl(2)合约替换后的关系图,Proxy指向了Impl(2),Impl(2)调用Store,而Store也只接收Impl(2)的合约调用。
Impl(1)合约仍然存在,在GUSD系统中已经没有作用,相当于作废了。
在GUSD详解中分析过,有三个高风险操作需要通过Custodian授权,其中有一个就是升级Impl。
看看修改Impl地址的函数调用流程:
1、创建ERC20Proxy合约,而ERC20Proxy继承于ERC20ImplUpgradeable,在ERC20ImplUpgradeable构造函数中会设置erc20Impl地址为0x0
function ERC20ImplUpgradeable(address _custodian) CustodianUpgradeable(_custodian) public {
erc20Impl = ERC20Impl(0x0);
}
2、ERC20Proxy发布后,请求修改Impl的地址
function requestImplChange(address _proposedImpl) public returns (bytes32 lockId) {
require(_proposedImpl != address(0));
lockId = generateLockId();
implChangeReqs[lockId] = ImplChangeRequest({
proposedNew: _proposedImpl
});
emit ImplChangeRequested(lockId, msg.sender, _proposedImpl);
}
3、通过Custodian确认Impl的变化
function confirmImplChange(bytes32 _lockId) public onlyCustodian {
erc20Impl = getImplChangeReq(_lockId);
delete implChangeReqs[_lockId];
emit ImplChangeConfirmed(_lockId, address(erc20Impl));
}
通过增加PrintLimiter实现在线和离线双重审核机制,离线Custodian可以授权PrintLimiter可以发行的数量,在这个数量内PrintLimiter指定的地址可以直接发行,超过这个数量后需要通过Custodian机制再次授权。
多重签名、时间锁、撤销这些功能都在Custodian合约中实现,具体分析另见。