El tercer artículo de nuestra serie que explica el modo Fusion se centra en el componente onchain de la resolución de swaps.

En los dos artículos anteriores de la serie discutimos, respectivamente, el concepto de resolutor y el componente fuera de la cadena del proceso de resolución de intercambio.

Continuaremos donde lo dejamos. Estamos en una etapa del proceso de resolución de intercambio en la que el backend del resolutor ha "decidido" completar una orden de Fusion que recibió del servicio de retransmisión de 1 pulgada, en un bloque determinado, con una cierta cantidad del activo intercambiado que se devolverá al usuario. Ahora, repasaremos la parte en cadena del proceso de resolución de swaps. Pero primero, describiremos a los participantes en este proceso.

La parte en cadena de la ejecución del intercambio Fusion implica interacciones bastante complejas entre las siguientes entidades de blockchain:

Un aviso muy importante: en algunos casos (no siempre), un resolutor realiza varios llenados en un lote, hasta 32. Normalmente, hay varios saldos de tokens en el contrato de trabajo del resolutor y el backend puede tomar varias órdenes del "flujo". que proporciona el retransmisor y realizar una secuencia de rellenos.

Repasaremos el siguiente escenario.

Un resolutor seleccionó 3 pedidos potencialmente lucrativos del retransmisor para ejecutar:

  • 100 DAI por al menos 0,6 WETH

  • 0,6 WETH por al menos 100 DAI

  • 0,01 WBTC para al menos 36 UNI

El objetivo comercial del solucionador es ejecutar los 3 intercambios de manera que los usuarios obtengan al menos la cantidad que esperaban. Dejaremos de lado las posibles estrategias de ganancias de los resolutores y simplificaremos los cálculos para que puedas entender la idea general.

Ahora, el backend proporciona información sobre los pedidos seleccionados al contrato del trabajador. ¿Qué pasa después?

NB: este cuadro es una continuación de uno del artículo dedicado al componente fuera de la cadena de la resolución de swaps. Pero, para simplificar la comprensión, comenzamos desde el paso 1.

Paso 1

El contrato de trabajo (o billetera) llama al método settleOrders() del contrato de liquidación de 1 pulgada, entregando la información del pedido en un formato comprimido liviano de bytes; Los argumentos calldata y tokensAndAmounts se utilizan para almacenar esta información.

Aquí puede que notes algunos detalles interesantes:

  • rateBump proviene del cotizador y determina efectivamente la rentabilidad. Es la diferencia porcentual entre el monto actual de la subasta y el monto mínimo de la subasta. Por ejemplo, si el valor rateBump es 4_000_000 y auctionEndAmount (retorno mínimo) es 500, el monto actual de la subasta es 700.

  • totalFee es una tarifa que todos los resolutores deben pagar a 1inch Foundation (Importante: actualmente esta función no se utiliza; los resolutores no pagan ninguna tarifa a 1inch Foundation).

  • limitOrderProtocol es una instancia del protocolo que se declara en el contrato de liquidación a través de una interfaz de Solidity respectiva. Se utiliza para llamar a este contrato desde el contrato de liquidación.

Paso 2

El contrato de liquidación llama al método fillOrderTo() del contrato de orden limitada, entregando los datos de una de las 3 órdenes de la lista, digamos, 100 DAI por al menos 0,6 WETH:

  • Interacción: contiene información de que hay 2 órdenes más en bloque que deberán ejecutarse posteriormente.

  • Hacer o recibir cantidades: literalmente, cuánto pagar o cuánto recibir. Sólo una de estas cantidades puede ser distinta de cero. Si configurasmakingAmount, especificas cuánto te gustaría recibir como resolutor. Alternativamente, al configurar TakingAmount, determinas cuánto te gustaría vender como resolutor. Uno se calculará en base a otro.

  • Destino: la dirección del contrato del trabajador que recibirá los tokens de origen.

Pasos 3-4

El contrato de orden limitada llama al contrato de token de origen para transferir el monto del swap del usuario al contrato de trabajador del resolutor, utilizando la interfaz ERC20 Solidity.

Una parte de ensamblaje que no es muy legible por humanos, forma datos de llamada y llama al contrato de token. Las piezas de ensamblaje del contrato se crean para la eficiencia del gas y la entrega de datos complejos.

Pasos 5-6

El contrato de orden limitada vuelve a llamar al contrato de liquidación con un método llamado  fillOrderInteraction() y envía interactiveData que contiene información sobre pedidos adicionales en el lote (la información recibida previamente en las interacciones). En el lado de la liquidación, el código decodifica interactiveData convirtiéndolos nuevamente en interacciones.

