From 7fbffc8dc9beb269fc116a1f7cc2361efbf04020 Mon Sep 17 00:00:00 2001 From: Konstantin Ullrich Date: Fri, 11 Apr 2025 11:06:15 +0200 Subject: [PATCH] fix(cw_tari): initial implementation --- cw_tari/.gitignore | 31 ++++ cw_tari/.metadata | 10 ++ cw_tari/CHANGELOG.md | 3 + cw_tari/README.md | 1 + cw_tari/analysis_options.yaml | 4 + cw_tari/lib/tari_balance.dart | 36 +++++ cw_tari/lib/tari_wallet.dart | 192 +++++++++++++++++++++++++ cw_tari/lib/tari_wallet_addresses.dart | 36 +++++ cw_tari/pubspec.yaml | 25 ++++ model_generator.sh | 2 +- 10 files changed, 339 insertions(+), 1 deletion(-) create mode 100644 cw_tari/.gitignore create mode 100644 cw_tari/.metadata create mode 100644 cw_tari/CHANGELOG.md create mode 100644 cw_tari/README.md create mode 100644 cw_tari/analysis_options.yaml create mode 100644 cw_tari/lib/tari_balance.dart create mode 100644 cw_tari/lib/tari_wallet.dart create mode 100644 cw_tari/lib/tari_wallet_addresses.dart create mode 100644 cw_tari/pubspec.yaml diff --git a/cw_tari/.gitignore b/cw_tari/.gitignore new file mode 100644 index 000000000..eb6c05cd3 --- /dev/null +++ b/cw_tari/.gitignore @@ -0,0 +1,31 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +build/ diff --git a/cw_tari/.metadata b/cw_tari/.metadata new file mode 100644 index 000000000..f5be3bc89 --- /dev/null +++ b/cw_tari/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "8495dee1fd4aacbe9de707e7581203232f591b2f" + channel: "stable" + +project_type: package diff --git a/cw_tari/CHANGELOG.md b/cw_tari/CHANGELOG.md new file mode 100644 index 000000000..41cc7d819 --- /dev/null +++ b/cw_tari/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/cw_tari/README.md b/cw_tari/README.md new file mode 100644 index 000000000..9330abeb2 --- /dev/null +++ b/cw_tari/README.md @@ -0,0 +1 @@ +# cw_tari diff --git a/cw_tari/analysis_options.yaml b/cw_tari/analysis_options.yaml new file mode 100644 index 000000000..a5744c1cf --- /dev/null +++ b/cw_tari/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/cw_tari/lib/tari_balance.dart b/cw_tari/lib/tari_balance.dart new file mode 100644 index 000000000..10879897b --- /dev/null +++ b/cw_tari/lib/tari_balance.dart @@ -0,0 +1,36 @@ +import 'package:cw_core/balance.dart'; +import 'package:cw_core/monero_amount_format.dart'; + +class TariBalance extends Balance { + TariBalance({required this.fullBalance, required this.unlockedBalance}) + : formattedUnconfirmedBalance = + moneroAmountToString(amount: fullBalance - unlockedBalance), + formattedUnlockedBalance = + moneroAmountToString(amount: unlockedBalance), + super(unlockedBalance, fullBalance); + + factory TariBalance.fromFfi((int, int, int, int) result) { + final availableBalance = result.$1; + final pendingIncoming = result.$2; + final pendingOutgoing = result.$3; + final timeLockedBalance = result.$4; + + return TariBalance( + fullBalance: availableBalance + + pendingIncoming + + pendingOutgoing + + timeLockedBalance, + unlockedBalance: availableBalance); + } + + final int fullBalance; + final int unlockedBalance; + final String formattedUnconfirmedBalance; + final String formattedUnlockedBalance; + + @override + String get formattedAvailableBalance => formattedUnlockedBalance; + + @override + String get formattedAdditionalBalance => formattedUnconfirmedBalance; +} diff --git a/cw_tari/lib/tari_wallet.dart b/cw_tari/lib/tari_wallet.dart new file mode 100644 index 000000000..1fbabb2c3 --- /dev/null +++ b/cw_tari/lib/tari_wallet.dart @@ -0,0 +1,192 @@ +import 'dart:async'; + +import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/node.dart'; +import 'package:cw_core/pending_transaction.dart'; +import 'package:cw_core/sync_status.dart'; +import 'package:cw_core/transaction_priority.dart'; +import 'package:cw_core/wallet_addresses.dart'; +import 'package:cw_core/wallet_base.dart'; +import 'package:cw_core/wallet_info.dart'; +import 'package:cw_core/wallet_keys_file.dart'; +import 'package:cw_tari/tari_balance.dart'; +import 'package:cw_tari/tari_wallet_addresses.dart'; +import 'package:mobx/mobx.dart'; +import 'package:tari/tari.dart'; + +part 'tari_wallet.g.dart'; + +abstract class TariWallet = TariWalletBase with _$TariWallet; + +abstract class TariWalletBase extends WalletBase< + TariBalance, + EVMChainTransactionHistory, + EVMChainTransactionInfo> with Store, WalletKeysFile { + TariWalletBase({ + required WalletInfo walletInfo, + required String password, + required TariWalletFfi walletFfi, + }) : syncStatus = const NotConnectedSyncStatus(), + walletAddresses = TariWalletAddresses(walletInfo), + _password = password, + _walletFfi = walletFfi, + balance = ObservableMap.of({ + CryptoCurrency.tari: TariBalance.fromFfi(walletFfi.getBalance()), + }), + super(walletInfo) { + this.walletInfo = walletInfo; + transactionHistory = + setUpTransactionHistory(walletInfo, password); + } + + final TariWalletFfi _walletFfi; + final String _password; + + @override + WalletAddresses walletAddresses; + + @override + @observable + SyncStatus syncStatus; + + @override + @observable + late ObservableMap balance; + + Future init() async { + await walletAddresses.init(); + await transactionHistory.init(); + + await save(); + } + + @override + int calculateEstimatedFee(TransactionPriority priority, int? amount) { + return 0; // ToDo + } + + @override + Future changePassword(String password) => + throw UnimplementedError("changePassword"); + + @override + Future close({bool shouldCleanup = false}) async { + _walletFfi.close(); + } + + @action + @override + Future connectToNode({required Node node}) async { + try { + syncStatus = ConnectingSyncStatus(); + + // ToDo + + syncStatus = ConnectedSyncStatus(); + } catch (e) { + syncStatus = FailedSyncStatus(); + } + } + + @action + @override + Future startSync() async { + try { + syncStatus = AttemptingSyncStatus(); + + // ToDo + + syncStatus = SyncedSyncStatus(); + } catch (e) { + syncStatus = FailedSyncStatus(); + } + } + + @override + Future createTransaction(Object credentials) async { + // ToDo + throw UnimplementedError(); + } + + + @override + Future> fetchTransactions() async { + // ToDo + throw UnimplementedError(); + } + + @override + Object get keys => throw UnimplementedError("keys"); + + @override + Future rescan({required int height}) { + throw UnimplementedError("rescan"); + } + + @override + Future save() async { + await walletAddresses.updateAddressesInBox(); + await transactionHistory.save(); + } + + @override + String? get seed => _walletFfi.getMnemonic(); + + @override + String? get privateKey => null; + + @override + WalletKeysData get walletKeysData => WalletKeysData( + mnemonic: seed, + privateKey: privateKey, + passphrase: passphrase, + ); + + @override + Future updateBalance() async { + balance[CryptoCurrency.tari] = TariBalance.fromFfi(_walletFfi.getBalance()); + } + + @override + Future renameWalletFiles(String newWalletName) async { + // final transactionHistoryFileNameForWallet = getTransactionHistoryFileName(); + // + // final currentWalletPath = + // await pathForWallet(name: walletInfo.name, type: type); + // final currentWalletFile = File(currentWalletPath); + // + // final currentDirPath = + // await pathForWalletDir(name: walletInfo.name, type: type); + // final currentTransactionsFile = + // File('$currentDirPath/$transactionHistoryFileNameForWallet'); + // + // // 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); + // } + // if (currentTransactionsFile.existsSync()) { + // final newDirPath = + // await pathForWalletDir(name: newWalletName, type: type); + // await currentTransactionsFile + // .copy('$newDirPath/$transactionHistoryFileNameForWallet'); + // } + // + // // Delete old name's dir and files + // await Directory(currentDirPath).delete(recursive: true); + } + + @override + Future signMessage(String message, {String? address}) async => + _walletFfi.signMessage(message); + + @override + Future verifyMessage(String message, String signature, + {String? address}) async { + throw UnimplementedError(); + } + + @override + String get password => _password; +} diff --git a/cw_tari/lib/tari_wallet_addresses.dart b/cw_tari/lib/tari_wallet_addresses.dart new file mode 100644 index 000000000..07bedbaa2 --- /dev/null +++ b/cw_tari/lib/tari_wallet_addresses.dart @@ -0,0 +1,36 @@ +import 'dart:developer'; + +import 'package:cw_core/wallet_addresses.dart'; +import 'package:mobx/mobx.dart'; + +part 'tari_addresses.g.dart'; + +class TariWalletAddresses = TariWalletAddressesBase with _$TariWalletAddresses; + +abstract class TariWalletAddressesBase extends WalletAddresses with Store { + TariWalletAddressesBase(super.walletInfo) : address = ''; + + @override + @observable + String address; + + @override + String get primaryAddress => address; + + @override + Future init() async { + address = walletInfo.address; + await updateAddressesInBox(); + } + + @override + Future updateAddressesInBox() async { + try { + addressesMap.clear(); + addressesMap[address] = ''; + await saveAddressesInBox(); + } catch (e) { + log(e.toString()); + } + } +} diff --git a/cw_tari/pubspec.yaml b/cw_tari/pubspec.yaml new file mode 100644 index 000000000..6b87b2250 --- /dev/null +++ b/cw_tari/pubspec.yaml @@ -0,0 +1,25 @@ +name: cw_tari +description: "A CakeWallet Package for Tari" +version: 0.0.0 +publish_to: none + +environment: + sdk: ^3.6.0 + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + cw_core: + path: ../cw_core + hive: ^2.2.3 + mobx: ^2.0.7+4 + tari: + path: ../../tari/clients/dart/ + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^5.0.0 + +flutter: diff --git a/model_generator.sh b/model_generator.sh index 7a5e3bfd7..be63648e9 100755 --- a/model_generator.sh +++ b/model_generator.sh @@ -1,7 +1,7 @@ #!/bin/bash set -x -e -for cwcoin in cw_{core,evm,monero,bitcoin,nano,bitcoin_cash,solana,tron,wownero,zano,decred} +for cwcoin in cw_{core,evm,monero,bitcoin,nano,bitcoin_cash,solana,tron,wownero,zano,decred,tari} do if [[ "x$1" == "xasync" ]]; then