fix: fail cancelled smart transactions through the standard failure path#9400
Open
cloudonshore wants to merge 2 commits into
Open
fix: fail cancelled smart transactions through the standard failure path#9400cloudonshore wants to merge 2 commits into
cloudonshore wants to merge 2 commits into
Conversation
When the relay cancels a smart transaction (e.g. FAILED_GAS_TOO_LOW), the smart-transactions-controller marked the associated regular transaction as failed via `TransactionController:updateTransaction`, which only patches state and does not emit any transaction lifecycle events. Consumers that react to `transactionFailed`/`transactionStatusUpdated` — notably the bridge status controller and transaction metrics — were therefore never notified, leaving cancelled smart transactions (such as bridges) stuck as pending indefinitely. - transaction-controller: add a public `failTransaction(transactionId, error)` method and `TransactionController:failTransaction` messenger action that fails a transaction through the internal fail path, emitting `transactionFailed`, `transactionStatusUpdated`, and `transactionFinished`. - smart-transactions-controller: use `failTransaction` instead of `updateTransaction` when marking regular transactions as failed.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
When the transaction relay cancels a smart transaction (e.g.
FAILED_GAS_TOO_LOW— the smart tx never lands on chain),SmartTransactionsControllermarks the associated regular transaction as failed via theTransactionController:updateTransactionaction.updateTransactiononly patches state — it does not emit any transaction lifecycle events. As a result, consumers that react totransactionFailed/transactionStatusUpdatedare never notified:BridgeStatusControllermarks a bridge item failed only from thetransactionStatusUpdated/transactionFailedevent. Since that event never fires for a cancelled smart tx, the bridge history item staysPENDINGforever — the transaction shows as failed, but the bridge UI remains stuck on "Pending".Transaction Finalized) are likely under-reported for the same reason.This was observed in production with bridge smart transactions repeatedly stuck as pending (source tx
status: failed, bridgestatus.status: PENDING), while the relay'sbatchStatusreportedminedTx: cancelled/cancellationReason: too_cheap.Fix
Route the cancellation failure through the standard fail path so the lifecycle events fire.
transaction-controller: add a publicfailTransaction(transactionId, error)method and correspondingTransactionController:failTransactionmessenger action. It fails the transaction through the internal#failTransaction, emittingtransactionFailed,transactionStatusUpdated, andtransactionFinished.smart-transactions-controller:markRegularTransactionsAsFailednow callsfailTransactioninstead ofupdateTransaction.References
Changelog
@metamask/transaction-controllerfailTransactionmethod andTransactionController:failTransactionmessenger action.@metamask/smart-transactions-controllerTransactionController:failTransaction(wasupdateTransaction) so transaction lifecycle events are emitted and downstream consumers no longer leave cancelled smart transactions stuck as pending.TransactionController:failTransaction(previouslyTransactionController:updateTransaction).Checklist
Note
Medium Risk
Touches core transaction failure signaling and requires a messenger permission change for smart-transactions-controller; behavior is narrowly scoped to cancelled smart-tx paths but downstream bridge/metrics depend on it.
Overview
When a smart transaction is cancelled, the linked regular transaction must be marked failed in a way that emits transaction lifecycle events, not only a state patch.
transaction-controlleradds publicfailTransaction(transactionId, error)andTransactionController:failTransaction, routing through the existing internal failure path sotransactionFailed,transactionStatusUpdated, andtransactionFinishedfire.updateTransactionis unchanged and still does not emit those events.smart-transactions-controllerupdatesmarkRegularTransactionsAsFailedand#createOrUpdateSmartTransactionto callfailTransactionwith aSmartTransactionFailederror instead ofupdateTransactionwith a full failedTransactionMeta. Messenger allowed actions swapTransactionController:updateTransactionforTransactionController:failTransaction.Integrators must grant the smart transactions controller access to
TransactionController:failTransaction(replacingupdateTransactionfor this flow). This fixes bridge and similar flows where the source tx looked failed but bridge history stayed PENDING because subscribers never saw lifecycle events.Reviewed by Cursor Bugbot for commit c72d709. Bugbot is set up for automated code reviews on this repo. Configure here.