> Markdown twin of https://golantern.xyz/docs/deliverables/d2/ — index of every page: https://golantern.xyz/docs/llms.txt # D2 — Transaction security scanner **Statement of Work:** Deliverable 2, §4.1 · **Target:** Week 2 (14–20 Sep) · **Status:** Complete — recording pending > *"A scanner that simulates any Stellar transaction via RPC, decodes the `SorobanAuthorizationEntry` tree, and screens counterparties against the on-chain registry. Committed coverage: full structured effect-decoding and plain-language explanation for payment operations and token-interface calls (SEP-41 / SAC) — the operations most users actually sign."* — SOW §4.1 ## Evidence | SOW §6.1 evidence | Where | What it shows | Status | |---|---|---|---| | Public MIT-licensed repository | [`LICENSE`](https://github.com/kimerran/stellar-lantern/blob/develop/LICENSE) · [`packages/lantern-scanner/LICENSE`](https://github.com/kimerran/stellar-lantern/blob/develop/packages/lantern-scanner/LICENSE) | MIT at the repository root and inside the package; `"license": "MIT"` in both `package.json` files | Present | | Scanner test suite green in CI, offline | [Tests workflow](https://github.com/kimerran/stellar-lantern/actions/workflows/test.yml) | 748 passed, 1 skipped, 67 files, no network — every RPC answer comes from a recorded fixture; no CI secret exists | Present | | 90-second recording: a payment and a token-interface call decoded into effects + summary + verdict, plus an unverified contract handled safely | *TODO: link — pending* | Shot list and read-aloud script are written; the recording has not been made | Pending | | QA sign-off against the manual plan | [`docs/qa/d2-transaction-scanner-test-plan.md`](https://github.com/kimerran/stellar-lantern/blob/develop/docs/qa/d2-transaction-scanner-test-plan.md) | Complete: a ten-section plan with a results table, merged; the author's full dry run passes every runnable case including the three hard blockers. Not complete: an independent tester's sign-off in the results table | In progress | | Evidence decks + raw captures | [`docs/evidence/d2/`](https://github.com/kimerran/stellar-lantern/tree/develop/docs/evidence/d2) | Proof of Deliverables (9 slides) and Technical Documentation & Demo Evidence (6 slides); every proof slide's terminal output is committed alongside so a slide can be diffed against its source | Present | ## What a user can do when this is done Before signing anything, a user (or a wallet, a dApp, a command line) can hand the scanner a transaction and get back: exactly what it does — what leaves, what arrives, who receives, including money moved by a contract calling another contract — whether any recipient has been reported on the Deliverable 1 registry, a risk level with reasons that comes from deterministic rules, and one plain-English sentence. When the scanner cannot read or simulate the transaction, cannot reach the registry, or does not know what a contract does, it says so and raises the risk instead of guessing. ## Traceability | SOW clause | Change | Evidence | Status | |---|---|---|---| | Open-source, MIT-licensed package | [`addfea1`](https://github.com/kimerran/stellar-lantern/commit/addfea1) — `@lantern/scanner` extracted with its own LICENSE and README | Repository | Evidenced | | A pipeline whose verdict cannot be moved by the explainer | [`57ff777`](https://github.com/kimerran/stellar-lantern/commit/57ff777) — six stage signatures; verdict and effects deep-frozen before stage 6; type-level test | Proof deck slide 9; `tests/scanner-explain.test.ts` | Evidenced | | §4.1 — simulate via RPC | [`d8ffe18`](https://github.com/kimerran/stellar-lantern/commit/d8ffe18) — Ingest: timeout + backoff, fail-closed on undecodable / transport / timeout / malformed / reverted / archived | Proof deck slide 8 (fails closed); QA plan section 7 | Evidenced | | §4.1 — decode the authorization tree | [`3bd3123`](https://github.com/kimerran/stellar-lantern/commit/3bd3123) — every entry, every nested sub-invocation, with depth | Proof deck slide 5 | Evidenced | | §4.1 — structured effects for payment operations | [`f9048d0`](https://github.com/kimerran/stellar-lantern/commit/f9048d0), [`6e0f2c5`](https://github.com/kimerran/stellar-lantern/commit/6e0f2c5) — payment, createAccount, path payments (min/max bounds), accountMerge (entire balance), per-address aggregate | Proof deck slide 3; QA plan section 3 | Evidenced | | §4.1 — structured effects for SEP-41 / SAC token calls | [`3f09105`](https://github.com/kimerran/stellar-lantern/commit/3f09105) — transfer, approve (allowance + expiry, unlimited flagged), burn, mint, clawback; amounts scaled by resolved decimals or shown raw with "decimals unknown" | Proof deck slide 4; QA plan section 4 | Evidenced | | §4.1 — an unverified contract handled safely | [`57f34cc`](https://github.com/kimerran/stellar-lantern/commit/57f34cc) — structured label *unverified — semantics unknown*, decoded args shown, no name-based guessing, risk raised | Proof deck slide 6; QA plan section 5 | Evidenced | | §4.1 — screen counterparties against the registry | [`c30f30a`](https://github.com/kimerran/stellar-lantern/commit/c30f30a) — every address, three outcomes, unknown never folded into clean, TTL cache | Proof deck slide 7 with the explorer row; QA plan section 6 | Evidenced | | A deterministic risk verdict | [`faa3829`](https://github.com/kimerran/stellar-lantern/commit/faa3829) — pure rules; signal trail with provenance; `effects shown, terms not judged` on every verdict | Proof deck slides 3–8 | Evidenced | | §4.1 — plain-language explanation | [`e76700d`](https://github.com/kimerran/stellar-lantern/commit/e76700d) — one hosted model (`claude-haiku-4-5-20251001`), structured facts only, 4 s deadline, sanitised, contradiction-guarded, rules-based fallback | Proof deck slide 9; QA plan section 8 | Evidenced | | No key ships in a client | [`418d4c1`](https://github.com/kimerran/stellar-lantern/commit/418d4c1) — the Lantern API proxy (`POST /v1/explain`), rate-limited and capped; [`3addf40`](https://github.com/kimerran/stellar-lantern/commit/3addf40) — AI flag OFF in release builds | Service `/healthz`; release workflow | Evidenced | | §6.1 — manual QA plan and a way to run the scanner by hand | [`73d5b34`](https://github.com/kimerran/stellar-lantern/commit/73d5b34) — `npm run scan` harness (online, offline, `--no-ai`, hostile-stub mode) + the plan with real fixture names | Test plan; dry run | In progress | | §6.1 — 90-second recording | Runbook written | — | In progress | ## Scope notes - **Committed coverage is payments and the token interface.** Anything else is decoded as far as the bytes allow and labelled *unverified — semantics unknown*; the scanner does not attempt DeFi-protocol semantics in D2. - **The scanner never signs and never submits.** Its only network calls are two read-only RPC methods (`simulateTransaction`, `getLedgerEntries`) and, when configured, the explainer. - **The verdict is about what a transaction does, not whether it is a good deal** (§3.9) — every verdict carries that scope statement as a constant. ## Implementation choices - **The AI layer arrived last, on purpose.** The deterministic core was built and tested to stand on its own before a model was attached to it; the SOW explicitly allows the verdict to stand without the sentence. - **Option 2 for the model key — ship none** — then option 1, a proxy, before any public surface. A browser extension cannot keep a secret, so the release builds carry no key and no endpoint; the Lantern API holds the key and serves the sentence with a per-IP window and a daily cap. - **Offline by construction.** Nineteen recorded fixtures (real testnet XDR and the raw RPC bodies) answer every network call in tests; a QA harness `--offline` mode uses the same recordings and fails closed on anything unrecorded. - **Three fixtures were added for the QA plan** (payment to the flagged address; two recipients with one flagged; the flagged payment with a prompt-injection memo) so a tester can exercise screening and the injection case without building transactions.