You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(bridge-status-controller): pass swap asset ids to Tron, Solana, and Bitcoin snap requests - #10775
getClientRequest builds the signAndSendTransaction options per non-EVM chain. Before this PR it forwarded the swap/bridge sourceAssetId/destAssetId only for Stellar. Tron, Solana, and Bitcoin therefore could not see the swap asset ids, so their snaps could not tell a same-chain swap from a cross-chain bridge and reported unknown (Tron) or a balance-derived send (Solana, Bitcoin) for those transactions.
Solution
Forward sourceAssetId and destAssetId for Tron, Solana, and Bitcoin, mirroring the existing Stellar behavior.
For Stellar, Solana, and Bitcoin, the options contain only the two asset ids.
Tron additionally keeps its visible flag and contract type in the same options object.
The asset-id condition uses the chain-id guards (isStellarChainId, isSolanaChainId, isBitcoinChainId) rather than trade-shape guards, since getClientRequest already receives srcChainId and a Stellar trade can also be a plain base64 string.
Each snap then compares the CAIP-2 chains of the two asset ids to classify the transaction as a same-chain swap or a cross-chain bridgeSend.
Non-obvious points
The asset ids describe the swap or bridge transaction, not the token approval that can precede it. handleNonEvmTx now takes an isApproval flag and only attaches the asset ids to the main trade. Without this, the approval request would inherit the swap asset ids, and the Tron snap (which gives the asset ids precedence over the contract type) would classify an approve as swap/bridgeSend instead of tokenApprove.
The fields are added conditionally, so a request without asset ids is unchanged.
The Tron branch still uses isTronTrade because it needs to read visible and the contract type off the trade object.
This change is additive for the snaps: Tron validates the new options explicitly, while Solana and Bitcoin use permissive option schemas that ignore unknown keys. Releasing the corresponding snap changes first is still preferable so classification starts as soon as this lands.
The Solana swap test fixture previously set destChainId to Solana but gave the destination asset an eip155 CAIP id. Now that the asset ids are forwarded, that mismatch would classify the same-chain swap as a bridgeSend, so the fixture was corrected to use a Solana asset id.
References
Depends on the snap changes that classify swap/bridge from the asset ids: MetaMask/internal-snaps (Tron, Solana, Bitcoin).
Related to the Non-EVM flow analytics work for Tron, Solana, Bitcoin, and Stellar.
Checklist
I've updated the test suite for new or updated code as appropriate
I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
…ests
Include the sourceAssetId and destAssetId in the Tron
signAndSendTransaction options so the Tron snap can classify the
transaction as a same-chain swap or a cross-chain bridge, mirroring the
Stellar snap.
…quests
Include the sourceAssetId and destAssetId in the Solana
signAndSendTransaction options so the Solana snap can classify the
transaction as a same-chain swap or a cross-chain bridge, mirroring the
Stellar snap.
The Solana and Stellar branches share the same asset-id-only options
shape, so they are combined into a single condition.
…equests
Include the sourceAssetId and destAssetId in the Bitcoin
signAndSendTransaction options so the Bitcoin snap can classify the
transaction as a same-chain swap or a cross-chain bridge, mirroring the
Stellar snap.
The Bitcoin snap ignores unknown options, so no strict rollout ordering
is required.
…t ids
Replace the mixed isStellarTrade/isBitcoinTrade guards with
isStellarChainId/isBitcoinChainId so all three non-Tron chains use the
same chain-id check, since getClientRequest already receives srcChainId.
The Tron branch is unchanged as it reads fields from the trade object.
Battambang
changed the title
feat(bridge-status-controller): pass swap asset ids to Tron snap request
feat(bridge-status-controller): pass swap asset ids to Tron, Solana, and Bitcoin snap requests
Oct 10, 2026
A Stellar trade is either a stringor an { xdr / xdrBase64 } object. So isStellarTrade(trade) is false for a string-shaped Stellar trade, and that string is indistinguishable from a Solana trade by shape alone. The chain id is the only reliable signal for Stellar-vs-Solana strings, which is exactly why the original Solana check used isSolanaChainId(srcChainId) (there is no isSolanaTrade).
getClientRequest already has srcChainId in scope (it derives scope from it on the first line), so using chain guards for all three makes the condition uniform:
isStellarChainId accepts both pubnet and testnet (XlmScope.Pubnet / XlmScope.Testnet), whereas isStellarTrade only reflects the payload shape.
Behavior equivalence
Chain
Before
After
Same?
Stellar (object xdr)
isStellarTrade -> true
isStellarChainId -> true
Yes
Stellar (string xdr)
isStellarTrade -> false
isStellarChainId -> true
After is more correct
Solana
isSolanaChainId -> true
isSolanaChainId -> true
Yes
Bitcoin
isBitcoinTrade -> true
isBitcoinChainId -> true
Yes
Tron
not in this condition
not in this condition
Yes (separate branch)
EVM
all false
all false
Yes
The only behavioral difference is the string-shaped Stellar case, where the new version is correct and the old one would have silently omitted the asset ids.
…he swap fixture
The Solana swap fixture set destChainId to Solana but gave the
destination asset an eip155 CAIP id. Now that the swap asset ids are
forwarded to the snap, that mismatch would classify the same-chain swap
as a bridgeSend, contradicting the fixture's own swap_type of
single_chain. Use a Solana asset id for the destination asset and
regenerate the affected snapshots.
… requests
handleNonEvmTx always attached the quote's source and destination asset
ids to the signAndSendTransaction options, including for the token
approval that precedes a swap or bridge. The Tron snap gives those asset
ids precedence over the contract type, so an approve was classified as a
swap or bridgeSend instead of tokenApprove.
Add an isApproval flag and only attach the asset ids to the main trade.
The approval request now falls back to the contract-type classification.
This snapshot for the “Tron bridge” request passes two tron:728126428 asset IDs, so the downstream chain comparison classifies it as a same-chain swap rather than bridgeSend. The bridge fixture only changes destChainId; update its destination asset (including assetId) to an EVM asset and regenerate the snapshot so the new bridge-classification contract is actually covered.
Avoid increasing the no-unsafe-assignment suppression baseline
oxlint-suppressions.json:2241
This increases the temporary no-unsafe-assignment baseline by four for the newly added assertions, hiding new lint violations instead of keeping the changed tests type-safe. Rewrite the new matchers with typed request values (or assert dynamic fields separately), then restore the previous suppression count.
The reason will be displayed to describe this comment to others. Learn more.
First, the Tron snap is bumped before/at the same time than this bridge-status-controller will be bumped so there will be no regression with retro-compatibility.
Second, the new arguments are optional on the Tron snap side so it would still be compatible with previous versions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Explanation
Current state
getClientRequestbuilds thesignAndSendTransactionoptions per non-EVM chain. Before this PR it forwarded the swap/bridgesourceAssetId/destAssetIdonly for Stellar. Tron, Solana, and Bitcoin therefore could not see the swap asset ids, so their snaps could not tell a same-chain swap from a cross-chain bridge and reportedunknown(Tron) or a balance-derivedsend(Solana, Bitcoin) for those transactions.Solution
Forward
sourceAssetIdanddestAssetIdfor Tron, Solana, and Bitcoin, mirroring the existing Stellar behavior.visibleflag and contracttypein the same options object.isStellarChainId,isSolanaChainId,isBitcoinChainId) rather than trade-shape guards, sincegetClientRequestalready receivessrcChainIdand a Stellar trade can also be a plain base64 string.Each snap then compares the CAIP-2 chains of the two asset ids to classify the transaction as a same-chain
swapor a cross-chainbridgeSend.Non-obvious points
handleNonEvmTxnow takes anisApprovalflag and only attaches the asset ids to the main trade. Without this, the approval request would inherit the swap asset ids, and the Tron snap (which gives the asset ids precedence over the contract type) would classify anapproveasswap/bridgeSendinstead oftokenApprove.isTronTradebecause it needs to readvisibleand the contract type off the trade object.destChainIdto Solana but gave the destination asset aneip155CAIP id. Now that the asset ids are forwarded, that mismatch would classify the same-chain swap as abridgeSend, so the fixture was corrected to use a Solana asset id.References
Checklist