Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c4fe11a
feat: v1 of quote streaming
micaelae Sep 23, 2025
1b9d3e2
chore: add @microsoft/fetch-event-source dependency
micaelae Sep 23, 2025
5f4179b
test: logging etc
micaelae Sep 30, 2025
5eac8e7
fix: rm TODO
micaelae Sep 30, 2025
9621d5f
chore: add logs
micaelae Oct 1, 2025
d19327d
Merge branch 'main' into swaps3025-quote-streaming
micaelae Oct 1, 2025
c699eff
chore: working wip
micaelae Oct 7, 2025
25ed707
Merge branch 'main' into swaps3025-quote-streaming
micaelae Oct 7, 2025
ed5314a
refactor: clean up
micaelae Oct 7, 2025
118d3d0
chore: read sseEnabled FF
micaelae Oct 7, 2025
f3be855
refactor: combine streaming + non-streaming fetch
micaelae Oct 7, 2025
b87b372
fix: fetch unit tests
micaelae Oct 7, 2025
4229401
fix: bridge-controller unit tests
micaelae Oct 7, 2025
954f1ec
fix: catch mobile errors
micaelae Oct 8, 2025
b5bc520
refactor: comments
micaelae Oct 8, 2025
9493678
fix: clear quotes on open
micaelae Oct 9, 2025
6362df7
test: sse unit test
micaelae Oct 9, 2025
c5d3353
Merge branch 'main' into swaps3025-quote-streaming
micaelae Oct 9, 2025
e200039
chore: add clientVersion to fetchQuotesStream call
micaelae Oct 9, 2025
0ae2c9c
fix: rename functions
micaelae Oct 9, 2025
c5212e4
refactor: reset on request change
micaelae Oct 9, 2025
e679425
refactor: unit tests
micaelae Oct 9, 2025
bcf5a41
chore: clean up comments
micaelae Oct 10, 2025
04430f8
Merge branch 'main' into swaps3025-quote-streaming
micaelae Oct 10, 2025
a0ff8e6
fix: more readable error handling
micaelae Oct 10, 2025
48b1f40
refactor: extract quote fee logic to util file
micaelae Oct 10, 2025
b9e02f8
refactor: extract setMinimumBalanceForRentExemptionInLamports snap ca…
micaelae Oct 10, 2025
303e0e8
refactor: extract quote sorting to util
micaelae Oct 10, 2025
6396f66
refactor: SSE
micaelae Oct 11, 2025
ef5ae87
fix: unit tests
micaelae Oct 11, 2025
9ee0ebb
fix: lint error
micaelae Oct 11, 2025
b6b8abe
Merge branch 'main' into swaps3025-quote-streaming
micaelae Oct 13, 2025
24608ed
fix: pass abortSignal to spot-prices fetch call
micaelae Oct 13, 2025
225423b
chore: update changelog
micaelae Oct 13, 2025
5cf3ff7
fix: changelog
micaelae Oct 13, 2025
d35699b
Merge branch 'main' into swaps3025-quote-streaming
micaelae Oct 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/bridge-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Introduce server‑sent events quote streaming and integrates incremental quote updates into the bridge controller polling flow ([#6760](https://github.com/MetaMask/core/pull/6760))
- Add private `getQuoteStreaming` handler that calls `getQuoteStream` when the `sseEnabled` flag is enabled in LaunchDarkly
- Reuse existing polling, metrics and validation utilities when processing server-sent quotes
- Add dependency on `@microsoft/fetch-event-source` at `^2.0.1` ([#6760](https://github.com/MetaMask/core/pull/6760))
- Note that clients need to patch this library such that it rejects instead of resolving when the quote request is cancelled. This preserves the controller's expected request cancellation behavior

### Changed

- Extract some logic from bridge-controller and move them to utility files for better readability ([#6760](https://github.com/MetaMask/core/pull/6760))

### Removed

- Remove cache options from spot-prices and getQuote api calls since they are only required by the extension client ([#6760](https://github.com/MetaMask/core/pull/6760))

### Fixed

- Pass abortSignal to fetchAssetPricesForCurrency in order to cancel exchange rate fetching when quote parameters change ([#6760](https://github.com/MetaMask/core/pull/6760))

## [50.0.0]

### Changed
Expand Down
1 change: 1 addition & 0 deletions packages/bridge-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"@metamask/multichain-network-controller": "^1.0.1",
"@metamask/polling-controller": "^14.0.1",
"@metamask/utils": "^11.8.1",
"@microsoft/fetch-event-source": "^2.0.1",
"bignumber.js": "^9.1.2",
"reselect": "^5.1.1",
"uuid": "^8.3.2"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`BridgeController SSE should publish validation failures 3`] = `
Array [
Array [
"Unified SwapBridge Quotes Failed Validation",
Object {
"action_type": "swapbridge-v1",
"chain_id_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"chain_id_source": "eip155:1",
"failures": Array [
"lifi|trade",
"lifi|trade.chainId",
"lifi|trade.to",
"lifi|trade.from",
"lifi|trade.value",
"lifi|trade.data",
"lifi|trade.gasLimit",
"lifi|trade.unsignedPsbtBase64",
"lifi|trade.inputsToSign",
],
"refresh_count": 1,
"token_address_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:123d1",
"token_address_source": "eip155:1/slip44:60",
},
],
Array [
"Unified SwapBridge Quotes Failed Validation",
Object {
"action_type": "swapbridge-v1",
"chain_id_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"chain_id_source": "eip155:1",
"failures": Array [
"unknown|quote",
],
"refresh_count": 2,
"token_address_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:123d1",
"token_address_source": "eip155:1/slip44:60",
},
],
]
`;

exports[`BridgeController SSE should replace all stale quotes after a refresh and first quote is received 1`] = `
Array [
"Unified SwapBridge Quotes Requested",
Object {
"action_type": "swapbridge-v1",
"chain_id_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"chain_id_source": "eip155:1",
"custom_slippage": true,
"has_sufficient_funds": true,
"is_hardware_wallet": false,
"security_warnings": Array [],
"slippage_limit": 0.5,
"stx_enabled": true,
"swap_type": "crosschain",
"token_address_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:123d1",
"token_address_source": "eip155:1/slip44:60",
"token_symbol_destination": "USDC",
"token_symbol_source": "ETH",
"usd_amount_source": 100,
"warnings": Array [],
},
]
`;

exports[`BridgeController SSE should reset and refetch quotes after quote request is changed 1`] = `
Array [
Array [
"Unified SwapBridge Quotes Requested",
Object {
"action_type": "swapbridge-v1",
"chain_id_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"chain_id_source": "eip155:1",
"custom_slippage": true,
"has_sufficient_funds": true,
"is_hardware_wallet": false,
"security_warnings": Array [],
"slippage_limit": 0.5,
"stx_enabled": true,
"swap_type": "crosschain",
"token_address_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:123d1",
"token_address_source": "eip155:1/slip44:60",
"token_symbol_destination": "USDC",
"token_symbol_source": "ETH",
},
],
]
`;

exports[`BridgeController SSE should reset quotes list if quote refresh fails 2`] = `
Array [
Array [
"Unified SwapBridge Quotes Requested",
Object {
"action_type": "swapbridge-v1",
"chain_id_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"chain_id_source": "eip155:1",
"custom_slippage": true,
"has_sufficient_funds": true,
"is_hardware_wallet": false,
"security_warnings": Array [],
"slippage_limit": 0.5,
"stx_enabled": true,
"swap_type": "crosschain",
"token_address_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:123d1",
"token_address_source": "eip155:1/slip44:60",
"token_symbol_destination": "USDC",
"token_symbol_source": "ETH",
"usd_amount_source": 100,
"warnings": Array [],
},
],
Array [
"Unified SwapBridge Quotes Error",
Object {
"action_type": "swapbridge-v1",
"chain_id_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"chain_id_source": "eip155:1",
"custom_slippage": true,
"error_message": "Network error",
"has_sufficient_funds": true,
"is_hardware_wallet": false,
"security_warnings": Array [],
"slippage_limit": 0.5,
"stx_enabled": true,
"swap_type": "crosschain",
"token_address_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:123d1",
"token_address_source": "eip155:1/slip44:60",
"token_symbol_destination": "USDC",
"token_symbol_source": "ETH",
"usd_amount_source": 100,
"warnings": Array [],
},
],
]
`;

exports[`BridgeController SSE should trigger quote polling if request is valid 1`] = `
Object {
"assetExchangeRates": Object {
"eip155:10/erc20:0x1f9840a85d5af5bf1d1762f925bdaddc4201f984": Object {
"exchangeRate": undefined,
"usdExchangeRate": "100",
},
},
"minimumBalanceForRentExemptionInLamports": "0",
"quoteFetchError": null,
"quoteRequest": Object {
"destChainId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"destTokenAddress": "123d1",
"destWalletAddress": "SolanaWalletAddres1234",
"insufficientBal": false,
"slippage": 0.5,
"srcChainId": "0x1",
"srcTokenAddress": "0x0000000000000000000000000000000000000000",
"srcTokenAmount": "1000000000000000000",
"walletAddress": "0x30E8ccaD5A980BDF30447f8c2C48e70989D9d294",
},
"quotes": Array [],
"quotesInitialLoadTime": null,
"quotesLoadingStatus": 0,
"quotesRefreshCount": 0,
}
`;

exports[`BridgeController SSE should trigger quote polling if request is valid 2`] = `
Array [
Array [
"Unified SwapBridge Input Changed",
Object {
"action_type": "swapbridge-v1",
"input": "chain_source",
"input_value": "eip155:1",
},
],
Array [
"Unified SwapBridge Input Changed",
Object {
"action_type": "swapbridge-v1",
"input": "chain_destination",
"input_value": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
},
],
Array [
"Unified SwapBridge Input Changed",
Object {
"action_type": "swapbridge-v1",
"input": "token_destination",
"input_value": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:123d1",
},
],
Array [
"Unified SwapBridge Input Changed",
Object {
"action_type": "swapbridge-v1",
"input": "slippage",
"input_value": 0.5,
},
],
Array [
"Unified SwapBridge Quotes Requested",
Object {
"action_type": "swapbridge-v1",
"chain_id_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"chain_id_source": "eip155:1",
"custom_slippage": true,
"has_sufficient_funds": true,
"is_hardware_wallet": false,
"security_warnings": Array [],
"slippage_limit": 0.5,
"stx_enabled": true,
"swap_type": "crosschain",
"token_address_destination": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:123d1",
"token_address_source": "eip155:1/slip44:60",
"token_symbol_destination": "USDC",
"token_symbol_source": "ETH",
"usd_amount_source": 100,
"warnings": Array [],
},
],
]
`;
Loading
Loading