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

Das Thema Blockchain hört nicht auf, nicht nur für alle Arten von Hype zu sorgen, sondern auch für Ideen, die aus technologischer Sicht sehr wertvoll sind. Daher umging sie die Bewohner der sonnigen Stadt nicht. Die Menschen beobachten, studieren und versuchen, ihr Fachwissen in der traditionellen Informationsanalyse auf Blockchain-Systeme zu übertragen. Bisher nur ein Punkt: Eine der Entwicklungen von Rostelecom-Solar ist in der Lage, die Sicherheit von Software anhand der Blockchain zu überprüfen. Dabei tauchen einige Überlegungen zur Lösung der angewandten Probleme der Blockchain-Community auf. Einer dieser Hacks im Leben - wie Sie mit CREATE2 die Adresse eines intelligenten Vertrags vor der Bereitstellung ermitteln - möchte ich Ihnen heute im Rahmen der Kürzung mitteilen.

Bild
Der CREATE2-Opcode wurde am 28. Februar dieses Jahres in die harte Gabel von Konstantinopel eingefügt. Wie in der EIP angegeben, wurde dieser Opcode hauptsächlich für staatliche Kanäle eingeführt. Wir haben es jedoch verwendet, um ein anderes Problem zu lösen.

Es sind Benutzer an der Börse mit Guthaben. Wir müssen jedem Benutzer eine Ethereum-Adresse zur Verfügung stellen, an die jeder Token senden und damit sein Konto auffüllen kann. Nennen wir diese Adressen "Brieftaschen". Wenn Token in Brieftaschen eingehen, müssen sie an eine einzelne Brieftasche (Hotwallet) gesendet werden.

In den folgenden Abschnitten analysiere ich Lösungen für dieses Problem ohne CREATE2 und erkläre, warum wir sie aufgegeben haben. Wenn Sie nur am Endergebnis interessiert sind, finden Sie es im Abschnitt „Endlösung“.

Ethereum-Adressen


Die einfachste Lösung besteht darin, neue Ethereum-Adressen für neue Benutzer zu generieren. Diese Adressen sind Brieftaschen. Um Token von der Brieftasche in die Hotwallet zu übertragen, müssen Sie die Transaktion signieren, indem Sie die Funktion transfer () mit dem privaten Schlüssel der Brieftasche aus dem Backend aufrufen.

Dieser Ansatz hat folgende Vorteile:

  • das ist einfach
  • Die Kosten für die Übertragung von Tokens von der Brieftasche zur Hotwallet entsprechen dem Preis für den Aufruf der transfer () - Funktion

Wir haben diesen Ansatz jedoch aufgegeben, da er einen erheblichen Nachteil hat: Sie müssen private Schlüssel irgendwo speichern. Und der Punkt ist nicht nur, dass sie verloren gehen können, sondern auch, dass Sie den Zugriff auf diese Schlüssel sorgfältig kontrollieren müssen. Wenn mindestens einer von ihnen kompromittiert ist, erreichen die Token eines bestimmten Benutzers kein heißes Portemonnaie.

Bild

Erstellen Sie einen separaten Smart-Vertrag für jeden Benutzer


Durch die Bereitstellung eines separaten Smart-Vertrags für jeden Benutzer ist es nicht mehr erforderlich, private Brieftaschenschlüssel auf dem Server zu speichern. Die Börse ruft diesen intelligenten Vertrag auf, um Token auf die Hotwallet zu übertragen.

Wir haben diese Entscheidung auch abgelehnt, da dem Benutzer die Adresse seiner Brieftasche nicht angezeigt werden kann, ohne einen intelligenten Vertrag zu implementieren (dies ist tatsächlich möglich, jedoch auf komplizierte Weise mit anderen Unzulänglichkeiten, auf die wir hier nicht eingehen werden). Während des Austauschs kann ein Benutzer so viele Konten erstellen, wie er benötigt, und jeder benötigt sein eigenes Portemonnaie. Dies bedeutet, dass wir Geld für die Bereitstellung des Vertrags ausgeben müssen und nicht einmal sicher sind, ob der Benutzer dieses Konto verwenden wird.

Opcode CREATE2


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

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

wo:
  • address - Die Adresse des Smart-Vertrags, der CREATE2 aufruft
  • Salz - Zufallswert
  • init_code - intelligenter Vertragsbytecode für die Bereitstellung

Dies stellt sicher, dass die Adresse, die wir dem Benutzer zur Verfügung stellen, tatsächlich den gewünschten Bytecode enthält. Darüber hinaus kann dieser intelligente Vertrag bei Bedarf implementiert werden. Zum Beispiel, wenn ein Benutzer seine Brieftasche zum ersten Mal verwendet.
Bild
Darüber hinaus können Sie die Adresse eines Smart-Vertrags jedes Mal berechnen, anstatt sie zu speichern, da:

  • Die Adresse in der Formel ist konstant, da dies die Adresse unserer Brieftaschenfabrik ist
  • salt - Hash von user_id
  • init_code ist persistent, da wir dieselbe Brieftasche verwenden

Weitere Verbesserungen


Die vorherige Lösung hat noch einen Nachteil: Sie müssen bezahlen, um einen intelligenten Vertrag bereitzustellen. Sie können dies jedoch loswerden. Dazu können Sie im Wallet-Konstruktor die Funktion transfer () und dann selfdestruct () aufrufen . Und dann wird das Gas für den Einsatz des Smart Contract zurückgegeben.

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

Beachten Sie, dass diese Lösung der Adressoption von Ethereum ähnelt, jedoch keine privaten Schlüssel gespeichert werden müssen. Die Kosten für den Geldtransfer von einer Brieftasche zu einer Hotwallet entsprechen in etwa den Kosten für den Aufruf der transfer () - Funktion, da die Bereitstellung eines intelligenten Vertrags nicht bezahlt wird.

Endgültige Entscheidung


Bild

Zunächst vorbereitet von:

  • Funktion, um Salt von user_id zu erhalten
  • einen intelligenten Vertrag, der den CREATE2-Opcode mit dem entsprechenden Salt (d. h. Wallet Factory) aufruft
  • Wallet-Byte-Code, der dem 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 Brieftaschenadresse durch Berechnung an

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

Wenn ein Benutzer Token an die entsprechende Brieftaschenadresse überträgt, sieht unser Backend das Ereignis Transfer mit dem Parameter _to , der der Brieftaschenadresse entspricht. Zu diesem Zeitpunkt ist es bereits möglich, das Guthaben des Benutzers in der Vermittlungsstelle zu erhöhen, bevor die Brieftasche bereitgestellt wird.

Wenn sich eine ausreichende Anzahl von Tokens an der Brieftaschenadresse angesammelt hat, können wir sie alle gleichzeitig auf eine Hotwallet übertragen. Dazu ruft das Backend die Funktion der Smart Contract Factory auf, die folgende Aktionen ausführt:

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

So wird der Konstruktor des Smart-Wallet-Vertrags aufgerufen, der alle seine Token an die Hot-Wallet-Adresse überträgt und sich dann selbst zerstört.

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

Gepostet von Pavel Kondratenkov, Ethereum Specialist

Source: https://habr.com/ru/post/de475496/


All Articles