@@ -9,6 +9,7 @@ import type { Status } from "../../../bridge/types/Status.js";
99import { getCachedChain } from "../../../chains/utils.js" ;
1010import type { ThirdwebClient } from "../../../client/client.js" ;
1111import { waitForReceipt } from "../../../transaction/actions/wait-for-tx-receipt.js" ;
12+ import { waitForCallsReceipt } from "../../../wallets/eip5792/wait-for-calls-receipt.js" ;
1213import type { Account , Wallet } from "../../../wallets/interfaces/wallet.js" ;
1314import type { WindowAdapter } from "../adapters/WindowAdapter.js" ;
1415import type { BridgePrepareResult } from "./useBridgePrepare.js" ;
@@ -200,6 +201,7 @@ export function useStepExecutor(
200201 data : tx . data ,
201202 to : tx . to ,
202203 value : tx . value ,
204+ extraGas : 50000n , // add gas buffer
203205 } ) ;
204206
205207 // Send the transaction
@@ -276,6 +278,7 @@ export function useStepExecutor(
276278 data : tx . data ,
277279 to : tx . to ,
278280 value : tx . value ,
281+ extraGas : 50000n , // add gas buffer
279282 } ) ;
280283 return preparedTx ;
281284 } ) ,
@@ -326,6 +329,95 @@ export function useStepExecutor(
326329 [ poller , preparedQuote ?. type ] ,
327330 ) ;
328331
332+ // Execute batch transactions
333+ const executeSendCalls = useCallback (
334+ async (
335+ txs : FlattenedTx [ ] ,
336+ wallet : Wallet ,
337+ account : Account ,
338+ completedStatusResults : CompletedStatusResult [ ] ,
339+ abortSignal : AbortSignal ,
340+ ) => {
341+ if ( typeof preparedQuote ?. type === "undefined" ) {
342+ throw new Error ( "No quote generated. This is unexpected." ) ;
343+ }
344+ if ( ! account . sendCalls ) {
345+ throw new Error ( "Account does not support eip5792 send calls" ) ;
346+ }
347+
348+ const { prepareTransaction } = await import (
349+ "../../../transaction/prepare-transaction.js"
350+ ) ;
351+ const { sendCalls } = await import (
352+ "../../../wallets/eip5792/send-calls.js"
353+ ) ;
354+
355+ if ( txs . length === 0 ) {
356+ throw new Error ( "No transactions to batch" ) ;
357+ }
358+ const firstTx = txs [ 0 ] ;
359+ if ( ! firstTx ) {
360+ throw new Error ( "Invalid batch transaction" ) ;
361+ }
362+
363+ // Prepare and convert all transactions
364+ const serializableTxs = await Promise . all (
365+ txs . map ( async ( tx ) => {
366+ const preparedTx = prepareTransaction ( {
367+ chain : tx . chain ,
368+ client : tx . client ,
369+ data : tx . data ,
370+ to : tx . to ,
371+ value : tx . value ,
372+ extraGas : 50000n , // add gas buffer
373+ } ) ;
374+ return preparedTx ;
375+ } ) ,
376+ ) ;
377+
378+ // Send batch
379+ const result = await sendCalls ( {
380+ wallet,
381+ calls : serializableTxs ,
382+ } ) ;
383+
384+ // get tx hash
385+ const callsStatus = await waitForCallsReceipt ( result ) ;
386+ const lastReceipt =
387+ callsStatus . receipts ?. [ callsStatus . receipts . length - 1 ] ;
388+
389+ if ( ! lastReceipt ) {
390+ throw new Error ( "No receipts found" ) ;
391+ }
392+
393+ const { status } = await import ( "../../../bridge/Status.js" ) ;
394+ await poller ( async ( ) => {
395+ const statusResult = await status ( {
396+ chainId : firstTx . chainId ,
397+ client : firstTx . client ,
398+ transactionHash : lastReceipt . transactionHash ,
399+ } ) ;
400+
401+ if ( statusResult . status === "COMPLETED" ) {
402+ // Add type field from preparedQuote for discriminated union
403+ const typedStatusResult = {
404+ type : preparedQuote . type ,
405+ ...statusResult ,
406+ } ;
407+ completedStatusResults . push ( typedStatusResult ) ;
408+ return { completed : true } ;
409+ }
410+
411+ if ( statusResult . status === "FAILED" ) {
412+ throw new Error ( "Payment failed" ) ;
413+ }
414+
415+ return { completed : false } ;
416+ } , abortSignal ) ;
417+ } ,
418+ [ poller , preparedQuote ?. type ] ,
419+ ) ;
420+
329421 // Execute onramp step
330422 const executeOnramp = useCallback (
331423 async (
@@ -448,11 +540,15 @@ export function useStepExecutor(
448540 }
449541
450542 // Check if we can batch transactions
543+ const canSendCalls =
544+ ( await supportsAtomic ( account , currentTx . chainId ) ) &&
545+ i < flatTxs . length - 1 ; // Not the last transaction;
546+
451547 const canBatch =
452548 account . sendBatchTransaction !== undefined &&
453549 i < flatTxs . length - 1 ; // Not the last transaction
454550
455- if ( canBatch ) {
551+ if ( canBatch || canSendCalls ) {
456552 // Find consecutive transactions on the same chain
457553 const batchTxs : FlattenedTx [ ] = [ currentTx ] ;
458554 let j = i + 1 ;
@@ -467,12 +563,26 @@ export function useStepExecutor(
467563
468564 // Execute batch if we have multiple transactions
469565 if ( batchTxs . length > 1 ) {
470- await executeBatch (
471- batchTxs ,
472- account ,
473- completedStatusResults ,
474- abortController . signal ,
475- ) ;
566+ // prefer batching if supported
567+ if ( canBatch ) {
568+ await executeBatch (
569+ batchTxs ,
570+ account ,
571+ completedStatusResults ,
572+ abortController . signal ,
573+ ) ;
574+ } else if ( canSendCalls ) {
575+ await executeSendCalls (
576+ batchTxs ,
577+ wallet ,
578+ account ,
579+ completedStatusResults ,
580+ abortController . signal ,
581+ ) ;
582+ } else {
583+ // should never happen
584+ throw new Error ( "No supported execution mode found" ) ;
585+ }
476586
477587 // Mark all batched transactions as completed
478588 for ( const tx of batchTxs ) {
@@ -530,6 +640,7 @@ export function useStepExecutor(
530640 flatTxs ,
531641 executeSingleTx ,
532642 executeBatch ,
643+ executeSendCalls ,
533644 onrampStatus ,
534645 executeOnramp ,
535646 onComplete ,
@@ -602,3 +713,15 @@ export function useStepExecutor(
602713 steps : preparedQuote ?. steps ,
603714 } ;
604715}
716+
717+ async function supportsAtomic ( account : Account , chainId : number ) {
718+ const capabilitiesFn = account . getCapabilities ;
719+ if ( ! capabilitiesFn ) {
720+ return false ;
721+ }
722+ const capabilities = await capabilitiesFn ( { chainId } ) ;
723+ const atomic = capabilities [ chainId ] ?. atomic as
724+ | { status : "supported" | "ready" | "unsupported" }
725+ | undefined ;
726+ return atomic ?. status === "supported" || atomic ?. status === "ready" ;
727+ }
0 commit comments