Skip to content

[Feature] Extract a wallet abstraction layer from the Freighter-specific connect flow #476

Description

@collinsezedike

Summary

apps/web/src/hooks/useWalletConnect.ts and apps/web/src/lib/wallet.ts are hardcoded to Freighter (connectFreighter/isFreighterInstalled/signTransaction from @stellar/freighter-api), despite the hook's generic name suggesting a wallet-agnostic abstraction. Extract a common wallet interface so additional wallets (xBull, LOBSTR) can be added as separate implementations without touching the connect/sign call sites.

Motivation

Freighter is a desktop-only browser extension. The README targets "users in West Africa and other emerging markets" and the roadmap names low-end Android devices as the target device class, but a user on mobile cannot install Freighter at all. This is the first of several issues to add real multi-wallet support; this one is the foundation the wallet-specific issues depend on.

Proposed Solution

Define a common interface (e.g. connect/sign/isInstalled, matching the shape useWalletConnect.ts and wallet.ts already use for Freighter) and reimplement the existing Freighter calls as the first implementation against it. Freighter's behavior should not change from a user's perspective; this issue is a pure structural extraction, not a UI change.

Optimize for the cleanest interface design. Don't design around preserving the exact current shape of the persisted wallet state in apps/web/src/store/wallet.ts (zustand persist middleware) — if the cleanest design changes that shape, existing connected users seeing a one-time reconnect prompt is an acceptable, trivial cost. Do not add migration logic to avoid it.

Scope

Field Value
Area Frontend
Protocol affected None
Network Both
Breaking change? No (Freighter-facing behavior unchanged; internal structure only)

Alternatives Considered

Adding each new wallet directly into the existing Freighter-specific hook with conditional branching: rejected, since it would make useWalletConnect.ts and wallet.ts grow a branch per wallet indefinitely rather than each wallet being an independent, addable implementation.

Acceptance Criteria

  • A common wallet interface exists, implemented first by Freighter
  • useWalletConnect.ts/wallet.ts call sites go through the interface, not Freighter-specific functions directly
  • Freighter connect/sign behavior is unchanged from a user's perspective (manual verification: connect, sign a transaction, disconnect)
  • Existing wallet-related tests (useWalletConnect.test.ts, wallet.test.ts, store/wallet.test.ts) updated to match the new structure and pass
  • pnpm --filter @meridian/web lint && pnpm --filter @meridian/web typecheck && pnpm --filter @meridian/web test pass

Additional Context

First of a small batch of multi-wallet issues: this abstraction layer, then one issue per additional wallet (xBull, LOBSTR), then a wallet-picker UI issue, then a docs update to docs/signing-flow.md/apps/docs/architecture/signing-flow.md, both of which currently say "the user's wallet (Freighter)" specifically.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestfrontendInvolves React components, Tailwind styling, or Next.js pagesmediumRequires familiarity with the Meridian codebase or relevant tooling; expect 4–8 hours

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions