So ermitteln Sie die Adresse eines Smart Contracts vor der Bereitstellung: Verwenden von CREATE2 für einen Krypto-Austausch

Das Thema Blockchain ist nicht nur Anlass für allerlei Hype, sondern auch aus technologischer Sicht sehr wertvolle Ideen. Daher ging sie nicht an den Bewohnern der sonnigen Stadt vorbei. Die Leute schauen genau hin, studieren und versuchen, ihr Fachwissen in der traditionellen Infobase auf Blockchain-Systeme zu übertragen. Bisher punktuell: Eine der Entwicklungen von Rostelecom-Solar ist in der Lage, die Sicherheit von Software auf Basis der Blockchain zu überprüfen. Und nebenbei entstehen einige Gedanken zur Lösung angewandter Probleme der Blockchain-Community. Einen dieser Life-Hacks – wie man die Adresse eines Smart Contracts vor der Bereitstellung mithilfe von CREATE2 ermittelt – möchte ich Ihnen heute im Rahmen des Cuts vorstellen.

So ermitteln Sie die Adresse eines Smart Contracts vor der Bereitstellung: Verwenden von CREATE2 für einen Krypto-Austausch
Der CREATE2-Opcode wurde am 28. Februar dieses Jahres im Constantinople Hard Fork hinzugefügt. Wie im EIP angegeben, wurde dieser Opcode hauptsächlich für staatliche Sender eingeführt. Allerdings haben wir damit ein anderes Problem gelöst.

Es gibt Benutzer mit Guthaben an der Börse. Wir müssen jedem Benutzer eine Ethereum-Adresse zur Verfügung stellen, an die jeder Token senden und so sein Konto auffüllen kann. Nennen wir diese Adressen „Wallets“. Wenn Token in Wallets ankommen, müssen wir sie an ein einzelnes Wallet (Hotwallet) senden.

In den folgenden Abschnitten analysiere ich Optionen zur Lösung dieses Problems ohne CREATE2 und erkläre, warum wir darauf verzichtet haben. Wenn Sie nur das Endergebnis interessiert, finden Sie es im Abschnitt Endgültige Lösung.

Ethereum-Adressen

Die einfachste Lösung besteht darin, neue Ethereum-Adressen für neue Benutzer zu generieren. Diese Adressen werden die Wallets sein. Um Token vom Wallet zum Hotwallet zu übertragen, müssen Sie die Transaktion durch Aufruf der Funktion signieren Transfer() mit dem privaten Schlüssel des Wallets aus dem Backend.

Dieser Ansatz hat folgende Vorteile:

  • das ist einfach
  • Die Kosten für die Übertragung von Tokens von Wallet zu Hotwallet entsprechen den Kosten für den Aufruf der Funktion Transfer()

Wir haben diesen Ansatz jedoch aufgegeben, da er einen wesentlichen Nachteil hat: Sie müssen private Schlüssel irgendwo speichern. Und sie können nicht nur verloren gehen, sondern Sie müssen den Zugriff auf diese Schlüssel auch sorgfältig verwalten. Wenn mindestens einer von ihnen kompromittiert ist, erreichen die Token eines bestimmten Benutzers das Hot Wallet nicht.

So ermitteln Sie die Adresse eines Smart Contracts vor der Bereitstellung: Verwenden von CREATE2 für einen Krypto-Austausch

Erstellen Sie für jeden Benutzer einen separaten Smart Contract

Durch die Bereitstellung eines separaten Smart-Vertrags für jeden Benutzer können Sie private Schlüssel aus Wallets nicht auf dem Server speichern. Die Börse ruft diesen Smart Contract auf, um die Token an das Hotwallet zu übertragen.

Wir haben diese Lösung ebenfalls aufgegeben, da dem Benutzer seine Wallet-Adresse ohne den Einsatz eines Smart Contracts nicht angezeigt werden kann (dies ist tatsächlich möglich, allerdings auf ziemlich komplizierte Weise mit anderen Nachteilen, auf die wir hier nicht eingehen). Auf der Börse kann der Benutzer so viele Konten erstellen, wie er benötigt, und jeder benötigt ein eigenes Wallet. Das bedeutet, dass wir Geld für die Bereitstellung eines Vertrags ausgeben müssen, ohne überhaupt sicher zu sein, dass der Benutzer dieses Konto verwenden wird.

Opcode CREATE2

