Seedelf-Wallet

Chunk 8 plan: create a Seedelf (stealth mint)

Branch: web-wallet/create-seedelf, created from seedelf-web-wallet after PR #251 (chunk 7) is merged. It ends with a PR back into seedelf-web-wallet.

This is the first script spend in the web wallet. Every Seedelf spend in chunks 9 and 10 (transfer, sweep, remove) reuses what this chunk builds: owned contract inputs with Schnorr proofs, a one-time key, reference scripts, giveme.my collateral, and evaluation through Ogmios.

Start here (new session)

  1. Sync, and branch:
    git checkout seedelf-web-wallet && git pull
    git log --oneline HEAD..origin/main   # merge main first if this lists anything
    git checkout -b web-wallet/create-seedelf
    
  2. Read this plan, then the chunk 7 entry in roadmap.md, architecture.md Transaction building, flows.md Create a Seedelf, and privacy.md Rules the wallet enforces.
  3. Read the code this chunk extracts: seedelf-cli/src/commands/util/mint.rs (about 500 lines), and the helpers it uses in seedelf-core/src/transaction.rs (seedelf_token_name, extract_budgets, total_computation_fee, seedelf_minimum_lovelace, collateral_input, reference_utxo), seedelf-core/src/data_structures.rs (the redeemers), and seedelf-cli/src/commands/fee.rs (the collateral output and even rounding).
  4. Finish chunk 7’s live move-in first. Minting spends owned contract UTxOs, and on preprod none exist for a phrase wallet until a move-in lands.
    • The test wallet is in extension/.preprod-test-wallet.txt (gitignored). The user funds its receive_0 from the faucet.
    • Then run npm run build && node e2e/live/move-in.mjs 10.
    • Record the tx hash in the roadmap.
  5. The tooling is already installed (see chunk 5’s plan). Commands are in extension/README.md.
  6. Confirm the decisions with the user before building the parts they affect.

What util mint does today

seedelf-cli/src/commands/util/mint.rs, which becomes network-free builders plus a thin run():

  1. Select owned contract UTxOs (collect_wallet_utxos, which skips UTxOs holding a Seedelf) worth the Seedelf minimum (about 1.5 ADA) plus a fee guess.
  2. Token name: seedelf_token_name(label, inputs), which is 5eed0e1f ‖ the label (at most 15 bytes) ‖ the index of the lexicographically smallest input ‖ its tx id, cut to 32 bytes.
  3. Outputs:
    • The new Seedelf: the minimum ADA, the token, and a freshly re-randomized own register.
    • Change back to the contract under fresh registers, with tokens 20 to an output.
  4. One-time key: a fresh random ed25519 key. Its hash pkh is a required signer, and so is COLLATERAL_HASH.
  5. Spend redeemers: per input, create_proof(register, sk, pkh) gives (z, g_r). The proof is bound to pkh, which is the rollback-replay defence.
  6. Script plumbing:
    • The mint redeemer carries the label.
    • Reference inputs for the Seedelf and wallet scripts.
    • The PlutusV3 language view.
    • The collateral input is giveme.my’s UTxO. The collateral output returns 5 ADA − 1.5 × fee to the collateral address.
  7. Draft → evaluate:
    • Build with placeholder ex-units (14M mem, 10G steps).
    • evaluate_transaction (Koios /ogmios, JSON-RPC evaluateTransaction) gives budgets.
    • extract_budgets reads them in response order, and split_last treats the last one as the mint.
  8. Fee:
    • Size fee: the draft signed by the one-time key plus one fake signature.
    • Compute fee: from the budgets.
    • Script-reference fee: (seedelf_size + wallet_size) × 15.
    • The total is rounded up to even, so the collateral maths stays whole.
  9. Finalize with the real budgets and fee.
  10. Witness: POST { tx: cbor } to giveme.my. It answers { witness }, whose last 64 bytes are the collateral key’s signature. Sign with the one-time key, add that signature, then submit.

Decisions to confirm first

Decision Suggestion Notes
Label (personal tag) Optional; printable ASCII, at most 15 characters, with a live preview of how it will read On chain it’s any bytes, cut to 15. Multi-byte text could be cut mid-character, and the wallet reads tags back as printable ASCII (seedelfLabel in chain.ts).
When giveme.my is contacted At Send, not at Review Draft, evaluate and finalize happen at Review, so the user sees the real fee. The collateral witness is fetched only once the user commits.
The Seedelf’s register A fresh re-randomization of the user’s own base register The CLI can also mint to someone else’s register (--generator/--public-value). The web wallet doesn’t need that in v1.
Which UTxOs pay Automatic, from the Seedelf balance (as in the CLI’s select) Privacy: few inputs, and never the Cardano account (privacy rule 5).
Minimum balance Show the cost up front: about 1.5 ADA locked with the Seedelf, plus about 0.3–0.6 ADA in fees Only remove gets the locked ADA back (chunk 10).

Work items

1. Core: script-spend builders (seedelf-core/src/build.rs)

2. WebAssembly: a stateful spend builder

3. Service worker

4. UI

5. Tests

6. Docs

Risks and things to check

Out of scope

Transfer (chunk 9), sweep and remove (chunk 10), minting to someone else’s register, and the CLI’s create (paid by an outside wallet, which links it).