Glans en armoede van atomic swaps

Wat zijn de nadelen van atomic swaps en hoe kunnen kanalen helpen, wat is er belangrijk gebeurd tijdens de hardfork Constantinople en hoe te handelen als je niet kunt betalen voor gas.

De belangrijkste motivatie van elke veiligheidspecialist is de wens om aansprakelijkheid te vermijden.

De voorzienigheid was genadig, ik verliet de ICO voordat de eerste onomkeerbare transactie plaatsvond, maar ontdekte al snel dat ik bezig was met de ontwikkeling van een cryptocurrency-exchange.

Ik ben absoluut geen Kibalchich, en ƩƩn strenge blik is voldoende om me alle sleutels en wachtwoorden te laten overhandigen. Daarom was mijn belangrijkste doel als architect om de brander van crypto-analyse zo ver mogelijk van de waardevolle elementen van de infrastructuur te plaatsen.

Niet jouw sleutels, niet jouw problemen.

We bouwen een systeem voor het ruilen van activa en willen de tussenopslag van deze activa bij ons uitsluiten, maar we moeten de veiligheid van de transactie waarborgen.

Men kan als scheidsrechter optreden in een geschil en transacties uitvoeren met portefeuilles die twee van de drie handtekeningen vereisen: van de koper, de verkoper en de escrow.

Echter, als een deelnemer succesvol de escrow aanvalt, krijgt hij de gewenste twee handtekeningen.

Atomic swap is een ruilmechanisme waarbij een smart contract als garant fungeert, dat alleen eerlijke gedragingen toestaat.

Net als in de raadsel over de wolf, de geit en de kool, kun je alleen volgens het enige juiste scenario handelen en maak je verlies als je ervan afwijkt.

Maar in plaats van vraatzuchtige dieren zorgt een hashfunctie voor de orde, waar het zo moeilijk is om een botsing te vinden dat je beter helemaal niet kunt beginnen.

Stap ƩƩn: de puzzel.

Stel je voor dat Alice op een mooie ochtend Bitcoin aan Bob wil geven in ruil voor een handvol 'crypto-yanen'.

  • Ze bedenkt een grote geheim.
  • Ontvangt van hem een hash.
  • Ze verplaatst Bitcoins naar een smart contract, waarvan Bob het geld kan ophalen door het geheim te tonen (de hash ervan moet overeenkomen met die in het contract).
  • Als Bob tegen de avond zijn Bitcoins niet heeft opgehaald, kan Alice ze terugkrijgen.

Stap twee: de lokvogel.

Bob komt in het spel en verplaatst 'crypto-euros' naar zijn contract, dat zo is geschreven dat:

  • Alice de 'crypto-yens' kan ophalen door een geheim getal te tonen.
  • Bob kan zijn aanbetaling terugkrijgen als Alice voor de lunch niet verschijnt.

Stap drie: de oplossing voor de lokvogel.

Alice komt voor haar geld en haalt het geld van Bobs contract, terwijl ze haar geheim onthult.

De laatste stap: de raadsel is opgelost

Bob ziet de transactie en haalt met een scherp oog het geheim eruit dat Alice aan het contract heeft gepresenteerd. Dit geheim gebruikt hij om zijn bitcoins op te eisen.

Wanneer er iets misgaat

Als Alice plotseling sterfelijk blijkt te zijn, haalt Bob in de middag zijn yuan op.

Tegen de avond retourneert Alice de bitcoin, als de bedrieglijke Bob besluit het geld vast te houden tot betere tijden.

Als je de voorkeur geeft aan een afbeelding boven tekst, is er een meer gedetailleerde en visuele uitleg op Habr. over de werking van atomaire swaps.

Het verschil tussen de time-outs is bedoeld om ons te beschermen tegen de kwade Alice, die Bobs geld op het allerlaatste moment steelt, terwijl de time-out verstrijkt terwijl hij met trillende vingers de hex in de transactie invoert.

De deelnemers kunnen hun geld niet verliezen, hooguit moeten ze wachten op terugbetaling.

Ondersteuning in blockchainsDit is een eenvoudig systeem dat van de betrokken blockchains niet veel vereist:

  • Ondersteuning voor slimme contracten met ten minste ƩƩn vertakking
  • Beide blockchains moeten dezelfde hashing-algoritmen ondersteunen (vergeet niet de lengte van het geheim te controleren)
  • Time-locks.

