Saltar al contenido principal

Guía Cross-VM

QoreChain ejecuta EVM, SVM y CosmWasm en paralelo, y el módulo x/crossvm permite que una sola cuenta nativa invoque un contrato en cualquiera de ellos. El SDK proporciona un ayudante de alto nivel createCrossVMClient para construir, firmar y difundir estas llamadas, incluso empaquetando varias en una transacción atómica a través de las tres VM, además de ayudantes de lectura tipados para seguir el estado de los mensajes. El enrutamiento EVM→nativo iniciado desde dentro de la EVM aún se ejecuta en la cadena a través del precompilado del puente cross-VM en @qorechain/evm.

Llamadas cross-VM unificadas

createCrossVMClient envuelve MsgCrossVMCall (URL de tipo /qorechain.crossvm.v1.MsgCrossVMCall) para que nunca tengas que construir a mano un { typeUrl, value } ni codificar una carga útil por tu cuenta. El emisor del cliente es la dirección del TxClient conectado; sourceVm toma por defecto el valor "evm".

import { createClient, createCrossVMClient } from "@qorechain/sdk";

const client = createClient({ network: "testnet", endpoints: { rpc, rest } });
const tx = await client.connectTx(signer);
const xvm = createCrossVMClient(tx);

// Call an EVM contract from a native account — the payload is ABI-encoded.
const { messageId, result } = await xvm.call({
sourceVm: "cosmwasm",
targetVm: "evm",
targetContract: "0xToken",
evm: { abi: erc20Abi, functionName: "transfer", args: ["0xRecipient", 1n] },
});

VMType es uno de "evm" | "cosmwasm" | "svm" (también exportado como el array VM_TYPES).

Codificación de la carga útil por VM

Elige exactamente una forma de carga útil por llamada:

FormaCodificación
{ payload: Uint8Array | Hex }bytes en bruto, pasados sin cambios
{ evm: { abi, functionName, args } }codificada en ABI con encodeFunctionData de viem (selector + args)
{ cosmwasm: object }JSON.stringify y luego bytes UTF-8 (la convención de mensaje de ejecución de CosmWasm)
{ svm: { data: Uint8Array | Hex } }bytes en bruto (un blob de instrucción SVM)

La ruta EVM importa viem de forma diferida, por lo que el par opcional viem solo se necesita cuando realmente usas una carga útil { evm: ... }.

Solo construcción (sin conexión)

buildCall devuelve el EncodeObject sin difundirlo: práctico para inspección, para agrupar a mano o para firmar en otro lugar. (Las cargas útiles EVM se codifican en ABI de forma asíncrona, así que para esas usa call/callAtomic, o precodifica y pasa { payload }.)

const msg = xvm.buildCall({
targetVm: "svm",
targetContract: "Prog...",
svm: { data: new Uint8Array([1, 2, 3]) },
});

Transacciones atómicas a través de tres VM

callAtomic empaqueta varios mensajes MsgCrossVMCall en un único cuerpo de transacción para que se ejecuten de forma atómica bajo una sola firma: el titular de las tres VM. Una firma, llamadas a través de EVM + SVM + CosmWasm que aterrizan todas juntas o ninguna:

const { messageIds, result } = await xvm.callAtomic([
{
targetVm: "evm",
targetContract: "0xToken",
evm: { abi: erc20Abi, functionName: "transfer", args: ["0xRecipient", 2n] },
},
{ targetVm: "svm", targetContract: "Prog...", svm: { data: instructionBytes } },
{ targetVm: "cosmwasm", targetContract: "qor1c...", cosmwasm: { ping: {} } },
]);

Volver a leer un mensaje

getMessage lee un mensaje cross-VM por id, prefiriendo el cliente de consulta tipado y recurriendo al método JSON-RPC qor_getCrossVMMessage:

import { connectQueryClients } from "@qorechain/sdk";

const queries = connectQueryClients(rpcClient);
const reader = createCrossVMClient(tx, { query: queries.crossvm });

const msg = await reader.getMessage(messageId);

Lectura del estado de los mensajes cross-VM

@qorechain/sdk exporta envoltorios REST tipados sobre x/crossvm:

import {
createClient,
getCrossVmMessage,
getPendingCrossVmMessages,
getCrossVmParams,
} from "@qorechain/sdk";

const client = createClient({
endpoints: { rest: "https://rest.testnet.example" },
});

// A single message by id.
const msg = await getCrossVmMessage(client.rest, messageId);

// All pending messages.
const pending = await getPendingCrossVmMessages(client.rest);

// Module parameters.
const params = await getCrossVmParams(client.rest);

Estos devuelven formas tipadas: CrossVmMessage, CrossVmMessageResponse, PendingCrossVmMessagesResponse y CrossVmParamsResponse.

También puedes leer un mensaje a través del espacio de nombres JSON-RPC qor_:

const m = await client.qor.getCrossVMMessage(messageId);

El precompilado del puente EVM

El enrutamiento EVM→nativo se ejecuta en la cadena a través del precompilado del puente cross-VM, expuesto en @qorechain/evm:

import { PRECOMPILE_ADDRESSES } from "@qorechain/evm";

console.log(PRECOMPILE_ADDRESSES.crossVmBridge);
// 0x0000000000000000000000000000000000000901

Llama al precompilado desde un contrato de Solidity (o mediante viem) en esa dirección para enrutar un mensaje a la capa nativa, y luego sigue su estado con los ayudantes de lectura de arriba. Consulta la guía de EVM para ver la lista completa de precompilados.