dev
dart 153 lines 4.4 KB
Raw
1 import 'dart:convert';
2 import 'package:cw_core/payment_uris.dart';
3 import 'package:cw_core/receive_page_option.dart';
4 import 'package:cw_core/utils/print_verbose.dart';
5 import 'package:mobx/mobx.dart';
6
7 import 'package:cw_core/wallet_addresses.dart';
8 import 'package:cw_core/wallet_info.dart';
9 import 'package:cw_decred/api/libdcrwallet.dart';
10
11 part 'wallet_addresses.g.dart';
12
13 class DecredWalletAddresses = DecredWalletAddressesBase with _$DecredWalletAddresses;
14
15 abstract class DecredWalletAddressesBase extends WalletAddresses with Store {
16 DecredWalletAddressesBase(super.walletInfo, this._libwallet, super.isTestnet);
17
18 final Libwallet _libwallet;
19 String _currentAddr = '';
20
21 @observable
22 bool isEnabledAutoGenerateSubaddress = true;
23
24 @observable
25 String selectedAddr = '';
26
27 @override
28 @computed
29 String get address => selectedAddr;
30
31 @override
32 set address(value) => selectedAddr = value;
33
34 @override
35 Future<void> init() async {
36 addressesMap = await walletInfo.getAddresses();
37 addressInfos = await walletInfo.getAddressInfos();
38 usedAddresses = await walletInfo.getUsedAddresses();
39 manualAddresses = await walletInfo.getManualAddresses();
40 hiddenAddresses = await walletInfo.getHiddenAddresses();
41 await updateAddressesInBox();
42 }
43
44 @override
45 Future<void> updateAddressesInBox() async {
46 final addrs = await _libAddresses();
47 final allAddrs = List.from(addrs.usedAddrs)..addAll(addrs.unusedAddrs);
48
49 // Add all addresses.
50 allAddrs.forEach((addr) {
51 if (addressesMap.containsKey(addr)) return;
52
53 addressesMap[addr] = "";
54 addressInfos[0] ??= [];
55 addressInfos[0]?.add(
56 WalletInfoAddressInfo(
57 walletInfoId: walletInfo.internalId,
58 mapKey: 0,
59 address: addr,
60 label: "",
61 accountIndex: 0,
62 ),
63 );
64 });
65
66 // Add used addresses.
67 addrs.usedAddrs.forEach((addr) {
68 if (!usedAddresses.contains(addr)) usedAddresses.add(addr);
69 });
70
71 if (addrs.unusedAddrs.length > 0 && addrs.unusedAddrs[0] != _currentAddr) {
72 _currentAddr = addrs.unusedAddrs[0];
73 selectedAddr = _currentAddr;
74 }
75
76 await saveAddressesInBox();
77 }
78
79 List<WalletInfoAddressInfo> getAddressInfos() {
80 if (addressInfos.containsKey(0)) return addressInfos[0]!;
81
82 return <WalletInfoAddressInfo>[];
83 }
84
85 Future<void> updateAddress(String address, String label) async {
86 if (!addressInfos.containsKey(0)) return;
87
88 addressInfos[0]!.forEach((info) {
89 if (info.address == address) info.label = label;
90 });
91 await saveAddressesInBox();
92 }
93
94 Future<_LibAddresses> _libAddresses() async {
95 final nUsed = "10";
96 var nUnused = "1";
97 if (this.isEnabledAutoGenerateSubaddress) nUnused = "3";
98
99 try {
100 final res = await _libwallet.addresses(walletInfo.name, nUsed, nUnused);
101 final decoded = json.decode(res);
102 final usedAddrs = List<String>.from(decoded["used"] ?? []);
103 final unusedAddrs = List<String>.from(decoded["unused"] ?? []);
104 // index is the index of the first unused address.
105 final index = decoded["index"] ?? 0;
106 return _LibAddresses(usedAddrs, unusedAddrs, index);
107 } catch (e) {
108 printV(e);
109 return _LibAddresses([], [], 0);
110 }
111 }
112
113 Future<void> generateNewAddress(String label) async {
114 // NOTE: This will ignore the gap limit and may cause problems when restoring from seed if too
115 // many addresses are taken and not used.
116 final addr = await _libwallet.newExternalAddress(walletInfo.name) ?? '';
117 if (addr == "") return;
118
119 if (!addressesMap.containsKey(addr)) {
120 addressesMap[addr] = "";
121 addressInfos[0] ??= [];
122 addressInfos[0]?.add(
123 WalletInfoAddressInfo(
124 walletInfoId: walletInfo.internalId,
125 mapKey: 0,
126 address: addr,
127 label: label,
128 accountIndex: 0,
129 ),
130 );
131 }
132 selectedAddr = addr;
133 await saveAddressesInBox();
134 }
135
136 @override
137 List<ReceivePageOption> get receivePageOptions => isTestnet
138 ? [
139 ReceivePageOption.testnet,
140 ...ReceivePageOptions.where((element) => element != ReceivePageOption.mainnet)
141 ]
142 : ReceivePageOptions;
143
144 @override
145 PaymentURI getPaymentUri(String amount) => DecredURI(address: address, amount: amount);
146 }
147
148 class _LibAddresses {
149 final List<String> usedAddrs, unusedAddrs;
150 final int firstUnusedAddrIndex;
151
152 _LibAddresses(this.usedAddrs, this.unusedAddrs, this.firstUnusedAddrIndex);
153 }