Rivellum

Rivellum Portal

Checking...
testnet

Developer Getting Started Guide

Welcome to Rivellum development! This guide will help you set up your environment, run a local node, and build your first intent-based application.

šŸ”— API Reference: Explore all available endpoints interactively in the API Explorer with live testing and code examples.

Prerequisites

Required Software

  • Rust: 1.81+ with cargo

    rustup default stable
    rustup update
    
  • Node.js: 20+ with npm

    node --version  # Should be v20+
    npm --version
    
  • Git: For cloning the repository

Optional Tools

  • Docker: For running local devnets
  • Move CLI: For compiling Move contracts
  • VS Code: Recommended IDE with Rust and Move extensions

Quick Start (5 minutes)

1. Clone and Build

# Clone the repository
git clone https://github.com/rivellum/rivellum.git
cd rivellum

# Build all crates in release mode
cargo build --release

# Run tests to verify
cargo test --workspace

Expected build time: 2-5 minutes on modern hardware.

2. Start a Local Node

# Run with default configuration
.\target\release\rivellum-node.exe --config config\dev.toml

You should see:

[INFO] Starting Rivellum node...
[INFO] Network listening on /ip4/127.0.0.1/tcp/9000
[INFO] RPC server listening on 127.0.0.1:8545
[INFO] Node ready! ID: 12D3KooW...

3. Submit Your First Intent

Create my-intent.jsonl:

{"intent_id":"0x1234","from":"0xalice","nonce":0,"payload":{"Plain":[1,2,3]},"signature":"0xabc...","max_fee":1000}

Submit using CLI:

.\target\release\rivellum-node.exe intent submit my-intent.jsonl

Or using the TypeScript SDK:

import { RivellumClient } from '@rivellum/sdk';

const client = new RivellumClient('http://localhost:8545');
await client.submitIntent({
  from: '0xalice',
  payload: { type: 'transfer', to: '0xbob', amount: 100 },
});

Architecture Refresher

Before diving deeper, understand these core concepts:

  • Intents: User declarations of desired outcomes (not imperative transactions)
  • Batches: Groups of intents processed together for efficiency
  • Shards: Parallel execution contexts (Aurora Fabric)
  • Photon: BFT consensus algorithm with instant finality
  • PoUW: Proof-of-Useful-Work for ZK proof generation

See Architecture Overview for full details.

Development Workflow

Project Structure

rivellum/
ā”œā”€ā”€ crates/              # Rust workspace
│   ā”œā”€ā”€ rivellum-node/    # Main binary
│   ā”œā”€ā”€ rivellum-intents/ # Intent types & validation
│   ā”œā”€ā”€ rivellum-execution/ # Aurora Fabric execution
│   ā”œā”€ā”€ rivellum-ledger/  # State & storage
│   ā”œā”€ā”€ rivellum-network/ # P2P networking
│   ā”œā”€ā”€ rivellum-crypto/  # Cryptographic primitives
│   ā”œā”€ā”€ rivellum-zk/      # ZK proof system
│   ā”œā”€ā”€ rivellum-pouw/    # Proof-of-Useful-Work
│   └── ...
ā”œā”€ā”€ sdk/                 # TypeScript SDK
ā”œā”€ā”€ explorer/            # Block explorer UI
ā”œā”€ā”€ portal/              # Developer playground
ā”œā”€ā”€ contracts/           # Move smart contracts
ā”œā”€ā”€ config/              # Node configuration files
└── docs/                # Documentation (you are here!)

Configuration Files

Rivellum uses TOML configuration files in config/:

  • dev.toml: Local development (single node, mock ZK)
  • testnet.toml: Multi-node testnet
  • mainnet.example.toml: Production template
  • zk-real.toml: Enable real ZK proofs (requires prover)

Key settings:

chain_id = "devnet"

[network]
listen_addr = "127.0.0.1:9000"
bootstrap_peers = []
max_peers = 50

[rpc]
listen_addr = "127.0.0.1:8545"
max_concurrent_requests = 1000
request_timeout_secs = 30

[execution]
workers_per_committee = 4
max_queue_size = 50000
gas_limit = 1000000
lane_count = 4

[execution.sequencer]
window_k = 4
max_buffered_per_sender = 16
max_nonce_gap = 100

[events]
backend = "in_memory"
data_dir = "./data/events"
max_in_memory_events = 100000
durability = "async"

[startup]
seed_prefab_registry = true

Building Specific Crates

# Build only the node binary
cargo build --release --package rivellum-node

# Build with optimizations for size
cargo build --release --package rivellum-node --profile=release-small

# Check code without building
cargo check --workspace

# Run clippy linter
cargo clippy --workspace -- -D warnings

