Skip to main content

Cross-VM Interoperability

QoreChain's triple-VM architecture (EVM, CosmWasm, SVM) allows smart contracts on any virtual machine to communicate with contracts on any other VM. The x/crossvm module provides both synchronous and asynchronous messaging paths.

note

The endpoints below default to a local node. On mainnet, use the qorechain-vladi RPC endpoints (Cosmos RPC 26657, EVM JSON-RPC 8545); the testnet is qorechain-diana.


Architecture Overview

EVM (Solidity) CosmWasm (Rust/Wasm) SVM (BPF)
| | |
|--- sync (precompile) ->| |
| | |
|<-- async (EndBlocker) -|-- async (EndBlocker) ->|
| | |
|<------------ async (EndBlocker) ----------------|
PathDirectionTimingMechanism
SynchronousEVM to CosmWasmSame transactionPrecompile at 0x0000...0901
AsynchronousCosmWasm to EVMNext blockMsgCrossVMCall via EndBlocker
AsynchronousSVM to any VMNext blockMsgCrossVMCall via EndBlocker
AsynchronousAny to SVMNext blockMsgCrossVMCall via EndBlocker

Synchronous Path (EVM to CosmWasm)

The synchronous path uses an EVM precompile at address 0x0000000000000000000000000000000000000901. This allows Solidity contracts to call CosmWasm contracts and receive a response within the same transaction.

Solidity Example

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

interface ICrossVM {
function call(bytes calldata payload) external returns (bytes memory);
}

contract CrossVMCaller {
ICrossVM constant CROSSVM = ICrossVM(0x0000000000000000000000000000000000000901);

function callCosmWasmContract(
string memory cosmwasmAddr,
string memory executeMsg,
uint256 funds
) external returns (bytes memory) {
bytes memory payload = abi.encode(cosmwasmAddr, executeMsg, funds);
return CROSSVM.call(payload);
}
}

The precompile executes the CosmWasm contract immediately and returns the result. Gas cost: 50,000 base + execution cost.


Asynchronous Path

All other cross-VM directions use the asynchronous message queue. Messages are submitted in one block and processed by the EndBlocker in the next block.

CLI

# CosmWasm to EVM
qorechaind tx crossvm call \
--source-vm cosmwasm \
--target-vm evm \
--target-contract 0x1234...abcd \
--payload '{"method":"transfer","params":["0xRecipient",100]}' \
--from mykey \
-y

# SVM to CosmWasm
qorechaind tx crossvm call \
--source-vm svm \
--target-vm cosmwasm \
--target-contract qor1contractaddr... \
--payload '{"execute":{"action":{}}}' \
--from mykey \
-y

# EVM to SVM (async)
qorechaind tx crossvm call \
--source-vm evm \
--target-vm svm \
--target-contract <program-id-base58> \
--payload '0a0b0c...' \
--from mykey \
-y

Message Lifecycle

Every cross-VM message transitions through a defined set of states:

Submitted --> Pending --> Executed
|
+--> Failed
|
+--> Timed Out
StateDescription
SubmittedMessage accepted into the queue
PendingAwaiting execution in the next EndBlocker pass
ExecutedTarget contract called successfully; response recorded
FailedTarget contract execution reverted; error recorded
Timed OutMessage exceeded queue_timeout_blocks without execution

Parameters

ParameterValueDescription
max_message_size65,536 bytesMaximum payload size per message
max_queue_size1,000Maximum pending messages in the queue
queue_timeout_blocks100Blocks before an unprocessed message times out

Events

The x/crossvm module emits the following events:

EventAttributesDescription
crossvm_requestmessage_id, source_vm, target_vm, target_contract, senderNew cross-VM message submitted
crossvm_responsemessage_id, status, resultMessage executed (success or failure)
crossvm_timeoutmessage_id, source_vm, target_vmMessage expired without execution

Subscribe to events via WebSocket:

wscat -c ws://localhost:26657/websocket
> {"jsonrpc":"2.0","method":"subscribe","params":["tm.event='Tx' AND crossvm_request.message_id EXISTS"],"id":1}

Querying Messages

CLI

# Query a specific message by ID
qorechaind query crossvm message <message-id>

# List all pending messages
qorechaind query crossvm pending

# List messages by sender
qorechaind query crossvm messages-by-sender <address>

JSON-RPC

curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "qor_getCrossVMMessage",
"params": ["<message-id>"],
"id": 1
}'

Response Format

{
"message_id": "crossvm-00000042",
"source_vm": "cosmwasm",
"target_vm": "evm",
"target_contract": "0x1234...abcd",
"sender": "qor1sender...",
"payload": "...",
"status": "executed",
"result": "0x...",
"submitted_height": 12345,
"executed_height": 12346
}

Design Considerations

Atomicity: Synchronous calls (EVM to CosmWasm via precompile) are atomic — if either side reverts, the entire transaction reverts. Asynchronous calls are not atomic across blocks; design your contracts to handle the Failed and Timed Out states gracefully.

Ordering: Messages in the queue are processed FIFO within each EndBlocker pass. There is no guaranteed ordering across different source VMs.

Payload encoding: The payload format depends on the target VM:

  • EVM targets: ABI-encoded function calls
  • CosmWasm targets: JSON-encoded execute messages
  • SVM targets: Hex-encoded BPF instruction data

Next Steps