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
50 changes: 50 additions & 0 deletions bridgelet-product-audit/glossary/lighthouse-ci-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Lighthouse CI Configuration

## What Lighthouse CI measures

Lighthouse audits a running page and scores it in categories — performance,
accessibility, best practices, SEO. Lighthouse **CI** runs those audits
automatically against a built app and can fail the build when a score drops below
a configured floor, turning page quality into a merge gate rather than a
spot check.

## Where the config actually lives

Note a correction worth recording: this file is **not** root-level. It sits at
`frontend/lighthouserc.js`, alongside the app it audits. There is no
`lighthouserc.js` at the repository root.

## What it currently checks

The config starts the production server (`npm run start`, awaiting the `Ready`
pattern) and audits three URLs, **3 runs each**:

- `http://localhost:3000/` — home
- `http://localhost:3000/send` — sender flow
- `http://localhost:3000/claim/abc123` — claim flow, via a dummy token

Assertions:

| Category | Threshold | Level |
|---|---|---|
| Performance | ≥ 0.85 | `error` |
| Accessibility | ≥ 0.95 | `error` |
| Best practices | ≥ 0.90 | `error` |
| SEO | — | `off` |

All three active thresholds are `error`, so falling below any of them fails the
run. Accessibility is held to the strictest bar. Reports upload to
`temporary-public-storage`.

## Is it actually invoked?

Yes — but not by the workflow you might expect. **`frontend-ci.yml` does not
reference it.** A *separate* workflow, `lighthouse-ci.yml`, runs `npm run lhci`
(i.e. `lhci autorun`) from `frontend/`. Two consequences:

- It is **path-filtered** to `frontend/**`, `docs/**` and its own workflow file. A
change touching none of those — a docs-only addition to a new top-level folder,
say — will not run Lighthouse at all.
- It passes `LHCI_GITHUB_APP_TOKEN` from repository secrets, typically unavailable to pull requests from forks.

See the checklist entry on CI-coverage gaps.
45 changes: 45 additions & 0 deletions bridgelet-product-audit/glossary/multi-chain-evaluation-summary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Multi-Chain Evaluation — Summary

A high-level pointer to `docs/multi-chain-evaluation.md`. All reasoning and detail
stays in that document; this is orientation only.

## Current direction

The document is an **evaluation**, not a commitment — it scopes what supporting
chains beyond Stellar would require, rather than announcing that Bridgelet is
becoming multi-chain. Read alongside `ROADMAP.md`, whose current status is MVP
implementation focused on Stellar ephemeral accounts, it reads as forward-looking
groundwork.

Its conclusion, at the highest level: multi-chain support is **not a surface-level
change**. It reaches into the send flow, the claim flow, and the data model
simultaneously.

## Areas it identifies

1. **Send flow changes** — chain selection becomes part of the sending decision.
2. **Claim flow changes** — the biggest conceptual jump. Claiming on a chain
other than the one funds were sent on requires actual cross-chain bridging
infrastructure, and recipients must connect a wallet compatible with their
chosen target chain.
3. **Database and API schema** — today's schema is Stellar-specific in ways that
don't generalise: Stellar-denominated amount fields, and asset identifiers
that carry no chain qualifier.

## Why this matters to the rest of this folder

This is important background for anyone reading
[`wallet-connection-types.md`](./wallet-connection-types.md). All three
connection types documented there — Freighter, LOBSTR, and generated keypairs —
are **Stellar-specific assumptions baked into the frontend**. Freighter is a
Stellar extension; `generateNewWallet()` calls `Keypair.random()` from
`@stellar/stellar-sdk`; address validation elsewhere in the app assumes the
Stellar `G...` format.

None of that is wrong today. But it means the wallet layer is one of the places
multi-chain work would land hardest, and the entries in this folder describing it
should be read as documenting *the current Stellar-only design*, not a
chain-agnostic one.

**For any actual detail, go to `docs/multi-chain-evaluation.md`.** Nothing here
should be treated as a substitute for it.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# LOBSTR Paste Flow — Documented but Not Wired Up

A discrepancy between `docs/sender-auth-model.md` and the code it describes.

## What the doc claims

