diff --git a/fusiondart b/fusiondart index 04c8bd01b..fb563fb37 160000 --- a/fusiondart +++ b/fusiondart @@ -1 +1 @@ -Subproject commit 04c8bd01b1982d1543f3f0a2554361056eb7ef38 +Subproject commit fb563fb37b0867cd1ada29e0b956778836049ebe diff --git a/lib/services/mixins/fusion_wallet_interface.dart b/lib/services/mixins/fusion_wallet_interface.dart index 265ea8798..90bfa7c57 100644 --- a/lib/services/mixins/fusion_wallet_interface.dart +++ b/lib/services/mixins/fusion_wallet_interface.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -11,15 +12,20 @@ import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; +import 'package:stackwallet/services/tor_service.dart'; + const String kReservedFusionAddress = "reserved_fusion_address"; + +/// A mixin for the BitcoinCashWallet class that adds CashFusion functionality. mixin FusionWalletInterface { - // passed in wallet data + // Passed in wallet data. late final String _walletId; late final Coin _coin; late final MainDB _db; + late final TorService _torService; - // passed in wallet functions + // Passed in wallet functions. late final Future
Function( int chain, int index, @@ -40,13 +46,29 @@ mixin FusionWalletInterface { _coin = coin; _db = db; _generateAddressForChain = generateAddressForChain; + _torService = TorService.sharedInstance; + + // Start the Tor service if it's not already running. + if (_torService.proxyInfo.port == -1) { // -1 indicates that the proxy is not running. + // Initialize the ffi lib instance if it hasn't already been set. + _torService.init(); + + // Start the Tor service. + // + // TODO should we await this? At this point I don't want to make this init function async. + // The risk would be that the Tor service is not started before the Fusion library tries to + // connect to it. + unawaited(_torService.start()); + } } + /// Returns a list of all addresses in the wallet. Future> getFusionAddresses() async { List
_addresses = await _db.getAddresses(_walletId).findAll(); return _addresses.map((address) => address.toFusionAddress()).toList(); } + /// Returns a list of all transactions in the wallet for the given address. Future> getTransactionsByAddress( String address) async { var _txs = await _db.getTransactions(_walletId).findAll(); @@ -56,6 +78,7 @@ mixin FusionWalletInterface { .toSet(); // TODO feed in proper public key } + /// Returns a list of all UTXOs in the wallet for the given address. Future> getInputsByAddress(String address) async { var _utxos = await _db.getUTXOsByAddress(_walletId, address).findAll(); @@ -65,6 +88,7 @@ mixin FusionWalletInterface { .toList(); } + /// Creates a new reserved change address. Future createNewReservedChangeAddress() async { int? highestChangeIndex = await _db .getAddresses(_walletId) @@ -96,44 +120,78 @@ mixin FusionWalletInterface { return address.toFusionAddress(); } + /// Returns a list of unused reserved change addresses. + /// + /// If there are not enough unused reserved change addresses, new ones are created. Future> getUnusedReservedChangeAddresses( int numberOfAddresses, ) async { + // Fetch all transactions that have been sent to a reserved change address. final txns = await _db .getTransactions(_walletId) .filter() .address((q) => q.otherDataEqualTo(kReservedFusionAddress)) .findAll(); + // Fetch all addresses that have been used in a transaction. final List usedAddresses = txns .where((e) => e.address.value != null) .map((e) => e.address.value!.value) .toList(growable: false); + // Fetch all reserved change addresses. final List
addresses = await _db .getAddresses(_walletId) .filter() .otherDataEqualTo(kReservedFusionAddress) .findAll(); + // Initialize a list of unused reserved change addresses. final List unusedAddresses = []; + // Add any unused reserved change addresses to the list. for (final address in addresses) { if (!usedAddresses.contains(address.value)) { unusedAddresses.add(address.toFusionAddress()); } } + // If there are not enough unused reserved change addresses, create new ones. if (unusedAddresses.length < numberOfAddresses) { for (int i = unusedAddresses.length; i < numberOfAddresses; i++) { unusedAddresses.add(await createNewReservedChangeAddress()); } } + // Return the list of unused reserved change addresses. return unusedAddresses; } - void fuse() async { + /// Returns the current Tor proxy address. + Future<({InternetAddress host, int port})> getSocksProxyAddress() async { + /* + // Start the Tor service if it's not already running. + if (_torService.proxyInfo.port == -1) { // -1 indicates that the proxy is not running. + await _torService.start(); // We already unawaited this in initFusionInterface... + } + */ + + // TODO make sure we've properly awaited the Tor service starting before + // returning the proxy address. + + // Return the proxy address. + return _torService.proxyInfo; + } + + // Initial attempt for CashFusion integration goes here. + + /// Fuse the wallet's UTXOs. + /// + /// This function is called when the user taps the "Fuse" button in the UI. + /// + /// Returns: + /// A `Future` that resolves when the fusion operation is finished. + Future fuse() async { // Initial attempt for CashFusion integration goes here. Fusion mainFusionObject = Fusion( getAddresses: () => getFusionAddresses(), @@ -143,6 +201,7 @@ mixin FusionWalletInterface { // createNewReservedChangeAddress: () => createNewReservedChangeAddress(), getUnusedReservedChangeAddresses: (int numberOfAddresses) => getUnusedReservedChangeAddresses(numberOfAddresses), + getSocksProxyAddress: () => getSocksProxyAddress(), ); // Pass wallet functions to the Fusion object @@ -151,7 +210,8 @@ mixin FusionWalletInterface { getTransactionsByAddress: getTransactionsByAddress, getInputsByAddress: getInputsByAddress, /*createNewReservedChangeAddress: createNewReservedChangeAddress,*/ - getUnusedReservedChangeAddresses: getUnusedReservedChangeAddresses); + getUnusedReservedChangeAddresses: getUnusedReservedChangeAddresses, + getSocksProxyAddress: getSocksProxyAddress); // Add stack UTXOs. List utxos = await _db.getUTXOs(_walletId).findAll(); @@ -160,9 +220,11 @@ mixin FusionWalletInterface { utxos.map((e) => (e.txid, e.vout, e.value)).toList()); // Fuse UTXOs. - await mainFusionObject.fuse(); + return await mainFusionObject.fuse(); //print ("DEBUG FUSION bitcoincash_wallet.dart 1202"); + // TODO remove or fix code below. + /* print("DEBUG: Waiting for any potential incoming data..."); try { @@ -172,7 +234,6 @@ mixin FusionWalletInterface { print (e); } print("DEBUG: Done waiting."); - */ bool mydebug1 = false; if (mydebug1 == true) { @@ -258,6 +319,7 @@ mixin FusionWalletInterface { // await _checkCurrentChangeAddressesForTransactions(); // await _checkCurrentReceivingAddressesForTransactions(); + */ } Future refreshFusion() { diff --git a/lib/services/tor_service.dart b/lib/services/tor_service.dart index ead6ab5fa..1f6e2a8eb 100644 --- a/lib/services/tor_service.dart +++ b/lib/services/tor_service.dart @@ -25,6 +25,8 @@ class TorService { static final sharedInstance = TorService._(); /// Getter for the proxyInfo. + /// + /// Returns a Map with the host and port of the Tor proxy. ({ InternetAddress host, int port,