Quick Start
Build and deploy your first Vara.eth program in 5 minutes.
Quick Start
This guide takes you from zero to a deployed program on Vara.eth testnet. You'll create a simple counter program, deploy it to Ethereum Hoodi, and interact with it.
Prerequisites
Rust toolchain, Sails CLI, and ethexe CLI installed. → Tools Install
1. Create a New Project
cargo sails new counter-app
cd counter-appThis scaffolds a new Sails program with the correct project structure.
2. Write Your Program
Open app/src/lib.rs and replace the contents with:
#![no_std]
use sails_rs::prelude::*;
// Program state
static mut COUNTER: i64 = 0;
// Service definition — your program's API
#[derive(Default)]
pub struct CounterService;
#[service]
impl CounterService {
/// Increment the counter and return the new value
pub fn increment(&mut self) -> i64 {
unsafe {
COUNTER += 1;
COUNTER
}
}
/// Decrement the counter and return the new value
pub fn decrement(&mut self) -> i64 {
unsafe {
COUNTER -= 1;
COUNTER
}
}
/// Read the current counter value
pub fn get(&self) -> i64 {
unsafe { COUNTER }
}
}
// Program entry point
#[derive(Default)]
pub struct CounterProgram;
#[program]
impl CounterProgram {
/// Constructor — called once when the program is initialized
pub fn init() -> Self {
Self
}
/// Expose the CounterService
pub fn counter(&self) -> CounterService {
CounterService
}
}Why static mut is acceptable here
In Vara.eth's actor model, each program processes messages sequentially (single-threaded execution per program), so
this simple static mut counter example does not have concurrent access. For production contracts and richer state,
prefer structured state patterns in Sails services.
Update Cargo.toml to enable ethexe support:
[package]
name = "counter-app"
version = "0.1.0"
edition = "2021"
[dependencies]
sails-rs = { version = "0.10.1", features = ["ethexe"] }
parity-scale-codec = { version = "3", default-features = false }
scale-info = { version = "2", default-features = false }3. Build
cargo build --releaseThis produces two artifacts in target/wasm32-gear/release/:
counter_app.opt.wasm— the compiled WASM binarycounter_app.idl— the Interface Definition Language file describing your program's API
4. Deploy to Testnet
Set up your environment:
# Insert your private key (testnet wallet only!)
ethexe key insert <YOUR_PRIVATE_KEY>
# Set variables for convenience
export RPC="wss://hoodi-reth-rpc.gear-tech.io/ws"
export ROUTER="0xBC888a8B050B9B76a985d91c815d2c4f2131a58A"
export SENDER="<YOUR_WALLET_ADDRESS>"Router Address Source
For the latest network addresses, always check Contract Addresses.
Upload the WASM code
ethexe tx upload target/wasm32-gear/release/counter_app.opt.wasm \
--watch \
--ethereum-rpc "$RPC" \
--ethereum-router "$ROUTER" \
--sender "$SENDER"This uploads your WASM as an EIP-4844 blob and requests code validation. Wait for the CODE_ID to appear in the output.
export CODE_ID="0x..." # Copy from outputCreate a program instance
ethexe tx create "$CODE_ID" \
--salt 0x0000000000000000000000000000000000000000000000000000000000000001 \
--ethereum-rpc "$RPC" \
--ethereum-router "$ROUTER" \
--sender "$SENDER"This deploys a Mirror contract on Ethereum representing your program. The output contains your PROGRAM_ID (Mirror address).
export PROGRAM_ID="0x..." # Copy from outputDeterministic Addressing
The --salt parameter makes the Mirror address deterministic. Use different salts to deploy multiple instances of the
same code. Address is computed as CREATE2(Router, keccak256(codeId, salt)).
Fund the program
Your program needs wVARA to pay for execution. Use the executableBalanceTopUp function on the Mirror contract via Etherscan, the SDK, or CLI.
Initialize the program
Send the first message to trigger the constructor:
ethexe tx send-message "$PROGRAM_ID" "0x..." 0 \
--ethereum-rpc "$RPC" \
--ethereum-router "$ROUTER" \
--sender "$SENDER"5. Interact with Your Program
Once initialized, anyone can send messages to your program. The Mirror contract on Ethereum accepts standard transactions.
Interact via:
- Etherscan — If you deployed with an ABI interface, methods appear under "Write as Proxy"
- CLI — Use
ethexe tx send-message - SDK — Use sails-js or
@vara-eth/apifrom your frontend
Read state
ethexe tx query "$PROGRAM_ID" \
--ethereum-rpc "$RPC" \
--ethereum-router "$ROUTER" \
--sender "$SENDER"What Just Happened?
You completed the core lifecycle:
- Build and upload code
- Create Mirror instance
- Fund executable balance
- Initialize and interact
Your program is now live on Ethereum via its Mirror address.
→ Full lifecycle details: Program Basics
→ API/design structure: Sails Workflow