The Security Notes section of `sender-auth-model.md` states, in effect, that
LOBSTR — the mobile wallet — **is supported** via a paste-your-public-key
fallback, and that this fallback is *already wired in* `lib/wallet.ts`.

Read plainly, that tells a reader LOBSTR is a working, if manual, option today.

## What the code actually does

`connectLobstr()` in `frontend/lib/wallet.ts` has exactly one behaviour — it
throws:

```ts
export async function connectLobstr(): Promise<ConnectedWallet> {
// ...comments describing the intended paste flow...
throw new Error('USE_PASTE_FLOW');
}
```

`USE_PASTE_FLOW` is a **sentinel** — a marker the UI is evidently meant to catch
in order to render a paste-your-address step. The comment directly above it says
as much: "This function returns a placeholder — the UI handles the paste step."

The problem is the other half never landed. Searching the repository for that
sentinel returns **exactly one hit: the `throw` itself.** No component, hook, or
error boundary catches it. `connectLobstr()` also has **no callers anywhere** in
`frontend/`, so nothing is positioned to catch it even in principle.

So the doc's "already wired in `lib/wallet.ts`" is half-true in a misleading way:
the *function* exists in `lib/wallet.ts`, but it implements no paste flow — it
implements a request for one.

## Practical consequence

If a user were routed to the LOBSTR option today, `connectLobstr()` would reject
with the literal message `USE_PASTE_FLOW`. With no handler mapping that sentinel
to a paste UI, the user would hit whatever generic error path exists — very
plausibly seeing the raw string `USE_PASTE_FLOW`, which is meaningless to them,
rather than "paste your LOBSTR address here." The one mitigation is that no UI
appears to call it, so the failure may be unreachable in practice rather than
actively broken.

**Related:** [`sender-auth-model-doc-accuracy.md`](./sender-auth-model-doc-accuracy.md) ·
[`../runbooks/diagnose-lobstr-connection-confusion.md`](../runbooks/diagnose-lobstr-connection-confusion.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Wallet Signing → SDK Handoff

What happens between a wallet signing in the browser and the transaction reaching
the chain. Recorded at integration-note level; the precise division of labour
needs confirming (see the flag at the bottom).

## The shape of the handoff

As currently implemented:

1. The browser obtains **signed transaction XDR** from Freighter.
`signFreighterTransaction()` in `frontend/lib/wallet.ts` passes unsigned XDR
plus a `networkPassphrase` to the extension and reads back
`{ signedTxXdr, signerAddress, networkPassphrase }`. The secret key never
leaves the extension.
2. The frontend hands that off to the **bridgelet-sdk API**.
3. The **API layer, not the browser**, talks to Soroban/Horizon. Per
bridgelet-sdk-audit's `horizon-vs-soroban-rpc.md`, network access lives on the
backend side. The browser does not submit transactions directly.

Network selection is resolved browser-side from `NEXT_PUBLIC_CRYPTO_NETWORK`,
defaulting to `stellar-testnet` — meaning the passphrase the user signs against is
chosen by frontend configuration.

## The ambiguity worth resolving

`docs/sender-auth-model.md` describes step 4 of its flow as: *"the Bridgelet SDK
signs the transaction with the connected key."*

That sentence can be read two ways, and the readings have very different security
properties:

| Reading | Who holds the key | Implication |
|---|---|---|
| **A** — the SDK *triggers* signing by the connected wallet | Freighter extension | Non-custodial for this step; matches `signFreighterTransaction()` |
| **B** — the SDK itself signs with a key it holds | Backend | Custodial for this step; the "connected key" is not the signer |

Reading A is consistent with the code in `lib/wallet.ts`, which is unambiguously
extension-side signing. But the same document elsewhere leans on the SDK as an
active participant, and Bridgelet genuinely *does* hold a funding key for
ephemeral-account creation and sweeping (see the custodial model). So both
readings describe things that are true of *some* transaction in this system.

**The flag:** which party signs *which* transaction is not stated precisely
anywhere found in this review. Sender-authorised transfers and Bridgelet-initiated
funding/sweep operations plausibly have different signers, and conflating them
would misstate the trust model. This should be confirmed explicitly by someone
with knowledge of the SDK's internals rather than inferred from phrasing. See also
[`sender-auth-model-doc-accuracy.md`](./sender-auth-model-doc-accuracy.md).
Loading