Le troisième article de notre série expliquant le mode Fusion se concentre sur le composant onchain de la résolution des swaps.
Dans les deux articles précédents de la série, nous avons discuté respectivement du concept de résolveur et du composant hors chaîne du processus de résolution de swap.
Reprenons là où nous nous sommes arrêtés. Nous sommes à une étape du processus de résolution de swap où le backend du résolveur a « décidé » d'exécuter une commande Fusion qu'il a reçue du service de relais 1 pouce, dans un certain bloc, avec une certaine quantité de l'actif échangé à restituer au utilisateur. Passons maintenant à la partie en chaîne du processus de résolution des swaps. Mais d’abord, nous décrirons les participants à ce processus.
La partie en chaîne de l'exécution du swap Fusion implique des interactions assez complexes entre les entités blockchain suivantes :

Un avis très important : dans certains cas (pas toujours), un résolveur effectue plusieurs remplissages en un seul lot, jusqu'à 32. Normalement, il y a plusieurs soldes de jetons dans le contrat de travail du résolveur et le backend peut prendre plusieurs commandes du « flux ». que le relayeur fournit, et effectuez une séquence de remplissages.
Nous allons passer en revue le scénario suivant.
Un résolveur a sélectionné 3 commandes potentiellement lucratives du relais à exécuter :
100 DAI pour au moins 0,6 WETH
0,6 WETH pour au moins 100 DAI
0,01 WBTC pour au moins 36 UNI
L'objectif commercial du résolveur est d'exécuter les 3 échanges de manière à ce que les utilisateurs obtiennent au moins le montant attendu. Nous laisserons de côté les stratégies de gains possibles des résolveurs et simplifierons les calculs afin que vous puissiez comprendre l’idée générale.
Désormais, le backend fournit des informations sur les commandes sélectionnées au contrat de travail. Que se passe-t-il ensuite ?
NB : ce graphique est la suite de celui de l'article dédié au composant offchain de la résolution des swaps. Mais, pour simplifier la compréhension, nous partons de l’étape 1.