Um das Problem der vorherigen Methode zu beheben, haben wir uns für die Verwendung des CREATE2-Opcodes entschieden. Mit CREATE2 können Sie die Adresse vorab festlegen, an der der Smart Contract bereitgestellt wird. Die Adresse wird nach folgender Formel berechnet:

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


, wo:

  • Adresse – Adresse des Smart-Vertrags, der CREATE2 aufruft
  • Salz - Zufallswert
  • init_code - Smart-Contract-Bytecode für die Bereitstellung

Dadurch wird sichergestellt, dass die Adresse, die wir dem Benutzer zur Verfügung stellen, tatsächlich den gewünschten Bytecode enthält. Außerdem kann dieser intelligente Vertrag jederzeit bereitgestellt werden. Zum Beispiel, wenn sich ein Benutzer dazu entschließt, sein Wallet zum ersten Mal zu verwenden.
So ermitteln Sie die Adresse eines Smart Contracts vor der Bereitstellung: Verwenden von CREATE2 für einen Krypto-Austausch
Darüber hinaus können Sie die Smart-Contract-Adresse jedes Mal berechnen, anstatt sie zu speichern, denn:

  • Adresse in der Formel ist konstant, da es sich um die Adresse unserer Wallet-Fabrik handelt
  • Salz - Benutzer-ID-Hash
  • init_code ist dauerhaft, da wir dasselbe Wallet verwenden

Weitere Verbesserungen

Die bisherige Lösung hat immer noch einen Nachteil: Sie müssen für die Bereitstellung intelligenter Verträge bezahlen. Sie können es jedoch loswerden. Hierzu können Sie die Funktion aufrufen Transfer()und Drop Selbstzerstörung() im Wallet-Konstruktor. Und dann wird das Gas für die Bereitstellung des Smart Contracts zurückgegeben.

Entgegen der landläufigen Meinung können Sie mit dem CREATE2-Opcode einen Smart Contract mehrmals an derselben Adresse bereitstellen. Dies liegt daran, dass CREATE2 prüft, ob die Nonce der Zieladresse Null ist (ihr wird am Anfang des Konstruktors der Wert „1“ zugewiesen). Gleichzeitig ist die Funktion Selbstzerstörung() Setzt die Nonce-Adresse jedes Mal zurück. Wenn Sie also CREATE2 erneut mit denselben Argumenten aufrufen, ist die Nonce-Prüfung erfolgreich.

Bitte beachten Sie, dass diese Lösung der Ethereum-Adresslösung ähnelt, jedoch keine Speicherung privater Schlüssel erforderlich ist. Die Kosten für den Geldtransfer von einem Wallet zu einem Hotwallet entsprechen in etwa den Kosten für den Aufruf einer Funktion Transfer(), da wir nicht für die Bereitstellung des Smart Contracts zahlen.

Endgültige Entscheidung

So ermitteln Sie die Adresse eines Smart Contracts vor der Bereitstellung: Verwenden von CREATE2 für einen Krypto-Austausch

Zunächst vorbereitet:

  • Funktion zur Gewinnung von Salz user_id
  • Smart Contract, der den CREATE2-Opcode mit dem entsprechenden Salt aufruft (d. h. Wallet Factory)
  • Wallet-Bytecode entsprechend dem Vertrag mit dem folgenden Konstruktor:

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


Für jeden neuen Benutzer zeigen wir seine Wallet-Adresse durch Berechnung an

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


Wenn der Benutzer Token an die entsprechende Wallet-Adresse überträgt, sieht unser Backend das Transfer-Ereignis mit dem Parameter _zuentspricht der Wallet-Adresse. Zu diesem Zeitpunkt ist es bereits möglich, das Guthaben des Benutzers auf der Börse zu erhöhen, bevor das Wallet bereitgestellt wird.

Wenn sich in der Wallet-Adresse genügend Token angesammelt haben, können wir sie alle auf einmal auf das Hotwallet übertragen. Dazu ruft das Backend die Smart-Contract-Factory-Funktion auf, die folgende Aktionen ausführt:

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


Daher wird der Wallet-Smart-Contract-Konstruktor aufgerufen, der alle seine Token an die Hotwallet-Adresse überträgt und sich dann selbst zerstört.

Den vollständigen Code finden Sie hier hier. Bitte beachten Sie, dass dies nicht unser Produktionscode ist, da wir uns entschieden haben, den Wallet-Bytecode zu optimieren und ihn in Opcodes zu schreiben.

Autor Pavel Kondratenkov, Ethereum-Spezialist

Source: habr.com

Kommentar hinzufügen