| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
| |
still accepted); silent-payment leftovers removed
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
that keeps tips apart.
A new deferred feature (src/features/pos.js): type the amount in the display
unit, optionally a note, Charge. With the tip prompt on, the customer sees
the bill and picks a percentage (configurable, default 10/15/20), their own
figure, or no tip; one Lightning invoice is made for the total through the
Ark feature's receive (new hooks arkLnInvoice/arkLnWatch/arkLnUnwatch/
arkLnCancel wrap createLnInvoice and pollArkLn). Paid, expired and cancelled
sales are recorded with the bill and the tip as separate figures, and the
fiat rate at the time; the amount screen shows today's bills, tips and total.
Doors: Settings → Payments card, and a button under the payment address on
Receive (a receiveExtras hook the names pane renders).
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
| |
shared chunks alongside, 61KB of gifts/NWC/hats deferred past first paint into slots that keep their hook seniority), the lazy scripts wear IIFE coats so their names can't collide with the page's — which is what silently broke the remote-signer button — nip98 moves out of the login module so minimal builds stop hauling backup relays, and the smoke test learns the front door's new steps while the regtest stack rises from its IBD nap
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi
|
| |
|
|
|
|
|
| |
avatar everywhere it appears, from 21-sat beanie to 2.1M-sat top hat; the crown stays on the founder
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JtaatFfAbx91Nh3xqKVqKz
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Implements the Concord protocol (CORD-01..04) — private streams, the
control-plane fold, guestbook membership, owner-rooted authority — and
ships a built-in "coinos" community founded by Adam's npub (owner/admin).
Messages sign with the nostr login identity when a signer is live, else
the wallet's NIP-06 key; all encryption rides derived stream keys so
remote signers only ever sign seals.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Consistency fix with teeth: logging in with a pasted key derived one
wallet while an extension login for the SAME identity found no backup
and generated a different one. Now every signer kind runs one flow —
look for the published association first (that's where the money is),
then derive (key in hand) or generate (signer only) — and a derived
seed is published too. That costs nothing, since the derivation is
public and anyone holding the key could compute it anyway, and it makes
the identity open the same wallet however you log in.
Registrar auth is now NIP-98 (HTTP Auth, kind 27235) instead of a
homemade envelope: the signature binds the URL, method and body hash,
so a captured header can't be replayed elsewhere. NIP-78 already
covered the encrypted association; NIP-26 delegation is deprecated, so
owner→manager nomination lives in the registrar's own model: an
npub-shaped name may only be claimed by that identity, which nominates
the wallet key to keep the record updated afterwards (the wallet key is
the only one always available — offline, in the worker).
Payment addresses therefore default to the user's REAL npub in all
three login methods, falling back to the wallet's own identity when no
Nostr account is linked.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Three ways in: a NIP-07 browser extension, a NIP-46 remote signer
(Amber, Amethyst — paste its bunker:// address), or a pasted
nsec/hex key that lives in memory for the session and is never stored.
How an account gets a wallet depends on what we can see, and the two
cases are genuinely different:
* We hold the key (pasted nsec): the seed is DERIVED from it —
sha256("coinos:wallet-seed:v1" | privkey) as BIP-39 entropy. The
same Nostr key always opens the same wallet, on any device, with
nothing stored anywhere.
* We only have a signer: deriving is impossible (we never see the
key, and neither signatures nor NIP-44 ciphertexts reproduce), so
the seed is ASSOCIATED instead — generated once and published as a
replaceable event encrypted to the user's own key, which only their
signer can decrypt. Later logins find and decrypt it.
The second path means the Nostr key can recover the money; the UI says
so before publishing anything. Linking an already-open wallet uses the
same publish path and refuses to overwrite an account's existing wallet.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Receiving: a Settings card claims a username, signed with the wallet's
nostr key; the new names registrar (names/server.js, deployed at
names.halwallet.app) enforces first-come ownership by that key and
mirrors the claim into a DNSSEC-signed TXT record at
<name>.user._bitcoin-payment.halwallet.app whose BIP-21 URI carries the
wallet's reusable ark address. The record re-registers itself if the
ark address ever changes, and a collapsible hint shows the single CNAME
a user adds to serve the same name from their own domain (BIP-353
supports delegation when both zones are DNSSEC-signed).
Sending: a pasted name@domain resolves over DNS first — two independent
DoH resolvers must agree and both report the DNSSEC AD flag (full
client-side chain validation is the stated follow-up) — an ark=
instruction pays natively, an on-chain path fills the send form, and a
name with no DNS record falls back to the Lightning-address zap flow.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Dropped: silent payments (feature, wallet chains, scan worker, indexer
config), Boltz submarine/reverse swaps (feature + swap.js + tools), the
third-party ark swap bridge (config, client flows, settings card — the
ASP's own Lightning send is the one path now), and the Consolidate
coins settings action.
The NWC pouch is gone with them: background answering now spends the
WHOLE ark balance. The IndexedDB record mirrors the real manager state
plus the chain-3 keys for its live coins and a change-index window; the
worker pays through the ASP exactly like the open app, and the app
folds the worker's spends, change, and key allocations back in on
connect (additive merge + reconcile against the server). A leftover
chain-6 pouch from the short-lived pouch era is swept home
automatically using the keys stored in its own record. The stated
tradeoff: same-origin script access now reaches the ark balance, not a
carve-out — the ark balance is walking-around money, the on-chain
wallet's keys are never mirrored, and per-connection NWC budgets remain
the enforced ceiling.
Bundle: 726KB -> 602KB.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Other apps can connect over nostr and pay from this wallet without touching
its keys, within a per-payment and daily budget the user sets, revocable at
any time. hal holds no native Lightning balance, so every operation runs over
Ark: pay_invoice takes the swap bridge when configured and falls back to the
ASP's lightning-send, make_invoice mints on the ASP. NWC availability
therefore tracks Ark availability.
- kinds 13194/23194/23195, nip44_v2 and nip04, replying in whichever scheme
the request used; every request gets a reply so clients never hang
- each connection gets its own service keypair, so revoking one can't affect
the others and none is tied to the user's nostr identity
- budgets are checked BEFORE spending, not reconciled after
- requests are ignored unless signed by that connection's client key, and
replayed/stale events (>120s) can't re-trigger a payment
- Settings card to create, show (URI + QR) and revoke connections, and it
says plainly that this only works while a tab is open
tools/nwc-test.js drives it as a real client: both encryption schemes, budget
refusal with a genuine over-limit invoice, unsupported-method errors, and a
request from an unauthorized key being ignored.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Send a Lightning zap to a nostr npub, a lightning address (name@domain),
or an lnurl. New src/lnurl.js does the resolution half — target → LNURL-pay
params → signed kind-9734 zap request → callback → bolt11 — and the new
zaps feature (src/features/zaps.js) drives the amount/comment UI, then hands
the invoice to the existing Boltz submarine-swap flow via a new
swaps.startLnPay hook, so there's one tested pay/review/confirm/success path.
Routing: a bolt11 is still caught by swaps; an npub still prefers an instant
free Ark zap when Ark can serve it, and only falls through to a Lightning
zap otherwise — ark's "no Ark address" screen also offers an explicit
"Zap over Lightning" fallback (gated on the zaps feature's canLnZap). A real
zap receipt is attributed only when the server advertises allowsNostr and we
know the recipient's pubkey; otherwise it degrades to a plain LNURL-pay.
Nostr seam gains nostrSign (finalize without publishing), nostrProfile
(kind-0 with lud16/lud06), and nostrRelays. Lightning addresses are
debounced in matchSendText since their regex matches mid-typing.
Verified: unit tests for parse/encode/zap-request; a live resolve→signed
9734→payable mainnet bolt11 against coinos; and an in-browser DOM smoke
(zap form + LNURL params over CORS + allowsNostr hint + handoff).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
wallet.js drops from 2,374 to ~1,970 lines, holding only BIP84 on-chain
logic plus generic feature seams. New seams added this pass:
registerBalanceExtra extra confirmed/pending buckets
registerInputProvider extra spendable inputs for buildTx
registerSendPreparer destinations needing post-selection derivation
registerInputSigner non-BIP84 input signing
registerHistoryProvider / registerScanHook / registerRealtimeHook /
registerLoadHook / registerCacheExtension / registerCacheSavedHook
src/features/sp-wallet.js: the whole BIP-352 engine — key derivation,
worker-accelerated indexer scanning, the live indexer WebSocket, SP
outputs as spendable inputs, sp1 send preparation, and per-output-key
signing — installs via those seams (installSpWallet).
src/features/sync.js: nostr identity + encrypted cross-device state sync
plus its Settings card, installed via load/cache-saved/realtime hooks.
profileChip/nostrProfile move here-adjacent (into gifts, the only other
nostr consumer), so core app.js no longer imports nostr at all.
buildTx/sign are now feature-agnostic (input providers + preparers +
signers); _recomputeBalance* use the balance-extra registry, so a core
build with no SP no longer calls a missing spBalance() (that regression
dropped the minimal build into offline mode — caught by the smoke test).
New coverage: tools/sp-test.js drives two browser "devices" through an
SP send, indexer discovery, and an SP-input spend on the ark regtest
chain (needs tools/sp-indexer.js pointed at bitcoind:18543). Minimal
smoke now also asserts no SP/nostr code ships.
Minimal profile: 314KB, down from 412KB (full: 580KB). All suites green:
minimal smoke, sp-test, ark UI, gift lifecycle.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QFAcD4V284DvYZZHP7Rxxy
|
|
|
build.js swaps src/features/index.js for a generated module importing
only the enabled features (gifts,swaps,ark,sp — unset means all,
"none" means a plain on-chain wallet), so excluded feature code and
its network endpoints never enter the bundle. Minimal profile:
476KB vs 577KB, with the Ark/gRPC, Boltz, and MuSig2 code verifiably
absent. `bun run build:minimal` builds it.
tools/minimal-smoke.js proves the minimal profile end-to-end: no
receive-mode dropdown, no gift button, no swap/Ark/SP settings cards,
no page errors, and a plain on-chain receive still lands. The two
blessed profiles are full (everything, the existing e2e suites) and
minimal (this smoke test); other combos should work but aren't CI'd.
Gift and SP primitives still live inside wallet.js, so those bytes
remain in the minimal bundle for now — extracting them is the next
step if we want the core leaner still.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QFAcD4V284DvYZZHP7Rxxy
|