@@ -8,7 +8,7 @@ import { User, PendingPayment } from '../models';
88import lnd from './connect' ;
99import { handleReputationItems , getUserI18nContext } from '../util' ;
1010import * as messages from '../bot/messages' ;
11- import { logger } from '../logger' ;
11+ import { logger , logTimeout , logOperationDuration } from '../logger' ;
1212import * as OrderEvents from '../bot/modules/events/orders' ;
1313import { IOrder } from '../models/order' ;
1414import { HasTelegram } from '../bot/start' ;
@@ -24,6 +24,9 @@ interface PayViaPaymentRequestParams {
2424}
2525
2626const payRequest = async ( { request, amount } : { request : string , amount : number } ) => {
27+ const startTime = Date . now ( ) ;
28+ const operationName = 'payRequest' ;
29+
2730 try {
2831 const invoice = parsePaymentRequest ( { request } ) ;
2932 if ( ! invoice ) return false ;
@@ -36,10 +39,13 @@ const payRequest = async ({ request, amount }: { request: string, amount: number
3639 // We need to set a max fee amount
3740 const maxFee = amount * parseFloat ( maxRoutingFee ) ;
3841
42+ // Use configurable pathfinding timeout, default to 60 seconds
43+ const pathfindingTimeout = parseInt ( process . env . LN_PATHFINDING_TIMEOUT || '60000' ) ;
44+
3945 const params : PayViaPaymentRequestParams = {
4046 lnd,
4147 request,
42- pathfinding_timeout : 60000 ,
48+ pathfinding_timeout : pathfindingTimeout ,
4349 } ;
4450 // If the invoice doesn't have amount we add it to the params
4551 if ( ! invoice . tokens ) params . tokens = amount ;
@@ -51,12 +57,36 @@ const payRequest = async ({ request, amount }: { request: string, amount: number
5157 // Delete all routing reputations to clear pathfinding memory
5258 await deleteForwardingReputations ( { lnd } ) ;
5359
60+ logger . info ( `Starting payment for ${ amount } sats with ${ pathfindingTimeout } ms timeout` ) ;
5461 const payment = await payViaPaymentRequest ( params ) ;
55-
62+
63+ logOperationDuration ( operationName , startTime , true ) ;
5664 return payment ;
57- } catch ( error ) {
58- logger . error ( `payRequest: ${ error } ` ) ;
59- return false ;
65+ } catch ( error : any ) {
66+ const errorMessage = error . toString ( ) ;
67+ const pathfindingTimeout = parseInt ( process . env . LN_PATHFINDING_TIMEOUT || '60000' ) ;
68+
69+ logOperationDuration ( operationName , startTime , false ) ;
70+
71+ // Enhanced error handling for different timeout scenarios
72+ if ( errorMessage . includes ( 'TimeoutError' ) || errorMessage . includes ( 'timed out' ) ) {
73+ logTimeout ( 'payRequest' , pathfindingTimeout , error ) ;
74+ logger . error ( `payRequest timeout after ${ pathfindingTimeout } ms: ${ errorMessage } ` ) ;
75+ return { error : 'TIMEOUT' , message : errorMessage } ;
76+ }
77+
78+ if ( errorMessage . includes ( 'UnknownPaymentHash' ) || errorMessage . includes ( 'PaymentPathfindingFailedToFindPossibleRoute' ) ) {
79+ logger . error ( `payRequest routing failed: ${ errorMessage } ` ) ;
80+ return { error : 'ROUTING_FAILED' , message : errorMessage } ;
81+ }
82+
83+ if ( errorMessage . includes ( 'InsufficientBalance' ) ) {
84+ logger . error ( `payRequest insufficient balance: ${ errorMessage } ` ) ;
85+ return { error : 'INSUFFICIENT_BALANCE' , message : errorMessage } ;
86+ }
87+
88+ logger . error ( `payRequest unexpected error: ${ errorMessage } ` ) ;
89+ return { error : 'UNKNOWN' , message : errorMessage } ;
6090 }
6191} ;
6292
@@ -104,14 +134,34 @@ const payToBuyer = async (bot: HasTelegram, order: IOrder) => {
104134 ) ;
105135 await messages . rateUserMessage ( bot , buyerUser , order , i18nCtx ) ;
106136 } else {
107- await messages . invoicePaymentFailedMessage ( bot , buyerUser , i18nCtx ) ;
137+ // Handle different types of payment failures
138+ if ( payment && typeof payment === 'object' && 'error' in payment ) {
139+ const errorType = payment . error as string ;
140+
141+ if ( errorType === 'TIMEOUT' ) {
142+ logger . warn ( `Payment timeout for order ${ order . _id } , will retry later` ) ;
143+ await messages . invoicePaymentFailedMessage ( bot , buyerUser , i18nCtx ) ;
144+ } else if ( errorType === 'ROUTING_FAILED' ) {
145+ logger . warn ( `Routing failed for order ${ order . _id } , will retry with cleared reputation` ) ;
146+ await messages . invoicePaymentFailedMessage ( bot , buyerUser , i18nCtx ) ;
147+ } else {
148+ logger . error ( `Payment failed for order ${ order . _id } with error: ${ errorType } ` ) ;
149+ await messages . invoicePaymentFailedMessage ( bot , buyerUser , i18nCtx ) ;
150+ }
151+ } else {
152+ await messages . invoicePaymentFailedMessage ( bot , buyerUser , i18nCtx ) ;
153+ }
154+
155+ // Create pending payment for retry
108156 const pp = new PendingPayment ( {
109157 amount : order . amount ,
110158 payment_request : order . buyer_invoice ,
111159 user_id : buyerUser . _id ,
112160 description : order . description ,
113161 hash : order . hash ,
114162 order_id : order . _id ,
163+ attempts : 1 ,
164+ last_error : payment && typeof payment === 'object' && 'error' in payment ? payment . error as string : 'UNKNOWN' ,
115165 } ) ;
116166 await pp . save ( ) ;
117167 }
0 commit comments