Running Tests

# Run all tests
cargo test --workspace

# Run tests for specific crate
cargo test --package rivellum-intents

# Run integration tests only
cargo test --test integration_tests

# Run with output
cargo test --workspace -- --nocapture

# Run specific test
cargo test test_intent_validation

Code Formatting

# Format all code
cargo fmt --all

# Check formatting without changes
cargo fmt --all -- --check

Working with Intents

Intent Structure

pub struct Intent {
    pub intent_id: IntentId,        // Unique identifier
    pub from: Address,               // Sender address
    pub nonce: u64,                  // Replay protection
    pub payload: PayloadKind,        // Plain or Encrypted
    pub signature: Signature,        // EdDSA signature
    pub max_fee: u64,                // Maximum fee willing to pay
}

Creating Intents Programmatically

Rust:

use rivellum_intents::{Intent, IntentId, PayloadKind};
use rivellum_crypto::{KeyPair, sign_intent};

let keypair = KeyPair::generate();
let intent = Intent {
    intent_id: IntentId::random(),
    from: keypair.public_key().to_address(),
    nonce: 0,
    payload: PayloadKind::Plain(vec![1, 2, 3]),
    signature: Signature::default(),  // Placeholder
    max_fee: 1000,
};

let signed = sign_intent(&intent, &keypair)?;

TypeScript SDK:

import { RivellumClient, Wallet } from '@rivellum/sdk';

const wallet = Wallet.fromMnemonic('your seed phrase...');
const client = new RivellumClient('http://localhost:8545');

const intent = await client.createIntent({
  from: wallet.address,
  payload: {
    type: 'custom',
    data: [1, 2, 3],
  },
  maxFee: 1000,
});

const signed = await wallet.signIntent(intent);
await client.submitIntent(signed);

Intent Types

Rivellum supports various built-in intent types:

  1. Transfer: Send tokens between accounts
  2. Contract Call: Invoke Move contract functions
  3. Contract Deploy: Deploy new Move modules
  4. Batch: Execute multiple operations atomically
  5. Custom: Application-specific payloads

Example transfer intent:

{
  type: 'transfer',
  to: '0xrecipient',
  amount: 100,
  token: '0x1::Coin::RIVL',  // Native token
}

Smart Contracts with Move

Setting Up Move Development

# Install Move CLI (if not already installed)
cargo install --git https://github.com/move-language/move move-cli

# Create new Move project
mkdir my-contract
cd my-contract
move new MyModule

Your First Move Contract

Create sources/Counter.move:

module MyAddress::Counter {
    use std::signer;

    struct Counter has key {
        value: u64,
    }

    public entry fun init(account: &signer) {
        move_to(account, Counter { value: 0 });
    }

    public entry fun increment(account: &signer) acquires Counter {
        let addr = signer::address_of(account);
        let counter = borrow_global_mut<Counter>(addr);
        counter.value = counter.value + 1;
    }

    public fun get_value(addr: address): u64 acquires Counter {
        borrow_global<Counter>(addr).value
    }
}

Compiling Move Contracts

# Compile to bytecode
move build

# Run Move unit tests
move test

# Generate documentation
move docgen

Deploying Contracts

Option 1: CLI

rivellum-node.exe contract deploy `
  --bytecode ./build/MyModule/bytecode_modules/Counter.mv `
  --sender 0xMyAddress

Option 2: SDK

import fs from 'fs';

const bytecode = fs.readFileSync('./build/MyModule/bytecode_modules/Counter.mv');
await client.deployContract({
  bytecode,
  sender: wallet.address,
});

Calling Contracts

await client.callContract({
  module: 'MyAddress::Counter',
  function: 'increment',
  args: [],
  sender: wallet.address,
});

const value = await client.view({
  module: 'MyAddress::Counter',
  function: 'get_value',
  args: [wallet.address],
});
console.log('Counter value:', value);

Using the TypeScript SDK

Installation

npm install @rivellum/sdk

Basic Usage

import { RivellumClient, Wallet } from '@rivellum/sdk';

// Connect to node
const client = new RivellumClient('http://localhost:8545');

// Create wallet from private key
const wallet = Wallet.fromPrivateKey('0x123...');

// Check balance
const balance = await client.getBalance(wallet.address);
console.log('Balance:', balance);

// Submit transfer intent
const txHash = await client.transfer({
  from: wallet.address,
  to: '0xrecipient',
  amount: 100,
  signer: wallet,
});

// Wait for finality
const receipt = await client.waitForFinality(txHash);
console.log('Finalized in block:', receipt.blockNumber);

Advanced SDK Features

Batch Intents:

