Snowblossom Docs
Docs › Running software › Integration guide

Integration guide

A practical recipe for accepting SNOW - in a shop, a service, or an exchange - using only the stock software: a node with indexes, a watch-only wallet for deposits, a separate hot wallet for withdrawals, and the wallet's JSON-RPC. Where the protocol has sharp edges, they are called out.

Architecture

Your nodeaddr_index · tx_index Watch-only walletxpub · rpcserver · deposits Hot wallet (keys)rpcserver · withdrawals, small float Your applicationJSON-RPC client cold seed wallet offline → xpub
Deposits are watched without any private key online; withdrawals come from a separately funded hot wallet.

1. Run a node with indexes

network=snowblossom
db_type=rocksdb
db_path=node_db/mainnet
addr_index=true
tx_index=true
service_port=2338

Both indexes must be on before the first sync (they are not retroactive). Without addr_index the wallet cannot see history, cannot detect used addresses beyond balance checks, and seed recovery is unreliable; without tx_index confirmed transactions cannot be looked up by id. Keep the node on its own host or container, reachable only from your wallets. See Node.

2. Deposit addresses from a watch-only wallet

  1. On an offline machine create the seed wallet (key_mode=seed, the default) and record the 12 words; show_seed prints the account xpub.
  2. Online, create a wallet config with watch_only=true and run import_xpub <xpub>; start rpcserver.
  3. Hand out deposit addresses with getfresh {"mark_used":true}. Marking used guarantees an address is never issued twice and moves the derivation window forward; store the address → customer mapping in your database.

Alternatively derive addresses yourself with get_xpub_address {xpub, index} and track the index - then the wallet only learns that an address is used once the node's index or a balance shows it, so keep the node's addr_index on. The wallet derives 20 addresses past the highest used one (seed_gap); do not skip far ahead.

3. Detecting deposits

  • Polling: get_address_history {address} returns confirmed entries with block_height and mempool entries flagged mempool:true. For each new tx_hash call get_transaction {tx_hash, send_json:true}, sum the outputs whose recipientSpecHashAddress is the deposit address, and read status.confirmations.
  • Push: over gRPC, SubscribeAddressUpdates fires once per address immediately and again whenever a block or mempool transaction touches it; then fetch as above. The MonitorTool class is a reference implementation (it replays full history, so de-duplicate by address + tx id).
  • Confirmations: blocks come every ~10 minutes; reorganisations are cheap for the protocol, so do not credit on 1 confirmation. There is no reorg notification - keep re-checking a transaction's status until it reaches your threshold, and treat a regression to unknown as a reversal. Six confirmations (~1 hour) is a common choice; adjust to the value involved and the network hash rate.
  • Do not reuse one address for everything: GetAddressHistory returns at most 10,000 entries per address.

4. Withdrawals

Fund a separate hot wallet (seed or standard keys) and run its rpcserver bound to localhost:

-d '{"jsonrpc":"2.0","id":1,"method":"send","params":{"outputs":[{"address":"snow:…","flakes":250000000}],"input_confirmed_only":true}}'
# → {"tx_hash":"…","fee":…,"all_signed":true}

Store the returned tx_hash and confirm it later with get_transaction. input_confirmed_only avoids building chains of unconfirmed transactions. For stricter control use the two-step flow: create_transaction {broadcast:false, sign:false} on the watch-only wallet, move the hex to the signing host, sign_transaction, then broadcast from anywhere - the transaction id is fixed before signing, so you can record it up front. parse_transaction shows exactly what will be signed; with SIP-4 the inputs can carry their values so an offline signer sees the full picture.

Since 2.2 the same flows work from the command line without the RPC server: send 250 snow:dest --confirmed-only --yes --json for scripted withdrawals (exit status 0/1, one JSON document on stdout), send … --out tx.hex on the watch-only wallet + signtx tx.hex --out signed.hex on the signing host + broadcast signed.hex for the offline flow, and decodetx to inspect any file before signing. outputs --json and consolidate help keep a busy hot wallet's UTXO set tidy. See wallet scripting and offline signing.

5. Amounts, fees and addresses

  • Use integer flakes (106 per SNOW) everywhere; the snow decimal fields are for humans.
  • Fees are per byte (≈ 2.5 flakes/byte, i.e. well under 0.001 SNOW for an ordinary payment); the wallet estimates them from the node. Post-quantum wallets make transactions of several kilobytes - budget accordingly if you use them for the hot wallet.
  • Validate addresses with get_address_hash (checks the Duck32 checksum and network label). Accept both snow:xyz… and bare xyz…; the label is recommended.
  • A send is funded from one shard only; on mainnet (single shard) this never matters, on a split network a very large withdrawal may have to be split into several sends.

6. Operations checklist

  • Back up the hot wallet directory after it creates new addresses (each send creates a change address); back up the cold seed once. Wallet files are unencrypted - restrict permissions.
  • The RPC server is plain HTTP with basic auth: bind to localhost, tunnel if needed, rotate the password.
  • Monitor the node: get_statusnode_status.head_summary.header.block_height should track the explorer; connected_peers > 0.
  • Keep clocks in sync (NTP); nodes reject blocks 45 s in the future and warn at 5 s drift.
  • Watch protocol upgrades: SIP activations require node updates by a block height (the last was SIP-6 at block 358,700). Follow the releases.
  • Explorer cross-check: https://snowblossom-explorer.org/api/tx/{hash} and /api/address/{address} give an independent view for support staff.

Alternatives

  • Direct gRPC (reference): skip the wallet entirely, generate keys in your own code (secp256k1 compressed, 1-of-1 spec, Skein-256-160, Duck32) and build transactions yourself. The TransactionFactory, AddressUtil and Duck32 classes are small and readable references.
  • Embedding the Java library: the //client:client and //lib:lib Bazel targets can be used as a library from any JVM application.