@@ -267,14 +267,7 @@ export class BridgeController extends StaticIntervalPollingController<BridgePoll
267
267
}
268
268
269
269
_executePoll = async ( pollingInput : BridgePollingInput ) => {
270
- const shouldStream = Boolean (
271
- getBridgeFeatureFlags ( this . messagingSystem ) . sseEnabled ,
272
- ) ;
273
- if ( shouldStream ) {
274
- await this . #fetchBridgeQuoteStream( pollingInput ) ;
275
- } else {
276
- await this . #fetchBridgeQuotes( pollingInput ) ;
277
- }
270
+ await this . #fetchBridgeQuotes( pollingInput ) ;
278
271
} ;
279
272
280
273
updateBridgeQuoteRequestParams = async (
@@ -391,13 +384,8 @@ export class BridgeController extends StaticIntervalPollingController<BridgePoll
391
384
392
385
this . #trackResponseValidationFailures( validationFailures ) ;
393
386
394
- const quotesWithL1GasFees = await this . #appendL1GasFees( baseQuotes ) ;
395
- const quotesWithNonEvmFees = await this . #appendNonEvmFees(
396
- baseQuotes ,
397
- quoteRequest . walletAddress ,
398
- ) ;
399
- const quotesWithFees =
400
- quotesWithL1GasFees ?? quotesWithNonEvmFees ?? baseQuotes ;
387
+ const quotesWithFees = await this . #appendFees( quoteRequest , baseQuotes ) ;
388
+
401
389
// Sort perps quotes by increasing estimated processing time (fastest first)
402
390
if ( featureId === FeatureId . PERPS ) {
403
391
return quotesWithFees . sort ( ( a , b ) => {
@@ -410,6 +398,20 @@ export class BridgeController extends StaticIntervalPollingController<BridgePoll
410
398
return quotesWithFees ;
411
399
} ;
412
400
401
+ readonly #appendFees = async (
402
+ quoteRequest : GenericQuoteRequest ,
403
+ baseQuotes : QuoteResponse [ ] ,
404
+ ) => {
405
+ const quotesWithL1GasFees = await this . #appendL1GasFees( baseQuotes ) ;
406
+ const quotesWithNonEvmFees = await this . #appendNonEvmFees(
407
+ baseQuotes ,
408
+ quoteRequest . walletAddress ,
409
+ ) ;
410
+ const quotesWithFees =
411
+ quotesWithL1GasFees ?? quotesWithNonEvmFees ?? baseQuotes ;
412
+ return quotesWithFees ;
413
+ } ;
414
+
413
415
readonly #trackResponseValidationFailures = (
414
416
validationFailures : string [ ] ,
415
417
) => {
@@ -587,10 +589,14 @@ export class BridgeController extends StaticIntervalPollingController<BridgePoll
587
589
) ;
588
590
this . update ( ( state ) => {
589
591
state . quotesLoadingStatus = RequestStatus . LOADING ;
590
- state . quoteRequest = updatedQuoteRequest ;
591
592
state . quoteFetchError = DEFAULT_BRIDGE_CONTROLLER_STATE . quoteFetchError ;
592
593
} ) ;
593
594
595
+ const { sseEnabled, maxRefreshCount } = getBridgeFeatureFlags (
596
+ this . messagingSystem ,
597
+ ) ;
598
+ const shouldStream = Boolean ( sseEnabled ) ;
599
+
594
600
try {
595
601
await this . #trace(
596
602
{
@@ -611,17 +617,49 @@ export class BridgeController extends StaticIntervalPollingController<BridgePoll
611
617
this . #setMinimumBalanceForRentExemptionInLamports(
612
618
updatedQuoteRequest . srcChainId ,
613
619
) ;
614
- const quotes = await this . fetchQuotes (
615
- updatedQuoteRequest ,
616
- // AbortController is always defined by this line, because we assign it a few lines above,
617
- // not sure why Jest thinks it's not
618
- // Linters accurately say that it's defined
619
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
620
- this . #abortController! . signal as AbortSignal ,
621
- ) ;
620
+ if ( shouldStream ) {
621
+ await fetchBridgeQuoteStream (
622
+ this . #fetchFn,
623
+ updatedQuoteRequest ,
624
+ this . #abortController?. signal ,
625
+ this . #clientId,
626
+ this . #config. customBridgeApiBaseUrl ?? BRIDGE_PROD_API_BASE_URL ,
627
+ {
628
+ onValidationFailures : ( validationFailures : string [ ] ) => {
629
+ this . #trackResponseValidationFailures( validationFailures ) ;
630
+ } ,
631
+ onValidQuotesReceived : async ( quotes : QuoteResponse [ ] ) => {
632
+ const quotesWithFees = await this . #appendFees(
633
+ updatedQuoteRequest ,
634
+ quotes ,
635
+ ) ;
636
+ this . update ( ( state ) => {
637
+ // If there are no other quotes yet, set initial load time
638
+ if (
639
+ state . quotes . length === 0 &&
640
+ quotesWithFees . length > 0
641
+ ) {
642
+ state . quotesInitialLoadTime = Date . now ( ) ;
643
+ }
644
+ state . quotes . push ( ...quotesWithFees ) ;
645
+ } ) ;
646
+ } ,
647
+ } ,
648
+ ) ;
649
+ } else {
650
+ const quotes = await this . fetchQuotes (
651
+ updatedQuoteRequest ,
652
+ // AbortController is always defined by this line, because we assign it a few lines above,
653
+ // not sure why Jest thinks it's not
654
+ // Linters accurately say that it's defined
655
+ this . #abortController?. signal as AbortSignal ,
656
+ ) ;
657
+ this . update ( ( state ) => {
658
+ state . quotes = quotes ;
659
+ } ) ;
660
+ }
622
661
623
662
this . update ( ( state ) => {
624
- state . quotes = quotes ;
625
663
state . quotesLoadingStatus = RequestStatus . FETCHED ;
626
664
} ) ;
627
665
} ,
@@ -641,134 +679,18 @@ export class BridgeController extends StaticIntervalPollingController<BridgePoll
641
679
}
642
680
643
681
this . update ( ( state ) => {
644
- state . quoteFetchError =
645
- error instanceof Error ? error . message : ( error ?. toString ( ) ?? null ) ;
646
- state . quotesLoadingStatus = RequestStatus . ERROR ;
647
- state . quotes = DEFAULT_BRIDGE_CONTROLLER_STATE . quotes ;
648
- } ) ;
649
- this . trackUnifiedSwapBridgeEvent (
650
- UnifiedSwapBridgeEventName . QuotesError ,
651
- context ,
652
- ) ;
653
- console . log ( 'Failed to fetch bridge quotes' , error ) ;
654
- }
655
- const bridgeFeatureFlags = getBridgeFeatureFlags ( this . messagingSystem ) ;
656
- const { maxRefreshCount } = bridgeFeatureFlags ;
657
-
658
- // Stop polling if the maximum number of refreshes has been reached
659
- if (
660
- updatedQuoteRequest . insufficientBal ||
661
- ( ! updatedQuoteRequest . insufficientBal &&
662
- this . state . quotesRefreshCount >= maxRefreshCount )
663
- ) {
664
- this . stopAllPolling ( ) ;
665
- }
666
-
667
- // Update quote fetching stats
668
- const quotesLastFetched = Date . now ( ) ;
669
- this . update ( ( state ) => {
670
- state . quotesInitialLoadTime =
671
- state . quotesRefreshCount === 0 && this . #quotesFirstFetched
672
- ? quotesLastFetched - this . #quotesFirstFetched
673
- : this . state . quotesInitialLoadTime ;
674
- state . quotesLastFetched = quotesLastFetched ;
675
- state . quotesRefreshCount += 1 ;
676
- } ) ;
677
- } ;
678
-
679
- readonly #fetchBridgeQuoteStream = async ( {
680
- networkClientId : _networkClientId ,
681
- updatedQuoteRequest,
682
- context,
683
- } : BridgePollingInput ) => {
684
- this . #abortController?. abort ( 'New quote request' ) ;
685
- this . #abortController = new AbortController ( ) ;
686
-
687
- this . trackUnifiedSwapBridgeEvent (
688
- UnifiedSwapBridgeEventName . QuotesRequested ,
689
- context ,
690
- ) ;
691
- this . update ( ( state ) => {
692
- state . quotesLoadingStatus = RequestStatus . LOADING ;
693
- state . quoteFetchError = DEFAULT_BRIDGE_CONTROLLER_STATE . quoteFetchError ;
694
- } ) ;
695
-
696
- try {
697
- await this . #trace(
698
- {
699
- name : isCrossChain (
700
- updatedQuoteRequest . srcChainId ,
701
- updatedQuoteRequest . destChainId ,
702
- )
703
- ? TraceName . BridgeQuotesFetched
704
- : TraceName . SwapQuotesFetched ,
705
- data : {
706
- srcChainId : formatChainIdToCaip ( updatedQuoteRequest . srcChainId ) ,
707
- destChainId : formatChainIdToCaip ( updatedQuoteRequest . destChainId ) ,
708
- } ,
709
- } ,
710
- async ( ) => {
711
- // This call is not awaited to prevent blocking quote fetching if the snap takes too long to respond
712
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
713
- this . #setMinimumBalanceForRentExemptionInLamports(
714
- updatedQuoteRequest . srcChainId ,
715
- ) ;
716
- await fetchBridgeQuoteStream (
717
- this . #fetchFn,
718
- updatedQuoteRequest ,
719
- // AbortController is always defined by this line, because we assign it a few lines above,
720
- // not sure why Jest thinks it's not
721
- // Linters accurately say that it's defined
722
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
723
- this . #abortController! . signal as AbortSignal ,
724
- this . #clientId,
725
- this . #config. customBridgeApiBaseUrl ?? BRIDGE_PROD_API_BASE_URL ,
726
- {
727
- onValidationFailures : ( validationFailures : string [ ] ) => {
728
- this . #trackResponseValidationFailures( validationFailures ) ;
729
- } ,
730
- onValidQuotesReceived : async ( quotes : QuoteResponse [ ] ) => {
731
- const quotesWithL1GasFees = await this . #appendL1GasFees( quotes ) ;
732
- const quotesWithNonEvmFees = await this . #appendNonEvmFees(
733
- quotes ,
734
- updatedQuoteRequest . walletAddress ,
735
- ) ;
736
- const quotesWithFees =
737
- quotesWithL1GasFees ?? quotesWithNonEvmFees ?? quotes ;
738
- this . update ( ( state ) => {
739
- // If there are no other quotes yet, set initial load time
740
- if ( state . quotes . length === 0 && quotesWithFees . length > 0 ) {
741
- state . quotesInitialLoadTime = Date . now ( ) ;
742
- }
743
- state . quotes . push ( ...quotesWithFees ) ;
744
- } ) ;
745
- } ,
746
- } ,
747
- ) ;
748
- } ,
749
- ) ;
750
- this . update ( ( state ) => {
751
- state . quotesLoadingStatus = RequestStatus . FETCHED ;
752
- } ) ;
753
- } catch ( error ) {
754
- const isAbortError = ( error as Error ) . name === 'AbortError' ;
755
- if (
756
- isAbortError ||
757
- [
758
- AbortReason . ResetState ,
759
- AbortReason . NewQuoteRequest ,
760
- AbortReason . QuoteRequestUpdated ,
761
- ] . includes ( error as AbortReason )
762
- ) {
763
- // Exit the function early to prevent other state updates
764
- return ;
765
- }
682
+ if ( shouldStream ) {
683
+ state . quoteFetchError =
684
+ this . #clientId === BridgeClientId . MOBILE
685
+ ? 'generic streaming error'
686
+ : ( ( error ?? 'error' ) as never as string ) ;
687
+ } else {
688
+ state . quoteFetchError =
689
+ error instanceof Error
690
+ ? error . message
691
+ : ( error ?. toString ( ) ?? null ) ;
692
+ }
766
693
767
- this . update ( ( state ) => {
768
- state . quoteFetchError =
769
- this . #clientId === BridgeClientId . MOBILE
770
- ? 'generic streaming error'
771
- : ( ( error ?? 'error' ) as never as string ) ;
772
694
state . quotesLoadingStatus = RequestStatus . ERROR ;
773
695
state . quotes = DEFAULT_BRIDGE_CONTROLLER_STATE . quotes ;
774
696
} ) ;
@@ -777,10 +699,11 @@ export class BridgeController extends StaticIntervalPollingController<BridgePoll
777
699
UnifiedSwapBridgeEventName . QuotesError ,
778
700
context ,
779
701
) ;
780
- console . log ( 'Failed to stream bridge quotes.' , error ) ;
702
+ console . log (
703
+ `Failed to ${ shouldStream ? 'stream' : 'fetch' } bridge quotes` ,
704
+ error ,
705
+ ) ;
781
706
}
782
- const bridgeFeatureFlags = getBridgeFeatureFlags ( this . messagingSystem ) ;
783
- const { maxRefreshCount } = bridgeFeatureFlags ;
784
707
785
708
// Stop polling if the maximum number of refreshes has been reached
786
709
if (
0 commit comments