Échanges atomiques de brillance et de pauvreté

Pourquoi les échanges atomiques sont mauvais et comment les canaux les aideront, ce qui est important dans la fourche dure de Constantinople et quoi faire quand il n'y a rien à payer pour le gaz.

La principale motivation de tout professionnel de la sécurité est le désir d'éviter la responsabilité.

La Providence a été gracieuse, j'ai quitté l'ICO, n'attendant pas la première transaction irréversible, mais je me suis vite retrouvé derrière le développement d'un échange de crypto-monnaie.

Je ne suis définitivement pas Malchish Kibalchish, et un regard strict me suffit pour passer toutes les clés et mots de passe. Par conséquent, mon objectif principal en tant qu'architecte était de placer la piqûre brûlante de la cryptanalyse aussi loin que possible des éléments d'infrastructure qui me sont chers.

Pas vos clés, pas vos problèmes


Nous construisons un système d'échange d'actifs et souhaitons exclure le stockage intermédiaire de ces actifs à domicile, mais nous devons assurer la sécurité de la transaction.

Vous pouvez agir en tant que juge dans une situation controversée et effectuer des transactions avec des portefeuilles qui nécessitent deux des trois signatures: l'acheteur, le vendeur et l'entiercement.

Cependant, si un participant réussit à attaquer un séquestre, il reçoit alors les deux signatures requises.

Le swap atomique est un système d'échange où un contrat intelligent agit en tant que garant, ce qui ne permet qu'un comportement honnête.

Comme dans une énigme sur une chèvre loup et un chou, vous ne pouvez agir que selon le seul scénario correct et subir des pertes si vous vous en éloignez.

Seulement au lieu d'animaux voraces, l'ordre fournit une fonction de hachage dans laquelle il est si difficile de trouver une collision qu'il ne vaut pas la peine de commencer.

Première étape: l'énigme


Supposons qu'Alice veuille donner Bitcoin à Bob pour une poignée de «crypto yuan» un beau matin.

  • Elle fait un grand secret
  • Reçoit un hachage de celui-ci
  • Il transfère des bitcoins vers un contrat intelligent, à partir duquel Bob peut prendre de l'argent en présentant un secret (le hachage de celui-ci doit être égal à celui spécifié dans le contrat)
  • Dans le cas où Bob n'est pas à ses bitcoins dans la soirée, Alice peut les ramener à elle.

Deuxième étape: appât


Bob entre dans le jeu et transfère «cryptoeuro» à son contrat, qui est rédigé de telle manière que:

  • Alice peut ramasser des «crypto-pièces» en présentant un numéro secret
  • Pas avant le déjeuner, Bob, si Alice n'apparaît pas, peut retourner le dépôt

Troisième étape: la solution dans l'appât


Alice vient chercher son argent et prend l'argent du contrat de Bob, tout en révélant son secret.

La dernière étape: l'énigme est résolue


Bob voit la transaction et avec son regard aquilin il isole d'elle le secret présenté par Alice au contrat. Il utilise ce secret pour récupérer ses bitcoins.

Quand quelque chose tourne mal


Si Alice se révèle soudainement mortelle, Bob prend son yuan pour le déjeuner.

À son tour, Alice dans la soirée retourne Bitcoin si le perfide Bob décide de conserver l'argent jusqu'à des temps meilleurs.

Si vous préférez une image à un texte, sur Habré il y a pour vous une explication plus détaillée et plus claire du travail des swaps atomiques .

La différence entre les délais d'attente est conçue pour nous protéger contre la malveillante Alice, qui prend l'argent de Bob au tout dernier moment, et le délai expire pendant qu'il conduit l'hexagone dans la transaction avec les doigts tremblants.

Les participants ne peuvent pas perdre leur argent, le maximum devra attendre un retour.

