feat: enable security scan for send confirmations#85
Conversation
There was a problem hiding this comment.
Pull request overview
This PR enables transaction security scanning for the unified send confirmation flow and adds background “while dialog is open” transaction re-validation for send + change-trust confirmations, surfacing invalid-transaction alerts and blocking confirmation when appropriate.
Changes:
- Wire send confirmations into the existing security scan pipeline and render security alerts in the send confirmation UI.
- Add a new confirmation-context refresher that re-validates pending transactions against latest on-chain state, and disable confirmation when re-validation fails.
- Extend confirmation context/types and add UI banner + locale strings for invalid-transaction states.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/snap/src/ui/confirmation/views/ConfirmSignChangeTrustOptOut/ConfirmSignChangeTrustOptOut.tsx | Disables confirm on invalid tx state and renders the new validation alert banner. |
| packages/snap/src/ui/confirmation/views/ConfirmSignChangeTrustOptIn/ConfirmSignChangeTrustOptIn.tsx | Disables confirm on invalid tx state and renders the new validation alert banner. |
| packages/snap/src/ui/confirmation/views/ConfirmSendTransaction/ConfirmSendTransaction.tsx | Adds security scan alert rendering, validation alert banner, and confirm disabling logic for send confirmations. |
| packages/snap/src/ui/confirmation/utils.ts | Adds isConfirmDisabledByTransactionValidation helper for confirm-button gating. |
| packages/snap/src/ui/confirmation/controller.tsx | Adds validateTxn render option and injects transaction-validation context for background refreshing. |
| packages/snap/src/ui/confirmation/components/TransactionValidationAlert.tsx | New banner component shown when background re-validation marks the tx invalid. |
| packages/snap/src/ui/confirmation/components/index.ts | Exports the new TransactionValidationAlert component. |
| packages/snap/src/ui/confirmation/api.ts | Extends confirmation context types/structs to include transaction re-validation context and status. |
| packages/snap/src/handlers/cronjob/refreshConfirmationContext/transactionRefresher.ts | New refresher that re-resolves sender + checks envelope time bounds + re-validates tx against latest state. |
| packages/snap/src/handlers/cronjob/refreshConfirmationContext/transactionRefresher.test.ts | Unit tests covering success, invalidation, expiry, recovery, and gating for the new refresher. |
| packages/snap/src/handlers/cronjob/refreshConfirmationContext/index.ts | Exposes the new transaction refresher from the refresh-confirmation module. |
| packages/snap/src/handlers/cronjob/refreshConfirmationContext/api.ts | Adds a new refresher key for transaction re-validation. |
| packages/snap/src/handlers/clientRequest/confirmSend.ts | Enables scan + validation refresh for send confirmations and passes XDR to both pipelines. |
| packages/snap/src/handlers/clientRequest/confirmSend.test.ts | Extends send confirmation tests to assert scan + validation request wiring (XDR capture). |
| packages/snap/src/handlers/clientRequest/changeTrustOpt.ts | Enables scan + validation refresh for change-trust confirmations and passes XDR + request context. |
| packages/snap/src/handlers/clientRequest/changeTrustOpt.test.ts | Extends change-trust tests to assert validation request wiring. |
| packages/snap/src/context.ts | Registers the new transaction refresher in the consolidated confirmation refresh handler. |
| packages/snap/snap.manifest.json | Updates snap bundle shasum to match the new build output. |
| packages/snap/messages.json | Adds new message keys for “transaction invalid” banner strings. |
| packages/snap/locales/es.json | Adds the new “transaction invalid” message keys to the Spanish locale file. |
| packages/snap/locales/en.json | Adds the new “transaction invalid” message keys to the English locale file. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return { | ||
| result: { transactionsFetchStatus: FetchStatus.Error }, | ||
| reschedule: false, | ||
| }; |
There was a problem hiding this comment.
since the createValidatedSendTransaction will throw an error
lets say the fee suddenly raise, and user suddenly doesnt have enough fund, however, may be after few second, the fee drop, and we dont reschedule anymore, is it expected?
it is very rare, but possible
There was a problem hiding this comment.
Same as the scan refresher, which also stops on error. If validation fails the user just closes and reopens to re-validate. Auto-recovering would mean rescheduling on error + dropping the Error check in shouldFetch, which brings back constant polling and Error/Fetched
There was a problem hiding this comment.
have u check if it behave the same as blockaid or tron
There was a problem hiding this comment.
Checked Blockaid and Tron. Our scan refresher behaves the same reschedule: false on error. Tron is the exception: it keeps rescheduling and rebuilds the tx instead of marking it invalid. We fail closed (user closes/reopens to re-validate), which matches our scan refresher
There was a problem hiding this comment.
Lets address it in other PR / ticket when we confirmed it is needed
| return ( | ||
| <Container> | ||
| <Box> | ||
| {hasEnabledTransactionScan(preferences) ? ( |
There was a problem hiding this comment.
i was thinking, should we merge transaction refresher into the scan refresher
as right now scan refresher also support transaction validation...
There was a problem hiding this comment.
I prefer keeping them separate. The scan refresher calls Blockaid : this one checks on-chain state (expiry, balance, fees). A scan error is a warning, a validation error blocks confirm (for now). Merging would mix two unrelated things.
There was a problem hiding this comment.
then i think u have to make sure they dont appear together (from code base)
There was a problem hiding this comment.
Good point. Checked Tron : it merges everything into one scanFetchStatus so only one banner ever shows. Ours has two separate alerts that can stack today. I'll make them mutually exclusive so only one shows (validation takes priority since it blocks confirm)
| severity="danger" | ||
| > | ||
| <SnapText> | ||
| {translate('confirmation.transactionInvalidSubtitle')} |
There was a problem hiding this comment.
we dont have reason on it?
There was a problem hiding this comment.
Tron does not show a specific reason for a re-validation/expiration failure: it logs it and shows the generic scan-error message. So keeping our generic subtitle is consistent with Tron
stanleyyconsensys
left a comment
There was a problem hiding this comment.
LGTM, we can refine this condition to be more clear later
{transactionsFetchStatus !== FetchStatus.Error &&
hasEnabledTransactionScan(preferences) ? (
Explanation
Enables transaction security scanning for the Unified Non-EVM send confirmation flow, and adds background transaction re-validation to the send and trustline confirmation flows.
Changes
Security scanning (send flow)
scanTxnforconfirmSendconfirmations.confirmSendtests to assert scan request wiring.Transaction validation refresh
ConfirmationTransactionRefresheras a new slice of the consolidatedRefreshConfirmationContextbackground job. While a confirmation dialog is open it re-resolves the sender on-chain (RPC/Horizon), checks the pending envelope's time bound, and re-validates the transaction (sequence, balance, fees, inactive destination).confirmSend) and trustline opt-in/opt-out flows via a newvalidateTxnrender option andtransactionValidationRequest({ accountId, transaction, request }).ContextWithTransactionScanStructandtransactionsFetchStatusto the confirmation context.TransactionValidationAlertbanner and disables the confirm button when re-validation marks the transaction invalid (transactionsFetchStatus: Error).transactionInvalid*locale strings (en/es).Notes / follow-ups
signTransaction— the dapp owns that XDR ("sign what you see").txBadSeqretry. A follow-up could validate the stored envelope directly.Fetched(the tx was validated at build time); a follow-up could add a final synchronous re-validation right before signing.References
Checklist