透過CREATE2獲得合約地址:解決交易所充值賬號問題

買賣虛擬貨幣
CREATE2 是以太坊在2019年2月28號的君士坦丁堡(Constantinople)硬分叉[1]中引入 的一個新操作碼。根據EIP1014[2]CREATE2操作碼引入,主要是用於狀態通道,然而,我們也可以用於解決其他問題。例如,交易所需要為每個使用者提供一個以太坊地址,以便使用者可以向其充值。我們稱這些地址為“充值地址”。當代幣進入充值地址時,我們需要將其彙總到一個錢包(熱錢包)。下面我們分析一下在沒有CREATE2操作碼時,如何解決上述問題, 以及為什麼這些方案不適用。如果你只對最終結果感興趣,可以直接跳到最後一節:最終方案[3]。淘汰方案:直接使用以太坊地址最簡單的解決方案是為新使用者生成以太坊賬號地址作為使用者充值地址。需要時則在後臺用充值地址的私鑰簽名呼叫transfer()把使用者錢包歸集到交易所熱錢包。此方法具有以下優點:
· 很簡單· 將代幣從使用者充值地址轉到熱錢包的費用與呼叫transfer()的費用一樣(譯者注:這是相對於後面需要部署合約其他方案來說)然而,我們決定放棄這個方案,因為它有一個重大的缺陷:總是需要在一些地方儲存私鑰,這不僅僅是私鑰可能丟失的問題,還需要仔細管理私鑰的訪問許可權。如果其中一個私鑰被盜,那麼這個使用者的代幣就無法歸集到熱錢包。淘汰方案:為使用者建立獨立的智慧合約每個使用者建立一個單獨的智慧合約[4]並用合約地址作為使用者的充值地址,這避免了在伺服器上儲存地址的私鑰, 交易透過呼叫智慧合約進行代幣歸集。不過我們依舊沒有選擇這個方案,因為在部署合約之前使用者沒有辦法顯示充值地址(實際上是可能的,但是會非常複雜,並且還有一些其他缺陷)。在交易所中,使用者應該可以建立任意多的賬號,這意味著需要在合約部署上浪費資金,並且還不能確認使用者是否會使用這個賬號。
改進:使用CREATE2 操作碼預計算合約地址為了解決上一節沒有辦法顯示充值地址的問題,我們決定使用 CREATE2 操作碼,它允許我們提前計算出要部署的合約地址,地址計算公式如下:keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]說明:● address— 呼叫CREATE2的智慧合約的地址● salt— 隨機數
● init_code— 要部署合約的位元組碼因此,可以保證提供給使用者的合約地址中包含了期望的合約位元組碼。此外,合約可以在需要的時候才部署。例如,當使用者決定使用錢包時。更進一步,可以隨時計算出合約的地址而無需儲存地址,因為公式中的:address:是個常量,它是部署錢包的工廠合約地址salt:使用user_id的雜湊init_code:也是個常量,因為總是部署相同合約
繼續改進上面的解決方案仍然有一個缺陷:交易所需要付費部署智慧合約。但是,這是可以避免的。可以在合約建構函式中呼叫transfer()函式,然後呼叫selfdestruct()。這將退還部署智慧合約部分的gas。與常見錯誤認識相反,其實你可以使用CREATE2操作碼在同一地址多次部署智慧合約。這是因為CREATE2檢查目標地址的 nonce 是否為零(它會在建構函式的開頭將其設定為1)。在這種情況下,selfdestruct()函式每次都會重置地址的 nonce。因此,如果再次使用相同的引數呼叫CREATE2建立合約,對nonce的檢查是可以透過的。這個解決方案類似於使用以太坊地址的方案,但是無需儲存私鑰。因為我們不支付智慧合約部署費用,所以將錢從充值地址到熱錢包的成本大約等於呼叫transfer()函式的成本。最終方案初始準備:● 透過user_id獲取隨機值(salt)的函式
● 呼叫CREATE2操作碼(使用適當的隨機數)的智慧合約● 具有如下建構函式的充值錢包合約的位元組碼:constructor () {    address hotWallet = 0x …;    address token = 0x …;    token.transfer (hotWallet, token.balanceOf (address(this)));
    selfdestruct (address (0));}對於每個新使用者,我們透過下面的公式計算其充值錢包地址:keccak256 (0xff ++ fabric_addr ++ hash (user_id) ++ keccak256 (wallet_init_code)) [12:]當使用者將代幣轉入其充值錢包地址時,後臺系統會監控到 Transfer事件,並且目標引數( _to )是充值地址。此時,在實際部署充值錢包合約前,已經可以增加使用者在交易所的餘額了。當使用者充值錢包中累積了足夠的代幣時,我們就可以將所有幣一次性轉入平臺熱錢包。為此,後臺呼叫工廠合約的如下方法:
function deployWallet (uint256 salt) {    bytes memory walletBytecode = …;    // 用充值錢包合約的位元組碼及 salt 呼叫 CREATE2 }此時充值錢包智慧合約的建構函式被呼叫,這會將所有代幣轉入熱錢包然後自動銷燬。以下是完整程式碼:
// Note that this is not the production codepragma solidity 0.5.6;import "./IERC20.sol";contract Wallet {    address internal token = 0x123...<hot_wallet_addr>;    address internal hotWallet = 0x321...<hot_wallet_addr>;
    constructor() public {        // send all tokens from this contract to hotwallet        IERC20(token).transfer(            hotWallet,            IERC20(token).balanceOf(address(this))        );
        // selfdestruct to receive gas refund and reset nonce to 0        selfdestruct(address(0x0));    }}contract Fabric {    function createContract(uint256 salt) public {
        // get wallet init_code        bytes memory bytecode = type(Wallet).creationCode;        assembly {            let codeSize := mload(bytecode) // get size of init_bytecode            let newAddr := create2(                0, // 0 wei
                add(bytecode, 32), // the bytecode itself starts at the second slot. The first slot contains array length                codeSize, // size of init_code                salt // salt from function arguments            )        }    }
}.注意,這不是我們的生產環境程式碼,因為我們還要最佳化錢包合約的位元組碼,並且使用操作碼編寫了。原文[5]由 SmartDec[6] 創作,專門從事靜態程式碼分析,反編譯和安全開發的安全團隊。本翻譯得到登鏈社羣[7]及 CellNetwork[8] 支援。參考資料[1]君士坦丁堡(Constantinople)硬分叉: https://learnblockchain.cn/2019/06/15/eth-history1#%E5%A4%A7%E9%83%BD%E4%BC%9A-%E5%90%9B%E5%A3%AB%E5%9D%A6%E4%B8%81%E5%A0%A1-Constantinople-%E7%A1%AC%E5%88%86%E5%8F%89--2019%E5%B9%B42%E6%9C%8828%E6%97%A5[2]EIP1014: https://learnblockchain.cn/docs/eips/eip-1014.html
[3]最終方案: #最終方案[4]智慧合約: https://learnblockchain.cn/2018/01/04/understanding-smart-contracts[5]原文: https://blog.smartdec.net/how-to-define-smart-contract-address-before-the-deploy-create2-use-case-for-decentralized-exchange-52b7daa7873b[6]SmartDec: https://www.smartcontracts.smartdec.net/[7]登鏈社羣: https://learnblockchain.cn/[8]CellNetwork: https://www.cellnetwork.io/?utm_souce=learnblockchain

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;