Si el lote no contiene más pedidos (escenario 1 a continuación), finaliza la interacción y llama al contrato de trabajo del resolutor "indicándole" que resuelva los pedidos. Esto será posible porque el contrato del trabajador importará nuestra interfaz llamada IResolver. En Solidity, las interacciones entre contratos generalmente se realizan de esta manera. Cubriremos lo que hace el trabajador en los pasos 16 y 17 a continuación.

Si quedan otras órdenes en el lote, el contrato de liquidación vuelve a llamar al contrato de orden limitada. Los dos contratos continuarán intercambiando datos hasta que se hayan liquidado todas las órdenes y se hayan cobrado todos los fondos de las cuentas de los usuarios (100 DAI, 0,6 WETH y 0,01 WBTC en nuestro ejemplo).

Paso 7

Ya casi hemos terminado. El contrato de resolución de trabajadores ha recibido todos los fondos de los usuarios a través de los contratos de liquidación de 1 pulgada y de orden limitada. ¡Ahora es el momento de resolver los pedidos!

Estas son las propiedades de las órdenes:

  • Orden 1: 100 DAI por al menos 0,6 WETH

  • Orden 2: 0,6 WETH por al menos 100 DAI

  • Orden 3: 0,01 WBTC por al menos 36 UNI

Parece que podemos, literalmente, hacer coincidir el orden 1 y el orden 2 sin ninguna acción adicional. Por lo tanto, enviaremos de forma segura 0,6 WETH recopilados del usuario que envió el pedido 2 al usuario que envió el pedido 1, y viceversa. Así, las órdenes 2 de 3 se han resuelto con fondos propios de los usuarios.

La última orden restante es un intercambio de 0,01 WBTC por 36 UNI. El contrato de trabajo no tiene ningún UNI en su saldo. Entonces, el contrato de trabajador llama al contrato de enrutador de agregación de 1 pulgada de la misma manera que lo hace cualquier usuario en un intercambio heredado. El backend del solucionador puede llamar a nuestra API de agregación para obtener una ruta óptima y pasársela al trabajador para su ejecución. El enrutador ejecuta este intercambio y entrega 36 UNI al solucionador.

En este ejemplo simplificado, el solucionador no ganó nada pero gastó fondos en gasolina para transferir datos entre contratos. En la vida real, como se mencionó anteriormente, el backend del solucionador tomaría en cuenta todos los gastos y se aseguraría de que las operaciones sean rentables para ellos y se mantengan dentro del marco proporcionado por el servicio de cotización. El solucionador también intentaría que el intercambio fuera lo más rentable posible para el usuario.

Pasos 8-11

Ahora, después de que el trabajador-resolvedor tenga los tokens de destino, debe responder a la devolución de llamada y transferirlos al contrato de liquidación. Pero espera… ¿Por qué no pueden enviar los tokens directamente al usuario?

No, no pueden hacerlo debido a la forma en que se implementa la arquitectura. Recuerde, el paso 5 de este flujo es una devolución de llamada al método fillOrderTo() llamado por el contrato de liquidación del contrato de orden limitada. Entonces, ¡la función aún se está ejecutando!

Dado que la persona que llama era el contrato de liquidación, en esta configuración, se considera que es el receptor de la orden. Por lo tanto, se supone que esta instancia recibe una respuesta del solucionador y los tokens transferidos. Luego, proporciona aprobación al contrato de orden limitada, que, a su vez, llama a transferFrom() al contrato de token de destino y el monto del intercambio finalmente llega a la billetera del usuario. ¡Hemos terminado!

Un ejemplo de Etherscan de la vida real

Como ejercicio final, revisemos un caso real de un intercambio de Fusion: 1INCH a DAI, resuelto por el solucionador Seawise y sus transferencias de tokens ERC20. Para obtener la mejor experiencia, debe comparar la imagen a continuación con el diagrama de arriba, haciendo coincidir los pasos.

En el paso 4, el contrato de orden limitada llama a transferFrom() en el contrato de token de 1INCH para transferir el token de origen desde la dirección del fabricante (0x90…9044) a la dirección de resolución.

Los pasos 5 y 6 no se reflejan en esta lista porque no implican ninguna transferencia de tokens ERC20.

En el paso 7, Seawise, como solucionador, intercambia 1 PULGADA por DAI en el grupo Uniswap como fuente de liquidez.

En el paso 8, Seawise transfiere DAI al contrato de liquidación de 1 pulgada.

Los pasos 9 y 10 también se omiten aquí porque se trata de respuestas de devolución de llamada internas entre los contratos del resolutor y de 1 pulgada.

Finalmente, en el paso 11, el contrato de liquidación de 1 pulgada transfiere los tokens de destino al fabricante.

No dude en explorar esta transacción en Etherscan:

https://etherscan.io/tx/0x55e621337837f4f69f0c398ad5e9072a24811bbfd8cb2b208d621b940c9689b5