如何在部署之前確定智能合約的地址:使用 CREATE2 進行加密貨幣交易所

區塊鍊主題不僅是各種炒作的來源,而且從技術角度來看也是非常有價值的想法。 所以,她並沒有繞過陽光城的居民。 人們正在仔細觀察、研究,試圖將他們在傳統信息庫中的專業知識轉移到區塊鏈系統上。 到目前為止,具體而言:Rostelecom-Solar 的發展之一是能夠檢查基於區塊鏈的軟件的安全性。 在此過程中,出現了一些關於解決區塊鏈社區應用問題的想法。 這些生活竅門之一——如何在部署之前使用 CREATE2 確定智能合約的地址——今天我想與大家分享一下。

如何在部署之前確定智能合約的地址:使用 CREATE2 進行加密貨幣交易所
CREATE2操作碼於今年28月XNUMX日被添加到君士坦丁堡硬分叉中。 正如 EIP 中所述,該操作碼主要是為狀態通道引入的。 然而,我們用它來解決不同的問題。

有用戶在交易所有餘額。 我們必須為每個用戶提供一個以太坊地址,任何人都可以向該地址發送代幣,從而補充他們的帳戶。 我們將這些地址稱為“錢包”。 當代幣到達錢包時,我們必須將它們發送到單個錢包(熱錢包)。

在下面的部分中,我分析了在不使用 CREATE2 的情況下解決此問題的選項,並解釋了我們放棄它們的原因。 如果您只對最終結果感興趣,可以在最終解決方案部分找到它。

以太坊地址

最簡單的解決方案是為新用戶生成新的以太坊地址。 這些地址將是錢包。 要將代幣從錢包轉移到熱錢包,您需要通過調用該函數來簽署交易 轉移() 使用後端錢包的私鑰。

這種方法有以下優點:

  • 這很簡單
  • 將代幣從錢包轉移到熱錢包的成本等於調用該函數的成本 轉移()

然而,我們放棄了這種方法,因為它有一個顯著的缺點:您需要將私鑰存儲在某處。 不僅它們可能會丟失,而且您還需要仔細管理對這些密鑰的訪問。 如果其中至少一個被洩露,那麼某個用戶的代幣將無法到達熱錢包。

如何在部署之前確定智能合約的地址:使用 CREATE2 進行加密貨幣交易所

為每個用戶創建單獨的智能合約

為每個用戶部署單獨的智能合約可以讓您不必在服務器上存儲錢包中的私鑰。 交易所將調用此智能合約將代幣轉移到熱錢包。

我們也放棄了這個解決方案,因為如果不部署智能合約,用戶就無法顯示他的錢包地址(這實際上是可能的,但方式相當複雜,還有其他缺點,我們不會在這裡討論)。 在交易所,用戶可以創建任意數量的賬戶,每個人都需要自己的錢包。 這意味著我們需要花錢部署合約,甚至不確定用戶是否會使用這個賬戶。

操作碼 CREATE2

為了解決上一個方法的問題,我們決定使用 CREATE2 操作碼。 CREATE2 允許您預先確定將部署智能合約的地址。 地址使用以下公式計算:

keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]


,其中:

  • 地址 — 將調用 CREATE2 的智能合約的地址
  • - 隨機值
  • 初始化代碼 - 用於部署的智能合約字節碼

這確保了我們提供給用戶的地址實際上包含所需的字節碼。 此外,這個智能合約可以在我們需要時部署。 例如,當用戶決定第一次使用他們的錢包時。
如何在部署之前確定智能合約的地址:使用 CREATE2 進行加密貨幣交易所
此外,您可以每次計算智能合約地址,而不是存儲它,因為:

  • 地址 公式中是常數,因為它是我們錢包工廠的地址
  • - user_id 哈希
  • 初始化代碼 是永久性的,因為我們使用同一個錢包

更多改進

之前的解決方案仍然有一個缺點:需要支付智能合約部署費用。 但是,您可以擺脫它。 為此,您可以調用該函數 轉移()然後 自我毀滅() 在錢包構造函數中。 然後部署智能合約的gas將被返還。

與普遍的看法相反,您可以使用 CREATE2 操作碼將智能合約多次部署到同一地址。 這是因為 CREATE2 檢查目標地址的隨機數是否為零(在構造函數的開頭為其分配了值“1”)。 同時,函數 自我毀滅() 每次都會重置隨機數地址。 因此,如果您使用相同的參數再次調用 CREATE2,則隨機數檢查將通過。

請注意,該解決方案類似於以太坊地址解決方案,但不需要存儲私鑰。 將錢從錢包轉移到熱錢包的成本大約等於調用函數的成本 轉移(),因為我們不支付智能合約的部署費用。

最終決定

如何在部署之前確定智能合約的地址:使用 CREATE2 進行加密貨幣交易所

初步準備:

  • 獲取鹽的函數 USER_ID
  • 智能合約將使用適當的鹽調用 CREATE2 操作碼(即錢包工廠)
  • 與具有以下構造函數的合約對應的錢包字節碼:

constructor () {
    address hotWallet = 0x…;
    address token = 0x…;
    token.transfer (hotWallet, token.balanceOf (address (this)));
    selfdestruct (address (0));
}


對於每個新用戶,我們通過計算顯示他/她的錢包地址

keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]


當用戶向對應的錢包地址轉賬時,我們的後端會看到帶有參數的Transfer事件 _到等於錢包地址。 至此,在部署錢包之前就已經可以增加用戶在交易所的餘額了。

當錢包地址中積累了足夠的代幣時,我們可以將它們一次性全部轉移到熱錢包中。 為此,後端調用智能合約工廠函數,該函數執行以下操作:

function deployWallet (соль uint256) {
    bytes memory walletBytecode =…;
    // invoke CREATE2 with wallet bytecode and salt
}


因此,調用錢包智能合約構造函數,將其所有代幣轉移到熱錢包地址,然後自毀。

完整代碼可以找到 這裡。 請注意,這不是我們的生產代碼,因為我們決定優化錢包字節碼並將其寫入操作碼中。

作者 Pavel Kondratenkov,以太坊專家

來源: www.habr.com

添加評論