From 84893bad5828f162ae2d6e1974aef1fae1abafd2 Mon Sep 17 00:00:00 2001 From: jwinterm Date: Wed, 7 Oct 2026 11:06:21 -0400 Subject: [PATCH] feat(signin): use the wallet's one-approval signIn when available --- src/app/page.tsx | 24 ++++++++++++++++++++---- src/types/smirk.d.ts | 10 ++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index 1b49515..68eed71 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -89,8 +89,12 @@ export default function Home() { try { setError(null); - // Connect to extension (get public keys) - await window.smirk.connect(); + // A wallet with signIn connects and signs in one approval once a coin is + // chosen, so skip the separate connect prompt (and its unlock). + if (typeof window.smirk.signIn !== 'function') { + // Older wallets: connect first (get public keys), sign afterwards. + await window.smirk.connect(); + } setStep('choose-coin'); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to connect'); @@ -108,8 +112,20 @@ export default function Home() { // Get challenge from backend const challenge = await getChallenge(window.location.origin); - // Sign with the selected coin - const result = await window.smirk.signMessage(challenge.challenge); + // Sign with the selected coin: one approval on wallets with signIn, the + // older connect-then-sign path otherwise. + let result: SmirkSignResult | null = null; + if (typeof window.smirk.signIn === 'function') { + try { + result = await window.smirk.signIn(challenge.challenge, [coin]); + } catch (e) { + if ((e as { code?: string } | null)?.code !== 'UNSUPPORTED') throw e; + } + } + if (!result) { + if (!(await window.smirk.isConnected())) await window.smirk.connect(); + result = await window.smirk.signMessage(challenge.challenge); + } const sig = result.signatures.find((s) => s.asset === coin); if (!sig) { throw new Error(`No signature found for ${coin}`); diff --git a/src/types/smirk.d.ts b/src/types/smirk.d.ts index 52abfd5..203d48a 100644 --- a/src/types/smirk.d.ts +++ b/src/types/smirk.d.ts @@ -37,6 +37,10 @@ interface SmirkSignResult { signatures: SmirkSignature[]; } +interface SmirkSignInResult extends SmirkSignResult { + publicKeys: SmirkPublicKeys; +} + interface SmirkClaimResult { success: boolean; txid?: string; @@ -72,6 +76,12 @@ interface SmirkAPI { getPublicKeys(): Promise; getAddresses(): Promise; signMessage(message: string): Promise; + /** + * Connect (when needed) and sign a login challenge in one approval, so a + * wallet that locks every time asks for the password once. Newer wallets + * only: feature-detect with `typeof window.smirk.signIn === 'function'`. + */ + signIn?(message: string, assets?: SmirkAsset[]): Promise; /** * Request a payment from the user. Surfaces the Smirk send flow * pre-filled with the asset/amount/address; user must approve.