1
0
forked from GRIN/grim
Commit Graph

1057 Commits

Author SHA1 Message Date
2ro 54344bd1d3 android: one-shot payment-requested notification (id=3)
Fire a separate high-importance system notification when an incoming
payment request (Invoice1 -> SurfaceRequest) is ingested over nostr,
mirroring the existing received-payment notification (id=2). Fail-open on
a missing JNI handle; fires once per not-yet-seen slate. No-op off Android.

Also add examples/tunnel_measure.rs, a dev harness for measuring the Nym
read tunnel (cold connect + warm per-fetch latency over the real transport).
2026-07-02 22:19:23 -04:00
2ro 23bb845689 nym: major transport speedup (throughput + reuse), money path unchanged
The in-process smolmix tunnel was far slower than the old SOCKS5 model.
Fixes:
- smolmix TCP buffers 8KB -> 256KB and burst 1 -> 64: bulk throughput
  ceiling rises ~32x (was capping relay backfill and JSON reads at a few
  KB/s).
- Read tunnel runs a high-traffic mixnet profile (cover traffic off, higher
  send rate, fewer reply SURBs) for lower latency; per-hop mix delays kept.
  The scoped-exit money-path client is separate and unchanged.
- HTTP over the mixnet now reuses connections (keep-alive pool) instead of a
  fresh TCP+TLS+HTTP handshake per request - fixes slow price and username
  reads.
- DNS prewarm no longer skips on cold start and serves stale-while-revalidate
  for known hosts, so a dial never blocks on DoT/DoH.

Money path (streamexit.rs, transport.rs) byte-for-byte unchanged.
2026-07-02 19:57:35 -04:00
2ro aa39737d3b nym: fast interactive reads + faster reconnect (no money-path change)
Profile/username/NIP-05 reads were ~10s and the tunnel stalled 20s on a
dead gateway. Fixes:
- Profile/accepts/dm-relay fetches stream scoped to their dial set and
  return on the first matching event instead of waiting for every relay
  (or the full timeout) - the ~10s nprofile search.
- HTTP over the mixnet is tunnel-first, scoped-exit only as fallback when
  the tunnel is not up (NIP-11/price/name lookups are public data).
- Name re-verify interval 78s -> 6h (was a debug leftover churning reads).
- Discovery relay NIP-11 probes run in parallel, not sequentially.
- Tunnel build timeout split from the exit dial cap: build 20s -> 10s
  (env GOBLIN_NYM_BUILD_TIMEOUT) so a dead gateway is abandoned fast; the
  exit money-path dial stays 20s.
- Cold start brings the tunnel up first, then prewarms the exit once after
  publish (grant sequencing preserved).
- NIP-05 search bounded to 15s instead of hanging up to ~90s.

Money path (transport.rs, streamexit.rs) byte-for-byte unchanged.
2026-07-02 18:57:52 -04:00
2ro 5733b9a894 update: fix in-app update download names (android-arm, linux tar.gz)
The in-app updater built the ARM Android download as goblin-<tag>-
android-arm.apk and the Linux download as .AppImage, but releases ship
goblin-<tag>-android-arm.apk (this build on) and a linux .tar.gz. On an
older release the ARM apk was named -android.apk, so the in-app update
404'd. Releases now name the ARM apk -android-arm.apk and the updater
targets the tar.gz, so Android and Linux in-app updates resolve.
2026-07-02 16:59:07 -04:00
2ro 8f1a955f9a docs: remove internal planning/meta docs, keep user and technical docs 2026-07-02 16:54:45 -04:00
2ro ae4306febe ci: fetch the nip44 crate for release builds
Adds a fetch-nip44 composite action (clones 2ro/nip44@v3 into ../nip44)
and runs it alongside fetch-nym in the linux/windows/macos jobs, so the
`nip44 = { path = "../nip44" }` dependency resolves on the runners.
2026-07-02 15:41:42 -04:00
2ro 989fd5b04a goblin: name avatars get a thin yellow outline, not a conic gradient
The username-seeded conic-gradient ring is replaced by a single thin,
light-yellow outline that hugs the avatar circle (image or grinmark
orb). It only appears for a claimed name (never a bare npub) and simply
signifies 'this identity has a name' - no per-name color, no gap, no
gradient. Drops the now-dead ring_params seed.
2026-07-02 15:41:42 -04:00
2ro acf9a140f6 goblin: scan an amount from a pay-URI QR (GoblinPay parity)
The recipient QR gains optional amount/memo query params:
  nostr:<nprofile>?amount=<decimal GRIN>&memo=<percent-encoded>
