import 'package:cw_decred/transaction_history.dart'; import 'package:cw_decred/wallet_addresses.dart'; import 'package:cw_decred/transaction_priority.dart'; import 'package:cw_decred/api/dcrlibwallet.dart'; import 'package:cw_decred/balance.dart'; import 'package:cw_decred/transaction_info.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:mobx/mobx.dart'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/pending_transaction.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/sync_status.dart'; import 'package:cw_core/node.dart'; import 'package:cw_core/unspent_transaction_output.dart'; part 'wallet.g.dart'; class DecredWallet = DecredWalletBase with _$DecredWallet; abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransactionHistory, DecredTransactionInfo> with Store { DecredWalletBase(SPVWallet spv, WalletInfo walletInfo) : this.spv = spv, balance = ObservableMap<CryptoCurrency, DecredBalance>.of( {CryptoCurrency.dcr: spv.balance()}), syncStatus = NotConnectedSyncStatus(), super(walletInfo) { transactionHistory = DecredTransactionHistory(); walletAddresses = DecredWalletAddresses(walletInfo, spv); } final SPVWallet spv; static Future<DecredWallet> create( {required String mnemonic, required String password, required WalletInfo walletInfo}) async { final seed = mnemonicToSeedBytes(mnemonic); final spv = SPVWallet().create(seed, password, walletInfo); final wallet = DecredWallet(spv, walletInfo); return wallet; } static Future<DecredWallet> open( {required String password, required String name, required WalletInfo walletInfo}) async { final spv = SPVWallet().load(name, password, walletInfo); final wallet = DecredWallet(spv, walletInfo); return wallet; } // TODO: Set up a way to change the balance and sync status when dcrlibwallet // changes. Long polling probably? @override @observable late ObservableMap<CryptoCurrency, DecredBalance> balance; @override @observable SyncStatus syncStatus; // @override // set syncStatus(SyncStatus status); @override String? get seed { // throw UnimplementedError(); return ""; } // @override // String? get privateKey => null; @override Object get keys { // throw UnimplementedError(); return {}; } @override late DecredWalletAddresses walletAddresses; // @override // set isEnabledAutoGenerateSubaddress(bool value) {} // @override // bool get isEnabledAutoGenerateSubaddress => false; @override Future<void> connectToNode({required Node node}) async { //throw UnimplementedError(); } @action @override Future<void> startSync() async { try { this.spv.startSync(); syncStatus = this.spv.syncStatus(); } catch (e, stacktrace) { print(stacktrace); print(e.toString()); syncStatus = FailedSyncStatus(); } } @override Future<PendingTransaction> createTransaction(Object credentials) async { return this.spv.createTransaction(credentials); } int feeRate(TransactionPriority priority) { try { return this.spv.feeRate(priority.raw); } catch (_) { return 0; } } @override int calculateEstimatedFee(TransactionPriority priority, int? amount) { if (priority is DecredTransactionPriority) { return this.spv.calculateEstimatedFeeWithFeeRate( this.spv.feeRate(priority.raw), amount ?? 0); } return 0; } @override Future<Map<String, DecredTransactionInfo>> fetchTransactions() async { return this.spv.transactions(); } @override Future<void> save() async {} @override Future<void> rescan({required int height}) async { return spv.rescan(height); } @override void close() { this.spv.close(); } @override Future<void> changePassword(String password) async { return this.spv.changePassword(password); } @override String get password { // throw UnimplementedError(); return ""; } @override Future<void>? updateBalance() async { balance[CryptoCurrency.dcr] = this.spv.balance(); } @override void setExceptionHandler(void Function(FlutterErrorDetails) onError) => onError; Future<void> renameWalletFiles(String newWalletName) async { final currentWalletPath = await pathForWallet(name: walletInfo.name, type: type); final currentWalletFile = File(currentWalletPath); final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type); // TODO: Stop the wallet, wait, and restart after. // Copies current wallet files into new wallet name's dir and files if (currentWalletFile.existsSync()) { final newWalletPath = await pathForWallet(name: newWalletName, type: type); await currentWalletFile.copy(newWalletPath); } // Delete old name's dir and files await Directory(currentDirPath).delete(recursive: true); } @override String signMessage(String message, {String? address = null}) { return this.spv.signMessage(message, address); } List<Unspent> unspents() { return this.spv.unspents(); } @override Future<bool> verifyMessage(String message, String signature, {String? address = null}) { return true; } @override String get password { return ""; } }