@@ -282,82 +282,108 @@ async def execute( # pragma: no cover
282282 payer_keypair = Keypair .from_base58_string (self ._payer_private_key )
283283 sponsor = str (payer_keypair .pubkey ())
284284
285- # Get order from DFlow
286- order_result = await dflow .get_order (
287- input_mint = input_mint ,
288- output_mint = output_mint ,
289- amount = int (amount ),
290- user_public_key = public_key ,
291- slippage_bps = slippage_bps if slippage_bps > 0 else None ,
292- platform_fee_bps = self ._platform_fee_bps ,
293- platform_fee_mode = "outputMint" ,
294- fee_account = self ._fee_account ,
295- referral_account = self ._referral_account ,
296- sponsor = sponsor ,
297- )
298-
299- if not order_result .success :
300- return {"status" : "error" , "message" : order_result .error }
301-
302- if not order_result .transaction :
303- return {
304- "status" : "error" ,
305- "message" : "No transaction returned from DFlow." ,
306- }
307-
308- # Sign transaction
309- tx_to_sign = order_result .transaction
310-
311- # If gasless, sign with payer first
312- if self ._payer_private_key :
313- payer_keypair = Keypair .from_base58_string (self ._payer_private_key )
314- tx_bytes = base64 .b64decode (order_result .transaction )
315- transaction = VersionedTransaction .from_bytes (tx_bytes )
316- message_bytes = to_bytes_versioned (transaction .message )
317- payer_signature = payer_keypair .sign_message (message_bytes )
318-
319- # Create partially signed transaction
320- partially_signed = VersionedTransaction .populate (
321- transaction .message ,
322- [payer_signature , transaction .signatures [1 ]],
285+ # Retry logic for blockhash expiration
286+ max_retries = 3
287+ last_error = None
288+
289+ for attempt in range (max_retries ):
290+ # Get fresh order from DFlow (includes fresh blockhash)
291+ order_result = await dflow .get_order (
292+ input_mint = input_mint ,
293+ output_mint = output_mint ,
294+ amount = int (amount ),
295+ user_public_key = public_key ,
296+ slippage_bps = slippage_bps if slippage_bps > 0 else None ,
297+ platform_fee_bps = self ._platform_fee_bps ,
298+ platform_fee_mode = "outputMint" ,
299+ fee_account = self ._fee_account ,
300+ referral_account = self ._referral_account ,
301+ sponsor = sponsor ,
323302 )
324- tx_to_sign = base64 .b64encode (bytes (partially_signed )).decode ("utf-8" )
325-
326- # Sign and send via Privy (uses signAndSendTransaction RPC method)
327- send_result = await _privy_sign_and_send_transaction (
328- privy_client ,
329- wallet_id ,
330- tx_to_sign ,
331- self ._signing_key ,
332- )
333-
334- if not send_result .get ("success" ):
335- return {
336- "status" : "error" ,
337- "message" : send_result .get (
338- "error" , "Failed to sign and send transaction via Privy."
339- ),
340- }
341303
342- signature = send_result .get ("hash" )
343- if not signature :
344- return {
345- "status" : "error" ,
346- "message" : "No transaction signature returned from Privy." ,
347- }
304+ if not order_result .success :
305+ return {"status" : "error" , "message" : order_result .error }
306+
307+ if not order_result .transaction :
308+ return {
309+ "status" : "error" ,
310+ "message" : "No transaction returned from DFlow." ,
311+ }
312+
313+ # Sign transaction
314+ tx_to_sign = order_result .transaction
315+
316+ # If gasless, sign with payer first
317+ if self ._payer_private_key :
318+ payer_keypair = Keypair .from_base58_string (self ._payer_private_key )
319+ tx_bytes = base64 .b64decode (order_result .transaction )
320+ transaction = VersionedTransaction .from_bytes (tx_bytes )
321+ message_bytes = to_bytes_versioned (transaction .message )
322+ payer_signature = payer_keypair .sign_message (message_bytes )
323+
324+ # Create partially signed transaction
325+ partially_signed = VersionedTransaction .populate (
326+ transaction .message ,
327+ [payer_signature , transaction .signatures [1 ]],
328+ )
329+ tx_to_sign = base64 .b64encode (bytes (partially_signed )).decode (
330+ "utf-8"
331+ )
332+
333+ # Sign and send via Privy (uses signAndSendTransaction RPC method)
334+ send_result = await _privy_sign_and_send_transaction (
335+ privy_client ,
336+ wallet_id ,
337+ tx_to_sign ,
338+ self ._signing_key ,
339+ )
348340
341+ if send_result .get ("success" ):
342+ signature = send_result .get ("hash" )
343+ if not signature :
344+ return {
345+ "status" : "error" ,
346+ "message" : "No transaction signature returned from Privy." ,
347+ }
348+
349+ return {
350+ "status" : "success" ,
351+ "signature" : signature ,
352+ "input_amount" : order_result .in_amount ,
353+ "output_amount" : order_result .out_amount ,
354+ "min_output_amount" : order_result .min_out_amount ,
355+ "input_mint" : order_result .input_mint ,
356+ "output_mint" : order_result .output_mint ,
357+ "price_impact" : order_result .price_impact_pct ,
358+ "platform_fee" : order_result .platform_fee ,
359+ "execution_mode" : order_result .execution_mode ,
360+ "message" : f"Swap successful! Signature: { signature } " ,
361+ }
362+
363+ # Check if it's a blockhash error - retry with fresh transaction
364+ error_msg = send_result .get ("error" , "" )
365+ if (
366+ "blockhash" in error_msg .lower ()
367+ or "Blockhash not found" in error_msg
368+ ):
369+ last_error = error_msg
370+ logger .warning (
371+ f"Blockhash expired on attempt { attempt + 1 } /{ max_retries } , retrying with fresh transaction..."
372+ )
373+ continue
374+ else :
375+ # Non-blockhash error, don't retry
376+ return {
377+ "status" : "error" ,
378+ "message" : send_result .get (
379+ "error" , "Failed to sign and send transaction via Privy."
380+ ),
381+ }
382+
383+ # All retries exhausted
349384 return {
350- "status" : "success" ,
351- "signature" : signature ,
352- "input_amount" : order_result .in_amount ,
353- "output_amount" : order_result .out_amount ,
354- "min_output_amount" : order_result .min_out_amount ,
355- "input_mint" : order_result .input_mint ,
356- "output_mint" : order_result .output_mint ,
357- "price_impact" : order_result .price_impact_pct ,
358- "platform_fee" : order_result .platform_fee ,
359- "execution_mode" : order_result .execution_mode ,
360- "message" : f"Swap successful! Signature: { signature } " ,
385+ "status" : "error" ,
386+ "message" : f"Transaction failed after { max_retries } attempts. Last error: { last_error } " ,
361387 }
362388
363389 except Exception as e :
0 commit comments