Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture: the three pillars

Summary. Goblin is layered. A GRIM wallet/node core handles money; a Nostr layer handles messaging and identity; a Nym layer handles transport. The UI ties them into a Cash-App-style experience. Each layer is replaceable in principle and isolated in the code.

The stack, top to bottom

┌─────────────────────────────────────────────────────────┐
│  Goblin UI   (src/gui/views/goblin/)                     │
│  Home · Pay · Activity · Receive · Me · Send flow · …     │
├─────────────────────────────────────────────────────────┤
│  Nostr messaging   (src/nostr/)                          │
│  identity · gift-wrapped slatepacks · ingest policy ·    │
│  relays · NIP-05 names · per-wallet service thread       │
├─────────────────────────────────────────────────────────┤
│  Nym mixnet transport   (src/nym/)                       │
│  in-process SOCKS5 client → 5-hop mixnet → exit          │
│  ALL relay sockets + ALL HTTP go through here            │
├─────────────────────────────────────────────────────────┤
│  GRIM wallet + node engine   (wallet/, node/)            │
│  seed · keys · sync · Mimblewimble slatepack tx machine  │
└─────────────────────────────────────────────────────────┘
        │                                   │
   Nym mixnet                        Grin node (direct,
 (identity + payments               public chain data,
  + price + avatars)                 not tied to identity)

Why these three

Each pillar exists because the layer below it leaves a gap:

  • GRIM gives a correct, complete Grin wallet, but its native payment UX is file-swapping. Gap: usability.
  • Nostr closes that gap: it turns the slatepack handshake into encrypted, store-and-forward messaging addressed by key, with human usernames on top. Gap it leaves: the relay still sees your IP, and an observer can correlate the two legs of the exchange by timing.
  • Nym closes that gap: routing everything through a mixnet hides your network identity and breaks timing correlation. Result: who-pays-whom is private from the chain up and the network down.

What rides which transport

A deliberate split (see the project decisions):

TrafficPathWhy
Nostr relay sockets (payments, identity events)Nym mixnetReveals who you talk to; must be hidden.
NIP-05 name lookups, price feed, avatars (HTTP)Nym mixnetReveal who you are / who you’re paying.
Grin node connection (block sync, broadcast)DirectPublic chain data, identical for everyone, not tied to your identity. Anonymizing it buys little and costs reliability.

Code map

LayerDirectoryStart here
UIgoblin/src/gui/views/goblin/mod.rs (GoblinWalletView)
Nostrgoblin/src/nostr/mod.rs, client.rs
Nymgoblin/src/nym/sidecar.rs, transport.rs
Wallet↔Nostr gluegoblin/src/wallet/wallet.rsWalletTask::Nostr*
GRIM coregoblin/wallet/, goblin/node/inherited from GRIM
Identity servergoblin-nip05d/ (sibling crate)the NIP-05 authority

A payment in one breath

You tap Pay → GRIM builds a slatepack → the Nostr layer gift-wraps it and publishes it to relays → the bytes leave your machine through the Nym mixnet → the recipient’s wallet ingests it, auto-builds its half, and replies the same way → your wallet finalizes and GRIM broadcasts to the Grin node. The payment-flow page walks every step.

References

  • Layer directories: goblin/src/{gui/views/goblin,nostr,nym}/, goblin/wallet/, goblin/node/.
  • Transport split rationale: goblin/README.md; see also Nym in Goblin.
  • Architecture overview diagram: Goblin-Transport-Overview.pdf (project root).