Design¶
This document captures the design agreed at project inception. The constitution is the authoritative short form; this is the narrative.
Origin¶
A live amaru-treasury-tx reorganize failed with:
tx-build: reorganize failed while building the transaction:
collateral shortfall; required collateral lovelace: 17537408;
available collateral lovelace: 3709675
A reorganize spends many treasury UTxOs (each a Plutus execution), so
its fee is large (~11.7 ADA), and the ledger requires collateral =
fee × 150% ≈ 17.5 ADA. The builder pinned collateral to a single
wallet UTxO (3.7 ADA), the largest pure-ADA one available. No layer
selected collateral to a target, and collateral_return was ADA-only,
so token-bearing UTxOs were ineligible. cardano-wallet-tools exists to
make wallet-side selection — coin and collateral — a first-class,
verifiable concern.
Mission¶
An operator wallet-UTxO toolkit plus a PureScript CIP-30 browser wallet, over one pure Haskell core. Capabilities:
- Coin + collateral selection — input selection to cover
outputs + fee; multi-UTxO, native-asset-aware collateral selection with a conservingcollateral_return, capped atmaxCollateralInputs, with explicit shortfall reporting. - Consolidation / provisioning — build a defrag tx, or a send-to-self tx that mints a single fat pure-ADA collateral UTxO.
- Balancing over
cardano-tx-tools— a clean "balance this" entry point that drives the existing build/balance machinery with correct inputs and collateral. - UTxO reports — pure-ADA vs token, fragmentation, max collateral reachable, fee/collateral headroom.
Architecture¶
One pure wallet-core, two frontends:
- Native operator CLI (
resolve,utxo-report,select-collateral,consolidate/provision-collateral,balance,submit) — n2c reads, optional age-vault signing. - Haskell → WASM module consumed by a PureScript + CIP-30 browser wallet (spago / esbuild / Halogen).
The core is pure and WASM-portable, so both frontends run the same selection and verification code.
Trust model¶
TxIn -> TxOut resolution is a pluggable backend, tiered by trust:
| Backend | Trust | Mechanism |
|---|---|---|
| N2C (own node) | trusted | LocalStateQuery, authoritative |
| Blockfrost / Koios | untrusted → verified | fetch producing-tx CBOR, recompute blake2b-256(body), assert == txid, read outputs[ix] |
The verifier TxIn -> TxCbor -> Either ResolveError TxOut is pure
and lives in the core, so the browser inherits the guarantee. CIP-30
getUtxos provides the user's own (trusted) wallet UTxOs; any other
TxIn is resolved through a verified Blockfrost/Koios fetch.
Protocol parameters are best-effort from the backend: a wrong value only mis-sizes fee/collateral and the node re-validates at submit, so funds cannot be stolen. This weaker guarantee is documented, not hidden.
Collateral selection algorithm¶
Inside the fee fixpoint (so the required amount is known each pass):
required = ceil(fee × ppCollateralPercentage / 100).- Candidates: VKey-locked UTxOs. Pure-ADA preferred; native-asset
UTxOs allowed when
collateral_returnis built to conserve their assets. - Largest-first, reusing inputs already in the body, until
sum ≥ requiredorcount = maxCollateralInputs. - Exhausted and still short →
CollateralShortfall { selected, sum, required }— never a silent under-provision.
The leftover (sum − total_collateral) becomes collateral_return,
carrying any collateral-input assets; folded into total_collateral
only when an asset-free residual is below min-UTxO.
Why getCollateral (CIP-30) is bypassed: it exposes only a handful of
small pre-set collateral UTxOs — precisely the limitation this project
removes. The browser reads getUtxos and runs our selection instead.
Coin selection¶
Pluggable strategy: LargestFirst (default — fewest inputs, matches
the collateral cap reasoning) and RandomImprove (CIP-2, opt-in,
seeded so WASM stays deterministic).
Submission & signing¶
- Submit symmetric across N2C / Blockfrost / Koios / CIP-30, with confirm-on-chain (poll for the txid or time out).
- Signing: build-only by default. Browser → CIP-30
signTx/submitTx. CLI → optional age-vault signing. No multisig in v1; co-signing is handed off tocardano-tx-tools/ amaru.
Package layout (target)¶
lib/ wallet-core pure: selection, collateral, resolution verifier, reports (WASM-safe)
lib/ wallet-tx balancing/assembly over cardano-tx-tools
app/ wallet-cli native operator CLI (n2c reads, vault signing)
wasm/ wallet-wasm foreign-export surface for the browser
web/ purescript CIP-30 wallet (spago + esbuild + Halogen)
lean/ selection invariants (optional formalization)
v0 ships wallet-core with the pure selection algorithms only; the
remaining components land as tracked tickets, each admitting its
dependencies against the WASM-portability rule first.