Op het eerste gezicht kan je al zeggen tegen de beurs 'vaarwel, onze ontmoeting was een vergissing', maar dat is niet het geval.

Bij al zijn voordelen verrassen oplossingen op basis van atomic swap niet met liquiditeit. Dit komt grotendeels omdat de fiat component in de meest populaire paar BTC-USD niet volledig getokeniseerd was.
Het succes van USDT heeft een golf van stablecoins in ERC20-formaat voortgebracht, van de meest bewuste USDC tot de meest algorithimische DAI.

Daarom redeneren we voor de eenvoud dat Alice bitcoin aan Bob verkoopt in ruil voor bepaalde ERC20-tokens, en hopen we op het geluk van de stabilisatoren, omdat we nog veel meer technische problemen hebben.

Snelheid

Bitcoin en Ethereum zijn beide niet erg snel, en we moeten eerst ƩƩn storting met alle bevestigingen afwachten, en daarna de tweede.

Dit komt omdat eerst het geld wordt gestort door de deelnemer die het geheim kent, terwijl de tegenstander wacht op de finaliteit en pas dan zijn deel overmaakt.

Daarnaast hebben we te maken met een zeer volatiele activa, dus in de tussentijd kan de koers aanzienlijk fluctueren, en het is niet eenvoudig om de voorwaarden te wijzigen.

Privacy

Elke ruil laat artefacten achter op beide blockchains. Een oplettende waarnemer kan identieke hashes in smart contracts opmerken en logisch concluderen dat er een transactie heeft plaatsgevonden, waaruit verschillende conclusies kunnen worden getrokken, van koersspeculaties tot belastingkwesties.

Wanneer de beurs op de hoogte is van jouw zaken - is dat al erg vervelend, maar wanneer iedereen het weet - is dat twee keer zo vervelend.

Gebruiksvriendelijkheid

De specialiteit van blockchain in het algemeen en Ethereum in het bijzonder. Laten we eens kijken naar de stappen die zowel de verkoper als de koper moeten nemen.

Vanuit het perspectief van de verkoper is alles relatief eenvoudig: je moet gewoon Bitcoin naar een p2sh-adres overmaken. Met Ethereum is het een stuk gecompliceerder.

ContractLaten we een gemiddelde GitHub-contract bekijken voor swaps:

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); // controleer of er al een swap met de gegeven hash bestaat
        require(token.transferFrom(msg.sender, address(this), amount)); // verplaats de vergrendelde tokens naar het swapcontract
        swaps[msg.sender][receiver] = Swap(token, hash, amount, refundTime, 0x00); // creƫer 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 bestaat
        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);
    }
}

Let op! Gebruik dit contract en andere contracten uit het artikel niet in productie; ze zijn uitsluitend voor demonstratiedoeleinden geschreven. Vooral deze.

  • Bob moet de tokencontract-methode aanroepen reject, waardoor het swapcontract toegang krijgt tot zijn tokens
  • Bob creĆ«ert de swap en het contract met behulp van de methode transferFrom neemt de tokens van de verzender naar zijn adres
  • Alice in withdraw onthult een geheim en roept een contract op transfer

De meeste wallets en cryptocurrency-beurzen ondersteunen niet reject tokens, en dat is niet zonder reden.

Gebruikers maken vaak fouten en sturen gewoon tokens naar het contract, waarna de tokens gewoon verloren gaan. De opmerkingen op Etherscan zijn vol met geklaag van ongelukkigen.

Om een contract op te roepen, moet je een vergoeding in ETH betalen, wat betekent dat beide partijen zich daarmee moeten voorhouden voordat ze een transactie beginnen, iets waar weinig mensen zich mee willen bezighouden.

Gascontainer

Om te beginnen, moet je de controle op de verzender overal waar mogelijk weghalen en aannemen dat we iemand hebben die lijdt onder een overvloed aan gas en contracten oproept voor iedereen die dat wil.

Gemoderniseerd contract

