Skip to content

Conversation

@dawnseeker8
Copy link
Contributor

@dawnseeker8 dawnseeker8 commented Sep 10, 2025

References

Relates to https://consensyssoftware.atlassian.net/browse/BETR-5

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
  • I've communicated my changes to consumers by updating changelogs for packages I've changed, highlighting breaking changes as necessary
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes

Note

Introduces intent-based swap/bridge flow end-to-end.

  • Types/validators: Add Intent/IntentOrder schemas and optional quote.intent; extend StatusTypes with SUBMITTED
  • BridgeStatusController: New submitIntent action; create synthetic TC tx, write history (originalTransactionId, srcTxHashes), and poll intent order status via new IntentApiImpl; map intent statuses to bridge/TC statuses; start/stop polling and track events (skip when featureId)
  • API: Implement IntentApiImpl with submitIntent/getOrderStatus and status mapping
  • Tests: Comprehensive unit tests for intent submission, polling, and validators; snapshot updates; jest coverage thresholds adjusted
  • Misc: Export intent types; changelogs updated; .gitignore adds Emacs patterns

Written by Cursor Bugbot for commit 87e2d3a. This will update automatically on new commits. Configure here.

@dawnseeker8 dawnseeker8 changed the title wip: Intent base Swap POC feat: CowSwap intent base swap Sep 24, 2025
@oscarwroche oscarwroche force-pushed the wip/intent-swap-architecture-refactory branch from 4832227 to 126f733 Compare January 8, 2026 09:54
bfullam
bfullam previously approved these changes Jan 8, 2026
Akaryatrh
Akaryatrh previously approved these changes Jan 8, 2026
@oscarwroche oscarwroche changed the title feat: CowSwap intent-based swaps feat: intent-based swaps support Jan 8, 2026
@matthewwalsh0
Copy link
Member

Given the volume of code here, I'd recommend merging the bridge controllers code in isolation, then we can address any required changes to the TransactionController separately without blocking the full code changes.

## Explanation

<!--
Thanks for your contribution! Take a moment to answer these questions so
that reviewers have the information they need to properly understand
your changes:

* What is the current state of things and why does it need to change?
* What is the solution your changes offer and how does it work?
* Are there any changes whose purpose might not obvious to those
unfamiliar with the domain?
* If your primary goal was to update one package but you found you had
to update another one along the way, why did you do so?
* If you had to upgrade a dependency, why did you do so?
-->

## References

<!--
Are there any issues that this pull request is tied to?
Are there other links that reviewers should consult to understand these
changes better?
Are there client or consumer pull requests to adopt any breaking
changes?

For example:

* Fixes #12345
* Related to #67890
-->

## 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
- [ ] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/contributing.md#updating-changelogs)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> - **Keyring Controller**: New `KeyringControllerError` class with
codes/context, JSON/string serialization, and error chaining; refactors
controller to throw `KeyringControllerError` (renamed enum to
`KeyringControllerErrorMessage`); exports `errors`; extensive test
updates including hardware wallet error preservation.
> - **Multichain Account Service (Snaps)**: Add `SnapPlatformWatcher`
and `MultichainAccountService:ensureCanUseSnapPlatform`; new
`SnapAccountProvider.withSnap` guard (and make `client` private); update
`Sol/Btc/Trx` providers to use guarded `client/keyring` access for
discovery/creation; add lodash; new tests.
> - **Bridge/Intents**: In bridge status controller, set `isStateOnly:
true` on intent addTransaction and remove `swaps` metadata and initial
gas estimate.
> - **Assets/Bridge package bumps**: `@metamask/assets-controllers` to
`95.0.0` with changelog links; `bridge-controller` depends on it;
monorepo version to `742.0.0`.
> 
> Scope: error-handling overhaul and Snap readiness guard across
providers; minor intent/bridge metadata change; package version bumps.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e493417. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Monte Lai <[email protected]>
Co-authored-by: Charly Chevalier <[email protected]>
Co-authored-by: Salim TOUBAL <[email protected]>
Co-authored-by: Matthew Walsh <[email protected]>
@oscarwroche oscarwroche dismissed stale reviews from Akaryatrh and bfullam via 6c38a94 January 9, 2026 11:00
@oscarwroche oscarwroche requested review from a team as code owners January 9, 2026 11:00
return TransactionStatus.confirmed;
case IntentOrderStatus.FAILED:
case IntentOrderStatus.EXPIRED:
return TransactionStatus.failed;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cancelled intent orders incorrectly mapped to submitted status

