Wallet Address Book — Watch-Only & Light-Client Flows
The wallet address book: watch-only accounts, light-client verification, and integrity checks that do not require a full node.
6 min read 1,373 words
View docs/wallets/ADDRESS_BOOK.md on GitHub
Source: docs/wallets/ADDRESS_BOOK.md — this page mirrors the repository documentation.
Naming note. Older repository documents call the signature scheme “Dilithium3”; that is the lineage name for ML-DSA-65 (FIPS 204, scheme id
0x1003), the only signature scheme mainnet accepts for new transactions. Where SPHINCS+ is mentioned as a backup scheme, note that on mainnet it is legacy and consensus-stranded: it cannot sign transactions.
This document describes the address book feature for Animica wallets, focusing on:
- Watch-only accounts (no private keys held; read-only portfolio & alerts).
- Light-client verification paths for balances, transactions, and logs.
The goal is to provide a safe default for tracking accounts and contracts across networks, with integrity checks that do not require a full node.
Animica notes
- Addresses are bech32m
anim1…and encode alg_id || sha3_256(pubkey) for PQ keys.- Networks (chain IDs, RPCs) are defined under
website/chains/*.- Light verification primitives are documented in
docs/spec/LIGHT_CLIENT.mdand implemented in SDKs (sdk/*/light_client/verify).
1) Concepts
1.1 Address Types
- Externally Owned Accounts (EOA): Controlled by a PQ key (e.g., Dilithium3). May be watch-only if the wallet does not store the key.
- Contracts: Code at an address; watch-only tracks code hash, ABI (if verified), and emitted events.
- Labels & Tags: Human-friendly names and quick filters (e.g., “Treasury”, “Ops”, “Provider”).
1.2 Watch-Only
- No private material stored. The wallet:
- Fetches balance, nonce, code hash, recent transactions, and events.
- Can create unsigned transactions for simulation or export.
- Cannot sign or send unless a signer is attached later.
- Safe defaults: send actions disabled, “watch-only” badge, & opt-in alerts.
1.3 Light-Client Flows (High Level)
- Headers: Keep a verified chain of headers (via
sdk/*/light_client/verify). - Receipts: Verify transaction inclusion using the receipts root from headers.
- DA (optional): For blob-backed data, verify DA roots as needed.
- Randomness Beacon: Cross-check rounds when used by clients (not required for address book basics).
2) Data Model
2.1 Address Record (JSON)
{
"id": "addr_01J5E5W2J8PV…",
"address": "anim1qxyz…",
"network": "animica.testnet",
"chainId": 2,
"kind": "eoa", // "eoa" | "contract"
"watchOnly": true,
"label": "Ops Treasury",
"tags": ["treasury", "ops"],
"color": "#6C5CE7",
"algId": "dilithium3", // if known for EOAs
"codeHash": null, // if contract; hex string when known
"abiRef": null, // artifact/vk reference or URL when verified
"notes": "One-way inflow; alerts on outbound.",
"createdAt": "2025-01-05T12:03:11Z",
"updatedAt": "2025-01-05T12:03:11Z",
"sources": [
{"type":"explorer","url":"https://explorer.animica.dev/address/…"},
{"type":"import","format":"qrcode"}
],
"alerts": {
"txOutbound": true,
"balanceBelow": "1000000000",
"eventSignatures": ["Transfer(address,address,uint256)"]
}
}
2.2 Storage & Crypto Hygiene
- Store locally (browser extension storage / mobile keystore) under a namespaced key.
- Encrypt notes and labels at rest (optional) with the wallet vault key.
- Non-secret metadata (chainId, tags) can remain plaintext.
- Maintain a content hash of each record for tamper detection.
3) Import / Export
3.1 Supported Inputs
- Paste Address / QR Code (bech32m): Validate HRP + checksum, then store.
- CSV (label,address,network,tags…): Strict header row, UTF-8.
- JSON Lines (NDJSON): One record per line (recommended for bulk).
Example CSV:
label,address,network,tags,watchOnly Ops Treasury,anim1qxyz…,animica.testnet,“treasury;ops”,true Counter (dev),anim1qabc…,animica.localnet,“demo;contract”,true
3.2 Export
- JSON Lines with a top-level export manifest:
{
"exportFormat": "animica-address-book-v1",
"exportedAt": "2025-01-06T10:10:00Z",
"records": 42
}
- Offer redaction options: strip notes, strip tags, strip alert rules.
4) Fetching & Verification
4.1 Trust Tiers
- Direct RPC (unverified): Fast UI updates; mark status as “unverified”.
- Multi-RPC consensus: Query ≥2 providers; quorum on results; flag disagreements.
- Light-verified: Use header chain + inclusion proofs to mark data verified.
The UI should surface a Status Badge:
- Healthy (verified): Data backed by light proof.
- Degraded (quorum only): Multiple RPCs agree, but not locally proven.
- Unverified: Single RPC source; show disclaimer.
4.2 Balances & Nonce (EOA)
- Query state.getBalance and state.getNonce (RPC).
- Optionally re-query via a second RPC for consensus.
- For light verification, pin the header height the response claims and verify the header chain up to that height.
4.3 Transactions & Receipts
- Fetch tx by hash; obtain block hash/number and receipt.
- Verify:
- The block header is in the verified header chain.
- The receipts root in that header matches the included receipt.
- SDK helpers: sdk/*/light_client/verify (Python/TS/Rust) can drive inclusion checks.
4.4 Contracts & Events
- For verified contracts, store the code hash and (optional) ABI reference.
- Event logs:
- Check bloom/logs root ↔ header receiptsRoot (see docs/spec/RECEIPTS_EVENTS.md).
- Light-verify inclusion where possible; otherwise degraded state.
4.5 Data Availability (Optional)
- If a watch-only flow references blobs (e.g., contract artifacts pinned in DA), verify:
- The blob commitment is under the header’s DA root.
- Use sdk/*/da/client for proof retrieval & light verification.
5) UX Flows
5.1 Add Watch-Only Address
- Paste/Scan address → validate checksum & HRP.
- Choose network (default from website/chains/index.json).
- Set label, color, tags.
- Confirm watch-only toggle ⇒ disable send/sign.
- (Optional) Alerts: outbound tx, balance thresholds, event signatures.
5.2 Attach a Signer Later
- Convert a watch-only EOA into a signing account by:
- Unlocking a local vault (extension/mobile)
- Or attaching a hardware key or WebAuthn credential.
- Always show a dangerous change warning when enabling send/sign.
5.3 Cross-Network Portfolio
- List same address on multiple networks (main/test/local).
- Aggregate balances with per-network row and a converted total (FX rates optional).
5.4 Alerts & Notifications
- Implement debounced polling (WS subscribe preferred where available).
- For light-verified alerts, only trigger after inclusion proof passes; otherwise mark as prelim.
6) CLI / SDK Examples
6.1 TypeScript (balance + light verify)
import { HttpClient } from "@animica/sdk/src/rpc/http";
import { verifyHeaders } from "@animica/sdk/src/light_client/verify";
const rpc = new HttpClient({ url: process.env.RPC_URL! });
const head = await rpc.call("chain.getHead", []);
const ok = await verifyHeaders(head); // pins header chain locally
const balance = await rpc.call("state.getBalance", ["anim1qxyz…"]);
console.log({ height: head.height, verified: ok, balance });
6.2 Python (receipt inclusion)
from omni_sdk.rpc.http import HttpClient
from omni_sdk.light_client.verify import verify_headers, verify_receipt
rpc = HttpClient(url=os.environ["RPC_URL"])
head = rpc.call("chain.getHead", [])
verify_headers(head)
tx = rpc.call("tx.getTransactionByHash", ["0xabc…"])
rcpt = rpc.call("tx.getTransactionReceipt", ["0xabc…"])
assert verify_receipt(head, rcpt), "Receipt failed light verification"
7) Security & Privacy
- No private keys in watch-only mode. Ensure TX send/sign UI is disabled.
- Domain separation for any approval/sign messages (see docs/spec/ENCODING.md).
- Rate limit RPC to avoid leaking behavior patterns; optional anonymized proxy.
- Local encryption for notes/labels; redact on export by default.
- Phishing-resistant deep links: use InlineLink component rules from the website to set rel=“noopener noreferrer” & target=“_blank”.
8) Edge Cases
- Reorgs: If a tracked tx is reorged out, mark status and re-verify on the new tip.
- Code Upgrades: If a contract code hash changes (via upgrade proxy), notify user and require ABI re-ack.
- Multiple HRPs / Chains: Reject addresses with mismatched HRP vs chosen network.
- Alias/Multisig: For AA or multisig schemes, expose implementation address and policy summary if known.
9) Testing Checklist
- Import CSV & JSONL (labels with unicode).
- Validate bech32m HRP and checksum; reject malformed.
- Watch-only cannot send/sign; buttons disabled.
- Multi-RPC quorum disagreement → “Degraded” status.
- Light-verification success/failure paths surfaced in UI.
- Reorg handling: tx status transitions correctly.
- Export redaction works as advertised.
10) Minimal API (Internal)
Storage key: wallet.addressBook.v1
type AddressRecord = {
id: string;
address: string;
network: string;
chainId: number;
kind: "eoa" | "contract";
watchOnly: boolean;
label?: string;
tags?: string[];
color?: string;
algId?: string | null;
codeHash?: string | null;
abiRef?: string | null;
notes?: string;
alerts?: {
txOutbound?: boolean;
balanceBelow?: string | null;
eventSignatures?: string[];
};
createdAt: string;
updatedAt: string;
};
11) Quickstart
- Add address (anim1…) as watch-only on Animica Testnet.
- Enable multi-RPC in settings for consensus fetch.
- Turn on light verification (downloads recent headers).
- Subscribe to outbound tx alerts; simulate a small tx (no signing).
- Verify that the Status Badge shows Healthy (verified) once inclusion is proven.
12) References
- docs/spec/LIGHT_CLIENT.md — light verification details
- docs/spec/RECEIPTS_EVENTS.md — receipts, logs, and blooms
- website/src/components/StatusBadge.tsx — status indicator component
- website/chains/* — networks & RPC metadata
- SDKs: sdk/typescript, sdk/python, sdk/rust (light verify helpers)
This page mirrors a file in the animicaorg/all repository. If the repository and this page ever disagree, the repository is authoritative. For long-form explainers written for newcomers, see Learn.