Étape 1
Le contrat de travail (ou portefeuille) appelle la méthode settleOrders() du contrat de règlement 1inch, fournissant les informations de commande dans un format d'octets compressé léger ; Les arguments calldata et tokensAndAmounts sont utilisés pour stocker ces informations.
Ici, vous remarquerez peut-être quelques détails intéressants :
rateBump provient du coteur et détermine efficacement le rendement. Il s'agit de la différence en pourcentage entre le montant actuel de l'enchère et le montant minimum de l'enchère. Par exemple, si la valeur rateBump est 4_000_000 et auctionEndAmount (retour min.) est de 500, le montant actuel de l'enchère est de 700.
totalFee est des frais que tous les résolveurs doivent payer à la Fondation 1inch (Important : actuellement cette fonctionnalité n'est pas utilisée - les résolveurs ne paient aucun frais à la Fondation 1inch).
limitOrderProtocol est une instance du protocole déclaré dans le contrat de règlement via une interface Solidity respective. Il est utilisé pour appeler ce contrat à partir du contrat de règlement.

Étape 2
Le contrat de règlement appelle la méthode fillOrderTo() du contrat d'ordre limité, fournissant les données de l'une des trois commandes de la liste - disons, 100 DAI pour au moins 0,6 WETH :
Interaction - ceci contient des informations selon lesquelles il y a 2 commandes supplémentaires en gros qui devront être exécutées par la suite.
Faire ou prendre des montants – littéralement combien payer ou combien obtenir. Un seul de ces montants peut être non nul. Si vous définissez makingAmount, vous spécifiez le montant que vous souhaitez recevoir en tant que résolveur. Alternativement, en définissant TakingAmount, vous déterminez combien vous souhaitez vendre en tant que résolveur. L'un sera calculé en fonction de l'autre.
Target - l'adresse du contrat de travail qui recevra les jetons source.

Étapes 3-4
Le contrat d'ordre limité appelle le contrat de jeton source pour transférer le montant du swap de l'utilisateur vers le contrat de travail du résolveur, à l'aide de l'interface ERC20 Solidity.
Une partie d'assemblage peu lisible par l'homme forme des données d'appel et appelle le contrat de jeton. Les pièces d’assemblage du contrat sont créées pour l’efficacité du gaz et la fourniture de données complexes.

Étapes 5 à 6
Le contrat à ordre limité rappelle le contrat de règlement avec une méthode appelée fillOrderInteraction() et envoie des interactiveData contenant des informations sur les autres commandes du lot (les informations précédemment reçues lors des interactions). Du côté du règlement, le code décode les données interactives et les reconvertit en interactions.
Si le lot ne contient plus de commandes (scénario 1 ci-dessous), il finalise l’interaction et appelle le contrat de travail du résolveur « en lui disant » de résoudre les commandes. Cela sera possible car le contrat de travail importera notre interface appelée IResolver. Dans Solidity, les interactions entre contrats se font généralement de cette manière. Nous verrons ce que fait le travailleur aux étapes 16 et 17 ci-dessous.
S'il reste d'autres commandes dans le lot, le contrat de règlement rappelle à nouveau le contrat à ordre limité. Les deux contrats continueront à échanger des données jusqu'à ce que toutes les commandes soient réglées et que tous les fonds aient été collectés sur les comptes des utilisateurs (100 DAI, 0,6 WETH et 0,01 WBTC dans notre exemple).

Étape 7
Nous avons presque terminé. Le contrat travailleur-résolveur a reçu tous les fonds des utilisateurs via les contrats de règlement 1 pouce et d'ordre limité. Il est maintenant temps de résoudre les commandes !
Voici les propriétés des commandes :
Commande 1 : 100 DAI pour au moins 0,6 WETH
Commande 2 : 0,6 WETH pour au moins 100 DAI
Commande 3 : 0,01 WBTC pour au moins 36 UNI
Il semble que nous puissions littéralement faire correspondre la commande 1 et la commande 2 sans aucune action supplémentaire. Nous allons donc simplement envoyer en toute sécurité 0,6 WETH collectés auprès de l’utilisateur qui a soumis la commande 2 à l’utilisateur qui a soumis la commande 1, et vice versa. Ainsi, les commandes 2 sur 3 ont été résolues avec les fonds propres des utilisateurs.
La dernière commande restante est un swap de 0,01 WBTC contre 36 UNI. Le contrat de travail ne comporte aucune UNI à son bilan. Ainsi, le contrat de travail appelle le contrat du routeur d'agrégation 1 pouce de la même manière que n'importe quel utilisateur le fait dans un échange existant. Le backend du résolveur peut appeler notre API d’agrégation pour obtenir un itinéraire optimal et le transmettre au travailleur pour exécution. Le routeur exécute cet échange et délivre 36 UNI au résolveur.
Dans cet exemple simplifié, le résolveur n’a rien gagné mais a dépensé des fonds en gaz pour transférer des données entre contrats. Dans la vraie vie, comme mentionné ci-dessus, le backend du résolveur prendrait en compte toutes les dépenses et s'assurerait que les transactions sont rentables pour elles et restent dans le cadre fourni par le service de cotation. Le résolveur essaierait également de rendre le swap le plus rentable possible pour l'utilisateur.
Étapes 8 à 11
Désormais, une fois que le travailleur résolveur a les jetons de destination, il doit répondre au rappel et les transférer vers le contrat de règlement. Mais attendez… Pourquoi ne peuvent-ils pas envoyer les jetons directement à l’utilisateur ?
Non, ils ne le peuvent pas en raison de la manière dont l’architecture est mise en œuvre. N'oubliez pas que l'étape 5 de ce flux est un rappel à la méthode fillOrderTo() appelée par le contrat de règlement au contrat à ordre limité. La fonction est donc toujours en cours d'exécution !
L’appelant étant le contrat de règlement, dans cette configuration, il est considéré comme le preneur de la commande. Par conséquent, cette instance est censée recevoir une réponse du résolveur et des jetons transférés. Ensuite, il approuve le contrat d'ordre limité, qui, à son tour, appelle transferFrom() au contrat de jeton de destination et le montant du swap atterrit finalement dans le portefeuille de l'utilisateur. Avaient fini!
Un exemple réel d'Etherscan
Comme dernier exercice, passons en revue un cas réel d'échange Fusion : 1INCH vers DAI, résolu par le résolveur Seawise, et ses transferts de jetons ERC20. Pour une expérience optimale, vous devez croiser l'image ci-dessous avec le diagramme ci-dessus, en faisant correspondre les étapes.

À l'étape 4, le contrat à ordre limité appelle transferFrom() sur le contrat de jeton 1INCH pour transférer le jeton source de l'adresse du fabricant (0x90…9044) vers l'adresse du résolveur.
Les étapes 5 et 6 ne figurent pas dans cette liste car elles n'impliquent aucun transfert de jeton ERC20.
À l'étape 7, Seawise, en tant que résolveur, échange 1INCH en DAI dans le pool Uniswap comme source de liquidité.
À l'étape 8, Seawise transfère le DAI vers le contrat de règlement de 1 pouce.
Les étapes 9 et 10 sont également ignorées ici car il s'agit de réponses de rappel internes entre les contrats du résolveur et de 1 pouce.
Enfin, à l'étape 11, le contrat de règlement 1inch transfère les jetons de destination au fabricant.
N'hésitez pas à explorer cette transaction sur Etherscan :
https://etherscan.io/tx/0x55e621337837f4f69f0c398ad5e9072a24811bbfd8cb2b208d621b940c9689b5
