國慶長假快進尾聲蜗巧,今天把GUSD的合約代碼仔細看了,得出一個非常驚人的結論:
GUSD已經(jīng)拋棄了Custodian
第三方托管合約蕾盯,變成由Gemini自由控制的中心化的增發(fā)工具幕屹。
通過仔細閱讀GUSD復雜的合約,筆者發(fā)現(xiàn)级遭,GUSD的主合約:ERC20Impl
合約的custodian
(托管賬戶)從原先的Custodian
合約變成了PrintingLimiter
合約望拖,導致增發(fā)等重要的操作可以不受Custodian
合約控制,無需第三方托管賬戶操作挫鸽。
事實上说敏,GUSD的Custodian
合約有史以來只操作了4次,見:https://etherscan.io/address/0x9a7b5f6e453d0cda978163cb4a9a88367250a52d
每次只是授權了confirmImplChange
方法(該方法的Method Id為0x8181b029
)
下面丢郊,我們來進一步查看究竟GUSD是如何實現(xiàn)增發(fā)的盔沫。
首先,我們來看該代幣地址:https://etherscan.io/token/0x056fd409e1d7a124bd7017459dfea2f387b6d5cd
顯示余額為:957525.96
GUSD(2018年10月6日16點左右)
在列表中隨意找一個From
為0x0000...
的Tx交易記錄枫匾,點擊后架诞,查看交易詳情:
https://etherscan.io/tx/0xd204a0e54d63a27de84074d48491016892a933ddce9cf7debf36747f1af96460。
可以看出干茉,該幣交易增發(fā)了157,882.70
個GUSD谴忧。
通過查詢交易的Event Logs
,可以看出,這筆交易完成后收到了三個事件:
-
ERC20Impl
合約的requestPrint
方法沾谓,發(fā)送PrintingLocked
事件委造; -
ERC20Impl
合約的confirmPrint
方法,發(fā)送PrintingConfirmed
事件均驶; -
ERC20Proxy
合約的發(fā)送代幣争涌,并釋放Transfer
事件。
而以上事件全部是由PrintLimiter
合約中的limitedPrint
方法統(tǒng)一控制的辣恋。
在PrintLimiter
合約中找到limitedPrint
函數(shù),源碼如下:
function limitedPrint(address _receiver, uint256 _value) public onlyLimitedPrinter {
uint256 totalSupply = erc20Impl.totalSupply();
uint256 newTotalSupply = totalSupply + _value;
require(newTotalSupply >= totalSupply);
require(newTotalSupply <= totalSupplyCeiling);
erc20Impl.confirmPrint(erc20Impl.requestPrint(_receiver, _value));
}
看最后一句erc20Impl.confirmPrint(erc20Impl.requestPrint(_receiver, _value));
模软,是指擁有增發(fā)權限的用戶伟骨,直接從requestPrint()
方法中獲取lockId
,并交給confirmPrint()
方法作為參數(shù)燃异,確認其增發(fā)行為携狭。
按道理,應該在提出增發(fā)申請回俐,即requestPrint()
后逛腿,由資金托管方Custodian
進行多簽授權,然后執(zhí)行確認增發(fā)命令仅颇,即confirmPrint()
单默。但實際上,這里全部省略了忘瓦。
我們再來看看到底誰擁有增發(fā)權限的賬戶呢搁廓?也即是上面代碼中的modifier
方法onlyLimitedPrinter
中的條件到底是什么?
看代碼:
modifier onlyLimitedPrinter {
require(msg.sender == limitedPrinter);
_;
}
即只要發(fā)送改指令的以太坊賬號msg.sender
等于limitedPrinter
就行了耕皮,而limitedPrinter
是在部署PrintLimiter
合約時的構造函數(shù)中設定的境蜕。因此,只要部署該合約時指定某個以太坊賬戶擁有增發(fā)權限即可凌停。
那么粱年,究竟誰是擁有這個增發(fā)權限的超級賬號呢?
我們通過查詢前面的交易記錄:https://etherscan.io/tx/0xd204a0e54d63a27de84074d48491016892a933ddce9cf7debf36747f1af96460
找到From
賬戶罚拟,就是給合約發(fā)送指令的msg.sender
的地址:0xd24400ae8bfebb18ca49be86258a3c749cf46853
台诗。
那這個地址又是什么呢?
讓我們打開ERC20Impl
合約的詳情:https://etherscan.io/address/0x6704ba24b8640BCcEe6BF2fd276a6a1b8EdF4Ade#readContract
可以發(fā)現(xiàn)舟舒,以上地址就是sweeper
拉庶。
查看ERC20Impl
合約的構造函數(shù)可以發(fā)現(xiàn),這個sweeper
地址是在部署ERC20Impl
合約時設定的參數(shù)秃励。通過etherscan.io
查詢氏仗,發(fā)現(xiàn)這個地址就是Gemini
交易所地址。
由此,一個看似復雜皆尔,公平呐舔,受第三方監(jiān)管的穩(wěn)定幣GUSD
,其實增發(fā)完全被一個交易所賬戶控制著慷蠕。增發(fā)過程很容易珊拼,只要執(zhí)行PrintLimiter
合約中的limitedPrint
方法即可。所謂的托管方Custodian
只是一個幌子罷了流炕。
那么澎现,GUSD的所有代碼是不是都是擺設呢?也不是每辟,在Custodian
合約中剑辫,已經(jīng)把所有邏輯寫的很清楚了。其基本邏輯是:
如果某人需要執(zhí)行某個更改(如增發(fā))渠欺,首先需要提出一個申請妹蔽,獲取lockId
,然后第三方監(jiān)管機構執(zhí)行Custodian
合約中的requestUnlock
函數(shù)挠将,提出解鎖申請胳岂。第三方監(jiān)管機構中有權限的幾個賬戶中的兩個對該申請審核,然后通過多簽舔稀,確定是否批準解鎖乳丰。如果批準,則執(zhí)行人擁有執(zhí)行該方法的權限(如增發(fā))镶蹋。
以上邏輯成艘,其實建立了一套:發(fā)行-監(jiān)管
的模式,該模式適用于幾乎所有金融應用場景贺归。
根據(jù)筆者對GUSD合約的理解淆两,只要將上面的limitPrint
方法的modifier
方法改為onlyCustodian
即可實現(xiàn)增發(fā)行為的第三方監(jiān)管,如下:
function limitedPrint(address _receiver, uint256 _value) public onlyCustodian {
uint256 totalSupply = erc20Impl.totalSupply();
uint256 newTotalSupply = totalSupply + _value;
require(newTotalSupply >= totalSupply);
require(newTotalSupply <= totalSupplyCeiling);
erc20Impl.confirmPrint(erc20Impl.requestPrint(_receiver, _value));
}