warn sp dust (#2402)
* feat: warn sp dust * Update lib/view_model/send/send_view_model.dart * fix condition --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
rafael_xmr committed
Jul 29, 2025 at 09:50 UTC
10499814bb9d1f58d78a80b971b5be0bbf299266
3 files changed
+46
-8
cw_bitcoin/lib/electrum_wallet.dart
+24
-2
@@ -780,7 +780,11 @@ abstract class ElectrumWalletBase
780
}
781
782
if (outputs.length == 1) {
783
- outputs[0] = BitcoinOutput(address: outputs.last.address, value: BigInt.from(amount));
783
+ outputs[0] = BitcoinOutput(
784
+ address: outputs.last.address,
785
+ value: BigInt.from(amount),
786
+ isSilentPayment: hasSilentPayment,
787
+ );
788
}
789
790
return EstimatedTxResult(
@@ -888,7 +892,17 @@ abstract class ElectrumWalletBase
892
);
893
894
updatedOutputs.clear();
891
- updatedOutputs.addAll(temp);
895
+ for (int i = 0; i < temp.length; i++) {
896
+ final output = temp[i];
897
+ final oldOutput = outputs[i];
898
+
899
+ updatedOutputs.add(BitcoinOutput(
900
+ address: output.address,
901
+ value: output.value,
902
+ isSilentPayment: oldOutput.isSilentPayment,
903
+ isChange: output.isChange,
904
+ ));
905
+ }
906
907
if (fee == 0) {
908
throw BitcoinTransactionNoFeeException();
@@ -1088,6 +1102,14 @@ abstract class ElectrumWalletBase
1102
);
1103
}
1104
1105
+ for (final output in updatedOutputs) {
1106
+ // TODO: get from server
1107
+ // if (output.isSilentPayment && output.value.toInt() > silentPaymentsMin) {
1108
+ if (output.isSilentPayment && output.value.toInt() <= 1000) {
1109
+ throw BitcoinTransactionNoDustException();
1110
+ }
1111
+ }
1112
+
1113
if (walletInfo.isHardwareWallet) {
1114
final transaction = await buildHardwareWalletTransaction(
1115
utxos: estimatedTx.utxos,
lib/src/screens/send/widgets/send_card.dart
+1
-1
@@ -258,7 +258,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
258
!sendViewModel.isBatchSending && sendViewModel.shouldDisplaySendALL,
259
currencyValueValidator: output.sendAll
260
? sendViewModel.allAmountValidator
261
- : sendViewModel.amountValidator,
261
+ : sendViewModel.amountValidator(output),
262
allAmountCallback: () async =>
263
output.setSendAll(await sendViewModel.sendingBalance),
264
),
lib/view_model/send/send_view_model.dart
+21
-5
@@ -182,9 +182,9 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
182
if (pendingTransaction != null) {
183
final currency = pendingTransactionFeeCurrency(walletType);
184
final fiat = calculateFiatAmount(
185
- price: _fiatConversationStore.prices[currency]!,
186
- cryptoAmount: pendingTransaction!.feeFormattedValue,
187
- );
185
+ price: _fiatConversationStore.prices[currency]!,
186
+ cryptoAmount: pendingTransaction!.feeFormattedValue,
187
+ );
188
return fiat;
189
} else {
190
return '0.00';
@@ -210,8 +210,15 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
210
211
CryptoCurrency get currency => wallet.currency;
212
213
- Validator<String> get amountValidator =>
214
- AmountValidator(currency: walletTypeToCryptoCurrency(wallet.type));
213
+ Validator<String> amountValidator(Output output) => AmountValidator(
214
+ currency: walletTypeToCryptoCurrency(wallet.type),
215
+ minValue: isSendToSilentPayments(output)
216
+ ?
217
+ // TODO: get from server
218
+ // bitcoin!.silentPaymentsMinAmount
219
+ '0.00001'
220
+ : null,
221
+ );
222
223
Validator<String> get allAmountValidator => AllAmountValidator();
224
@@ -289,6 +296,15 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
296
// If silent payments scanning, can still send payments
297
(wallet.type == WalletType.bitcoin && wallet.syncStatus is SyncingSyncStatus);
298
299
+ bool isSendToSilentPayments(Output output) =>
300
+ wallet.type == WalletType.bitcoin &&
301
+ (RegExp(AddressValidator.silentPaymentAddressPatternMainnet).hasMatch(output.address) ||
302
+ RegExp(AddressValidator.silentPaymentAddressPatternMainnet)
303
+ .hasMatch(output.extractedAddress) ||
304
+ (output.parsedAddress.addresses.isNotEmpty &&
305
+ RegExp(AddressValidator.silentPaymentAddressPatternMainnet)
306
+ .hasMatch(output.parsedAddress.addresses[0])));
307
+
308
@computed
309
List<Template> get templates => sendTemplateViewModel.templates
310
.where((template) => _isEqualCurrency(template.cryptoCurrency))