Scanning a GoblinPay checkout QR now prefills the amount (and the send
note) instead of only the recipient. Bare nostr:<nprofile> is unchanged.

The parser (src/nostr/payuri.rs) is pure and fail-closed over untrusted
scan input: amount is accepted only if the wallet's own
amount_from_hr_string parses it strictly positive; memo is percent-
decoded, control-stripped and 256-byte capped; only the nostr: scheme
unlocks params; 4096-byte cap; embedded NUL rejected; any problem
degrades to recipient-only. PREFILL ONLY - the picker resolver and the
amount/review confirm still gate every send; nothing auto-advances.
2026-07-02 15:25:57 -04:00
2ro db793bc13d goblin: log in to nostr apps with your nsec (Advanced -> Nostr key)
Advanced gains a password-gated Nostr key card: reveal the wallet's nsec,
Copy it, or show it as a QR. Scanning that QR (or pasting the copied
nsec) into a nostr app's private-key login - e.g. magick.market - signs
you in with the same identity the wallet uses. The nsec is derived on
demand behind the wallet password and never persisted; wrong password
cannot leak it. Six advanced.* strings added across all six locales.
2026-07-02 15:03:32 -04:00
2ro 71bf9b90e5 Goblin Build 123: fast relay connect after app updates
Fix: a relay-pool cache written by an older build parses fine but lacks
the scoped-exit addresses, which silently disabled the fast money path
for up to 7 days after an update - relay connects rode the slow public
path for minutes. The cache is now ignored and replaced when it lacks
exits, and the pinned pool takes over immediately.

Fix: the scoped-exit mixnet client now prewarms at cold start, so the
sequencer's head start is real (it previously waited on a client that
nothing had started until the first relay dial).

Build: wallet submodule repinned to the upstream grim branch tip
(c2db754) - the previous pin was deleted upstream, breaking CI checkout
and fresh clones. Policy: submodules stay pinned to GRIM's sources.

