Skip to content

feat: make /send and /request functional without a deployed indexer - #28

Merged
YazarAyobami merged 1 commit into
mainfrom
feat/known-payees-chain-read
Oct 8, 2026
Merged

YazarAyobami merged 1 commit into
mainfrom
feat/known-payees-chain-read

Conversation

@abrcrmb

@abrcrmb abrcrmb commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

What and why

/send and /request showed "The list of payees can't be loaded right now" for every payee, since no indexer is deployed yet (M2-18, still TODO). Investigated whether kinlock-registry's real data could substitute directly: its payees/ directory is empty (.gitkeep only), and the indexer's own registry-join (kinlock-sdk/services/indexer/src/registry/sync.ts) reads a local filesystem checkout of the registry repo, not something kinlock-app should fetch live from GitHub at runtime or re-implement wholesale (that's real infrastructure work, a separate, bigger task).

Changes

  • lib/payees/known.ts: a committed snapshot of kinlock-registry/fixtures/payees/'s three fictional testnet fixtures (NG School, KE School, PH Rent).
  • lib/payees/registry.ts: listKnownPayees() joins each snapshot entry with a live chain read (getPayee, hard rule 3: chain is truth) and only shows a payee's display fields when the on-chain meta_hash still matches this snapshot's hash of the full record, computed with the exact same canonicalize/sha256 algorithm kinlock-registry's own scripts/registry.ts and the indexer's sync already use (so this isn't a new trust model, just the same one, duplicated the same way the indexer already duplicates it). status and payout are always the live on-chain values, never the snapshot's.
  • app/send/page.tsx, app/request/page.tsx: use listKnownPayees() instead of the indexer's listPayees().

While investigating, found all three fixtures are in fact already registered and Active on testnet (from earlier work this session, not part of this PR); confirmed directly against the deployed contract with stellar contract invoke ... get_payee, independent of this app's code.

Hard rules / invariants touched

None broken; this restores rule 3 (chain is truth) for the sender/payee-selection surface, which was previously just failing closed. status and payout are never taken from the committed snapshot.

Tests

pnpm lint, pnpm typecheck, pnpm test (101/101, 7 new in lib/payees/registry.test.ts: payeeIdOf matches kinlock-registry's own pnpm hash output, display fields clear when meta_hash doesn't match, a failed chain read drops that payee rather than throwing, live status is always reflected), pnpm build all green.

Full end-to-end functional test with Playwright against a real local build with no indexer configured (matching production): both pages list all three payees; /request generates a real, working prefilled /send link; /send's complete review flow (payee select, schedule, take-back date, USD total, preflight) runs through to "Connect your wallet first", the correct stopping point (actual signing needs a real wallet extension).

Docs / ADR

None needed; no SDK API or event change.

Roadmap

New row M3-26 added (app, P1, DONE). Phase 4 App: 10→11 DONE, total 25→26 (40%→42%). All rows: 40→41 DONE, total 200→201 (23%, unchanged after rounding). M3-06 is untouched (IN PROGRESS): its "Done when" is "creates a lock on testnet end to end," which still needs an actual wallet-signed createLock, not something this PR attempts.

Assumptions and open questions

This is explicitly an interim measure. M3-26's row says so, and the code comments point at it. Once M2-18 (real indexer) ships, /send and /request should go back to the indexer-backed listPayees(), which also serves /payee's dashboard and will cover real, non-fixture payees as they're onboarded (this interim source only ever shows these three fixtures, by design).

While investigating I also installed the stellar CLI (Homebrew) and generated a throwaway testnet attester identity (kinlock-fixture-attester), expecting I'd need to register these payees myself. That turned out to be unnecessary (they were already registered), so that identity is unused; it's a local-only Stellar CLI keystore entry, nothing committed to this repo.

Deploying to kinlock-app.vercel.app via vercel --prod after this merges.

Both pages showed "can't be loaded" for every payee, since no indexer
is deployed (M2-18, still TODO). kinlock-registry's real payees/ dir
is empty, and the indexer's own registry-join reads a local filesystem
checkout, not something kinlock-app should fetch live or re-implement.

Added a scoped interim source instead:
- lib/payees/known.ts: a committed snapshot of kinlock-registry's
  three fixture payees.
- lib/payees/registry.ts: joins each one with a live chain read
  (getPayee), verifying the on-chain meta_hash still matches this
  snapshot's hash of the full record before showing any of its display
  fields, exactly the binding the real indexer enforces. status and
  payout are always the live on-chain values.

Wired into /send and /request in place of the broken listPayees()
call. All three fixtures turned out to already be registered and
Active on testnet from earlier work; confirmed directly against the
deployed contract.
@abrcrmb
abrcrmb requested a review from a team as a code owner October 8, 2026 11:55
@YazarAyobami
YazarAyobami merged commit 00e271c into main Oct 8, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants