dev
dart 108 lines 3.46 KB
Raw
1 import 'dart:async';
2 import 'dart:ffi';
3
4 import 'package:cw_core/amount/money.dart';
5 import 'package:cw_core/utils/print_verbose.dart';
6 import 'package:cw_core/wallet_info.dart';
7 import 'package:cw_core/crypto_currency.dart';
8 import 'package:cw_core/pending_transaction.dart';
9 import 'package:cw_monero/api/account_list.dart';
10 import 'package:cw_monero/api/structs/pending_transaction.dart';
11 import 'package:cw_monero/api/transaction_history.dart' as monero_transaction_history;
12 import 'package:cw_monero/api/wallet.dart';
13 import 'package:cw_monero/monero_wallet.dart';
14 import 'package:monero/monero.dart' as monero;
15
16 class DoubleSpendException implements Exception {
17 DoubleSpendException();
18
19 @override
20 String toString() =>
21 'This transaction cannot be committed. This can be due to many reasons including the wallet not being synced, there is not enough XMR in your available balance, or previous transactions are not yet fully processed.';
22 }
23
24 class PendingMoneroTransaction with PendingTransaction {
25 PendingMoneroTransaction(this.pendingTransactionDescription, this.wallet);
26
27 final PendingTransactionDescription pendingTransactionDescription;
28 final MoneroWalletBase wallet;
29
30 Money get amount => Money.fromInt(pendingTransactionDescription.amount, CryptoCurrency.xmr);
31
32 Money get fee => Money.fromInt(pendingTransactionDescription.fee, CryptoCurrency.xmr);
33
34 @override
35 String get id => pendingTransactionDescription.hash;
36
37 @override
38 String get hex => pendingTransactionDescription.hex;
39
40 @override
41 String get amountFormatted => amount.toString();
42
43 @override
44 bool shouldCommitUR() => isViewOnly && wallet.hardwareWalletType != HardwareWalletType.trezor;
45
46 @override
47 Future<void> commit() async {
48 if (wallet.hardwareWalletType == HardwareWalletType.trezor) {
49 final ptr = Pointer<Void>.fromAddress(pendingTransactionDescription.pointerAddress);
50 final ret = await monero.PendingTransaction_commitTrezor(ptr, 0);
51
52 final json = await wallet.signTrezorTransaction(ret);
53
54 final wptr = Pointer<Void>.fromAddress(currentWallet!.ffiAddress());
55
56 final suc = await monero.Wallet_submitTransactionHex(wptr, json);
57
58 if (!suc) {
59 final err = monero.UnsignedTransaction_errorString(ptr);
60 printV(err);
61 throw err;
62 }
63 } else {
64 try {
65 await monero_transaction_history.commitTransactionFromPointerAddress(
66 address: pendingTransactionDescription.pointerAddress, useUR: false);
67 } catch (e) {
68 final message = e.toString();
69
70 if (message.contains('Reason: double spend')) {
71 throw DoubleSpendException();
72 }
73
74 rethrow;
75 }
76 }
77 storeSync(force: true);
78 unawaited(() async {
79 await Future.delayed(const Duration(milliseconds: 250));
80 await wallet.fetchTransactions();
81 }());
82 }
83
84 @override
85 Future<Map<String, String>> commitUR() async {
86 try {
87 final ret = await monero_transaction_history.commitTransactionFromPointerAddress(
88 address: pendingTransactionDescription.pointerAddress, useUR: true);
89 storeSync(force: true);
90 unawaited(() async {
91 await Future.delayed(const Duration(milliseconds: 250));
92 await wallet.fetchTransactions();
93 }());
94 if (ret == null) return {};
95 return {
96 "xmr-txsigned": ret,
97 };
98 } catch (e) {
99 final message = e.toString();
100
101 if (message.contains('Reason: double spend')) {
102 throw DoubleSpendException();
103 }
104
105 rethrow;
106 }
107 }
108 }