Medium Severity

The mapIntentOrderStatusToTransactionStatus function is missing a case for IntentOrderStatus.CANCELLED, causing it to fall through to the default and return TransactionStatus.submitted. However, in #updateBridgeHistoryFromIntentOrder, CANCELLED is correctly included in the isFailed array and mapped to StatusTypes.FAILED. This inconsistency means cancelled orders will show as "submitted" in the TransactionController but "failed" in the bridge history, creating a confusing user experience where the same order appears in different states across the UI.

Additional Locations (1)

Fix in Cursor Fix in Web

// Check metadata for additional transaction hashes
const metadataTxHashes = Array.isArray(intentOrder.metadata.txHashes)
? intentOrder.metadata.txHashes
: [];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String txHashes ignored when not array format

Medium Severity

The IntentOrder type and schema explicitly allow metadata.txHashes to be either string[] or string, but the code only handles the array case. When txHashes is a single string, Array.isArray() returns false and metadataTxHashes becomes an empty array, silently discarding the transaction hash. If intentOrder.txHash is also undefined, this results in lost transaction hash data that won't be recorded in the history.

Fix in Cursor Fix in Web

return TransactionStatus.confirmed;
case IntentOrderStatus.FAILED:
case IntentOrderStatus.EXPIRED:
return TransactionStatus.failed;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cancelled intent orders mapped to wrong transaction status

Medium Severity

The mapIntentOrderStatusToTransactionStatus function is missing a case for IntentOrderStatus.CANCELLED. When an intent order is cancelled, it falls through to the default case and incorrectly returns TransactionStatus.submitted. This is inconsistent with #updateBridgeHistoryFromIntentOrder which correctly treats CANCELLED as a failed state. The result is that the bridge history shows the order as failed, but the TransactionController transaction shows it as submitted, causing conflicting UI states.

Additional Locations (1)

Fix in Cursor Fix in Web

// Check metadata for additional transaction hashes
const metadataTxHashes = Array.isArray(intentOrder.metadata.txHashes)
? intentOrder.metadata.txHashes
: [];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String value in metadata.txHashes silently discarded

Medium Severity

The IntentOrder type defines metadata.txHashes as string[] | string, but the code at #updateBridgeHistoryFromIntentOrder only handles the array case. When the API returns a single string instead of an array, Array.isArray() returns false and the code falls back to an empty array, losing the transaction hash. This could cause transaction hashes to be missing from the history when the API returns txHashes as a single string value.

Fix in Cursor Fix in Web

* This is called during initialization
*/
readonly #restartPollingForIncompleteHistoryItems = () => {
readonly #restartPollingForIncompleteHistoryItems = (): void => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intent transactions excluded from polling restart on browser reopen

High Severity

The #restartPollingForIncompleteHistoryItems method has two gaps that prevent intent-based transactions from resuming polling after browser restart. First, the status filter (lines 404-408) only checks for PENDING and UNKNOWN, but excludes the new StatusTypes.SUBMITTED status used by intent orders. Second, the filter at lines 415-422 only passes cross-chain bridge transactions, excluding same-chain intent swaps entirely. However, #startPollingForTxId correctly handles intent transactions via txId.startsWith('intent:'). This causes intent-based swaps to become stuck with no status updates if the user closes and reopens their browser while a swap is in progress.

Fix in Cursor Fix in Web

@oscarwroche oscarwroche added this pull request to the merge queue Jan 9, 2026
Merged via the queue into main with commit e229c9c Jan 9, 2026
286 checks passed
@oscarwroche oscarwroche deleted the wip/intent-swap-architecture-refactory branch January 9, 2026 12:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants