Skip to content

Commit 369355a

Browse files
authored
Merge pull request #183 from pradhankukiran/fix/confirmation-errors-surface-immediately
fix(transactions): surface confirmation errors immediately
2 parents 94e8db5 + f7f6d00 commit 369355a

2 files changed

Lines changed: 31 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66

77
## [Unreleased]
88

9+
### Fixed
10+
- Smart transaction confirmation now surfaces on-chain `TransactionError`s immediately instead of retrying until timeout
11+
912
## [1.0.0] - 2026-03-12
1013

1114
### Added

src/optimized_transaction.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ fn collect_unique_keypair_refs<'a>(signers: &'a [Keypair], fee_payer: &'a Keypai
101101
all_signers
102102
}
103103

104+
fn is_retryable_confirmation_error(err: &HeliusError) -> bool {
105+
matches!(err, HeliusError::Timeout { .. })
106+
}
107+
104108
/// URL to fetch current Jito bundle tip floor prices.
105109
///
106110
/// This endpoint returns the minimum tip amounts required for different
@@ -611,8 +615,8 @@ impl Helius {
611615
// Poll for transaction confirmation
612616
match self.poll_transaction_confirmation(signature).await {
613617
Ok(sig) => return Ok(sig),
614-
// Retry on polling failure
615-
Err(_) => continue,
618+
Err(err) if is_retryable_confirmation_error(&err) => continue,
619+
Err(err) => return Err(err),
616620
}
617621
}
618622
// Retry on send failure
@@ -1150,7 +1154,8 @@ impl Helius {
11501154

11511155
match self.poll_transaction_confirmation(sig).await {
11521156
Ok(confirmed) => return Ok(confirmed),
1153-
Err(_) => sleep(interval).await,
1157+
Err(err) if is_retryable_confirmation_error(&err) => sleep(interval).await,
1158+
Err(err) => return Err(err),
11541159
}
11551160
}
11561161
}
@@ -1199,14 +1204,16 @@ impl Helius {
11991204

12001205
#[cfg(test)]
12011206
mod tests {
1202-
use super::{collect_unique_keypair_refs, collect_unique_signers};
1207+
use super::{collect_unique_keypair_refs, collect_unique_signers, is_retryable_confirmation_error};
1208+
use crate::error::HeliusError;
1209+
use reqwest::StatusCode;
12031210
use solana_sdk::{
12041211
hash::Hash,
1205-
instruction::{AccountMeta, Instruction},
1212+
instruction::{AccountMeta, Instruction, InstructionError},
12061213
message::{v0, VersionedMessage},
12071214
pubkey::Pubkey,
12081215
signature::{Keypair, Signature, Signer},
1209-
transaction::{Transaction, VersionedTransaction},
1216+
transaction::{Transaction, TransactionError, VersionedTransaction},
12101217
};
12111218
use std::sync::Arc;
12121219

@@ -1382,4 +1389,19 @@ mod tests {
13821389
]
13831390
);
13841391
}
1392+
1393+
#[test]
1394+
fn confirmation_retries_only_on_timeout() {
1395+
let timeout = HeliusError::Timeout {
1396+
code: StatusCode::REQUEST_TIMEOUT,
1397+
text: "pending".to_string(),
1398+
};
1399+
let tx_error =
1400+
HeliusError::TransactionError(TransactionError::InstructionError(0, InstructionError::Custom(1)));
1401+
let invalid_input = HeliusError::InvalidInput("bad config".to_string());
1402+
1403+
assert!(is_retryable_confirmation_error(&timeout));
1404+
assert!(!is_retryable_confirmation_error(&tx_error));
1405+
assert!(!is_retryable_confirmation_error(&invalid_input));
1406+
}
13851407
}

0 commit comments

Comments
 (0)