1
0
forked from GRIN/grim
Commit Graph

39 Commits

Author SHA1 Message Date
2ro 6bf6f3a2e9 Goblin: route macOS goblin: link clicks to the send-review screen
The goblin: scheme was registered everywhere last night, but macOS is the one
platform that delivers a scheme click as a Carbon/Apple Event (kAEGetURL), not on
argv and not through any path winit or eframe surface, so on a Mac the click went
nowhere.

Install a kAEGetURL handler straight on the shared NSAppleEventManager at startup
(macOS only), pull the URL string out of the event, and feed it to on_data, the
exact same entry the desktop argv path uses. The per-frame Goblin router then lands
the pay URI on the prefilled review screen, identical to a scanned checkout QR or a
Linux argv link. This covers both a cold launch (event queued at start-up) and a
warm click (app already running).

The bridge is entirely cfg(target_os = "macos"): zero bytes on Linux, Windows and
Android (Linux binary size byte-for-byte unchanged). It talks to the Objective-C
runtime through the classic objc crate, which is already in the macOS build graph
via nokhwa/cocoa/metal/wgpu, so it adds no new dependency tree, only its own small
handler class. It registers its own Apple Event handler rather than touching the
NSApplicationDelegate winit owns, so nothing winit does is clobbered.
2026-07-05 03:44:54 -04:00
2ro 5352afee4e Goblin: proof-on-request payments (wallet side of the frozen contract)
Implements the Goblin-wallet half of the proof-on-request architecture
(magick payment infra spec section 4/5): the buyer's wallet threads a
native Grin payment proof per transaction, off by default and on only
when the scanned pay URI asks for it, and auto-delivers the proof to the
market and watcher on finalize. Person-to-person sends are unchanged.

W1 pay-URI parser (payuri.rs): PayUri gains proof/order/notify, each
fail-closed (a bad value drops to None and never blocks the payment).
proof is a grin1/tgrin1 slatepack-address shape check, order is an opaque
control-stripped routing key capped at 64 bytes, notify is an npub shape
check. Unknown-param forward-compat and the magick interop tests still
hold. 12 new parser tests.

W2 proof threading: WalletTask::NostrSend carries proof/order/notify; the
handler re-parses proof authoritatively into a SlatepackAddress and calls
w.send(a, Some(addr)) instead of the hard-coded None, setting
payment_proof_recipient_address. The order handle, watcher npub, and
amount persist in TxNostrMeta (new serde-default fields) before dispatch,
so a crash between send and finalize loses nothing.

W3 review indicator: the send-review screen shows a small "proof included"
row when proof mode is active. New t!() keys row_proof / row_proof_val in
all six locales (drift test green).

