Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions bridgelet-product-audit/glossary/claim-token-and-claim-url.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Claim Token and Claim URL

## Canonical definitions

`docs/GLOSSARY.md` holds the canonical short definitions — a **Claim Token** is
the unique token that lets a recipient securely claim funds, and a **Claim URL**
is the web link containing that token. Those entries are the source of truth for
the terms themselves; this page does not restate them, it describes the frontend
flow that produces and consumes them.

## Which route renders the claim experience

The claim UI lives at a dynamic Next.js route keyed on the token itself:

```
frontend/app/claim/[token]/
├── page.tsx # route entry
├── loading.tsx # loading state
└── claim-page-client.tsx # client component doing the real work
```

The token is therefore a **path segment**, not a query parameter — a claim URL
looks like `/claim/<token>`. The `[token]` segment is what the recipient's link
carries, and `claim-page-client.tsx` is where the claim is actually presented and
attempted.

A separate sandbox page exists at `frontend/app/sandbox/claim-test/` for
exercising the flow without a real token.

## How this ties back on-chain

Opening a claim URL is the product-level entry point to the on-chain sweep. The
token identifies the **ephemeral account** holding the funds (see
`docs/GLOSSARY.md`), and completing a claim is what triggers the sweep of that
account's balance to the recipient's destination wallet.

The on-chain mechanics of ephemeral accounts and sweeping are documented in the
`bridgelet-audit/` initiative for `bridgelet-core`; this repo's concern stops at
rendering the claim and calling the API.

## Related

- [`claim-url-security-properties.md`](../integration-notes/claim-url-security-properties.md)
— what a claim URL guarantees as a bearer credential.
- [`sender-vs-recipient-auth-models.md`](./sender-vs-recipient-auth-models.md)
50 changes: 50 additions & 0 deletions bridgelet-product-audit/glossary/connected-wallet-persistence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Connected Wallet Persistence

How a connected wallet survives a page reload, per `frontend/lib/wallet.ts`.

## The storage key and shape

Persistence is plain `localStorage` under a single key:

```ts
const STORAGE_KEY = 'bridgelet_wallet';
```

`persistWallet()` writes `JSON.stringify(wallet)`, where `wallet` is a
`ConnectedWallet`. That type has exactly two fields:

| Field | Type | Example |
|---|---|---|
| `publicKey` | `string` | `G...` (Stellar public key) |
| `type` | `WalletType` | `'freighter' \| 'lobstr' \| 'generated'` |

## What is *not* stored

**No secret key material is written to `localStorage` by this path.** The
`ConnectedWallet` type has no field for it. Note that `generateNewWallet()` does
return a `secretKey` alongside the wallet, but that secret is returned to the
caller only — `persistWallet()` never receives it and therefore cannot store it.
This is a factual record of current behaviour, not a guarantee about future
callers.

## Corrupted or missing values

`loadPersistedWallet()` wraps the read in `try`/`catch` and returns `null` on any
failure:

```ts
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
return JSON.parse(raw) as ConnectedWallet;
} catch {
return null;
}
```

So a malformed JSON value degrades silently to "no wallet connected" rather than
throwing — the user sees a disconnected state with no error explaining why.
`clearPersistedWallet()` removes the key outright. Note the cast is unchecked: a
*well-formed* JSON value of the wrong shape is returned as-is rather than
rejected. See
[`../runbooks/clear-stale-persisted-wallet.md`](../runbooks/clear-stale-persisted-wallet.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Freighter vs LOBSTR vs Generated — Tradeoffs

The practical tradeoffs behind the three `WalletType` values. For what each value
*is*, see [`wallet-connection-types.md`](./wallet-connection-types.md).

## Freighter

**Requires** the user to have installed the Freighter browser extension. That is
a real drop-off point: `connectFreighter()` throws
`"Freighter extension not found. Please install it from freighter.app and refresh."`
for anyone who hasn't.

In exchange it has the strongest security model of the three. The secret key
never leaves the extension — the app calls `signTransaction()` and receives back
signed XDR, so Bridgelet code never handles key material. `signFreighterTransaction()`
tolerates several response shapes (`signedTxXdr`, `signedTxXDR`, `xdr`), which
suggests the extension's response format has varied across versions.

**Best for:** crypto-literate senders on desktop.

## LOBSTR

Currently a **manual paste flow**, not a live connection — LOBSTR ships no
browser JS SDK comparable to Freighter's. The user copies their public key out of
the LOBSTR app and pastes it in.

The tradeoff is a manual-entry error surface: a mistyped or truncated key is only
caught by format validation, and the app never gets signing capability — it learns
an address, nothing more. It also can't prove the user controls that address.

**Best for:** mobile-first users, accepting reduced assurance.

## Generated

Maximum convenience — one call to `generateNewWallet()` and the user has a
keypair, no install and no existing wallet needed. This is the path that serves
Bridgelet's core "recipient has no wallet" use case.

The cost is key custody. The function returns a raw `secretKey` string, and
whoever receives it becomes responsible for storing it and for the user's ability
to recover funds. Lose it and the funds are unrecoverable. See
[`generated-wallet-key-custody.md`](../integration-notes/generated-wallet-key-custody.md)
— this path has no caller yet, and the custody question is unresolved.

**Best for:** first-time recipients — once custody is specified.
45 changes: 45 additions & 0 deletions bridgelet-product-audit/glossary/wallet-connection-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Wallet Connection Types

The `WalletType` union in `frontend/lib/wallet.ts` has three values. Each means
something quite different in practice today.

```ts
export type WalletType = 'freighter' | 'lobstr' | 'generated';
```

A connected wallet is represented as `ConnectedWallet { publicKey, type }`.

## `freighter`

A live connection to the [Freighter](https://freighter.app) browser extension,
established by `connectFreighter()`. The function checks `freighter.isConnected()`
first and throws a descriptive "extension not found" error if the extension is
absent, then calls `requestAccess()` (which opens the extension popup) and reads
the address back via `getAddress()`.

## `lobstr`

Not a live SDK connection. LOBSTR has no browser-extension JS SDK equivalent to
Freighter's, so `connectLobstr()` immediately throws the sentinel string
`USE_PASTE_FLOW`. The intent is that the UI catches this and renders a
paste-your-public-key step instead. See
[`lobstr-paste-flow-not-implemented.md`](../integration-notes/lobstr-paste-flow-not-implemented.md)
for whether that handling actually exists.

## `generated`

A brand-new Stellar keypair created client-side by `generateNewWallet()`, which
dynamically imports `@stellar/stellar-sdk` (to avoid SSR issues) and calls
`Keypair.random()`. It returns both the wallet and a raw `secretKey` string.
Key-custody implications are covered in
[`generated-wallet-key-custody.md`](../integration-notes/generated-wallet-key-custody.md).

## Relationship to the existing glossary

This entry **extends** rather than replaces `docs/GLOSSARY.md`, which defines the
broader Stellar and product vocabulary (Account, Ephemeral Account, Custodial
Model). Read that first for the domain terms; read this for what the three
connection values concretely mean in the frontend code.

For the decision record behind choosing wallet-based auth at all, see
`docs/sender-auth-model.md` (Option B).
Loading