diff --git a/.gitmodules b/.gitmodules index 7474c8a54..95b02e580 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,4 +6,4 @@ url = https://github.com/cypherstack/flutter_libmonero.git [submodule "crypto_plugins/flutter_liblelantus"] path = crypto_plugins/flutter_liblelantus - url = https://github.com/cypherstack/flutter_liblelantus.git + url = https://github.com/cypherstack/flutter_liblelantus.git \ No newline at end of file diff --git a/lib/electrumx_rpc/cached_electrumx_client.dart b/lib/electrumx_rpc/cached_electrumx_client.dart index 021bdf065..a92203cc4 100644 --- a/lib/electrumx_rpc/cached_electrumx_client.dart +++ b/lib/electrumx_rpc/cached_electrumx_client.dart @@ -11,6 +11,7 @@ import 'dart:convert'; import 'dart:math'; +import 'package:electrum_adapter/electrum_adapter.dart' as electrum_adapter; import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/electrumx_rpc/electrumx_client.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; @@ -188,8 +189,11 @@ class CachedElectrumXClient { final cachedTx = box.get(txHash) as Map?; if (cachedTx == null) { - final Map result = await electrumXClient - .getTransaction(txHash: txHash, verbose: verbose); + var channel = await electrum_adapter.connect(electrumXClient.host, + port: electrumXClient.port); // TODO pass useSLL. + var client = electrum_adapter.ElectrumClient( + channel, electrumXClient.host, electrumXClient.port); + final Map result = await client.getTransaction(txHash); result.remove("hex"); result.remove("lelantusData"); diff --git a/lib/electrumx_rpc/electrumx_client.dart b/lib/electrumx_rpc/electrumx_client.dart index 931c9334f..dcbc47568 100644 --- a/lib/electrumx_rpc/electrumx_client.dart +++ b/lib/electrumx_rpc/electrumx_client.dart @@ -14,6 +14,8 @@ import 'dart:io'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:decimal/decimal.dart'; +import 'package:electrum_adapter/electrum_adapter.dart' as electrum_adapter; +import 'package:electrum_adapter/methods/specific/firo.dart'; import 'package:event_bus/event_bus.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_libsparkmobile/flutter_libsparkmobile.dart'; @@ -741,41 +743,20 @@ class ElectrumXClient { bool verbose = true, String? requestID, }) async { - dynamic response; - try { - response = await request( - requestID: requestID, - command: 'blockchain.transaction.get', - args: [ - txHash, - verbose, - ], - ); - if (!verbose) { - return {"rawtx": response["result"] as String}; - } + Logging.instance.log("attempting to fetch blockchain.transaction.get...", + level: LogLevel.Info); + var channel = + await electrum_adapter.connect(host, port: port); // TODO pass useSLL. + var client = electrum_adapter.ElectrumClient(channel, host, port); + dynamic response = await client.getTransaction(txHash); + Logging.instance.log("Fetching blockchain.transaction.get finished", + level: LogLevel.Info); - if (response is! Map) { - final String msg = "getTransaction($txHash) returned a non-Map response" - " of type ${response.runtimeType}.\nResponse: $response"; - Logging.instance.log(msg, level: LogLevel.Fatal); - throw Exception(msg); - } - - if (response["result"] == null) { - final String msg = "getTransaction($txHash) returned null result." - "\nResponse: $response"; - Logging.instance.log(msg, level: LogLevel.Fatal); - throw Exception(msg); - } - return Map.from(response["result"] as Map); - } catch (e, s) { - Logging.instance.log( - "getTransaction($txHash) response: $response" - "\nError: $e\nStack trace: $s", - level: LogLevel.Error); - rethrow; + if (!verbose) { + return {"rawtx": response as String}; } + + return Map.from(response as Map); } /// Returns the whole Lelantus anonymity set for denomination in the groupId. @@ -797,23 +778,15 @@ class ElectrumXClient { String blockhash = "", String? requestID, }) async { - try { - Logging.instance.log("attempting to fetch lelantus.getanonymityset...", - level: LogLevel.Info); - final response = await request( - requestID: requestID, - command: 'lelantus.getanonymityset', - args: [ - groupId, - blockhash, - ], - ); - Logging.instance.log("Fetching lelantus.getanonymityset finished", - level: LogLevel.Info); - return Map.from(response["result"] as Map); - } catch (e) { - rethrow; - } + Logging.instance.log("attempting to fetch lelantus.getanonymityset...", + level: LogLevel.Info); + var channel = await electrum_adapter.connect(host, port: port); + var client = electrum_adapter.FiroElectrumClient(channel); + Map anonymitySet = await client.getLelantusAnonymitySet( + groupId: groupId, blockHash: blockhash); + Logging.instance.log("Fetching lelantus.getanonymityset finished", + level: LogLevel.Info); + return anonymitySet; } //TODO add example to docs @@ -824,18 +797,14 @@ class ElectrumXClient { dynamic mints, String? requestID, }) async { - try { - final response = await request( - requestID: requestID, - command: 'lelantus.getmintmetadata', - args: [ - mints, - ], - ); - return response["result"]; - } catch (e) { - rethrow; - } + Logging.instance.log("attempting to fetch lelantus.getmintmetadata...", + level: LogLevel.Info); + var channel = await electrum_adapter.connect(host, port: port); + var client = electrum_adapter.FiroElectrumClient(channel); + dynamic mintData = await client.getLelantusMintData(mints: mints); + Logging.instance.log("Fetching lelantus.getmintmetadata finished", + level: LogLevel.Info); + return mintData; } //TODO add example to docs @@ -844,45 +813,39 @@ class ElectrumXClient { String? requestID, required int startNumber, }) async { - try { - int retryCount = 3; - dynamic result; + Logging.instance.log("attempting to fetch lelantus.getusedcoinserials...", + level: LogLevel.Info); + var channel = await electrum_adapter.connect('firo.stackwallet.com'); + var client = electrum_adapter.FiroElectrumClient(channel); - while (retryCount > 0 && result is! List) { - final response = await request( - requestID: requestID, - command: 'lelantus.getusedcoinserials', - args: [ - "$startNumber", - ], - requestTimeout: const Duration(minutes: 2), - ); + int retryCount = 3; + dynamic usedCoinSerials; - result = response["result"]; - retryCount--; - } + while (retryCount > 0 && usedCoinSerials is! List) { + usedCoinSerials = + await client.getLelantusUsedCoinSerials(startNumber: startNumber); + // TODO add 2 minute timeout. + Logging.instance.log("Fetching lelantus.getusedcoinserials finished", + level: LogLevel.Info); - return Map.from(result as Map); - } catch (e) { - Logging.instance.log(e, level: LogLevel.Error); - rethrow; + retryCount--; } + + return Map.from(usedCoinSerials as Map); } /// Returns the latest Lelantus set id /// /// ex: 1 Future getLelantusLatestCoinId({String? requestID}) async { - try { - final response = await request( - requestID: requestID, - command: 'lelantus.getlatestcoinid', - ); - return response["result"] as int; - } catch (e) { - Logging.instance.log(e, level: LogLevel.Error); - rethrow; - } + Logging.instance.log("attempting to fetch lelantus.getlatestcoinid...", + level: LogLevel.Info); + var channel = await electrum_adapter.connect('firo.stackwallet.com'); + var client = electrum_adapter.FiroElectrumClient(channel); + int latestCoinId = await client.getLatestCoinId(); + Logging.instance.log("Fetching lelantus.getlatestcoinid finished", + level: LogLevel.Info); + return latestCoinId; } // ============== Spark ====================================================== @@ -908,17 +871,13 @@ class ElectrumXClient { try { Logging.instance.log("attempting to fetch spark.getsparkanonymityset...", level: LogLevel.Info); - final response = await request( - requestID: requestID, - command: 'spark.getsparkanonymityset', - args: [ - coinGroupId, - startBlockHash, - ], - ); + var channel = await electrum_adapter.connect('firo.stackwallet.com'); + var client = electrum_adapter.FiroElectrumClient(channel); + Map anonymitySet = await client.getSparkAnonymitySet( + coinGroupId: coinGroupId, startBlockHash: startBlockHash); Logging.instance.log("Fetching spark.getsparkanonymityset finished", level: LogLevel.Info); - return Map.from(response["result"] as Map); + return anonymitySet; } catch (e) { rethrow; } @@ -931,15 +890,17 @@ class ElectrumXClient { required int startNumber, }) async { try { - final response = await request( - requestID: requestID, - command: 'spark.getusedcoinstags', - args: [ - "$startNumber", - ], - requestTimeout: const Duration(minutes: 2), - ); - final map = Map.from(response["result"] as Map); + // Use electrum_adapter package's getSparkUsedCoinsTags method. + Logging.instance.log("attempting to fetch spark.getusedcoinstags...", + level: LogLevel.Info); + var channel = await electrum_adapter.connect('firo.stackwallet.com'); + var client = electrum_adapter.FiroElectrumClient(channel); + Map usedCoinsTags = + await client.getUsedCoinsTags(startNumber: startNumber); + // TODO: Add 2 minute timeout. + Logging.instance.log("Fetching spark.getusedcoinstags finished", + level: LogLevel.Info); + final map = Map.from(usedCoinsTags); final set = Set.from(map["tags"] as List); return await compute(_ffiHashTagsComputeWrapper, set); } catch (e) { @@ -963,16 +924,15 @@ class ElectrumXClient { required List sparkCoinHashes, }) async { try { - final response = await request( - requestID: requestID, - command: 'spark.getsparkmintmetadata', - args: [ - { - "coinHashes": sparkCoinHashes, - }, - ], - ); - return List>.from(response["result"] as List); + Logging.instance.log("attempting to fetch spark.getsparkmintmetadata...", + level: LogLevel.Info); + var channel = await electrum_adapter.connect('firo.stackwallet.com'); + var client = electrum_adapter.FiroElectrumClient(channel); + List mintMetaData = + await client.getSparkMintMetaData(sparkCoinHashes: sparkCoinHashes); + Logging.instance.log("Fetching spark.getsparkmintmetadata finished", + level: LogLevel.Info); + return List>.from(mintMetaData); } catch (e) { Logging.instance.log(e, level: LogLevel.Error); rethrow; @@ -986,11 +946,14 @@ class ElectrumXClient { String? requestID, }) async { try { - final response = await request( - requestID: requestID, - command: 'spark.getsparklatestcoinid', - ); - return response["result"] as int; + Logging.instance.log("attempting to fetch spark.getsparklatestcoinid...", + level: LogLevel.Info); + var channel = await electrum_adapter.connect(host, port: port); + var client = electrum_adapter.FiroElectrumClient(channel); + int latestCoinId = await client.getSparkLatestCoinId(); + Logging.instance.log("Fetching spark.getsparklatestcoinid finished", + level: LogLevel.Info); + return latestCoinId; } catch (e) { Logging.instance.log(e, level: LogLevel.Error); rethrow; @@ -1007,15 +970,9 @@ class ElectrumXClient { /// "rate": 1000, /// } Future> getFeeRate({String? requestID}) async { - try { - final response = await request( - requestID: requestID, - command: 'blockchain.getfeerate', - ); - return Map.from(response["result"] as Map); - } catch (e) { - rethrow; - } + var channel = await electrum_adapter.connect(host, port: port); + var client = electrum_adapter.FiroElectrumClient(channel); + return await client.getFeeRate(); } /// Return the estimated transaction fee per kilobyte for a transaction to be confirmed within a certain number of [blocks]. diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart index 676cb87fe..d7346d328 100644 --- a/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart +++ b/lib/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart @@ -1250,6 +1250,8 @@ mixin ElectrumXInterface on Bip39HDWallet { coin: cryptoCurrency.coin, ); + print("txn: $txn"); + final vout = jsonUTXO["tx_pos"] as int; final outputs = txn["vout"] as List; diff --git a/pubspec.lock b/pubspec.lock index 840efc472..b87faa62d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -524,6 +524,15 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + electrum_adapter: + dependency: "direct main" + description: + path: "." + ref: dd443e293feb3b37eb494ab7c8dadef9205de14c + resolved-ref: dd443e293feb3b37eb494ab7c8dadef9205de14c + url: "https://github.com/cypherstack/electrum_adapter.git" + source: git + version: "3.0.0" emojis: dependency: "direct main" description: @@ -674,10 +683,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "3.0.1" flutter_local_notifications: dependency: "direct main" description: @@ -1038,10 +1047,10 @@ packages: dependency: transitive description: name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "3.0.0" local_auth: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index df60947c5..1534b95a8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -173,6 +173,10 @@ dependencies: url: https://github.com/cypherstack/coinlib.git path: coinlib_flutter ref: 376d520b4516d4eb7c3f0bd4b1522f7769f3f2a7 + electrum_adapter: + git: + url: https://github.com/cypherstack/electrum_adapter.git + ref: dd443e293feb3b37eb494ab7c8dadef9205de14c dev_dependencies: flutter_test: @@ -189,7 +193,7 @@ dev_dependencies: # lint: ^1.10.0 analyzer: ^5.13.0 import_sorter: ^4.6.0 - flutter_lints: ^2.0.1 + flutter_lints: ^3.0.1 isar_generator: 3.0.5 flutter_launcher_icons: