nip44 is now published, so depend on the registry crate instead of the local
path checkout. A fresh checkout (the Mac included) no longer needs ../nip44
cloned next to goblin - that missing sibling was the reported build failure.
Byte-identical source (0.3.0 was published from this tree); cargo check --lib
green. nym stays a path dep (private fork, not on crates.io).
The 180s cold connect was the public-IPR path (nested TCP over the mixnet) plus
the public-exit lottery -- NOT the scoped exit, which was removed by mistake in
3372202. Restore the co-located MixnetStream exit: a relay connects in 0-2s over
it (measured), vs 15-180s over the tunnel.
- Cold-start sequencer: streamexit::is_ready + a bounded EXIT_HEAD_START gate in
nymproc so the exit client claims its Nym bandwidth grant before the tunnel,
avoiding two-client serialization (~1min otherwise). No SDK surgery.
- Pin relay.floonet.dev as the primary money-path relay (with its co-located
exit) in PINNED_POOL; keep relay.goblin.st as a secondary through transition.
- E2E: a funded 0.1 GRIN payment finalizes in 6s over the exit across two
different Grin nodes (grincoin.org, main.gri.mw).
The exit is unpinned everywhere, so the streamexit module + the exit_for/
exit_connect forks in transport + http were dead code. Remove them; the
wallet's only mixnet path is the smolmix tunnel.
Money path:
- Scoped, unbonded Nym exit for the money-path relay: the wallet dials a
relay operator's co-located exit over a MixnetStream (src/nym/streamexit.rs)
which pipes to its one relay; hostname-validated TLS end to end, no public
DNS. Anchor + fallback (never pin-only): any exit failure degrades to the
smolmix tunnel. relay.goblin.st's exit address is pinned in the relay pool
(src/nostr/pool.rs) and the maintainer gist so it bootstraps offline.
- STREAM_SETTLE bridges the open-before-accept gap so the first TLS byte is
not dropped into a stalled handshake.
- Verified end to end: two wallets complete a real gift-wrapped Grin payment
through relay.goblin.st over the exit, finalized + posted on mainnet
(src/wallet/e2e.rs, ignored live test).
Encryption:
- Adopt NIP-44 v3 for the NIP-17 gift-wrap path (G4): src/nostr/wrapv3.rs,
nip44 path dep; v3<->v3 and v3->v2 interop.
Also: mix-DNS (src/nym/dns.rs), full localization pass, GUI polish,
avatar-ring example, Android icon/script updates, GRIM deviation notes,
xrelay + connect-timing tests.
The .msi shortcuts already carry the icon, but the bare goblin.exe had none, so
Explorer/taskbar showed the generic exe icon. build.rs now embeds
wix/Product.ico (the yellow Goblin icon) as the exe's application icon resource.
Gated to Windows hosts: winresource is a `cfg(windows)` build-dependency and the
embed fn is `#[cfg(windows)]` (with a no-op stub otherwise), so Linux/macOS/
Android builds don't compile or run it — other releases are untouched. The embed
is best-effort (warns, never fails the build) in case rc.exe is unavailable.
The vendored 'openssl' dependency existed only to statically link OpenSSL on Linux/Android (where native-tls uses it). In the global [dependencies] it also forced openssl-src to compile on Windows and macOS, which don't use OpenSSL at all (SChannel / Security.framework). On the Windows MSVC CI runner that build fails: openssl-src's perl Configure runs under Git-Bash's MSYS perl, which lacks Params::Check / Locale::Maketext::Simple. Gating the dependency to cfg(any(linux, android)) removes the pointless, fragile build on Windows/macOS and keeps the self-contained static link on Linux/Android. No behavior change on any platform.
Settings now says "Manual transaction" and the privacy row reads "Messages &
lookups" opening a new Network privacy page that tells the truth: messages,
names, price and avatars ride the Nym mixnet; the grin node connects directly.
README and lander updated to match.
Requests are messages, payments are final: declining a request now sends the
requester a void control message (NIP-17), a requester can cancel a request they
sent (cancels the local invoice and notifies the payer), and incoming requests
resolve the sender's verified @username instead of a bare npub. The Requested
amount on the success screen is centered. New NostrDecline/NostrCancel tasks and
a goblin-action control message carry it, bound to the stored counterparty.
Localization: every Goblin-screen string moved to t!() keys (370 keys) and
translated into de/fr/ru/tr/zh-CN, guarded by a key/placeholder drift test.
System-locale auto-detect now matches region locales like zh-CN.
Pay: stop reddening the amount while typing — requesting more than you hold is
a valid request, so the digits stay black. Pressing Pay without enough funds
now shakes and briefly flashes the amount red and buzzes the phone, then
settles back. Bigger scan-to-pay puck.
Settings: the username "@" moves inside the field as the "@yourname"
placeholder (a leading "@" the user types is stripped). Mixnet routing is
shortened to "All traffic" and flagged in the privacy color. The Build row
links to GitHub releases. Network reads "MW + Nym mixnet + nostr". The Nym
third-party row shows the linked SDK version instead of "socks5".
Wallet: expose GRIM's native by-hand slatepack flow as an advanced
"Slatepacks" page — paste to receive/pay/finalize, or create a payment
slatepack to hand over. The fallback for when a payment can't ride a @username.
CI: fix the red GitHub builds. nym-sdk is a path dep on ../nym, which the
runners didn't have. A composite action materializes the pinned upstream nym
commit plus Goblin's small Android webpki patch before each build; aws-lc-sys
uses prebuilt NASM on native Windows.
Builds: strip release binaries, dropping ~17 MB of debug symbols from the
desktop build.
Goblin now links nym-sdk directly and runs its SOCKS5 client on an
internal tokio runtime exposing 127.0.0.1:1080 — the same loopback seam
the transport already dials. There is no sidecar subprocess and no
bundled/embedded/sideloaded helper binary; the goblin process itself owns
:1080. This mirrors how GRIM links arti/Tor in-process. Verified live: the
mixnet comes up in ~1.4-2s (gateway persisted in ~/.goblin/nym, reused
across launches) and a relay connects in ~2s over it, with no separate
process.
- Cargo.toml: add nym-sdk (path dep on the local nym checkout, which carries
the Android webpki-roots patch) + rustls with the ring feature.
- src/lib.rs: install rustls' ring CryptoProvider at startup. Linking nym-sdk
pulls aws-lc-rs alongside our ring; with two providers present rustls 0.23
won't auto-pick a default and tokio-tungstenite/reqwest panic on the first
TLS handshake. nym uses its own explicit provider, so this only steers our
relay/HTTP TLS.
- src/nym/sidecar.rs: replace the subprocess machinery with an in-process
Socks5MixnetClient (persistent storage; ephemeral fallback) kept alive for
the process lifetime on a dedicated runtime. Drops the binary lookup, embed
extraction, init/launch, and child management.
- build.rs: drop the GOBLIN_NYM_*_BIN embed block (nothing to embed).
- src/nym/{mod,transport}.rs, src/nostr/{mod,avatar}.rs: docs now describe the
in-process client; clear stray "old Tor/arti" wording (no Tor transport code
remains — only grin-core's slatepack OnionV3Address, which is unrelated).
Also: named users now get the pubkey-seeded gradient background with their
initial composited on top (instead of the Grin mark) — gui identicon.rs gains
gradient_bg_svg and widgets.rs gains gradient_letter_avatar; avatar_any routes
named keys to it. Verified live with @nymgoblin.
Ship the bundled nym-socks5-client on Windows and Android, not just Linux:
- sidecar.rs resolves the binary per platform — nym-socks5-client.exe on
Windows; on Android the sidecar rides in the APK jniLibs as
libnym_socks5_client.so and is launched from the native-library dir (the
one exec-allowed path), located via NATIVE_LIBS_DIR.
- Restore a vendored, statically-linked OpenSSL. Upstream Grim got this from
arti's static feature; dropping arti for Nym took it with it, which broke
Android/cross builds (no system OpenSSL for the target) and left desktop
dynamically linked to libssl. Inert on Windows/macOS (SChannel/Security.fw).
- android.sh bundles the sidecar into jniLibs per ABI; scripts/nym-android.sh
cross-builds it. Onboarding copy: Tor -> the Nym mixnet.
Verified end to end on an x86_64 emulator: the sidecar extracts, launches,
initialises, and opens the mixnet SOCKS5 proxy on 127.0.0.1:1080.
Route every relay and HTTP request (nostr relays, NIP-05, price) through
a local nym-socks5-client sidecar on 127.0.0.1:1080, so all traffic
egresses via the 5-hop Nym mixnet and nothing touches the clear net.
- Add src/nym/: SOCKS5 HTTP client (reqwest socks5h), NymWebSocketTransport
for the nostr relay pool (tokio-socks dial + TLS/ws handshake over the
mixnet), and a sidecar launcher that reuses or spawns nym-socks5-client.
- Swap the nostr-sdk transport off ArtiWebSocketTransport; route nip05.rs
and price.rs off Tor; revert the clearnet username-lookup shortcut.
- Remove the embedded arti Tor client wholesale: the onion-service
listener and send-to-onion path in the wallet, the legacy transport
GUI tab, the Tor settings page, src/tor/, the webtunnel pluggable
transport (Go build + submodule), and all arti crates from Cargo.toml.
The Grin node connection is unchanged (chain data, no payment metadata,
and never used Tor). The network requester the sidecar routes through is
configured via GOBLIN_NYM_PROVIDER / NETWORK_REQUESTER at deploy time.
The read-only NIP-05 username lookups (resolve + check_availability) carry no
secret and need no anonymity — routing them over Tor is what made choosing a
username slow. They now use a fast clearnet HTTPS GET (reqwest + rustls/ring,
so it still cross-compiles to Android), falling back to Tor only if clearnet is
blocked. The anonymity-critical paths (slatepack delivery, NIP-98-signed ops)
are untouched.
tests/nostr_e2e.rs (run with --ignored):
- nip17_slatepack_roundtrip: Alice gift-wraps a slatepack payment DM with a
subject to Bob over wss://nrelay.us-ea.st; Bob unwraps, the seal-author ==
sender invariant holds, the slatepack and subject extract intact.
- nip05_registration_roundtrip: registers a fresh name on goblin.st with a
real NIP-98 signature, resolves it back to the right pubkey, releases it.
Both pass against the live deployed infrastructure.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Infrastructure (P0): deployed nostr-rs-relay (wss://nrelay.us-ea.st) and the
goblin-nip05d NIP-05 service (goblin.st) on us-ea.st with TLS + DNS.
Brand & theme (P1): Goblin name/icon/data-dir (.goblin); three-theme token
system (light/dark/yellow) in gui/theme.rs with colors.rs remapped as a shim;
Geist + Geist Mono fonts; AppConfig theme/density/last_wallet_id.
Nostr subsystem (P2-P3): src/nostr/ with NIP-06 identity (seed-derived,
NIP-49 encrypted), per-wallet rkv archive, guarded ingest policy (never
auto-pays Invoice1; binds replies to the stored counterparty npub), NIP-17
send/receive pipeline, NIP-05 client. Relay traffic routed over the embedded
arti Tor client via a custom WebSocketTransport. Wired into Wallet lifecycle
and the task handler. 26 unit tests pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Limit loading at tix list
- Sort txs by confirmation status to show txs waiting for an action at top
- Ability to delete wallet from the list without opening
- Optimize Tor connection on account switch
Reviewed-on: https://code.gri.mw/GUI/grim/pulls/53
- Ability to export and verify payment proofs
Some fixes:
- Migrated tx heights store from lmdb (also changed heights key from local id to slate_id to avoid conflict between wallets)
- Close address panel on wallet change
Reviewed-on: https://code.gri.mw/GUI/grim/pulls/52
- Update common dependencies
- Optimize check of running Tor service
- Async peer saving
- Add mainnet and testnet seeds
- Remove grinnode.live from default external connections
Reviewed-on: https://code.gri.mw/GUI/grim/pulls/43
Use node and wallet submodules to avoid dependency conflicts inside grin-wallet on grin repo update.
Reviewed-on: https://code.gri.mw/GUI/grim/pulls/29