W4 proof delivery on finalize: when a finalized SEND was sent in proof
mode, the wallet publishes the two contract events: a plain unencrypted
kind-17 "payment sent" receipt to the app relays (payment-request tag =
order handle; proof and kernel deliberately omitted to avoid leaking the
buyer's sender address; flips the page to "detected", never "paid"), and
a NIP-59 gift-wrapped kind-17 rumor to the notify npub carrying the full
proof JSON plus a kernel-excess tag. Both are enrolled in the existing
crash-safe reconcile pass and retried until a relay accepts them.
wrapv3 gains wrap_kind() to gift-wrap an arbitrary rumor kind.

Matching is by the payment-request (invoice number) tag alone; the wallet
never learns magick's internal orderId. No merchant-side auto-receipt is
built: the rewritten spec has the buyer publish on finalize instead.
2026-07-05 03:44:53 -04:00
2ro 9caa7f7ffe Goblin: goblin: payment deep link opens straight to send review
Web "Open in Goblin" pay buttons fired generic nostr: URIs, which the
OS routed to whatever social client claims nostr:. Register a dedicated
goblin: scheme and route it (plus nostr: pay URIs) to the prefilled
send-review screen, the same destination as scanning a checkout QR.

Parser (payuri): accept goblin: alongside nostr: (same payload, either
scheme); add is_pay_uri() to tell a payment link from a slatepack.

Runtime: an argv/intent/socket payload that is a pay URI is stashed and
opened by the Goblin surface via SendFlow::from_deeplink, which shares
the exact apply_scan path the camera uses. Desktop cold + warm start
(argv + single-instance socket) and Android cold + warm (intent-filter)
covered.

Registration: Linux .desktop x-scheme-handler/goblin, Android goblin
intent-filter, macOS CFBundleURLTypes, Windows WiX HKCR URL protocol.
2026-07-05 03:44:53 -04:00
2ro aff0c7c1b2 Goblin: fix desktop clipboard (copy/paste lost the selection)
On desktop the Paste button in the wallet-restore seed entry did nothing, and
the mirror copy on the new-wallet creation screen was equally broken: a copied
recovery phrase never made it to the clipboard.

Root cause (inherited from GRIM, not a Goblin regression — the two clipboard
impls are byte-identical): copy_string_to_buffer / get_string_from_buffer each
created a fresh `arboard::Clipboard` and dropped it the instant the function
returned. On Linux (X11 AND Wayland) the clipboard selection is owned by the
live Clipboard instance, so dropping it immediately released ownership and the
copied text vanished before it could be pasted. Reproduced with arboard 3.6.1
on a Wayland session: fresh-instance-per-call read back empty; one persistent
instance across set+get read back correctly.

Fix: keep ONE long-lived `arboard::Clipboard` on the Desktop platform (behind a
Mutex, since the trait methods take &self and arboard's take &mut self), so our
process stays the durable selection owner. Also stop unwrap()-panicking on a
clipboard backend error — a failed copy/paste now logs instead of crashing.

Every clipboard button in the app routes through this one platform pair
(onboarding paste/copy, GRIM creation paste/copy, proof, slatepack message
entry, tx/receipt copy, receive copy, npub/nsec/backup copy, the shared
TextEdit paste), so this single change repairs the whole class at once.

Verified end-to-end: an #[ignore]d clipboard_roundtrip test drives the real
Desktop impl on the live session clipboard and asserts a 24-word phrase
survives copy -> paste (run with --ignored). It passes on Wayland now and would
fail under the old pattern.
2026-07-05 01:13:49 -04:00
2ro 6543a9a4ea Goblin: GoblinPay QR scans straight to review
When a scanned QR is recognized as a full GoblinPay payment payload (a
recipient key that decodes locally to a concrete pubkey AND a validated
amount), skip the recipient discovery/search step and open the review screen
prefilled with recipient, amount and memo. The merchant checkout QR already
carries everything needed to pay, so re-walking the recipient search was
redundant. The review screen still confirms the send unchanged (the user
holds-to-send); nothing auto-sends.

recognize_scan classifies the payload:
- Review: nprofile/npub/64-hex recipient + amount -> straight to review. A
  cheap LOCAL contact lookup supplies a friendly name; otherwise the short
  npub (no network resolution on this path). nprofile relay hints carry
  through as delivery targets.
- Search: a name/@handle (needs NIP-05 resolution), an amount-less key, or
  non-nostr text -> the pre-existing search-box path, with any amount/memo
  still prefilled.

This covers every scanner entry into the send flow (search-field scan icon
and the header scan-to-pay screen), so it works from anywhere the payment
scanner is reachable.

Unit tests on the pure recognize_scan / decode_recipient_key:
GoblinPay-uri-with-amount -> Review; key-without-amount -> Search;
name+amount -> Search; non-nostr -> Search; key decode variants.
2026-07-05 01:13:49 -04:00
2ro ce6ac5a1e4 Goblin: language-aware news panel
Show the newest news article whose language matches the wallet's active
locale, falling back to the newest English article when none exists.

Language detection per article, in priority order:
1. An event language tag: NIP-32-style ["l","<code>","ISO-639-1"] or the
   bare ["l","<code>"] / ["lang","<code>"] (code is the tag's 2nd element),
   extracted in handle_news and persisted on NewsItem.lang.
2. A trailing "[xx]" marker on the title (case-insensitive, xx = ISO 639-1
   two letters), e.g. "2026-07-05 Welcome to Goblin [de]".
3. No marker anywhere = English.

Selection happens at the data layer (news_latest): the store stays
language-agnostic (still newest-per-d-tag, cap 8, edit-in-place). Among all
cached articles, filter by detected language, take the newest by created_at;
the "[xx]" marker is stripped from the displayed title. The app locale is
folded to its ISO 639-1 primary for matching (zh-CN -> zh).

The GOBLIN_FAKE_NEWS debug hook now injects an English + German sample so the
panel selection can be screenshotted per locale.

Unit tests: tag detection (both shapes), title-suffix detect + strip,
no-marker-means-English, zh-CN folding, locale match + English fallback,
newest-within-language-slice.
2026-07-05 01:13:49 -04:00
2ro 2afea5abc0 i18n: translate lagging fallback strings and localize settings username hint 2026-07-04 23:25:06 -04:00
2ro a9023d0404 README: drop stale onion claim (Tor-exit only since 134), style sweep
Every relay, money path included, is reached over a Tor exit to its
clearnet host; the pinned-onion wording was Build <134. Em dashes
normalized per house style.
2026-07-04 23:25:06 -04:00
2ro e14a16f693 README: Build 136 news panel on Home
Latest article from the official Goblin news key (kind 30023) between
Send/Receive and Recent Activity; hidden when empty; latest-only with
edits-in-place.
2026-07-04 23:25:06 -04:00
2ro 47b095ab88 Goblin Build 136 - home news panel, faster send confirmation
Home now shows the latest post from the Goblin news key (kind 30023) in
a card with tappable links; the panel stays hidden until a post is seen.
Desktop Home widens to use the available space. Send confirms faster.
2026-07-04 20:42:17 -04:00
butler 71570980fe docs: mixnet references updated to Tor (build 134) 2026-07-04 20:42:17 -04:00
2ro 05ee05e2d2 Goblin: dedupe balance sync indicator
Remove the Build 135 balance-hero "Updating…" line. During a routine
sync it duplicated the header node card's "Syncing" status, so a funded
wallet showed two updating indicators at once. Keep the established
"Balance updating…" line (zero-balance / first-sync case) and the header
status as the single sync indicators. Drop the now-orphan
goblin.home.updating key from all six locales (i18n drift green).
2026-07-04 20:42:17 -04:00
2ro 04f8741686 chore: gitignore local release artifacts 2026-07-04 20:42:17 -04:00
2ro 1d7775a037 Goblin Build 135 - Tor credit, balance updating indicator, Nym sweep
- Third-party credits: replace the "Nym mixnet" row with "Tor (arti)" (0.43,
  linking the arti repo), matching the other credit rows' hardcoded style. No
  locale strings existed for it (credit labels are hardcoded, not localized).
- Balance: show a quiet "Updating…" line under the balance while the node is
  still warming, reusing the existing wallet.syncing() signal and the
  balance-updating line's muted style; it clears once the node is synced. New
  t!() key goblin.home.updating added to all six locales (i18n drift green).
- Nym sweep: Cargo.toml package description "Nym mixnet" -> "Tor". The only
  other user-facing Nym reference was the credit above. Remaining references
  are the deliberately-dormant `nym` feature/module and internal code comments,
  left as-is; README and all locale values were already Tor.
2026-07-04 06:21:05 -04:00
2ro 174e387a87 Goblin: retire Nym from the public toolchains + drop internal test harnesses
- CI (release.yml/build.yml): remove fetch-nym + AWS_LC_SYS_PREBUILT_NASM;
  the default cargo build --release is Tor/arti only now (nip44 fetch kept).
- Cargo.toml: nym-sdk is optional behind the `nym` feature so the default
  build never pulls it.
- Delete the dead Nym-era probes (xrelay_smoke, connect_timing,
  tunnel_measure) that referenced the removed Nym API and broke `cargo test`.
- Untrack the internal E2E harnesses (e2e.rs, nostr_e2e.rs) via .gitignore;
  gate `mod e2e` behind the `e2e-internal` feature so clones still compile.
- Refresh stale Nym comments in build.rs and the build scripts.
2026-07-04 06:21:05 -04:00
2ro 7b56855e16 Goblin Build 134 - Tor delivery fixes (drop the flapping onion)
build133 shipped the Tor transport but two delivery bugs remained; this
fixes both so payments resolve through confirmations again.

- Drop the pinned relay .onion. It was a single fragile hidden-service hop
  shared by every wallet; under load it flapped (WebSocket 1006), and when
  it dropped mid-handshake a payment stalled after the first gift-wrap --
  you'd get the incoming alert but the money never confirmed. Every relay is
  now reached over the Tor exit to its clearnet host: your IP still stays
  hidden from the relay, with no fragile onion hop to wedge. The has-onion
  gate that rejected an onion-less relay list is removed, and the pinned
  candidate pool carries no onion/exit fields.

- Tor-friendly relay set. Defaults/fallbacks had included relays that refuse
  Tor-exit connections (damus, nos.lol); wallets that fell back to them
  couldn't send at all. Defaults and the pinned pool are now
  relay.floonet.dev, relay.0xchat.com, offchain.pub.

- confirm-before-sent no longer false-fails across a relay reconnect (a
  confirmed-received wrap is treated as sent-pending instead of re-dispatched,
  which had duplicated wraps and hung the spinner); a v3 gift-wrap unwrap
  failure no longer silently drops the message.

Validated over Tor with two funded wallets on two independent mainnet nodes:
connect in seconds, send to finalize in 8s.
2026-07-04 05:33:48 -04:00
2ro 1e2f41b404 README: update transport description from Nym mixnet to Tor
The README still described the old Nym-mixnet transport, including a
reference to src/nym/sidecar.rs which no longer exists post-switch.
Update the intro, feature list, payment-travel diagram, and build
instructions to describe the current embedded-Tor (arti) transport:
in-process, dialed at the relay's pinned .onion, no sidecar, no sibling
checkout needed for the default build.
2026-07-04 03:52:29 -04:00
2ro 6f1caf4511 Goblin Build 133 - Tor transport (replaces the Nym mixnet)
The wallet's private transport moves from the Nym mixnet to embedded Tor
(arti, copied from GRIM's engine): it dials the relay's pinned .onion, so
the relay never learns your IP, while the relay + NIP-59 gift-wrap hide the
rest - content, sender, and (via a relay-side randomized release) timing.
The Grin node stays on the clear internet as before.

Why leave the mixnet: the Nym free-tier bandwidth this depended on is being
removed upstream (the grant expires at UTC midnight; the paid path requires
holding NYM tokens), so a payments wallet can't stand on it. Tor is
unmetered, embedded in-process on mobile, faster where users wait, and
lighter on the battery.

Preserved intact: the confirm-before-sent guard, relay-gated readiness, and
the lazy warm-on-activity node polling. src/nym/ is feature-gated off (arti
and nym-sdk can't share one binary); full removal is a follow-up.
2026-07-04 03:35:31 -04:00
2ro 1c8d848e18 Goblin Build 132 - payments never fail silently
Adds confirm-before-sent: a payment is not shown as "sent" until the relay
actually confirms receipt. If the path is slow or a send doesn't land, you now
see a clear "not confirmed — retry" instead of a false "sent" that quietly loses
the payment.

Routing is unchanged from prior builds: all wallet nostr traffic — slatepacks,
payment requests, identity, discovery, goblin.st name + relay lookups — rides
the mixnet; the grin node and price/fiat lookups stay direct.
2026-07-03 22:50:02 -04:00
2ro d05e015f98 Goblin Build 131 - connectivity sweep
Connect reliability, measured before release:
- Cold start: the wallet races two mixnet entry-gateway connects and takes the
  first up, so a dead random draw no longer costs the full timeout (dead-round
  rate drops from p to p^2; verified across 30 cold trials).
- Dead exits are condemned in ~10s instead of ~32s (fresh-tunnel probe budget
  5s x 2 rounds, 4.2x margin over the worst measured healthy probe), removing
  the 50-70s worst-case connects. Established-tunnel keepalive unchanged.
- "Connecting relays..." clears in ~2-4s after saving the relay list (the
  Connected flag now tracks the real relay-up signal instead of waiting on a
  30s catch-up fetch); identity publishes are time-boxed; the onboarding
  Claim button un-gates equally sooner.
- Gateway-race and probe timings are now visible in [timing] logs.

Also: the update banner shows Goblin build numbers (not the inherited 0.3.6),
and the nip44 crate is consumed from crates.io (v0.3.0) - no sibling checkout
needed to build.
2026-07-03 17:22:42 -04:00
2ro e8bfe8d76f Goblin Build 130 - Nym connect reliability
Bugfix: the mixnet exit-liveness probe now races two stable targets over two
rounds instead of a single one-shot 1.1.1.1 connect, so a healthy tunnel is no
longer false-condemned and reselected forever. Fixes the intermittent
Connecting to Nym hangs that could take minutes or never resolve (verified:
15/15 cold starts connected, zero hangs).

Also: the Android versionCode/versionName now track the Goblin build number
(were frozen at GRIM's 5 / "0.3.6"), so the OS detects upgrades correctly.
2026-07-03 11:49:01 -04:00
2ro 71f7584800 Goblin Build 129 - relay migration
Bugfix: the default and fallback messaging relay moved from relay.goblin.st
(being retired) to relay.floonet.dev, so new installs and reconnects use the
live relay. Built-in relay fallback list updated to match.
2026-07-03 04:02:23 -04:00
2ro 523d397ad7 Goblin Build 128 - warm connect, instant price, faster reads 2026-07-03 00:09:31 -04:00
2ro ce7008665a Goblin Build 127 - payment request notifications, remove avatar name ring, fix CI 2026-07-02 23:01:49 -04:00
2ro 4ab91c6ece Goblin Build 127 - payment request notifications, remove avatar name ring 2026-07-02 22:31:16 -04:00
2ro 36509c6b9a Goblin Build 127 - payment request notifications 2026-07-02 22:20:51 -04:00
2ro c0981916da Goblin Build 126 - major mixnet transport speedup 2026-07-02 20:54:41 -04:00
2ro c5fbb9fa14 Goblin Build 125 - faster Nostr reads and Nym reconnect 2026-07-02 19:18:35 -04:00
2ro b7d479ede7 Goblin Build 124 - fix in-app update download names 2026-07-02 17:09:33 -04:00
2ro f79bf9d926 Goblin Build 123 - fast relay connect, nostr-app login, scan amounts, name outline 2026-07-02 15:51:37 -04:00
2ro d1070008e7 Goblin Build 122 - drop notification enable-node action; re-enable macOS release CI 2026-07-02 13:38:57 -04:00
2ro 060272626a Goblin Build 121 - restore scoped exit + relay.floonet.dev money-path cutover 2026-07-02 13:27:18 -04:00
2ro 5f90f00d3b Goblin Build 120 - remove dead scoped-exit egress 2026-07-02 10:06:51 -04:00
2ro 3a3cf8fdb0 Goblin Build 119 - paste npub in Send-to (issue #1) 2026-07-02 09:56:40 -04:00
2ro ebe5bc94eb Goblin Build 118 - fast connect (drop blocking exit), avatar ring, ecosystem 2026-07-02 09:48:38 -04:00
2ro 90eb0500c1 Goblin Build 117 - avatar ring gap + magick/floonet ecosystem 2026-07-02 09:35:57 -04:00
2ro 2d2bf326b3 Goblin Build 116
Floonet scoped Nym exit on the money-path relay (dial a relay operator's
co-located exit over a MixnetStream, TLS end to end, no public DNS; anchor +
fallback, never pin-only), NIP-44 v3 gift wraps (G4), mix-DNS, localization,
GUI polish. Verified end to end: two wallets complete a real gift-wrapped Grin
payment over relay.goblin.st, finalized + posted on mainnet.
2026-07-02 04:23:06 -04:00
2ro 5deffbda4c settings: GRIM link now points at the live upstream
The Settings third-party 'GRIM (upstream wallet)' link opened github.com/ardocrat/grim
— a stale personal fork ~106 commits behind. Point it at github.com/GetGrin/grim, the
live GitHub mirror of canonical code.gri.mw/GUI/grim.
2026-06-18 00:24:34 -04:00
2ro 54e1e83bfe Goblin — Build 98 2026-06-17 22:22:21 -04:00