Prise en charge de la blockchain
C'est un schéma simple comme des bottes en feutre, qui ne nécessite rien des chaînes de blocs en interaction:

  • Prise en charge des contrats intelligents avec au moins une succursale
  • Les deux chaînes de blocs doivent prendre en charge les mêmes algorithmes de hachage (n'oubliez pas de vérifier la longueur du secret)
  • Timelocks.


À première vue, on peut déjà dire à l’échange «au revoir, notre rencontre était une erreur», mais elle n’était pas là.

Pour tous ses mérites, les solutions de swap atomique ne frappent pas avec la liquidité. En grande partie parce que dans la paire de BTC-USD la plus populaire, la partie fiduciaire n'était pas complètement symbolisée.
Le succès de l'USDT a généré une vague de pièces stables au format ERC20 pour tous les goûts, du USDC gardien au DAI le plus algorithmique.

Par conséquent, pour simplifier, nous soutenons en outre qu'Alice vend des Bobcoins à Bob pour certains jetons ERC20, et nous espérons le succès des stabilisateurs, car nous avons beaucoup plus de problèmes techniques.

La vitesse


Bitcoin et Ethereum seuls ne sont pas trop rapides, mais ici, nous devons d'abord attendre un dépôt avec toutes les confirmations, puis le second.

Tout cela parce qu'au début, le participant gagne de l'argent, qui connaît le secret, et l'adversaire attend la finalité et ne transfère ensuite sa part.

De plus, nous avons affaire à un actif très volatil, de sorte que pendant ce temps, le cours peut changer considérablement et changer les conditions n'est pas facile.

Confidentialité


Tout échange laisse des artefacts sur les deux chaînes de blocs. Un observateur attentif peut remarquer les mêmes hachages dans les contrats intelligents et conclure logiquement qu'un accord a été conclu ici, à partir duquel de nombreuses conclusions peuvent être tirées du taux de change à la taxe.

Lorsque l'échange connaît vos affaires - c'est extrêmement désagréable, quand tout le monde le sait - c'est doublement désagréable.

Convivialité


Le cheval blockchain en général et l'éther en particulier. Voyons quels mouvements corporels le vendeur et l'acheteur devront effectuer.

Du point de vue du vendeur, tout est relativement simple: il suffit de transférer Bitcoin vers une adresse p2sh. Avec l'éther, tout est beaucoup plus délicat.

Le contrat
Considérons un contrat de swap en moyenne gigab:

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

Attention! N'utilisez pas cela et d'autres contrats d'un article sur la production, ils sont écrits uniquement à des fins de démonstration. Surtout celui-ci .

  • Bob doit appeler la méthode d' approve sur le contrat de jeton, donnant au contrat d'échange l'accès à ses jetons
  • Bob crée un swap et un contrat à l'aide de la méthode transferFrom prend les jetons d'expéditeur à son adresse
  • Alice en withdraw révèle un secret et le contrat appelle le transfer

La plupart des portefeuilles et des approve ne prennent pas en charge les jetons d' approve , et pour une bonne raison.

Les utilisateurs eux-mêmes se trompent souvent et transfèrent simplement des jetons au contrat, après quoi les jetons sont simplement perdus. Les commentaires sur Etherscan sont pleins de misérables gémissants.

Et pour appeler un contrat, vous devez payer une commission en ETH, donc les deux participants doivent les approvisionner avant le début de la transaction, et peu de gens veulent le faire.

Support de gaz


Pour commencer, cela vaut la peine de retirer le chèque de l'expéditeur dans la mesure du possible et de supposer que nous avons quelqu'un qui souffre d'un excès de gaz et cause des contrats pour tout le monde.

Contrat amélioré
 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); } } 


Dualisme de clé de contrat et EIP 712


Comme nous le savons, l'adresse à l'antenne peut être un contrat ou un sujet, c'est-à-dire une clé.
L'occupation principale de la clé est de signer tous les messages.

Nous pouvons utiliser le contrat Bob comme expéditeur, qui effectue toutes les passes nécessaires, avant de vérifier la signature de la clé Bob.

Désormais, n'importe qui peut parrainer une commission membre, mais seul celui qui connaît la clé prend la décision.

Contrat Bob
 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 dispose d'une norme EIP 712 pour travailler avec les signatures de structures de données complexes. Vous pouvez en savoir plus à ce sujet sur le blog du portefeuille Metamask.

Diviser et conquérir


Souvent, le scénario de piratage d'un contrat Ethereum ressemble à ceci:

  • Le participant verse des fonds au contrat
  • Prend ensuite l'argent
  • Quelque chose ne va pas
  • Un attaquant prend de l'argent encore et encore

Si nous revenons à notre premier exemple, quelque chose ne va pas si l'énigme est un ensemble d'octets vide.

Comment voler un million
Créer un échange avec un hachage 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
C'est sha256 de 0x0000000000000000000000000000000000000000000000000000000000000000
Nous passons le secret et récupérons nos jetons
Nous le repassons et prenons les étrangers, tout cela parce que 0 = 0

En créant un contrat distinct pour chaque transaction, nous pouvons isoler les contrats au niveau EVM.

Mais ce n'est pas tout: chaque transaction a désormais sa propre adresse, à laquelle vous pouvez transférer des jetons depuis n'importe quel portefeuille ou échange.

Contrats abandonnés et create2


