GUSD白皮书解读
仔细看了遍GUSD的白皮书,把白皮书里的功能和代码结合起来分析下。
合约分离
分成几个合约,并且可以升级,有几个好处:
- 解决漏洞;
- 扩展系统新功能;
- 完善和优化系统;
- 暂停、阻止或撤销Token传输,如灾难性安全事件,或者法院或其他政府机构有法律要求时。
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));
}
发行Token
通过增加PrintLimiter实现在线和离线双重审核机制,离线Custodian可以授权PrintLimiter可以发行的数量,在这个数量内PrintLimiter指定的地址可以直接发行,超过这个数量后需要通过Custodian机制再次授权。
合约安全
- 离线Keys:高风险操作需要的Keys可以冷存储
- Key生成:硬件(HSMs)生成、存储和管理Keys
- 多重签名:高风险操作需要至少两个身份签名
- 时间锁:每个高风险操作即使批准后,也会有一段安全锁定期才会执行,可以在这安全锁定期内检测风险
- 撤销:未执行的操作可以撤销,在执行前错误和恶意行为可以被撤销。
多重签名、时间锁、撤销这些功能都在Custodian合约中实现,具体分析另见。
参考
Leave GUSD白皮书解读 to:
Read more #gusd posts
Best Posts From 老鱼
We have not curated any of chaimyu's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.