Warum Atom-Swaps schlecht sind und wie Kanäle ihnen helfen, welche wichtigen Dinge beim Constantinople Hard Fork passiert sind und was zu tun ist, wenn man nichts für Gas zu bezahlen hat.
Die Hauptmotivation eines jeden Sicherheitsspezialisten ist der Wunsch, Verantwortung zu vermeiden.
Die Vorsehung war gnädig, ich verließ das ICO, ohne auf die erste unumkehrbare Transaktion zu warten, fand mich aber bald in der Entwicklung einer Krypto-Börse wieder.
Ich bin definitiv nicht Malchish Kibalchish und ein strenger Blick genügt mir, um alle Schlüssel und Passwörter herauszugeben. Daher bestand mein Hauptziel als Architekt darin, den glühenden Stachel der Kryptoanalyse so weit wie möglich von den Infrastrukturelementen entfernt zu platzieren, die mir am Herzen liegen.
Nicht deine Schlüssel, nicht deine Probleme
Wir bauen ein System zum Austausch von Vermögenswerten auf und möchten die Zwischenspeicherung dieser Vermögenswerte vermeiden, müssen jedoch die Sicherheit der Transaktion gewährleisten.
Sie können in einer kontroversen Situation als Richter fungieren und Transaktionen mit Wallets durchführen, die zwei von drei Unterschriften erfordern: Käufer, Verkäufer und Treuhänder.
Wenn der Teilnehmer jedoch erfolgreich das Treuhandkonto angreift, erhält er die erforderlichen zwei Unterschriften.
Atomic Swap ist ein Tauschsystem, bei dem der Bürge ein intelligenter Vertrag ist, der nur ehrliches Verhalten zulässt.
Wie bei einem Rätsel um einen Wolf, eine Ziege und einen Kohl kann man nur nach dem einzig richtigen Szenario handeln und Verluste erleiden, wenn man davon abweicht.
Nur statt gefräßiger Tiere sorgt eine Hash-Funktion für Ordnung, bei der es so schwierig ist, eine Kollision zu finden, dass es sich nicht lohnt, damit anzufangen.
Schritt eins: Rätsel
Angenommen, Alice möchte Bob eines schönen Morgens für eine Handvoll „Krypto-Yuan“ einen Bitcoin geben.
- Sie macht ein großes Geheimnis
- Erhält einen Hash davon
- Überträgt Bitcoins an einen Smart-Vertrag, von dem Bob Geld abheben kann, indem er ein Geheimnis preisgibt (der Hashwert muss mit dem im Vertrag angegebenen übereinstimmen).
- Wenn Bob abends nicht erscheint, um seine Bitcoins abzuholen, kann Alice sie zu sich zurückbringen.
Schritt zwei: Köder
Bob kommt ins Spiel und überträgt „Krypto-Euro“ in seinen Vertrag, der so geschrieben ist:
- Alice kann durch Vorlage einer Geheimnummer „Krypto-Yens“ abheben
- Spätestens zum Mittagessen kann Bob die Kaution zurückerstatten, wenn Alice nicht erscheint.
Schritt drei: Die Antwort liegt im Köder
Alice kommt, um ihr Geld zu holen, nimmt das Geld aus Bobs Vertrag und verrät dabei ihr Geheimnis.
Letzter Schritt: Das Rätsel ist gelöst
Bob sieht die Transaktion und entlockt ihr mit seinem Adlerauge das Geheimnis, das Alice dem Vertrag preisgegeben hat. Dieses Geheimnis nutzt er, um seine Bitcoins zurückzubekommen.
Wenn Dinge schief laufen
Wenn sich herausstellt, dass Alice plötzlich sterblich ist, nimmt Bob beim Mittagessen seinen Yuan.
Alice wiederum gibt die Bitcoins am Abend zurück, wenn der verräterische Bob beschließt, das Geld bis zu besseren Zeiten aufzubewahren.
Wenn Sie ein Bild dem Text vorziehen, hat Habré ein detaillierteres und visuelleres für Sie. .
Der Unterschied zwischen den Zeitüberschreitungen soll uns vor der böswilligen Alice schützen, die im allerletzten Moment Bobs Geld nimmt, und die Zeitüberschreitung läuft ab, während er mit zitternden Fingern das Hex in die Transaktion eingibt.
Teilnehmer können ihr Geld nicht verlieren, sondern müssen höchstens auf eine Rückerstattung warten.
Blockchain-UnterstützungDies ist ein einfaches Schema, das überhaupt nichts von interagierenden Blockchains erfordert:
- Unterstützung für Smart Contracts mit mindestens einer Filiale
- Beide Blockchains müssen die gleichen Hashing-Algorithmen unterstützen (denken Sie daran, die geheime Länge zu überprüfen).
- Zeitschlösser.
Auf den ersten Blick kann man der Börse schon sagen „Auf Wiedersehen, unser Treffen war ein Fehler“, aber das war nicht der Fall.
Bei all ihren Vorteilen überzeugen Atom-Swap-Lösungen nicht durch ihre Liquidität. Vor allem, weil im beliebtesten BTC-USD-Paar der Fiat-Anteil nicht vollständig tokenisiert war.
Der Erfolg von USDT hat zu einer ganzen Welle stabiler Münzen im ERC20-Format für jeden Geschmack geführt, vom USDC mit der höchsten Verwahrung bis zum DAI mit den meisten Algorithmen.
Deshalb argumentieren wir der Einfachheit halber weiter, dass Alice Bitcoins für einige ERC20-Tokens an Bob verkauft, und wir hoffen auf das Glück der Stabilisatoren, da wir noch viele weitere technische Probleme haben.
Geschwindigkeit
Bitcoin und Ethereum sind einzeln nicht sehr schnell, aber hier müssen wir zuerst auf eine Einzahlung mit allen Bestätigungen warten, dann auf die zweite.
Dies liegt daran, dass der Teilnehmer, der das Geheimnis kennt, zuerst das Geld einzahlt und der Gegner auf die Endgültigkeit wartet und erst dann seinen Teil überweist.
Darüber hinaus haben wir es mit einem sehr volatilen Vermögenswert zu tun, sodass sich der Kurs in dieser Zeit erheblich ändern kann und eine Änderung der Bedingungen nicht mehr einfach ist.
Vertraulichkeit
Jeder Austausch hinterlässt Artefakte auf beiden Blockchains. Ein aufmerksamer Beobachter kann die gleichen Hashes in Smart Contracts erkennen und daraus den logischen Schluss ziehen, dass eine Transaktion abgeschlossen wurde, woraus viele Rückschlüsse vom Wechselkurs bis zur Steuer gezogen werden können.
Wenn die Börse von Ihren Angelegenheiten weiß, ist es äußerst unangenehm; wenn jeder davon weiß, ist es doppelt unangenehm.
Intuitive Bedienung
Die Stärke von Blockchain im Allgemeinen und Ether im Besonderen. Mal sehen, welche Gesten Verkäufer und Käufer machen müssen.
Aus Sicht des Verkäufers ist alles relativ einfach: Sie müssen lediglich Bitcoin an eine p2sh-Adresse übertragen. Bei Ether ist alles viel schwieriger.
VertragSchauen wir uns den über Github gemittelten Vertrag für einen Swap an:
contract iERC20 {
function totalSupply() public view returns (uint256);
function transfer(address receiver, uint numTokens) public returns (bool);
function balanceOf(address tokenOwner) public view returns (uint);
function approve(address delegate, uint numTokens) public returns (bool);
function allowance(address owner, address delegate) public view returns (uint);
function transferFrom(address owner, address buyer, uint numTokens) public returns (bool);
}
contract Swapper {
struct Swap {
iERC20 token;
bytes32 hash;
uint amount;
uint refundTime;
bytes32 secret;
}
mapping (address => mapping(address => Swap)) swaps;
function create(iERC20 token, bytes32 hash, address receiver, uint amount, uint refundTime) public {
require(swaps[msg.sender][receiver].amount == 0); // check is swap with given hash already exists
require(token.transferFrom(msg.sender, address(this), amount)); // transfer locked tokens to swap contract
swaps[msg.sender][receiver] = Swap(token, hash, amount, refundTime, 0x00); //create swap
}
function hashOf(bytes32 secret) public pure returns(bytes32) {
return sha256(abi.encodePacked(secret));
}
function withdraw(address owner, bytes32 secret) public {
Swap memory swap = swaps[owner][msg.sender];
require(swap.secret == bytes32(0));
require(swap.hash == sha256(abi.encodePacked(secret))); // swap exists
swaps[owner][msg.sender].secret = secret;
swap.token.transfer(msg.sender, swap.amount);
}
function refund(address receiver) public {
Swap memory swap = swaps[msg.sender][receiver];
require(now > swap.refundTime);
delete swaps[msg.sender][receiver];
swap.token.transfer(msg.sender, swap.amount);
}
}
Achtung! Verwenden Sie diesen und andere Verträge aus dem Artikel nicht in der Produktion, sie dienen nur zu Demonstrationszwecken. Besonders dieses hier.
- Bob muss die Methode des Token-Vertrags aufrufen
approve, wodurch der Swap-Vertrag Zugriff auf seine Token erhält - Bob erstellt den Swap und den Vertrag mithilfe der Methode
transferFrombringt die Token des Absenders an Ihre Adresse - Alice rein
withdrawlüftet das Geheimnis und der Vertrag läufttransfer
Die meisten Wallets und Krypto-Börsen unterstützen dies nicht approve Token, und das aus gutem Grund.
Benutzer selbst machen oft Fehler und übertragen Token einfach auf den Vertrag, woraufhin die Token einfach verloren gehen. Die Kommentare auf Etherscan sind voller Klagen der Unglücklichen.
Und um einen Vertrag zu kündigen, müssen Sie eine Provision an ETH zahlen, was bedeutet, dass beide Teilnehmer sich damit eindecken müssen, bevor sie mit der Transaktion beginnen, und nur wenige Menschen möchten dies tun.
Gasbehälter
Ein guter Anfang besteht darin, die Absenderprüfung nach Möglichkeit zu entfernen und davon auszugehen, dass wir jemanden haben, der unter überschüssigen Gasanrufverträgen für alle Ankömmlinge leidet.
Verbesserter Vertrag
contract Swapper {
struct Swap {
iERC20 token;
address receiver;
uint amount;
address refundAddress;
uint refundTime;
}
mapping (bytes32 => Swap) swaps;
function create(iERC20 token, bytes32 hash, address receiver, uint amount, address refundAddress, uint refundTime) public {
require(swaps[hash].amount == 0); // use hash once
require(token.transferFrom(msg.sender, address(this), amount));
swaps[hash] = Swap(token, receiver, amount, refundAddress, refundTime);
}
function withdraw(bytes memory secret) public {
bytes32 hash = sha256(secret);
Swap memory swap = swaps[hash];
require(swap.amount > 0);
delete swaps[hash];
swap.token.transfer(swap.receiver, swap.amount);
}
function refund(bytes32 hash) public {
Swap memory swap = swaps[hash];
require(now > swap.refundTime);
delete swaps[hash];
swap.token.transfer(swap.refundAddress, swap.amount);
}
}
Vertragsschlüsseldualismus und EIP 712
Wie wir wissen, kann eine gesendete Adresse ein Vertrag oder ein Betreff, also ein Schlüssel, sein.
Die Hauptaufgabe des Schlüssels besteht darin, einige Nachrichten zu signieren.
Als Absender können wir den Bob-Vertrag verwenden, der alle notwendigen Durchgänge durchführt, nachdem wir zunächst die Signatur des Bob-Schlüssels überprüft haben.
Nun kann jeder die Provision eines Teilnehmers sponsern, aber nur derjenige, der den Schlüssel kennt, trifft die Entscheidung.
Bob-Vertrag
library EIP712ProxyLibrary {
function hashCommand(address sender, iERC20 token, Swapper swapper, bytes32 hash, address receiver, uint amount, address refundAddress, uint refundTime) public view returns(bytes32);
}
contract ProxyBob {
address owner;
constructor(address _owner) public {
owner = _owner;
}
function createSwap(Swapper swapper, iERC20 token, bytes32 hash, address receiver, uint amount, address refundAddress, uint refundTime, uint8 v, bytes32 r, bytes32 s) public {
require(owner == ecrecover(EIP712ProxyLibrary.hashCommand(address(this), token, swapper, hash, receiver, amount, refundAddress, refundTime), v, r, s));
token.approve(address(swapper), amount);
swapper.create(token, hash, receiver, amount, refundAddress, refundTime);
}
}
Ethereum verfügt über einen Standard für die Arbeit mit Signaturen komplexer Datenstrukturen , mehr darüber können Sie unter lesen
Divide and Conquer
Oftmals sieht das Szenario für das Hacken eines Ethereum-Vertrags so aus:
- Der Teilnehmer zahlt Geld in den Vertrag ein
- Dann nimmt er das Geld
- Etwas läuft schief
- Der Angreifer erbeutet immer wieder das Geld
Wenn wir zu unserem ersten Beispiel zurückkehren, geht etwas schief, wenn das Rätsel ein leerer Satz von Bytes ist.
Wie man eine Million stiehltErstellen Sie einen Swap mit einem Hash 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
Das ist sha256 von 0x0000000000000000000000000000000000000000000000000000000000000000
Wir übertragen das Geheimnis und nehmen unsere Token
Wir übermitteln erneut und nehmen die von jemand anderem, alles nur, weil 0 = 0
Indem wir für jeden Handel einen separaten Vertrag erstellen, können wir Verträge auf EVM-Ebene isolieren.
Aber das ist noch nicht alles: Jetzt hat jede Transaktion eine eigene Adresse, an die Sie Token von jedem Wallet oder jeder Börse übertragen können.
Abgebrochene Verträge und create2
Aber jetzt müssen wir für jede Transaktion einen Vertrag erstellen und darauf warten, dass der Käufer die Arbeit zur „Krypto-Findung“ dorthin überträgt. Beim Schema „Morgens Verträge, abends Geld“ besteht immer die Gefahr, dass der Käufer abfällt und der Äther bereits für die Vertragserstellung ausgegeben wurde.
Ist es möglich, dass man morgens Geld und abends Bytes hat?
Entwickler im Constantinople Hard Fork Die Anweisung „create2“ wurde hinzugefügt, die einen neuen Vertrag an einer deterministischen Adresse erstellt
keccak256( 0xff ++ address ++ salt ++ keccak256(init_code))[12:]
Wo
- Adresse – Fabrikvertragsadresse
- Salz – eine Zahl, deren Bedeutung wir in der nächsten Serie erfahren werden
- init_code – Vertragsbytecode und Konstruktorparameter.
FabrikDie Anleitung funktioniert nur durch den Zusammenbau, daher sieht die Fabrik etwas gruselig aus:
contract Factory {
event Deployed(address addr, uint256 salt);
function create2(bytes memory code, uint256 salt) public {
address addr;
assembly {
addr := create2(0, add(code, 0x20), mload(code), salt)
}
emit Deployed(addr, salt);
}
}
Ihren Vertragscode erhalten Sie über web3:
const MyContract = new web3.eth.Contract(ABI, {})
const сode = MyContract.deploy({
data: BYTECODE,
arguments: contructorArgs
}).encodeABI();
const factory = new web3.eth.Contract(FACTORY_ABI, factoryAddress);
tx = factory.methods.create2(сode, salt);
Aufgrund der begrenzten Unterstützung der Solidität kann es aufgrund einiger Feinheiten des Äthers dazu kommen, dass Gas für einen Vertrag falsch berechnet wird.
Besonders schön ist, dass im Falle einer Gasknappheit der Vertrag mit einem internen Fehler abstürzt, ohne wie erwartet zu melden, dass nicht genügend Gas vorhanden ist.
Jetzt können wir Token in Verträge übertragen, ohne sie vorher zu erstellen, und bis wir sie im Netzwerk veröffentlichen, wird niemand erraten, was genau der Vertrag bewirkt.
Krähe sucht die Krähe nicht aus
Es ist klar, dass ein echter Analyst, insbesondere einer, der viel Geld in den Kampf gegen die Feinde des Regimes mit Geldwäsche investiert hat, sich von solch kindischen Tricks nicht aufhalten lässt und nach der Erstellung des Vertrags immer noch den Hash sehen wird.
Wie kann verhindert werden, dass der Hash angezeigt wird?
Wir übertragen den Swap selbst in die Off-Chain: Die Teilnehmer tauschen Unterschriften für die Übertragung in einen Swap-Vertrag aus, und dann wird das Geheimnis vertraulich gelüftet.
Schritt für SchrittEs werden zwei „Multisigs“ erstellt, von denen Gelder abgehoben werden können, wenn Alice und Bob Unterschriften haben.
Um zu verhindern, dass es für einen Teilnehmer zu einer Tragödie wird, offline zu gehen, fügen wir eine gute alte Auszeit hinzu.
Alice und Bob tätigen parallel Einzahlungen
- Alice errät ein Geheimnis und gibt Bob einen Hash des Geheimnisses und eine Transaktionssignatur, die die Bitcoins an die Swap-Adresse überträgt.
- Bob gibt Alice eine Unterschrift, um Token mit einem versteckten Hash aus einem Swap-Vertrag abzuheben.
- Alice verrät Bob ein Geheimnis.
In diesem Moment kommt Harmonie: Sowohl Alice als auch Bob können den Deal jederzeit abschließen. In einer so freundlichen Umgebung können sie Unterschriften austauschen, um Geld an die endgültigen Adressen abzuheben.
Für einen externen Beobachter sieht es so aus, als ob das Geld über einen 2-von-2-Multisig-Vertrag geflossen ist.
Dieses Schema ermöglicht es beiden Parteien auch, gleichzeitig eine Einzahlung zu tätigen, da das Geheimnis nach allen Bestätigungen gelüftet wird.
Level 2
Da wir Geld an eine Adresse abheben können, ohne eine Zwischentransaktion zu veröffentlichen, hindert uns nichts daran, Geld an mehrere Adressen abzuheben und eine unbegrenzte Anzahl von Zwischentransaktionen durchzuführen. Es ist nicht so, dass dies ein notwendiges Set für einen Tausch ist, aber wenn man einmal angefangen hat, einen Tausch zu sammeln, ist es schwer, damit aufzuhören.
Jetzt können Alice und Bob sich mit aller Kraft umdrehen. Berechnen Sie beispielsweise automatisch den Durchschnittspreis, indem Sie Satoshi pro Sekunde austauschen, oder verbinden Sie einfach direkt den Market Maker und den Liquiditätsempfänger.
Schritt für Schritt
- Der Verkäufer macht ein Geheimnis und gibt dem Käufer einen Hash des Geheimnisses und eine Transaktionssignatur, wobei ein Teil des Geldes an die p2sh-Swap-Adresse überwiesen wird und der Rest an die Adresse des Verkäufers zurückgesendet wird
- Der Käufer reicht eine Unterschrift ein, mit der er die Swap-Tokens und das Wechselgeld an die Adresse des Empfängers senden kann.
- Der Verkäufer lüftet das Geheimnis
- Die Geschichte wiederholt sich mit einem neuen Geheimnis, und zusätzlich zum Tausch und Wechsel kommt die Auszahlung dessen, was zuvor an die Adresse des Käufers gekauft und bereits an die Adresse des Verkäufers bezahlt wurde
Jetzt haben wir Zugang zum Hochgeschwindigkeits-P2P-Handel. Die Hauptsache ist, die Zeit im Auge zu behalten und den Deal vor Ablauf der Zeit abzuschließen.
Indem wir unsere Verträge jedoch ein wenig optimieren, können wir unseren Kanälen Unsterblichkeit verleihen, was uns den Aufbau eines Netzwerks erheblich erleichtert.
Aber darüber werden wir in der nächsten Folge sprechen.
Source: habr.com
