GUSD白皮书解读

仔细看了遍GUSD的白皮书,把白皮书里的功能和代码结合起来分析下。

合约分离

分成几个合约,并且可以升级,有几个好处:

  1. 解决漏洞;
  2. 扩展系统新功能;
  3. 完善和优化系统;
  4. 暂停、阻止或撤销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机制再次授权。


合约安全

  1. 离线Keys:高风险操作需要的Keys可以冷存储
  2. Key生成:硬件(HSMs)生成、存储和管理Keys
  3. 多重签名:高风险操作需要至少两个身份签名
  4. 时间锁:每个高风险操作即使批准后,也会有一段安全锁定期才会执行,可以在这安全锁定期内检测风险
  5. 撤销:未执行的操作可以撤销,在执行前错误和恶意行为可以被撤销。

多重签名、时间锁、撤销这些功能都在Custodian合约中实现,具体分析另见。

参考

GUSD初览

GUSD详解

H2
H3
H4
3 columns
2 columns
1 column
Join the conversation now
Logo
Center