Skip to main content

JSON-RPC and dev mode

Quantum exposes standard Ethereum JSON-RPC on port 8545 (HTTP) and 8546 (WebSocket), with a small surface of Quantum-specific extensions. The intent is maximum compatibility: most read endpoints work unchanged with ethers, viem, and other clients. Write endpoints work too, but only for Quantum transactions (EIP-2718 type 0x7A) — there is no legacy / 1559 / 2930 / 4844 / 7702 transaction support.

Standard endpoints

# Check chain ID
curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'

# Get block by number
curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest", true],"id":1}'

# Get transaction by hash
curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0x..."],"id":1}'

Block headers carry a synthetic timestampMillis = timestamp * 1000 + timestampMillisPart for clients that want sub-second precision. The standard timestamp field is still the second-level value, so existing tooling sees a normal Ethereum-shaped response.

Quantum-specific endpoints

# Consensus status
curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"consensus_status","params":[],"id":1}'

Additional endpoints exposed for the Quantum chain are documented alongside the chain spec; the standard eth_* and net_* namespaces work as expected for reads.

Dev mode

cargo run --bin quantum-reth -- node --dev --http.api all brings up a single-validator devnet. Dev mode:

  • Auto-generates keys.
  • Creates a single-validator set.
  • Prefunds 10 ML-DSA-44 derived accounts with 10,000 QBIT each.
  • Selects marshal::standard (single node).

Dev account derivation is deterministic:

seed_i = sha256("quantum-ml-dsa-dev-" + i) for i in 0..9
sk_i, pk_i = MlDsa::generate_from_seed(seed_i)
addr_i = keccak256(pk_i)[12..]
balance = 10,000 QBIT

These keys are deterministic and public — never use them in production.

Wallet configuration

When adding Quantum as a custom network in MetaMask or other wallets:

  • Currency Symbol: QBIT
  • Decimals: 18

The currency symbol is wallet-side configuration, not an on-chain setting (it lives in chainspec/chain.toml).

Multi-node localnet

The minimum Coding-variant localnet is 4 validators (N ≥ 4 selects marshal::coding, N = 1 selects marshal::standard, N ∈ {2, 3} is rejected):

cargo run --bin quantum-reth -- localnet init --nodes 4 --output ./localnet

localnet init prints one launch command per node — copy each into a separate terminal. If you script the launches with background &, insert sleep 0.1 between launches to avoid the commonware-p2p bind race.

Footprint guidance

Recommended: build with --release if your laptop has under 32 GB of RAM. Debug-build steady-state at empty blocks is roughly:

  • ~10 GB total RSS (≈ 2.5 GB per node × 4)
  • < 1 core total CPU

Real transaction load grows the numbers. Measured outbound bandwidth at N=4 and N=8 (both Standard and Coding variants) lives in Benchmarks.

Submitting Quantum transactions

The composite tx envelope cannot be built by ethers or viem out of the box — they don't know about EIP-2718 type 0x7A. Use the bundled CLI:

# Bootstrap a new account (first-use registration, creates key_id = 0)
cargo run --bin quantum-send-tx -- bootstrap \
--rpc-url http://localhost:8545 \
--dev-index 0 --fill

# Normal transaction
cargo run --bin quantum-send-tx -- send \
--rpc-url http://localhost:8545 \
--dev-index 0 --fill \
--to 0x... --value 1000000000000000000

# Add co-signer to key_id = 0
cargo run --bin quantum-send-tx -- update-key-auth \
--rpc-url http://localhost:8545 \
--dev-index 0 --fill \
--key-id 0 \
--primary-pubkey 0x... --primary-scheme 1 \
--new-cosigner-pubkey 0x... --cosigner-scheme 2

# Remove co-signer (requires current cosigner sig)
cargo run --bin quantum-send-tx -- update-key-auth \
--rpc-url http://localhost:8545 \
--dev-index 0 --fill \
--key-id 0 \
--primary-pubkey 0x... --primary-scheme 1 \
--cosigner-type p256 --cosigner-dev-index 0 \
--new-cosigner-pubkey "" --cosigner-scheme 0

