A modern command line interface for interacting with the Quantus Network, featuring built-in quantum-safe wallet management and real blockchain operations using SubXT.
# Install the CLI tool
cargo install quantus-cli
# The binary will be available as `quantus`
quantus --help
# Clone and build
git clone https://github.com/Quantus-Network/quantus-cli
cd quantus-cli
cargo build --release
# The binary will be available as `quantus`
The CLI checks GitHub for newer releases and notifies you when one is available (the result is cached for a few hours, and the check is non-blocking and best-effort). You can update in place without visiting the releases page:
# Check whether a newer version is available (no install)
quantus update --check
# Download and install the latest release for your platform
quantus update
# Update without the confirmation prompt (useful in scripts)
quantus update --yes
# Install a specific version
quantus update --version 1.5.0
quantus update downloads the prebuilt binary for your platform from the
GitHub releases and
replaces the running executable. If the binary lives in a protected location
you may need to re-run with elevated privileges (e.g. sudo quantus update).
To disable the automatic "new version available" notice, set the
QUANTUS_NO_UPDATE_CHECK environment variable to any value.
Add to your Cargo.toml:
[dependencies]
# Full functionality (CLI + library)
quantus-cli = "0.1.0"
# Library only (smaller dependencies)
quantus-cli = { version = "0.1.0", default-features = false }
Start by exploring the available commands:
# Get help to see all available commands
quantus --help
# Explore specific command groups
quantus wallet --help
quantus send --help
quantus tech-collective --help
The CLI provides comprehensive help at every level, allowing you to discover functionality step by step.
The CLI provides comprehensive help at every level. Every command and subcommand supports --help:
quantus --help shows all available top-level commandsquantus <command> --help shows options for specific commandsquantus <command> <subcommand> --help shows options for subcommandsThis hierarchical help system allows you to discover available functionality step by step, starting from the main help and drilling down to specific command options.
Every command supports --verbose for detailed debugging information:
--verbose provides detailed execution logs, network calls, and internal state informationThese options work on every command:
--verbose / -v: Enable debug logging with detailed output--node-url <URL>: Specify node endpoint (default: ws://127.0.0.1:9944)--help / -h: Show help for any command or subcommandThe CLI uses a hierarchical structure:
quantus [GLOBAL_OPTIONS] <COMMAND> [COMMAND_OPTIONS] <SUBCOMMAND> [SUBCOMMAND_OPTIONS]
Structure: The CLI follows a consistent pattern where global options can be combined with any command and subcommand at any level of nesting.
Start with the main help and drill down to explore available functionality. The CLI provides helpful error messages and suggestions when you make mistakes, guiding you to the correct command syntax.
Common navigation patterns:
quantus --help to see all available commandsquantus <command> --help to explore specific command options--verbose to any command for detailed debugging information--node-url to connect to different nodes (defaults to localhost)The wormhole commands implement a ZK-proof-based privacy layer. Funds are sent to an unspendable account derived from a secret, a zero-knowledge proof is generated to prove ownership, and the proof is verified on-chain to mint equivalent tokens to an exit account -- breaking the on-chain link between sender and receiver.
quantus wormhole addressDerive the unspendable wormhole address from a secret. This is step one of a private transfer -- it shows the address you need to send funds to.
quantus wormhole address --secret-file ./secret.hex
--secret-file: File containing the 32-byte hex secret. On Unix the file must be a regular file owned by you with no group/other access (chmod 600), like --password-file.Output:
Wormhole Address
SS58: qDx...
Hex: 0x...
To fund this address:
quantus send --from <wallet> --to qDx... --amount <amount>
Then send funds using a standard transfer (the chain's WormholeProofRecorderExtension automatically records a transfer proof for any balance transfer):
quantus send --from crystal_alice --to qDx... --amount 100
quantus wormhole proveGenerate a ZK proof for an existing wormhole transfer. The proof demonstrates knowledge of the secret without revealing it.
quantus wormhole prove \
--secret-file ./secret.hex \
--amount 100000000000000 \
--exit-account <SS58-or-hex> \
--block 0x<block-hash> \
--transfer-count <count> \
--funding-account 0x<funding-account> \
--output proof.hex
--secret-file: File containing the 32-byte hex secret. On Unix the file must be a regular file owned by you with no group/other access (chmod 600), like --password-file.--exit-account: The destination address that will receive funds after on-chain verification (SS58 or 0x-prefixed hex).--block: Block hash where the transfer was included.--transfer-count: Transfer count from the NativeTransferred event.--output: Output file path for the hex-encoded proof (default: proof.hex).quantus wormhole aggregateAggregate multiple leaf proofs into a single recursive proof. The aggregation circuit pads with dummy proofs and shuffles to hide which slots are real.
quantus wormhole aggregate \
--proofs proof_1.hex proof_2.hex \
--output aggregated_proof.hex
--proofs: One or more hex-encoded proof files. The number must not exceed num_leaf_proofs from the circuit config.quantus wormhole verify-aggregatedSubmit an aggregated proof to the chain for on-chain verification. This is an unsigned extrinsic -- no wallet is needed.
quantus wormhole verify-aggregated --proof aggregated_proof.hex
ProofVerified and ExtrinsicFailed events and reports the result.quantus wormhole parse-proofInspect the public inputs of a proof file for debugging.
# Parse a leaf proof
quantus wormhole parse-proof --proof proof.hex
# Parse an aggregated proof
quantus wormhole parse-proof --proof aggregated_proof.hex --aggregated
# Parse and cryptographically verify locally
quantus wormhole parse-proof --proof aggregated_proof.hex --aggregated --verify
quantus wormhole multiroundRun an automated multi-round wormhole flow: fund -> prove -> aggregate -> verify on-chain, repeated over multiple rounds. This is the primary integration test for the wormhole system.
quantus wormhole multiround \
--num-proofs 4 \
--rounds 2 \
--amount 100000000000000 \
--wallet crystal_alice \
--password "" \
--keep-files \
--output-dir /tmp/wormhole_test
--num-proofs: Number of proofs per round (1 to num_leaf_proofs from circuit config, default: 2).--rounds: Number of rounds (default: 2). In intermediate rounds, exit accounts are the next round's wormhole addresses; in the final round, funds exit back to the wallet.--amount: Total amount in planck to randomly partition across proofs (default: 100 DEV).--wallet: Wallet name for funding (round 1) and final exit.--keep-files: Preserve proof files after completion (default: cleaned up).--output-dir: Directory for intermediate proof files (default: /tmp/wormhole_multiround).--dry-run: Show configuration and derived addresses without executing.Each round performs:
m/44'/189189189'/0'/<round>'/<index>'.After all rounds, the command verifies the wallet balance matches expectations (initial - fees).
quantus wormhole collect-rewardsCollect miner rewards from a wormhole address. Queries Subsquid for pending transfers, filters out already-spent nullifiers, generates ZK proofs, and submits withdrawal transactions.
# Collect all available rewards using a stored wallet
quantus wormhole collect-rewards --wallet my_wallet --password ""
# Collect a specific amount
quantus wormhole collect-rewards --wallet my_wallet --amount 50.0
# Use a mnemonic file (requires --destination; the phrase is never accepted on argv)
quantus wormhole collect-rewards \
--mnemonic-file ./mnemonic.txt \
--destination <SS58-address>
# Dry run to see available transfers without submitting
quantus wormhole collect-rewards --wallet my_wallet --dry-run
--wallet: Wallet name for HD derivation of the wormhole secret and default exit address.--mnemonic-file: Alternative to --wallet; derive wormhole secrets from the mnemonic in the file. On Unix the file must be a regular file owned by you with no group/other access (chmod 600), like --password-file.--secret-file: Alternative to --wallet/--mnemonic-file; file containing the direct 32-byte hex wormhole secret, with the same owner-only requirement on Unix.--destination: Destination address for withdrawn funds (required with --mnemonic-file or --secret-file, defaults to wallet address).--amount: Amount in DEV to withdraw (default: withdraw all available).--wormhole-index: Wormhole address index for HD derivation (default: 0).--subsquid-url: Subsquid indexer URL (default: https://sub2.quantus.com/v1/graphql).--dry-run: Show available transfers without submitting any transactions.--at-block: Use a specific block number for proofs instead of the latest block.quantus wormhole check-nullifierCheck whether nullifiers have been spent (consumed by a withdrawal). Useful for verifying if specific transfers have already been claimed.
# Check a single transfer count using a wallet
quantus wormhole check-nullifier --wallet my_wallet --transfer-counts 0
# Check a range of transfer counts
quantus wormhole check-nullifier --wallet my_wallet --transfer-counts 0-10
# Check using a secret file directly
quantus wormhole check-nullifier --secret-file ./secret.hex --transfer-counts 0-5
--wallet: Wallet name for HD derivation of the wormhole secret.--secret-file: File containing the 32-byte hex secret (alternative to --wallet). On Unix the file must be a regular file owned by you with no group/other access (chmod 600), like --password-file.--transfer-counts: Single number or range (e.g., 0-10) of transfer counts to check.--wormhole-index: Wormhole address index for HD derivation (default: 0).--subsquid-url: Subsquid indexer URL (default: https://sub2.quantus.com/v1/graphql).The airdrop commands find testnet addresses you own in the published reward
snapshot and claim their rewards. You prove ownership either by signing with an
ML-DSA-87 (Dilithium) key or with a ZK wormhole ownership proof; the payout is
credited to any account you choose.
Ownership is re-derived from your wallet, so old addresses are found even if the key-derivation scheme has changed since they were created. From a single wallet mnemonic the scan covers:
"Bitcoin seed" master (soft m/44'/189189'/N'/0/0 and hardened
m/44'/189189'/N'/0'/0' paths, plus account-only m/44'/189189'/N'), and the
current "Dilithium seed" HD tree — accounts 0..=8 by default, plus the
wallet's own stored derivation path if it was imported with a custom
--derivation-path."Dilithium seed" tree and the
legacy "Bitcoin seed" tree (including the pre-2026 master-node secret), at
paths m/44'/189189189'/0'/round'/index' for rounds 0..=8 and indexes
0..=16 by default.Wallets without a mnemonic (raw-seed imports) are matched on their current key only; cold wallets cannot be used. ML-DSA-65 wallets cannot sign Dilithium claims, but their mnemonic is still scanned for historical ML-DSA-87 and wormhole addresses.
quantus airdrop checkList snapshot rows owned by your wallet and/or an explicit wormhole secret. Read-only: nothing is signed or submitted.
quantus airdrop check --wallet my_wallet
# Also (or only) check an explicit wormhole secret
quantus airdrop check --wallet my_wallet --wormhole-secret-file ./secret.hex
quantus airdrop check --wormhole-secret-file ./secret.hex
# No mnemonic, seed, or secret file? Paste the secret at a hidden prompt
quantus airdrop check --wormhole-secret-prompt
Output:
Snapshot v1 (3f9c2a81be04) — 1234 rewarded addresses
2 snapshot match(es):
qDx... 150.00 QTC Resonance dilithium-v08-padded (dilithium) [claimable]
qDy... 75.50 QTC Planck wormhole-rate8-compact (wormhole) [claimable]
--wallet: Hot wallet used to derive Dilithium and HD wormhole addresses.--wormhole-secret-file: File with a 32-byte hex wormhole secret. On Unix
the file must be a regular file owned by you with no group/other access
(chmod 600), like --password-file.--wormhole-secret-prompt: Paste a 32-byte hex wormhole secret at a hidden
prompt instead — for users who only have the raw secret. Secrets are never
accepted as command-line values (they would leak into shell history and
process listings).--wormhole-index: Pin the HD wormhole address index instead of scanning
0..=16; every branch/round is still scanned.--scan-accounts: Highest Dilithium account index scanned per historical
keygen family (default: 8). Raise it if the wallet was created with a
higher account index.--scan-rounds: Highest wormhole branch/round component scanned (default:
8). Raise it if you ran wormhole multiround with more rounds.--server: Claim server base URL.quantus airdrop claimProve ownership of every match and submit the claims. Amounts come from the snapshot; the server verifies each proof and records the payout.
# Claim everything the wallet owns, paid out to the wallet's own account
quantus airdrop claim --wallet my_wallet
# Pay out to a different account (wallet name or SS58 address)
quantus airdrop claim --wallet my_wallet --to qDz...
# Claim from an explicit wormhole secret (requires --to)
quantus airdrop claim --wormhole-secret-file ./secret.hex --to qDz...
# Or paste the secret at a hidden prompt (requires --to)
quantus airdrop claim --wormhole-secret-prompt --to qDz...
# Inspect the exact payloads without submitting anything
quantus airdrop claim --wallet my_wallet --dry-run
For each match the CLI builds the appropriate proof:
Dilithium rewards are claimed with an ML-DSA-87 signature over
address ‖ payout account ‖ expiry, using your wallet's key or, for
historical matches, a key re-derived on the spot from the mnemonic with that
era's exact scheme (all secret material is wiped from memory after signing).
Wormhole rewards under the current scheme (wormhole-rate8-compact) are
claimed with a ZK ownership proof, so the secret itself is never sent.
Matches under older wormhole schemes are listed as not claimable yet and
skipped — the server does not accept them yet.
--to: Payout destination (wallet name or SS58). Defaults to --wallet's
own account; required when claiming with only a secret file.
--dry-run: Print the signed/proved claim payloads without POSTing.
All check flags (--wormhole-secret-file, --wormhole-secret-prompt,
--wormhole-index, --scan-accounts, --scan-rounds, --server) work the
same here.
The command exits non-zero if any claim fails, and prints a summary of recorded, skipped, and failed claims.
quantus airdrop payOperator command: pay out recorded (claimed but unpaid) rewards and mark them paid on the claim server. It fetches the server's unpaid list, presents every pending payout for review, batches the transfers into as few extrinsics as the chain's batch limit allows, and marks each claim paid once its batch is in a block.
# Review and pay everything pending, confirming interactively
quantus airdrop pay --from treasury_wallet --admin-token-file ./admin.token
# Air-gapped payout: any cold wallet works, one QR roundtrip per batch
quantus airdrop pay --from my_cold --admin-token-file ./admin.token
# See the full payout plan without touching the chain or the server
quantus airdrop pay --from treasury_wallet --dry-run
# Test the flow end-to-end by paying a single claim first
quantus airdrop pay --from treasury_wallet --admin-token-file ./admin.token --limit 1
# Or pay one specific rewarded address
quantus airdrop pay --from treasury_wallet --admin-token-file ./admin.token --only qRewarded1
# Unattended (skips the review prompt)
quantus airdrop pay --from treasury_wallet --yes \
--password-file ./pass --admin-token-file ./admin.token
Example review output:
3 recorded claim(s) awaiting payout:
qRewarded1 → qPayout1 [Apple-River-Stone-Cloud-Fox] 150.00 QTC dilithium-v08-padded (verified 2026-09-20 11:02 UTC)
qRewarded2 → qPayout2 [Maple-Tiger-Coral-Dawn-Iris] 75.50 QTC wormhole-rate8-compact (verified 2026-09-21 08:44 UTC)
qRewarded3 → qPayout3 [Cedar-Whale-Amber-Frost-Owl] 10.00 QTC dilithium-v10-padded (verified 2026-09-21 09:15 UTC)
Total: 235.50 QTC to 3 account(s); 1201 snapshot row(s) remain unclaimed.
Plan: 1 batch extrinsic(s) of up to 256 transfer(s) each.
Pay 235.50 QTC to 3 account(s) in 1 batch(es) from 'treasury_wallet'? [y/N]
Every destination address is shown with its human checkphrase (the same five-word phrase the wallet apps display), so payout accounts can be verified against the recipient out of band before confirming.
--from: Wallet that funds the payouts — hot or cold. Cold wallets follow
the standard QR signing flow, one roundtrip per batch extrinsic.--admin-token-file: File with the claim server's admin token (chmod 600), used for mark-paid. Falls back to the QUANTUS_AIRDROP_ADMIN_TOKEN
environment variable. Required up front, before anything is paid, so every
completed payout can be marked.--limit: Pay at most this many claims this run — --limit 1 to test the
whole flow on a single claim before paying the rest (a re-run pays the
remainder, since paid claims drop off /unpaid).--only: Pay only the given rewarded address(es) (repeatable). Errors if
an address has no recorded unpaid claim.--batch-size: Max transfers per batch extrinsic (default: the chain's
safe utility.batch limit).--tip: Optional tip per batch extrinsic.--yes: Skip the interactive review confirmation.--dry-run: Print the payout plan (rows, batches, raw amounts) without
submitting transfers or marking anything paid.--server: Claim server base URL.Safety properties: each batch is waited on until it is in a block before its
claims are marked paid, and a claim is only marked after its transfer
succeeded. If a mark-paid call fails after payment, the command prints the
affected addresses loudly and exits non-zero — mark them manually before
re-running, or those rows would be paid twice. If a batch fails, everything
already paid is already marked, but the failed batch's transaction may still go
through, so check the chain before re-running or those rows will be paid twice.
After all batches land, the command re-fetches /unpaid and verifies none of
the paid addresses are still listed, failing loudly if any are. Like
passwords, the bearer token is never accepted as a command-line value.
quantus developer build-circuitsBuild ZK circuit binaries from the qp-zk-circuits repository, then copy them to the CLI and chain directories. This is required whenever the circuit logic changes.
quantus developer build-circuits \
--num-leaf-proofs 2 \
--num-layer0-proofs 2 \
--chain-path ../chain
Add --skip-prover when you only need verifier artifacts:
quantus developer build-circuits \
--num-leaf-proofs 2 \
--num-layer0-proofs 2 \
--chain-path ../chain \
--skip-prover
--num-leaf-proofs: Number of leaf proofs per layer-0 aggregation.--num-layer0-proofs: Number of inner proofs per layer-1 aggregation.--chain-path: Path to the chain repo (default: ../chain).--skip-chain: Skip copying binaries to the chain directory.--skip-prover: Skip generating prover binaries.What it does (3 steps):
generated-bins/ directory.qp-wormhole-circuit-builder library directly to regenerate binary files in generated-bins/ (verifier.bin, common.bin, private_batch_verifier.bin, private_batch_common.bin, config.json, plus prover binaries unless --skip-prover is set).private_batch_common.bin, private_batch_verifier.bin, config.json) to chain/pallets/wormhole/ and touches the pallet source.After running, rebuild the chain (cargo build --release in the chain directory) so include_bytes!() picks up the new binaries.
quantus developer create-test-walletsCreate standard test wallets (crystal_alice, crystal_bob, crystal_charlie) with developer passwords for local testing.
quantus developer create-test-wallets
# Create a new quantum-safe wallet (default scheme: ml-dsa-65, HD path …/1')
quantus wallet create --name my_wallet
# ML-DSA-87 (HD path defaults to …/0' when --derivation-path is omitted)
quantus wallet create --name my_wallet_87 --scheme ml-dsa-87
# Create with an explicit derivation path
quantus wallet create --name my_wallet --derivation-path "m/44'/189189'/0'/0'/1'"
# Import from mnemonic (phrase is read from a hidden prompt — never pass it on the CLI)
quantus wallet import --name recovered_wallet
# Import from a mnemonic file (owner-only on Unix, chmod 600; never pass the phrase on argv)
quantus wallet import --name recovered_wallet --mnemonic-file ./mnemonic.txt
# Import as ML-DSA-87 (same secure prompt)
quantus wallet import --name recovered_87 --scheme ml-dsa-87
# Create from raw 32-byte seed
quantus wallet from-seed --name raw_wallet --seed <64-hex-chars>
# List wallets
quantus wallet list
# View wallet details
quantus wallet view --name my_wallet
# Export mnemonic
quantus wallet export --name my_wallet --format mnemonic
Pair the CLI with an air-gapped signer — a Keystone 3 hardware wallet or the Quantus cold wallet app. The CLI stores only the address (watch-only); every transaction is signed on the device by exchanging QR codes.
# Import by scanning the device's address QR with the laptop camera
quantus wallet import-cold --name my_cold
# Or paste the address directly (no camera needed)
quantus wallet import-cold --name my_cold --address qz...
# Any extrinsic command works with a cold wallet: the CLI shows the
# transaction as a QR, then scans the device's animated signature QR
quantus send --from my_cold --to <address> --amount 10.5 --wait-for-transaction
quantus multisig approve --from my_cold --address qz... --proposal-id 0
The signing flow (identical for every command — commands don't know whether the wallet is hot or cold; the shared submit stage branches on the wallet type):
ur:quantus-sign-request QR
(animated if the payload is large). Scan it with the cold wallet, review
the details on the device, and press Enter in the CLI.Notes:
runtime update,
tech-referenda submit-with-preimage) do one QR roundtrip per extrinsic.--cold-response-in <file> (or - for stdin)
reads the response UR parts (one per line) instead of scanning, and the
hidden --cold-request-out <file> writes the request UR parts for
scripted flows. Both are global flags that work with any command. Builds
without the default camera feature (cargo build --no-default-features)
support only this path.quantus developer cold-sign-sim command, which plays the cold
wallet side using a local hot wallet.NEAR accepts ML-DSA-65 access keys and signatures from protocol version 85,
so a Quantus ML-DSA-65 wallet (quantus wallet create --scheme ml-dsa-65)
can be the sole key on a NEAR account. ML-DSA-87 wallets are rejected: NEAR
defined ML-DSA-65 only. --network is testnet or mainnet, served by
FastNear RPC, or one of their known endpoints (FastNear or rpc.*.near.org);
any other endpoint goes in --rpc-url.
# The wallet's key in NEAR text form (ml-dsa-65:<base58>) and its on-chain handle
quantus near show-key --wallet my65
# Create a sub-account whose only access key is the wallet's key
quantus near create-account --new-account vault.alice.testnet --wallet my65 \
--parent-credentials ~/.near-credentials/testnet/alice.testnet.json
# Verify the key list from chain state
quantus near keys --account vault.alice.testnet --wallet my65
# Spend from it
quantus near send --wallet my65 --account vault.alice.testnet --to bob.testnet --amount 1.5
# Sputnik DAO membership: propose and vote
quantus near dao propose-transfer --dao treasury.sputnik-dao.testnet --account vault.alice.testnet \
--wallet my65 --receiver bob.testnet --amount 10
quantus near dao vote --dao treasury.sputnik-dao.testnet --account vault.alice.testnet \
--wallet my65 --id 3 --vote approve
quantus near sign-cold signs a transaction prepared by
near-cli-rs with a cold wallet over
the same QR transport as Quantus extrinsics. This covers every contract
call — swaps, lending, staking — not just the commands above.
# 1. Build the unsigned transaction offline with near-cli-rs. The signer key is
# the cold wallet's ML-DSA-65 key; nonce and block hash come from
# `near account view-account-summary` / `view-access-key` or any RPC.
near contract call-function as-transaction v2.ref-finance.near storage_deposit \
json-args '{"registration_only": true}' prepaid-gas '30 Tgas' attached-deposit '0.125 NEAR' \
sign-as vault.alice.near network-config mainnet \
sign-later --signer-public-key ml-dsa-65:<base58> --nonce <nonce+1> --block-hash <recent> \
save-to-file unsigned.json
# 2. Sign it on the cold wallet: the CLI shows the transaction as a QR,
# then scans the device's signature QR and verifies it against the stored
# address before producing a signed transaction.
quantus near sign-cold --unsigned-tx @unsigned.json --wallet my_cold --network mainnet --out signed.b64
# 3. Submit with near-cli-rs, or add --send in step 2 to submit directly.
near transaction send-signed-transaction file-with-base64-signed-transaction signed.b64 \
network-config mainnet send
The device sees the decoded transaction (signer, receiver, nonce, every
action) and signs only if the transaction's declared key is its own. The CLI
accepts the response only if that key also hashes to the cold wallet's stored
address, so a transaction built for someone else's key cannot be signed as
--wallet my_cold. The hidden quantus developer cold-sign-sim command
answers NEAR requests too, using a local ML-DSA-65 hot wallet, for end-to-end
testing without a device.
A cold wallet file holds only an SS58 address, which is a hash of the key and
cannot be turned back into the 1952-byte ML-DSA-65 public key NEAR needs.
Import the key once from the QR the cold wallet app shows (account → Show
public key → NEAR); after that every quantus near command accepts the cold
wallet, signing over QR where a hot wallet would sign locally.
# Scan the key export QR (or pass it as text with --key ml-dsa-65:<base58>)
quantus near import-cold-key --wallet my_cold
# Now the same commands as for a hot wallet, no password involved
quantus near show-key --wallet my_cold
quantus near create-account --new-account vault.alice.testnet --wallet my_cold \
--parent-credentials ~/.near-credentials/testnet/alice.testnet.json
quantus near send --wallet my_cold --account vault.alice.testnet --to bob.testnet --amount 1.5
The import is refused unless the exported key hashes to the wallet's stored
address, so a QR from another device cannot be attached to my_cold. The
key is re-checked against the address every time it is read from the wallet
file. For testing without a device, quantus developer cold-sign-sim --wallet <hot65> --export-near-key --response-file export.ur writes the same QR
payload a device would show.
# Simple transfer (default: submit and return once the node accepts the extrinsic)
quantus send --from crystal_alice --to <address> --amount 10.5
# Wait for inclusion in a best block
quantus send --from crystal_alice --to <address> --amount 10.5 --wait-for-transaction
# Wait for finalization (implies --wait-for-transaction)
quantus send --from crystal_alice --to <address> --amount 10.5 --finalized-tx
# Optional advanced: add a tip to prioritize the transaction
quantus send --from crystal_alice --to <address> --amount 10 --tip 0.1
# With manual nonce
quantus send --from crystal_alice --to <address> --amount 10 --nonce 42
Transaction status terms:
submitted: accepted by the node, but not yet known to be in a blockincluded: observed in a best blockfinalized: observed in a finalized block--amount and --tip use exact decimal parsing based on the chain's configured decimals. Malformed values, negative values, over-precision, or values that would round to zero are rejected. --tip is optional and omitted by default.
# From a JSON file (amounts are raw smallest-unit integers)
quantus batch send --from crystal_alice --batch-file transfers.json
# Generate identical test transfers
quantus batch send --from crystal_alice --count 10 --to <address> --amount 1.0
# Check batch limits
quantus batch config --limits
Schedule transfers with a time delay, allowing cancellation before execution.
# Schedule with default delay
quantus reversible schedule-transfer --from alice --to bob --amount 10
# Schedule with custom delay
quantus reversible schedule-transfer-with-delay --from alice --to bob --amount 10 --delay 3600
# Cancel a pending transfer
quantus reversible cancel --tx-id 0x<hash> --from alice
Configure reversibility settings for an account (interceptor + delay).
# Check status
quantus high-security status --account <address>
# Enable high-security with an interceptor
quantus high-security set --interceptor <address> --delay-seconds 3600 --from alice
# Show accounts you guard
quantus high-security entrusted --from alice
Treasury is the account that receives a configurable portion of mining rewards. No special spend/proposal flow — just view its state.
# Show treasury account and balance
quantus treasury info
Treasury-funded vesting schedules. Funds vest linearly between start and end (nothing before cliff). claim is permissionless — anyone can trigger a payout, which always goes to the schedule's stored beneficiary (this is the claim path for keyless wormhole or high-security beneficiaries). The admin calls (create-schedule, end-schedule, retarget) require the treasury origin; since the treasury is a multisig on real deployments, print the call data with --call-data-only and route it through quantus multisig propose.
# Inspect
quantus vesting info
quantus vesting list [--beneficiary qz...]
quantus vesting show --schedule-id 0
# Claim the vested payout of a schedule (any funded wallet can sign)
quantus vesting claim --schedule-id 0 --from my_wallet
# Admin: create a schedule (moments are unix ms, "now", or "+<seconds>")
quantus vesting create-schedule \
--beneficiary qz... \
--start now --cliff +7776000 --end +31536000 \
--total 10000 \
--call-data-only # print hex call data for a treasury multisig proposal
# Admin: end early (vested part to beneficiary, rest back to treasury)
quantus vesting end-schedule --schedule-id 3 --call-data-only
# Admin: change beneficiary
quantus vesting retarget --schedule-id 3 --new-beneficiary qz... --call-data-only
Runtime upgrades use the restricted FastUpgrade governance track. The proposal contains only
System::authorize_upgrade(blake2_256(wasm)), so it stays below the referendum's 4 KiB proposal
limit. The full WASM is supplied only after the authorization enacts.
# Note the small authorization preimage and submit the FastUpgrade referendum
quantus runtime update \
--wasm-file /path/to/quantus-runtime.compact.compressed.wasm \
--from <tech-collective-wallet> \
--node-url <endpoint>
# Place the decision deposit, collect 8-of-10 ayes, then wait for enactment
quantus tech-referenda list --node-url <endpoint>
quantus tech-referenda place-decision-deposit \
--index <referendum-index> --from <funded-wallet> --node-url <endpoint>
quantus tech-collective vote \
--referendum-index <referendum-index> --vote aye \
--from <member-wallet> --node-url <endpoint>
# Anyone can submit the exact authorized WASM after enactment
quantus runtime apply \
--wasm-file /path/to/quantus-runtime.compact.compressed.wasm \
--from <funded-wallet> \
--node-url <endpoint>
runtime apply verifies the on-chain authorization hash before submitting and verifies :code
at the inclusion block afterward. It always waits for inclusion even without
--wait-for-transaction. Because the apply extrinsic carries the full WASM, use a hot wallet in
normal operation rather than QR signing.
Query transfers via a Subsquid indexer using hash-prefix queries that hide your exact address.
quantus transfers query \
--subsquid-url https://indexer.quantus.com/graphql \
--prefix-len 4 \
--wallet my_wallet
# Analyze a specific block
quantus block analyze --number 1234 --all
# Analyze latest block
quantus block analyze --latest --extrinsics --events
# List blocks in a range
quantus block list --start 100 --end 110
Call any pallet function using metadata-driven parsing:
quantus call \
--pallet Balances \
--call transfer_allow_death \
--args '["5GrwvaEF...", "1000000000000"]' \
--from crystal_alice
quantus exercise runs a live-node smoke/fuzz suite against a node — reads, balances,
utility, reversible transfers, multisig, preimage, governance, vesting, negative
cases, a seeded fuzz loop, and wormhole round-trips. It derives a handful of ephemeral
accounts, funds them from a root account, drives each pallet, and verifies on-chain state
as it goes. Intended for CI and post-upgrade validation.
# Against a local dev node — crystal_alice is genesis-funded, so every phase runs
quantus exercise
# Against a public testnet: fund from your own wallet, spending no more than 100 tokens.
# Specifying --total-amount drops the governance phase automatically (it needs the dev
# genesis tech-collective accounts, and its referendum deposits alone are far larger than
# the rest of the suite)
quantus exercise \
--root-account my-wallet --root-password <pw> \
--total-amount 100 \
--node-url wss://a1-planck.quantus.cat
# Run only specific phases, or skip the CPU-heavy wormhole phase
quantus exercise --phases reads,balances,multisig
quantus exercise --skip wormhole
# Reproduce a fuzz failure from its seed; emit the report as JSON
quantus exercise --seed 12345 --json
# Runtime upgrade smoke (fast-governance node only). Mutually exclusive:
# --self-upgrade re-installs the current on-chain :code (no WASM file; no post-upgrade re-run)
# --upgrade-wasm installs a candidate WASM, then re-runs the other phases against it
quantus exercise --phases upgrade --self-upgrade
quantus exercise --phases upgrade --upgrade-wasm path/to/runtime.wasm
Key flags:
| Flag | Default | Description |
|---|---|---|
--root-account <NAME> | crystal_alice | Wallet that funds the run. Supply your own to run against a public testnet. |
--root-password <PW> / --root-password-file <PATH> | — | Password for the root wallet (or set QUANTUS_WALLET_PASSWORD_<NAME>). |
--total-amount <TOKENS> | 500 | Hard cap on what the whole run may draw from the root account. A ceiling, not an allocation — see below. Specifying it drops the governance phase unless --phases lists it explicitly. |
--ephemeral-accounts <N> | 4 | Number of ephemeral accounts to derive and fund. |
--phases <LIST> / --skip <LIST> | all | Comma-separated phases to run / skip. |
--seed <N> | random | Reproducible fuzz seed. |
--fuzz-iterations <N> | 25 | Number of fuzz iterations. |
--upgrade-wasm <PATH> | — | Enable the runtime-upgrade phase with the given WASM (fast-governance node only). Re-runs other phases after a successful upgrade. |
--self-upgrade | off | No-WASM upgrade smoke test: authorize/apply the current on-chain runtime blob via tech-referenda (fast-governance node only). Conflicts with --upgrade-wasm. Does not re-run other phases (runtime unchanged). Not the same as quantus update (CLI binary self-update). |
--upgrade-timeout-secs <N> | 900 | How long to wait for the upgrade referendum / code write. |
--fail-fast | off | Stop at the first failed step. |
--json | off | Emit the final report as JSON. |
--total-amount is a hard cap on the root account's balance drop, enforced for the whole run,
not just the initial funding: every root-paid transfer, deposit and estimated transaction fee
is reserved against it before submission and the run fails with the numbers rather than
exceeding it. The final report ends with a budget / root_account_spend line stating what was
actually spent — and fails if the cap was exceeded.
It is a ceiling, not an allocation. Ephemeral accounts are funded with what the chain's own
deposits and fees require, not with a share of the cap, and the phases that fund dedicated
accounts — wormhole — sweep them back into the root account when they are
done, so their funding is borrowed rather than spent. Discretionary test transfers are scaled
down by a fixed factor on top of that; chain-imposed amounts (existential deposit, multisig,
vesting and governance deposits) are read from the chain and never scaled.
Notes:
governancesubmits two referenda whose chain-fixed deposits stay locked for the whole run — on the order of a thousand tokens, dwarfing every other phase — and it relies on the dev genesis tech-collective accounts. It is therefore dropped whenever--total-amountis given, and when it (orupgrade) does run, its dev-account spend is exempt from the cap.vesting's admin steps dispatch through the dev Alice/Bob/Charlie treasury multisig; on chains whose treasury is a different account they are skipped, and the permissionless vesting checks still run.- The
wormholephase is CPU-heavy (ZK proving) — use--skip wormholefor a faster run. Its amount is fixed by an on-chain minimum and cannot be scaled down, so it needs ~52 tokens of headroom at once (returned afterwards).- Setup fails fast, with the numbers, if the root account can't cover
--total-amount, if the cap is too low to fund the ephemeral accounts, or if a selected phase needs more headroom than the cap leaves.
| Command | Description |
|---|---|
quantus balance --address <addr> | Query account balance |
quantus events --block 123 | Query events from a block |
quantus events --finalized | Events from the latest finalized block |
quantus system | System information |
quantus system --runtime | Runtime version details |
quantus metadata --pallet Balances | Explore chain metadata |
quantus version | CLI version |
quantus compatibility-check | Check CLI/node spec-version and transaction-version compatibility |
QUANTUS_WALLET_PASSWORD: Global password for all walletsQUANTUS_WALLET_PASSWORD_<WALLET_NAME>: Wallet-specific password (e.g., QUANTUS_WALLET_PASSWORD_CRYSTAL_ALICE)--node-url flag or default to ws://127.0.0.1:9944The CLI provides a comprehensive set of commands for blockchain interaction. Start by exploring the help system to discover available functionality:
quantus --help to see all available commandsquantus <command> --help to see command-specific options--verbose to any command for detailed execution information--node-url to connect to different blockchain nodesThe CLI supports both simple commands and complex workflows, with built-in help and error recovery at every level.
The Quantus CLI provides comprehensive support for multi-signature wallets, allowing you to create shared accounts that require multiple approvals before executing transactions.
10 instead of 10000000000000qz...)info command# 1. Create a 2-of-3 multisig (waits for confirmation by default)
quantus multisig create \
--signers "alice,bob,charlie" \
--threshold 2 \
--from alice \
--wait-for-transaction
# Output: 📍 Multisig address: qz... (with proper network prefix)
# 2. Fund the multisig (anyone can send funds)
quantus send \
--from alice \
--to qz... \
--amount 1000
# 3. Create a transfer proposal (human-readable amount)
quantus multisig propose transfer \
--address qz... \
--to dave \
--amount 10 \
--expiry 1500 \
--from alice
# Note: Expiry is BLOCK NUMBER (e.g., current block + 1000)
# 4. Check proposal details (shows current block + blocks remaining)
quantus multisig info --address qz... --proposal-id 0
# Output shows:
# Current Block: 450
# Expiry: block 1500 (1050 blocks remaining)
# 5. Second signer approves (auto-executes at threshold)
quantus multisig approve \
--address qz... \
--proposal-id 0 \
--from bob
# Default: Wait for transaction and extract address from event
quantus multisig create \
--signers "addr1,addr2,addr3" \
--threshold 2 \
--from creator_wallet
# Fast mode: Predict address immediately (may be wrong if concurrent creation)
quantus multisig create \
--signers "addr1,addr2,addr3" \
--threshold 2 \
--from creator_wallet \
--predict
quantus multisig propose transfer \
--address <multisig_address> \
--to <recipient> \
--amount 10 \
--expiry <future_block_number> \
--from signer_wallet
# Amount formats supported:
# 10 → 10 QUAN
# 10.5 → 10.5 QUAN
# 0.001 → 0.001 QUAN
# 10000000000000 → raw format (auto-detected)
quantus multisig propose custom \
--address <multisig_address> \
--pallet System \
--call remark \
--args '["Hello from multisig"]' \
--expiry <future_block_number> \
--from signer_wallet
quantus multisig approve \
--address <multisig_address> \
--proposal-id <id> \
--from signer_wallet
quantus multisig cancel \
--address <multisig_address> \
--proposal-id <id> \
--from proposer_wallet
# Show multisig details (signers, threshold, balance, etc.)
quantus multisig info --address <multisig_address>
# Show specific proposal details (includes current block + time remaining)
quantus multisig info --address <multisig_address> --proposal-id <id>
quantus multisig list-proposals --address <multisig_address>
# Remove single expired proposal
quantus multisig remove-expired \
--address <multisig_address> \
--proposal-id <id> \
--from signer_wallet
# Batch cleanup all expired proposals
quantus multisig claim-deposits \
--address <multisig_address> \
--from any_signer_wallet
# Requires: no proposals exist, zero balance
quantus multisig dissolve \
--address <multisig_address> \
--from creator_or_signer_wallet
The multisig pallet uses an economic model to prevent spam and incentivize cleanup:
Deposits are visible in multisig info output:
Balance: 1000 QUAN ← Spendable balance
Deposit: 0.5 QUAN (locked) ← Refundable creation deposit
info --proposal-id to decode and verify proposal contents before approvingclaim-deposits to recover deposits from expired proposalsinfo --address commandDecoding Proposals: The CLI automatically decodes common call types:
$ quantus multisig info --address qz... --proposal-id 0
📝 PROPOSAL Information:
Current Block: 450
Call: Balances::transfer_allow_death
To: qzmqr...
Amount: 10 QUAN
Expiry: block 1500 (1050 blocks remaining)
SS58 Address Format: All addresses use the Quantus network prefix (qz... for prefix 189) automatically.
Password Convenience: Omit --password "" for wallets with no password.
For more details, see quantus multisig --help and explore subcommands with --help.
--scheme ml-dsa-65), with ML-DSA-87 available (--scheme ml-dsa-87). Each scheme has its own default HD path (…/1' vs …/0') so the same mnemonic does not collide across schemes.✅ Fully Implemented:
The Quantus CLI is a production-ready tool that:
✅ Handles Real Money: All transactions are real and irreversible
✅ Quantum-Safe: Uses post-quantum cryptography for future security
✅ Developer-Friendly: Rich tooling and clear error messages
✅ Scriptable: Environment variables and flags for automation
✅ Extensible: Clean architecture for adding new blockchain features
✅ SubXT-Powered: Modern, type-safe blockchain integration
⚠️ Security Note: This tool handles real cryptocurrency. Always:
The project includes a script to regenerate SubXT types and metadata when the blockchain runtime changes:
# Regenerate metadata and types from the running node
./regenerate_metadata.sh
What this script does:
src/quantus_metadata.scalesrc/chain/quantus_subxt.rscargo fmtsrc/config/mod.rs (newer unlisted specs warn rather than hard-fail)When to use:
quantus compatibility-check allowlistRequirements:
subxt-cli must be installed: cargo install subxt-cliUsage:
# Use default node URL (ws://127.0.0.1:9944)
./regenerate_metadata.sh
# Use custom node URL
./regenerate_metadata.sh --node-url ws://other-node:9944
# Show help
./regenerate_metadata.sh --help
Output:
Using node URL: ws://127.0.0.1:9944
Updating metadata file at src/quantus_metadata.scale...
Generating SubXT types to src/chain/quantus_subxt.rs...
Formatting generated code...
Reminder: update src/config/mod.rs with the new compatible spec/transaction version pair.
Done!
After regeneration, re-run:
quantus compatibility-check --node-url <node>
The compatibility gate accepts exact spec_version / transaction_version pairs listed in src/config/mod.rs. A Quantus node whose spec_version is newer than the highest listed pair connects with a warning (extrinsics may still fail if the runtime has moved on). Wrong specName values and older/unknown pairs outside the table are still rejected.
1 activity