Skip to content

feat: enable security scan for send confirmations#85

Merged
wantedsystem merged 6 commits into
mainfrom
feat/enable-security-scan-send-flow
Jun 3, 2026
Merged

feat: enable security scan for send confirmations#85
wantedsystem merged 6 commits into
mainfrom
feat/enable-security-scan-send-flow

Conversation

@wantedsystem
Copy link
Copy Markdown
Contributor

@wantedsystem wantedsystem commented Jun 1, 2026

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)

  • Passes the send transaction XDR to the confirmation security scan pipeline.
  • Enables scanTxn for confirmSend confirmations.
  • Renders transaction security alerts in the send confirmation UI.
  • Disables the confirm button while scanning or when a malicious validation result is returned.
  • Updates confirmSend tests to assert scan request wiring.

Transaction validation refresh

  • Adds a ConfirmationTransactionRefresher as a new slice of the consolidated RefreshConfirmationContext background 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).
  • Wires it into the send (confirmSend) and trustline opt-in/opt-out flows via a new validateTxn render option and transactionValidationRequest ({ accountId, transaction, request }).
  • Adds ContextWithTransactionScanStruct and transactionsFetchStatus to the confirmation context.
  • Adds a TransactionValidationAlert banner and disables the confirm button when re-validation marks the transaction invalid (transactionsFetchStatus: Error).
  • Adds transactionInvalid* locale strings (en/es).
  • Adds unit tests for the refresher (send + change-trust opt-in/opt-out, expired envelope, recovery, and gating).

Notes / follow-ups

  • Does not apply to SEP-43 signTransaction — the dapp owns that XDR ("sign what you see").
  • Validation re-uses a rebuilt draft as a proxy for the stored envelope; the stored envelope's time bound is checked explicitly, and sequence drift is covered by the submit-time txBadSeq retry. A follow-up could validate the stored envelope directly.
  • Transaction validation starts optimistically as Fetched (the tx was validated at build time); a follow-up could add a final synchronous re-validation right before signing.

References

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
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

@wantedsystem wantedsystem requested a review from a team as a code owner June 1, 2026 14:22
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

Comment thread packages/snap/src/ui/confirmation/controller.tsx Outdated
Comment thread packages/snap/src/ui/confirmation/api.ts
Comment thread packages/snap/src/ui/confirmation/utils.ts
Comment thread packages/snap/src/handlers/clientRequest/confirmSend.ts Outdated
Comment on lines +180 to +183
return {
result: { transactionsFetchStatus: FetchStatus.Error },
reschedule: false,
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

have u check if it behave the same as blockaid or tron

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Lets address it in other PR / ticket when we confirmed it is needed

return (
<Container>
<Box>
{hasEnabledTransactionScan(preferences) ? (
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i was thinking, should we merge transaction refresher into the scan refresher

as right now scan refresher also support transaction validation...

Copy link
Copy Markdown
Contributor Author

@wantedsystem wantedsystem Jun 2, 2026

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

then i think u have to make sure they dont appear together (from code base)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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)

Comment thread packages/snap/src/handlers/clientRequest/changeTrustOpt.ts Outdated
severity="danger"
>
<SnapText>
{translate('confirmation.transactionInvalidSubtitle')}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

we dont have reason on it?

Copy link
Copy Markdown
Contributor Author

@wantedsystem wantedsystem Jun 2, 2026

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Collaborator

@stanleyyconsensys stanleyyconsensys left a comment

Choose a reason for hiding this comment

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

LGTM, we can refine this condition to be more clear later

  {transactionsFetchStatus !== FetchStatus.Error &&
        hasEnabledTransactionScan(preferences) ? (

@wantedsystem wantedsystem merged commit d51f780 into main Jun 3, 2026
10 checks passed
@wantedsystem wantedsystem deleted the feat/enable-security-scan-send-flow branch June 3, 2026 10:22
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.

3 participants