Mais maintenant, pour chaque transaction, nous devons créer un contrat et attendre que l'acheteur y transfère la «cryptofening» de la main-d'œuvre. Dans le schéma «contrats du matin, argent du soir», il y a toujours un risque que l'acheteur tombe, et l'éther a déjà été dépensé pour créer le contrat.

Est-il possible de gagner de l'argent le matin et des octets le soir?

Dans le hard fork de Constantinople, les développeurs EIP 1014 ont ajouté une instruction create2 qui crée un nouveau contrat à une adresse déterministe

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

O Where

  • adresse - adresse du contrat d'usine
  • sel - un certain nombre, dont nous apprendrons la signification dans la prochaine série
  • init_code - contrat bytecode et paramètres constructeur.

L'usine
L'instruction ne fonctionne que par l'assemblage, donc l'usine semble un peu intimidante:

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

Votre code de contrat peut être obtenu via 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); 

En raison d'un soutien limité en solidité, le gaz pour le contrat peut ne pas être calculé correctement en raison de certaines subtilités de l'éther.

Il est particulièrement agréable qu'en cas de pénurie de gaz, le contrat tombe avec une erreur interne, sans informer qu'il n'y avait pas assez de gaz, comme on pouvait s'y attendre.

Maintenant, nous pouvons transférer des jetons vers des contrats sans les créer à l'avance et jusqu'à ce que nous les publions sur le réseau, personne ne devinera exactement ce que fait le contrat.

Le corbeau ne picorera pas le corbeau


Il est clair que les trucs d'un tel enfant n'arrêteront pas un véritable analyste, en particulier celui qui a reçu de bons investissements dans la lutte contre les ennemis du régime de blanchiment d'argent, et après avoir créé le contrat, il verra toujours un hachage.

Comment s'assurer que le hachage ne s'allume pas?

Nous transférons le swap lui-même à la chaîne: les participants échangent des signatures pour être transférés vers un contrat de swap, puis le secret est divulgué en privé.

Pas à pas
Deux "multisig" sont créés, desquels vous pouvez retirer des fonds si vous avez les signatures d'Alice et Bob.

Afin de se déconnecter l'un des participants n'est pas devenu une tragédie, nous ajoutons le bon vieux timeout.

Alice et Bob font des dépôts en parallèle

  • Alice fait un secret et donne à Bob le hachage du secret et la signature de la transaction, qui transfère les bitcoins à l'adresse de swap
  • Bob donne à Alice une signature sur le retrait de jetons sur un contrat de swap avec un hachage caché.
  • Alice révèle à Bob le secret.


À ce moment, l'harmonie s'ensuit: Alice et Bob peuvent conclure l'accord à tout moment. Dans un environnement aussi convivial, ils peuvent échanger des signatures pour retirer de l'argent à leur adresse finale.

Pour un observateur extérieur, il semble que l'argent ait passé un contrat avec une multi-signature 2 sur 2.

Et un tel schéma permet également aux deux parties d'effectuer un dépôt en même temps, car le secret est déjà constitué après toutes les confirmations.

Niveau 2


Étant donné que nous pouvons retirer de l'argent à une seule adresse et ne pas publier une transaction intermédiaire, rien ne nous empêche de retirer de l'argent à plusieurs adresses et d'effectuer un nombre illimité de transactions intermédiaires. Non pas que c'était un ensemble nécessaire pour un échange, mais si vous avez commencé à collecter un échange, il est difficile de s'arrêter.

Maintenant, Alice et Bob pourront se retourner avec puissance et main. Par exemple, calculez automatiquement le prix moyen en échangeant Satoshi par seconde, ou connectez simplement directement le teneur de marché et le destinataire de la liquidité.

Pas à pas
  • Le vendeur fait un secret et donne à l'acheteur un hachage de la signature secrète et de la transaction où une partie des fonds est transférée à l'adresse d'échange p2sh et le reste est retourné à l'adresse du vendeur
  • L'acheteur transmet une signature permettant de retirer les jetons sur le swap et la livraison à l'adresse du destinataire.
  • Le vendeur révèle un secret
  • L'histoire se répète avec un nouveau secret, tandis qu'au swap et à la remise s'ajoute la sortie précédemment achetée à l'adresse de l'acheteur et déjà payée à l'adresse du vendeur


Nous avons maintenant accès au trading P2P à grande vitesse, l'essentiel est de surveiller l'heure et de conclure l'affaire avant l'expiration.

Cependant, après avoir légèrement ajusté nos contrats, nous pouvons donner à nos chaînes une immortalité, ce qui simplifiera grandement la création d'un réseau pour nous.

Mais nous en parlerons dans la prochaine série.

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


All Articles