Ganchos EVM IBC

Descripción general

Los ganchos EVM, implementados como middleware IBC, desempeñan un papel fundamental a la hora de facilitar las llamadas de contratos entre cadenas que implican transferencias de tokens. Esta capacidad es particularmente crucial para los intercambios entre cadenas, ya que proporciona un mecanismo sólido para el comercio descentralizado entre diferentes redes blockchain. La clave de esta funcionalidad es el memocampo en los paquetes de transferencia ICS20 e ICS721, como se introdujo en IBC v3.4.0.

Formato de ejecución de contrato EVM

Antes de sumergirnos en el formato de metadatos de IBC, echemos un vistazo al formato de datos del enlace y abordemos qué campos debemos configurar. El EVM MsgCallse define aquí y otros tipos se definen aquí .

// HookData defines a wrapper for evm execute message
// and async callback.
type HookData struct {
 // Message is a evm execute message which will be executed
 // at `OnRecvPacket` of receiver chain.
 Message evmtypes.MsgCall `json:"message"`

 // AsyncCallback is a callback message which will be executed
 // at `OnTimeoutPacket` and `OnAcknowledgementPacket` of
 // sender chain.
 AsyncCallback *AsyncCallback `json:"async_callback,omitempty"`
}

// AsyncCallback is data wrapper which is required
// when we implement async callback.
type AsyncCallback struct {
 // callback id should be issued form the executor contract
 Id            uint64 `json:"id"`
 ContractAddr  string `json:"contract_addr"`
}

// MsgCall is a message to call an Ethereum contract.
type MsgCall struct {
 // Sender is the that actor that signed the messages
 Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"`
 // ContractAddr is the contract address to be executed.
 // It can be cosmos address or hex encoded address.
 ContractAddr string `protobuf:"bytes,2,opt,name=contract_addr,json=contractAddr,proto3" json:"contract_addr,omitempty"`
 // Hex encoded execution input bytes.
 Input string `protobuf:"bytes,3,opt,name=input,proto3" json:"input,omitempty"`
}

Así que detallamos de dónde queremos obtener cada uno de estos campos:

  • Remitente: No podemos confiar en el remitente de un paquete IBC, la cadena de contraparte tiene plena capacidad de mentir al respecto. No podemos arriesgarnos a que este remitente sea confundido con un usuario o dirección de módulo en particular en Initia. Entonces reemplazamos el remitente con una cuenta para representar al remitente con el prefijo del canal y un prefijo de módulo evm. Esto se hace configurando el remitente en Bech32(Hash(Hash("ibc-evm-hook-intermediary") + channelID/sender)), donde channelId es la identificación del canal en la cadena local.

  • ContractAddr: este campo debe obtenerse directamente de los metadatos del paquete ICS-20.

  • Entrada: este campo debe obtenerse directamente de los metadatos del paquete ICS-20.

Entonces nuestro mensaje de llamada evm construido que ejecutamos se verá así:

msg := MsgCall{
 // Sender is the that actor that signed the messages
 Sender: "init1-hash-of-channel-and-sender",
 // ContractAddr is the contract address to be executed.
 // It can be cosmos address or hex encoded address.
 ContractAddr: packet.data.memo["evm"]["message"]["contract_addr"],
 // Hex encoded execution input bytes.
 Input: packet.data.memo["evm"]["message"]["input"],
}

Estructura del paquete ICS20

Entonces, dados los detalles anteriores, propagamos la estructura de datos del paquete ICS20 implícita. ICS20 es JSON nativo, por lo que usamos JSON para el formato de nota.

{
  //... other ibc fields that we don't care about
  "data": {
    "denom": "denom on counterparty chain (e.g. uatom)", // will be transformed to the local denom (ibc/...)
    "amount": "1000",
    "sender": "addr on counterparty chain", // will be transformed
    "receiver": "ModuleAddr::ModuleName::FunctionName",
    "memo": {
      "evm": {
        // execute message on receive packet
        "message": {
          "contract_addr": "0x1",
          "input": "hex encoded byte string",
        },
        // optional field to get async callback (ack and timeout)
        "async_callback": {
          "id": 1,
          "contract_addr": "0x1"
        }
      }
    }
  }
}

Un paquete ICS20 tiene el formato correcto para evmhooks si se cumple lo siguiente:

  • memono esta en blanco

  • memoes JSON válido

  • memotiene al menos una clave, con valor"evm"

  • memo["evm"]["message"]tiene exactamente cinco entradas, "contract_addr"y"input"

  • receiver== "" || receiver== "dirección_del_módulo::nombre_del_módulo::nombre_de_la_función"

Consideramos que un paquete ICS20 está dirigido a evmhooks si se cumple todo lo siguiente:

  • memono esta en blanco

  • memoes JSON válido

  • memotiene al menos una clave, con nombre"evm"

Si un paquete ICS20 no está dirigido a evmhooks, evmhooks no hace nada. Si un paquete ICS20 se dirige hacia evmhooks y tiene un formato incorrecto, evmhooks devuelve un error.

Flujo de ejecución

Ganchos previos a la evm:

  • Asegúrese de que el paquete IBC entrante sea criptográficamente válido

  • Asegúrese de que el paquete IBC entrante no haya agotado el tiempo de espera.

En ganchos evm, ejecución previa del paquete:

  • Asegúrese de que el paquete esté formateado correctamente (como se define anteriormente)

  • Edite el receptor para que sea la cuenta del módulo IBC codificada

En ganchos evm, publique la ejecución del paquete:

  • Construya el mensaje evm como se definió anteriormente

  • Ejecutar mensaje evm

  • si el mensaje evm tiene error, devuelve ErrAck

  • de lo contrario, continúe a través del middleware

Devolución de llamada asíncrona

Es posible que un contrato que envía una transferencia IBC necesite escuchar el ACK de ese paquete. Para permitir que los contratos escuchen el acuse de recibo de paquetes específicos, proporcionamos devoluciones de llamada de acuse de recibo. El contrato que desea recibir una devolución de llamada debe implementar dos funciones.

  • ibc_ack

  • ibc_timeout

interface IIBCAsyncCallback {
    function ibc_ack(uint64 callback_id, bool success) external;
    function ibc_timeout(uint64 callback_id) external;
}

Además, cuando un contrato realiza una solicitud de transferencia de IBC, debe proporcionar datos de devolución de llamada asíncronos a través del campo de nota.

  • memo['evm']['async_callback']['id']: la identificación de devolución de llamada asíncrona se asigna desde el contrato. luego se pasará como argumento de ibc_acky ibc_timeout.

  • memo['evm']['async_callback']['contract_addr']: La dirección del módulo que define la función de devolución de llamada.

Conclusión

El gancho EVM representa un avance en la interoperabilidad, ya que permite funcionalidades fluidas entre cadenas y mejora la utilidad de las transferencias de tokens. Al aprovechar el gancho EVM, los desarrolladores pueden iniciar interacciones contractuales complejas en diferentes cadenas, fomentando nuevos casos de uso y aplicaciones. Este desarrollo no solo simplifica las barreras técnicas previamente asociadas con las comunicaciones entre cadenas, sino que también allana el camino para ecosistemas blockchain más integrados y eficientes. A medida que esta tecnología madure, sin duda desbloqueará un mayor potencial para aplicaciones descentralizadas, contribuyendo a una adopción más amplia y a la eficacia operativa de las tecnologías blockchain.

Last updated