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