# Add a new key lane (key_id = 1)
cargo run --bin quantum-send-tx -- add-key \
--rpc-url http://localhost:8545 \
--dev-index 0 --fill \
--key-id 1 \
--primary-pubkey 0x... --primary-scheme 1 \
--permission 0

--dev-index selects a deterministic dev signing keypair (not a key lane). Bootstrap is always primary-only. Co-signer activation is a separate update-key-auth step. The --sender flag supports decoupled account-lane targeting where the signer key does not derive to the sender address.

Lifecycle submission note. bootstrap, add-key, remove-key, and update-key-auth depend on transient bootstrap / auth / lifecycle context written during real transaction validation. RPC simulation rejects those selectors, so use the explicit lifecycle commands instead of send / sign or eth_call.

Key management operations map

CLI commandKeyVault operationDescription
bootstrapbootstrapKey()First-use registration — creates key_id = 0 as FullAccess primary-only
add-keyaddKey(...)Add a new key lane — requires FullAccess auth (create-only, not for updates)
remove-keyremoveKey(...)Remove an existing key lane — requires FullAccess auth (last FullAccess key cannot be removed)
update-key-authupdateKeyAuth(...)Update auth material for an existing key — self-scoped (auth_key_id == target_key_id)
send / sign(regular tx)Normal transaction — rejects KeyVault lifecycle selectors

Co-signer policy and Scoped delegated permissions are orthogonal controls: a key can independently have co-signer hedging (per-key auth-method policy) and / or Scoped permission restrictions (contract / method / allowance delegation). These are configured separately and coexist.

ERC-20 token operations

The CLI also wraps common ERC-20 flows so you don't need to write Solidity bytecode by hand for testing:

# Deploy MintableERC20 (owner-gated mint / burn)
cargo run --bin quantum-send-tx -- erc20-deploy \
--rpc-url http://localhost:8545 --dev-index 0 --fill \
--name "MultiVM Token" --symbol "MVM" --decimals 18 --initial-supply 1000000

# Read-only query
cargo run --bin quantum-send-tx -- erc20-info \
--rpc-url http://localhost:8545 \
--contract 0x<addr> --balance-of 0x<holder>

# Mint (owner only)
cargo run --bin quantum-send-tx -- erc20-mint \
--rpc-url http://localhost:8545 --dev-index 0 --fill \
--contract 0x<addr> --recipient 0x<to> --amount 10000

# Transfer
cargo run --bin quantum-send-tx -- erc20-transfer \
--rpc-url http://localhost:8545 --dev-index 0 --fill \
--contract 0x<addr> --recipient 0x<to> --amount 100

# Burn from sender's balance
cargo run --bin quantum-send-tx -- erc20-burn \
--rpc-url http://localhost:8545 --dev-index 0 --fill \
--contract 0x<addr> --amount 500

# Transfer ownership
cargo run --bin quantum-send-tx -- erc20-transfer-ownership \
--rpc-url http://localhost:8545 --dev-index 0 --fill \
--contract 0x<addr> --new-owner 0x<new_owner>

--amount is specified in whole tokens and automatically scaled by 10 ^ decimals. erc20-deploy prints the deployed contract address to stdout.

Snapshot and follow-mode

# Sync from a trusted RPC endpoint (no consensus participation)
cargo run --bin quantum-reth -- node --follow ws://127.0.0.1:8561

# Snapshot export (stopped or disposable fresh-node datadirs)
cargo run --bin quantum-reth -- snapshot export \
--datadir /path/to/data --output snapshot

# Snapshot import
cargo run --bin quantum-reth -- snapshot import \
--archive snapshot.tar.lz4 --datadir /path/to/data

Fresh nodes initialize new datadirs with the current storage layout. Snapshot export / import expects the v2 layout (db/, static_files/, and rocksdb/) and is intended for stopped or disposable fresh-node datadirs rather than in-place migration of legacy v1 data.

PathBackendStores
db/MDBXCanonical hot state and other core execution data
static_files/Static file segmentsReceipts, transaction senders, account / storage changesets
rocksdb/RocksDBHistory indices, transaction-hash lookups