const batch = client.createBatch();
batch.addTransfer({ to: '0xalice', amount: 50 });
batch.addTransfer({ to: '0xbob', amount: 50 });
batch.addContractCall({
  module: 'MyModule::MyContract',
  function: 'do_something',
  args: [42],
});

const txHash = await batch.submit(wallet);

Query State:

// Get account info
const account = await client.getAccount('0xaddress');
console.log('Nonce:', account.nonce);
console.log('Balance:', account.balance);

// Get batch by ID
const batch = await client.getBatch('0xbatchhash');
console.log('Intents:', batch.intents.length);
console.log('Status:', batch.status);

// Listen for events
client.on('batchFinalized', (batch) => {
  console.log('New batch finalized:', batch.id);
});

Local Development Tools

Interactive Playground

The web-based playground allows testing intents without a running node:

cd portal
npm install
npm run dev
# Open http://localhost:3000/playground

Features:

  • In-browser intent simulation
  • Account management
  • Contract deployment/testing
  • Batch execution visualization

Block Explorer

Monitor your local node in real-time:

cd explorer  
npm install
npm run dev
# Open http://localhost:3001

Shows:

  • Recent batches and intents
  • Account balances and nonces
  • Shard utilization
  • PoUW proof status

RPC API Testing

Use curl to test RPC endpoints directly:

# Get node info
curl http://localhost:8545/info

# Get account balance
curl -X POST http://localhost:8545/rpc `
  -H "Content-Type: application/json" `
  -d '{\"jsonrpc\":\"2.0\",\"method\":\"getBalance\",\"params\":[\"0xaddress\"],\"id\":1}'

# Submit intent
curl -X POST http://localhost:8545/rpc `
  -H "Content-Type: application/json" `
  -d '{\"jsonrpc\":\"2.0\",\"method\":\"submitIntent\",\"params\":[{...}],\"id\":1}'

Running a Multi-Node Devnet

For consensus testing, run multiple nodes:

# Start 3-node devnet with Docker
cd devnet
docker-compose up -d

# Check logs
docker-compose logs -f leader
docker-compose logs -f follower1
docker-compose logs -f follower2

# Shutdown
docker-compose down

Or manually:

# Terminal 1: Leader
rivellum-node.exe --config devnet\leader.toml

# Terminal 2: Follower 1
rivellum-node.exe --config devnet\follower1.toml

# Terminal 3: Follower 2  
rivellum-node.exe --config devnet\follower2.toml

Debugging Tips

Enable Verbose Logging

# In your config.toml
[node]
log_level = "debug"  # or "trace" for max verbosity

# Per-crate logging
[logging]
"rivellum_intents" = "debug"
"rivellum_execution" = "trace"
"rivellum_network" = "info"

Common Issues

Issue: Error: nonce mismatch Solution: Each intent must have nonce = previous_nonce + 1. Query current nonce:

curl http://localhost:8545/account/0xaddress | jq .nonce

Issue: Error: insufficient balance Solution: Check balance and ensure max_fee doesn't exceed available funds:

curl http://localhost:8545/account/0xaddress | jq .balance

Issue: Error: signature verification failed Solution: Ensure you're signing the intent correctly. The signature covers:

hash(intent_id || from || nonce || payload_hash || max_fee)

Issue: Node won't start - "Address already in use" Solution: Change listen ports in config or kill existing process:

Get-Process rivellum-node | Stop-Process

Using Rust Debugger

# Build with debug symbols
cargo build --package rivellum-node

# Run with lldb (or gdb on Linux)
rust-lldb .\target\debug\rivellum-node.exe -- --config config\dev.toml

Or use VS Code debugger with .vscode/launch.json:

{
  "type": "lldb",
  "request": "launch",
  "name": "Debug rivellum-node",
  "cargo": {
    "args": ["build", "--package=rivellum-node"]
  },
  "args": ["--config", "config/dev.toml"]
}

Performance Profiling

Benchmarking

# Run built-in benchmarks
cargo bench --package rivellum-intents

# Profile with flamegraph
cargo install flamegraph
cargo flamegraph --package rivellum-node -- --config config\dev.toml

Load Testing

# Generate 10,000 test intents
.\scripts\generate-test-intents.ps1 -Count 10000 -Output test-intents.jsonl

# Submit with parallel workers
.\scripts\load-test.ps1 -Intents test-intents.jsonl -Workers 10

Next Steps

Now that you have a working development environment:

  1. Build a dApp: See SDK Guide for full API reference
  2. Write Smart Contracts: Deep dive into Move Contracts
  3. Run a Prover: Learn PoUW Setup to earn rewards
  4. Deploy to Testnet: Follow Node Setup guide