Skip to content

Transaction Flow

A custom, dependency-free directed graph — no react-flow, no canvas. FlowNodeCards are placed on a column/row grid over a pure-SVG connector layer of smooth cubic beziers, colored only from the --ch-* token scale. Connector status tints the path (confirmed → success, pending → warning, failed → danger); pending dashes flow and freeze under reduced motion. Click or focus any node to highlight its neighborhood.

Worked example — inputs → tx → outputs

Two spent UTXOs fund one transaction that pays a recipient and returns change. The tx hub carries the aurum emphasis ring; every leg is confirmed, so connectors read success-green with amount captions at each midpoint. Fee = 0.5700 in − 0.5680 out = 0.0020 BTC. Click a node to trace only its neighborhood.

confirmed

Transaction flow: 5 nodes, 4 connections. UTXO 0.4200 to Transaction (confirmed); UTXO 0.1500 to Transaction (confirmed); Transaction 0.5000 to Recipient (confirmed); Transaction 0.0680 to Change (confirmed).

const nodes: FlowNode[] = [
  { id: "in-1", kind: "input", label: "UTXO", amount: "0.4200 BTC", column: 0, row: 0 },
  { id: "in-2", kind: "input", label: "UTXO", amount: "0.1500 BTC", column: 0, row: 2 },
  { id: "tx",   kind: "tx", label: "Transaction", column: 1, row: 1, emphasis: true },
  { id: "out-1", kind: "output", label: "Recipient", amount: "0.5000 BTC", column: 2, row: 0 },
  { id: "out-2", kind: "output", label: "Change", amount: "0.0680 BTC", column: 2, row: 2 },
];
const edges: FlowEdge[] = [
  { id: "c-e1", from: "in-1", to: "tx", amount: "0.4200" },
  { id: "c-e3", from: "tx", to: "out-1", amount: "0.5000" },
];
<TransactionFlow nodes={nodes} edges={edges} />
  • --ch-viz-1
  • --ch-success
  • --ch-border
  • --ch-surface
  • --ch-accent

Nodes place on a 3-column grid; the tx sits on the middle row so it centers between its two inputs.

Pending — flowing dashes

A deposit routes through a CoinJoin round to a fresh output. Pending legs render dashed in warning-amber and animate strokeDashoffset for a flowing effect — the animation freezes to a static dash under prefers-reduced-motion.

pending

Transaction flow: 3 nodes, 2 connections. Deposit 0.2500 to CoinJoin (pending); CoinJoin 0.2499 to Fresh UTXO (pending).

<TransactionFlow
  nodes={[{ id: "p-in", kind: "input", … }, { id: "p-cj", kind: "coinjoin", emphasis: true, … }, { id: "p-out", kind: "output", … }]}
  edges={[{ id: "p-e1", from: "p-in", to: "p-cj", amount: "0.2500", status: "pending" }, …]}
/>
  • --ch-warning
  • --ch-border
  • --ch-viz-1

Both connectors are status:'pending' — dashed + flowing.

Failed — a reverted leg

Funding reaches an exchange hot wallet (confirmed), but the withdrawal is reverted — that connector reads danger-red with a 'reverted' caption. Statuses are per-edge, so a single graph can mix confirmed, pending, and failed legs.

failed

Transaction flow: 3 nodes, 2 connections. Funding 1.0000 to Exchange (confirmed); Exchange to Withdrawal (failed).

<TransactionFlow
  nodes={[{ id: "f-in", kind: "input", … }, { id: "f-ex", kind: "exchange", … }, { id: "f-out", kind: "address", … }]}
  edges={[
    { id: "f-e1", from: "f-in", to: "f-ex", amount: "1.0000", status: "confirmed" },
    { id: "f-e2", from: "f-ex", to: "f-out", label: "reverted", status: "failed" },
  ]}
/>
  • --ch-danger
  • --ch-border
  • --ch-viz-1

The second edge is status:'failed'; its label overrides the amount caption.

Each kind maps to a lucide glyph and a tone: input=primary, output=accent, tx=fg, address=muted, exchange=info, coinjoin=warning. Emphasis (shown on the tx) draws the aurum accent ring. Optional mono amount sits under the title.

input

Transaction flow: 1 nodes, 0 connections.

<TransactionFlow nodes={[{ id: "g-input", kind: "input", label: "UTXO" }]} edges={[]} />
output

Transaction flow: 1 nodes, 0 connections.

<TransactionFlow nodes={[{ id: "g-output", kind: "output", label: "Recipient" }]} edges={[]} />
tx

Transaction flow: 1 nodes, 0 connections.

<TransactionFlow nodes={[{ id: "g-tx", kind: "tx", label: "Transaction", emphasis: true }]} edges={[]} />
address

Transaction flow: 1 nodes, 0 connections.

<TransactionFlow nodes={[{ id: "g-address", kind: "address", label: "Address" }]} edges={[]} />
exchange

Transaction flow: 1 nodes, 0 connections.

<TransactionFlow nodes={[{ id: "g-exchange", kind: "exchange", label: "Exchange" }]} edges={[]} />
coinjoin

Transaction flow: 1 nodes, 0 connections.

<TransactionFlow nodes={[{ id: "g-coinjoin", kind: "coinjoin", label: "CoinJoin" }]} edges={[]} />

Connector tokens

Connectors and node chrome read only from the --ch-* token scale, so the graph re-themes with the rest of the system across dark, light, and Harbor Mode. Status maps straight to the semantic tokens; node tints ride viz-1 (input / primary), accent (output), and border/surface for the card frame.

  • --ch-viz-1
  • --ch-success
  • --ch-warning
  • --ch-danger
  • --ch-border