Lean: drop verified-dead code (avatar upload pipeline, legacy UDP DNS
path, legacy watchdog, duplicate TLS config, one-use error type, dead
store helpers).
2026-07-02 14:34:13 -04:00
2ro 5869ff78be android: drop the notification enable-node action; re-enable macOS release CI
The Android keep-alive notification's background job is the light Nostr-over-Nym
payment listen ("Listening for payments"); the heavy integrated node is no
longer STARTable from it (Goblin defaults to an external node). Only STOP is kept
as a safety valve. Also re-enable the macOS release job (release: published) so a
published release attaches a universal .app build on the native runner.
2026-07-02 13:38:40 -04:00
2ro 300d9cea4c nym: restore scoped exit as fast money path + relay.floonet.dev cutover
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).
2026-07-02 12:50:33 -04:00
Goblin 337220299f nym: remove the dead scoped-exit egress
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.
2026-07-02 10:06:50 -04:00
Goblin 12f78f3af7 send: allow pasting an npub in the Send-to field (issue #1)
The recipient field had a QR-scan button but no paste, so on Android there
was no reliable way to paste an npub. Add the paste button (same one the
slatepack field uses).
2026-07-02 09:56:40 -04:00
Goblin bb2e8602ff relay pool: drop the scoped-exit pin (convenience first)
The money-path exit ran a second mixnet client whose cold bootstrap blocked
first-connect ~100s per session. Unset the exit so the wallet reaches
relay.goblin.st over the fast smolmix tunnel (still fully over the mixnet).
Privacy backbone unchanged; the exit stays deployed for a non-blocking
redesign later.
2026-07-02 09:48:37 -04:00
Goblin 78e141f319 avatar ring: sit around the orb with a clear gap, thinner
The username ring overlapped the gradient orb's edge. Inset the orb and
add a real gap so the ring sits around it without touching; thin the ring
(size*0.045) since it no longer needs to overlap.
2026-07-02 09:35:56 -04:00
2ro c701f0f480 Floonet scoped Nym exit + NIP-44 v3 + wallet polish
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.
2026-07-02 04:17:59 -04:00
2ro 1e8e0f6526 settings: point the GRIM link at the live upstream (GetGrin/grim), not the stale ardocrat fork 2026-06-17 23:06:52 -04:00
2ro 9262d7429b nip05: drop the name-transfer client — names are never transferred
The name service no longer exposes /api/v1/transfer (removed server-side), and
the model is release-and-reclaim, not transfer: on a key rotation you release
the old name and re-register (or import your existing identity). Removed the dead
nip05::transfer() client fn (it had no callers) and the "transfer" wording in the
README.
2026-06-17 22:10:35 -04:00
2ro 36e63d4751 sync upstream Grim: bump node + wallet, adapt tx_log_iter
Upstream Grim advanced past the fork base with a node + wallet version update
(b51a46b → its "node + wallet: update to latest versions"). Bumped both
submodules (node → bce5a71, wallet → c2db754) and applied the one source
adaptation that update requires: `tx_log_iter()` now yields Result items, so the
three call sites filter Ok + unwrap before use. The upstream Tor/arti-0.43 commit
is skipped — Goblin removed Tor entirely.
2026-06-17 22:10:25 -04:00
2ro f0b5410c13 goblin: approving a payment request goes through a hold-to-accept review
Tapping Approve on an incoming request no longer pays immediately — it opens a
full-surface review (who's asking, amount, note, live network fee, privacy,
delivery) with a hold-to-accept gesture, mirroring the send review. Paying a
request is a spend, so it should confirm like one. The NostrPayRequest is
dispatched only when the hold completes; decline is unchanged, and an
over-balance request disables the accept. New goblin.request.review_title /
hold_to_accept / hold_accept_hint across all six locales (drift green).
2026-06-17 15:08:51 -04:00
2ro 84cc9d663b docs: README no longer claims an avatar service — avatars are client-derived
The identity service stores names + pubkeys only; avatars are rendered
client-side from the pubkey (npub gradient + first letter, else the Grin mark).
Dropped the stale "avatar service"/"avatar pipeline" copy and the "avatar
fetches" mention from the mixnet-traffic line.
2026-06-17 12:05:13 -04:00
2ro 2235e64bac build(windows): embed the Goblin icon into goblin.exe via winresource
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.
2026-06-17 09:43:49 -04:00
2ro 2b5cb8ad55 ci(windows): build a WiX .msi installer, like GRIM (not just a bare exe zip)
GRIM ships a Windows .msi; we were only zipping goblin.exe. The Windows release
job now runs cargo-wix against wix/main.wxs (the cargo-wix default template:
WixUI_Minimal + launch-after-install), producing a proper installer whose
shortcuts and Add/Remove-Programs entry carry wix/Product.ico — the yellow
Goblin icon. WiX 3 is taken from the runner or installed via choco; --no-build
reuses the release exe so the embedded GOBLIN_BUILD number is preserved. We
upload BOTH the .msi and the portable .zip (matching GRIM). Windows-only change.
2026-06-17 08:48:01 -04:00
2ro 1fdbd80282 icons: regenerate every platform icon from the canonical Goblin sources
All app icons now derive from two sources, end to end:
  img/goblin-icon.png        gradient app icon (yellow gradient + black mascot)
  img/goblin-mark-black.svg  black mascot mark (vector) — Android adaptive fg

- scripts/gen_icons.sh rewritten: one run regenerates the desktop/egui window
  icon (img/icon.png), the Linux AppImage AppDir icon, all Android launcher +
  adaptive-foreground mipmaps, the WiX installer icon, and the macOS .icns.
  Dropped the dead goblin-mask*.png pipeline (the adaptive foreground is now the
  SVG mark composited by the OS over #FFD60A), so the script no longer references
  files that were removed.
- scripts/make-icns.py: new, dependency-free multi-resolution .icns builder
  (iconutil/png2icns aren't always present; ImageMagick alone emits one size).
- wix/Product.ico REPLACED with the Goblin logo (was a stale icon).
- Regenerated macOS AppIcon.icns, Linux goblin.png, all Android mipmaps,
  img/icon.png. Tracked the goblin-mark-{black,white}.svg sources.
2026-06-17 02:36:50 -04:00
2ro d0cb76fa02 img: drop unused legacy/GRIM images
Remove six images with no code or build references — leftovers from the GRIM
era and superseded logo variants:
  cover.png            old GRIM marketing cover (paw logo, "Grin · Tor")
  grin-logo.png        old Grin/MW smiley
  logo.png, logo_light.png   GRIM wordmarks
  goblin-logo-256.png  superseded
  goblin-logo2-256.png superseded (the app uses goblin-logo2.svg + -48.png)

Kept (all referenced): icon.png (main.rs window icon), goblin-logo2.svg + -48.png
(in-app marks), goblin-icon.png (gen_icons.sh source). The in-progress icon
rework (goblin-mask*/goblin-icon-512 pruning, new goblin-mark-*.svg) is left
untouched.
2026-06-17 01:23:52 -04:00
2ro 991670d863 nostr: pause the @name re-verify sweep while the app is backgrounded
The 78s sweep fired regardless of whether anyone was looking, spending mixnet
round-trips in the background. Gate it on a frame heartbeat: the GUI stamps
crate::mark_frame() each draw (with a light ~2s repaint cadence so it stays
fresh while visible); when the app is backgrounded eframe stops drawing and the
stamp goes stale, so crate::app_foreground() reads false and the sweep skips.

The skip deliberately does NOT advance last_name_sweep, so the first tick after
the app returns to the foreground runs the sweep immediately — catching up on
resume rather than waiting out another full interval. Heartbeat lives at the
crate root so nostr reads it without depending on the gui module.
2026-06-16 22:58:07 -04:00
2ro 55b78b78ef macOS app icon = Goblin gradient; keep a contact's name across a decline
- The macOS bundle still shipped the old GRIM paw AppIcon.icns. Regenerated it
  from Goblin-Logo-Gradient-SMALLER.png (the yellow-gradient goblin mark) as a
  proper multi-resolution PNG-icns (16–512), so Finder/Dock show the Goblin icon.

- Declining (or cancelling) a request never re-resolved the counterparty, so
  their @name could drop to a bare npub just because the request didn't go
  through. handle_wrap now re-resolves the counterparty after a void — cheap,
  authoritative via the by-pubkey reverse lookup, and a no-op for anonymous keys.
2026-06-16 22:15:43 -04:00
2ro 919cfcb71e nostr: resolve a contact's @name via authority reverse lookup first
The requester still saw a bare npub for the payer because resolving a name
depended on fetching the peer's kind-0 off a relay (a nostr REQ with tight
timeouts over the private transport) before it could verify the NIP-05. When
that fetch doesn't land, resolution never starts — even though the name server
knows the name perfectly well.

resolve_contact_identity now asks the home authority directly:
GET /api/v1/by-pubkey/{hex} → the active @name for that key, in one HTTP
round-trip, with no profile fetch. That answer is authoritative, so the name is
set verified immediately. The kind-0 + verify path stays as a fallback for
FOREIGN authorities (which the home server can't speak for) and is still what
CLEARS a released/reassigned name. New nip05::name_by_pubkey helper.

Pairs with the goblin-nip05d by-pubkey endpoint. Verified by me only as far as
compile + unit/i18n tests; the live two-party resolution is the owner's call.
2026-06-16 20:01:20 -04:00
2ro d60e71d1e0 onboarding + nostr: healthy default node, claim feedback, identity import, resolve payer name
Four field-reported issues from a fresh install + a friend payment:

- Default node was grincoin.org, whose foreign API was returning "rpc call
  failed" — onboarding sync died with an un-retryable error. Lead the node
  list with the verified-healthy api.grin.money (external.rs) and use it as the
  onboarding default (was grincoin.org); grincoin.org stays in the list.

- Claiming a username gave no feedback and the identity card kept showing the
  npub. The card now shows the @name + a seal check once claimed, and a clear
  "name is yours" success card replaces the claim form before Open wallet.

- A returning user who restores a seed gets a fresh random nostr key, so their
  old @name couldn't come back. Offer "Import it" in the identity step: paste an
  nsec or pick a .backup file (reuses the wallet password just set) to keep the
  existing key + username.

- The requester side of a request never resolved the payer's @username — the
  FinalizePost ingest arm skipped ensure_contact/resolve_contact_identity, so a
  completed request showed a bare npub for the payer. Resolve on finalize like
  every other ingest path.

i18n: claimed_title/claimed_blurb + import_existing/import_title/import_blurb
across all six locales; drift test green.
2026-06-16 18:50:19 -04:00
2ro 24abc7e7b3 docs: TRANSACTIONS.md — full payment lifecycle, statuses, ingest guard, cancel/expiry/recovery 2026-06-16 12:55:51 -04:00
2ro 11033b93fe Federation, note modal, save-to-device, onboarding fixes + UI polish
- Configurable name authority (Settings → Identity → Name authority): bare
  names resolve there, own-domain names show bare, foreign verified names show
  'name · domain' with a check — no '@' anywhere. Lets bob@otherdomain pay
  alice@goblin.st. Home domain derived from the configured server.
- Note entry is now a modal that floats above the soft keyboard (dimmed
  backdrop) instead of an inline editor the keyboard covered.
- Backup export SAVES to a chosen location (Android CREATE_DOCUMENT / desktop
  save dialog) instead of opening the share sheet.
- Onboarding status-bar icons are legible again (white on the dark surface,
  not black); identity step is less wordy and drops the '@' prefix; claiming a
  name during onboarding now republishes kind 0 so it's visible immediately.
- App-open name re-verify sweep (persisted, runs if >78s since last).
- Advanced 'Manage node connection' opens GRIM's native Connections UI.
- Manual slatepack paste: removed the QR icon. Pay screen: bolder, bigger ツ.
- Localized new strings across 6 locales.
2026-06-16 03:22:08 -04:00
2ro dfbd85c7b3 nostr: keep contact @usernames fresh; clear released/reassigned names
Cached names were verified once and never re-checked, so a contact who
released or changed their username kept showing the stale name forever.
Re-validate names on a 78s sweep (capped per tick to bound mixnet lookups):

- nip05::check — tri-state Verified/Mismatch/Unreachable, so we only clear on
  a definitive server answer (released, or reassigned to a different key),
  never on a network blip.
- resolve_contact_identity now re-checks names older than the freshness window
  and clears nip05 + nip05_verified_at on Mismatch (a user petname is kept);
  display falls back to the npub automatically.
- A periodic sweep in run_service re-verifies the stalest due contacts.

Tests for the tri-state parsing and the clear-keeps-petname logic.
2026-06-16 01:39:54 -04:00
2ro 7eb0683646 docs: drop the Cash App comparison; remove avatar mentions from the README
Rephrase the README as 'pay-by-username' and scrub the Cash App name from
code comments. Also drop the leftover 'hosted avatar'/'avatars' wording —
identities use generated identicons, not uploaded pictures.
2026-06-16 01:03:05 -04:00
2ro 9dba2163fa ui: profile/contacts, requests spinner, receipt fixes, backup file, send + advanced
- Republish kind 0 right after claiming a username (was invisible until restart).
- Request card shows a 'Paying…' spinner instead of a dead greyed button.
- Receipt: count confirmations 1/10…10/10 (was stuck at 0/10, jumped to done
  at one block); hide the network-fee row on received payments.
- Settings: one 'Back up to a file' flow (GOBLIN-*.backup) replacing copy-nsec
  / copy-JSON; import accepts a .backup file via the native picker.
- Advanced: 'Run your own node' opens the node-connection page (incl. an
  integrated-node option); Repair confirms in accent; Restore warns in red.
- Send: drop the 1/10/100/Max chips; Note becomes an Add-note editor.
- Remove the dead profile-picture upload UI and scrub picture wording.
- Localize all new strings across 6 locales; drift test green.
2026-06-16 00:32:02 -04:00
2ro 313a14b82c wallet: contacts on send, request-approve states, .backup create/import
- Create/refresh a contact when you SEND (not just receive) so people you
  pay show up under Suggested and resolve their @name.
- Approve-request: set SENT on the Standard1 success path and fail_send on
  the error + non-payable paths, so the button never sticks greyed.
- create_nostr_backup() + import of the encrypted .backup envelope.
2026-06-16 00:31:50 -04:00
2ro 222f149fc2 nostr identity: single fully-encrypted .backup envelope
Add to_encrypted_backup / from_encrypted_backup: the secret key is the
password-protected NIP-49 ncryptsec, and the rest of the identity is
NIP-44-sealed to our own key — so a GOBLIN-*.backup file leaks no npub or
username, yet any Goblin wallet reopens it with the password.
2026-06-16 00:31:37 -04:00
2ro 6ea94989bf nostr: fix profile loading over the relay
Profiles never loaded when scanning a bare npub (username/avatar stayed
blank) even though the relay stores and serves the kind-0 fine. Two causes:
fetch_profile_blocking ran on a throwaway current-thread runtime that can't
drive the relay connections (which live on the service runtime, behind the
custom Nym mixnet transport), and it only dialed nprofile hints, never the
user's own default relays. Run the fetch on the service runtime via a stored
Handle, and always dial the default relay set (incl relay.goblin.st).
2026-06-16 00:31:27 -04:00
2ro a35fb7956c Android: dark status-bar icons on the yellow GRIM/onboarding header
In dark theme the wallet list, app settings, wallet creation and onboarding
leave the bright accent-yellow title_panel_bg showing under the status bar,
but status_bar_white_icons() returned the dark-theme default (white) — white
icons are illegible on yellow. Force dark icons on every non-Goblin-surface
screen (the Goblin surface covers the inset and sets its own per-tab flag).
2026-06-15 21:42:43 -04:00
2ro 6a0c2565b5 Review page: show live network fee for the amount (priced like GRIM's send modal) 2026-06-15 21:18:34 -04:00
2ro b7c3b95f51 Copy buttons: haptic tick + transient 'Copied' confirmation 2026-06-15 21:15:26 -04:00
2ro 22292ef79c Onboarding skips node step; internal node moves to Advanced; WALLETS->GOBLIN
- Onboarding goes Intro -> wallet setup directly (connected to a public node
  instantly); the node-choice step is retired.
- External node settings stay in Settings; 'run your own node' (integrated) now
  lives in the Advanced submenu.
- Wallet-list: title reads GOBLIN (was WALLETS), dropped the redundant GOBLIN
  wordmark under the mark, build number kept but smaller.
2026-06-15 21:07:42 -04:00
2ro cc59be0834 android.sh: fix flavor default ([[ $flavor ]], not literal 'flavor')
The empty-flavor test compared the literal string 'flavor', so a no-flavor
invocation left the APK output path as apk//debug/app--debug.apk and the
rename failed. Default to 'local' correctly.
2026-06-15 20:20:15 -04:00
2ro 3eff81e18d macOS: package as Goblin.app bundle, not a bare binary
The macOS CI job lipo'd the universal binary and zipped it raw, so users got a
naked 'goblin' executable instead of a double-clickable app. Assemble the
universal binary into the existing macos/Goblin.app bundle (Info.plist + icon),
ad-hoc codesign it (required for the arm64 slice to run on Apple Silicon after
lipo strips the per-arch signature), and ditto-zip the bundle. Remove the stale
tracked _CodeSignature that would otherwise make the app read as 'damaged'.
2026-06-15 20:18:41 -04:00
2ro dbc988f9ae Default to relay.goblin.st (strfry) instead of nrelay.us-ea.st
The Goblin relay moved to strfry at relay.goblin.st; point the wallet's default
DM relay set there (public relays damus/nos.lol stay as redundancy).
2026-06-15 20:00:13 -04:00
2ro 9768de2fbd Add manual 'Cancel payment' to reclaim a stuck outgoing send
A Goblin payment locks the sender's outputs until the recipient replies (S2)
and we finalize+post. If the recipient never connects to nostr, the funds stay
locked until the 24h auto-expiry. This adds a manual Cancel that reclaims them
on demand (after a 10-min grace, or immediately if the send never reached a
relay), marks the payment Cancelled, and best-effort voids it to the recipient.

- WalletTask::NostrCancelSend: authoritative tx lookup; refuses if already
  finalized/confirmed (race); marks meta Cancelled BEFORE cancelling the grin
  tx; serialized with nostr_finalize_post via a per-service lock so a cancel and
  a concurrent S2 finalize can't both commit.
- nostr_finalize_post returns Ok(false) (skip, no retry/re-post) when the tx is
  cancelled or the meta is Cancelled — covers the tx-list cancel path too.
- decide() already drops a late S2 on a Cancelled meta (new unit tests assert
  it); recipient-side void marks a received payment Cancelled for display WITHOUT
  deleting the output (a malicious sender could void-then-post otherwise).
- Void-before-S1 ordering handled via a (slate,sender)-bound marker.
- Receipt: tap-twice 'Cancel payment' with caveat + outcome notice; honest
  'Waiting for X to receive…' label; first-class Cancelled status. 6 locales.
- cancel_grace_secs config (default 600).
2026-06-15 19:34:44 -04:00
2ro 2e6cff9eeb Receive screen: copy/share the npub, never a grin address
The right button copied the grin1 slatepack address and the left copied the
nprofile — both wrong for 'how people pay me'. Now: left = Share a friendly
'Pay me on Goblin (goblin.st) — npub1…' message, right = Copy the bare npub.
New receive.copy_npub / receive.share_message keys across all six locales.
2026-06-15 17:28:26 -04:00
2ro ba504aa266 Cap claimed names at 20 chars to match the name authority
The nip05d authority now enforces a 3..=20 length; align the wallet's claim
validation (onboarding + settings) and the 'Names are 3-20 chars' hint across
all six locales so the wallet never offers a name the server will reject.
2026-06-15 16:12:26 -04:00
2ro 49fbebd4ce Docs: drop the displayed @ before usernames (kept internally for lookup) 2026-06-15 12:07:31 -04:00
2ro 72181ec9eb Build 83: gate vendored OpenSSL to Linux/Android so Windows builds again
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.
2026-06-15 03:21:27 -04:00