From 6cf309d98a306036fd0bf29d6bbde33a43739ef8 Mon Sep 17 00:00:00 2001 From: jhaydeeee-web Date: Wed, 21 Oct 2026 19:02:35 +0100 Subject: [PATCH] fix(freighter): sign with user-action timeout and distinct rejection/timeout errors --- lib/freighter.ts | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib/freighter.ts b/lib/freighter.ts index 66c84f5..929c931 100644 --- a/lib/freighter.ts +++ b/lib/freighter.ts @@ -19,6 +19,7 @@ import { getNetworkDetails, isConnected, requestAccess, + signTransaction, } from '@stellar/freighter-api' import type { Network } from '@/types' @@ -284,3 +285,41 @@ export async function connectFreighter(): Promise { const details = await readNetworkDetails() return { publicKey: address, ...details } } + +/** + * Ask Freighter to sign a transaction XDR. The user has to review and approve + * the request in the extension, so it uses the long user-action timeout rather + * than the short probe timeout. A decline maps to `FreighterRejectedError` and + * an unsettled request to `FreighterTimeoutError`. + */ +export async function signWithFreighter( + xdr: string, + networkPassphrase: string, + address?: string +): Promise { + try { + const result = await withTimeout( + signTransaction(xdr, { networkPassphrase, address }), + USER_ACTION_TIMEOUT_MS, + () => new FreighterTimeoutError() + ) + if (result.error) { + throw new FreighterRejectedError( + apiErrorMessage(result.error, 'Signature rejected') + ) + } + if (!result.signedTxXdr) { + throw new FreighterRejectedError('Signature rejected') + } + return result.signedTxXdr + } catch (error) { + if ( + error instanceof FreighterRejectedError || + error instanceof FreighterUnavailableError || + error instanceof FreighterTimeoutError + ) { + throw error + } + throw new FreighterRejectedError(messageOf(error, 'Signature rejected')) + } +}