contract Swapper {

    struct Swap {
        iERC20 token;
        address ontvanger;
        uint bedrag;
        address terugbetalingsAdres;
        uint terugbetalingsTijd;
    }

    mapping (bytes32 => Swap) swaps;

    function create(iERC20 token, bytes32 hash, address ontvanger, uint bedrag, address terugbetalingsAdres, uint terugbetalingsTijd) public {
        require(swaps[hash].bedrag == 0); // gebruik hash eenmaal
        require(token.transferFrom(msg.sender, address(this), bedrag));
        swaps[hash] = Swap(token, ontvanger, bedrag, terugbetalingsAdres, terugbetalingsTijd);
    }


    function withdraw(bytes memory geheim) public {
        bytes32 hash = sha256(geheim);
        Swap memory swap = swaps[hash];
        require(swap.bedrag > 0);
        delete swaps[hash];
        swap.token.transfer(swap.ontvanger, swap.bedrag);
    }

    function refund(bytes32 hash) public {
        Swap memory swap = swaps[hash];
        require(now > swap.terugbetalingsTijd);
        delete swaps[hash];
        swap.token.transfer(swap.terugbetalingsAdres, swap.bedrag);
    }
}

Contract-sleutel dualiteit en EIP 712

Zoals we weten, kan een adres in Ethereum een contract zijn of een entiteit, oftewel een sleutel.
De belangrijkste taak van de sleutel is om berichten te ondertekenen.

We kunnen Bob-contract gebruiken als verzender, die alle benodigde doorvoeren doet, voorafgaand aan de handtekening van Bob-sleutel.

Nu kan iedereen de vergoeding van de deelnemer sponsoren, maar de beslissing wordt alleen genomen door degene die de sleutel kent.

Bob-contract

library EIP712ProxyLibrary {
    function hashCommand(address verzender, iERC20 token, Swapper swapper, bytes32 hash, address ontvanger, uint bedrag, address terugbetalingsAdres, uint terugbetalingsTijd) public view returns(bytes32);
}

contract ProxyBob {
    address eigenaar;

    constructor(address _eigenaar) public {
        eigenaar = _eigenaar;
    }

    function createSwap(Swapper swapper, iERC20 token, bytes32 hash, address ontvanger, uint bedrag, address terugbetalingsAdres, uint terugbetalingsTijd, uint8 v, bytes32 r, bytes32 s) public {
        require(eigenaar == ecrecover(EIP712ProxyLibrary.hashCommand(address(this), token, swapper, hash, ontvanger, bedrag, terugbetalingsAdres, terugbetalingsTijd), v, r, s));
        token.approve(address(swapper), bedrag);
        swapper.create(token, hash, ontvanger, bedrag, terugbetalingsAdres, terugbetalingsTijd);
    }
}

Voor het werken met handtekeningen van complexe datatypes in Ethereum is er een standaard EIP 712, je kunt er meer over lezen in de Metamask-portefeuilleblog

Splits en heers

Vaak ziet het hackscenario van een Ethereum-contract er zo uit:

  • De deelnemer stopt geld in het contract
  • Daarna haalt hij het geld weer op
  • Er gaat iets mis
  • De aanvaller haalt het geld steeds weer opnieuw op

Als we teruggaan naar ons eerste voorbeeld, gaat er iets mis als de puzzel een lege byte-array is.

Hoe een miljoen te stelenWe maken een swap met een hash 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
Dit is sha256 van 0x0000000000000000000000000000000000000000000000000000000000000000
We geven het geheim door en halen onze tokens op
We geven het nog een keer door en halen andermans op, allemaal omdat 0 = 0

Door voor elke transactie een afzonderlijk contract te maken, kunnen we de contracten op EVM-niveau isoleren.

Maar dat is nog niet alles: nu heeft elke transactie zijn eigen adres waarop tokens vanaf elke portemonnee of uitwisseling kunnen worden overgemaakt.

Verworpen contracten en create2

Maar nu moeten we voor elke transactie een contract aanmaken en wachten tot de koper geld naar het arbeidsintensieve 'cryptofunding' heeft overgemaakt. In het schema 'ochtend contracten, avond geld' is er altijd het risico dat de koper afhaakt, terwijl de ether voor het aanmaken van het contract al is uitgegeven.

Kunnen we het niet zo maken dat er 'ochtend geld is, en avond bytes'?

In de Constantinople hardfork hebben de ontwikkelaars EIP 1014 de create2-instructie toegevoegd, die een nieuw contract op een deterministisch adres aanmaakt

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

Waarbij

  • address — het adres van de fabriekscontract
  • salt — een bepaald getal, waarvan we de betekenis in de volgende aflevering zullen ontdekken
  • init_code — de bytecode van het contract en de parameters van de constructeur.

FabriekDe instructie werkt alleen via assembly, dus de fabriek ziet er een beetje intimiderend uit:

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);
  }
}

