@@ -35,8 +35,8 @@ import {
3535 MAX_ATTEMPTS ,
3636 REFRESH_INTERVAL_MS ,
3737} from './constants' ;
38- import executeSubmitFlow from './submit-flows ' ;
39- import type { ExecuteParams } from './submit-flows /types' ;
38+ import executeSubmitFlow from './strategy ' ;
39+ import type { ExecuteParams } from './strategy /types' ;
4040import type {
4141 BridgeStatusControllerState ,
4242 StartPollingForBridgeTxStatusArgsSerialized ,
@@ -838,6 +838,7 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
838838 * TX SUBMISSION HANDLING
839839 *******************************************************
840840 */
841+
841842 /**
842843 * Submits a cross-chain swap transaction
843844 *
@@ -849,6 +850,7 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
849850 * @param abTests - Legacy A/B test context for `ab_tests` (backward compatibility)
850851 * @param activeAbTests - New A/B test context for `active_ab_tests` (migration target). Attributes events to specific experiments.
851852 * @returns The transaction meta
853+ * @throws An error if transaction submission fails before it gets published
852854 */
853855 submitTx = async (
854856 accountAddress : string ,
@@ -901,108 +903,104 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
901903 preConfirmationProperties ,
902904 ) ;
903905
904- const submit = async ( ) : Promise < TransactionMeta | undefined > => {
905- // TODO all failures should publish the Failed event
906- let skipFailedEvent = true ;
907-
908- try {
909- let tradeTxMeta : TransactionMeta | undefined ;
910- /**
911- * Check if the account is an EIP-7702 delegated account
912- * Delegated accounts only allow 1 in-flight tx, so approve + swap
913- * must be batched into a single transaction
914- */
915- const isDelegatedAccount = isNonEvmChainId (
916- quoteResponse . quote . srcChainId ,
917- )
918- ? false
919- : await checkIsDelegatedAccount (
920- this . messenger ,
921- selectedAccount . address as Hex ,
922- [ formatChainIdToHex ( quoteResponse . quote . srcChainId ) ] ,
923- ) ;
924-
925- const params : ExecuteParams = {
926- quoteResponse,
927- isStxEnabledOnClient,
928- isDelegatedAccount,
929- messenger : this . messenger ,
930- selectedAccount,
931- traceFn : this . #trace,
932- requireApproval,
933- isBridgeTx,
934- clientId : this . #clientId,
935- fetchFn : this . #fetchFn,
936- bridgeApiBaseUrl : this . #config. customBridgeApiBaseUrl ,
937- addTransactionBatchFn : this . #addTransactionBatchFn,
938- } ;
939- const results = executeSubmitFlow ( params ) ;
906+ let tradeTxMeta : TransactionMeta ;
907+ let publishFailedEvent = false ;
940908
941- // Each submission strategy determines when to return values, which means these values can be returned in any order
942- for await ( const result of results ) {
943- if ( result . skipFailedEvent !== undefined ) {
944- skipFailedEvent = result . skipFailedEvent ;
945- }
946- if ( result . historyItem ) {
947- this . #addTxToHistory( {
948- ...result . historyItem ,
949- quoteResponse,
950- accountAddress : selectedAccount . address ,
951- isStxEnabled : isStxEnabledOnClient ,
952- startTime,
953- location,
954- abTests,
955- activeAbTests,
956- slippagePercentage : 0 , // TODO include slippage provided by quote if using dynamic slippage, or slippage from quote request
957- } ) ;
958- }
959- if ( result . tradeMeta ) {
960- result . historyItem ?. actionId &&
961- this . #rekeyHistoryItem(
962- result . historyItem ?. actionId ,
963- result . tradeMeta ,
909+ try {
910+ return await this . #trace(
911+ getTraceParams ( quoteResponse , isStxEnabledOnClient ) ,
912+ async ( ) => {
913+ /**
914+ * Check if the account is an EIP-7702 delegated account.
915+ * Delegated accounts only allow 1 in-flight tx, so approve + swap
916+ * must be batched into a single transaction
917+ */
918+ const isDelegatedAccount = isNonEvmChainId (
919+ quoteResponse . quote . srcChainId ,
920+ )
921+ ? false
922+ : await checkIsDelegatedAccount (
923+ this . messenger ,
924+ selectedAccount . address as Hex ,
925+ [ formatChainIdToHex ( quoteResponse . quote . srcChainId ) ] ,
964926 ) ;
965- tradeTxMeta = result . tradeMeta ;
966- }
967- if ( result . pollingToken ) {
927+
928+ const params : ExecuteParams = {
929+ quoteResponse,
930+ isStxEnabledOnClient,
931+ isDelegatedAccount,
932+ messenger : this . messenger ,
933+ selectedAccount,
934+ traceFn : this . #trace,
935+ requireApproval,
936+ isBridgeTx,
937+ clientId : this . #clientId,
938+ fetchFn : this . #fetchFn,
939+ bridgeApiBaseUrl : this . #config. customBridgeApiBaseUrl ,
940+ addTransactionBatchFn : this . #addTransactionBatchFn,
941+ } ;
942+ const steps = executeSubmitFlow ( params ) ;
943+
944+ // Each submission strategy determines when to return values, which means these values can be returned in any order
945+ for await ( const { type, payload } of steps ) {
946+ if ( type === 'publishFailedEvent' ) {
947+ publishFailedEvent = payload ;
948+ }
949+ if ( type === 'rekeyHistoryItem' ) {
950+ this . #rekeyHistoryItem( payload . actionId , payload . tradeMeta ) ;
951+ }
952+ if ( type === 'setTradeMeta' ) {
953+ tradeTxMeta = payload ;
954+ }
955+
956+ // Non-blocking steps
968957 try {
969- this . #startPollingForTxId( result . pollingToken ) ;
958+ if ( type === 'addHistoryItem' ) {
959+ this . #addTxToHistory( {
960+ ...payload ,
961+ quoteResponse,
962+ accountAddress : selectedAccount . address ,
963+ isStxEnabled : isStxEnabledOnClient ,
964+ startTime,
965+ location,
966+ abTests,
967+ activeAbTests,
968+ slippagePercentage : 0 , // TODO include slippage provided by quote if using dynamic slippage, or slippage from quote request
969+ } ) ;
970+ }
971+ if ( type === 'startPolling' ) {
972+ this . #startPollingForTxId( payload ) ;
973+ }
974+ if ( type === 'publishCompletedEvent' ) {
975+ this . #trackUnifiedSwapBridgeEvent(
976+ UnifiedSwapBridgeEventName . Completed ,
977+ payload ,
978+ ) ;
979+ }
970980 } catch ( error ) {
971981 console . error (
972982 'Failed to add to bridge history and start polling' ,
973983 error ,
974984 ) ;
975985 }
976986 }
977- if ( result . completedEventPayload ) {
978- this . #trackUnifiedSwapBridgeEvent(
979- UnifiedSwapBridgeEventName . Completed ,
980- result . completedEventPayload ,
981- ) ;
982- }
983- }
984987
985- return tradeTxMeta ;
986- } catch ( error ) {
987- if ( ! ( quoteResponse . featureId || skipFailedEvent ) ) {
988- this . #trackUnifiedSwapBridgeEvent (
989- UnifiedSwapBridgeEventName . Failed ,
990- undefined ,
991- {
992- error_message : ( error as Error ) ?. message ,
993- ... preConfirmationProperties ,
994- } ,
995- ) ;
996- }
997- throw error ;
988+ return tradeTxMeta ;
989+ } ,
990+ ) ;
991+ } catch ( error ) {
992+ if ( ! quoteResponse . featureId && publishFailedEvent ) {
993+ this . #trackUnifiedSwapBridgeEvent (
994+ UnifiedSwapBridgeEventName . Failed ,
995+ undefined ,
996+ {
997+ error_message : ( error as Error ) ?. message ,
998+ ... preConfirmationProperties ,
999+ } ,
1000+ ) ;
9981001 }
999- } ;
1000-
1001- const txMeta = await this . #trace(
1002- getTraceParams ( quoteResponse , isStxEnabledOnClient ) ,
1003- submit ,
1004- ) ;
1005- return txMeta ;
1002+ throw error ;
1003+ }
10061004 } ;
10071005
10081006 /**
@@ -1018,6 +1016,7 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
10181016 * @param params.isStxEnabledOnClient - Whether smart transactions are enabled on the client, for example the getSmartTransactionsEnabled selector value from the extension
10191017 * @param params.quotesReceivedContext - The context for the QuotesReceived event
10201018 * @returns A lightweight TransactionMeta-like object for history linking
1019+ * @throws An error if intent or transaction submission fails before they get published
10211020 */
10221021 submitIntent = async ( params : {
10231022 quoteResponse : QuoteResponse < Trade , Trade > & QuoteMetadata ;
0 commit comments