Skip to content

feat(wallet): native wallet framework for SDK integrators#132

Open
JaeLeex wants to merge 2 commits into
mainfrom
feat/wallet-framework
Open

feat(wallet): native wallet framework for SDK integrators#132
JaeLeex wants to merge 2 commits into
mainfrom
feat/wallet-framework

Conversation

@JaeLeex

@JaeLeex JaeLeex commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR ships a first-party wallet framework in the Nunchi SDK so chain operators and dApp developers can create, store, sign, and submit transactions without rolling their own tooling.

  • Adds nunchi-wallet crate: encrypted keystore, Ed25519 CLI, JSON-RPC client, and passkey assertion types
  • Adds examples/wallet-web: browser passkey wallet kit (Constantinople-compatible encoding)
  • Adds chain_id to TransactionPayload for cross-chain replay protection
  • Updates MCP sdk_build_* tools to accept optional chain_id

Specification

1. Bech32 addresses (nch1…)

Field Value
Standard BIP-173 classic Bech32
HRP nch
Payload 32-byte Address digest
API Address::to_bech32() / Address::from_bech32()

Addresses are derived identifiers:

SHA256("nunchi/account/v1" || kind || material)
Kind Account type
0 External wallet (Ed25519 or secp256r1 public key)
1 Multisig bootstrap policy
2 Reserved module label

Only Address user-facing fields use Bech32. Public keys, coin IDs, tx hashes, and state roots remain hex.

Canonical implementation: nunchi-common/src/account.rs (merged in #75).

2. Chain ID replay protection

Every TransactionPayload now includes chain_id: u64 encoded before nonce and operation.

Signing bytes:

account_id || authorization_tag || payload.encode()

where payload.encode() is chain_id || nonce || operation.

  • DEFAULT_CHAIN_ID = 0 for devnet/tests
  • Wallets must sign with the target chain's id
  • Changing chain_id after signing invalidates the authorization
  • Cross-chain replay test added in common/src/tests/transaction.rs

3. CLI wallet (Ed25519)

Property Value
Default curve Ed25519
Keystore root ~/.nunchi/wallets/<name>/wallet.json
Encryption Argon2id + ChaCha20-Poly1305
Password source NUNCHI_WALLET_PASSWORD env var
Dev escape hatch --insecure-store (plaintext JSON)

Commands:

export NUNCHI_WALLET_PASSWORD='your-passphrase'
nunchi-wallet create --name default --chain-id 1
nunchi-wallet list
nunchi-wallet show --name default
nunchi-wallet address --name default
nunchi-wallet submit-transfer \
  --name default \
  --rpc http://127.0.0.1:8545 \
  --chain-id 1 \
  --coin <coin-id-hex> \
  --to nch1… \
  --amount 1000 \
  --nonce 0

4. RPC client

Submits hex-encoded coin transactions via:

coins.submit_transaction { "transaction": "<hex>" }

Library API: nunchi_wallet::client::WalletRpcClient

5. Passkey wallet (web)

Browser wallets use WebAuthn P-256 assertions in Constantinople-compatible form:

[scheme=1][64-byte sig][u16 len][authenticatorData][u16 len][clientDataJSON]

Reference: examples/wallet-web — adapted from Commonware Constantinople.

On-chain verification of passkey signatures requires chain support for bundled WebAuthn assertions (future nunchi-crypto extension). This PR ships encoding types now so web wallets and chains can integrate without another breaking wire change.

6. Wallet kit scope for third parties

Layer Crate / path Audience
Address + tx signing nunchi-common, nunchi-crypto All integrators
Encrypted keystore + CLI nunchi-wallet Operators, devnets
Browser passkey kit examples/wallet-web dApp developers
RPC submission nunchi-wallet::client CLIs, agents, MCP tools

7. Security notes

  • Never log private keys or NUNCHI_WALLET_PASSWORD
  • Production deployments must not use --insecure-store
  • Wallets are chain-scoped via chain_id; multi-chain operators should create one wallet record per chain
  • Cross-chain replay of identical signed payloads is rejected once chains use distinct chain_id values

Breaking changes

Transaction::sign and Transaction::sign_multisig now require an explicit chain_id argument. All in-repo call sites are updated.

Test plan

  • cargo test -p nunchi-common (includes cross-chain replay test)
  • cargo test -p nunchi-coins -p nunchi-mempool -p nunchi-mcp -p nunchi-wallet
  • nunchi-wallet keystore round-trip + Bech32 address creation
  • Passkey assertion encoding unit test
  • Manual: nunchi-wallet create + submit-transfer against a running devnet node
  • Manual: examples/wallet-web passkey create/sign in a secure browser context

Docs

Made with Cursor

JaeLeex and others added 2 commits July 13, 2026 12:15
Ship nunchi-wallet for SDK integrators with encrypted keystore, CLI, RPC
client, and passkey types, and bind transactions to chain_id to prevent
cross-chain replay.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant