Das Blockchain-Thema sorgt unaufhörlich für Hype und liefert auch technologisch wertvolle Ideen. Daher ist es auch an den Bewohnern der sonnigen Stadt nicht vorbeigegangen. Man beobachtet es aufmerksam, forscht und versucht, sein Fachwissen im Bereich der traditionellen Informationssicherheit auf Blockchain-Systeme zu übertragen. Bisher nur gezielt: Eine der Entwicklungen von Rostelecom-Solar ermöglicht die Überprüfung der Sicherheit von Blockchain-basierter Software. Nebenbei entstehen auch Ideen zur Lösung angewandter Probleme der Blockchain-Community. Einen dieser Lifehacks – die Ermittlung der Adresse eines Smart Contracts vor der Bereitstellung mit CREATE2 – möchte ich heute mit Ihnen teilen.

Der CREATE2-Opcode wurde im Constantinople-Hardfork am 28. Februar dieses Jahres hinzugefügt. Wie im EIP erwähnt, wurde dieser Opcode hauptsächlich für Statuskanäle eingeführt. Wir haben ihn jedoch verwendet, um ein anderes Problem zu lösen.
Es gibt Benutzer mit Guthaben an der Börse. Wir müssen jedem Benutzer eine Ethereum-Adresse zuweisen, an die jeder Token senden und so sein Konto auffüllen kann. Nennen wir diese Adressen „Wallets“. Wenn Token in den Wallets ankommen, müssen wir sie an ein einziges Wallet (Hotwallet) senden.
In den folgenden Abschnitten analysiere ich die Möglichkeiten zur Lösung dieses Problems ohne CREATE2 und erkläre, warum wir diese verworfen haben. Wer sich nur für das Endergebnis interessiert, findet 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 als Wallets verwendet. Um Token vom Wallet zum Hotwallet zu übertragen, müssen Sie die Transaktion signieren, indem Sie die Funktion aufrufen Transfer() mit dem privaten Schlüssel des Wallets aus dem Backend.
Dieser Ansatz bietet folgende Vorteile:
- das ist einfach
- Die Kosten für die Übertragung von Token von einer Wallet zu einer Hotwallet entsprechen den Kosten für den Aufruf der Funktion Transfer()
Wir haben diesen Ansatz jedoch verworfen, da er einen großen Nachteil hat: Die privaten Schlüssel müssen irgendwo gespeichert werden. Sie können nicht nur verloren gehen, sondern der Zugriff auf diese Schlüssel muss auch sorgfältig verwaltet werden. Wenn auch nur einer davon kompromittiert wird, gelangen die Token eines bestimmten Benutzers nicht in die Hot Wallet.

Erstellen Sie für jeden Benutzer einen separaten Smart Contract
Durch die Bereitstellung eines separaten Smart Contracts für jeden Benutzer entfällt die Notwendigkeit, private Schlüssel für Wallets zu speichern. ServerDie Börse wird diesen Smart Contract aufrufen, um die Token an die Hotwallet zu übertragen.
Wir haben diese Lösung auch deshalb verworfen, weil dem Benutzer seine Wallet-Adresse ohne die Bereitstellung eines Smart Contracts nicht angezeigt werden kann (dies ist zwar möglich, aber auf recht komplizierte Weise mit weiteren Nachteilen, die wir hier nicht näher erläutern). An der Börse kann der Benutzer beliebig viele Konten erstellen, und jedes benötigt ein eigenes Wallet. Das bedeutet, dass wir Geld für die Bereitstellung eines Vertrags ausgeben müssen, auch wenn wir nicht sicher sind, dass der Benutzer dieses Konto auch nutzen wird.
Operationscode CREATE2
Um das Problem der vorherigen Methode zu lösen, haben wir uns für den Opcode CREATE2 entschieden. Mit CREATE2 können Sie die Adresse vordefinieren, an die der Smart Contract gesendet wird. Die Adresse wird nach folgender Formel berechnet:
keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]
, wo:
- Adresse — die Adresse des Smart Contracts, der CREATE2 aufruft
- Salz — Zufallswert
- init_code – Smart-Contract-Bytecode für die Bereitstellung
Dadurch wird sichergestellt, dass die dem Benutzer bereitgestellte Adresse tatsächlich den gewünschten Bytecode enthält. Darüber hinaus kann dieser Smart Contract bei Bedarf eingesetzt werden. Beispielsweise, wenn der Benutzer sein Wallet zum ersten Mal nutzt.

Darüber hinaus können Sie die Smart-Contract-Adresse jedes Mal berechnen, anstatt sie zu speichern, weil:
- Adresse in der Formel ist konstant, da dies die Adresse unserer Wallet-Fabrik ist
- Salz — user_id-Hash
- init_code ist konstant, da wir die gleiche Brieftasche verwenden
Weitere Verbesserungen
Die bisherige Lösung hat noch einen Nachteil: Sie müssen für die Bereitstellung des Smart Contracts bezahlen. Sie können dies jedoch vermeiden. Rufen Sie dazu die Funktion 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 einen Smart Contract mit dem CREATE2-Opcode mehrfach an dieselbe Adresse senden. Dies liegt daran, dass CREATE2 prüft, ob die Nonce der Zieladresse Null ist (ihr wird zu Beginn des Konstruktors der Wert „1“ zugewiesen). In diesem Fall ist die Funktion Selbstzerstörung () setzt den Nonce der Adresse jedes Mal zurück. Wenn Sie CREATE2 also erneut mit denselben Argumenten aufrufen, ist die Nonce-Prüfung erfolgreich.
Beachten Sie, dass diese Lösung der Ethereum-Adressoption ähnelt, jedoch ohne die Notwendigkeit, private Schlüssel zu speichern. Die Kosten für die Überweisung von Geld von einer Wallet zu einer Hotwallet entsprechen ungefähr den Kosten für den Aufruf der Funktion Transfer(), da wir für die Bereitstellung eines Smart Contracts nicht bezahlen.
Endgültige Entscheidung

Ursprünglich erstellt von:
- Funktion zum Erhalten von Salz durch user_id
- ein Smart Contract, der den CREATE2-Opcode mit dem entsprechenden Salt aufruft (d. h. eine Wallet-Factory)
- Wallet-Bytecode, der einem Vertrag mit dem folgenden Konstruktor entspricht:
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/ihre Wallet-Adresse an, indem wir berechnen
keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]
Wenn ein Benutzer Token an die entsprechende Wallet-Adresse überträgt, sieht unser Backend ein Transfer-Ereignis mit dem Parameter _Zu, gleich der Wallet-Adresse. Zu diesem Zeitpunkt ist es bereits möglich, das Guthaben des Benutzers an der Börse zu erhöhen, bevor das Wallet bereitgestellt wird.
Wenn eine Wallet-Adresse genügend Token angesammelt hat, können wir diese alle auf einmal auf 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
}
Dadurch wird der Smart-Contract-Konstruktor der Wallet aufgerufen, der alle Token an die Hotwallet-Adresse überträgt und sich anschließend selbst zerstört.
Den vollständigen Code finden Sie . Bitte beachten Sie, dass dies nicht unser Produktionscode ist, da wir uns entschieden haben, den Wallet-Bytecode zu optimieren und ihn in Opcodes geschrieben haben.
Autor Pavel Kondratenkov, Ethereum-Spezialist
Source: habr.com
