Sending Messages
Send messages to programs — the core interaction primitive.
Sending Messages
Messages are the fundamental way to interact with Vara.eth programs. Every user action — whether a token transfer, a game move, or a state query — is a message sent to a program's Mirror contract on Ethereum.
Message Structure
| Field | Description |
|---|---|
payload | Encoded method call and arguments (SCALE or ABI-encoded) |
value | Optional ETH amount (wei) sent to the program |
callReply | Whether to request an on-chain reply |
Two Sending Paths
Vara.eth offers two distinct paths for sending messages, each with different trade-offs:
| Path | How | Cost | Latency | Use Case |
|---|---|---|---|---|
| Ethereum-side | Transaction to Mirror contract on L1 | ETH gas + wVARA | ~12s (L1 block) | On-chain settlement, value transfers |
| Vara.eth-side (Injected) | Direct to validator nodes | No ETH gas | Sub-second | Pre-confirmations, fast UX |
sequenceDiagram
participant User
participant Mirror as Mirror Contract<br/>(Ethereum L1)
participant Executors as Executor Network
participant Router as Router Contract<br/>(Ethereum L1)
rect rgb(230, 245, 255)
Note over User,Router: Path 1: Ethereum-side (Classic L1 Transaction)
User->>Mirror: sendMessage(payload, value)<br/>[Pays ETH gas]
Mirror->>Mirror: Emit MessageQueueingRequested
Executors->>Mirror: Observe event
Executors->>Executors: Execute WASM program
Executors->>Executors: Sign result (FROST)
Executors->>Router: commitBatch(stateTransition)
Router->>Mirror: Update stateHash
Mirror-->>User: StateChanged event<br/>[~12s total]
end
rect rgb(255, 243, 224)
Note over User,Router: Path 2: Vara.eth-side (Injected Transaction)
User->>Executors: send() via RPC<br/>[No ETH gas]
Executors->>Executors: Execute WASM immediately
Executors->>Executors: FROST signature
Executors-->>User: Pre-confirmation<br/>[Sub-second]
Note over Executors,Router: Later: batch settlement to L1
Executors->>Router: commitBatch(stateTransition)
Router->>Mirror: Update stateHash
endWhen to Use Each Path
Ethereum-side: On-chain value transfer, Solidity composability, L1 receipts. Vara.eth-side: Instant feedback for users (Web2-like UX) when immediate L1 settlement is not required.
Both paths are supported by the @vara-eth/api SDK.
→ RPC API
Ethereum-Side: Mirror Contract
CLI
ethexe tx send-message "$PROGRAM_ID" "0x..." 0 \
--ethereum-rpc "$RPC" \
--ethereum-router "$ROUTER" \
--sender "$SENDER"TypeScript SDK
import { getMirrorClient } from '@vara-eth/api';
const mirror = getMirrorClient(programId, signer, publicClient);
// Send message (payload encoded via sails-js)
const tx = await mirror.sendMessage(payload, 0n);
await tx.send();
// Wait for reply
const { waitForReply } = await tx.setupReplyListener();
const { payload: replyPayload, replyCode, value } = await waitForReply;Vara.eth IDEA
Vara.eth IDEA provides a visual interface for sending messages — no code required. Open your program, attach an IDL, and call methods from the WRITE tab directly in the browser. → IDEA Guide
Etherscan (with ABI)
If the program was deployed with ABI, navigate to the Mirror on Etherscan (or Hoodi Etherscan for testnet), go to "Write as Proxy", and call methods directly.
From Solidity
IMirror mirror = IMirror(mirrorAddress);
mirror.sendMessage(payload, false);Vara.eth-Side: Injected Transactions
Injected transactions are sent directly to Vara.eth validator nodes, bypassing Ethereum entirely. They are signed with your Ethereum private key but submitted off-chain — no ETH gas costs, sub-second execution.
This is the primary mechanism for pre-confirmations.
import { VaraEthApi, WsVaraEthProvider } from '@vara-eth/api';
const api = new VaraEthApi(new WsVaraEthProvider('ws://vara-eth-node:9944'), ethereumClient);
// Create and send injected transaction
const injected = await api.createInjectedTransaction({
destination: programId,
payload: encodedPayload,
value: 0n,
});
// Send and wait for reply with FROST signature
const promise = await injected.sendAndWaitForPromise();
await promise.validateSignature(); // Verify validator signaturesMessage Lifecycle
User sends tx → Mirror queues → Executors detect → WASM executes → Batch commits → State updated- User sends a transaction to the Mirror contract on Ethereum L1
- Mirror emits
MessageQueueingRequestedevent with the payload - Executors observe the event and queue the message for processing
- The program's WASM code executes the message handler
- Results (state transition, replies, events) are included in the next batch
- The Router commits the batch to Ethereum, updating the Mirror's
stateHash
Handling Replies
On-Chain Replies
Set callReply = true when sending. The program's reply is emitted as a Reply event on the Mirror when the batch is committed.
// Listen for replies
mirror.on('Reply', (payload, value, replyTo, replyCode) => {
if (replyCode === '0x00000000') {
// Success — decode payload
}
});Pre-Confirmed Replies (Off-Chain)
For instant feedback, use injected transactions via Vara.eth RPC and wait for the signed promise:
const injected = await api.createInjectedTransaction({
destination: programId,
payload: encodedPayload,
value: 0n,
});
const promise = await injected.sendAndWaitForPromise();
await promise.validateSignature();
// Decode promise.payloadSending with Value
Ether Value (via sendMessage)
Programs can also receive native Ether. The sendMessage function on the Mirror is payable:
// Send message with Ether
const mirror = new ethers.Contract(mirrorAddress, mirrorAbi, signer);
await mirror.sendMessage(payload, false, {
value: ethers.parseEther('0.1'), // Send 0.1 ETH
});wVARA vs ETH
Sending a message with sendMessage transfers ETH (Owned Balance). Funding execution requires wVARA
top-up to Executable Balance.
Gas Considerations
As a user, you only pay ETH gas for the L1 transaction to the Mirror. You do not pay for the off-chain execution — that's covered by the program's Executable Balance (the reverse gas model).
Typical gas costs on Ethereum L1:
| Operation | Gas |
|---|---|
sendMessage | ~60,000-100,000 gas |
sendReply | ~60,000-100,000 gas |
executableBalanceTopUp | ~50,000-80,000 gas |