Je kunt de code van je contract krijgen met behulp van web3:

const MyContract = new web3.eth.Contract(ABI, {})
const code = MyContract.deploy({
    data: BYTECODE,
    arguments: contructorArgs  
}).encodeABI();
const factory = new web3.eth.Contract(FACTORY_ABI, factoryAddress);
tx = factory.methods.create2(code, salt);

Vanwege beperkte ondersteuning in Solidity kan de gas voor het contract verkeerd worden berekend vanwege enkele nuances van Ether.

Het is bijzonder charmant dat in geval van onvoldoende gas het contract faalt met een interne fout, zonder te melden dat er geen gas was, zoals je zou verwachten.

Nu kunnen we tokens op contracten vertalen zonder ze van tevoren aan te maken en zolang we ze niet openbaar maken in het netwerk zal niemand raden wat het contract precies doet.

De raaf pikt de ogen van de raaf niet uit.

Het is duidelijk dat een echte analist, vooral eentje die goede investeringen heeft gekregen in de strijd tegen de vijanden van het regime door middel van witwassen van geld, niet zal worden tegengehouden door zulke kinderlijke trucjes en dat hij, na het creƫren van het contract, toch de hash zal zien.

Hoe zorg je ervoor dat de hash niet zichtbaar is?

De swap zelf verplaatsen we off-chain: deelnemers wisselen handtekeningen uit voor de overdracht naar het swap-contract, en dan wordt het geheim privƩ onthuld.

Stap voor stap.Er worden twee "multisigs" aangemaakt, van waaruit middelen kunnen worden opgenomen met de handtekeningen van Alice en Bob.

Om te voorkomen dat de offlinegang van een van de deelnemers een tragedie wordt, voegen we de oude goede timeout toe.

Alice en Bob storten tegelijkertijd hun deposito's.

  • Alice bedenkt een geheim en geeft Bob de hash van het geheim en de handtekening van de transactie die de Bitcoins naar het swapadres overmaakt.
  • Bob geeft Alice de handtekening voor de opname van tokens naar het swapcontract met de bedachte hash.
  • Alice deelt haar geheim met Bob.

Op dat moment is er harmonie: zowel Alice als Bob kunnen op elk moment de transactie afronden. In deze vriendelijke omgeving kunnen ze handtekeningen uitwisselen voor het opnemen van geld naar de uiteindelijke adressen.

Voor een externe waarnemer lijkt het alsof het geld door een contract met een multisig 2 van 2 is gegaan.

Bovendien maakt dit schema het mogelijk voor beide partijen om gelijktijdig een deposit te doen, aangezien het geheim pas na alle bevestigingen wordt bedacht.

Niveau 2.

Nu we geld naar ƩƩn adres kunnen opnemen en de tussenliggende transactie niet hoeven te publiceren, staat niets ons in de weg om geld naar meerdere adressen op te nemen en een onbeperkt aantal tussentijdse transacties uit te voeren. Het is niet dat dit een noodzakelijke set is voor een ruil, maar als je eenmaal een swap begint te verzamelen, is het moeilijk om te stoppen.

Nu kunnen Alice en Bob zich helemaal uitleven. Bijvoorbeeld door automatisch de gemiddelde prijs te berekenen, terwijl ze om de seconde met satoshi’s wisselen, of gewoon rechtstreeks een market maker met een liquiditeitsontvanger verbinden.

Stap voor stap.

  • De verkoper bedenkt een geheim en geeft de koper de hash van het geheim en de handtekening van de transactie waar een deel van de middelen naar het p2sh swapadres wordt overgemaakt, terwijl de rest naar het adres van de verkoper terugkomt.
  • De koper geeft een handtekening om tokens en change naar het ontvangstadres te sturen.
  • De verkoper onthult een geheim
  • De geschiedenis herhaalt zich met een nieuw geheim, waarbij aan de swap en change ook de uitvoer wordt toegevoegd van eerder aangekochte items naar het adres van de koper en al betaald naar het adres van de verkoper.

Nu hebben we toegang tot razendsnelle p2p-handel, het belangrijkste is om de tijd in de gaten te houden en de deal vóór de time-out te sluiten.

Echter, door onze contracten een beetje aan te passen, kunnen we onze kanalen onsterfelijkheid geven, wat het voor ons veel gemakkelijker maakt om een netwerk te creƫren.

Maar daarover vertellen we in de volgende aflevering.

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers šŸ”„ Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster