From 182146a4f4f73047a46fa5c2770020a4f16a9990 Mon Sep 17 00:00:00 2001 From: pedromcunha Date: Tue, 24 Feb 2026 15:20:17 -0500 Subject: [PATCH 1/3] Update solana adapter to poll for signature rather than wait for confirmation --- .../relay-svm-wallet-adapter/src/adapter.ts | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/packages/relay-svm-wallet-adapter/src/adapter.ts b/packages/relay-svm-wallet-adapter/src/adapter.ts index fc2b17e9..bbd17f16 100644 --- a/packages/relay-svm-wallet-adapter/src/adapter.ts +++ b/packages/relay-svm-wallet-adapter/src/adapter.ts @@ -122,24 +122,35 @@ export const adaptSolanaWallet = ( // So we don't need to handle onReplaced and onCancelled assertBase58TransactionSignature(txHash) - const { blockhash, lastValidBlockHeight } = - await connection.getLatestBlockhash('confirmed') + const POLL_INTERVAL_MS = 200 + const MAX_POLL_DURATION_MS = 120_000 + const start = Date.now() - const result = await connection.confirmTransaction({ - blockhash: blockhash, - lastValidBlockHeight: lastValidBlockHeight, - signature: txHash - }) + while (Date.now() - start < MAX_POLL_DURATION_MS) { + const { value } = await connection.getSignatureStatuses([txHash]) + const status = value?.[0] - if (result.value.err) { - throw new Error(`Transaction failed: ${result.value.err}`) - } + if (status?.err) { + throw new Error(`Transaction failed: ${JSON.stringify(status.err)}`) + } + + if ( + status?.confirmationStatus === 'confirmed' || + status?.confirmationStatus === 'finalized' + ) { + return { + blockHash: status.slot.toString(), + blockNumber: status.slot, + txHash + } + } - return { - blockHash: result.context.slot.toString(), - blockNumber: result.context.slot, - txHash + await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS)) } + + throw new Error( + `Transaction confirmation timeout: ${txHash} was not confirmed within ${MAX_POLL_DURATION_MS / 1000}s` + ) }, switchChain: (chainId: number) => { _chainId = chainId From 96f1f37339b1b15cd86b2e41d7a09adb34614f04 Mon Sep 17 00:00:00 2001 From: pedromcunha Date: Tue, 24 Feb 2026 15:20:59 -0500 Subject: [PATCH 2/3] feat: changeset --- .changeset/rich-lizards-reply.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/rich-lizards-reply.md diff --git a/.changeset/rich-lizards-reply.md b/.changeset/rich-lizards-reply.md new file mode 100644 index 00000000..1f82c3e6 --- /dev/null +++ b/.changeset/rich-lizards-reply.md @@ -0,0 +1,5 @@ +--- +'@relayprotocol/relay-svm-wallet-adapter': patch +--- + +Poll for signature instead of waiting for confirmation From 753e3fb8f30934c7227ca8af73b44e0a53c365f6 Mon Sep 17 00:00:00 2001 From: pedromcunha Date: Wed, 11 Mar 2026 16:58:35 -0400 Subject: [PATCH 3/3] Add exponential backoff for solana rpc confirmation --- packages/relay-svm-wallet-adapter/src/adapter.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/relay-svm-wallet-adapter/src/adapter.ts b/packages/relay-svm-wallet-adapter/src/adapter.ts index bbd17f16..73ba4db0 100644 --- a/packages/relay-svm-wallet-adapter/src/adapter.ts +++ b/packages/relay-svm-wallet-adapter/src/adapter.ts @@ -122,12 +122,16 @@ export const adaptSolanaWallet = ( // So we don't need to handle onReplaced and onCancelled assertBase58TransactionSignature(txHash) - const POLL_INTERVAL_MS = 200 + const INITIAL_INTERVAL_MS = 200 + const MAX_INTERVAL_MS = 1000 const MAX_POLL_DURATION_MS = 120_000 const start = Date.now() + let attempt = 0 while (Date.now() - start < MAX_POLL_DURATION_MS) { - const { value } = await connection.getSignatureStatuses([txHash]) + const { value } = await connection.getSignatureStatuses([txHash], { + searchTransactionHistory: attempt >= 5 + }) const status = value?.[0] if (status?.err) { @@ -145,7 +149,12 @@ export const adaptSolanaWallet = ( } } - await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS)) + const interval = Math.min( + INITIAL_INTERVAL_MS * Math.pow(2, attempt), + MAX_INTERVAL_MS + ) + await new Promise((resolve) => setTimeout(resolve, interval)) + attempt++ } throw new Error(