Task 1-1: Transaction Retry on BlockhashNotFound / Slippage
Phase: 1 Priority: High Module:
solanaDepends on: Không có Reference: docs/bountyhunter-blockchain-p2/details/feature-solana-integration/SPEC.md
Background
Solana transactions thất bại với lỗi BlockhashNotFound khi blockhash hết hạn (window ~400ms) — phổ biến khi network congestion cao. SlippageToleranceExceeded xảy ra trong AMM swaps khi giá thay đổi quá nhanh. Hiện tại SolanaService không có retry logic cho các lỗi transient này, dẫn đến job fail ngay cả khi resend với blockhash mới sẽ thành công.
Tasks
Note:
SolanaUtillà class quản lý SolanaConnection— đây là nơi tốt nhất để thêmsendWithRetrymethod. ImportsendAndConfirmTransaction,Transactiontừ@solana/web3.js.commitmentlevel nên là'confirmed'hoặc'finalized'tùy usecase. Max 3 retries là đủ; retry quá nhiều có thể gây duplicate transaction nếu tx đã được broadcast.
- [ ] Tạo method
sendWithRetrytrongSolanaUtil:async sendWithRetry( transaction: Transaction, signers: Signer[], options?: { maxRetries?: number; commitment?: Commitment }, ): Promise<TransactionSignature> { const maxRetries = options?.maxRetries ?? 3; const commitment = options?.commitment ?? 'confirmed'; for (let attempt = 0; attempt < maxRetries; attempt++) { try { // Fetch fresh blockhash on every attempt const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash(commitment); transaction.recentBlockhash = blockhash; transaction.lastValidBlockHeight = lastValidBlockHeight; const signature = await sendAndConfirmTransaction( this.connection, transaction, signers, { commitment, skipPreflight: false }, ); return signature; } catch (error) { const isRetryable = error.message?.includes('BlockhashNotFound') || error.message?.includes('block height exceeded') || error.message?.includes('SlippageToleranceExceeded'); if (isRetryable && attempt < maxRetries - 1) { this.logger.warn( `[SOLANA] sendWithRetry attempt=${attempt + 1}/${maxRetries} retryable error: ${error.message}` ); await new Promise((r) => setTimeout(r, 500 * (attempt + 1))); // backoff continue; } throw error; } } } - [ ] Thay thế
sendAndConfirmTransactioncalls trực tiếp trongSolanaServicebằngthis.solanaUtil.sendWithRetry(...) - [ ] Đảm bảo
skipPreflight: falseđể bắt lỗi simulation trước khi broadcast - [ ] Log attempt number và error type để debug
Verification / Acceptance Criteria
- [ ] Simulate
BlockhashNotFounderror lần đầu → retry lần 2 với blockhash mới → thành công - [ ] Simulate
SlippageToleranceExceedederror → retry với slippage mới hoặc fail sau 3 lần - [ ] Non-retryable error (e.g.,
InsufficientFunds) → không retry, throw ngay lập tức - [ ] Max 3 retries → sau lần thứ 3 throw error bình thường để Bull queue xử lý
- [ ] Log rõ ràng
attempt=X/3cho mỗi retry - [ ] TypeScript compile không có lỗi
Files to Modify
src/solana/utils/solana.util.tssrc/solana/solana.service.ts(thay thế directsendAndConfirmTransactioncalls)