1
+import 'package:bitcoin_base/bitcoin_base.dart';
2
+import 'package:blockchain_utils/blockchain_utils.dart';
3
+import 'package:cw_bitcoin/bitcoin_address_record.dart';
4
+import 'package:cw_bitcoin/bitcoin_mnemonics_bip39.dart';
5
+import 'package:cw_bitcoin/electrum_balance.dart';
6
+import 'package:cw_bitcoin/electrum_wallet.dart';
7
+import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
8
+import 'package:cw_core/crypto_currency.dart';
9
+import 'package:cw_core/encryption_file_utils.dart';
10
+import 'package:cw_core/unspent_coins_info.dart';
11
+import 'package:cw_core/wallet_info.dart';
12
+import 'package:cw_core/wallet_keys_file.dart';
13
+import 'package:flutter/foundation.dart';
14
+import 'package:hive/hive.dart';
15
+import 'package:mobx/mobx.dart';
16
+
17
+import 'dogecoin_wallet_addresses.dart';
18
+
19
+part 'dogecoin_wallet.g.dart';
20
+
21
+class DogeCoinWallet = DogeCoinWalletBase with _$DogeCoinWallet;
22
+
23
+abstract class DogeCoinWalletBase extends ElectrumWallet with Store {
24
+ DogeCoinWalletBase({
25
+ required String mnemonic,
26
+ required String password,
27
+ required WalletInfo walletInfo,
28
+ required Box<UnspentCoinsInfo> unspentCoinsInfo,
29
+ required Uint8List seedBytes,
30
+ required EncryptionFileUtils encryptionFileUtils,
31
+ String? passphrase,
32
+ BitcoinAddressType? addressPageType,
33
+ List<BitcoinAddressRecord>? initialAddresses,
34
+ ElectrumBalance? initialBalance,
35
+ Map<String, int>? initialRegularAddressIndex,
36
+ Map<String, int>? initialChangeAddressIndex,
37
+ }) : super(
38
+ mnemonic: mnemonic,
39
+ password: password,
40
+ walletInfo: walletInfo,
41
+ unspentCoinsInfo: unspentCoinsInfo,
42
+ network: DogecoinNetwork.mainnet,
43
+ initialAddresses: initialAddresses,
44
+ initialBalance: initialBalance,
45
+ seedBytes: seedBytes,
46
+ currency: CryptoCurrency.doge,
47
+ encryptionFileUtils: encryptionFileUtils,
48
+ passphrase: passphrase) {
49
+ walletAddresses = DogeCoinWalletAddresses(
50
+ walletInfo,
51
+ initialAddresses: initialAddresses,
52
+ initialRegularAddressIndex: initialRegularAddressIndex,
53
+ initialChangeAddressIndex: initialChangeAddressIndex,
54
+ mainHd: hd,
55
+ sideHd: accountHD.childKey(Bip32KeyIndex(1)),
56
+ network: network,
57
+ initialAddressPageType: addressPageType,
58
+ isHardwareWallet: walletInfo.isHardwareWallet,
59
+ );
60
+ autorun((_) {
61
+ this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
62
+ });
63
+ }
64
+
65
+ @override
66
+ int get networkDustAmount => 100000000; // 1 DOGE = 1e8 koinu
67
+
68
+ static Future<DogeCoinWallet> create(
69
+ {required String mnemonic,
70
+ required String password,
71
+ required WalletInfo walletInfo,
72
+ required Box<UnspentCoinsInfo> unspentCoinsInfo,
73
+ required EncryptionFileUtils encryptionFileUtils,
74
+ String? passphrase,
75
+ String? addressPageType,
76
+ List<BitcoinAddressRecord>? initialAddresses,
77
+ ElectrumBalance? initialBalance,
78
+ Map<String, int>? initialRegularAddressIndex,
79
+ Map<String, int>? initialChangeAddressIndex}) async {
80
+ return DogeCoinWallet(
81
+ mnemonic: mnemonic,
82
+ password: password,
83
+ walletInfo: walletInfo,
84
+ unspentCoinsInfo: unspentCoinsInfo,
85
+ initialAddresses: initialAddresses,
86
+ initialBalance: initialBalance,
87
+ seedBytes: MnemonicBip39.toSeed(mnemonic, passphrase: passphrase),
88
+ encryptionFileUtils: encryptionFileUtils,
89
+ initialRegularAddressIndex: initialRegularAddressIndex,
90
+ initialChangeAddressIndex: initialChangeAddressIndex,
91
+ addressPageType: P2pkhAddressType.p2pkh,
92
+ passphrase: passphrase,
93
+ );
94
+ }
95
+
96
+ static Future<DogeCoinWallet> open({
97
+ required String name,
98
+ required WalletInfo walletInfo,
99
+ required Box<UnspentCoinsInfo> unspentCoinsInfo,
100
+ required String password,
101
+ required EncryptionFileUtils encryptionFileUtils,
102
+ }) async {
103
+ final hasKeysFile = await WalletKeysFile.hasKeysFile(name, walletInfo.type);
104
+
105
+ ElectrumWalletSnapshot? snp = null;
106
+
107
+ try {
108
+ snp = await ElectrumWalletSnapshot.load(
109
+ encryptionFileUtils,
110
+ name,
111
+ walletInfo.type,
112
+ password,
113
+ DogecoinNetwork.mainnet,
114
+ );
115
+ } catch (e) {
116
+ if (!hasKeysFile) rethrow;
117
+ }
118
+
119
+ final WalletKeysData keysData;
120
+ // Migrate wallet from the old scheme to then new .keys file scheme
121
+ if (!hasKeysFile) {
122
+ keysData =
123
+ WalletKeysData(mnemonic: snp!.mnemonic, xPub: snp.xpub, passphrase: snp.passphrase);
124
+ } else {
125
+ keysData = await WalletKeysFile.readKeysFile(
126
+ name,
127
+ walletInfo.type,
128
+ password,
129
+ encryptionFileUtils,
130
+ );
131
+ }
132
+
133
+ return DogeCoinWallet(
134
+ mnemonic: keysData.mnemonic!,
135
+ password: password,
136
+ walletInfo: walletInfo,
137
+ unspentCoinsInfo: unspentCoinsInfo,
138
+ initialAddresses: snp?.addresses,
139
+ initialBalance: snp?.balance,
140
+ seedBytes: await MnemonicBip39.toSeed(keysData.mnemonic!, passphrase: keysData.passphrase),
141
+ encryptionFileUtils: encryptionFileUtils,
142
+ initialRegularAddressIndex: snp?.regularAddressIndex,
143
+ initialChangeAddressIndex: snp?.changeAddressIndex,
144
+ addressPageType: P2pkhAddressType.p2pkh,
145
+ passphrase: keysData.passphrase,
146
+ );
147
+ }
148
+
149
+ @override
150
+ Future<String> signMessage(String message, {String? address = null}) async {
151
+ int? index;
152
+ try {
153
+ index = address != null
154
+ ? walletAddresses.allAddresses.firstWhere((element) => element.address == address).index
155
+ : null;
156
+ } catch (_) {}
157
+ final HD = index == null ? hd : hd.childKey(Bip32KeyIndex(index));
158
+ final priv = ECPrivate.fromWif(
159
+ WifEncoder.encode(HD.privateKey.raw, netVer: network.wifNetVer),
160
+ netVersion: network.wifNetVer,
161
+ );
162
+ return priv.signMessage(StringUtils.encode(message));
163
+ }
164
+}