dev
dart 266 lines 8.93 KB
Raw
1 import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 import 'package:cake_wallet/core/execution_state.dart';
3 import 'package:cake_wallet/core/wallet_creation_service.dart';
4 import 'package:cake_wallet/di.dart';
5 import 'package:cw_core/generate_name.dart';
6 import 'package:cake_wallet/entities/hash_wallet_identifier.dart';
7 import 'package:cake_wallet/generated/i18n.dart';
8 import 'package:cake_wallet/nano/nano.dart';
9 import 'package:cake_wallet/store/app_store.dart';
10 import 'package:cake_wallet/store/settings_store.dart';
11 import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
12 import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
13 import 'package:cw_core/exceptions.dart';
14 import 'package:cw_core/pathForWallet.dart';
15 import 'package:cw_core/utils/print_verbose.dart';
16 import 'package:cw_core/wallet_base.dart';
17 import 'package:cw_core/wallet_credentials.dart';
18 import 'package:cw_core/wallet_info.dart';
19 import 'package:cw_core/wallet_type.dart';
20 import 'package:cake_wallet/zcash/zcash_network_type.dart';
21 import 'package:mobx/mobx.dart';
22 import 'package:polyseed/polyseed.dart';
23
24 part 'wallet_creation_vm.g.dart';
25
26 class WalletCreationVM = WalletCreationVMBase with _$WalletCreationVM;
27
28 abstract class WalletCreationVMBase with Store {
29 WalletCreationVMBase(this._appStore, this.walletCreationService, this.seedSettingsViewModel,
30 {required this.type, required this.isRecovery})
31 : state = InitialExecutionState(),
32 name = '';
33
34 @observable
35 bool _useTestnet = false;
36
37 int _zcashNetwork = ZcashNetworkType.mainnet;
38
39 @computed
40 bool get useTestnet => _useTestnet;
41
42 int get zcashNetwork => _zcashNetwork;
43
44 @observable
45 String name;
46
47 @observable
48 ExecutionState state;
49
50 @observable
51 String? walletPassword;
52
53 @observable
54 String? repeatedWalletPassword;
55 bool get hasWalletPassword => SettingsStoreBase.walletPasswordDirectInput;
56
57 WalletType type;
58 final bool isRecovery;
59 final WalletCreationService walletCreationService;
60 final AppStore _appStore;
61 final SeedSettingsViewModel seedSettingsViewModel;
62
63 bool isPolyseed(String seed) =>
64 [WalletType.monero, WalletType.wownero].contains(type) &&
65 (Polyseed.isValidSeed(seed) || (seed.split(" ").length == 14));
66
67 Future<bool> nameExists(String name) => walletCreationService.exists(name);
68
69 Future<bool> typeExists(WalletType type) => walletCreationService.typeExists(type);
70
71 bool _isCreating = false;
72 Future<void> create({dynamic options}) async {
73 try {
74 if (_isCreating) {
75 printV("not creating because we don't feel like doing so");
76 return;
77 }
78 _isCreating = true;
79 await _create(options: options);
80 } finally {
81 _isCreating = false;
82 }
83 }
84
85 Future<void> _create({dynamic options}) async {
86 final type = this.type;
87 try {
88 state = IsExecutingState();
89 if (name.isEmpty) {
90 name = await generateName();
91 }
92
93 if (hasWalletPassword && (walletPassword?.isEmpty ?? true)) {
94 throw Exception(S.current.wallet_password_is_empty);
95 }
96
97 if (hasWalletPassword && walletPassword != repeatedWalletPassword) {
98 throw Exception(S.current.repeated_password_is_incorrect);
99 }
100
101 await walletCreationService.checkIfExists(name);
102 final dirPath = await pathForWalletDir(name: name, type: type);
103 final path = await pathForWallet(name: name, type: type);
104
105 final credentials = getCredentials(options);
106
107 final di = ((credentials.derivationInfo?.derivationPath ?? "") == "")
108 ? getDefaultCreateDerivation()
109 : credentials.derivationInfo;
110
111 final diId = await di!.save();
112 credentials.derivationInfo = di;
113
114 credentials.walletInfo = WalletInfo.external(
115 id: WalletBase.idFor(name, type),
116 name: name,
117 type: type,
118 isRecovery: isRecovery,
119 restoreHeight: credentials.height ?? 0,
120 date: DateTime.now(),
121 path: path,
122 dirPath: dirPath,
123 address: '',
124 showIntroCakePayCard:
125 (!await walletCreationService.typeExists(type)) && type != WalletType.haven,
126 derivationInfoId: diId,
127 hardwareWalletType: credentials.hardwareWalletType,
128 );
129
130 printV("derivationInfo: ${(await credentials.walletInfo!.getDerivationInfo()).toJson()}");
131 final wallet = await process(credentials);
132
133 final isNonSeedWallet = isRecovery ? wallet.seed == null : false;
134 credentials.walletInfo!.isNonSeedWallet = isNonSeedWallet;
135 credentials.walletInfo!.hashedWalletIdentifier = createHashedWalletIdentifier(wallet);
136 credentials.walletInfo!.address = wallet.walletAddresses.address;
137 await credentials.walletInfo!.save();
138 await wallet.save();
139 await _appStore.changeCurrentWallet(wallet);
140 _appStore.authenticationStore.allowedCreate();
141 state = ExecutedSuccessfullyState();
142 } catch (e, s) {
143 printV("error: $e");
144 printV("stack: $s");
145 String message = e.toString();
146 if (e is RestoreFromSeedException) {
147 message = e.message;
148 }
149 state = FailureState(message);
150 }
151 }
152
153 DerivationInfo getDefaultCreateDerivation() {
154 final useBip39ForBitcoin = seedSettingsViewModel.bitcoinSeedType.type == DerivationType.bip39;
155 final useBip39ForNano = seedSettingsViewModel.nanoSeedType.type == DerivationType.bip39;
156 switch (type) {
157 case WalletType.nano:
158 if (useBip39ForNano) {
159 return DerivationInfo(derivationType: DerivationType.bip39);
160 }
161 return DerivationInfo(derivationType: DerivationType.nano);
162 case WalletType.bitcoin:
163 if (useBip39ForBitcoin) {
164 return DerivationInfo(
165 derivationType: DerivationType.bip39,
166 derivationPath: "m/84'/0'/0'",
167 description: "Standard BIP84 native segwit",
168 scriptType: "p2wpkh",
169 );
170 }
171 return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
172 case WalletType.litecoin:
173 if (useBip39ForBitcoin) {
174 return DerivationInfo(
175 derivationType: DerivationType.bip39,
176 derivationPath: "m/84'/2'/0'",
177 description: "Default Litecoin",
178 scriptType: "p2wpkh",
179 );
180 }
181 return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
182 case WalletType.decred:
183 return DerivationInfo(derivationType: DerivationType.bip39);
184 default:
185 return DerivationInfo(derivationType: DerivationType.unknown);
186 }
187 }
188
189 DerivationInfo? getCommonRestoreDerivation() {
190 final useElectrum = seedSettingsViewModel.bitcoinSeedType.type == DerivationType.electrum;
191 final useNanoStandard = seedSettingsViewModel.nanoSeedType.type == DerivationType.nano;
192 switch (this.type) {
193 case WalletType.nano:
194 if (useNanoStandard) {
195 return DerivationInfo(derivationType: DerivationType.nano);
196 }
197 return DerivationInfo(derivationType: DerivationType.bip39);
198 case WalletType.bitcoin:
199 if (useElectrum) {
200 return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
201 }
202 return DerivationInfo(
203 derivationType: DerivationType.bip39,
204 derivationPath: "m/84'/0'/0'/0",
205 description: "Standard BIP84 native segwit",
206 scriptType: "p2wpkh",
207 );
208 case WalletType.litecoin:
209 if (useElectrum) {
210 return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
211 }
212 return DerivationInfo(
213 derivationType: DerivationType.bip39,
214 derivationPath: "m/84'/2'/0'/0",
215 description: "Standard BIP84 native segwit (litecoin)",
216 scriptType: "p2wpkh",
217 );
218 default:
219 return null;
220 }
221 }
222
223 Future<List<DerivationInfo>> getDerivationInfoFromQRCredentials(
224 RestoredWallet restoreWallet) async {
225 var list = <DerivationInfo>[];
226 final walletType = restoreWallet.type;
227 var appStore = getIt.get<AppStore>();
228 var node = appStore.settingsStore.getCurrentNode(walletType);
229
230 switch (walletType) {
231 case WalletType.bitcoin:
232 case WalletType.litecoin:
233 final derivationList = await bitcoin!.getDerivationsFromMnemonic(
234 mnemonic: restoreWallet.mnemonicSeed!,
235 node: node,
236 passphrase: restoreWallet.passphrase,
237 );
238
239 if (derivationList.firstOrNull?.transactionsCount == 0 && derivationList.length > 1)
240 return [];
241 return derivationList;
242
243 case WalletType.nano:
244 return nanoUtil!.getDerivationsFromMnemonic(
245 mnemonic: restoreWallet.mnemonicSeed!,
246 node: node,
247 );
248 default:
249 break;
250 }
251 return list;
252 }
253
254 WalletCredentials getCredentials(dynamic options) => throw UnimplementedError();
255
256 Future<WalletBase> process(WalletCredentials credentials) => throw UnimplementedError();
257
258 @action
259 void toggleUseTestnet(bool? value) {
260 _useTestnet = value ?? !_useTestnet;
261 }
262
263 void setZcashNetwork(int network) {
264 _zcashNetwork = network;
265 }
266 }