Merge branch 'staging' into feat/trocador-onion
What changed, and why it matters
This commit adds a small convenience feature in Stack Wallet: when a user scans or opens a Firo payment QR code that contains a 'message' field and the payment address is a Spark privacy address, the wallet now automatically copies that message into the Spark memo field. Spark memos are like short notes attached to private Firo transactions. The change is a user-experience improvement to match how the official Firo desktop wallet (firo-qt) behaves. There is no obvious security bug in the code itself, but it does involve handling untrusted payment data and trusting a third-party address-validation helper.
Review SparkInterface.validateSparkAddress for correctness and ensure paymentData.message is sanitized before being placed in memoController.text. Confirm that the memo field cannot be used to inject malicious content, exceed size limits, or trick users into approving unintended Spark transactions. Treat this as a routine UX merge unless additional context shows the change addresses a reported bug.
Security signals we found
Untrusted paymentData.message is copied into a transaction memo field without visible escaping/sanitization
Relies on SparkInterface.validateSparkAddress to gate memo population; correctness of that helper is not shown in the diff
Behavior parity with firo-qt suggests a UX fix rather than a vulnerability fix
No explicit security claims, advisory references, or incident attribution in commit message or diff
Evidence from the diff
Two UI files (mobile SendView and desktop DesktopSend) now check whether the selected coin is Firo, paymentData.message is non-null, and the destination address validates as a Spark address via SparkInterface.validateSparkAddress. If all conditions pass, the message is assigned to memoController.text. The change is purely additive (+20 lines, no deletions) and mirrors firo-qt behavior. No input sanitization beyond the existing address validation is visible in the diff, and the commit does not modify the validation routine itself.
Changed components
lib/pages/send_view/send_view.dartlib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dartFiro Spark send/memo flowInspect captured patch +20 / −0
### lib/pages/send_view/send_view.dart
@@ -169,6 +169,16 @@ class _SendViewState extends ConsumerState<SendView> {
noteController.text = paymentData.label!;
}
+ // firo-qt treats message as the spark memo when paying a spark address
+ if (coin is Firo &&
+ paymentData.message != null &&
+ SparkInterface.validateSparkAddress(
+ address: _address!,
+ isTestNet: coin.network.isTestNet,
+ )) {
+ memoController.text = paymentData.message!;
+ }
+
// autofill amount field
if (paymentData.amount != null) {
final amount = Amount.tryParseCanonicalAmount(
### lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart
@@ -1010,6 +1010,16 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
_note = paymentData.label;
}
+ // firo-qt treats message as the spark memo when paying a spark address
+ if (coin is Firo &&
+ paymentData.message != null &&
+ SparkInterface.validateSparkAddress(
+ address: _address!,
+ isTestNet: coin.network.isTestNet,
+ )) {
+ memoController.text = paymentData.message!;
+ }
+
// autofill amount field
if (paymentData.amount != null) {
final amount = Amount.tryParseCanonicalAmount(Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.