From 2edfe0f3cc4a1940b4314a582124e75636ca4e9e Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Tue, 28 Jan 2025 02:11:58 -0800 Subject: [PATCH 01/50] xelis boiler plate early setup --- .gitignore | 1 + .gitmodules | 3 +++ crypto_plugins/xelis_flutter | 1 + lib/models/isar/models/blockchain_data/address.dart | 5 ++++- lib/wallets/isar/models/wallet_info.dart | 1 + lib/wallets/isar/models/wallet_info.g.dart | 2 ++ scripts/android/build_all.sh | 1 + scripts/android/build_all_campfire.sh | 1 + scripts/android/build_all_duo.sh | 1 + scripts/ios/build_all.sh | 1 + scripts/ios/build_all_campfire.sh | 1 + scripts/ios/build_all_duo.sh | 1 + scripts/linux/build_all.sh | 1 + scripts/linux/build_all_campfire.sh | 1 + scripts/linux/build_all_duo.sh | 1 + scripts/macos/build_all.sh | 1 + scripts/macos/build_all_campfire.sh | 1 + scripts/macos/build_all_duo.sh | 1 + scripts/windows/build_all.sh | 1 + scripts/windows/build_all_campfire.sh | 1 + scripts/windows/build_all_duo.sh | 1 + scripts/windows/build_secp256k1.bat | 4 ++-- 22 files changed, 29 insertions(+), 3 deletions(-) create mode 160000 crypto_plugins/xelis_flutter diff --git a/.gitignore b/.gitignore index 3d212c730..9b2706bb0 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,7 @@ libepic_cash_wallet.dll libmobileliblelantus.dll libtor_ffi.dll flutter_libsparkmobile.dll +xelis_flutter.dll secp256k1.dll /libisar.so /lib/app_config.g.dart diff --git a/.gitmodules b/.gitmodules index 2186826df..2f76b7ffa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "crypto_plugins/frostdart"] path = crypto_plugins/frostdart url = https://github.com/cypherstack/frostdart +[submodule "crypto_plugins/xelis_flutter"] + path = crypto_plugins/xelis_flutter + url = https://github.com/Tritonn204/xelis_flutter_ffi.git diff --git a/crypto_plugins/xelis_flutter b/crypto_plugins/xelis_flutter new file mode 160000 index 000000000..294bdf87e --- /dev/null +++ b/crypto_plugins/xelis_flutter @@ -0,0 +1 @@ +Subproject commit 294bdf87e5f5350ecc15b2066b77a91c9ef0568d diff --git a/lib/models/isar/models/blockchain_data/address.dart b/lib/models/isar/models/blockchain_data/address.dart index 584636050..0d8d48791 100644 --- a/lib/models/isar/models/blockchain_data/address.dart +++ b/lib/models/isar/models/blockchain_data/address.dart @@ -175,7 +175,8 @@ enum AddressType { frostMS, p2tr, solana, - cardanoShelley; + cardanoShelley + xelis; String get readableName { switch (this) { @@ -213,6 +214,8 @@ enum AddressType { return "P2TR (taproot)"; case AddressType.cardanoShelley: return "Cardano Shelley"; + case AddressType.xelis: + return "Xelis"; } } } diff --git a/lib/wallets/isar/models/wallet_info.dart b/lib/wallets/isar/models/wallet_info.dart index 51aa69a45..779f1dd78 100644 --- a/lib/wallets/isar/models/wallet_info.dart +++ b/lib/wallets/isar/models/wallet_info.dart @@ -517,6 +517,7 @@ abstract class WalletInfoKeys { static const String epiccashData = "epiccashDataKey"; static const String bananoMonkeyImageBytes = "monkeyImageBytesKey"; static const String tezosDerivationPath = "tezosDerivationPathKey"; + static const String xelisDerivationPath = "xelisDerivationPathKey"; static const String lelantusCoinIsarRescanRequired = "lelantusCoinIsarRescanRequired"; static const String enableLelantusScanning = "enableLelantusScanningKey"; diff --git a/lib/wallets/isar/models/wallet_info.g.dart b/lib/wallets/isar/models/wallet_info.g.dart index 6e02fd6d5..39506f199 100644 --- a/lib/wallets/isar/models/wallet_info.g.dart +++ b/lib/wallets/isar/models/wallet_info.g.dart @@ -269,6 +269,7 @@ const _WalletInfomainAddressTypeEnumValueMap = { 'p2tr': 14, 'solana': 15, 'cardanoShelley': 16, + 'xelis': 17, }; const _WalletInfomainAddressTypeValueEnumMap = { 0: AddressType.p2pkh, @@ -288,6 +289,7 @@ const _WalletInfomainAddressTypeValueEnumMap = { 14: AddressType.p2tr, 15: AddressType.solana, 16: AddressType.cardanoShelley, + 15: AddressType.xelis, }; Id _walletInfoGetId(WalletInfo object) { diff --git a/scripts/android/build_all.sh b/scripts/android/build_all.sh index 60aa13c6a..4d09d7aa0 100755 --- a/scripts/android/build_all.sh +++ b/scripts/android/build_all.sh @@ -16,6 +16,7 @@ PLUGINS_DIR=../../crypto_plugins (cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) set_rust_to_1720 (cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh ) +(cd "${PLUGINS_DIR}"/xelis_flutter/scripts/android && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/android/build_all_campfire.sh b/scripts/android/build_all_campfire.sh index 60aa13c6a..4d09d7aa0 100755 --- a/scripts/android/build_all_campfire.sh +++ b/scripts/android/build_all_campfire.sh @@ -16,6 +16,7 @@ PLUGINS_DIR=../../crypto_plugins (cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) set_rust_to_1720 (cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh ) +(cd "${PLUGINS_DIR}"/xelis_flutter/scripts/android && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/android/build_all_duo.sh b/scripts/android/build_all_duo.sh index d67e700a8..9c928a084 100755 --- a/scripts/android/build_all_duo.sh +++ b/scripts/android/build_all_duo.sh @@ -18,6 +18,7 @@ PLUGINS_DIR=../../crypto_plugins (cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) set_rust_to_1720 (cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh ) +(cd "${PLUGINS_DIR}"/xelis_flutter/scripts/android && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/ios/build_all.sh b/scripts/ios/build_all.sh index bcb03e991..abebdfdb8 100755 --- a/scripts/ios/build_all.sh +++ b/scripts/ios/build_all.sh @@ -18,6 +18,7 @@ rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) +(cd ../../crypto_plugins/xelis_flutter/scripts/ios && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/ios/build_all_campfire.sh b/scripts/ios/build_all_campfire.sh index bcb03e991..abebdfdb8 100755 --- a/scripts/ios/build_all_campfire.sh +++ b/scripts/ios/build_all_campfire.sh @@ -18,6 +18,7 @@ rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) +(cd ../../crypto_plugins/xelis_flutter/scripts/ios && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/ios/build_all_duo.sh b/scripts/ios/build_all_duo.sh index 89e6f4641..2dd4d30ee 100755 --- a/scripts/ios/build_all_duo.sh +++ b/scripts/ios/build_all_duo.sh @@ -20,6 +20,7 @@ rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) +(cd ../../crypto_plugins/xelis_flutter/scripts/ios && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/linux/build_all.sh b/scripts/linux/build_all.sh index 423646185..16de64450 100755 --- a/scripts/linux/build_all.sh +++ b/scripts/linux/build_all.sh @@ -16,6 +16,7 @@ mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) +(cd ../../crypto_plugins/xelis_flutter/scripts/linux && ./build_all.sh ) ./build_secp256k1.sh diff --git a/scripts/linux/build_all_campfire.sh b/scripts/linux/build_all_campfire.sh index 423646185..16de64450 100755 --- a/scripts/linux/build_all_campfire.sh +++ b/scripts/linux/build_all_campfire.sh @@ -16,6 +16,7 @@ mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) +(cd ../../crypto_plugins/xelis_flutter/scripts/linux && ./build_all.sh ) ./build_secp256k1.sh diff --git a/scripts/linux/build_all_duo.sh b/scripts/linux/build_all_duo.sh index 78067b478..a57cc7f91 100755 --- a/scripts/linux/build_all_duo.sh +++ b/scripts/linux/build_all_duo.sh @@ -18,6 +18,7 @@ mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) +(cd ../../crypto_plugins/xelis_flutter/scripts/linux && ./build_all.sh ) ./build_secp256k1.sh diff --git a/scripts/macos/build_all.sh b/scripts/macos/build_all.sh index af608846f..02d45501b 100755 --- a/scripts/macos/build_all.sh +++ b/scripts/macos/build_all.sh @@ -10,6 +10,7 @@ set_rust_to_1671 (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) +(cd ../../crypto_plugins/xelis_flutter/scripts/macos && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/macos/build_all_campfire.sh b/scripts/macos/build_all_campfire.sh index af608846f..02d45501b 100755 --- a/scripts/macos/build_all_campfire.sh +++ b/scripts/macos/build_all_campfire.sh @@ -10,6 +10,7 @@ set_rust_to_1671 (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) +(cd ../../crypto_plugins/xelis_flutter/scripts/macos && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/macos/build_all_duo.sh b/scripts/macos/build_all_duo.sh index 8a53e5801..2e309ad12 100755 --- a/scripts/macos/build_all_duo.sh +++ b/scripts/macos/build_all_duo.sh @@ -12,6 +12,7 @@ set_rust_to_1671 (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) +(cd ../../crypto_plugins/xelis_flutter/scripts/macos && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/windows/build_all.sh b/scripts/windows/build_all.sh index 191a46cc0..8b8a3e822 100755 --- a/scripts/windows/build_all.sh +++ b/scripts/windows/build_all.sh @@ -11,6 +11,7 @@ mkdir -p build (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) +(cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_campfire.sh b/scripts/windows/build_all_campfire.sh index 191a46cc0..8b8a3e822 100755 --- a/scripts/windows/build_all_campfire.sh +++ b/scripts/windows/build_all_campfire.sh @@ -11,6 +11,7 @@ mkdir -p build (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) +(cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_duo.sh b/scripts/windows/build_all_duo.sh index 3e27eff02..fe05ba659 100755 --- a/scripts/windows/build_all_duo.sh +++ b/scripts/windows/build_all_duo.sh @@ -13,6 +13,7 @@ mkdir -p build (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) +(cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_secp256k1.bat b/scripts/windows/build_secp256k1.bat index f5777b974..bae7c9788 100644 --- a/scripts/windows/build_secp256k1.bat +++ b/scripts/windows/build_secp256k1.bat @@ -7,6 +7,6 @@ git reset --hard cmake -G "Visual Studio 17 2022" -A x64 -S . -B build cd build cmake --build . -if not exist "..\..\..\..\build\" mkdir "..\..\..\..\build\" -xcopy bin\Debug\libsecp256k1-2.dll "..\..\..\..\build\secp256k1.dll" /Y +if not exist "..\..\..\..\..\build\" mkdir "..\..\..\..\..\build\" +xcopy bin\Debug\libsecp256k1-2.dll "..\..\..\..\..\build\secp256k1.dll" /Y cd ..\..\..\ From 2061eba2f2aa3b973aea8043fe699410a31baa5f Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Wed, 29 Jan 2025 00:38:23 -0800 Subject: [PATCH 02/50] xelis CryptoCurrency definition added, bridged wallet wrapper started --- lib/wallets/crypto_currency/coins/xelis.dart | 122 +++++++++++++++++++ lib/wallets/wallet/impl/xelis_wallet.dart | 14 +++ lib/wallets/wallet/wallet.dart | 4 + 3 files changed, 140 insertions(+) create mode 100644 lib/wallets/crypto_currency/coins/xelis.dart create mode 100644 lib/wallets/wallet/impl/xelis_wallet.dart diff --git a/lib/wallets/crypto_currency/coins/xelis.dart b/lib/wallets/crypto_currency/coins/xelis.dart new file mode 100644 index 000000000..24db5815b --- /dev/null +++ b/lib/wallets/crypto_currency/coins/xelis.dart @@ -0,0 +1,122 @@ +import '../../../models/isar/models/blockchain_data/address.dart'; +import '../../../models/node_model.dart'; +import '../../../utilities/default_nodes.dart'; +import '../../../utilities/enums/derive_path_type_enum.dart'; +import '../crypto_currency.dart'; +import '../intermediate/bip39_currency.dart'; + +import 'package:xelis_flutter/lib.dart' as xelis; + +class Xelis extends Bip39Currency { + Xelis(super.network) { + _idMain = "xelis"; + _uriScheme = "xelis"; + switch (network) { + case CryptoCurrencyNetwork.main: + _id = _idMain; + _name = "Xelis"; + _ticker = "XEL"; + default: + throw Exception("Unsupported network: $network"); + } + } + + late final String _id; + @override + String get identifier => _id; + + late final String _idMain; + @override + String get mainNetId => _idMain; + + late final String _name; + @override + String get prettyName => _name; + + late final String _uriScheme; + @override + String get uriScheme => _uriScheme; + + late final String _ticker; + @override + String get ticker => _ticker; + + @override + NodeModel get defaultNode { + switch (network) { + case CryptoCurrencyNetwork.main: + return NodeModel( + host: "https://us-node.xelis.io", + port: 443, + name: DefaultNodes.defaultName, + id: DefaultNodes.buildId(this), + useSSL: true, + enabled: true, + coinName: identifier, + isFailover: true, + isDown: false, + torEnabled: true, + clearnetEnabled: true, + ); + default: + throw Exception("Unsupported network: $network"); + } + } + + @override + int get minConfirms => 20; + + @override + bool get torSupport => true; + + @override + bool validateAddress(String address) { + try { + return xelis.isAddressValid(address); + } catch (_) { + return false; + } + } + + @override + String get genesisHash => throw UnimplementedError(); + + @override + int get defaultSeedPhraseLength => 12; + + @override + int get fractionDigits => 9; + + @override + bool get hasBuySupport => false; + + @override + bool get hasMnemonicPassphraseSupport => false; + + @override + List get possibleMnemonicLengths => [defaultSeedPhraseLength, 24]; + + @override + AddressType get defaultAddressType => defaultDerivePathType.getAddressType(); + + @override + BigInt get satsPerCoin => BigInt.from(1000000000); + + @override + int get targetBlockTimeSeconds => 15; + + @override + DerivePathType get defaultDerivePathType => DerivePathType.xelis; + + @override + Uri defaultBlockExplorer(String txid) { + switch (network) { + case CryptoCurrencyNetwork.main: + return Uri.parse("https://explorer.xelis.io/txs/$txid"); + default: + throw Exception( + "Unsupported network for defaultBlockExplorer(): $network", + ); + } + } +} diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart new file mode 100644 index 000000000..c53a266d5 --- /dev/null +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -0,0 +1,14 @@ +// this source file acts as a structural formality +import 'package:xelis_flutter/lib.dart' as xelis; + +class XelisWallet extends Bip39Wallet { + XelisWallet(CryptoCurrencyNetwork network) : super(Xelis(network)); + + final syncMutex = Mutex(); + + final xelis.Network network = cryptoCurrency.network == CryptoCurrencyNetwork.main + ? xelis.Network.Mainnet + : xelis.Network.Testnet; + + xelis.XelisWallet _wallet; +} \ No newline at end of file diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart index 161c68f5f..733c3cf3e 100644 --- a/lib/wallets/wallet/wallet.dart +++ b/lib/wallets/wallet/wallet.dart @@ -47,6 +47,7 @@ import 'impl/stellar_wallet.dart'; import 'impl/sub_wallets/eth_token_wallet.dart'; import 'impl/tezos_wallet.dart'; import 'impl/wownero_wallet.dart'; +import 'impl/xelis_wallet.dart'; import 'intermediate/cryptonote_wallet.dart'; import 'wallet_mixin_interfaces/electrumx_interface.dart'; import 'wallet_mixin_interfaces/lelantus_interface.dart'; @@ -406,6 +407,9 @@ abstract class Wallet { case const (Wownero): return WowneroWallet(net); + case const (Xelis): + return XelisWallet(net); + default: // should never hit in reality throw Exception("Unknown crypto currency: ${walletInfo.coin}"); From 34cee820182da984a5866293d01c2c2788932e4a Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Wed, 29 Jan 2025 00:38:54 -0800 Subject: [PATCH 03/50] added xelis enum variants --- lib/utilities/enums/derive_path_type_enum.dart | 6 +++++- lib/wallets/crypto_currency/crypto_currency.dart | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/utilities/enums/derive_path_type_enum.dart b/lib/utilities/enums/derive_path_type_enum.dart index 3d64fb45a..e50ed2387 100644 --- a/lib/utilities/enums/derive_path_type_enum.dart +++ b/lib/utilities/enums/derive_path_type_enum.dart @@ -19,7 +19,8 @@ enum DerivePathType { eCash44, solana, bip86, - cardanoShelley; + cardanoShelley, + xelis; AddressType getAddressType() { switch (this) { @@ -45,6 +46,9 @@ enum DerivePathType { case DerivePathType.cardanoShelley: return AddressType.cardanoShelley; + + case DerivePathType.xelis: + return AddressType.xelis; } } } diff --git a/lib/wallets/crypto_currency/crypto_currency.dart b/lib/wallets/crypto_currency/crypto_currency.dart index 066675d28..d5553ceca 100644 --- a/lib/wallets/crypto_currency/crypto_currency.dart +++ b/lib/wallets/crypto_currency/crypto_currency.dart @@ -23,6 +23,7 @@ export 'coins/solana.dart'; export 'coins/stellar.dart'; export 'coins/tezos.dart'; export 'coins/wownero.dart'; +export 'coins/xelis.dart'; enum CryptoCurrencyNetwork { main, From 5f9466ca3cbd78447cb3b48462b3c8bfd56191bc Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 6 Feb 2025 04:34:50 -0800 Subject: [PATCH 04/50] build script + dep updates, xelis library integration progress --- crypto_plugins/xelis_flutter | 2 +- .../isar/models/blockchain_data/address.dart | 2 +- .../models/blockchain_data/address.g.dart | 2 + lib/wallets/crypto_currency/coins/xelis.dart | 26 +- .../intermediate/electrum_currency.dart | 5 + lib/wallets/isar/models/wallet_info.g.dart | 2 +- lib/wallets/wallet/impl/xelis_wallet.dart | 542 +++++++++++++++++- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 55 ++ scripts/android/build_all.sh | 3 +- scripts/android/build_all_campfire.sh | 3 +- scripts/android/build_all_duo.sh | 3 +- scripts/app_config/configure_stack_wallet.sh | 2 + scripts/app_config/templates/pubspec.template | 5 + scripts/ios/build_all.sh | 3 +- scripts/ios/build_all_campfire.sh | 3 +- scripts/ios/build_all_duo.sh | 3 +- scripts/linux/build_all.sh | 3 +- scripts/linux/build_all_campfire.sh | 3 +- scripts/linux/build_all_duo.sh | 3 +- scripts/macos/build_all.sh | 3 +- scripts/macos/build_all_campfire.sh | 3 +- scripts/macos/build_all_duo.sh | 3 +- scripts/rust_version.sh | 9 + scripts/windows/build_all.sh | 3 +- scripts/windows/build_all_campfire.sh | 3 +- scripts/windows/build_all_duo.sh | 3 +- .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 31 files changed, 680 insertions(+), 28 deletions(-) create mode 100644 lib/wallets/crypto_currency/intermediate/electrum_currency.dart diff --git a/crypto_plugins/xelis_flutter b/crypto_plugins/xelis_flutter index 294bdf87e..e93337c26 160000 --- a/crypto_plugins/xelis_flutter +++ b/crypto_plugins/xelis_flutter @@ -1 +1 @@ -Subproject commit 294bdf87e5f5350ecc15b2066b77a91c9ef0568d +Subproject commit e93337c262580665ffb0d16cfcd8d3614f7e371a diff --git a/lib/models/isar/models/blockchain_data/address.dart b/lib/models/isar/models/blockchain_data/address.dart index 0d8d48791..8947d6c46 100644 --- a/lib/models/isar/models/blockchain_data/address.dart +++ b/lib/models/isar/models/blockchain_data/address.dart @@ -175,7 +175,7 @@ enum AddressType { frostMS, p2tr, solana, - cardanoShelley + cardanoShelley, xelis; String get readableName { diff --git a/lib/models/isar/models/blockchain_data/address.g.dart b/lib/models/isar/models/blockchain_data/address.g.dart index 340ab9f1b..a9289a481 100644 --- a/lib/models/isar/models/blockchain_data/address.g.dart +++ b/lib/models/isar/models/blockchain_data/address.g.dart @@ -279,6 +279,7 @@ const _AddresstypeEnumValueMap = { 'p2tr': 14, 'solana': 15, 'cardanoShelley': 16, + 'xelis': 17, }; const _AddresstypeValueEnumMap = { 0: AddressType.p2pkh, @@ -298,6 +299,7 @@ const _AddresstypeValueEnumMap = { 14: AddressType.p2tr, 15: AddressType.solana, 16: AddressType.cardanoShelley, + 17: AddressType.xelis, }; Id _addressGetId(Address object) { diff --git a/lib/wallets/crypto_currency/coins/xelis.dart b/lib/wallets/crypto_currency/coins/xelis.dart index 24db5815b..84e8439bb 100644 --- a/lib/wallets/crypto_currency/coins/xelis.dart +++ b/lib/wallets/crypto_currency/coins/xelis.dart @@ -5,9 +5,9 @@ import '../../../utilities/enums/derive_path_type_enum.dart'; import '../crypto_currency.dart'; import '../intermediate/bip39_currency.dart'; -import 'package:xelis_flutter/lib.dart' as xelis; +import 'package:xelis_flutter/src/api/utils.dart' as x_utils; -class Xelis extends Bip39Currency { +class Xelis extends CryptoCurrency { Xelis(super.network) { _idMain = "xelis"; _uriScheme = "xelis"; @@ -16,6 +16,10 @@ class Xelis extends Bip39Currency { _id = _idMain; _name = "Xelis"; _ticker = "XEL"; + case CryptoCurrencyNetwork.test: + _id = "xelisTestNet"; + _name = "tXelis"; + _ticker = "XET"; default: throw Exception("Unsupported network: $network"); } @@ -58,6 +62,22 @@ class Xelis extends Bip39Currency { torEnabled: true, clearnetEnabled: true, ); + + case CryptoCurrencyNetwork.test: + return NodeModel( + host: "https://testnet-node.xelis.io", + port: 443, + name: DefaultNodes.defaultName, + id: DefaultNodes.buildId(this), + useSSL: true, + enabled: true, + coinName: identifier, + isFailover: true, + isDown: false, + torEnabled: true, + clearnetEnabled: true, + ); + default: throw Exception("Unsupported network: $network"); } @@ -72,7 +92,7 @@ class Xelis extends Bip39Currency { @override bool validateAddress(String address) { try { - return xelis.isAddressValid(address); + return x_utils.isAddressValid(strAddress: address); } catch (_) { return false; } diff --git a/lib/wallets/crypto_currency/intermediate/electrum_currency.dart b/lib/wallets/crypto_currency/intermediate/electrum_currency.dart new file mode 100644 index 000000000..4d8378f16 --- /dev/null +++ b/lib/wallets/crypto_currency/intermediate/electrum_currency.dart @@ -0,0 +1,5 @@ +import '../crypto_currency.dart'; + +abstract class ElectrumCurrency extends CryptoCurrency { + ElectrumCurrency(super.network); +} \ No newline at end of file diff --git a/lib/wallets/isar/models/wallet_info.g.dart b/lib/wallets/isar/models/wallet_info.g.dart index 39506f199..5e93564c0 100644 --- a/lib/wallets/isar/models/wallet_info.g.dart +++ b/lib/wallets/isar/models/wallet_info.g.dart @@ -289,7 +289,7 @@ const _WalletInfomainAddressTypeValueEnumMap = { 14: AddressType.p2tr, 15: AddressType.solana, 16: AddressType.cardanoShelley, - 15: AddressType.xelis, + 17: AddressType.xelis, }; Id _walletInfoGetId(WalletInfo object) { diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index c53a266d5..c21100625 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -1,14 +1,542 @@ -// this source file acts as a structural formality -import 'package:xelis_flutter/lib.dart' as xelis; +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:decimal/decimal.dart'; +import 'package:flutter/foundation.dart'; +import 'package:isar/isar.dart'; + +import 'package:xelis_flutter/src/api/network.dart' as x_network; +import 'package:xelis_flutter/src/api/wallet.dart' as x_wallet; +import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk; + +import '../../../models/isar/models/blockchain_data/address.dart'; +import '../../../models/isar/models/blockchain_data/transaction.dart'; +import '../../../models/isar/models/blockchain_data/v2/input_v2.dart'; +import '../../../models/isar/models/blockchain_data/v2/output_v2.dart'; +import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart'; + +import '../../../models/node_model.dart'; +import '../../../models/balance.dart'; +import '../../../utilities/amount/amount.dart'; +import '../../crypto_currency/crypto_currency.dart'; +import '../../models/tx_data.dart'; +import '../wallet.dart'; + +import 'package:isar/isar.dart'; +import 'package:mutex/mutex.dart'; +import 'package:stack_wallet_backup/generate_password.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; +import '../intermediate/bip39_wallet.dart'; + +extension XelisNetworkConversion on CryptoCurrencyNetwork { + x_network.Network get xelisNetwork { + switch (this) { + case CryptoCurrencyNetwork.main: + return x_network.Network.mainnet; + case CryptoCurrencyNetwork.test: + return x_network.Network.testnet; + default: + throw ArgumentError('Unsupported network type for Xelis: $this'); + } + } +} + +extension CryptoCurrencyNetworkConversion on x_network.Network { + CryptoCurrencyNetwork get cryptoCurrencyNetwork { + switch (this) { + case x_network.Network.mainnet: + return CryptoCurrencyNetwork.main; + case x_network.Network.testnet: + return CryptoCurrencyNetwork.test; + default: + throw ArgumentError('Unsupported Xelis network type: $this'); + } + } +} + +class XelisWallet extends Wallet { + x_wallet.XelisWallet? _wallet; + + x_wallet.XelisWallet? get wallet => _wallet; + set wallet(x_wallet.XelisWallet newWallet) { + _wallet = newWallet; + } + + void _checkInitialized() { + if (_wallet == null) { + throw StateError('XelisWallet not initialized'); + } + } -class XelisWallet extends Bip39Wallet { XelisWallet(CryptoCurrencyNetwork network) : super(Xelis(network)); final syncMutex = Mutex(); + NodeModel? _xelisNode; + Timer? timer; + + // ==================== Overrides ============================================ + + @override + int get isarTransactionVersion => 2; + + @override + Future init({bool? isRestore}) async { + if (isRestore != true) { + x_wallet.PrecomputedTablesShared? encodedTables = + await secureStorageInterface.read(key: "xelis_precomputed_tables"); + + String? encodedWallet = + await secureStorageInterface.read(key: "${walletId}_wallet"); + + // check if should create a new wallet + if (encodedWallet == null) { + final String password = generatePassword(); + + await secureStorageInterface.write( + key: '${walletId}_password', + value: password, + ); + + final String name = walletId; + + final wallet = await x_wallet.createXelisWallet( + name: name, + password: password, + network: cryptoCurrency.network.xelisNetwork, + seed: null, // Xelis lib will autogenerate this + privateKey: null, // Xelis lib will autogenerate this + precomputedTables: encodedTables, + ); + + await secureStorageInterface.write( + key: '${walletId}_wallet', + value: wallet, + ); + + _wallet = wallet; + } else { + try { + + final String name = walletId; + final password = + await secureStorageInterface.read(key: '${walletId}_password'); + + final wallet = await x_wallet.openXelisWallet( + name: name, + password: password, + network: cryptoCurrency.network.xelisNetwork, + precomputedTables: encodedTables, + ); + + await secureStorageInterface.write( + key: '${walletId}_wallet', + value: wallet, + ); + + _wallet = wallet; + } catch (e, s) { + // do nothing, still allow user into wallet + } + } + + // Creation or Opening of Xelis wallets will generate tables if required + // Make sure to store said shared tables if we make it this far, to save + // time in the future + if (encodedTables == null) { + await secureStorageInterface.write( + key: 'xelis_precomputed_tables', + value: x_wallet.getCachedTable(), + ); + } + } + + return await super.init(); + } + + @override + Future pingCheck() async { + _checkInitialized(); + try { + await _wallet!.getDaemonInfo(); + return true; + } catch (_) { + return false; + } + } + + @override + Future updateBalance() async { + try { + final BigInt xelBalance = await _wallet!.getXelisBalanceRaw(); // in the future, use getAssetBalances and handle each + final balance = Balance( + total: Amount( + rawValue: xelBalance, + fractionDigits: cryptoCurrency.fractionDigits, + ), + spendable: Amount( + rawValue: xelBalance, + fractionDigits: cryptoCurrency.fractionDigits, + ), + blockedTotal: Amount.zeroWith( + fractionDigits: cryptoCurrency.fractionDigits, + ), + pendingSpendable: Amount.zeroWith( + fractionDigits: cryptoCurrency.fractionDigits, + ), + ); + await info.updateBalance( + newBalance: balance, + isar: mainDB.isar, + ); + } catch (e, s) { + } + } + + @override + Future updateChainHeight() async { + try { + final infoString = await _wallet!.getDaemonInfo(); + + final Map nodeInfo = json.decode(infoString); + + final int topoheight = nodeInfo['topoheight'] as int; + + await info.updateCachedChainHeight( + newHeight: topoheight, + isar: mainDB.isar, + ); + } catch (e, s) { + print('Error updating chain height: $e'); + print('Stack trace: $s'); + } + } + + @override + Future updateNode() async { + // do nothing + } + + @override + Future> updateTransactions({bool isRescan = false}) async { + _checkInitialized(); + + int firstBlock = 0; + if (!isRescan) { + firstBlock = await mainDB.isar.transactionV2s + .where() + .walletIdEqualTo(walletId) + .heightProperty() + .max() ?? + 0; + + if (firstBlock > 10) { + // add some buffer + firstBlock -= 10; + } + } + + await _wallet!.rescan(topoheight: firstBlock as BigInt); + final txListJson = await _wallet!.allHistory(); + + final List txns = []; + + for (final jsonString in txListJson) { + try { + final transactionEntry = xelis_sdk.TransactionEntry.fromJson(json.decode(jsonString)); + + // Check for duplicates + final storedTx = await mainDB.isar.transactionV2s + .where() + .txidWalletIdEqualTo(transactionEntry.hash, walletId) + .findFirst(); + + if (storedTx != null && + storedTx.height != null && + storedTx.height! > 0) { + continue; // Skip already processed transactions + } + + final List outputs = []; + final List inputs = []; + TransactionType txType; + TransactionSubType txSubType = TransactionSubType.none; + int? nonce; + Amount? fee; + Map otherData = {}; + + final entryData = transactionEntry.txEntryType; + + if (entryData is xelis_sdk.CoinbaseEntry) { + final coinbase = entryData; + txType = TransactionType.incoming; + outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( + scriptPubKeyHex: "00", + valueStringSats: coinbase.reward.toString(), + addresses: [thisAddress], + walletOwns: true, + )); + } else if (entryData is xelis_sdk.BurnEntry) { + final burn = entryData; + txType = TransactionType.outgoing; + inputs.add(InputV2.isarCantDoRequiredInDefaultConstructor( + scriptSigAsm: null, + scriptSigHex: null, + sequence: null, + outpoint: null, + valueStringSats: burn.amount.toString(), + addresses: [thisAddress], + witness: null, + innerRedeemScriptAsm: null, + coinbase: null, + walletOwns: true, + )); + otherData['burnAsset'] = burn.asset; + } else if (entryData is xelis_sdk.IncomingEntry) { + final incoming = entryData; + txType = incoming.from == thisAddress + ? TransactionType.sentToSelf + : TransactionType.incoming; + + for (final transfer in incoming.transfers) { + final int decimals = await _wallet!.getAssetDecimals( + asset: transfer.asset + ); + + outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( + scriptPubKeyHex: "00", + valueStringSats: transfer.amount.toString(), + addresses: [thisAddress], + walletOwns: true, + )); + otherData['asset_${transfer.asset}'] = transfer.amount.toString(); + if (transfer.extraData != null) { + otherData['extraData_${transfer.asset}'] = transfer.extraData!.toJson(); + } + } + } else if (entryData is xelis_sdk.OutgoingEntry) { + final outgoing = entryData; + txType = TransactionType.outgoing; + nonce = outgoing.nonce; + fee = Amount( + rawValue: BigInt.from(outgoing.fee), + fractionDigits: decimals + ); + + for (final transfer in outgoing.transfers) { + final int decimals = await _wallet!.getAssetDecimals( + asset: transfer.asset + ); + + outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( + scriptPubKeyHex: "00", + valueStringSats: transfer.amount.toString(), + addresses: [transfer.destination], + walletOwns: transfer.destination == thisAddress, + )); + otherData['asset_${transfer.asset}'] = transfer.amount.toString(); + if (transfer.extraData != null) { + otherData['extraData_${transfer.asset}'] = transfer.extraData!.toJson(); + } + } + } else { + // Skip unknown entry types + return; + } + + final txn = TransactionV2( + walletId: walletId, + blockHash: "", // Not provided in Xelis data + hash: transactionEntry.hash, + txid: transactionEntry.hash, + timestamp: (transactionEntry.timestamp?.millisecondsSinceEpoch ?? 0) ~/ 1000, + height: transactionEntry?.topoheight, + inputs: List.unmodifiable(inputs), + outputs: List.unmodifiable(outputs), + version: -1, // Version not provided + type: txType, + subType: txSubType, + otherData: jsonEncode({ + ...otherData, + if (nonce != null) 'nonce': nonce, + if (fee != null) 'overrideFee': fee.toJsonString(), + }), + ); + + txns.add(txn); + } catch (e, s) { + } + } + + await mainDB.updateOrPutTransactionV2s(txns); + return txns.map((e) => e.txid).toList(); + } + + @override + Future updateUTXOs() async { + // not used in xel + return false; + } + + @override + Future checkSaveInitialReceivingAddress() async { + // do nothing + } + + @override + FilterOperation? get changeAddressFilterOperation => + throw UnimplementedError("Not used for $runtimeType"); + + @override + FilterOperation? get receivingAddressFilterOperation => + FilterGroup.and(standardReceivingAddressFilters); + + @override + Future prepareSend({required TxData txData}) async { + try { + _checkInitialized(); + + // Validate recipients + if (txData.recipients == null || txData.recipients!.length != 1) { + throw Exception("$runtimeType prepareSend requires 1 recipient"); + } + + final recipient = txData.recipients!.first; + final Amount sendAmount = recipient.amount; + final asset = cryptoCurrency.assetId ?? xelis_sdk.xelisAsset; + + final sendAmountStr = await _wallet!.formatCoin( + atomicAmount: sendAmount.rawValue, + assetHash: asset + ); + + // Check balance using raw method + final xelBalance = await _wallet!.getXelisBalanceRaw(); + final balance = Amount( + rawValue: xelBalance, + fractionDigits: cryptoCurrency.fractionDigits, // needs to become tied to asset + ); + + // Create transfers for fee estimation + final transfers = [ + x_wallet.Transfer( + floatAmount: sendAmountStr as double, + strAddress: recipient.address, + assetHash: asset, + ) + ]; + + // Estimate fees + final estimatedFeeString = await _wallet!.estimateFees(transfers: transfers); + final feeAmount = Amount( + rawValue: BigInt.parse(estimatedFeeString), + fractionDigits: cryptoCurrency.fractionDigits, + ); + + // Apply fee multiplier + final feeMultiplier = txData.feeRateAmount ?? 1.0; + final boostedFee = Amount( + rawValue: (BigInt.from((feeAmount.raw * + BigInt.from((feeMultiplier * 100).toInt())) / + BigInt.from(100))), + fractionDigits: cryptoCurrency.fractionDigits, + ); + + // Check if we have enough for both transfer and fee + if (sendAmount + boostedFee > balance) { + final requiredAmt = await _wallet!.formatCoin( + atomicAmount: (sendAmount + boostedFee).rawValue, + assetHash: asset + ); + + final availableAmt = await _wallet!.formatCoin( + atomicAmount: xelBalance, + assetHash: asset + ); + + throw Exception( + "Insufficient balance to cover transfer and fees. " + "Required: $requiredAmt, Available: $availableAmt" + ); + } + + return txData.copyWith( + fee: boostedFee, + otherData: { + 'asset': asset, + }, + ); + } catch (e, s) { + rethrow; + } + } + + @override + Future confirmSend({required TxData txData}) async { + try { + _checkInitialized(); + + // Validate recipients + if (txData.recipients == null || txData.recipients!.length != 1) { + throw Exception("$runtimeType confirmSend requires 1 recipient"); + } + + final recipient = txData.recipients!.first; + final Amount sendAmount = recipient.amount; + final asset = txData.otherData?['asset'] ?? xelis_sdk.xelisAsset; + + String txHash; + + final amt = await _wallet!.formatCoin( + atomicAmount: recipient.amount as BigInt, + assetHash: asset + ) as double; + + // Create a transfer transaction + final txJson = await _wallet!.createTransfersTransaction( + transfers: [ + x_wallet.Transfer( + floatAmount: amt, + strAddress: recipient.address, + assetHash: asset, + extraData: null, // Add extra data if needed + ) + ] + ); + + final tx = x_wallet.TransactionSummary.fromJson(txJson); + + // Broadcast the transaction + await _wallet!.broadcastTransaction(txHash: tx.hash); + + return await updateSentCachedTxData(txData: txData.copyWith( + txid: tx.hash, + )); + } catch (e, s) { + rethrow; + } + } - final xelis.Network network = cryptoCurrency.network == CryptoCurrencyNetwork.main - ? xelis.Network.Mainnet - : xelis.Network.Testnet; + @override + Future recover({required bool isRescan}) async { + await refreshMutex.protect(() async { + if (isRescan) { + await mainDB.deleteWalletBlockchainData(walletId); + await checkSaveInitialReceivingAddress(); + await updateBalance(); + await updateTransactions(isRescan: true); + } else { + await checkSaveInitialReceivingAddress(); + unawaited(updateBalance()); + unawaited(updateTransactions()); + } + }); + } - xelis.XelisWallet _wallet; + @override + Future exit() async { + timer?.cancel(); + timer = null; + await super.exit(); + } } \ No newline at end of file diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 88c196c5e..4a096bcde 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -16,6 +16,7 @@ #include #include #include +#include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) cs_monero_flutter_libs_linux_registrar = @@ -48,4 +49,7 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) window_size_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "WindowSizePlugin"); window_size_plugin_register_with_registrar(window_size_registrar); + g_autoptr(FlPluginRegistrar) xelis_flutter_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "XelisFlutterPlugin"); + xelis_flutter_plugin_register_with_registrar(xelis_flutter_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 72a81025c..22b92c965 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -13,6 +13,7 @@ list(APPEND FLUTTER_PLUGIN_LIST stack_wallet_backup url_launcher_linux window_size + xelis_flutter ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 245400e1a..73a62daf8 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -26,6 +26,7 @@ import stack_wallet_backup import url_launcher_macos import wakelock_plus import window_size +import xelis_flutter func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { CameraMacosPlugin.register(with: registry.registrar(forPlugin: "CameraMacosPlugin")) @@ -49,4 +50,5 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) WindowSizePlugin.register(with: registry.registrar(forPlugin: "WindowSizePlugin")) + XelisFlutterPlugin.register(with: registry.registrar(forPlugin: "XelisFlutterPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index b611f6f20..920ea7743 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -187,6 +187,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.1" + build_cli_annotations: + dependency: transitive + description: + name: build_cli_annotations + sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172 + url: "https://pub.dev" + source: hosted + version: "2.1.0" build_config: dependency: transitive description: @@ -885,6 +893,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + flutter_rust_bridge: + dependency: transitive + description: + name: flutter_rust_bridge + sha256: "3292ad6085552987b8b3b9a7e5805567f4013372d302736b702801acb001ee00" + url: "https://pub.dev" + source: hosted + version: "2.7.1" flutter_secure_storage: dependency: "direct main" description: @@ -1185,6 +1201,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.8.0" + jsontool: + dependency: transitive + description: + name: jsontool + sha256: e49bf419e82d90f009426cd7fdec8d54ba8382975b3454ed16a3af3ee1d1b697 + url: "https://pub.dev" + source: hosted + version: "2.1.0" keyboard_dismisser: dependency: "direct main" description: @@ -2148,6 +2172,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + very_good_analysis: + dependency: transitive + description: + name: very_good_analysis + sha256: "62d2b86d183fb81b2edc22913d9f155d26eb5cf3855173adb1f59fac85035c63" + url: "https://pub.dev" + source: hosted + version: "7.0.0" vm_service: dependency: transitive description: @@ -2237,6 +2269,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.5" + web_socket_client: + dependency: transitive + description: + name: web_socket_client + sha256: "0ec5230852349191188c013112e4d2be03e3fc83dbe80139ead9bf3a136e53b5" + url: "https://pub.dev" + source: hosted + version: "0.1.5" webdriver: dependency: transitive description: @@ -2286,6 +2326,21 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + xelis_dart_sdk: + dependency: "direct main" + description: + name: xelis_dart_sdk + sha256: "2a7f8ab4c30fad2fd824ba6ea4e83ac20c726b47c7aa4f1e713ef3971a3ec1f7" + url: "https://pub.dev" + source: hosted + version: "0.24.0" + xelis_flutter: + dependency: "direct main" + description: + path: "crypto_plugins/xelis_flutter" + relative: true + source: path + version: "0.0.1" xml: dependency: transitive description: diff --git a/scripts/android/build_all.sh b/scripts/android/build_all.sh index 4d09d7aa0..b6e6527c3 100755 --- a/scripts/android/build_all.sh +++ b/scripts/android/build_all.sh @@ -14,9 +14,10 @@ PLUGINS_DIR=../../crypto_plugins (cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh ) (cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) +set_rust_to_1840 +(cd "${PLUGINS_DIR}"/xelis_flutter/scripts/android && ./build_all.sh ) set_rust_to_1720 (cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh ) -(cd "${PLUGINS_DIR}"/xelis_flutter/scripts/android && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/android/build_all_campfire.sh b/scripts/android/build_all_campfire.sh index 4d09d7aa0..b6e6527c3 100755 --- a/scripts/android/build_all_campfire.sh +++ b/scripts/android/build_all_campfire.sh @@ -14,9 +14,10 @@ PLUGINS_DIR=../../crypto_plugins (cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh ) (cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) +set_rust_to_1840 +(cd "${PLUGINS_DIR}"/xelis_flutter/scripts/android && ./build_all.sh ) set_rust_to_1720 (cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh ) -(cd "${PLUGINS_DIR}"/xelis_flutter/scripts/android && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/android/build_all_duo.sh b/scripts/android/build_all_duo.sh index 9c928a084..a84ec4f8f 100755 --- a/scripts/android/build_all_duo.sh +++ b/scripts/android/build_all_duo.sh @@ -16,9 +16,10 @@ PLUGINS_DIR=../../crypto_plugins (cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh ) (cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) +set_rust_to_1840 +(cd "${PLUGINS_DIR}"/xelis_flutter/scripts/android && ./build_all.sh ) set_rust_to_1720 (cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh ) -(cd "${PLUGINS_DIR}"/xelis_flutter/scripts/android && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/app_config/configure_stack_wallet.sh b/scripts/app_config/configure_stack_wallet.sh index 0fd8e5e8a..a7311a19a 100755 --- a/scripts/app_config/configure_stack_wallet.sh +++ b/scripts/app_config/configure_stack_wallet.sh @@ -71,6 +71,7 @@ final List _supportedCoins = List.unmodifiable([ Peercoin(CryptoCurrencyNetwork.main), Solana(CryptoCurrencyNetwork.main), Stellar(CryptoCurrencyNetwork.main), + Xelis(CryptoCurrencyNetwork.main), Tezos(CryptoCurrencyNetwork.main), Wownero(CryptoCurrencyNetwork.main), Bitcoin(CryptoCurrencyNetwork.test), @@ -83,6 +84,7 @@ final List _supportedCoins = List.unmodifiable([ Litecoin(CryptoCurrencyNetwork.test), Peercoin(CryptoCurrencyNetwork.test), Stellar(CryptoCurrencyNetwork.test), + Xelis(CryptoCurrencyNetwork.test), ]); final ({String from, String to}) _swapDefaults = (from: "BTC", to: "XMR"); diff --git a/scripts/app_config/templates/pubspec.template b/scripts/app_config/templates/pubspec.template index c52440856..26d28185a 100644 --- a/scripts/app_config/templates/pubspec.template +++ b/scripts/app_config/templates/pubspec.template @@ -30,6 +30,11 @@ dependencies: frostdart: path: ./crypto_plugins/frostdart + xelis_flutter: + path: ./crypto_plugins/xelis_flutter + + xelis_dart_sdk: ^0.24.0 + flutter_libsparkmobile: git: url: https://github.com/cypherstack/flutter_libsparkmobile.git diff --git a/scripts/ios/build_all.sh b/scripts/ios/build_all.sh index abebdfdb8..013346c9b 100755 --- a/scripts/ios/build_all.sh +++ b/scripts/ios/build_all.sh @@ -16,9 +16,10 @@ rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) +set_rust_to_1840 +(cd ../../crypto_plugins/xelis_flutter/scripts/ios && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) -(cd ../../crypto_plugins/xelis_flutter/scripts/ios && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/ios/build_all_campfire.sh b/scripts/ios/build_all_campfire.sh index abebdfdb8..013346c9b 100755 --- a/scripts/ios/build_all_campfire.sh +++ b/scripts/ios/build_all_campfire.sh @@ -16,9 +16,10 @@ rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) +set_rust_to_1840 +(cd ../../crypto_plugins/xelis_flutter/scripts/ios && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) -(cd ../../crypto_plugins/xelis_flutter/scripts/ios && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/ios/build_all_duo.sh b/scripts/ios/build_all_duo.sh index 2dd4d30ee..02045eb26 100755 --- a/scripts/ios/build_all_duo.sh +++ b/scripts/ios/build_all_duo.sh @@ -18,9 +18,10 @@ rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) +set_rust_to_1840 +(cd ../../crypto_plugins/xelis_flutter/scripts/ios && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) -(cd ../../crypto_plugins/xelis_flutter/scripts/ios && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/linux/build_all.sh b/scripts/linux/build_all.sh index 16de64450..746bfd880 100755 --- a/scripts/linux/build_all.sh +++ b/scripts/linux/build_all.sh @@ -14,9 +14,10 @@ mkdir -p build ./build_secure_storage_deps.sh (cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) +set_rust_to_1840 +(cd ../../crypto_plugins/xelis_flutter/scripts/linux && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) -(cd ../../crypto_plugins/xelis_flutter/scripts/linux && ./build_all.sh ) ./build_secp256k1.sh diff --git a/scripts/linux/build_all_campfire.sh b/scripts/linux/build_all_campfire.sh index 16de64450..746bfd880 100755 --- a/scripts/linux/build_all_campfire.sh +++ b/scripts/linux/build_all_campfire.sh @@ -14,9 +14,10 @@ mkdir -p build ./build_secure_storage_deps.sh (cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) +set_rust_to_1840 +(cd ../../crypto_plugins/xelis_flutter/scripts/linux && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) -(cd ../../crypto_plugins/xelis_flutter/scripts/linux && ./build_all.sh ) ./build_secp256k1.sh diff --git a/scripts/linux/build_all_duo.sh b/scripts/linux/build_all_duo.sh index a57cc7f91..1fa5419c5 100755 --- a/scripts/linux/build_all_duo.sh +++ b/scripts/linux/build_all_duo.sh @@ -16,9 +16,10 @@ mkdir -p build ./build_secure_storage_deps.sh & (cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) +set_rust_to_1840 +(cd ../../crypto_plugins/xelis_flutter/scripts/linux && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) -(cd ../../crypto_plugins/xelis_flutter/scripts/linux && ./build_all.sh ) ./build_secp256k1.sh diff --git a/scripts/macos/build_all.sh b/scripts/macos/build_all.sh index 02d45501b..6f612b822 100755 --- a/scripts/macos/build_all.sh +++ b/scripts/macos/build_all.sh @@ -8,9 +8,10 @@ set_rust_to_1671 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) +set_rust_to_1840 +(cd ../../crypto_plugins/xelis_flutter/scripts/macos && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) -(cd ../../crypto_plugins/xelis_flutter/scripts/macos && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/macos/build_all_campfire.sh b/scripts/macos/build_all_campfire.sh index 02d45501b..6f612b822 100755 --- a/scripts/macos/build_all_campfire.sh +++ b/scripts/macos/build_all_campfire.sh @@ -8,9 +8,10 @@ set_rust_to_1671 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) +set_rust_to_1840 +(cd ../../crypto_plugins/xelis_flutter/scripts/macos && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) -(cd ../../crypto_plugins/xelis_flutter/scripts/macos && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/macos/build_all_duo.sh b/scripts/macos/build_all_duo.sh index 2e309ad12..387020650 100755 --- a/scripts/macos/build_all_duo.sh +++ b/scripts/macos/build_all_duo.sh @@ -10,9 +10,10 @@ set_rust_to_1671 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) +set_rust_to_1840 +(cd ../../crypto_plugins/xelis_flutter/scripts/macos && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) -(cd ../../crypto_plugins/xelis_flutter/scripts/macos && ./build_all.sh ) wait echo "Done building" diff --git a/scripts/rust_version.sh b/scripts/rust_version.sh index 8cda1229b..ac553f969 100755 --- a/scripts/rust_version.sh +++ b/scripts/rust_version.sh @@ -16,4 +16,13 @@ set_rust_to_1720() { echo "Rust version 1.72.0 is not installed. Please install it using 'rustup install 1.72.0'." >&2 exit 1 fi +} + +set_rust_to_1840() { + if rustup toolchain list | grep -q "1.84.0"; then + rustup default 1.84.0 + else + echo "Rust version 1.84.0 is not installed. Please install it using 'rustup install 1.84.0'." >&2 + exit 1 + fi } \ No newline at end of file diff --git a/scripts/windows/build_all.sh b/scripts/windows/build_all.sh index 8b8a3e822..498e95b75 100755 --- a/scripts/windows/build_all.sh +++ b/scripts/windows/build_all.sh @@ -9,9 +9,10 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) +set_rust_to_1840 +(cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) -(cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_campfire.sh b/scripts/windows/build_all_campfire.sh index 8b8a3e822..6eb31ac04 100755 --- a/scripts/windows/build_all_campfire.sh +++ b/scripts/windows/build_all_campfire.sh @@ -9,8 +9,9 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) -set_rust_to_1720 +set_rust_to_1840 (cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_duo.sh b/scripts/windows/build_all_duo.sh index fe05ba659..5b5b0772a 100755 --- a/scripts/windows/build_all_duo.sh +++ b/scripts/windows/build_all_duo.sh @@ -11,8 +11,9 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) -set_rust_to_1720 +set_rust_to_1840 (cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 74ef33c4e..eca37870c 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -20,6 +20,7 @@ #include #include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { CameraWindowsRegisterWithRegistrar( @@ -50,4 +51,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("UrlLauncherWindows")); WindowSizePluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("WindowSizePlugin")); + XelisFlutterPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("XelisFlutterPluginCApi")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 2f370e685..4c59517d9 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -17,6 +17,7 @@ list(APPEND FLUTTER_PLUGIN_LIST stack_wallet_backup url_launcher_windows window_size + xelis_flutter ) list(APPEND FLUTTER_FFI_PLUGIN_LIST From 96478de9cce1fbb16128632f9cbc6bcc4859691e Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 6 Feb 2025 04:36:55 -0800 Subject: [PATCH 05/50] gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9b2706bb0..aa0b3b8a8 100644 --- a/.gitignore +++ b/.gitignore @@ -107,3 +107,4 @@ scripts/linux/build/libsecret/subprojects/gi-docgen/.meson-subproject-wrap-hash. crypto_plugins/cs_monero/built_outputs crypto_plugins/cs_monero/build +crypto_plugins/*.diff From 24a20238bccc2881d4a395360647a9e00c793d50 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Tue, 11 Feb 2025 22:21:07 -0800 Subject: [PATCH 06/50] Xelis base integration --- .gitignore | 4 + crypto_plugins/xelis_flutter | 2 +- flutter_01.png | 0 lib/main.dart | 16 + ...w_wallet_recovery_phrase_warning_view.dart | 228 +++++ .../restore_view_only_wallet_view.dart | 5 + .../restore_wallet_view.dart | 14 +- .../verify_recovery_phrase_view.dart | 5 + .../helpers/restore_create_backup.dart | 5 + .../my_stack_view/wallet_summary_table.dart | 4 +- .../xelis_table_progress_provider.dart | 69 ++ lib/providers/providers.dart | 1 + lib/utilities/test_node_connection.dart | 23 + lib/wallets/crypto_currency/coins/xelis.dart | 16 +- lib/wallets/models/tx_data.dart | 12 + lib/wallets/wallet/impl/xelis_wallet.dart | 786 ++++++++++++------ .../intermediate/cryptonote_wallet.dart | 3 +- .../wallet/intermediate/external_wallet.dart | 12 + .../intermediate/lib_monero_wallet.dart | 1 + .../wallet/intermediate/lib_xelis_wallet.dart | 563 +++++++++++++ lib/wallets/wallet/wallet.dart | 4 +- lib/widgets/xelis_table_progress.dart | 77 ++ pubspec.lock | 12 +- .../app_config/templates/linux/CMakeLists.txt | 3 + scripts/app_config/templates/pubspec.template | 9 +- .../templates/windows/CMakeLists.txt | 4 + 26 files changed, 1613 insertions(+), 265 deletions(-) create mode 100644 flutter_01.png create mode 100644 lib/providers/progress_report/xelis_table_progress_provider.dart create mode 100644 lib/wallets/wallet/intermediate/external_wallet.dart create mode 100644 lib/wallets/wallet/intermediate/lib_xelis_wallet.dart create mode 100644 lib/widgets/xelis_table_progress.dart diff --git a/.gitignore b/.gitignore index aa0b3b8a8..5e86f725e 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,10 @@ secp256k1.dll /lib/app_config.g.dart /android/app/src/main/app_icon-playstore.png +# Dart generated files (Freezed, Riverpod, GoRouter etc..) +lib/**/*.g.dart +lib/**/*.freezed.dart + ## other generated project files pubspec.yaml diff --git a/crypto_plugins/xelis_flutter b/crypto_plugins/xelis_flutter index e93337c26..2a3824490 160000 --- a/crypto_plugins/xelis_flutter +++ b/crypto_plugins/xelis_flutter @@ -1 +1 @@ -Subproject commit e93337c262580665ffb0d16cfcd8d3614f7e371a +Subproject commit 2a382449090daac64a15434b6e802d6e06d30502 diff --git a/flutter_01.png b/flutter_01.png new file mode 100644 index 000000000..e69de29bb diff --git a/lib/main.dart b/lib/main.dart index fde2ce42a..45a1fff18 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -74,15 +74,31 @@ import 'wallets/isar/providers/all_wallets_info_provider.dart'; import 'wallets/wallet/wallet_mixin_interfaces/spark_interface.dart'; import 'widgets/crypto_notifications.dart'; +import 'package:xelis_flutter/src/frb_generated.dart' as xelis_rust; +import 'package:xelis_flutter/src/api/api.dart' as xelis_api; + final openedFromSWBFileStringStateProvider = StateProvider((ref) => null); +void startListeningToRustLogs() { + xelis_api.createLogStream().listen((logEntry) { + print("[Rust Log] [${logEntry.level}] ${logEntry.tag}: ${logEntry.msg}"); + }, onError: (e) { + print("Error receiving Rust logs: $e"); + }); +} + // main() is the entry point to the app. It initializes Hive (local database), // runs the MyApp widget and checks for new users, caching the value in the // miscellaneous box for later use void main(List args) async { + // talker.info('initializing Rust lib ...'); + await xelis_rust.RustLib.init(); WidgetsFlutterBinding.ensureInitialized(); + await xelis_api.setUpRustLogger(); + startListeningToRustLogs(); + if (Util.isDesktop && args.length == 2 && args.first == "-d") { StackFileSystem.setDesktopOverrideDir(args.last); } diff --git a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart index 1ab649f26..9d6b7fdf0 100644 --- a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart +++ b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart @@ -40,6 +40,7 @@ import '../../../widgets/desktop/desktop_scaffold.dart'; import '../../../widgets/rounded_container.dart'; import '../../../widgets/rounded_white_container.dart'; import '../../../widgets/stack_dialog.dart'; +import '../../../widgets/xelis_table_progress.dart'; import '../new_wallet_options/new_wallet_options_view.dart'; import '../new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart'; import 'recovery_phrase_explanation_dialog.dart'; @@ -103,6 +104,233 @@ class _NewWalletRecoveryPhraseWarningViewState ); } } + + // () async { + // try { + // unawaited( + // showDialog( + // context: context, + // barrierDismissible: false, + // useSafeArea: true, + // builder: (ctx) { + // return Center( + // child: Column( + // mainAxisSize: MainAxisSize.min, + // children: [ + // const LoadingIndicator( + // width: 50, + // height: 50, + // ), + // if (widget.coin is Xelis) ...[ + // const SizedBox(height: 16), + // const XelisTableProgress(), + // ], + // ], + // ), + // ); + // }, + // ), + // ); + // String? otherDataJsonString; + // if (widget.coin is Tezos) { + // otherDataJsonString = jsonEncode({ + // WalletInfoKeys + // .tezosDerivationPath: + // Tezos.standardDerivationPath + // .value, + // }); + // // }//todo: probably not needed (broken anyways) + // // else if (widget.coin is Epiccash) { + // // final int secondsSinceEpoch = + // // DateTime.now().millisecondsSinceEpoch ~/ 1000; + // // const int epicCashFirstBlock = 1565370278; + // // const double overestimateSecondsPerBlock = 61; + // // int chosenSeconds = secondsSinceEpoch - epicCashFirstBlock; + // // int approximateHeight = chosenSeconds ~/ overestimateSecondsPerBlock; + // // / + // // // debugPrint( + // // // "approximate height: $approximateHeight chosen_seconds: $chosenSeconds"); + // // height = approximateHeight; + // // if (height < 0) { + // // height = 0; + // // } + // // + // // otherDataJsonString = jsonEncode( + // // { + // // WalletInfoKeys.epiccashData: jsonEncode( + // // ExtraEpiccashWalletInfo( + // // receivingIndex: 0, + // // changeIndex: 0, + // // slatesToAddresses: {}, + // // slatesToCommits: {}, + // // lastScannedBlock: epicCashFirstBlock, + // // restoreHeight: height, + // // creationHeight: height, + // // ).toMap(), + // // ), + // // }, + // // ); + // } else if (widget.coin is Firo) { + // otherDataJsonString = jsonEncode( + // { + // WalletInfoKeys + // .lelantusCoinIsarRescanRequired: + // false, + // }, + // ); + // } + + // final info = WalletInfo.createNew( + // coin: widget.coin, + // name: widget.walletName, + // otherDataJsonString: + // otherDataJsonString, + // ); + + // var node = ref + // .read( + // nodeServiceChangeNotifierProvider, + // ) + // .getPrimaryNodeFor( + // currency: coin, + // ); + + // if (node == null) { + // node = coin.defaultNode; + // await ref + // .read( + // nodeServiceChangeNotifierProvider, + // ) + // .setPrimaryNodeFor( + // coin: coin, + // node: node, + // ); + // } + + // final txTracker = + // TransactionNotificationTracker( + // walletId: info.walletId, + // ); + + // int? wordCount; + // String? mnemonicPassphrase; + // String? mnemonic; + // String? privateKey; + + // wordCount = info + // .coin.defaultSeedPhraseLength; + + // // TODO: Refactor these to generate each coin in their respective classes + // // This code should not be in a random view page file + // if (coin is Monero || + // coin is Wownero || + // coin is Xelis) { + // // currently a special case due to the + // // xmr/wow/xelis libraries handling their + // // own mnemonic generation + // } else if (wordCount > 0) { + // if (ref + // .read( + // pNewWalletOptions.state, + // ) + // .state != + // null) { + // if (coin + // .hasMnemonicPassphraseSupport) { + // mnemonicPassphrase = ref + // .read( + // pNewWalletOptions.state, + // ) + // .state! + // .mnemonicPassphrase; + // } else { + // // this may not be epiccash specific? + // if (coin is Epiccash) { + // mnemonicPassphrase = ""; + // } + // } + + // wordCount = ref + // .read( + // pNewWalletOptions.state, + // ) + // .state! + // .mnemonicWordsCount; + // } else { + // mnemonicPassphrase = ""; + // } + + // if (wordCount < 12 || + // 24 < wordCount || + // wordCount % 3 != 0) { + // throw Exception( + // "Invalid word count", + // ); + // } + + // final strength = + // (wordCount ~/ 3) * 32; + + // mnemonic = bip39.generateMnemonic( + // strength: strength, + // ); + // } + + // final wallet = await Wallet.create( + // walletInfo: info, + // mainDB: ref.read(mainDBProvider), + // secureStorageInterface: + // ref.read(secureStoreProvider), + // nodeService: ref.read( + // nodeServiceChangeNotifierProvider, + // ), + // prefs: ref.read( + // prefsChangeNotifierProvider, + // ), + // mnemonicPassphrase: + // mnemonicPassphrase, + // mnemonic: mnemonic, + // privateKey: privateKey, + // ); + + // await wallet.init(); + + // // pop progress dialog + // if (context.mounted) { + // Navigator.pop(context); + // } + // // set checkbox back to unchecked to annoy users to agree again :P + // ref + // .read( + // checkBoxStateProvider.state, + // ) + // .state = false; + + // if (context.mounted) { + // final nav = Navigator.of(context); + // unawaited( + // nav.pushNamed( + // NewWalletRecoveryPhraseView + // .routeName, + // arguments: Tuple2( + // wallet, + // await (wallet + // as MnemonicInterface) + // .getMnemonicAsWords(), + // ), + // ), + // ); + // } + // } catch (e, s) { + // Logging.instance.log( + // "$e\n$s", + // level: LogLevel.Fatal, + // ); + // // TODO: handle gracefully + // // any network/socket exception here will break new wallet creation + // rethrow; + // } + // } } Future<(Wallet, List)> _initNewFuture() async { diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart index 3a7131762..9123b2f46 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart @@ -31,6 +31,7 @@ import '../../../wallets/isar/models/wallet_info.dart'; import '../../../wallets/wallet/impl/epiccash_wallet.dart'; import '../../../wallets/wallet/impl/monero_wallet.dart'; import '../../../wallets/wallet/impl/wownero_wallet.dart'; +import '../../../wallets/wallet/impl/xelis_wallet.dart'; import '../../../wallets/wallet/wallet.dart'; import '../../../wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart'; import '../../../widgets/custom_buttons/app_bar_icon_button.dart'; @@ -264,6 +265,10 @@ class _RestoreViewOnlyWalletViewState await (wallet as WowneroWallet).init(isRestore: true); break; + case const (XelisWallet): + await (wallet as XelisWallet).init(isRestore: true); + break; + default: await wallet.init(); } diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart index a5aec4d97..b70c2afcf 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart @@ -49,6 +49,7 @@ import '../../../wallets/wallet/impl/epiccash_wallet.dart'; import '../../../wallets/wallet/impl/monero_wallet.dart'; import '../../../wallets/wallet/impl/wownero_wallet.dart'; import '../../../wallets/wallet/intermediate/lib_monero_wallet.dart'; +import '../../../wallets/wallet/impl/xelis_wallet.dart'; import '../../../wallets/wallet/supporting/epiccash_wallet_info_extension.dart'; import '../../../wallets/wallet/wallet.dart'; import '../../../widgets/custom_buttons/app_bar_icon_button.dart'; @@ -199,6 +200,10 @@ class _RestoreWalletViewState extends ConsumerState { ); return wowneroWordList.contains(word); } + // TODO: use Xelis word list + if (widget.coin is Xelis) { + return true; + } return _wordListHashSet.contains(word); } @@ -283,10 +288,9 @@ class _RestoreWalletViewState extends ConsumerState { ); } - // TODO: do actual check to make sure it is a valid mnemonic for monero + // TODO: do actual check to make sure it is a valid mnemonic for monero + xelis if (bip39.validateMnemonic(mnemonic) == false && - !(widget.coin is Monero || widget.coin is Wownero)) { - if (mounted) setState(() => _hideSeedWords = false); + !(widget.coin is Monero || widget.coin is Wownero || widget.coin is Xelis)) { unawaited( showFloatingFlushBar( type: FlushBarType.warning, @@ -371,6 +375,10 @@ class _RestoreWalletViewState extends ConsumerState { await (wallet as WowneroWallet).init(isRestore: true); break; + case const (XelisWallet): + await (wallet as XelisWallet).init(isRestore: true); + break; + default: await wallet.init(); } diff --git a/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart b/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart index b1f5613bb..04dc94d33 100644 --- a/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart +++ b/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart @@ -40,6 +40,7 @@ import '../../../wallets/isar/providers/wallet_info_provider.dart'; import '../../../wallets/wallet/impl/epiccash_wallet.dart'; import '../../../wallets/wallet/impl/monero_wallet.dart'; import '../../../wallets/wallet/impl/wownero_wallet.dart'; +import '../../../wallets/wallet/impl/xelis_wallet.dart'; import '../../../wallets/wallet/intermediate/lib_monero_wallet.dart'; import '../../../wallets/wallet/wallet.dart'; import '../../../wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart'; @@ -225,6 +226,10 @@ class _VerifyRecoveryPhraseViewState await (voWallet as WowneroWallet).init(isRestore: true); break; + case const (XelisWallet): + await (voWallet as XelisWallet).init(isRestore: true); + break; + default: await voWallet.init(); } diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart index 935dad27b..b6e872bd4 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart @@ -55,6 +55,7 @@ import '../../../../../wallets/wallet/impl/bitcoin_frost_wallet.dart'; import '../../../../../wallets/wallet/impl/epiccash_wallet.dart'; import '../../../../../wallets/wallet/impl/monero_wallet.dart'; import '../../../../../wallets/wallet/impl/wownero_wallet.dart'; +import '../../../../../wallets/wallet/impl/xelis_wallet.dart'; import '../../../../../wallets/wallet/intermediate/lib_monero_wallet.dart'; import '../../../../../wallets/wallet/wallet.dart'; import '../../../../../wallets/wallet/wallet_mixin_interfaces/mnemonic_interface.dart'; @@ -506,6 +507,10 @@ abstract class SWB { case const (WowneroWallet): await (wallet as WowneroWallet).init(isRestore: true); break; + + case const (XelisWallet): + await (wallet as XelisWallet).init(isRestore: true); + break; default: await wallet.init(); diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart b/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart index 5df82cc0f..066ae9073 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_summary_table.dart @@ -25,7 +25,7 @@ import '../../utilities/text_styles.dart'; import '../../utilities/util.dart'; import '../../wallets/crypto_currency/crypto_currency.dart'; import '../../wallets/isar/providers/all_wallets_info_provider.dart'; -import '../../wallets/wallet/intermediate/lib_monero_wallet.dart'; +import '../../wallets/wallet/intermediate/external_wallet.dart'; import '../../widgets/breathing.dart'; import '../../widgets/conditional_parent.dart'; import '../../widgets/desktop/desktop_dialog.dart'; @@ -138,7 +138,7 @@ class _DesktopWalletSummaryRowState } final Future loadFuture; - if (wallet is LibMoneroWallet) { + if (wallet is ExternalWallet) { loadFuture = wallet.init().then((value) async => await (wallet).open()); } else { diff --git a/lib/providers/progress_report/xelis_table_progress_provider.dart b/lib/providers/progress_report/xelis_table_progress_provider.dart new file mode 100644 index 000000000..5f57dca29 --- /dev/null +++ b/lib/providers/progress_report/xelis_table_progress_provider.dart @@ -0,0 +1,69 @@ +import 'package:xelis_flutter/src/api/api.dart' as xelis_api; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +enum XelisTableGenerationStep { + t1PointsGeneration, + t1CuckooSetup, + t2Table, + unknown; + + factory XelisTableGenerationStep.fromString(String step) { + return switch (step) { + "T1PointsGeneration" => XelisTableGenerationStep.t1PointsGeneration, + "T1CuckooSetup" => XelisTableGenerationStep.t1CuckooSetup, + "T2Table" => XelisTableGenerationStep.t2Table, + _ => XelisTableGenerationStep.unknown, + }; + } + + String get displayName => switch (this) { + t1PointsGeneration => "Generating T1 Points", + t1CuckooSetup => "Setting up T1 Cuckoo", + t2Table => "Generating T2 Table", + unknown => "Processing", + }; +} + +class XelisTableProgressState { + final double? tableProgress; + final XelisTableGenerationStep currentStep; + + const XelisTableProgressState({ + this.tableProgress, + this.currentStep = XelisTableGenerationStep.unknown, + }); + + XelisTableProgressState copyWith({ + double? tableProgress, + XelisTableGenerationStep? currentStep, + }) { + return XelisTableProgressState( + tableProgress: tableProgress ?? this.tableProgress, + currentStep: currentStep ?? this.currentStep, + ); + } +} + +final xelisTableProgressProvider = StreamProvider((ref) { + return xelis_api.createProgressReportStream().map((report) { + return report.when( + tableGeneration: (progress, step, _) { + final currentStep = XelisTableGenerationStep.fromString(step); + final stepIndex = switch(currentStep) { + XelisTableGenerationStep.t1PointsGeneration => 0, + XelisTableGenerationStep.t1CuckooSetup => 1, + XelisTableGenerationStep.t2Table => 2, + XelisTableGenerationStep.unknown => 0, + }; + + final totalProgress = (stepIndex * 0.5) + (progress * 0.5); + + return XelisTableProgressState( + tableProgress: totalProgress, + currentStep: currentStep, + ); + }, + misc: (_) => const XelisTableProgressState(), + ); + }); +}); \ No newline at end of file diff --git a/lib/providers/providers.dart b/lib/providers/providers.dart index a96a9869c..e6e9ef20b 100644 --- a/lib/providers/providers.dart +++ b/lib/providers/providers.dart @@ -32,3 +32,4 @@ export './ui/verify_recovery_phrase/correct_word_provider.dart'; export './ui/verify_recovery_phrase/random_index_provider.dart'; export './ui/verify_recovery_phrase/selected_word_provider.dart'; export './wallet/transaction_note_provider.dart'; +export './progress_report/xelis_table_progress_provider.dart'; diff --git a/lib/utilities/test_node_connection.dart b/lib/utilities/test_node_connection.dart index b212d3a0a..8df98eab5 100644 --- a/lib/utilities/test_node_connection.dart +++ b/lib/utilities/test_node_connection.dart @@ -26,6 +26,9 @@ import 'test_monero_node_connection.dart'; import 'test_stellar_node_connection.dart'; import 'tor_plain_net_option_enum.dart'; +import 'package:logging/logging.dart' as std_logging; +import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk; + Future _xmrHelper( NodeFormData nodeFormData, BuildContext context, @@ -297,6 +300,26 @@ Future testNodeConnection({ testPassed = false; } break; + + case Xelis(): + try { + final daemon = xelis_sdk.DaemonClient( + endPoint: formData.host!, + secureWebSocket: formData.useSSL ?? false, + ); + daemon.connect(); + + final xelis_sdk.GetInfoResult networkInfo = await daemon.getInfo(); + testPassed = networkInfo.height != null; + + Logging.instance.log( + "Xelis testNodeConnection result: \"${networkInfo.toString()}\"", + level: LogLevel.Info, + ); + } catch (e, s) { + testPassed = false; + } + break; } return testPassed; diff --git a/lib/wallets/crypto_currency/coins/xelis.dart b/lib/wallets/crypto_currency/coins/xelis.dart index 84e8439bb..1f57b2afb 100644 --- a/lib/wallets/crypto_currency/coins/xelis.dart +++ b/lib/wallets/crypto_currency/coins/xelis.dart @@ -3,11 +3,11 @@ import '../../../models/node_model.dart'; import '../../../utilities/default_nodes.dart'; import '../../../utilities/enums/derive_path_type_enum.dart'; import '../crypto_currency.dart'; -import '../intermediate/bip39_currency.dart'; +import '../intermediate/electrum_currency.dart'; import 'package:xelis_flutter/src/api/utils.dart' as x_utils; -class Xelis extends CryptoCurrency { +class Xelis extends ElectrumCurrency { Xelis(super.network) { _idMain = "xelis"; _uriScheme = "xelis"; @@ -50,7 +50,7 @@ class Xelis extends CryptoCurrency { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( - host: "https://us-node.xelis.io", + host: "us-node.xelis.io", port: 443, name: DefaultNodes.defaultName, id: DefaultNodes.buildId(this), @@ -65,7 +65,7 @@ class Xelis extends CryptoCurrency { case CryptoCurrencyNetwork.test: return NodeModel( - host: "https://testnet-node.xelis.io", + host: "testnet-node.xelis.io", port: 443, name: DefaultNodes.defaultName, id: DefaultNodes.buildId(this), @@ -84,7 +84,7 @@ class Xelis extends CryptoCurrency { } @override - int get minConfirms => 20; + int get minConfirms => 1; @override bool get torSupport => true; @@ -102,10 +102,10 @@ class Xelis extends CryptoCurrency { String get genesisHash => throw UnimplementedError(); @override - int get defaultSeedPhraseLength => 12; + int get defaultSeedPhraseLength => 25; @override - int get fractionDigits => 9; + int get fractionDigits => 8; @override bool get hasBuySupport => false; @@ -114,7 +114,7 @@ class Xelis extends CryptoCurrency { bool get hasMnemonicPassphraseSupport => false; @override - List get possibleMnemonicLengths => [defaultSeedPhraseLength, 24]; + List get possibleMnemonicLengths => [defaultSeedPhraseLength]; @override AddressType get defaultAddressType => defaultDerivePathType.getAddressType(); diff --git a/lib/wallets/models/tx_data.dart b/lib/wallets/models/tx_data.dart index 21fa206c9..b8839fe3d 100644 --- a/lib/wallets/models/tx_data.dart +++ b/lib/wallets/models/tx_data.dart @@ -74,6 +74,9 @@ class TxData { final List? sparkMints; final List? usedSparkCoins; + // xelis specific + final String? otherData; + final TransactionV2? tempTx; final bool ignoreCachedBalanceChecks; @@ -113,6 +116,7 @@ class TxData { this.mintsMapLelantus, this.tezosOperationsList, this.sparkRecipients, + this.otherData, this.sparkMints, this.usedSparkCoins, this.tempTx, @@ -142,6 +146,11 @@ class TxData { return null; } + String? get getOtherData { + final val = this.otherData; + return val; + } + Amount? get amountSpark => sparkRecipients != null && sparkRecipients!.isNotEmpty ? sparkRecipients! @@ -213,6 +222,7 @@ class TxData { String? note, String? noteOnChain, String? memo, + String? otherData, Set? utxos, List? usedUTXOs, List? recipients, @@ -258,6 +268,7 @@ class TxData { note: note ?? this.note, noteOnChain: noteOnChain ?? this.noteOnChain, memo: memo ?? this.memo, + otherData: otherData ?? this.otherData, utxos: utxos ?? this.utxos, usedUTXOs: usedUTXOs ?? this.usedUTXOs, recipients: recipients ?? this.recipients, @@ -321,6 +332,7 @@ class TxData { 'sparkRecipients: $sparkRecipients, ' 'sparkMints: $sparkMints, ' 'usedSparkCoins: $usedSparkCoins, ' + 'otherData: $otherData, ' 'tempTx: $tempTx, ' 'ignoreCachedBalanceChecks: $ignoreCachedBalanceChecks, ' 'opNameState: $opNameState, ' diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index c21100625..b14ef7cc2 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -10,71 +10,45 @@ import 'package:xelis_flutter/src/api/network.dart' as x_network; import 'package:xelis_flutter/src/api/wallet.dart' as x_wallet; import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk; +import 'package:path_provider/path_provider.dart'; +import 'package:path/path.dart' as path; + +import '../intermediate/lib_xelis_wallet.dart'; + +import '../../../utilities/stack_file_system.dart'; import '../../../models/isar/models/blockchain_data/address.dart'; import '../../../models/isar/models/blockchain_data/transaction.dart'; import '../../../models/isar/models/blockchain_data/v2/input_v2.dart'; import '../../../models/isar/models/blockchain_data/v2/output_v2.dart'; import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart'; +import '../../../services/event_bus/events/global/blocks_remaining_event.dart'; +import '../../../services/event_bus/events/global/refresh_percent_changed_event.dart'; +import '../../../services/event_bus/events/global/tor_connection_status_changed_event.dart'; +import '../../../services/event_bus/events/global/tor_status_changed_event.dart'; +import '../../../services/event_bus/events/global/updated_in_background_event.dart'; +import '../../../services/event_bus/events/global/wallet_sync_status_changed_event.dart'; +import '../../../services/event_bus/global_event_bus.dart'; + import '../../../models/node_model.dart'; +import '../../../models/paymint/fee_object_model.dart'; import '../../../models/balance.dart'; import '../../../utilities/amount/amount.dart'; +import '../../../utilities/logger.dart'; import '../../crypto_currency/crypto_currency.dart'; import '../../models/tx_data.dart'; import '../wallet.dart'; +import '../../../providers/providers.dart'; + import 'package:isar/isar.dart'; import 'package:mutex/mutex.dart'; import 'package:stack_wallet_backup/generate_password.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; -import '../intermediate/bip39_wallet.dart'; - -extension XelisNetworkConversion on CryptoCurrencyNetwork { - x_network.Network get xelisNetwork { - switch (this) { - case CryptoCurrencyNetwork.main: - return x_network.Network.mainnet; - case CryptoCurrencyNetwork.test: - return x_network.Network.testnet; - default: - throw ArgumentError('Unsupported network type for Xelis: $this'); - } - } -} - -extension CryptoCurrencyNetworkConversion on x_network.Network { - CryptoCurrencyNetwork get cryptoCurrencyNetwork { - switch (this) { - case x_network.Network.mainnet: - return CryptoCurrencyNetwork.main; - case x_network.Network.testnet: - return CryptoCurrencyNetwork.test; - default: - throw ArgumentError('Unsupported Xelis network type: $this'); - } - } -} - -class XelisWallet extends Wallet { - x_wallet.XelisWallet? _wallet; - - x_wallet.XelisWallet? get wallet => _wallet; - set wallet(x_wallet.XelisWallet newWallet) { - _wallet = newWallet; - } - - void _checkInitialized() { - if (_wallet == null) { - throw StateError('XelisWallet not initialized'); - } - } +import '../intermediate/lib_xelis_wallet.dart'; +class XelisWallet extends LibXelisWallet { XelisWallet(CryptoCurrencyNetwork network) : super(Xelis(network)); - - final syncMutex = Mutex(); - NodeModel? _xelisNode; - Timer? timer; - // ==================== Overrides ============================================ @override @@ -82,145 +56,226 @@ class XelisWallet extends Wallet { @override Future init({bool? isRestore}) async { - if (isRestore != true) { - x_wallet.PrecomputedTablesShared? encodedTables = - await secureStorageInterface.read(key: "xelis_precomputed_tables"); + debugPrint("Xelis: init"); + + // final progressState = ref.read(xelisTableProgressProvider); + // if (progressState.hasValue && + // progressState.value?.tableProgress != null && + // progressState.value!.tableProgress! < 1.0) { + // GlobalEventBus.instance.fire( + // WalletSyncStatusChangedEvent( + // WalletSyncStatus.syncing, + // walletId, + // info.coin, + // ), + // ); + + // while ((ref.read(xelisTableProgressProvider).value?.tableProgress ?? 1.0) < 1.0) { + // await Future.delayed(const Duration(milliseconds: 100)); + // } + // } + + if (isRestore == true) { + await _restoreWallet(); + return await super.init(); + } - String? encodedWallet = + String? walletExists = await secureStorageInterface.read(key: "${walletId}_wallet"); - // check if should create a new wallet - if (encodedWallet == null) { - final String password = generatePassword(); + if (walletExists == null) { + await _createNewWallet(); + } - await secureStorageInterface.write( - key: '${walletId}_password', - value: password, - ); + await open(); + await updateTransactions(isRescan: true, topoheight: 0); - final String name = walletId; + return await super.init(); + } - final wallet = await x_wallet.createXelisWallet( - name: name, - password: password, - network: cryptoCurrency.network.xelisNetwork, - seed: null, // Xelis lib will autogenerate this - privateKey: null, // Xelis lib will autogenerate this - precomputedTables: encodedTables, - ); + Future _createNewWallet() async { + final String password = generatePassword(); + + debugPrint("Xelis: storing password"); + await secureStorageInterface.write( + key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), + value: password, + ); + + await secureStorageInterface.write( + key: '${walletId}_wallet', + value: 'true', + ); + + await secureStorageInterface.write( + key: '_${walletId}_needs_creation', + value: 'true', + ); + } - await secureStorageInterface.write( - key: '${walletId}_wallet', - value: wallet, - ); + Future _restoreWallet() async { + final String password = generatePassword(); - _wallet = wallet; - } else { - try { + await secureStorageInterface.write( + key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), + value: password, + ); - final String name = walletId; - final password = - await secureStorageInterface.read(key: '${walletId}_password'); + await secureStorageInterface.write( + key: '${walletId}_wallet', + value: 'true', + ); - final wallet = await x_wallet.openXelisWallet( - name: name, - password: password, - network: cryptoCurrency.network.xelisNetwork, - precomputedTables: encodedTables, - ); + await secureStorageInterface.write( + key: '_${walletId}_needs_restoration', + value: 'true', + ); - await secureStorageInterface.write( - key: '${walletId}_wallet', - value: wallet, - ); + if (libXelisWallet != null) { + await super.exit(); + } + } - _wallet = wallet; - } catch (e, s) { - // do nothing, still allow user into wallet - } - } + @override + Future recover({required bool isRescan}) async { + if (isRescan) { + await refreshMutex.protect(() async { + await mainDB.deleteWalletBlockchainData(walletId); + await updateTransactions(isRescan: true, topoheight: 0); + }); + return; + } - // Creation or Opening of Xelis wallets will generate tables if required - // Make sure to store said shared tables if we make it this far, to save - // time in the future - if (encodedTables == null) { - await secureStorageInterface.write( - key: 'xelis_precomputed_tables', - value: x_wallet.getCachedTable(), - ); - } - } + // Borrowed from libmonero for now, need to refactor for Xelis view keys + // if (isViewOnly) { + // await recoverViewOnly(); + // return; + // } - return await super.init(); + try { + await open(); + } catch (e, s) { + Logging.instance.log( + "Exception rethrown from recoverFromMnemonic(): $e\n$s", + level: LogLevel.Error, + ); + rethrow; + } } + @override Future pingCheck() async { - _checkInitialized(); + checkInitialized(); try { - await _wallet!.getDaemonInfo(); + await libXelisWallet!.getDaemonInfo(); return true; } catch (_) { return false; } } + final _balanceUpdateMutex = Mutex(); + @override - Future updateBalance() async { - try { - final BigInt xelBalance = await _wallet!.getXelisBalanceRaw(); // in the future, use getAssetBalances and handle each - final balance = Balance( - total: Amount( - rawValue: xelBalance, - fractionDigits: cryptoCurrency.fractionDigits, - ), - spendable: Amount( - rawValue: xelBalance, - fractionDigits: cryptoCurrency.fractionDigits, - ), - blockedTotal: Amount.zeroWith( - fractionDigits: cryptoCurrency.fractionDigits, - ), - pendingSpendable: Amount.zeroWith( - fractionDigits: cryptoCurrency.fractionDigits, - ), - ); - await info.updateBalance( - newBalance: balance, - isar: mainDB.isar, - ); - } catch (e, s) { - } + Future updateBalance({int? newBalance}) async { + await _balanceUpdateMutex.protect(() async { + try { + if (await libXelisWallet!.hasXelisBalance()) { + final BigInt xelBalance = newBalance != null + ? BigInt.from(newBalance) + : await libXelisWallet!.getXelisBalanceRaw(); // in the future, use getAssetBalances and handle each + final balance = Balance( + total: Amount( + rawValue: xelBalance, + fractionDigits: cryptoCurrency.fractionDigits, + ), + spendable: Amount( + rawValue: xelBalance, + fractionDigits: cryptoCurrency.fractionDigits, + ), + blockedTotal: Amount.zeroWith( + fractionDigits: cryptoCurrency.fractionDigits, + ), + pendingSpendable: Amount.zeroWith( + fractionDigits: cryptoCurrency.fractionDigits, + ), + ); + await info.updateBalance( + newBalance: balance, + isar: mainDB.isar, + ); + } + } catch (e, s) { + Logging.instance.log( + "Error in updateBalance(): $e\n$s", + level: LogLevel.Warning, + ); + } + }); + } + + Future _fetchChainHeight() async { + final infoString = await libXelisWallet!.getDaemonInfo(); + final Map nodeInfo = json.decode(infoString); + return int.parse(nodeInfo['topoheight'].toString()); } @override - Future updateChainHeight() async { + Future updateChainHeight({int? topoheight}) async { try { - final infoString = await _wallet!.getDaemonInfo(); - - final Map nodeInfo = json.decode(infoString); + final height = topoheight ?? await _fetchChainHeight(); - final int topoheight = nodeInfo['topoheight'] as int; - await info.updateCachedChainHeight( - newHeight: topoheight, + newHeight: height.toInt(), isar: mainDB.isar, ); } catch (e, s) { - print('Error updating chain height: $e'); - print('Stack trace: $s'); + Logging.instance.log( + "Error in updateChainHeight(): $e\n$s", + level: LogLevel.Warning, + ); } } @override Future updateNode() async { - // do nothing + try { + final node = getCurrentNode(); + await libXelisWallet?.offlineMode(); + await libXelisWallet!.onlineMode( + daemonAddress: node.host + ); + } catch (e, s) { + Logging.instance.log( + "Error updating node: $e\n$s", + level: LogLevel.Error, + ); + rethrow; + } } @override - Future> updateTransactions({bool isRescan = false}) async { - _checkInitialized(); + Future> updateTransactions({ + bool isRescan = false, + List? rawTransactions, + int? topoheight, + }) async { + checkInitialized(); + + final newReceivingAddress = await getCurrentReceivingAddress() ?? + Address( + walletId: walletId, + derivationIndex: 0, + derivationPath: null, + value: libXelisWallet!.getAddressStr(), + publicKey: [], + type: AddressType.xelis, + subType: AddressSubType.receiving, + ); + final thisAddress = newReceivingAddress.value; + int firstBlock = 0; if (!isRescan) { firstBlock = await mainDB.isar.transactionV2s @@ -234,17 +289,18 @@ class XelisWallet extends Wallet { // add some buffer firstBlock -= 10; } + } else { + await libXelisWallet!.rescan(topoheight: BigInt.from(topoheight!)); } - await _wallet!.rescan(topoheight: firstBlock as BigInt); - final txListJson = await _wallet!.allHistory(); + final txListJson = rawTransactions ?? await libXelisWallet!.allHistory(); final List txns = []; for (final jsonString in txListJson) { try { final transactionEntry = xelis_sdk.TransactionEntry.fromJson(json.decode(jsonString)); - + // Check for duplicates final storedTx = await mainDB.isar.transactionV2s .where() @@ -259,26 +315,49 @@ class XelisWallet extends Wallet { final List outputs = []; final List inputs = []; - TransactionType txType; + TransactionType? txType; TransactionSubType txSubType = TransactionSubType.none; int? nonce; - Amount? fee; + Amount fee = Amount( + rawValue: BigInt.zero, + fractionDigits: cryptoCurrency.fractionDigits + ); Map otherData = {}; - final entryData = transactionEntry.txEntryType; + final entryType = transactionEntry.txEntryType; - if (entryData is xelis_sdk.CoinbaseEntry) { - final coinbase = entryData; + if (entryType is xelis_sdk.CoinbaseEntry) { + final coinbase = entryType; txType = TransactionType.incoming; + + final int decimals = await libXelisWallet!.getAssetDecimals( + asset: xelis_sdk.xelisAsset + ); + + fee = Amount( + rawValue: BigInt.zero, + fractionDigits: decimals + ); + outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( - scriptPubKeyHex: "00", + scriptPubKeyHex: "", valueStringSats: coinbase.reward.toString(), addresses: [thisAddress], walletOwns: true, )); - } else if (entryData is xelis_sdk.BurnEntry) { - final burn = entryData; + } else if (entryType is xelis_sdk.BurnEntry) { + final burn = entryType; txType = TransactionType.outgoing; + + final int decimals = await libXelisWallet!.getAssetDecimals( + asset: burn.asset + ); + + fee = Amount( + rawValue: BigInt.from(burn.fee), + fractionDigits: decimals + ); + inputs.add(InputV2.isarCantDoRequiredInDefaultConstructor( scriptSigAsm: null, scriptSigHex: null, @@ -292,21 +371,26 @@ class XelisWallet extends Wallet { walletOwns: true, )); otherData['burnAsset'] = burn.asset; - } else if (entryData is xelis_sdk.IncomingEntry) { - final incoming = entryData; + } else if (entryType is xelis_sdk.IncomingEntry) { + final incoming = entryType; txType = incoming.from == thisAddress ? TransactionType.sentToSelf : TransactionType.incoming; for (final transfer in incoming.transfers) { - final int decimals = await _wallet!.getAssetDecimals( + final int decimals = await libXelisWallet!.getAssetDecimals( asset: transfer.asset ); + fee = Amount( + rawValue: BigInt.zero, + fractionDigits: decimals + ); + outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( - scriptPubKeyHex: "00", + scriptPubKeyHex: "", valueStringSats: transfer.amount.toString(), - addresses: [thisAddress], + addresses: [incoming.from], walletOwns: true, )); otherData['asset_${transfer.asset}'] = transfer.amount.toString(); @@ -314,34 +398,41 @@ class XelisWallet extends Wallet { otherData['extraData_${transfer.asset}'] = transfer.extraData!.toJson(); } } - } else if (entryData is xelis_sdk.OutgoingEntry) { - final outgoing = entryData; + } else if (entryType is xelis_sdk.OutgoingEntry) { + final outgoing = entryType; txType = TransactionType.outgoing; nonce = outgoing.nonce; - fee = Amount( - rawValue: BigInt.from(outgoing.fee), - fractionDigits: decimals - ); for (final transfer in outgoing.transfers) { - final int decimals = await _wallet!.getAssetDecimals( + final int decimals = await libXelisWallet!.getAssetDecimals( asset: transfer.asset ); - outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( - scriptPubKeyHex: "00", - valueStringSats: transfer.amount.toString(), + fee = Amount( + rawValue: BigInt.from(outgoing.fee), + fractionDigits: decimals + ); + + inputs.add(InputV2.isarCantDoRequiredInDefaultConstructor( + scriptSigHex: null, + scriptSigAsm: null, + sequence: null, + outpoint: null, addresses: [transfer.destination], - walletOwns: transfer.destination == thisAddress, + valueStringSats: (transfer.amount + outgoing.fee).toString(), + witness: null, + innerRedeemScriptAsm: null, + coinbase: null, + walletOwns: true, )); - otherData['asset_${transfer.asset}'] = transfer.amount.toString(); + otherData['asset_${transfer.asset}_amount'] = transfer.amount.toString(); + otherData['asset_${transfer.asset}_fee'] = fee.toString(); if (transfer.extraData != null) { otherData['extraData_${transfer.asset}'] = transfer.extraData!.toJson(); } } } else { // Skip unknown entry types - return; } final txn = TransactionV2( @@ -354,7 +445,7 @@ class XelisWallet extends Wallet { inputs: List.unmodifiable(inputs), outputs: List.unmodifiable(outputs), version: -1, // Version not provided - type: txType, + type: txType!, subType: txSubType, otherData: jsonEncode({ ...otherData, @@ -363,10 +454,21 @@ class XelisWallet extends Wallet { }), ); + Logging.instance.log( + "Entry done ${entryType.toString()}", + level: LogLevel.Debug, + ); + + txns.add(txn); } catch (e, s) { + Logging.instance.log( + "Error handling tx $jsonString: $e\n$s", + level: LogLevel.Warning, + ); } } + await updateBalance(); await mainDB.updateOrPutTransactionV2s(txns); return txns.map((e) => e.txid).toList(); @@ -392,81 +494,149 @@ class XelisWallet extends Wallet { FilterGroup.and(standardReceivingAddressFilters); @override - Future prepareSend({required TxData txData}) async { - try { - _checkInitialized(); - - // Validate recipients - if (txData.recipients == null || txData.recipients!.length != 1) { - throw Exception("$runtimeType prepareSend requires 1 recipient"); - } - - final recipient = txData.recipients!.first; - final Amount sendAmount = recipient.amount; - final asset = cryptoCurrency.assetId ?? xelis_sdk.xelisAsset; + Future get fees async { + // TODO: implement _getFees... maybe + return FeeObject( + numberOfBlocksFast: 10, + numberOfBlocksAverage: 10, + numberOfBlocksSlow: 10, + fast: 1, + medium: 1, + slow: 1, + ); + } - final sendAmountStr = await _wallet!.formatCoin( - atomicAmount: sendAmount.rawValue, - assetHash: asset + @override + Future prepareSend({required TxData txData, String? assetId}) async { + try { + checkInitialized(); + + // Use default address if recipients list is empty + final recipients = txData.recipients?.isNotEmpty == true + ? txData.recipients! + : [( + address: 'xel:xz9574c80c4xegnvurazpmxhw5dlg2n0g9qm60uwgt75uqyx3pcsqzzra9m', + amount: Amount.zeroWith( + fractionDigits: cryptoCurrency.fractionDigits, + ), + isChange: false + )]; + + final asset = assetId ?? xelis_sdk.xelisAsset; + + // Calculate total send amount + final totalSendAmount = recipients.fold( + Amount(rawValue: BigInt.zero, fractionDigits: cryptoCurrency.fractionDigits), + (sum, recipient) => sum + recipient.amount ); // Check balance using raw method - final xelBalance = await _wallet!.getXelisBalanceRaw(); + final xelBalance = await libXelisWallet!.getXelisBalanceRaw(); final balance = Amount( rawValue: xelBalance, - fractionDigits: cryptoCurrency.fractionDigits, // needs to become tied to asset - ); - - // Create transfers for fee estimation - final transfers = [ - x_wallet.Transfer( - floatAmount: sendAmountStr as double, - strAddress: recipient.address, - assetHash: asset, - ) - ]; - - // Estimate fees - final estimatedFeeString = await _wallet!.estimateFees(transfers: transfers); - final feeAmount = Amount( - rawValue: BigInt.parse(estimatedFeeString), fractionDigits: cryptoCurrency.fractionDigits, ); - // Apply fee multiplier - final feeMultiplier = txData.feeRateAmount ?? 1.0; - final boostedFee = Amount( - rawValue: (BigInt.from((feeAmount.raw * - BigInt.from((feeMultiplier * 100).toInt())) / - BigInt.from(100))), - fractionDigits: cryptoCurrency.fractionDigits, + // Estimate fee using the shared method + final boostedFee = await estimateFeeFor( + totalSendAmount, + 1, + feeMultiplier: 1.0, + recipients: recipients, + assetId: asset, ); - // Check if we have enough for both transfer and fee - if (sendAmount + boostedFee > balance) { - final requiredAmt = await _wallet!.formatCoin( - atomicAmount: (sendAmount + boostedFee).rawValue, + // Check if we have enough for both transfers and fee + if (totalSendAmount + boostedFee > balance) { + final requiredAmt = await libXelisWallet!.formatCoin( + atomicAmount: (totalSendAmount + boostedFee).raw, assetHash: asset ); - final availableAmt = await _wallet!.formatCoin( + final availableAmt = await libXelisWallet!.formatCoin( atomicAmount: xelBalance, assetHash: asset ); throw Exception( - "Insufficient balance to cover transfer and fees. " + "Insufficient balance to cover transfers and fees. " "Required: $requiredAmt, Available: $availableAmt" ); } return txData.copyWith( fee: boostedFee, - otherData: { + otherData: jsonEncode({ 'asset': asset, - }, + }), ); } catch (e, s) { + Logging.instance.log( + "Exception rethrown from prepareSend(): $e\n$s", + level: LogLevel.Error, + ); + rethrow; + } + } + + @override + Future estimateFeeFor( + Amount amount, + int feeRate, + { + double? feeMultiplier, + List recipients = const [], + String? assetId + } + ) async { + try { + checkInitialized(); + final asset = assetId ?? xelis_sdk.xelisAsset; + + // // Use default address if recipients list is empty + // final effectiveRecipients = recipients.isNotEmpty + // ? recipients + // : [( + // address: 'xel:xz9574c80c4xegnvurazpmxhw5dlg2n0g9qm60uwgt75uqyx3pcsqzzra9m', + // amount: amount, + // isChange: false + // )]; + + // final transfers = await Future.wait( + // effectiveRecipients.map((recipient) async { + // final amountStr = await libXelisWallet!.formatCoin( + // atomicAmount: recipient.amount.raw, + // assetHash: asset + // ); + // return x_wallet.Transfer( + // floatAmount: amountStr as double, + // strAddress: recipient.address, + // assetHash: asset, + // ); + // }) + // ); + + // // Estimate fees + // final estimatedFeeString = await libXelisWallet!.estimateFees(transfers: transfers); + // final feeAmount = Amount( + // rawValue: BigInt.parse(estimatedFeeString), + // fractionDigits: cryptoCurrency.fractionDigits, + // ); + + // // Apply fee multiplier + // final multiplier = feeMultiplier ?? 1.0; + return Amount( + // rawValue: (BigInt.from((feeAmount.raw * + // BigInt.from((multiplier * 100).toInt())) / + // BigInt.from(100))), + rawValue: BigInt.zero, + fractionDigits: cryptoCurrency.fractionDigits, + ); + } catch (e, s) { + Logging.instance.log( + "Exception rethrown from estimateFeeFor(): $e\n$s", + level: LogLevel.Error, + ); rethrow; } } @@ -474,7 +644,7 @@ class XelisWallet extends Wallet { @override Future confirmSend({required TxData txData}) async { try { - _checkInitialized(); + checkInitialized(); // Validate recipients if (txData.recipients == null || txData.recipients!.length != 1) { @@ -483,17 +653,16 @@ class XelisWallet extends Wallet { final recipient = txData.recipients!.first; final Amount sendAmount = recipient.amount; - final asset = txData.otherData?['asset'] ?? xelis_sdk.xelisAsset; - String txHash; + final asset = (txData.getOtherData != null ? jsonDecode(txData.getOtherData!) : null)?['asset'] ?? xelis_sdk.xelisAsset; - final amt = await _wallet!.formatCoin( - atomicAmount: recipient.amount as BigInt, + final amt = double.parse(await libXelisWallet!.formatCoin( + atomicAmount: sendAmount.raw, assetHash: asset - ) as double; + )); // Create a transfer transaction - final txJson = await _wallet!.createTransfersTransaction( + final txJson = await libXelisWallet!.createTransfersTransaction( transfers: [ x_wallet.Transfer( floatAmount: amt, @@ -504,39 +673,170 @@ class XelisWallet extends Wallet { ] ); - final tx = x_wallet.TransactionSummary.fromJson(txJson); + final txMap = jsonDecode(txJson); + final txHash = txMap['hash'] as String; // Broadcast the transaction - await _wallet!.broadcastTransaction(txHash: tx.hash); + await libXelisWallet!.broadcastTransaction(txHash: txHash); return await updateSentCachedTxData(txData: txData.copyWith( - txid: tx.hash, + txid: txHash, )); } catch (e, s) { + Logging.instance.log( + "Exception rethrown from confirmSend(): $e\n$s", + level: LogLevel.Error, + ); rethrow; } } @override - Future recover({required bool isRescan}) async { - await refreshMutex.protect(() async { - if (isRescan) { - await mainDB.deleteWalletBlockchainData(walletId); - await checkSaveInitialReceivingAddress(); - await updateBalance(); - await updateTransactions(isRescan: true); - } else { - await checkSaveInitialReceivingAddress(); - unawaited(updateBalance()); - unawaited(updateTransactions()); + Future handleEvent(Event event) async { + try { + switch (event) { + case NewTopoheight(:final height): + await handleNewTopoHeight(height); + case NewAsset(:final asset): + await handleNewAsset(asset); + case NewTransaction(:final transaction): + await handleNewTransaction(transaction); + case BalanceChanged(:final event): + await handleBalanceChanged(event); + case Rescan(:final startTopoheight): + await handleRescan(startTopoheight); + case Online(): + await handleOnline(); + case Offline(): + await handleOffline(); + case HistorySynced(:final topoheight): + await handleHistorySynced(topoheight); + } + } catch (e, s) { + Logging.instance.log( + "Error handling wallet event: $e\n$s", + level: LogLevel.Error, + ); + } + } + + @override + Future handleNewTopoHeight(int height) async { + await info.updateCachedChainHeight( + newHeight: height, + isar: mainDB.isar, + ); + } + + @override + Future handleNewTransaction(xelis_sdk.TransactionEntry tx) async { + try { + final txListJson = [jsonEncode(tx.toString())]; + final newTxIds = await updateTransactions( + isRescan: false, + rawTransactions: txListJson, + ); + + await updateBalance(); + + Logging.instance.log( + "New transaction processed: ${newTxIds.first}", + level: LogLevel.Info, + ); + } catch (e, s) { + Logging.instance.log( + "Error handling new transaction: $e\n$s", + level: LogLevel.Warning, + ); + } + } + + @override + Future handleBalanceChanged(xelis_sdk.BalanceChangedEvent event) async { + try { + final asset = event.assetHash; + if (asset == xelis_sdk.xelisAsset) { + await updateBalance(newBalance: event.balance); } + + // TODO: Update asset balances if needed + } catch (e, s) { + Logging.instance.log( + "Error handling balance change: $e\n$s", + level: LogLevel.Warning, + ); + } + } + + @override + Future handleRescan(int startTopoheight) async { + await refreshMutex.protect(() async { + await mainDB.deleteWalletBlockchainData(walletId); + await updateTransactions(isRescan: true, topoheight: startTopoheight); + await updateBalance(); }); } @override - Future exit() async { - timer?.cancel(); - timer = null; - await super.exit(); + Future handleOnline() async { + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.synced, + walletId, + info.coin, + ), + ); + unawaited(refresh()); + } + + @override + Future handleOffline() async { + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.unableToSync, + walletId, + info.coin, + ), + ); + } + + @override + Future handleHistorySynced(int topoheight) async { + await updateChainHeight(); + await updateBalance(); + await updateTransactions(); + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.synced, + walletId, + info.coin, + ), + ); + } + + @override + Future handleNewAsset(xelis_sdk.AssetData asset) async { + // TODO: Store asset information if needed + // TODO: Update UI/state for new asset + Logging.instance.log( + "New asset detected: ${asset}", + level: LogLevel.Info, + ); + } + + @override + Future refresh({int? topoheight}) async { + await refreshMutex.protect(() async { + try { + await updateChainHeight(topoheight: topoheight); + await updateBalance(); + await updateTransactions(); + } catch (e, s) { + Logging.instance.log( + "Error in refresh(): $e\n$s", + level: LogLevel.Warning, + ); + } + }); } } \ No newline at end of file diff --git a/lib/wallets/wallet/intermediate/cryptonote_wallet.dart b/lib/wallets/wallet/intermediate/cryptonote_wallet.dart index 131bf8f04..0d32e07a3 100644 --- a/lib/wallets/wallet/intermediate/cryptonote_wallet.dart +++ b/lib/wallets/wallet/intermediate/cryptonote_wallet.dart @@ -2,8 +2,9 @@ import '../../crypto_currency/intermediate/cryptonote_currency.dart'; import '../wallet.dart'; import '../wallet_mixin_interfaces/coin_control_interface.dart'; import '../wallet_mixin_interfaces/mnemonic_interface.dart'; +import 'external_wallet.dart'; -abstract class CryptonoteWallet extends Wallet +abstract class CryptonoteWallet extends ExternalWallet with MnemonicInterface, CoinControlInterface { CryptonoteWallet(super.currency); } diff --git a/lib/wallets/wallet/intermediate/external_wallet.dart b/lib/wallets/wallet/intermediate/external_wallet.dart new file mode 100644 index 000000000..e5ce6b39b --- /dev/null +++ b/lib/wallets/wallet/intermediate/external_wallet.dart @@ -0,0 +1,12 @@ +import '../../crypto_currency/crypto_currency.dart'; +import '../wallet.dart'; + +// anstract class to be fleshed out for the standardization of wallet implementations +// that rely on bridged code libraries outside, or external native wallet functions +abstract class ExternalWallet extends Wallet { + ExternalWallet(super.currency); + + // wallet opening and initialization separated to prevent db lock collision errors + // must be overridden + Future open(); +} diff --git a/lib/wallets/wallet/intermediate/lib_monero_wallet.dart b/lib/wallets/wallet/intermediate/lib_monero_wallet.dart index 5d176ec7d..b6b30de34 100644 --- a/lib/wallets/wallet/intermediate/lib_monero_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_monero_wallet.dart @@ -190,6 +190,7 @@ abstract class LibMoneroWallet } } + @override Future open() async { bool wasNull = false; diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart new file mode 100644 index 000000000..26cf77842 --- /dev/null +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -0,0 +1,563 @@ +import 'package:isar/isar.dart'; +import '../../../models/isar/models/blockchain_data/address.dart'; +import '../../crypto_currency/intermediate/electrum_currency.dart'; +import '../wallet.dart'; +import '../wallet_mixin_interfaces/mnemonic_interface.dart'; + +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:json_annotation/json_annotation.dart'; + +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:decimal/decimal.dart'; +import 'package:flutter/foundation.dart'; +import 'package:isar/isar.dart'; + +import 'package:xelis_flutter/src/api/network.dart' as x_network; +import 'package:xelis_flutter/src/api/wallet.dart' as x_wallet; +import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk; + +import 'package:path_provider/path_provider.dart'; +import 'package:path/path.dart' as path; + +import '../../../utilities/stack_file_system.dart'; +import '../../../models/isar/models/blockchain_data/transaction.dart'; +import '../../../models/isar/models/blockchain_data/v2/input_v2.dart'; +import '../../../models/isar/models/blockchain_data/v2/output_v2.dart'; +import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart'; + +import '../../../models/node_model.dart'; +import '../../../models/paymint/fee_object_model.dart'; +import '../../../models/balance.dart'; +import '../../../utilities/amount/amount.dart'; +import '../../../utilities/logger.dart'; +import '../../crypto_currency/crypto_currency.dart'; +import '../../models/tx_data.dart'; + +import 'package:isar/isar.dart'; +import 'package:mutex/mutex.dart'; +import 'package:stack_wallet_backup/generate_password.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; + +import 'external_wallet.dart'; + +enum XelisTableSize { + low, + full; + + bool get isLow => this == XelisTableSize.low; + + static XelisTableSize get platformDefault { + if (kIsWeb) { + return XelisTableSize.low; + } + return XelisTableSize.full; + } +} + +class XelisTableState { + final bool isGenerating; + final XelisTableSize currentSize; + final XelisTableSize _desiredSize; + + XelisTableSize get desiredSize { + if (kIsWeb) { + return XelisTableSize.low; + } + return _desiredSize; + } + + const XelisTableState({ + this.isGenerating = false, + this.currentSize = XelisTableSize.low, + XelisTableSize desiredSize = XelisTableSize.full, + }) : _desiredSize = desiredSize; + + XelisTableState copyWith({ + bool? isGenerating, + XelisTableSize? currentSize, + XelisTableSize? desiredSize, + }) { + return XelisTableState( + isGenerating: isGenerating ?? this.isGenerating, + currentSize: currentSize ?? this.currentSize, + desiredSize: kIsWeb ? XelisTableSize.low : (desiredSize ?? this._desiredSize), + ); + } + + factory XelisTableState.fromJson(Map json) { + return XelisTableState( + isGenerating: json['isGenerating'] as bool, + currentSize: XelisTableSize.values[json['currentSize'] as int], + desiredSize: XelisTableSize.values[json['desiredSize'] as int], + ); + } + + Map toJson() => { + 'isGenerating': isGenerating, + 'currentSize': currentSize.index, + 'desiredSize': _desiredSize.index, + }; +} + +extension XelisNetworkConversion on CryptoCurrencyNetwork { + x_network.Network get xelisNetwork { + switch (this) { + case CryptoCurrencyNetwork.main: + return x_network.Network.mainnet; + case CryptoCurrencyNetwork.test: + return x_network.Network.testnet; + default: + throw ArgumentError('Unsupported network type for Xelis: $this'); + } + } +} + +extension CryptoCurrencyNetworkConversion on x_network.Network { + CryptoCurrencyNetwork get cryptoCurrencyNetwork { + switch (this) { + case x_network.Network.mainnet: + return CryptoCurrencyNetwork.main; + case x_network.Network.testnet: + return CryptoCurrencyNetwork.test; + default: + throw ArgumentError('Unsupported Xelis network type: $this'); + } + } +} + +sealed class Event { + const Event(); +} + +final class NewTopoheight extends Event { + final int height; + const NewTopoheight(this.height); +} + +final class NewAsset extends Event { + final xelis_sdk.AssetData asset; + const NewAsset(this.asset); +} + +final class NewTransaction extends Event { + final xelis_sdk.TransactionEntry transaction; + const NewTransaction(this.transaction); +} + +final class BalanceChanged extends Event { + final xelis_sdk.BalanceChangedEvent event; + const BalanceChanged(this.event); +} + +final class Rescan extends Event { + final int startTopoheight; + const Rescan(this.startTopoheight); +} + +final class Online extends Event { + const Online(); +} + +final class Offline extends Event { + const Offline(); +} + +final class HistorySynced extends Event { + final int topoheight; + const HistorySynced(this.topoheight); +} + +abstract class LibXelisWallet extends ExternalWallet + with MnemonicInterface { + LibXelisWallet(super.currency); + + static const String _kHasFullTablesKey = 'xelis_has_full_tables'; + static const String _kGeneratingTablesKey = 'xelis_generating_tables'; + static const String _kWantsFullTablesKey = 'xelis_wants_full_tables'; + static bool _isAnyWalletGeneratingTables = false; + static final _initMutex = Mutex(); + static final _tableGenerationMutex = Mutex(); + static Completer? _tableGenerationCompleter; + + x_wallet.XelisWallet? libXelisWallet; + + x_wallet.XelisWallet? get wallet => libXelisWallet; + set wallet(x_wallet.XelisWallet? newWallet) { + if (newWallet == null && libXelisWallet != null) { + throw StateError('Cannot set wallet to null after initialization'); + } + libXelisWallet = newWallet; + } + + void checkInitialized() { + if (libXelisWallet == null) { + throw StateError('libXelisWallet not initialized'); + } + } + + final syncMutex = Mutex(); + NodeModel? _xelisNode; + Timer? timer; + String? tablePath; + + StreamSubscription? _eventSubscription; + + Future getPrecomputedTablesPath() async { + final appDir = await StackFileSystem.applicationRootDirectory(); + // Create a subdirectory for the tables + final tablePath = path.join(appDir.path, 'xelis', 'tables/'); + return tablePath; + } + + Future getTableState() async { + final hasFullTables = await secureStorageInterface.read(key: _kHasFullTablesKey) == 'true'; + final isGenerating = await secureStorageInterface.read(key: _kGeneratingTablesKey) == 'true'; + final wantsFull = await secureStorageInterface.read(key: _kWantsFullTablesKey) != 'false'; + + return XelisTableState( + isGenerating: isGenerating, + currentSize: hasFullTables ? XelisTableSize.full : XelisTableSize.low, + desiredSize: wantsFull ? XelisTableSize.full : XelisTableSize.low, + ); + } + + Future setTableState(XelisTableState state) async { + await secureStorageInterface.write( + key: _kHasFullTablesKey, + value: state.currentSize == XelisTableSize.full ? 'true' : 'false', + ); + await secureStorageInterface.write( + key: _kGeneratingTablesKey, + value: state.isGenerating ? 'true' : 'false', + ); + await secureStorageInterface.write( + key: _kWantsFullTablesKey, + value: state.desiredSize == XelisTableSize.full ? 'true' : 'false', + ); + } + + Stream convertRawEvents() async* { + checkInitialized(); + final rawEventStream = libXelisWallet!.eventsStream(); + + await for (final rawData in rawEventStream) { + final json = jsonDecode(rawData); + try { + final eventType = xelis_sdk.WalletEvent.fromStr(json['event'] as String); + switch (eventType) { + case xelis_sdk.WalletEvent.newTopoHeight: + yield NewTopoheight(json['data']['topoheight'] as int); + case xelis_sdk.WalletEvent.newAsset: + yield NewAsset( + xelis_sdk.AssetData.fromJson(json['data'] as Map)); + case xelis_sdk.WalletEvent.newTransaction: + yield NewTransaction( + xelis_sdk.TransactionEntry.fromJson( + json['data'] as Map)); + case xelis_sdk.WalletEvent.balanceChanged: + yield BalanceChanged( + xelis_sdk.BalanceChangedEvent.fromJson( + json['data'] as Map)); + case xelis_sdk.WalletEvent.rescan: + yield Rescan(json['data']['start_topoheight'] as int); + case xelis_sdk.WalletEvent.online: + yield const Online(); + case xelis_sdk.WalletEvent.offline: + yield const Offline(); + case xelis_sdk.WalletEvent.historySynced: + yield HistorySynced(json['data']['topoheight'] as int); + } + } catch (e, s) { + Logging.instance.log( + "Error processing wallet event: $e\n$s", + level: LogLevel.Error, + ); + continue; + } + } + } + + Future handleEvent(Event event) async {} + Future handleNewTopoHeight(int height); + Future handleNewTransaction(xelis_sdk.TransactionEntry tx); + Future handleBalanceChanged(xelis_sdk.BalanceChangedEvent event); + Future handleRescan(int startTopoheight) async {} + Future handleOnline() async {} + Future handleOffline() async {} + Future handleHistorySynced(int topoheight) async {} + Future handleNewAsset(xelis_sdk.AssetData asset) async {} + + Future refresh({int? topoheight}); + + Future connect() async { + try { + _eventSubscription = + convertRawEvents().listen(handleEvent); + + final node = getCurrentNode(); + Logging.instance.log( + "Connecting to node: ${node.host}", + level: LogLevel.Info, + ); + await libXelisWallet!.onlineMode( + daemonAddress: node.host + ); + await super.refresh(); + } catch (e, s) { + Logging.instance.log( + "Error connecting to node: $e\n$s", + level: LogLevel.Error, + ); + rethrow; + } + } + + List get standardReceivingAddressFilters => [ + FilterCondition.equalTo( + property: r"type", + value: info.mainAddressType, + ), + const FilterCondition.equalTo( + property: r"subType", + value: AddressSubType.receiving, + ), + ]; + + List get standardChangeAddressFilters => [ + FilterCondition.equalTo( + property: r"type", + value: info.mainAddressType, + ), + const FilterCondition.equalTo( + property: r"subType", + value: AddressSubType.change, + ), + ]; + + @override + Future open() async { + bool wasNull = false; + + if (libXelisWallet == null) { + wasNull = true; + final tablePath = await getPrecomputedTablesPath(); + final tableState = await getTableState(); + final String name = walletId; + final password = await secureStorageInterface.read( + key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), + ); + + await LibXelisWallet._initMutex.protect(() async { + try { + final needsCreation = await secureStorageInterface.read( + key: '_${walletId}_needs_creation', + ); + + final needsRestoration = await secureStorageInterface.read( + key: '_${walletId}_needs_restoration', + ); + + libXelisWallet = await syncMutex.protect(() async { + if (needsCreation == 'true') { + debugPrint("Xelis: creating new wallet"); + final wallet = await x_wallet.createXelisWallet( + name: name, + password: password!, + network: cryptoCurrency.network.xelisNetwork, + precomputedTablesPath: tablePath, + l1Low: tableState.currentSize.isLow + ); + + final mnemonic = await wallet.getSeed(); + await secureStorageInterface.write( + key: Wallet.mnemonicKey(walletId: walletId), + value: mnemonic.trim(), + ); + + await secureStorageInterface.delete( + key: '_${walletId}_needs_creation', + ); + + return wallet; + } else if (needsRestoration == 'true') { + final mnemonic = await getMnemonic(); + final seedLength = mnemonic.trim().split(" ").length; + + invalidSeedLengthCheck(seedLength); + + debugPrint("Xelis: recovering wallet"); + final wallet = await x_wallet.createXelisWallet( + name: name, + password: password!, + seed: mnemonic.trim(), + network: cryptoCurrency.network.xelisNetwork, + precomputedTablesPath: tablePath, + l1Low: tableState.currentSize.isLow + ); + + await secureStorageInterface.write( + key: Wallet.mnemonicKey(walletId: walletId), + value: mnemonic.trim(), + ); + + await secureStorageInterface.delete( + key: '_${walletId}_needs_restoration', + ); + + return wallet; + } else { + debugPrint("Xelis: opening existing wallet"); + return await x_wallet.openXelisWallet( + name: name, + password: password!, + network: cryptoCurrency.network.xelisNetwork, + precomputedTablesPath: tablePath, + l1Low: tableState.currentSize.isLow, + ); + } + }); + } catch (e, s) { + Logging.instance.log( + "Failed to open/create wallet: $e\n$s", + level: LogLevel.Error, + ); + rethrow; + } + }); + } + + if (await isTableUpgradeAvailable()) { + unawaited(updateTablesToDesiredSize()); + } + + final newReceivingAddress = await getCurrentReceivingAddress() ?? + Address( + walletId: walletId, + derivationIndex: 0, + derivationPath: null, + value: libXelisWallet!.getAddressStr(), + publicKey: [], + type: AddressType.xelis, + subType: AddressSubType.receiving, + ); + await mainDB.updateOrPutAddresses([newReceivingAddress]); + + if (info.cachedReceivingAddress != newReceivingAddress.value) { + await info.updateReceivingAddress( + newAddress: newReceivingAddress.value, + isar: mainDB.isar, + ); + } + + if (wasNull) { + try { + await connect(); + } catch (e) { + Logging.instance.log( + "Failed to start sync: $e", + level: LogLevel.Error, + ); + rethrow; + } + } + + unawaited(refresh()); + } + + @override + Future exit() async { + await refreshMutex.protect(() async { + timer?.cancel(); + timer = null; + + await _eventSubscription?.cancel(); + _eventSubscription = null; + + await libXelisWallet?.offlineMode(); + libXelisWallet?.dispose(); + libXelisWallet = null; + + await super.exit(); + }); + } + + void invalidSeedLengthCheck(int length) { + if (!(length == 25)) { + throw Exception("Invalid Xelis mnemonic length found: $length"); + } + } +} + +extension XelisTableManagement on LibXelisWallet { + Future isTableUpgradeAvailable() async { + if (kIsWeb) return false; + + final state = await getTableState(); + return state.currentSize != state.desiredSize; + } + + Future updateTablesToDesiredSize() async { + if (kIsWeb) return; + + if (LibXelisWallet._tableGenerationCompleter != null) { + try { + await LibXelisWallet._tableGenerationCompleter!.future; + return; + } catch (_) { + // Previous generation failed, we'll try again + } + } + + await LibXelisWallet._tableGenerationMutex.protect(() async { + // Check again after acquiring mutex + if (LibXelisWallet._tableGenerationCompleter != null) { + try { + await LibXelisWallet._tableGenerationCompleter!.future; + return; + } catch (_) { + // Previous generation failed, we'll try again + } + } + + final state = await getTableState(); + if (state.currentSize == state.desiredSize) return; + + LibXelisWallet._tableGenerationCompleter = Completer(); + await setTableState(state.copyWith(isGenerating: true)); + + try { + final tablePath = await getPrecomputedTablesPath(); + await x_wallet.updateTables( + precomputedTablesPath: tablePath, + l1Low: state.desiredSize.isLow, + ); + + await setTableState(XelisTableState( + isGenerating: false, + currentSize: state.desiredSize, + desiredSize: state.desiredSize, + )); + + LibXelisWallet._tableGenerationCompleter!.complete(); + } catch (e, s) { + Logging.instance.log( + "Failed to update tables: $e\n$s", + level: LogLevel.Error, + ); + await setTableState(state.copyWith(isGenerating: false)); + + LibXelisWallet._tableGenerationCompleter!.completeError(e); + } finally { + if (!LibXelisWallet._tableGenerationCompleter!.isCompleted) { + LibXelisWallet._tableGenerationCompleter!.completeError( + Exception('Table generation abandoned') + ); + } + LibXelisWallet._tableGenerationCompleter = null; + } + }); + } +} \ No newline at end of file diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart index 733c3cf3e..be21c5282 100644 --- a/lib/wallets/wallet/wallet.dart +++ b/lib/wallets/wallet/wallet.dart @@ -173,8 +173,8 @@ abstract class Wallet { value: viewOnlyData!.toJsonEncodedString(), ); } else if (wallet is MnemonicInterface) { - if (wallet is CryptonoteWallet) { - // currently a special case due to the xmr/wow libraries handling their + if (wallet is CryptonoteWallet || wallet is XelisWallet) { // + // currently a special case due to the xmr/wow/xelis libraries handling their // own mnemonic generation on new wallet creation // if its a restore we must set them if (mnemonic != null) { diff --git a/lib/widgets/xelis_table_progress.dart b/lib/widgets/xelis_table_progress.dart new file mode 100644 index 000000000..ffecba861 --- /dev/null +++ b/lib/widgets/xelis_table_progress.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../../../themes/stack_colors.dart'; +import '../../../utilities/text_styles.dart'; +import '../../../widgets/progress_bar.dart'; + +import '../providers/providers.dart'; + +class XelisTableProgress extends ConsumerWidget { + const XelisTableProgress({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final progressAsyncValue = ref.watch(xelisTableProgressProvider); + + return DefaultTextStyle( + style: TextStyle( + color: Theme.of(context).textTheme.bodyLarge?.color ?? Colors.black, + fontSize: 14, + ), + child: Center( + child: progressAsyncValue.when( + data: (progress) => Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: BorderRadius.circular(12), + ), + constraints: const BoxConstraints(maxWidth: 450), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Generating Precomputed Tables...", + style: STextStyles.desktopH3(context).copyWith( + fontSize: 24, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 8), + Text( + "These tables are required for the fast decryption of private transactions. This is a one-time process upon the creation of your first Xelis wallet in Stack Wallet.", + style: STextStyles.subtitle600(context).copyWith( + fontSize: 14, + color: Theme.of(context).extension()!.textSubtitle1, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + Text( + progress.currentStep.displayName, + style: STextStyles.titleBold12(context), + textAlign: TextAlign.center, + ), + const SizedBox(height: 8), + ProgressBar( + width: 200, + height: 8, + fillColor: const Color.fromARGB(255,2,255,207), + backgroundColor: Theme.of(context).extension()!.textFieldDefaultBG, + percent: progress.tableProgress ?? 0.0, + ), + const SizedBox(height: 4), + Text( + "${((progress.tableProgress ?? 0.0) * 100).toStringAsFixed(1)}%", + style: STextStyles.label(context), + ), + ], + ), + ), + loading: () => const SizedBox.shrink(), + error: (_, __) => const SizedBox.shrink(), + ), + ), + ); + } +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 920ea7743..a7480b775 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -967,8 +967,16 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e" + url: "https://pub.dev" + source: hosted + version: "2.5.7" freezed_annotation: - dependency: transitive + dependency: "direct main" description: name: freezed_annotation sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 @@ -2340,7 +2348,7 @@ packages: path: "crypto_plugins/xelis_flutter" relative: true source: path - version: "0.0.1" + version: "0.0.2" xml: dependency: transitive description: diff --git a/scripts/app_config/templates/linux/CMakeLists.txt b/scripts/app_config/templates/linux/CMakeLists.txt index 25750ef4f..16b662db7 100644 --- a/scripts/app_config/templates/linux/CMakeLists.txt +++ b/scripts/app_config/templates/linux/CMakeLists.txt @@ -140,6 +140,9 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libepiccash install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_liblelantus/scripts/linux/build/libmobileliblelantus.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/xelis_flutter/linux/bin/x86_64-unknown-linux-gnu/release/libxelis_flutter.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/jsoncpp/build/src/lib_json/libjsoncpp.so.1.7.4" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/jsoncpp/build/src/lib_json/libjsoncpp.so.1" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" diff --git a/scripts/app_config/templates/pubspec.template b/scripts/app_config/templates/pubspec.template index 26d28185a..f56904fde 100644 --- a/scripts/app_config/templates/pubspec.template +++ b/scripts/app_config/templates/pubspec.template @@ -1,5 +1,5 @@ -name: PLACEHOLDER -description: PLACEHOLDER +name: stackwallet +description: Stack Wallet # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -11,7 +11,7 @@ description: PLACEHOLDER # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: PLACEHOLDER_V+PLACEHOLDER_B +version: 2.1.1+211 environment: sdk: ">=3.7.0 <4.0.0" @@ -35,6 +35,8 @@ dependencies: xelis_dart_sdk: ^0.24.0 + freezed_annotation: ^2.4.1 + flutter_libsparkmobile: git: url: https://github.com/cypherstack/flutter_libsparkmobile.git @@ -229,6 +231,7 @@ dev_dependencies: sdk: flutter integration_test: sdk: flutter + freezed: ^2.4.2 build_runner: ^2.1.7 flutter_launcher_icons: ^0.13.1 hive_generator: ^2.0.0 diff --git a/scripts/app_config/templates/windows/CMakeLists.txt b/scripts/app_config/templates/windows/CMakeLists.txt index b9add856d..e998725c9 100644 --- a/scripts/app_config/templates/windows/CMakeLists.txt +++ b/scripts/app_config/templates/windows/CMakeLists.txt @@ -86,6 +86,10 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libepiccash install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_liblelantus/scripts/windows/build/libmobileliblelantus.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) +# todo make this handle arm+x86, required plugin adjustment +# install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/xelis_flutter/windows/bin/x86_64-unknown-windows-msvc/release/libxelis_flutter.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" +# COMPONENT Runtime) + if(PLUGIN_BUNDLED_LIBRARIES) install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" From 7a3558e7e9fab2abfc85d959a2f5fb522a1840e5 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Wed, 12 Feb 2025 01:52:52 -0800 Subject: [PATCH 07/50] Slight polish for Xelis integration --- .../svg/campfire/socials/discord.svg | 30 +- .../svg/campfire/socials/telegram-brands.svg | 20 +- .../svg/stack_duo/socials/discord.svg | 30 +- .../svg/stack_duo/socials/telegram-brands.svg | 20 +- .../svg/stack_wallet/socials/discord.svg | 30 +- .../stack_wallet/socials/telegram-brands.svg | 20 +- google_fonts/LICENSE.txt | 404 +++++++++--------- google_fonts/OFL.txt | 186 ++++---- .../xelis_table_progress_provider.dart | 15 +- lib/wallets/wallet/impl/xelis_wallet.dart | 22 +- .../wallet/intermediate/lib_xelis_wallet.dart | 13 +- .../app_config/templates/linux/CMakeLists.txt | 2 +- 12 files changed, 394 insertions(+), 398 deletions(-) diff --git a/asset_sources/svg/campfire/socials/discord.svg b/asset_sources/svg/campfire/socials/discord.svg index 4d6aff6ed..a93742dfd 100644 --- a/asset_sources/svg/campfire/socials/discord.svg +++ b/asset_sources/svg/campfire/socials/discord.svg @@ -1,15 +1,15 @@ - - - - - + + + + + diff --git a/asset_sources/svg/campfire/socials/telegram-brands.svg b/asset_sources/svg/campfire/socials/telegram-brands.svg index 61d09ee08..629eabf23 100644 --- a/asset_sources/svg/campfire/socials/telegram-brands.svg +++ b/asset_sources/svg/campfire/socials/telegram-brands.svg @@ -1,10 +1,10 @@ - - - - - + + + + + diff --git a/asset_sources/svg/stack_duo/socials/discord.svg b/asset_sources/svg/stack_duo/socials/discord.svg index 4d6aff6ed..a93742dfd 100644 --- a/asset_sources/svg/stack_duo/socials/discord.svg +++ b/asset_sources/svg/stack_duo/socials/discord.svg @@ -1,15 +1,15 @@ - - - - - + + + + + diff --git a/asset_sources/svg/stack_duo/socials/telegram-brands.svg b/asset_sources/svg/stack_duo/socials/telegram-brands.svg index 61d09ee08..629eabf23 100644 --- a/asset_sources/svg/stack_duo/socials/telegram-brands.svg +++ b/asset_sources/svg/stack_duo/socials/telegram-brands.svg @@ -1,10 +1,10 @@ - - - - - + + + + + diff --git a/asset_sources/svg/stack_wallet/socials/discord.svg b/asset_sources/svg/stack_wallet/socials/discord.svg index 4d6aff6ed..a93742dfd 100644 --- a/asset_sources/svg/stack_wallet/socials/discord.svg +++ b/asset_sources/svg/stack_wallet/socials/discord.svg @@ -1,15 +1,15 @@ - - - - - + + + + + diff --git a/asset_sources/svg/stack_wallet/socials/telegram-brands.svg b/asset_sources/svg/stack_wallet/socials/telegram-brands.svg index 61d09ee08..629eabf23 100644 --- a/asset_sources/svg/stack_wallet/socials/telegram-brands.svg +++ b/asset_sources/svg/stack_wallet/socials/telegram-brands.svg @@ -1,10 +1,10 @@ - - - - - + + + + + diff --git a/google_fonts/LICENSE.txt b/google_fonts/LICENSE.txt index 75b52484e..d64569567 100644 --- a/google_fonts/LICENSE.txt +++ b/google_fonts/LICENSE.txt @@ -1,202 +1,202 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/google_fonts/OFL.txt b/google_fonts/OFL.txt index ad214842c..b525cbf3a 100644 --- a/google_fonts/OFL.txt +++ b/google_fonts/OFL.txt @@ -1,93 +1,93 @@ -Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. +Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/lib/providers/progress_report/xelis_table_progress_provider.dart b/lib/providers/progress_report/xelis_table_progress_provider.dart index 5f57dca29..cbebe8224 100644 --- a/lib/providers/progress_report/xelis_table_progress_provider.dart +++ b/lib/providers/progress_report/xelis_table_progress_provider.dart @@ -1,6 +1,9 @@ import 'package:xelis_flutter/src/api/api.dart' as xelis_api; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter/foundation.dart'; +import 'dart:math' as math; + enum XelisTableGenerationStep { t1PointsGeneration, t1CuckooSetup, @@ -45,6 +48,7 @@ class XelisTableProgressState { } final xelisTableProgressProvider = StreamProvider((ref) { + double lastPrintedProgress = 0.0; return xelis_api.createProgressReportStream().map((report) { return report.when( tableGeneration: (progress, step, _) { @@ -56,10 +60,15 @@ final xelisTableProgressProvider = StreamProvider((ref) XelisTableGenerationStep.unknown => 0, }; - final totalProgress = (stepIndex * 0.5) + (progress * 0.5); - + if ((progress - lastPrintedProgress).abs() >= 0.05 || + currentStep != XelisTableGenerationStep.fromString(step) || + progress >= 0.99) { + debugPrint("Xelis Table Generation: $step - ${progress*100.0}%"); + lastPrintedProgress = progress; + } + return XelisTableProgressState( - tableProgress: totalProgress, + tableProgress: progress, currentStep: currentStep, ); }, diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index b14ef7cc2..5fbbf976b 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -57,23 +57,6 @@ class XelisWallet extends LibXelisWallet { @override Future init({bool? isRestore}) async { debugPrint("Xelis: init"); - - // final progressState = ref.read(xelisTableProgressProvider); - // if (progressState.hasValue && - // progressState.value?.tableProgress != null && - // progressState.value!.tableProgress! < 1.0) { - // GlobalEventBus.instance.fire( - // WalletSyncStatusChangedEvent( - // WalletSyncStatus.syncing, - // walletId, - // info.coin, - // ), - // ); - - // while ((ref.read(xelisTableProgressProvider).value?.tableProgress ?? 1.0) < 1.0) { - // await Future.delayed(const Duration(milliseconds: 100)); - // } - // } if (isRestore == true) { await _restoreWallet(); @@ -88,7 +71,6 @@ class XelisWallet extends LibXelisWallet { } await open(); - await updateTransactions(isRescan: true, topoheight: 0); return await super.init(); } @@ -168,10 +150,12 @@ class XelisWallet extends LibXelisWallet { Future pingCheck() async { checkInitialized(); try { - await libXelisWallet!.getDaemonInfo(); + final nodeInfo = await libXelisWallet!.getDaemonInfo(); + await handleOnline(); return true; } catch (_) { return false; + await handleOffline(); } } diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 26cf77842..e3651179e 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -427,10 +427,12 @@ abstract class LibXelisWallet extends ExternalWallet rethrow; } }); - } - - if (await isTableUpgradeAvailable()) { - unawaited(updateTablesToDesiredSize()); + + debugPrint("Checking for upgradability"); + if (await isTableUpgradeAvailable()) { + debugPrint("Generating large tables in background"); + unawaited(updateTablesToDesiredSize()); + } } final newReceivingAddress = await getCurrentReceivingAddress() ?? @@ -540,7 +542,8 @@ extension XelisTableManagement on LibXelisWallet { currentSize: state.desiredSize, desiredSize: state.desiredSize, )); - + + debugPrint("Table upgrade done"); LibXelisWallet._tableGenerationCompleter!.complete(); } catch (e, s) { Logging.instance.log( diff --git a/scripts/app_config/templates/linux/CMakeLists.txt b/scripts/app_config/templates/linux/CMakeLists.txt index 16b662db7..f1853439c 100644 --- a/scripts/app_config/templates/linux/CMakeLists.txt +++ b/scripts/app_config/templates/linux/CMakeLists.txt @@ -140,7 +140,7 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libepiccash install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_liblelantus/scripts/linux/build/libmobileliblelantus.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) -install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/xelis_flutter/linux/bin/x86_64-unknown-linux-gnu/release/libxelis_flutter.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/xelis_flutter/scripts/linux/build/libxelis_flutter.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/jsoncpp/build/src/lib_json/libjsoncpp.so.1.7.4" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" From c6bff81648a9f559e73b9c8af7dc33167820229a Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 13 Feb 2025 22:57:58 -0800 Subject: [PATCH 08/50] Android works --- crypto_plugins/xelis_flutter | 2 +- .../wallet/intermediate/lib_xelis_wallet.dart | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/crypto_plugins/xelis_flutter b/crypto_plugins/xelis_flutter index 2a3824490..24c66562d 160000 --- a/crypto_plugins/xelis_flutter +++ b/crypto_plugins/xelis_flutter @@ -1 +1 @@ -Subproject commit 2a382449090daac64a15434b6e802d6e06d30502 +Subproject commit 24c66562dce9019c1af7d43f5b58bba59e336e91 diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index e3651179e..53522fa74 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -206,10 +206,12 @@ abstract class LibXelisWallet extends ExternalWallet StreamSubscription? _eventSubscription; Future getPrecomputedTablesPath() async { - final appDir = await StackFileSystem.applicationRootDirectory(); - // Create a subdirectory for the tables - final tablePath = path.join(appDir.path, 'xelis', 'tables/'); - return tablePath; + if (kIsWeb) { + return ""; + } else { + final appDir = await getApplicationSupportDirectory(); + return "${appDir.path}/"; + } } Future getTableState() async { @@ -345,7 +347,8 @@ abstract class LibXelisWallet extends ExternalWallet wasNull = true; final tablePath = await getPrecomputedTablesPath(); final tableState = await getTableState(); - final String name = walletId; + final appDir = await getApplicationDocumentsDirectory(); + final String name = path.join(appDir.path, walletId); final password = await secureStorageInterface.read( key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), ); @@ -504,6 +507,7 @@ extension XelisTableManagement on LibXelisWallet { Future updateTablesToDesiredSize() async { if (kIsWeb) return; + await Future.delayed(const Duration(seconds: 1)); if (LibXelisWallet._tableGenerationCompleter != null) { try { await LibXelisWallet._tableGenerationCompleter!.future; From e1964ea68e7d7135be853496a4286c3cb548abed Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 13 Feb 2025 23:29:56 -0800 Subject: [PATCH 09/50] adjusted for xelis flutter refactor --- lib/wallets/wallet/intermediate/lib_xelis_wallet.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 53522fa74..9935e0f18 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -348,7 +348,8 @@ abstract class LibXelisWallet extends ExternalWallet final tablePath = await getPrecomputedTablesPath(); final tableState = await getTableState(); final appDir = await getApplicationDocumentsDirectory(); - final String name = path.join(appDir.path, walletId); + final String name = walletId; + final String directory = path.join(appDir.path, '/'); final password = await secureStorageInterface.read( key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), ); @@ -368,6 +369,7 @@ abstract class LibXelisWallet extends ExternalWallet debugPrint("Xelis: creating new wallet"); final wallet = await x_wallet.createXelisWallet( name: name, + directory: directory, password: password!, network: cryptoCurrency.network.xelisNetwork, precomputedTablesPath: tablePath, @@ -394,6 +396,7 @@ abstract class LibXelisWallet extends ExternalWallet debugPrint("Xelis: recovering wallet"); final wallet = await x_wallet.createXelisWallet( name: name, + directory: directory, password: password!, seed: mnemonic.trim(), network: cryptoCurrency.network.xelisNetwork, @@ -415,6 +418,7 @@ abstract class LibXelisWallet extends ExternalWallet debugPrint("Xelis: opening existing wallet"); return await x_wallet.openXelisWallet( name: name, + directory: directory, password: password!, network: cryptoCurrency.network.xelisNetwork, precomputedTablesPath: tablePath, From 1463ea79723aac8dacc1ac734be0730b701fa07c Mon Sep 17 00:00:00 2001 From: Anthony Tritonn Date: Sat, 15 Feb 2025 14:45:36 -0800 Subject: [PATCH 10/50] Xelis price service added, wallet storage bugs fixed, updated to apple-compliant xelis lib --- crypto_plugins/xelis_flutter | 2 +- lib/services/price.dart | 1 + lib/wallets/wallet/intermediate/lib_xelis_wallet.dart | 2 +- linux/flutter/generated_plugin_registrant.cc | 4 ---- linux/flutter/generated_plugins.cmake | 2 +- macos/Flutter/GeneratedPluginRegistrant.swift | 2 -- macos/Podfile.lock | 9 +++++++-- windows/flutter/generated_plugin_registrant.cc | 3 --- windows/flutter/generated_plugins.cmake | 2 +- 9 files changed, 12 insertions(+), 15 deletions(-) diff --git a/crypto_plugins/xelis_flutter b/crypto_plugins/xelis_flutter index 24c66562d..0f333afd9 160000 --- a/crypto_plugins/xelis_flutter +++ b/crypto_plugins/xelis_flutter @@ -1 +1 @@ -Subproject commit 24c66562dce9019c1af7d43f5b58bba59e336e91 +Subproject commit 0f333afd91531e45dc4b2523af3f85fee9375edc diff --git a/lib/services/price.dart b/lib/services/price.dart index a3c31ef17..801e720e2 100644 --- a/lib/services/price.dart +++ b/lib/services/price.dart @@ -48,6 +48,7 @@ class PriceAPI { Namecoin: "namecoin", Nano: "nano", Banano: "banano", + Xelis: "xelis", }; static const refreshInterval = 60; diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 9935e0f18..84a8e0817 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -349,7 +349,7 @@ abstract class LibXelisWallet extends ExternalWallet final tableState = await getTableState(); final appDir = await getApplicationDocumentsDirectory(); final String name = walletId; - final String directory = path.join(appDir.path, '/'); + final String directory = appDir.path; final password = await secureStorageInterface.read( key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), ); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 4a096bcde..88c196c5e 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -16,7 +16,6 @@ #include #include #include -#include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) cs_monero_flutter_libs_linux_registrar = @@ -49,7 +48,4 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) window_size_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "WindowSizePlugin"); window_size_plugin_register_with_registrar(window_size_registrar); - g_autoptr(FlPluginRegistrar) xelis_flutter_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "XelisFlutterPlugin"); - xelis_flutter_plugin_register_with_registrar(xelis_flutter_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 22b92c965..aa67f97ac 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -13,7 +13,6 @@ list(APPEND FLUTTER_PLUGIN_LIST stack_wallet_backup url_launcher_linux window_size - xelis_flutter ) list(APPEND FLUTTER_FFI_PLUGIN_LIST @@ -22,6 +21,7 @@ list(APPEND FLUTTER_FFI_PLUGIN_LIST flutter_libsparkmobile frostdart tor_ffi_plugin + xelis_flutter ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 73a62daf8..245400e1a 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -26,7 +26,6 @@ import stack_wallet_backup import url_launcher_macos import wakelock_plus import window_size -import xelis_flutter func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { CameraMacosPlugin.register(with: registry.registrar(forPlugin: "CameraMacosPlugin")) @@ -50,5 +49,4 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) WindowSizePlugin.register(with: registry.registrar(forPlugin: "WindowSizePlugin")) - XelisFlutterPlugin.register(with: registry.registrar(forPlugin: "XelisFlutterPlugin")) } diff --git a/macos/Podfile.lock b/macos/Podfile.lock index fa0068398..12715b6ea 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -65,6 +65,8 @@ PODS: - FlutterMacOS - window_size (0.0.2): - FlutterMacOS + - xelis_flutter (0.0.1): + - FlutterMacOS DEPENDENCIES: - camera_macos (from `Flutter/ephemeral/.symlinks/plugins/camera_macos/macos`) @@ -92,6 +94,7 @@ DEPENDENCIES: - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) - window_size (from `Flutter/ephemeral/.symlinks/plugins/window_size/macos`) + - xelis_flutter (from `Flutter/ephemeral/.symlinks/plugins/xelis_flutter/macos`) SPEC REPOS: trunk: @@ -149,6 +152,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos window_size: :path: Flutter/ephemeral/.symlinks/plugins/window_size/macos + xelis_flutter: + :path: Flutter/ephemeral/.symlinks/plugins/xelis_flutter/macos SPEC CHECKSUMS: camera_macos: c2603f5eed16f05076cf17e12030d2ce55a77839 @@ -170,7 +175,7 @@ SPEC CHECKSUMS: package_info_plus: f5790acc797bf17c3e959e9d6cf162cc68ff7523 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 - share_plus: 76dd39142738f7a68dd57b05093b5e8193f220f7 + share_plus: 3c787998077d6b31e839225a282e9e27edf99274 sqlite3: 292c3e1bfe89f64e51ea7fc7dab9182a017c8630 sqlite3_flutter_libs: 1be4459672f8168ded2d8667599b8e3ca5e72b83 stack_wallet_backup: 6ebc60b1bdcf11cf1f1cbad9aa78332e1e15778c @@ -181,4 +186,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index eca37870c..74ef33c4e 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -20,7 +20,6 @@ #include #include #include -#include void RegisterPlugins(flutter::PluginRegistry* registry) { CameraWindowsRegisterWithRegistrar( @@ -51,6 +50,4 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("UrlLauncherWindows")); WindowSizePluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("WindowSizePlugin")); - XelisFlutterPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("XelisFlutterPluginCApi")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 4c59517d9..55c2cc622 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -17,7 +17,6 @@ list(APPEND FLUTTER_PLUGIN_LIST stack_wallet_backup url_launcher_windows window_size - xelis_flutter ) list(APPEND FLUTTER_FFI_PLUGIN_LIST @@ -25,6 +24,7 @@ list(APPEND FLUTTER_FFI_PLUGIN_LIST flutter_libsparkmobile frostdart tor_ffi_plugin + xelis_flutter ) set(PLUGIN_BUNDLED_LIBRARIES) From e04efc7247f6513d1019f4adeaef8300edd170ce Mon Sep 17 00:00:00 2001 From: Anthony Tritonn Date: Sat, 15 Feb 2025 22:38:34 -0800 Subject: [PATCH 11/50] Apple/iOS builds working (with PRs from plugins) --- crypto_plugins/xelis_flutter | 2 +- ios/Podfile.lock | 36 +++++++++++-------- .../xcshareddata/xcschemes/Runner.xcscheme | 1 + scripts/app_config/templates/pubspec.template | 2 +- scripts/ios/build_all.sh | 8 +---- scripts/ios/build_all_campfire.sh | 2 -- scripts/ios/build_all_duo.sh | 2 -- scripts/macos/build_all.sh | 2 -- scripts/macos/build_all_campfire.sh | 2 -- scripts/macos/build_all_duo.sh | 2 -- 10 files changed, 25 insertions(+), 34 deletions(-) diff --git a/crypto_plugins/xelis_flutter b/crypto_plugins/xelis_flutter index 0f333afd9..6ab305434 160000 --- a/crypto_plugins/xelis_flutter +++ b/crypto_plugins/xelis_flutter @@ -1 +1 @@ -Subproject commit 0f333afd91531e45dc4b2523af3f85fee9375edc +Subproject commit 6ab3054347e6b58776c69059e3352ab980b0b83e diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 54bf5e55f..64fb9ea9e 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -109,6 +109,8 @@ PODS: - Flutter - wakelock_plus (0.0.1): - Flutter + - xelis_flutter (0.0.1): + - Flutter DEPENDENCIES: - barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`) @@ -138,6 +140,7 @@ DEPENDENCIES: - tor_ffi_plugin (from `.symlinks/plugins/tor_ffi_plugin/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) + - xelis_flutter (from `.symlinks/plugins/xelis_flutter/ios`) SPEC REPOS: trunk: @@ -205,6 +208,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/url_launcher_ios/ios" wakelock_plus: :path: ".symlinks/plugins/wakelock_plus/ios" + xelis_flutter: + :path: ".symlinks/plugins/xelis_flutter/ios" SPEC CHECKSUMS: barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0 @@ -215,34 +220,35 @@ SPEC CHECKSUMS: devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926 DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 - file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 + file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_libepiccash: 36241aa7d3126f6521529985ccb3dc5eaf7bb317 - flutter_libsparkmobile: 6373955cc3327a926d17059e7405dde2fb12f99f - flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086 - flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef - flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be + flutter_libepiccash: 7d480d11241faea8aefdcb96991319c5e26d4735 + flutter_libsparkmobile: e2fcf99dafae4f5d28bf15468bad6d2ba9403c64 + flutter_local_notifications: ad39620c743ea4c15127860f4b5641649a988100 + flutter_native_splash: 9e672d3818957718ee006a491730c09deeecace9 + flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418 frostdart: 4c72b69ccac2f13ede744107db046a125acce597 - integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 - isar_flutter_libs: fdf730ca925d05687f36d7f1d355e482529ed097 - lelantus: 417f0221260013dfc052cae9cf4b741b6479edba - local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3 + integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e + isar_flutter_libs: bc909e72c3d756c2759f14c8776c13b5b0556e26 + lelantus: a5bdee9de3d78dedd1fffda1d92ea3c67106881f + local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391 MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866 - share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5 + share_plus: de6030e33b4e106470e09322d87cf2a4258d2d1d sqlite3: 292c3e1bfe89f64e51ea7fc7dab9182a017c8630 sqlite3_flutter_libs: 0d611efdf6d1c9297d5ab03dab21b75aeebdae31 stack_wallet_backup: 5b8563aba5d8ffbf2ce1944331ff7294a0ec7c03 SwiftProtobuf: 6ef3f0e422ef90d6605ca20b21a94f6c1324d6b3 SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 - tor_ffi_plugin: d80e291b649379c8176e1be739e49be007d4ef93 - url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe - wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1 + tor_ffi_plugin: 2a4dd758515e5124dce8323f950f6bb135e611b5 + url_launcher_ios: 694010445543906933d732453a59da0a173ae33d + wakelock_plus: fd58c82b1388f4afe3fe8aa2c856503a262a5b03 + xelis_flutter: 63a1007da6fd27faa9f451bb9c2f7aa165c01cbe PODFILE CHECKSUM: 57c8aed26fba39d3ec9424816221f294a07c58eb -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 5e31d3d34..c53e2b314 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -48,6 +48,7 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" + enableGPUValidationMode = "1" allowLocationSimulation = "YES"> diff --git a/scripts/app_config/templates/pubspec.template b/scripts/app_config/templates/pubspec.template index f56904fde..e4d0612ac 100644 --- a/scripts/app_config/templates/pubspec.template +++ b/scripts/app_config/templates/pubspec.template @@ -11,7 +11,7 @@ description: Stack Wallet # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 2.1.1+211 +version: 2.1.2+212 environment: sdk: ">=3.7.0 <4.0.0" diff --git a/scripts/ios/build_all.sh b/scripts/ios/build_all.sh index 013346c9b..f21a66453 100755 --- a/scripts/ios/build_all.sh +++ b/scripts/ios/build_all.sh @@ -10,15 +10,9 @@ set_rust_to_1671 rustup target add aarch64-apple-ios rustup target add x86_64-apple-ios -# ensure ios rust triples are there -rustup target add aarch64-apple-ios -rustup target add x86_64-apple-ios - (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) -(cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) -set_rust_to_1840 -(cd ../../crypto_plugins/xelis_flutter/scripts/ios && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) wait diff --git a/scripts/ios/build_all_campfire.sh b/scripts/ios/build_all_campfire.sh index 013346c9b..bcb03e991 100755 --- a/scripts/ios/build_all_campfire.sh +++ b/scripts/ios/build_all_campfire.sh @@ -16,8 +16,6 @@ rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) -set_rust_to_1840 -(cd ../../crypto_plugins/xelis_flutter/scripts/ios && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) diff --git a/scripts/ios/build_all_duo.sh b/scripts/ios/build_all_duo.sh index 02045eb26..89e6f4641 100755 --- a/scripts/ios/build_all_duo.sh +++ b/scripts/ios/build_all_duo.sh @@ -18,8 +18,6 @@ rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) -set_rust_to_1840 -(cd ../../crypto_plugins/xelis_flutter/scripts/ios && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) diff --git a/scripts/macos/build_all.sh b/scripts/macos/build_all.sh index 6f612b822..af608846f 100755 --- a/scripts/macos/build_all.sh +++ b/scripts/macos/build_all.sh @@ -8,8 +8,6 @@ set_rust_to_1671 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) -set_rust_to_1840 -(cd ../../crypto_plugins/xelis_flutter/scripts/macos && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) diff --git a/scripts/macos/build_all_campfire.sh b/scripts/macos/build_all_campfire.sh index 6f612b822..af608846f 100755 --- a/scripts/macos/build_all_campfire.sh +++ b/scripts/macos/build_all_campfire.sh @@ -8,8 +8,6 @@ set_rust_to_1671 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) -set_rust_to_1840 -(cd ../../crypto_plugins/xelis_flutter/scripts/macos && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) diff --git a/scripts/macos/build_all_duo.sh b/scripts/macos/build_all_duo.sh index 387020650..8a53e5801 100755 --- a/scripts/macos/build_all_duo.sh +++ b/scripts/macos/build_all_duo.sh @@ -10,8 +10,6 @@ set_rust_to_1671 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) -set_rust_to_1840 -(cd ../../crypto_plugins/xelis_flutter/scripts/macos && ./build_all.sh ) set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) From 2f02d4dc58fa11f00a5e533e511913a677934a0c Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Sun, 16 Feb 2025 00:04:23 -0800 Subject: [PATCH 12/50] removed Xelis lib from build scripts --- crypto_plugins/xelis_flutter | 2 +- pubspec.lock | 92 +++++++++++++-------------- scripts/android/build_all.sh | 4 +- scripts/android/build_all_campfire.sh | 4 +- scripts/android/build_all_duo.sh | 4 +- scripts/ios/build_all_campfire.sh | 2 +- scripts/ios/build_all_duo.sh | 2 +- scripts/linux/build_all.sh | 4 +- scripts/linux/build_all_campfire.sh | 4 +- scripts/linux/build_all_duo.sh | 4 +- scripts/macos/build_all.sh | 2 +- scripts/macos/build_all_campfire.sh | 2 +- scripts/macos/build_all_duo.sh | 2 +- scripts/windows/build_all.sh | 4 +- scripts/windows/build_all_campfire.sh | 4 +- scripts/windows/build_all_duo.sh | 4 +- 16 files changed, 61 insertions(+), 79 deletions(-) diff --git a/crypto_plugins/xelis_flutter b/crypto_plugins/xelis_flutter index 6ab305434..0f333afd9 160000 --- a/crypto_plugins/xelis_flutter +++ b/crypto_plugins/xelis_flutter @@ -1 +1 @@ -Subproject commit 6ab3054347e6b58776c69059e3352ab980b0b83e +Subproject commit 0f333afd91531e45dc4b2523af3f85fee9375edc diff --git a/pubspec.lock b/pubspec.lock index a7480b775..4113dc2eb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -58,10 +58,10 @@ packages: dependency: "direct main" description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.11.0" barcode_scan2: dependency: "direct main" description: @@ -159,10 +159,10 @@ packages: dependency: transitive description: name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" borsh_annotation: dependency: transitive description: @@ -305,10 +305,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.3.0" charcode: dependency: transitive description: @@ -337,10 +337,10 @@ packages: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" code_builder: dependency: transitive description: @@ -371,10 +371,10 @@ packages: dependency: transitive description: name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.19.1" + version: "1.19.0" compat: dependency: "direct main" description: @@ -742,10 +742,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.1" ffi: dependency: "direct main" description: @@ -758,10 +758,10 @@ packages: dependency: transitive description: name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "7.0.0" file_picker: dependency: "direct main" description: @@ -1229,18 +1229,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -1341,10 +1341,10 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: @@ -1365,10 +1365,10 @@ packages: dependency: "direct main" description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.15.0" mime: dependency: transitive description: @@ -1486,10 +1486,10 @@ packages: dependency: transitive description: name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.9.0" path_parsing: dependency: transitive description: @@ -1614,10 +1614,10 @@ packages: dependency: transitive description: name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.6" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -1654,10 +1654,10 @@ packages: dependency: transitive description: name: process - sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" url: "https://pub.dev" source: hosted - version: "5.0.3" + version: "5.0.2" protobuf: dependency: transitive description: @@ -1861,10 +1861,10 @@ packages: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.10.1" + version: "1.10.0" sqlite3: dependency: "direct main" description: @@ -1885,10 +1885,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.12.1" + version: "1.12.0" stack_wallet_backup: dependency: "direct main" description: @@ -1918,10 +1918,10 @@ packages: dependency: "direct main" description: name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.2" stream_transform: dependency: transitive description: @@ -1934,10 +1934,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.3.0" string_validator: dependency: "direct main" description: @@ -1958,34 +1958,34 @@ packages: dependency: transitive description: name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.2.1" test: dependency: transitive description: name: test - sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e" + sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" url: "https://pub.dev" source: hosted - version: "1.25.15" + version: "1.25.8" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.3" test_core: dependency: transitive description: name: test_core - sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa" + sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" url: "https://pub.dev" source: hosted - version: "0.6.8" + version: "0.6.5" tezart: dependency: "direct main" description: @@ -2192,10 +2192,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "14.3.0" wakelock_platform_interface: dependency: transitive description: diff --git a/scripts/android/build_all.sh b/scripts/android/build_all.sh index b6e6527c3..6547783e2 100755 --- a/scripts/android/build_all.sh +++ b/scripts/android/build_all.sh @@ -13,10 +13,8 @@ mkdir -p build PLUGINS_DIR=../../crypto_plugins (cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh ) -(cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) -set_rust_to_1840 -(cd "${PLUGINS_DIR}"/xelis_flutter/scripts/android && ./build_all.sh ) set_rust_to_1720 +(cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) (cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh ) wait diff --git a/scripts/android/build_all_campfire.sh b/scripts/android/build_all_campfire.sh index b6e6527c3..6547783e2 100755 --- a/scripts/android/build_all_campfire.sh +++ b/scripts/android/build_all_campfire.sh @@ -13,10 +13,8 @@ mkdir -p build PLUGINS_DIR=../../crypto_plugins (cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh ) -(cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) -set_rust_to_1840 -(cd "${PLUGINS_DIR}"/xelis_flutter/scripts/android && ./build_all.sh ) set_rust_to_1720 +(cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) (cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh ) wait diff --git a/scripts/android/build_all_duo.sh b/scripts/android/build_all_duo.sh index a84ec4f8f..30ea1b82c 100755 --- a/scripts/android/build_all_duo.sh +++ b/scripts/android/build_all_duo.sh @@ -15,10 +15,8 @@ mkdir -p build PLUGINS_DIR=../../crypto_plugins (cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh ) -(cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) -set_rust_to_1840 -(cd "${PLUGINS_DIR}"/xelis_flutter/scripts/android && ./build_all.sh ) set_rust_to_1720 +(cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) (cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh ) wait diff --git a/scripts/ios/build_all_campfire.sh b/scripts/ios/build_all_campfire.sh index bcb03e991..1389a0dcc 100755 --- a/scripts/ios/build_all_campfire.sh +++ b/scripts/ios/build_all_campfire.sh @@ -15,8 +15,8 @@ rustup target add aarch64-apple-ios rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) -(cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) wait diff --git a/scripts/ios/build_all_duo.sh b/scripts/ios/build_all_duo.sh index 89e6f4641..60f9192ec 100755 --- a/scripts/ios/build_all_duo.sh +++ b/scripts/ios/build_all_duo.sh @@ -17,8 +17,8 @@ rustup target add aarch64-apple-ios rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) -(cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) wait diff --git a/scripts/linux/build_all.sh b/scripts/linux/build_all.sh index 746bfd880..f45a500ff 100755 --- a/scripts/linux/build_all.sh +++ b/scripts/linux/build_all.sh @@ -13,10 +13,8 @@ set_rust_to_1671 mkdir -p build ./build_secure_storage_deps.sh (cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh ) -(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) -set_rust_to_1840 -(cd ../../crypto_plugins/xelis_flutter/scripts/linux && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) (cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) ./build_secp256k1.sh diff --git a/scripts/linux/build_all_campfire.sh b/scripts/linux/build_all_campfire.sh index 746bfd880..f45a500ff 100755 --- a/scripts/linux/build_all_campfire.sh +++ b/scripts/linux/build_all_campfire.sh @@ -13,10 +13,8 @@ set_rust_to_1671 mkdir -p build ./build_secure_storage_deps.sh (cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh ) -(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) -set_rust_to_1840 -(cd ../../crypto_plugins/xelis_flutter/scripts/linux && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) (cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) ./build_secp256k1.sh diff --git a/scripts/linux/build_all_duo.sh b/scripts/linux/build_all_duo.sh index 1fa5419c5..6c8d5cd58 100755 --- a/scripts/linux/build_all_duo.sh +++ b/scripts/linux/build_all_duo.sh @@ -15,10 +15,8 @@ set_rust_to_1671 mkdir -p build ./build_secure_storage_deps.sh & (cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh ) -(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) -set_rust_to_1840 -(cd ../../crypto_plugins/xelis_flutter/scripts/linux && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) (cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) ./build_secp256k1.sh diff --git a/scripts/macos/build_all.sh b/scripts/macos/build_all.sh index af608846f..e7a9b6eea 100755 --- a/scripts/macos/build_all.sh +++ b/scripts/macos/build_all.sh @@ -7,8 +7,8 @@ source ../rust_version.sh set_rust_to_1671 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) -(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) wait diff --git a/scripts/macos/build_all_campfire.sh b/scripts/macos/build_all_campfire.sh index af608846f..e7a9b6eea 100755 --- a/scripts/macos/build_all_campfire.sh +++ b/scripts/macos/build_all_campfire.sh @@ -7,8 +7,8 @@ source ../rust_version.sh set_rust_to_1671 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) -(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) wait diff --git a/scripts/macos/build_all_duo.sh b/scripts/macos/build_all_duo.sh index 8a53e5801..ffba77824 100755 --- a/scripts/macos/build_all_duo.sh +++ b/scripts/macos/build_all_duo.sh @@ -9,8 +9,8 @@ source ../rust_version.sh set_rust_to_1671 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) -(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) wait diff --git a/scripts/windows/build_all.sh b/scripts/windows/build_all.sh index 498e95b75..7398f9ca0 100755 --- a/scripts/windows/build_all.sh +++ b/scripts/windows/build_all.sh @@ -8,10 +8,8 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) -(cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) -set_rust_to_1840 -(cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_campfire.sh b/scripts/windows/build_all_campfire.sh index 6eb31ac04..6c7d153ce 100755 --- a/scripts/windows/build_all_campfire.sh +++ b/scripts/windows/build_all_campfire.sh @@ -8,10 +8,8 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) -(cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) -set_rust_to_1840 -(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_duo.sh b/scripts/windows/build_all_duo.sh index 5b5b0772a..5d77f4292 100755 --- a/scripts/windows/build_all_duo.sh +++ b/scripts/windows/build_all_duo.sh @@ -10,10 +10,8 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) -(cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) -set_rust_to_1840 -(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh From 0dad4ad591a8f4b37216416898cd8a30cee721f9 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Mon, 17 Feb 2025 11:16:13 -0800 Subject: [PATCH 13/50] updated linux devops for new Xelis flutter setup, fixed Xelis fee estimation bug --- lib/wallets/wallet/impl/xelis_wallet.dart | 101 +++++++++++------- .../app_config/templates/linux/CMakeLists.txt | 3 - .../templates/windows/CMakeLists.txt | 4 - 3 files changed, 62 insertions(+), 46 deletions(-) diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 5fbbf976b..7e6fe2ebd 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -47,6 +47,8 @@ import 'package:stack_wallet_backup/generate_password.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import '../intermediate/lib_xelis_wallet.dart'; +import 'dart:math'; + class XelisWallet extends LibXelisWallet { XelisWallet(CryptoCurrencyNetwork network) : super(Xelis(network)); // ==================== Overrides ============================================ @@ -577,45 +579,66 @@ class XelisWallet extends LibXelisWallet { checkInitialized(); final asset = assetId ?? xelis_sdk.xelisAsset; - // // Use default address if recipients list is empty - // final effectiveRecipients = recipients.isNotEmpty - // ? recipients - // : [( - // address: 'xel:xz9574c80c4xegnvurazpmxhw5dlg2n0g9qm60uwgt75uqyx3pcsqzzra9m', - // amount: amount, - // isChange: false - // )]; - - // final transfers = await Future.wait( - // effectiveRecipients.map((recipient) async { - // final amountStr = await libXelisWallet!.formatCoin( - // atomicAmount: recipient.amount.raw, - // assetHash: asset - // ); - // return x_wallet.Transfer( - // floatAmount: amountStr as double, - // strAddress: recipient.address, - // assetHash: asset, - // ); - // }) - // ); - - // // Estimate fees - // final estimatedFeeString = await libXelisWallet!.estimateFees(transfers: transfers); - // final feeAmount = Amount( - // rawValue: BigInt.parse(estimatedFeeString), - // fractionDigits: cryptoCurrency.fractionDigits, - // ); - - // // Apply fee multiplier - // final multiplier = feeMultiplier ?? 1.0; - return Amount( - // rawValue: (BigInt.from((feeAmount.raw * - // BigInt.from((multiplier * 100).toInt())) / - // BigInt.from(100))), - rawValue: BigInt.zero, - fractionDigits: cryptoCurrency.fractionDigits, - ); + // Default values for a new wallet or when estimation fails + final defaultDecimals = 8; + final defaultFee = BigInt.from(0); + + // Use default address if recipients list is empty + final effectiveRecipients = recipients.isNotEmpty + ? recipients + : [( + address: 'xel:xz9574c80c4xegnvurazpmxhw5dlg2n0g9qm60uwgt75uqyx3pcsqzzra9m', + amount: amount, + isChange: false + )]; + + try { + final transfers = await Future.wait( + effectiveRecipients.map((recipient) async { + try { + final amt = double.parse(await libXelisWallet!.formatCoin( + atomicAmount: recipient.amount.raw, + assetHash: asset + )); + return x_wallet.Transfer( + floatAmount: amt, + strAddress: recipient.address, + assetHash: asset, + extraData: null, + ); + } catch (e) { + // Handle formatCoin error - use default conversion + debugPrint("formatCoin failed: $e, using fallback conversion"); + final rawAmount = recipient.amount.raw; + final floatAmount = rawAmount / BigInt.from(10).pow(defaultDecimals); + return x_wallet.Transfer( + floatAmount: floatAmount.toDouble(), + strAddress: recipient.address, + assetHash: asset, + extraData: null, + ); + } + }) + ); + + final decimals = await libXelisWallet!.getAssetDecimals( + asset: asset + ); + final estimatedFee = double.parse(await libXelisWallet!.estimateFees(transfers: transfers)); + final rawFee = (estimatedFee * pow(10, decimals)).round(); + return Amount( + rawValue: BigInt.from(rawFee), + fractionDigits: cryptoCurrency.fractionDigits, + ); + } catch (e, s) { + debugPrint("Fee estimation failed: $e\n$s"); + + debugPrint("Using fallback fee: $defaultFee"); + return Amount( + rawValue: defaultFee, + fractionDigits: cryptoCurrency.fractionDigits, + ); + } } catch (e, s) { Logging.instance.log( "Exception rethrown from estimateFeeFor(): $e\n$s", diff --git a/scripts/app_config/templates/linux/CMakeLists.txt b/scripts/app_config/templates/linux/CMakeLists.txt index f1853439c..25750ef4f 100644 --- a/scripts/app_config/templates/linux/CMakeLists.txt +++ b/scripts/app_config/templates/linux/CMakeLists.txt @@ -140,9 +140,6 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libepiccash install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_liblelantus/scripts/linux/build/libmobileliblelantus.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) -install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/xelis_flutter/scripts/linux/build/libxelis_flutter.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/jsoncpp/build/src/lib_json/libjsoncpp.so.1.7.4" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/jsoncpp/build/src/lib_json/libjsoncpp.so.1" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" diff --git a/scripts/app_config/templates/windows/CMakeLists.txt b/scripts/app_config/templates/windows/CMakeLists.txt index e998725c9..b9add856d 100644 --- a/scripts/app_config/templates/windows/CMakeLists.txt +++ b/scripts/app_config/templates/windows/CMakeLists.txt @@ -86,10 +86,6 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libepiccash install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_liblelantus/scripts/windows/build/libmobileliblelantus.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) -# todo make this handle arm+x86, required plugin adjustment -# install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/xelis_flutter/windows/bin/x86_64-unknown-windows-msvc/release/libxelis_flutter.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" -# COMPONENT Runtime) - if(PLUGIN_BUNDLED_LIBRARIES) install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" From 102fab5faee2f2969a8baa40bdb0dc98df2d77a3 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Mon, 17 Feb 2025 14:01:05 -0800 Subject: [PATCH 14/50] updated price_test, corrected outgoing tx db entries for xelis --- crypto_plugins/xelis_flutter | 2 +- .../tx_v2/transaction_v2_details_view.dart | 8 +++- lib/wallets/wallet/impl/xelis_wallet.dart | 21 +++++++++- test/price_test.dart | 38 ++++++++++++------- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/crypto_plugins/xelis_flutter b/crypto_plugins/xelis_flutter index 0f333afd9..0413b9e49 160000 --- a/crypto_plugins/xelis_flutter +++ b/crypto_plugins/xelis_flutter @@ -1 +1 @@ -Subproject commit 0f333afd91531e45dc4b2523af3f85fee9375edc +Subproject commit 0413b9e49fa5fb8f0b30c8c5c559228f26435e2c diff --git a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart index 2acb6b1a1..8f0852941 100644 --- a/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart +++ b/lib/pages/wallet_view/transaction_views/tx_v2/transaction_v2_details_view.dart @@ -1366,13 +1366,17 @@ class _TransactionV2DetailsViewState ], ), ), - if (coin is! NanoCurrency) + if (coin is! NanoCurrency && + !(coin is Xelis && _transaction.type == TransactionType.incoming) + ) isDesktop ? const _Divider() : const SizedBox( height: 12, ), - if (coin is! NanoCurrency) + if (coin is! NanoCurrency && + !(coin is Xelis && _transaction.type == TransactionType.incoming) + ) RoundedWhiteContainer( padding: isDesktop ? const EdgeInsets.all(16) diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 7e6fe2ebd..4eb300b90 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -356,6 +356,14 @@ class XelisWallet extends LibXelisWallet { coinbase: null, walletOwns: true, )); + + outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( + scriptPubKeyHex: "", + valueStringSats: burn.amount.toString(), + addresses: ['burn'], + walletOwns: false, + )); + otherData['burnAsset'] = burn.asset; } else if (entryType is xelis_sdk.IncomingEntry) { final incoming = entryType; @@ -376,9 +384,10 @@ class XelisWallet extends LibXelisWallet { outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( scriptPubKeyHex: "", valueStringSats: transfer.amount.toString(), - addresses: [incoming.from], + addresses: [thisAddress], walletOwns: true, )); + otherData['asset_${transfer.asset}'] = transfer.amount.toString(); if (transfer.extraData != null) { otherData['extraData_${transfer.asset}'] = transfer.extraData!.toJson(); @@ -404,13 +413,21 @@ class XelisWallet extends LibXelisWallet { scriptSigAsm: null, sequence: null, outpoint: null, - addresses: [transfer.destination], + addresses: [thisAddress], valueStringSats: (transfer.amount + outgoing.fee).toString(), witness: null, innerRedeemScriptAsm: null, coinbase: null, walletOwns: true, )); + + outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( + scriptPubKeyHex: "", + valueStringSats: transfer.amount.toString(), + addresses: [transfer.destination], + walletOwns: false, + )); + otherData['asset_${transfer.asset}_amount'] = transfer.amount.toString(); otherData['asset_${transfer.asset}_fee'] = fee.toString(); if (transfer.extraData != null) { diff --git a/test/price_test.dart b/test/price_test.dart index dc7aaeb9e..2a5b9c038 100644 --- a/test/price_test.dart +++ b/test/price_test.dart @@ -30,7 +30,7 @@ void main() { url: Uri.parse( "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids" "=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,bitcoin-cash" - ",namecoin,wownero,ethereum,particl,nano,banano,stellar,tezos" + ",namecoin,wownero,ethereum,particl,nano,banano,stellar,tezos,xelis" "&order=market_cap_desc&per_page=50" "&page=1&sparkline=false"), headers: { @@ -93,7 +93,10 @@ void main() { 'max_supply":null,"ath":0.00013848,"ath_change_percentage":-79.75864' ',"ath_date":"2021-12-11T08:39:41.129Z","atl":5.74028e-07,"atl_chang' 'e_percentage":4783.08078,"atl_date":"2020-03-13T16:55:01.177Z","roi' - '":null,"last_updated":"2022-08-22T16:38:32.826Z"}]'), + '":null,"last_updated":"2022-08-22T16:38:32.826Z"},{"id":"xelis","sy' + 'mbol":"xel","name":"Xelis","image":"https://assets.coingecko.com/co' + 'ins/images/37615/large/green_background_black_logo.png","current_pr' + 'ice":0.00001234,"price_change_percentage_24h":5.67}]'), 200)); final priceAPI = PriceAPI(client); @@ -125,7 +128,8 @@ void main() { 'Coin.dogecoinTestNet: [0, 0.0], ' 'Coin.firoTestNet: [0, 0.0], ' 'Coin.litecoinTestNet: [0, 0.0], ' - 'Coin.stellarTestnet: [0, 0.0]' + 'Coin.stellarTestnet: [0, 0.0], ' + 'Coin.xelis: [0.00001234, 5.67]' '}', ); verify(client.get( @@ -134,7 +138,7 @@ void main() { "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc" "&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin," "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,stellar" - ",tezos" + ",tezos,xelis" "&order=market_cap_desc&per_page=50&page=1&sparkline=false", ), headers: {'Content-Type': 'application/json'})).called(1); @@ -151,7 +155,7 @@ void main() { "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&" "ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin," "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,stellar" - ",tezos" + ",tezos,xelis" "&order=market_cap_desc&per_page=50&page=1&sparkline=false"), headers: { 'Content-Type': 'application/json' @@ -213,7 +217,10 @@ void main() { '21000000.0,"max_supply":null,"ath":0.00013848,"ath_change_percentag' 'e":-79.75864,"ath_date":"2021-12-11T08:39:41.129Z","atl":5.74028e-0' '7,"atl_change_percentage":4783.08078,"atl_date":"2020-03-13T16:55:01' - '.177Z","roi":null,"last_updated":"2022-08-22T16:38:32.826Z"}]'), + '.177Z","roi":null,"last_updated":"2022-08-22T16:38:32.826Z"},{"id":' + '"xelis","symbol":"xel","name":"Xelis","image":"https://assets.coing' + 'ecko.com/coins/images/37615/large/green_background_black_logo.png",' + '"current_price":0.00001234,"price_change_percentage_24h":5.67}]'), 200)); final priceAPI = PriceAPI(client); @@ -247,7 +254,8 @@ void main() { 'Coin.bitcoincashTestnet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], ' 'Coin.firoTestNet: [0, 0.0], ' 'Coin.litecoinTestNet: [0, 0.0], ' - 'Coin.stellarTestnet: [0, 0.0]' + 'Coin.stellarTestnet: [0, 0.0], ' + 'Coin.xelis: [0.00001234, 5.67]' '}', ); @@ -258,7 +266,7 @@ void main() { "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids" "=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin," "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,stellar" - ",tezos" + ",tezos,xelis" "&order=market_cap_desc&per_page=50&page=1&sparkline=false"), headers: {'Content-Type': 'application/json'})).called(1); @@ -274,7 +282,7 @@ void main() { "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc" "&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin," "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,stellar" - ",tezos" + ",tezos,xelis" "&order=market_cap_desc&per_page=50&page=1&sparkline=false"), headers: { 'Content-Type': 'application/json' @@ -337,7 +345,9 @@ void main() { 'y":21000000.0,"max_supply":null,"ath":0.00013848,"ath_change_perce' 'ntage":-79.75864,"ath_date":"2021-12-11T08:39:41.129Z","atl":5.74' '028e-07,"atl_change_percentage":4783.08078,"atl_date":"2020-03-13T' - '16:55:01.177Z","roi":null,"last_updated":"2022-08-22T16:38:32.826Z"}]'), + '16:55:01.177Z","roi":null,"last_updated":"2022-08-22T16:38:32.826Z"' + '},{"id":"xelis","symbol":xel,"name":com/coins/images/37615/large/g' + 'reen_background_black_logo.png,"image":"https://assets.coingecko'), 200)); final priceAPI = PriceAPI(client); @@ -368,7 +378,8 @@ void main() { 'Coin.dogecoinTestNet: [0, 0.0], ' 'Coin.firoTestNet: [0, 0.0], ' 'Coin.litecoinTestNet: [0, 0.0], ' - 'Coin.stellarTestnet: [0, 0.0]' + 'Coin.stellarTestnet: [0, 0.0], ' + 'Coin.xelis: [0, 0.0]' '}', ); }); @@ -382,7 +393,7 @@ void main() { "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc" "&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin," "bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano,stellar" - ",tezos" + ",tezos,xelis" "&order=market_cap_desc&per_page=50&page=1&sparkline=false"), headers: { 'Content-Type': 'application/json' @@ -418,7 +429,8 @@ void main() { 'Coin.dogecoinTestNet: [0, 0.0], ' 'Coin.firoTestNet: [0, 0.0], ' 'Coin.litecoinTestNet: [0, 0.0], ' - 'Coin.stellarTestnet: [0, 0.0]' + 'Coin.stellarTestnet: [0, 0.0], ' + 'Coin.xelis: [0, 0.0]' '}', ); }); From 8b41d0b588da82f57bbec278853c7041f91114cf Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 20 Feb 2025 13:43:48 -0800 Subject: [PATCH 15/50] xelis_flutter branch switch adopted --- crypto_plugins/xelis_flutter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto_plugins/xelis_flutter b/crypto_plugins/xelis_flutter index 0413b9e49..e331de2f3 160000 --- a/crypto_plugins/xelis_flutter +++ b/crypto_plugins/xelis_flutter @@ -1 +1 @@ -Subproject commit 0413b9e49fa5fb8f0b30c8c5c559228f26435e2c +Subproject commit e331de2f38e8a0240ae42f1f0c2d4e752dce9574 From a06945b3a24e45b022f09a9e32da8b5ad2eeda6d Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 20 Feb 2025 13:51:29 -0800 Subject: [PATCH 16/50] xelis_flutter correction --- crypto_plugins/xelis_flutter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto_plugins/xelis_flutter b/crypto_plugins/xelis_flutter index e331de2f3..c87f524be 160000 --- a/crypto_plugins/xelis_flutter +++ b/crypto_plugins/xelis_flutter @@ -1 +1 @@ -Subproject commit e331de2f38e8a0240ae42f1f0c2d4e752dce9574 +Subproject commit c87f524be99fc3fe448d24a86f368c10ac5b1e0b From 2879e5bc03134d41c38e062f93b4964a7611e237 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 20 Feb 2025 14:12:59 -0800 Subject: [PATCH 17/50] updated fee estimation params in xelis_flutter --- crypto_plugins/xelis_flutter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto_plugins/xelis_flutter b/crypto_plugins/xelis_flutter index c87f524be..e939a8120 160000 --- a/crypto_plugins/xelis_flutter +++ b/crypto_plugins/xelis_flutter @@ -1 +1 @@ -Subproject commit c87f524be99fc3fe448d24a86f368c10ac5b1e0b +Subproject commit e939a81205c7eb9b29069f27c965ff38f9f677f3 From 8c6f660ec643b654c3f64c1360aec1ab734353b9 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Wed, 26 Feb 2025 14:33:28 -0800 Subject: [PATCH 18/50] libepiccash build script corrections, pubspec template adjusted for staging --- scripts/app_config/templates/pubspec.template | 6 +++--- scripts/ios/build_all.sh | 2 +- scripts/ios/build_all_campfire.sh | 2 +- scripts/ios/build_all_duo.sh | 2 +- scripts/linux/build_all.sh | 2 +- scripts/linux/build_all_campfire.sh | 2 +- scripts/linux/build_all_duo.sh | 2 +- scripts/macos/build_all.sh | 2 +- scripts/macos/build_all_campfire.sh | 2 +- scripts/macos/build_all_duo.sh | 2 +- scripts/windows/build_all.sh | 2 +- scripts/windows/build_all_campfire.sh | 2 +- scripts/windows/build_all_duo.sh | 2 +- 13 files changed, 15 insertions(+), 15 deletions(-) diff --git a/scripts/app_config/templates/pubspec.template b/scripts/app_config/templates/pubspec.template index e4d0612ac..76da23390 100644 --- a/scripts/app_config/templates/pubspec.template +++ b/scripts/app_config/templates/pubspec.template @@ -1,5 +1,5 @@ -name: stackwallet -description: Stack Wallet +name: PLACEHOLDER +description: PLACEHOLDER # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -11,7 +11,7 @@ description: Stack Wallet # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 2.1.2+212 +version: PLACEHOLDER_V+PLACEHOLDER_B environment: sdk: ">=3.7.0 <4.0.0" diff --git a/scripts/ios/build_all.sh b/scripts/ios/build_all.sh index f21a66453..bef3e9095 100755 --- a/scripts/ios/build_all.sh +++ b/scripts/ios/build_all.sh @@ -11,8 +11,8 @@ rustup target add aarch64-apple-ios rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) -set_rust_to_1720 (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) wait diff --git a/scripts/ios/build_all_campfire.sh b/scripts/ios/build_all_campfire.sh index 1389a0dcc..bcb03e991 100755 --- a/scripts/ios/build_all_campfire.sh +++ b/scripts/ios/build_all_campfire.sh @@ -15,8 +15,8 @@ rustup target add aarch64-apple-ios rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) -set_rust_to_1720 (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) wait diff --git a/scripts/ios/build_all_duo.sh b/scripts/ios/build_all_duo.sh index 60f9192ec..89e6f4641 100755 --- a/scripts/ios/build_all_duo.sh +++ b/scripts/ios/build_all_duo.sh @@ -17,8 +17,8 @@ rustup target add aarch64-apple-ios rustup target add x86_64-apple-ios (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) -set_rust_to_1720 (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh ) wait diff --git a/scripts/linux/build_all.sh b/scripts/linux/build_all.sh index f45a500ff..423646185 100755 --- a/scripts/linux/build_all.sh +++ b/scripts/linux/build_all.sh @@ -13,8 +13,8 @@ set_rust_to_1671 mkdir -p build ./build_secure_storage_deps.sh (cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh ) -set_rust_to_1720 (cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) ./build_secp256k1.sh diff --git a/scripts/linux/build_all_campfire.sh b/scripts/linux/build_all_campfire.sh index f45a500ff..423646185 100755 --- a/scripts/linux/build_all_campfire.sh +++ b/scripts/linux/build_all_campfire.sh @@ -13,8 +13,8 @@ set_rust_to_1671 mkdir -p build ./build_secure_storage_deps.sh (cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh ) -set_rust_to_1720 (cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) ./build_secp256k1.sh diff --git a/scripts/linux/build_all_duo.sh b/scripts/linux/build_all_duo.sh index 6c8d5cd58..78067b478 100755 --- a/scripts/linux/build_all_duo.sh +++ b/scripts/linux/build_all_duo.sh @@ -15,8 +15,8 @@ set_rust_to_1671 mkdir -p build ./build_secure_storage_deps.sh & (cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh ) -set_rust_to_1720 (cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh ) ./build_secp256k1.sh diff --git a/scripts/macos/build_all.sh b/scripts/macos/build_all.sh index e7a9b6eea..af608846f 100755 --- a/scripts/macos/build_all.sh +++ b/scripts/macos/build_all.sh @@ -7,8 +7,8 @@ source ../rust_version.sh set_rust_to_1671 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) -set_rust_to_1720 (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) wait diff --git a/scripts/macos/build_all_campfire.sh b/scripts/macos/build_all_campfire.sh index e7a9b6eea..af608846f 100755 --- a/scripts/macos/build_all_campfire.sh +++ b/scripts/macos/build_all_campfire.sh @@ -7,8 +7,8 @@ source ../rust_version.sh set_rust_to_1671 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) -set_rust_to_1720 (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) wait diff --git a/scripts/macos/build_all_duo.sh b/scripts/macos/build_all_duo.sh index ffba77824..8a53e5801 100755 --- a/scripts/macos/build_all_duo.sh +++ b/scripts/macos/build_all_duo.sh @@ -9,8 +9,8 @@ source ../rust_version.sh set_rust_to_1671 (cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh ) -set_rust_to_1720 (cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh ) wait diff --git a/scripts/windows/build_all.sh b/scripts/windows/build_all.sh index 7398f9ca0..191a46cc0 100755 --- a/scripts/windows/build_all.sh +++ b/scripts/windows/build_all.sh @@ -8,8 +8,8 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) -set_rust_to_1720 (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_campfire.sh b/scripts/windows/build_all_campfire.sh index 6c7d153ce..f7c98194c 100755 --- a/scripts/windows/build_all_campfire.sh +++ b/scripts/windows/build_all_campfire.sh @@ -8,8 +8,8 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) -set_rust_to_1720 (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_duo.sh b/scripts/windows/build_all_duo.sh index 5d77f4292..51ca3956b 100755 --- a/scripts/windows/build_all_duo.sh +++ b/scripts/windows/build_all_duo.sh @@ -10,8 +10,8 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) -set_rust_to_1720 (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) +set_rust_to_1720 (cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh From f56519ec1401fe7b34bda236052be9c894425f85 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 27 Feb 2025 12:44:14 -0800 Subject: [PATCH 19/50] svg change reversal --- .../svg/campfire/socials/discord.svg | 30 +++++++++---------- .../svg/campfire/socials/telegram-brands.svg | 20 ++++++------- .../svg/stack_duo/socials/discord.svg | 30 +++++++++---------- .../svg/stack_duo/socials/telegram-brands.svg | 20 ++++++------- .../svg/stack_wallet/socials/discord.svg | 30 +++++++++---------- .../stack_wallet/socials/telegram-brands.svg | 20 ++++++------- 6 files changed, 75 insertions(+), 75 deletions(-) diff --git a/asset_sources/svg/campfire/socials/discord.svg b/asset_sources/svg/campfire/socials/discord.svg index a93742dfd..4d6aff6ed 100644 --- a/asset_sources/svg/campfire/socials/discord.svg +++ b/asset_sources/svg/campfire/socials/discord.svg @@ -1,15 +1,15 @@ - - - - - + + + + + diff --git a/asset_sources/svg/campfire/socials/telegram-brands.svg b/asset_sources/svg/campfire/socials/telegram-brands.svg index 629eabf23..61d09ee08 100644 --- a/asset_sources/svg/campfire/socials/telegram-brands.svg +++ b/asset_sources/svg/campfire/socials/telegram-brands.svg @@ -1,10 +1,10 @@ - - - - - + + + + + diff --git a/asset_sources/svg/stack_duo/socials/discord.svg b/asset_sources/svg/stack_duo/socials/discord.svg index a93742dfd..4d6aff6ed 100644 --- a/asset_sources/svg/stack_duo/socials/discord.svg +++ b/asset_sources/svg/stack_duo/socials/discord.svg @@ -1,15 +1,15 @@ - - - - - + + + + + diff --git a/asset_sources/svg/stack_duo/socials/telegram-brands.svg b/asset_sources/svg/stack_duo/socials/telegram-brands.svg index 629eabf23..61d09ee08 100644 --- a/asset_sources/svg/stack_duo/socials/telegram-brands.svg +++ b/asset_sources/svg/stack_duo/socials/telegram-brands.svg @@ -1,10 +1,10 @@ - - - - - + + + + + diff --git a/asset_sources/svg/stack_wallet/socials/discord.svg b/asset_sources/svg/stack_wallet/socials/discord.svg index a93742dfd..4d6aff6ed 100644 --- a/asset_sources/svg/stack_wallet/socials/discord.svg +++ b/asset_sources/svg/stack_wallet/socials/discord.svg @@ -1,15 +1,15 @@ - - - - - + + + + + diff --git a/asset_sources/svg/stack_wallet/socials/telegram-brands.svg b/asset_sources/svg/stack_wallet/socials/telegram-brands.svg index 629eabf23..61d09ee08 100644 --- a/asset_sources/svg/stack_wallet/socials/telegram-brands.svg +++ b/asset_sources/svg/stack_wallet/socials/telegram-brands.svg @@ -1,10 +1,10 @@ - - - - - + + + + + From 0ed0ef3ed98f9a25b38683f288524268db1def13 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 27 Feb 2025 12:48:25 -0800 Subject: [PATCH 20/50] removed frostdart from windows build scripts --- scripts/windows/build_all.sh | 2 -- scripts/windows/build_all_campfire.sh | 2 -- scripts/windows/build_all_duo.sh | 2 -- 3 files changed, 6 deletions(-) diff --git a/scripts/windows/build_all.sh b/scripts/windows/build_all.sh index 191a46cc0..19668811f 100755 --- a/scripts/windows/build_all.sh +++ b/scripts/windows/build_all.sh @@ -9,8 +9,6 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) -set_rust_to_1720 -(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_campfire.sh b/scripts/windows/build_all_campfire.sh index f7c98194c..19668811f 100755 --- a/scripts/windows/build_all_campfire.sh +++ b/scripts/windows/build_all_campfire.sh @@ -9,8 +9,6 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) -set_rust_to_1720 -(cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_duo.sh b/scripts/windows/build_all_duo.sh index 51ca3956b..cc55fe70b 100755 --- a/scripts/windows/build_all_duo.sh +++ b/scripts/windows/build_all_duo.sh @@ -11,8 +11,6 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) -set_rust_to_1720 -(cd ../../crypto_plugins/xelis_flutter/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh From 448fd0c94d6b0be1d7889712f5a8d29c0181e36e Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 27 Feb 2025 12:49:42 -0800 Subject: [PATCH 21/50] keep version update without frostdart in windows build scripts --- scripts/windows/build_all.sh | 1 + scripts/windows/build_all_campfire.sh | 1 + scripts/windows/build_all_duo.sh | 1 + 3 files changed, 3 insertions(+) diff --git a/scripts/windows/build_all.sh b/scripts/windows/build_all.sh index 19668811f..4c9f03472 100755 --- a/scripts/windows/build_all.sh +++ b/scripts/windows/build_all.sh @@ -9,6 +9,7 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) +set_rust_to_1720 ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_campfire.sh b/scripts/windows/build_all_campfire.sh index 19668811f..4c9f03472 100755 --- a/scripts/windows/build_all_campfire.sh +++ b/scripts/windows/build_all_campfire.sh @@ -9,6 +9,7 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) +set_rust_to_1720 ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_duo.sh b/scripts/windows/build_all_duo.sh index cc55fe70b..db58ca1ff 100755 --- a/scripts/windows/build_all_duo.sh +++ b/scripts/windows/build_all_duo.sh @@ -11,6 +11,7 @@ set_rust_to_1671 mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) +set_rust_to_1720 ./build_secp256k1_wsl.sh From c1cd9869c02d215d25ee1dd7cae10fa73090fbc8 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Tue, 11 Mar 2025 15:19:49 -0700 Subject: [PATCH 22/50] removed xelis submodule in favor of git tag dependency --- .gitignore | 1 - .gitmodules | 3 --- crypto_plugins/xelis_flutter | 1 - lib/wallets/crypto_currency/coins/xelis.dart | 2 +- lib/wallets/models/tx_data.dart | 5 ----- lib/wallets/wallet/impl/xelis_wallet.dart | 2 +- pubspec.lock | 8 +++++--- 7 files changed, 7 insertions(+), 15 deletions(-) delete mode 160000 crypto_plugins/xelis_flutter diff --git a/.gitignore b/.gitignore index 5e86f725e..41677c67a 100644 --- a/.gitignore +++ b/.gitignore @@ -65,7 +65,6 @@ libepic_cash_wallet.dll libmobileliblelantus.dll libtor_ffi.dll flutter_libsparkmobile.dll -xelis_flutter.dll secp256k1.dll /libisar.so /lib/app_config.g.dart diff --git a/.gitmodules b/.gitmodules index 2f76b7ffa..2186826df 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,6 +7,3 @@ [submodule "crypto_plugins/frostdart"] path = crypto_plugins/frostdart url = https://github.com/cypherstack/frostdart -[submodule "crypto_plugins/xelis_flutter"] - path = crypto_plugins/xelis_flutter - url = https://github.com/Tritonn204/xelis_flutter_ffi.git diff --git a/crypto_plugins/xelis_flutter b/crypto_plugins/xelis_flutter deleted file mode 160000 index e939a8120..000000000 --- a/crypto_plugins/xelis_flutter +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e939a81205c7eb9b29069f27c965ff38f9f677f3 diff --git a/lib/wallets/crypto_currency/coins/xelis.dart b/lib/wallets/crypto_currency/coins/xelis.dart index 1f57b2afb..db4adf76b 100644 --- a/lib/wallets/crypto_currency/coins/xelis.dart +++ b/lib/wallets/crypto_currency/coins/xelis.dart @@ -50,7 +50,7 @@ class Xelis extends ElectrumCurrency { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( - host: "us-node.xelis.io", + host: "127.0.0.1", port: 443, name: DefaultNodes.defaultName, id: DefaultNodes.buildId(this), diff --git a/lib/wallets/models/tx_data.dart b/lib/wallets/models/tx_data.dart index b8839fe3d..94474e390 100644 --- a/lib/wallets/models/tx_data.dart +++ b/lib/wallets/models/tx_data.dart @@ -146,11 +146,6 @@ class TxData { return null; } - String? get getOtherData { - final val = this.otherData; - return val; - } - Amount? get amountSpark => sparkRecipients != null && sparkRecipients!.isNotEmpty ? sparkRecipients! diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 4eb300b90..81cbfafe8 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -678,7 +678,7 @@ class XelisWallet extends LibXelisWallet { final recipient = txData.recipients!.first; final Amount sendAmount = recipient.amount; - final asset = (txData.getOtherData != null ? jsonDecode(txData.getOtherData!) : null)?['asset'] ?? xelis_sdk.xelisAsset; + final asset = (txData.otherData != null ? jsonDecode(txData.otherData!) : null)?['asset'] ?? xelis_sdk.xelisAsset; final amt = double.parse(await libXelisWallet!.formatCoin( atomicAmount: sendAmount.raw, diff --git a/pubspec.lock b/pubspec.lock index 4113dc2eb..51772d2f4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -2345,9 +2345,11 @@ packages: xelis_flutter: dependency: "direct main" description: - path: "crypto_plugins/xelis_flutter" - relative: true - source: path + path: "." + ref: "v0.1.0" + resolved-ref: "2d36e584ae5d913b2634bcfe54e2266880cbd813" + url: "https://github.com/Tritonn204/xelis_flutter_ffi.git" + source: git version: "0.0.2" xml: dependency: transitive From 4e26e4c246af31f927f18bc45d85db9b21b2c865 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Tue, 11 Mar 2025 16:29:35 -0700 Subject: [PATCH 23/50] updated dep template --- pubspec.lock | 164 +++++++++--------- scripts/app_config/templates/pubspec.template | 6 +- 2 files changed, 86 insertions(+), 84 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 51772d2f4..55d7b344c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -183,10 +183,10 @@ packages: dependency: transitive description: name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" build_cli_annotations: dependency: transitive description: @@ -199,42 +199,42 @@ packages: dependency: transitive description: name: build_config - sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" build_daemon: dependency: transitive description: name: build_daemon - sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" + sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.0.4" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0 url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.4" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" + sha256: "74691599a5bc750dc96a6b4bfd48f7d9d66453eab04c7f4063134800d6a5c573" url: "https://pub.dev" source: hosted - version: "2.4.13" + version: "2.4.14" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 + sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" url: "https://pub.dev" source: hosted - version: "7.3.2" + version: "8.0.0" built_collection: dependency: transitive description: @@ -247,10 +247,10 @@ packages: dependency: transitive description: name: built_value - sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2" url: "https://pub.dev" source: hosted - version: "8.9.2" + version: "8.9.3" calendar_date_picker2: dependency: "direct main" description: @@ -572,10 +572,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" + sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820" url: "https://pub.dev" source: hosted - version: "2.3.7" + version: "2.3.8" dartx: dependency: transitive description: @@ -881,10 +881,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "9b78450b89f059e96c9ebb355fa6b3df1d6b330436e0b885fb49594c41721398" + sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e" url: "https://pub.dev" source: hosted - version: "2.0.23" + version: "2.0.24" flutter_riverpod: dependency: "direct main" description: @@ -953,10 +953,10 @@ packages: dependency: "direct main" description: name: flutter_svg - sha256: "1b7723a814d84fb65869ea7115cdb3ee7c3be5a27a755c1ec60e049f6b9fcbb2" + sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b url: "https://pub.dev" source: hosted - version: "2.0.11" + version: "2.0.17" flutter_test: dependency: "direct dev" description: flutter @@ -1016,10 +1016,10 @@ packages: dependency: transitive description: name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" google_fonts: dependency: "direct main" description: @@ -1096,18 +1096,18 @@ packages: dependency: transitive description: name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" ieee754: dependency: transitive description: @@ -1149,10 +1149,10 @@ packages: dependency: transitive description: name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" isar: dependency: "direct main" description: @@ -1205,10 +1205,10 @@ packages: dependency: transitive description: name: json_serializable - sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b + sha256: c2fcb3920cf2b6ae6845954186420fca40bc0a8abcc84903b7801f17d7050d7c url: "https://pub.dev" source: hosted - version: "6.8.0" + version: "6.9.0" jsontool: dependency: transitive description: @@ -1462,26 +1462,26 @@ packages: dependency: transitive description: name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" package_info_plus: dependency: "direct main" description: name: package_info_plus - sha256: df3eb3e0aed5c1107bb0fdb80a8e82e778114958b1c5ac5644fb1ac9cae8a998 + sha256: "739e0a5c3c4055152520fa321d0645ee98e932718b4c8efeeb51451968fe0790" url: "https://pub.dev" source: hosted - version: "8.1.0" + version: "8.1.3" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66 + sha256: a5ef9986efc7bf772f2696183a3992615baa76c1ffb1189318dd8803778fb05b url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" path: dependency: transitive description: @@ -1494,10 +1494,10 @@ packages: dependency: transitive description: name: path_parsing - sha256: caa17e8f0b386eb190dd5b6a3b71211c76375aa8b6ffb4465b5863d019bdb334 + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.1.0" path_provider: dependency: "direct main" description: @@ -1510,18 +1510,18 @@ packages: dependency: transitive description: name: path_provider_android - sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a + sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" url: "https://pub.dev" source: hosted - version: "2.2.12" + version: "2.2.15" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" path_provider_linux: dependency: transitive description: @@ -1670,18 +1670,18 @@ packages: dependency: transitive description: name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.5.0" qr: dependency: transitive description: @@ -1766,10 +1766,10 @@ packages: dependency: transitive description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" shelf_packages_handler: dependency: transitive description: @@ -1790,10 +1790,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" + sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" sky_engine: dependency: transitive description: flutter @@ -1812,10 +1812,10 @@ packages: description: path: "." ref: master - resolved-ref: b1fa8ca505e7e488edb4c2859f0218d48b15dead + resolved-ref: e6232c53c1595469931ababa878759a067c02e94 url: "https://github.com/cypherstack/socks_socket.git" source: git - version: "1.0.0" + version: "1.1.1" solana: dependency: "direct main" description: @@ -1837,10 +1837,10 @@ packages: dependency: transitive description: name: source_helper - sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" url: "https://pub.dev" source: hosted - version: "1.3.4" + version: "1.3.5" source_map_stack_trace: dependency: transitive description: @@ -1926,10 +1926,10 @@ packages: dependency: transitive description: name: stream_transform - sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: @@ -2015,10 +2015,10 @@ packages: dependency: transitive description: name: timing - sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.2" tint: dependency: transitive description: @@ -2096,26 +2096,26 @@ packages: dependency: transitive description: name: url_launcher_ios - sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e + sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.3.2" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672" + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" url_launcher_platform_interface: dependency: transitive description: @@ -2128,18 +2128,18 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.0" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4" + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" uuid: dependency: "direct main" description: @@ -2152,26 +2152,26 @@ packages: dependency: transitive description: name: vector_graphics - sha256: "0b9149c6ddb013818075b072b9ddc1b89a5122fff1275d4648d297086b46c4f0" + sha256: "27d5fefe86fb9aace4a9f8375b56b3c292b64d8c04510df230f849850d912cb7" url: "https://pub.dev" source: hosted - version: "1.1.12" + version: "1.1.15" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec - sha256: "2430b973a4ca3c4dbc9999b62b8c719a160100dcbae5c819bae0cacce32c9cdb" + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" url: "https://pub.dev" source: hosted - version: "1.1.12" + version: "1.1.13" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: f3b9b6e4591c11394d4be4806c63e72d3a41778547b2c1e2a8a04fadcfd7d173 + sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad" url: "https://pub.dev" source: hosted - version: "1.1.12" + version: "1.1.16" vector_math: dependency: transitive description: @@ -2249,10 +2249,10 @@ packages: dependency: transitive description: name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" web: dependency: "direct overridden" description: @@ -2305,10 +2305,10 @@ packages: dependency: "direct overridden" description: name: win32 - sha256: "10169d3934549017f0ae278ccb07f828f9d6ea21573bab0fb77b0e1ef0fce454" + sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e url: "https://pub.dev" source: hosted - version: "5.7.2" + version: "5.10.1" win32_registry: dependency: transitive description: @@ -2347,10 +2347,10 @@ packages: description: path: "." ref: "v0.1.0" - resolved-ref: "2d36e584ae5d913b2634bcfe54e2266880cbd813" + resolved-ref: "966469f2660226c33a1de77d1c5efee5459a2d4e" url: "https://github.com/Tritonn204/xelis_flutter_ffi.git" source: git - version: "0.0.2" + version: "0.1.0" xml: dependency: transitive description: @@ -2371,10 +2371,10 @@ packages: dependency: transitive description: name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.3" zxcvbn: dependency: "direct main" description: diff --git a/scripts/app_config/templates/pubspec.template b/scripts/app_config/templates/pubspec.template index 76da23390..8ebd267fb 100644 --- a/scripts/app_config/templates/pubspec.template +++ b/scripts/app_config/templates/pubspec.template @@ -31,8 +31,10 @@ dependencies: path: ./crypto_plugins/frostdart xelis_flutter: - path: ./crypto_plugins/xelis_flutter - + git: + url: https://github.com/Tritonn204/xelis_flutter_ffi.git + ref: v0.1.0 + xelis_dart_sdk: ^0.24.0 freezed_annotation: ^2.4.1 From f7b73620e24b754c6a82f71d8235745ef3022878 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Tue, 11 Mar 2025 19:42:22 -0700 Subject: [PATCH 24/50] added port information to xelis connection invocations --- lib/utilities/test_node_connection.dart | 2 +- lib/wallets/crypto_currency/coins/xelis.dart | 2 +- lib/wallets/wallet/intermediate/lib_xelis_wallet.dart | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/utilities/test_node_connection.dart b/lib/utilities/test_node_connection.dart index 8df98eab5..b75c22b93 100644 --- a/lib/utilities/test_node_connection.dart +++ b/lib/utilities/test_node_connection.dart @@ -304,7 +304,7 @@ Future testNodeConnection({ case Xelis(): try { final daemon = xelis_sdk.DaemonClient( - endPoint: formData.host!, + endPoint: "${formData.host!}:${formData.port!}", secureWebSocket: formData.useSSL ?? false, ); daemon.connect(); diff --git a/lib/wallets/crypto_currency/coins/xelis.dart b/lib/wallets/crypto_currency/coins/xelis.dart index db4adf76b..1f57b2afb 100644 --- a/lib/wallets/crypto_currency/coins/xelis.dart +++ b/lib/wallets/crypto_currency/coins/xelis.dart @@ -50,7 +50,7 @@ class Xelis extends ElectrumCurrency { switch (network) { case CryptoCurrencyNetwork.main: return NodeModel( - host: "127.0.0.1", + host: "us-node.xelis.io", port: 443, name: DefaultNodes.defaultName, id: DefaultNodes.buildId(this), diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 84a8e0817..6985754d9 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -301,11 +301,11 @@ abstract class LibXelisWallet extends ExternalWallet final node = getCurrentNode(); Logging.instance.log( - "Connecting to node: ${node.host}", + "Connecting to node: ${node.host}:${node.port}", level: LogLevel.Info, ); await libXelisWallet!.onlineMode( - daemonAddress: node.host + daemonAddress: "${node.host}:${node.port}" ); await super.refresh(); } catch (e, s) { From dd67d2fdbbd2c664f6d445b658a67dcf713df5ab Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 13 Mar 2025 15:57:46 -0700 Subject: [PATCH 25/50] reversions and deletions as per request --- flutter_01.png | 0 google_fonts/LICENSE.txt | 404 +++++++++--------- google_fonts/OFL.txt | 186 ++++---- scripts/android/build_all.sh | 2 +- scripts/android/build_all_campfire.sh | 2 +- scripts/android/build_all_duo.sh | 2 +- scripts/app_config/configure_stack_wallet.sh | 2 - scripts/app_config/templates/pubspec.template | 10 - scripts/ios/build_all.sh | 4 + scripts/rust_version.sh | 9 - scripts/windows/build_all.sh | 1 + scripts/windows/build_all_campfire.sh | 1 + scripts/windows/build_all_duo.sh | 1 + 13 files changed, 305 insertions(+), 319 deletions(-) delete mode 100644 flutter_01.png diff --git a/flutter_01.png b/flutter_01.png deleted file mode 100644 index e69de29bb..000000000 diff --git a/google_fonts/LICENSE.txt b/google_fonts/LICENSE.txt index d64569567..75b52484e 100644 --- a/google_fonts/LICENSE.txt +++ b/google_fonts/LICENSE.txt @@ -1,202 +1,202 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/google_fonts/OFL.txt b/google_fonts/OFL.txt index b525cbf3a..ad214842c 100644 --- a/google_fonts/OFL.txt +++ b/google_fonts/OFL.txt @@ -1,93 +1,93 @@ -Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. +Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/scripts/android/build_all.sh b/scripts/android/build_all.sh index 6547783e2..60aa13c6a 100755 --- a/scripts/android/build_all.sh +++ b/scripts/android/build_all.sh @@ -13,8 +13,8 @@ mkdir -p build PLUGINS_DIR=../../crypto_plugins (cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh ) -set_rust_to_1720 (cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) +set_rust_to_1720 (cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh ) wait diff --git a/scripts/android/build_all_campfire.sh b/scripts/android/build_all_campfire.sh index 6547783e2..60aa13c6a 100755 --- a/scripts/android/build_all_campfire.sh +++ b/scripts/android/build_all_campfire.sh @@ -13,8 +13,8 @@ mkdir -p build PLUGINS_DIR=../../crypto_plugins (cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh ) -set_rust_to_1720 (cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) +set_rust_to_1720 (cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh ) wait diff --git a/scripts/android/build_all_duo.sh b/scripts/android/build_all_duo.sh index 30ea1b82c..d67e700a8 100755 --- a/scripts/android/build_all_duo.sh +++ b/scripts/android/build_all_duo.sh @@ -15,8 +15,8 @@ mkdir -p build PLUGINS_DIR=../../crypto_plugins (cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh ) -set_rust_to_1720 (cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh ) +set_rust_to_1720 (cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh ) wait diff --git a/scripts/app_config/configure_stack_wallet.sh b/scripts/app_config/configure_stack_wallet.sh index a7311a19a..0fd8e5e8a 100755 --- a/scripts/app_config/configure_stack_wallet.sh +++ b/scripts/app_config/configure_stack_wallet.sh @@ -71,7 +71,6 @@ final List _supportedCoins = List.unmodifiable([ Peercoin(CryptoCurrencyNetwork.main), Solana(CryptoCurrencyNetwork.main), Stellar(CryptoCurrencyNetwork.main), - Xelis(CryptoCurrencyNetwork.main), Tezos(CryptoCurrencyNetwork.main), Wownero(CryptoCurrencyNetwork.main), Bitcoin(CryptoCurrencyNetwork.test), @@ -84,7 +83,6 @@ final List _supportedCoins = List.unmodifiable([ Litecoin(CryptoCurrencyNetwork.test), Peercoin(CryptoCurrencyNetwork.test), Stellar(CryptoCurrencyNetwork.test), - Xelis(CryptoCurrencyNetwork.test), ]); final ({String from, String to}) _swapDefaults = (from: "BTC", to: "XMR"); diff --git a/scripts/app_config/templates/pubspec.template b/scripts/app_config/templates/pubspec.template index 8ebd267fb..c52440856 100644 --- a/scripts/app_config/templates/pubspec.template +++ b/scripts/app_config/templates/pubspec.template @@ -30,15 +30,6 @@ dependencies: frostdart: path: ./crypto_plugins/frostdart - xelis_flutter: - git: - url: https://github.com/Tritonn204/xelis_flutter_ffi.git - ref: v0.1.0 - - xelis_dart_sdk: ^0.24.0 - - freezed_annotation: ^2.4.1 - flutter_libsparkmobile: git: url: https://github.com/cypherstack/flutter_libsparkmobile.git @@ -233,7 +224,6 @@ dev_dependencies: sdk: flutter integration_test: sdk: flutter - freezed: ^2.4.2 build_runner: ^2.1.7 flutter_launcher_icons: ^0.13.1 hive_generator: ^2.0.0 diff --git a/scripts/ios/build_all.sh b/scripts/ios/build_all.sh index bef3e9095..bcb03e991 100755 --- a/scripts/ios/build_all.sh +++ b/scripts/ios/build_all.sh @@ -10,6 +10,10 @@ set_rust_to_1671 rustup target add aarch64-apple-ios rustup target add x86_64-apple-ios +# ensure ios rust triples are there +rustup target add aarch64-apple-ios +rustup target add x86_64-apple-ios + (cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh ) (cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh ) set_rust_to_1720 diff --git a/scripts/rust_version.sh b/scripts/rust_version.sh index ac553f969..8cda1229b 100755 --- a/scripts/rust_version.sh +++ b/scripts/rust_version.sh @@ -16,13 +16,4 @@ set_rust_to_1720() { echo "Rust version 1.72.0 is not installed. Please install it using 'rustup install 1.72.0'." >&2 exit 1 fi -} - -set_rust_to_1840() { - if rustup toolchain list | grep -q "1.84.0"; then - rustup default 1.84.0 - else - echo "Rust version 1.84.0 is not installed. Please install it using 'rustup install 1.84.0'." >&2 - exit 1 - fi } \ No newline at end of file diff --git a/scripts/windows/build_all.sh b/scripts/windows/build_all.sh index 4c9f03472..191a46cc0 100755 --- a/scripts/windows/build_all.sh +++ b/scripts/windows/build_all.sh @@ -10,6 +10,7 @@ mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_campfire.sh b/scripts/windows/build_all_campfire.sh index 4c9f03472..191a46cc0 100755 --- a/scripts/windows/build_all_campfire.sh +++ b/scripts/windows/build_all_campfire.sh @@ -10,6 +10,7 @@ mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh diff --git a/scripts/windows/build_all_duo.sh b/scripts/windows/build_all_duo.sh index db58ca1ff..3e27eff02 100755 --- a/scripts/windows/build_all_duo.sh +++ b/scripts/windows/build_all_duo.sh @@ -12,6 +12,7 @@ mkdir -p build (cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh ) (cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh ) set_rust_to_1720 +(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh ) ./build_secp256k1_wsl.sh From 0d20cb6b3b2af6cc98ec263b4751e911f1996a15 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 13 Mar 2025 16:05:24 -0700 Subject: [PATCH 26/50] remove logging package from test_node_connection --- lib/utilities/test_node_connection.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/utilities/test_node_connection.dart b/lib/utilities/test_node_connection.dart index b75c22b93..679571541 100644 --- a/lib/utilities/test_node_connection.dart +++ b/lib/utilities/test_node_connection.dart @@ -26,7 +26,6 @@ import 'test_monero_node_connection.dart'; import 'test_stellar_node_connection.dart'; import 'tor_plain_net_option_enum.dart'; -import 'package:logging/logging.dart' as std_logging; import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk; Future _xmrHelper( From 0f7e44faddb9fc6548eabd3b94262560c6e73d34 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Fri, 14 Mar 2025 14:38:05 -0700 Subject: [PATCH 27/50] rebase cleanup + xelis bug fixes --- ...w_wallet_recovery_phrase_warning_view.dart | 230 +----------------- lib/utilities/test_node_connection.dart | 3 +- lib/wallets/crypto_currency/coins/xelis.dart | 6 +- lib/wallets/wallet/impl/xelis_wallet.dart | 150 ++++++------ .../wallet/intermediate/lib_xelis_wallet.dart | 50 ++-- pubspec.lock | 104 ++++---- scripts/app_config/configure_stack_wallet.sh | 2 + scripts/app_config/templates/pubspec.template | 5 + 8 files changed, 168 insertions(+), 382 deletions(-) diff --git a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart index 9d6b7fdf0..7d93d038a 100644 --- a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart +++ b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart @@ -40,7 +40,6 @@ import '../../../widgets/desktop/desktop_scaffold.dart'; import '../../../widgets/rounded_container.dart'; import '../../../widgets/rounded_white_container.dart'; import '../../../widgets/stack_dialog.dart'; -import '../../../widgets/xelis_table_progress.dart'; import '../new_wallet_options/new_wallet_options_view.dart'; import '../new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart'; import 'recovery_phrase_explanation_dialog.dart'; @@ -104,233 +103,6 @@ class _NewWalletRecoveryPhraseWarningViewState ); } } - - // () async { - // try { - // unawaited( - // showDialog( - // context: context, - // barrierDismissible: false, - // useSafeArea: true, - // builder: (ctx) { - // return Center( - // child: Column( - // mainAxisSize: MainAxisSize.min, - // children: [ - // const LoadingIndicator( - // width: 50, - // height: 50, - // ), - // if (widget.coin is Xelis) ...[ - // const SizedBox(height: 16), - // const XelisTableProgress(), - // ], - // ], - // ), - // ); - // }, - // ), - // ); - // String? otherDataJsonString; - // if (widget.coin is Tezos) { - // otherDataJsonString = jsonEncode({ - // WalletInfoKeys - // .tezosDerivationPath: - // Tezos.standardDerivationPath - // .value, - // }); - // // }//todo: probably not needed (broken anyways) - // // else if (widget.coin is Epiccash) { - // // final int secondsSinceEpoch = - // // DateTime.now().millisecondsSinceEpoch ~/ 1000; - // // const int epicCashFirstBlock = 1565370278; - // // const double overestimateSecondsPerBlock = 61; - // // int chosenSeconds = secondsSinceEpoch - epicCashFirstBlock; - // // int approximateHeight = chosenSeconds ~/ overestimateSecondsPerBlock; - // // / - // // // debugPrint( - // // // "approximate height: $approximateHeight chosen_seconds: $chosenSeconds"); - // // height = approximateHeight; - // // if (height < 0) { - // // height = 0; - // // } - // // - // // otherDataJsonString = jsonEncode( - // // { - // // WalletInfoKeys.epiccashData: jsonEncode( - // // ExtraEpiccashWalletInfo( - // // receivingIndex: 0, - // // changeIndex: 0, - // // slatesToAddresses: {}, - // // slatesToCommits: {}, - // // lastScannedBlock: epicCashFirstBlock, - // // restoreHeight: height, - // // creationHeight: height, - // // ).toMap(), - // // ), - // // }, - // // ); - // } else if (widget.coin is Firo) { - // otherDataJsonString = jsonEncode( - // { - // WalletInfoKeys - // .lelantusCoinIsarRescanRequired: - // false, - // }, - // ); - // } - - // final info = WalletInfo.createNew( - // coin: widget.coin, - // name: widget.walletName, - // otherDataJsonString: - // otherDataJsonString, - // ); - - // var node = ref - // .read( - // nodeServiceChangeNotifierProvider, - // ) - // .getPrimaryNodeFor( - // currency: coin, - // ); - - // if (node == null) { - // node = coin.defaultNode; - // await ref - // .read( - // nodeServiceChangeNotifierProvider, - // ) - // .setPrimaryNodeFor( - // coin: coin, - // node: node, - // ); - // } - - // final txTracker = - // TransactionNotificationTracker( - // walletId: info.walletId, - // ); - - // int? wordCount; - // String? mnemonicPassphrase; - // String? mnemonic; - // String? privateKey; - - // wordCount = info - // .coin.defaultSeedPhraseLength; - - // // TODO: Refactor these to generate each coin in their respective classes - // // This code should not be in a random view page file - // if (coin is Monero || - // coin is Wownero || - // coin is Xelis) { - // // currently a special case due to the - // // xmr/wow/xelis libraries handling their - // // own mnemonic generation - // } else if (wordCount > 0) { - // if (ref - // .read( - // pNewWalletOptions.state, - // ) - // .state != - // null) { - // if (coin - // .hasMnemonicPassphraseSupport) { - // mnemonicPassphrase = ref - // .read( - // pNewWalletOptions.state, - // ) - // .state! - // .mnemonicPassphrase; - // } else { - // // this may not be epiccash specific? - // if (coin is Epiccash) { - // mnemonicPassphrase = ""; - // } - // } - - // wordCount = ref - // .read( - // pNewWalletOptions.state, - // ) - // .state! - // .mnemonicWordsCount; - // } else { - // mnemonicPassphrase = ""; - // } - - // if (wordCount < 12 || - // 24 < wordCount || - // wordCount % 3 != 0) { - // throw Exception( - // "Invalid word count", - // ); - // } - - // final strength = - // (wordCount ~/ 3) * 32; - - // mnemonic = bip39.generateMnemonic( - // strength: strength, - // ); - // } - - // final wallet = await Wallet.create( - // walletInfo: info, - // mainDB: ref.read(mainDBProvider), - // secureStorageInterface: - // ref.read(secureStoreProvider), - // nodeService: ref.read( - // nodeServiceChangeNotifierProvider, - // ), - // prefs: ref.read( - // prefsChangeNotifierProvider, - // ), - // mnemonicPassphrase: - // mnemonicPassphrase, - // mnemonic: mnemonic, - // privateKey: privateKey, - // ); - - // await wallet.init(); - - // // pop progress dialog - // if (context.mounted) { - // Navigator.pop(context); - // } - // // set checkbox back to unchecked to annoy users to agree again :P - // ref - // .read( - // checkBoxStateProvider.state, - // ) - // .state = false; - - // if (context.mounted) { - // final nav = Navigator.of(context); - // unawaited( - // nav.pushNamed( - // NewWalletRecoveryPhraseView - // .routeName, - // arguments: Tuple2( - // wallet, - // await (wallet - // as MnemonicInterface) - // .getMnemonicAsWords(), - // ), - // ), - // ); - // } - // } catch (e, s) { - // Logging.instance.log( - // "$e\n$s", - // level: LogLevel.Fatal, - // ); - // // TODO: handle gracefully - // // any network/socket exception here will break new wallet creation - // rethrow; - // } - // } } Future<(Wallet, List)> _initNewFuture() async { @@ -419,7 +191,7 @@ class _NewWalletRecoveryPhraseWarningViewState // TODO: Refactor these to generate each coin in their respective classes // This code should not be in a random view page file - if (coin is Monero || coin is Wownero) { + if (coin is Monero || coin is Wownero || coin is Xelis) { // currently a special case due to the // xmr/wow libraries handling their // own mnemonic generation diff --git a/lib/utilities/test_node_connection.dart b/lib/utilities/test_node_connection.dart index 679571541..a211dd97d 100644 --- a/lib/utilities/test_node_connection.dart +++ b/lib/utilities/test_node_connection.dart @@ -311,9 +311,8 @@ Future testNodeConnection({ final xelis_sdk.GetInfoResult networkInfo = await daemon.getInfo(); testPassed = networkInfo.height != null; - Logging.instance.log( + Logging.instance.i( "Xelis testNodeConnection result: \"${networkInfo.toString()}\"", - level: LogLevel.Info, ); } catch (e, s) { testPassed = false; diff --git a/lib/wallets/crypto_currency/coins/xelis.dart b/lib/wallets/crypto_currency/coins/xelis.dart index 1f57b2afb..b05fce216 100644 --- a/lib/wallets/crypto_currency/coins/xelis.dart +++ b/lib/wallets/crypto_currency/coins/xelis.dart @@ -59,7 +59,7 @@ class Xelis extends ElectrumCurrency { coinName: identifier, isFailover: true, isDown: false, - torEnabled: true, + torEnabled: false, clearnetEnabled: true, ); @@ -74,7 +74,7 @@ class Xelis extends ElectrumCurrency { coinName: identifier, isFailover: true, isDown: false, - torEnabled: true, + torEnabled: false, clearnetEnabled: true, ); @@ -87,7 +87,7 @@ class Xelis extends ElectrumCurrency { int get minConfirms => 1; @override - bool get torSupport => true; + bool get torSupport => false; @override bool validateAddress(String address) { diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 81cbfafe8..42d260255 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -139,10 +139,10 @@ class XelisWallet extends LibXelisWallet { try { await open(); } catch (e, s) { - Logging.instance.log( - "Exception rethrown from recoverFromMnemonic(): $e\n$s", - level: LogLevel.Error, - ); + // Logging.instance.log( + // "Exception rethrown from recoverFromMnemonic(): $e\n$s", + // level: LogLevel.Error, + // ); rethrow; } } @@ -193,10 +193,10 @@ class XelisWallet extends LibXelisWallet { ); } } catch (e, s) { - Logging.instance.log( - "Error in updateBalance(): $e\n$s", - level: LogLevel.Warning, - ); + // Logging.instance.log( + // "Error in updateBalance(): $e\n$s", + // level: LogLevel.Warning, + // ); } }); } @@ -204,6 +204,8 @@ class XelisWallet extends LibXelisWallet { Future _fetchChainHeight() async { final infoString = await libXelisWallet!.getDaemonInfo(); final Map nodeInfo = json.decode(infoString); + + pruningHeight = int.parse(nodeInfo['pruned_topoheight'].toString()); return int.parse(nodeInfo['topoheight'].toString()); } @@ -217,10 +219,10 @@ class XelisWallet extends LibXelisWallet { isar: mainDB.isar, ); } catch (e, s) { - Logging.instance.log( - "Error in updateChainHeight(): $e\n$s", - level: LogLevel.Warning, - ); + // Logging.instance.log( + // "Error in updateChainHeight(): $e\n$s", + // level: LogLevel.Warning, + // ); } } @@ -228,15 +230,16 @@ class XelisWallet extends LibXelisWallet { Future updateNode() async { try { final node = getCurrentNode(); - await libXelisWallet?.offlineMode(); - await libXelisWallet!.onlineMode( - daemonAddress: node.host - ); + final bool online = await libXelisWallet!.isOnline(); + if (online == true) { + await libXelisWallet!.offlineMode(); + } + await super.connect(); } catch (e, s) { - Logging.instance.log( - "Error updating node: $e\n$s", - level: LogLevel.Error, - ); + // Logging.instance.log( + // "Error updating node: $e\n$s", + // level: LogLevel.Error, + // ); rethrow; } } @@ -276,7 +279,7 @@ class XelisWallet extends LibXelisWallet { firstBlock -= 10; } } else { - await libXelisWallet!.rescan(topoheight: BigInt.from(topoheight!)); + await libXelisWallet!.rescan(topoheight: BigInt.from(pruningHeight)); } final txListJson = rawTransactions ?? await libXelisWallet!.allHistory(); @@ -457,18 +460,18 @@ class XelisWallet extends LibXelisWallet { }), ); - Logging.instance.log( - "Entry done ${entryType.toString()}", - level: LogLevel.Debug, - ); + // Logging.instance.log( + // "Entry done ${entryType.toString()}", + // level: LogLevel.Debug, + // ); txns.add(txn); } catch (e, s) { - Logging.instance.log( - "Error handling tx $jsonString: $e\n$s", - level: LogLevel.Warning, - ); + // Logging.instance.log( + // "Error handling tx $jsonString: $e\n$s", + // level: LogLevel.Warning, + // ); } } await updateBalance(); @@ -574,10 +577,10 @@ class XelisWallet extends LibXelisWallet { }), ); } catch (e, s) { - Logging.instance.log( - "Exception rethrown from prepareSend(): $e\n$s", - level: LogLevel.Error, - ); + // Logging.instance.log( + // "Exception rethrown from prepareSend(): $e\n$s", + // level: LogLevel.Error, + // ); rethrow; } } @@ -657,10 +660,10 @@ class XelisWallet extends LibXelisWallet { ); } } catch (e, s) { - Logging.instance.log( - "Exception rethrown from estimateFeeFor(): $e\n$s", - level: LogLevel.Error, - ); + // Logging.instance.log( + // "Exception rethrown from estimateFeeFor(): $e\n$s", + // level: LogLevel.Error, + // ); rethrow; } } @@ -707,10 +710,10 @@ class XelisWallet extends LibXelisWallet { txid: txHash, )); } catch (e, s) { - Logging.instance.log( - "Exception rethrown from confirmSend(): $e\n$s", - level: LogLevel.Error, - ); + // Logging.instance.log( + // "Exception rethrown from confirmSend(): $e\n$s", + // level: LogLevel.Error, + // ); rethrow; } } @@ -737,10 +740,10 @@ class XelisWallet extends LibXelisWallet { await handleHistorySynced(topoheight); } } catch (e, s) { - Logging.instance.log( - "Error handling wallet event: $e\n$s", - level: LogLevel.Error, - ); + // Logging.instance.log( + // "Error handling wallet event: $e\n$s", + // level: LogLevel.Error, + // ); } } @@ -763,15 +766,15 @@ class XelisWallet extends LibXelisWallet { await updateBalance(); - Logging.instance.log( - "New transaction processed: ${newTxIds.first}", - level: LogLevel.Info, - ); + // Logging.instance.log( + // "New transaction processed: ${newTxIds.first}", + // level: LogLevel.Info, + // ); } catch (e, s) { - Logging.instance.log( - "Error handling new transaction: $e\n$s", - level: LogLevel.Warning, - ); + // Logging.instance.log( + // "Error handling new transaction: $e\n$s", + // level: LogLevel.Warning, + // ); } } @@ -785,10 +788,10 @@ class XelisWallet extends LibXelisWallet { // TODO: Update asset balances if needed } catch (e, s) { - Logging.instance.log( - "Error handling balance change: $e\n$s", - level: LogLevel.Warning, - ); + // Logging.instance.log( + // "Error handling balance change: $e\n$s", + // level: LogLevel.Warning, + // ); } } @@ -842,24 +845,35 @@ class XelisWallet extends LibXelisWallet { Future handleNewAsset(xelis_sdk.AssetData asset) async { // TODO: Store asset information if needed // TODO: Update UI/state for new asset - Logging.instance.log( - "New asset detected: ${asset}", - level: LogLevel.Info, - ); + // Logging.instance.log( + // "New asset detected: ${asset}", + // level: LogLevel.Info, + // ); } @override Future refresh({int? topoheight}) async { await refreshMutex.protect(() async { try { - await updateChainHeight(topoheight: topoheight); - await updateBalance(); - await updateTransactions(); + final bool online = await libXelisWallet!.isOnline(); + if (online == true) { + await updateChainHeight(topoheight: topoheight); + await updateBalance(); + await updateTransactions(); + } else { + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.unableToSync, + walletId, + info.coin, + ), + ); + } } catch (e, s) { - Logging.instance.log( - "Error in refresh(): $e\n$s", - level: LogLevel.Warning, - ); + // Logging.instance.log( + // "Error in refresh(): $e\n$s", + // level: LogLevel.Warning, + // ); } }); } diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 6985754d9..fea6eef53 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -183,6 +183,7 @@ abstract class LibXelisWallet extends ExternalWallet static Completer? _tableGenerationCompleter; x_wallet.XelisWallet? libXelisWallet; + int pruningHeight = 0; x_wallet.XelisWallet? get wallet => libXelisWallet; set wallet(x_wallet.XelisWallet? newWallet) { @@ -273,10 +274,10 @@ abstract class LibXelisWallet extends ExternalWallet yield HistorySynced(json['data']['topoheight'] as int); } } catch (e, s) { - Logging.instance.log( - "Error processing wallet event: $e\n$s", - level: LogLevel.Error, - ); + // Logging.instance.log( + // "Error processing wallet event: $e\n$s", + // level: LogLevel.Error, + // ); continue; } } @@ -300,19 +301,19 @@ abstract class LibXelisWallet extends ExternalWallet convertRawEvents().listen(handleEvent); final node = getCurrentNode(); - Logging.instance.log( - "Connecting to node: ${node.host}:${node.port}", - level: LogLevel.Info, - ); + // Logging.instance.log( + // "Connecting to node: ${node.host}:${node.port}", + // level: LogLevel.Info, + // ); await libXelisWallet!.onlineMode( daemonAddress: "${node.host}:${node.port}" ); await super.refresh(); } catch (e, s) { - Logging.instance.log( - "Error connecting to node: $e\n$s", - level: LogLevel.Error, - ); + // Logging.instance.log( + // "Error connecting to node: $e\n$s", + // level: LogLevel.Error, + // ); rethrow; } } @@ -427,10 +428,10 @@ abstract class LibXelisWallet extends ExternalWallet } }); } catch (e, s) { - Logging.instance.log( - "Failed to open/create wallet: $e\n$s", - level: LogLevel.Error, - ); + // Logging.instance.log( + // "Failed to open/create wallet: $e\n$s", + // level: LogLevel.Error, + // ); rethrow; } }); @@ -465,10 +466,10 @@ abstract class LibXelisWallet extends ExternalWallet try { await connect(); } catch (e) { - Logging.instance.log( - "Failed to start sync: $e", - level: LogLevel.Error, - ); + // Logging.instance.log( + // "Failed to start sync: $e", + // level: LogLevel.Error, + // ); rethrow; } } @@ -486,6 +487,7 @@ abstract class LibXelisWallet extends ExternalWallet _eventSubscription = null; await libXelisWallet?.offlineMode(); + await libXelisWallet?.close(); libXelisWallet?.dispose(); libXelisWallet = null; @@ -554,10 +556,10 @@ extension XelisTableManagement on LibXelisWallet { debugPrint("Table upgrade done"); LibXelisWallet._tableGenerationCompleter!.complete(); } catch (e, s) { - Logging.instance.log( - "Failed to update tables: $e\n$s", - level: LogLevel.Error, - ); + // Logging.instance.log( + // "Failed to update tables: $e\n$s", + // level: LogLevel.Error, + // ); await setTableState(state.copyWith(isGenerating: false)); LibXelisWallet._tableGenerationCompleter!.completeError(e); diff --git a/pubspec.lock b/pubspec.lock index 55d7b344c..cec915896 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -58,10 +58,10 @@ packages: dependency: "direct main" description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.12.0" barcode_scan2: dependency: "direct main" description: @@ -159,10 +159,10 @@ packages: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" borsh_annotation: dependency: transitive description: @@ -305,10 +305,10 @@ packages: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" charcode: dependency: transitive description: @@ -337,10 +337,10 @@ packages: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" code_builder: dependency: transitive description: @@ -371,10 +371,10 @@ packages: dependency: transitive description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.19.1" compat: dependency: "direct main" description: @@ -742,10 +742,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" ffi: dependency: "direct main" description: @@ -758,10 +758,10 @@ packages: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" file_picker: dependency: "direct main" description: @@ -967,16 +967,8 @@ packages: description: flutter source: sdk version: "0.0.0" - freezed: - dependency: "direct dev" - description: - name: freezed - sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e" - url: "https://pub.dev" - source: hosted - version: "2.5.7" freezed_annotation: - dependency: "direct main" + dependency: transitive description: name: freezed_annotation sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 @@ -1229,18 +1221,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: @@ -1341,10 +1333,10 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -1365,10 +1357,10 @@ packages: dependency: "direct main" description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" mime: dependency: transitive description: @@ -1486,10 +1478,10 @@ packages: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" path_parsing: dependency: transitive description: @@ -1614,10 +1606,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -1654,10 +1646,10 @@ packages: dependency: transitive description: name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" + sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "5.0.3" protobuf: dependency: transitive description: @@ -1861,10 +1853,10 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" sqlite3: dependency: "direct main" description: @@ -1885,10 +1877,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.12.1" stack_wallet_backup: dependency: "direct main" description: @@ -1918,10 +1910,10 @@ packages: dependency: "direct main" description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" stream_transform: dependency: transitive description: @@ -1934,10 +1926,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.1" string_validator: dependency: "direct main" description: @@ -1958,34 +1950,34 @@ packages: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test: dependency: transitive description: name: test - sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" + sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e" url: "https://pub.dev" source: hosted - version: "1.25.8" + version: "1.25.15" test_api: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.4" test_core: dependency: transitive description: name: test_core - sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" + sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa" url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.8" tezart: dependency: "direct main" description: @@ -2192,10 +2184,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "14.3.1" wakelock_platform_interface: dependency: transitive description: @@ -2335,7 +2327,7 @@ packages: source: hosted version: "1.1.0" xelis_dart_sdk: - dependency: "direct main" + dependency: transitive description: name: xelis_dart_sdk sha256: "2a7f8ab4c30fad2fd824ba6ea4e83ac20c726b47c7aa4f1e713ef3971a3ec1f7" diff --git a/scripts/app_config/configure_stack_wallet.sh b/scripts/app_config/configure_stack_wallet.sh index 0fd8e5e8a..e46420fa0 100755 --- a/scripts/app_config/configure_stack_wallet.sh +++ b/scripts/app_config/configure_stack_wallet.sh @@ -73,6 +73,7 @@ final List _supportedCoins = List.unmodifiable([ Stellar(CryptoCurrencyNetwork.main), Tezos(CryptoCurrencyNetwork.main), Wownero(CryptoCurrencyNetwork.main), + Xelis(CryptoCurrencyNetwork.main), Bitcoin(CryptoCurrencyNetwork.test), Bitcoin(CryptoCurrencyNetwork.test4), Bitcoincash(CryptoCurrencyNetwork.test), @@ -83,6 +84,7 @@ final List _supportedCoins = List.unmodifiable([ Litecoin(CryptoCurrencyNetwork.test), Peercoin(CryptoCurrencyNetwork.test), Stellar(CryptoCurrencyNetwork.test), + Xelis(CryptoCurrencyNetwork.test), ]); final ({String from, String to}) _swapDefaults = (from: "BTC", to: "XMR"); diff --git a/scripts/app_config/templates/pubspec.template b/scripts/app_config/templates/pubspec.template index c52440856..b17e18a6d 100644 --- a/scripts/app_config/templates/pubspec.template +++ b/scripts/app_config/templates/pubspec.template @@ -30,6 +30,11 @@ dependencies: frostdart: path: ./crypto_plugins/frostdart + xelis_flutter: + git: + url: https://github.com/Tritonn204/xelis_flutter_ffi.git + ref: v0.1.0 + flutter_libsparkmobile: git: url: https://github.com/cypherstack/flutter_libsparkmobile.git From 4feb14c7da5b1fc9e08771728e66989dbf98b1e7 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Fri, 14 Mar 2025 20:51:00 -0700 Subject: [PATCH 28/50] updated rust logging method, added mnemonic word validation for Xelis --- lib/main.dart | 4 ++-- .../restore_wallet_view/restore_wallet_view.dart | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 45a1fff18..2304688fa 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -82,9 +82,9 @@ final openedFromSWBFileStringStateProvider = void startListeningToRustLogs() { xelis_api.createLogStream().listen((logEntry) { - print("[Rust Log] [${logEntry.level}] ${logEntry.tag}: ${logEntry.msg}"); + Logging.instance.i("[Rust Log] [${logEntry.level}] ${logEntry.tag}: ${logEntry.msg}"); }, onError: (e) { - print("Error receiving Rust logs: $e"); + Logging.instance.e("Error receiving Rust logs: $e"); }); } diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart index b70c2afcf..0c3ca9a6a 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart @@ -25,6 +25,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; +import 'package:xelis_flutter/src/api/seed_search_engine.dart' as x_seed; + import '../../../notifications/show_flush_bar.dart'; import '../../../pages_desktop_specific/desktop_home_view.dart'; import '../../../pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart'; @@ -104,6 +106,7 @@ class _RestoreWalletViewState extends ConsumerState { late final int _seedWordCount; late final bool isDesktop; + x_seed.SearchEngine? _xelisSeedSearch; final HashSet _wordListHashSet = HashSet.from(bip39wordlist.WORDLIST); final ScrollController controller = ScrollController(); @@ -168,6 +171,10 @@ class _RestoreWalletViewState extends ConsumerState { // _focusNodes.add(FocusNode()); } + if (widget.coin is Xelis) { + _xelisSeedSearch = x_seed.SearchEngine.init(languageIndex: BigInt.from(0)); + } + super.initState(); } @@ -202,7 +209,7 @@ class _RestoreWalletViewState extends ConsumerState { } // TODO: use Xelis word list if (widget.coin is Xelis) { - return true; + return _xelisSeedSearch!.search(query: word).length > 0; } return _wordListHashSet.contains(word); } From 6e725a5bb5bbdce79779f5af51200ea3badeafe0 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Fri, 14 Mar 2025 20:51:14 -0700 Subject: [PATCH 29/50] removed comment --- .../restore_wallet_view/restore_wallet_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart index 0c3ca9a6a..82aef0d60 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart @@ -207,7 +207,6 @@ class _RestoreWalletViewState extends ConsumerState { ); return wowneroWordList.contains(word); } - // TODO: use Xelis word list if (widget.coin is Xelis) { return _xelisSeedSearch!.search(query: word).length > 0; } From b190907caef58059d65bd2f13aa88af6779e1d3e Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 17 Mar 2025 08:25:41 -0600 Subject: [PATCH 30/50] pubspec lock update --- pubspec.lock | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index e7a85729a..95c5d28ab 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -831,9 +831,11 @@ packages: flutter_libsparkmobile: dependency: "direct main" description: - path: "../flutter_libsparkmobile" - relative: true - source: path + path: "." + ref: "28d0f6c8db56a7d14d6495e810b8705a5c438929" + resolved-ref: "28d0f6c8db56a7d14d6495e810b8705a5c438929" + url: "https://github.com/cypherstack/flutter_libsparkmobile.git" + source: git version: "0.0.2" flutter_lints: dependency: "direct dev" From fe2514e97e9c1bab18448433f2fcc49e76d16b8a Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 17 Mar 2025 08:42:32 -0600 Subject: [PATCH 31/50] lint and code formatting --- lib/wallets/wallet/impl/xelis_wallet.dart | 505 +++++++++--------- .../wallet/intermediate/lib_xelis_wallet.dart | 185 +++---- 2 files changed, 339 insertions(+), 351 deletions(-) diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 42d260255..0dbeb56df 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -1,53 +1,29 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; +import 'dart:math'; -import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; import 'package:isar/isar.dart'; - -import 'package:xelis_flutter/src/api/network.dart' as x_network; -import 'package:xelis_flutter/src/api/wallet.dart' as x_wallet; +import 'package:mutex/mutex.dart'; +import 'package:stack_wallet_backup/generate_password.dart'; import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk; +import 'package:xelis_flutter/src/api/wallet.dart' as x_wallet; -import 'package:path_provider/path_provider.dart'; -import 'package:path/path.dart' as path; - -import '../intermediate/lib_xelis_wallet.dart'; - -import '../../../utilities/stack_file_system.dart'; +import '../../../models/balance.dart'; import '../../../models/isar/models/blockchain_data/address.dart'; import '../../../models/isar/models/blockchain_data/transaction.dart'; import '../../../models/isar/models/blockchain_data/v2/input_v2.dart'; import '../../../models/isar/models/blockchain_data/v2/output_v2.dart'; import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart'; - -import '../../../services/event_bus/events/global/blocks_remaining_event.dart'; -import '../../../services/event_bus/events/global/refresh_percent_changed_event.dart'; -import '../../../services/event_bus/events/global/tor_connection_status_changed_event.dart'; -import '../../../services/event_bus/events/global/tor_status_changed_event.dart'; -import '../../../services/event_bus/events/global/updated_in_background_event.dart'; +import '../../../models/paymint/fee_object_model.dart'; import '../../../services/event_bus/events/global/wallet_sync_status_changed_event.dart'; import '../../../services/event_bus/global_event_bus.dart'; - -import '../../../models/node_model.dart'; -import '../../../models/paymint/fee_object_model.dart'; -import '../../../models/balance.dart'; import '../../../utilities/amount/amount.dart'; import '../../../utilities/logger.dart'; import '../../crypto_currency/crypto_currency.dart'; import '../../models/tx_data.dart'; -import '../wallet.dart'; - -import '../../../providers/providers.dart'; - -import 'package:isar/isar.dart'; -import 'package:mutex/mutex.dart'; -import 'package:stack_wallet_backup/generate_password.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; import '../intermediate/lib_xelis_wallet.dart'; - -import 'dart:math'; +import '../wallet.dart'; class XelisWallet extends LibXelisWallet { XelisWallet(CryptoCurrencyNetwork network) : super(Xelis(network)); @@ -59,14 +35,15 @@ class XelisWallet extends LibXelisWallet { @override Future init({bool? isRestore}) async { debugPrint("Xelis: init"); - + if (isRestore == true) { await _restoreWallet(); return await super.init(); } - String? walletExists = - await secureStorageInterface.read(key: "${walletId}_wallet"); + final String? walletExists = await secureStorageInterface.read( + key: "${walletId}_wallet", + ); if (walletExists == null) { await _createNewWallet(); @@ -79,7 +56,7 @@ class XelisWallet extends LibXelisWallet { Future _createNewWallet() async { final String password = generatePassword(); - + debugPrint("Xelis: storing password"); await secureStorageInterface.write( key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), @@ -128,9 +105,9 @@ class XelisWallet extends LibXelisWallet { await updateTransactions(isRescan: true, topoheight: 0); }); return; - } + } - // Borrowed from libmonero for now, need to refactor for Xelis view keys + // Borrowed from libmonero for now, need to refactor for Xelis view keys // if (isViewOnly) { // await recoverViewOnly(); // return; @@ -138,7 +115,7 @@ class XelisWallet extends LibXelisWallet { try { await open(); - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Exception rethrown from recoverFromMnemonic(): $e\n$s", // level: LogLevel.Error, @@ -147,17 +124,16 @@ class XelisWallet extends LibXelisWallet { } } - @override Future pingCheck() async { checkInitialized(); try { - final nodeInfo = await libXelisWallet!.getDaemonInfo(); + await libXelisWallet!.getDaemonInfo(); await handleOnline(); return true; } catch (_) { - return false; await handleOffline(); + return false; } } @@ -168,9 +144,11 @@ class XelisWallet extends LibXelisWallet { await _balanceUpdateMutex.protect(() async { try { if (await libXelisWallet!.hasXelisBalance()) { - final BigInt xelBalance = newBalance != null - ? BigInt.from(newBalance) - : await libXelisWallet!.getXelisBalanceRaw(); // in the future, use getAssetBalances and handle each + final BigInt xelBalance = + newBalance != null + ? BigInt.from(newBalance) + : await libXelisWallet! + .getXelisBalanceRaw(); // in the future, use getAssetBalances and handle each final balance = Balance( total: Amount( rawValue: xelBalance, @@ -187,12 +165,9 @@ class XelisWallet extends LibXelisWallet { fractionDigits: cryptoCurrency.fractionDigits, ), ); - await info.updateBalance( - newBalance: balance, - isar: mainDB.isar, - ); + await info.updateBalance(newBalance: balance, isar: mainDB.isar); } - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Error in updateBalance(): $e\n$s", // level: LogLevel.Warning, @@ -203,7 +178,8 @@ class XelisWallet extends LibXelisWallet { Future _fetchChainHeight() async { final infoString = await libXelisWallet!.getDaemonInfo(); - final Map nodeInfo = json.decode(infoString); + final Map nodeInfo = + (json.decode(infoString) as Map).cast(); pruningHeight = int.parse(nodeInfo['pruned_topoheight'].toString()); return int.parse(nodeInfo['topoheight'].toString()); @@ -213,12 +189,12 @@ class XelisWallet extends LibXelisWallet { Future updateChainHeight({int? topoheight}) async { try { final height = topoheight ?? await _fetchChainHeight(); - + await info.updateCachedChainHeight( newHeight: height.toInt(), isar: mainDB.isar, ); - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Error in updateChainHeight(): $e\n$s", // level: LogLevel.Warning, @@ -235,7 +211,7 @@ class XelisWallet extends LibXelisWallet { await libXelisWallet!.offlineMode(); } await super.connect(); - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Error updating node: $e\n$s", // level: LogLevel.Error, @@ -252,22 +228,24 @@ class XelisWallet extends LibXelisWallet { }) async { checkInitialized(); - final newReceivingAddress = await getCurrentReceivingAddress() ?? - Address( - walletId: walletId, - derivationIndex: 0, - derivationPath: null, - value: libXelisWallet!.getAddressStr(), - publicKey: [], - type: AddressType.xelis, - subType: AddressSubType.receiving, - ); + final newReceivingAddress = + await getCurrentReceivingAddress() ?? + Address( + walletId: walletId, + derivationIndex: 0, + derivationPath: null, + value: libXelisWallet!.getAddressStr(), + publicKey: [], + type: AddressType.xelis, + subType: AddressSubType.receiving, + ); final thisAddress = newReceivingAddress.value; - + int firstBlock = 0; if (!isRescan) { - firstBlock = await mainDB.isar.transactionV2s + firstBlock = + await mainDB.isar.transactionV2s .where() .walletIdEqualTo(walletId) .heightProperty() @@ -288,16 +266,19 @@ class XelisWallet extends LibXelisWallet { for (final jsonString in txListJson) { try { - final transactionEntry = xelis_sdk.TransactionEntry.fromJson(json.decode(jsonString)); + final transactionEntry = xelis_sdk.TransactionEntry.fromJson( + (json.decode(jsonString) as Map).cast(), + ); // Check for duplicates - final storedTx = await mainDB.isar.transactionV2s - .where() - .txidWalletIdEqualTo(transactionEntry.hash, walletId) - .findFirst(); - - if (storedTx != null && - storedTx.height != null && + final storedTx = + await mainDB.isar.transactionV2s + .where() + .txidWalletIdEqualTo(transactionEntry.hash, walletId) + .findFirst(); + + if (storedTx != null && + storedTx.height != null && storedTx.height! > 0) { continue; // Skip already processed transactions } @@ -305,140 +286,150 @@ class XelisWallet extends LibXelisWallet { final List outputs = []; final List inputs = []; TransactionType? txType; - TransactionSubType txSubType = TransactionSubType.none; + const TransactionSubType txSubType = TransactionSubType.none; int? nonce; Amount fee = Amount( - rawValue: BigInt.zero, - fractionDigits: cryptoCurrency.fractionDigits + rawValue: BigInt.zero, + fractionDigits: cryptoCurrency.fractionDigits, ); - Map otherData = {}; + final Map otherData = {}; final entryType = transactionEntry.txEntryType; if (entryType is xelis_sdk.CoinbaseEntry) { - final coinbase = entryType; - txType = TransactionType.incoming; + final coinbase = entryType; + txType = TransactionType.incoming; + + final int decimals = await libXelisWallet!.getAssetDecimals( + asset: xelis_sdk.xelisAsset, + ); + + fee = Amount(rawValue: BigInt.zero, fractionDigits: decimals); + + outputs.add( + OutputV2.isarCantDoRequiredInDefaultConstructor( + scriptPubKeyHex: "", + valueStringSats: coinbase.reward.toString(), + addresses: [thisAddress], + walletOwns: true, + ), + ); + } else if (entryType is xelis_sdk.BurnEntry) { + final burn = entryType; + txType = TransactionType.outgoing; + + final int decimals = await libXelisWallet!.getAssetDecimals( + asset: burn.asset, + ); + + fee = Amount( + rawValue: BigInt.from(burn.fee), + fractionDigits: decimals, + ); + inputs.add( + InputV2.isarCantDoRequiredInDefaultConstructor( + scriptSigAsm: null, + scriptSigHex: null, + sequence: null, + outpoint: null, + valueStringSats: burn.amount.toString(), + addresses: [thisAddress], + witness: null, + innerRedeemScriptAsm: null, + coinbase: null, + walletOwns: true, + ), + ); + + outputs.add( + OutputV2.isarCantDoRequiredInDefaultConstructor( + scriptPubKeyHex: "", + valueStringSats: burn.amount.toString(), + addresses: ['burn'], + walletOwns: false, + ), + ); + + otherData['burnAsset'] = burn.asset; + } else if (entryType is xelis_sdk.IncomingEntry) { + final incoming = entryType; + txType = + incoming.from == thisAddress + ? TransactionType.sentToSelf + : TransactionType.incoming; + + for (final transfer in incoming.transfers) { final int decimals = await libXelisWallet!.getAssetDecimals( - asset: xelis_sdk.xelisAsset + asset: transfer.asset, ); - fee = Amount( - rawValue: BigInt.zero, - fractionDigits: decimals - ); + fee = Amount(rawValue: BigInt.zero, fractionDigits: decimals); - outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( + outputs.add( + OutputV2.isarCantDoRequiredInDefaultConstructor( scriptPubKeyHex: "", - valueStringSats: coinbase.reward.toString(), + valueStringSats: transfer.amount.toString(), addresses: [thisAddress], walletOwns: true, - )); - } else if (entryType is xelis_sdk.BurnEntry) { - final burn = entryType; - txType = TransactionType.outgoing; + ), + ); + otherData['asset_${transfer.asset}'] = transfer.amount.toString(); + if (transfer.extraData != null) { + otherData['extraData_${transfer.asset}'] = + transfer.extraData!.toJson(); + } + } + } else if (entryType is xelis_sdk.OutgoingEntry) { + final outgoing = entryType; + txType = TransactionType.outgoing; + nonce = outgoing.nonce; + + for (final transfer in outgoing.transfers) { final int decimals = await libXelisWallet!.getAssetDecimals( - asset: burn.asset + asset: transfer.asset, ); fee = Amount( - rawValue: BigInt.from(burn.fee), - fractionDigits: decimals + rawValue: BigInt.from(outgoing.fee), + fractionDigits: decimals, ); - inputs.add(InputV2.isarCantDoRequiredInDefaultConstructor( - scriptSigAsm: null, + inputs.add( + InputV2.isarCantDoRequiredInDefaultConstructor( scriptSigHex: null, + scriptSigAsm: null, sequence: null, outpoint: null, - valueStringSats: burn.amount.toString(), addresses: [thisAddress], + valueStringSats: (transfer.amount + outgoing.fee).toString(), witness: null, innerRedeemScriptAsm: null, coinbase: null, walletOwns: true, - )); + ), + ); - outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( + outputs.add( + OutputV2.isarCantDoRequiredInDefaultConstructor( scriptPubKeyHex: "", - valueStringSats: burn.amount.toString(), - addresses: ['burn'], + valueStringSats: transfer.amount.toString(), + addresses: [transfer.destination], walletOwns: false, - )); + ), + ); - otherData['burnAsset'] = burn.asset; - } else if (entryType is xelis_sdk.IncomingEntry) { - final incoming = entryType; - txType = incoming.from == thisAddress - ? TransactionType.sentToSelf - : TransactionType.incoming; - - for (final transfer in incoming.transfers) { - final int decimals = await libXelisWallet!.getAssetDecimals( - asset: transfer.asset - ); - - fee = Amount( - rawValue: BigInt.zero, - fractionDigits: decimals - ); - - outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( - scriptPubKeyHex: "", - valueStringSats: transfer.amount.toString(), - addresses: [thisAddress], - walletOwns: true, - )); - - otherData['asset_${transfer.asset}'] = transfer.amount.toString(); - if (transfer.extraData != null) { - otherData['extraData_${transfer.asset}'] = transfer.extraData!.toJson(); - } - } - } else if (entryType is xelis_sdk.OutgoingEntry) { - final outgoing = entryType; - txType = TransactionType.outgoing; - nonce = outgoing.nonce; - - for (final transfer in outgoing.transfers) { - final int decimals = await libXelisWallet!.getAssetDecimals( - asset: transfer.asset - ); - - fee = Amount( - rawValue: BigInt.from(outgoing.fee), - fractionDigits: decimals - ); - - inputs.add(InputV2.isarCantDoRequiredInDefaultConstructor( - scriptSigHex: null, - scriptSigAsm: null, - sequence: null, - outpoint: null, - addresses: [thisAddress], - valueStringSats: (transfer.amount + outgoing.fee).toString(), - witness: null, - innerRedeemScriptAsm: null, - coinbase: null, - walletOwns: true, - )); - - outputs.add(OutputV2.isarCantDoRequiredInDefaultConstructor( - scriptPubKeyHex: "", - valueStringSats: transfer.amount.toString(), - addresses: [transfer.destination], - walletOwns: false, - )); - - otherData['asset_${transfer.asset}_amount'] = transfer.amount.toString(); - otherData['asset_${transfer.asset}_fee'] = fee.toString(); - if (transfer.extraData != null) { - otherData['extraData_${transfer.asset}'] = transfer.extraData!.toJson(); - } + otherData['asset_${transfer.asset}_amount'] = + transfer.amount.toString(); + otherData['asset_${transfer.asset}_fee'] = fee.toString(); + if (transfer.extraData != null) { + otherData['extraData_${transfer.asset}'] = + transfer.extraData!.toJson(); } + } } else { - // Skip unknown entry types + // Skip unknown entry types } final txn = TransactionV2( @@ -446,8 +437,9 @@ class XelisWallet extends LibXelisWallet { blockHash: "", // Not provided in Xelis data hash: transactionEntry.hash, txid: transactionEntry.hash, - timestamp: (transactionEntry.timestamp?.millisecondsSinceEpoch ?? 0) ~/ 1000, - height: transactionEntry?.topoheight, + timestamp: + (transactionEntry.timestamp?.millisecondsSinceEpoch ?? 0) ~/ 1000, + height: transactionEntry.topoheight, inputs: List.unmodifiable(inputs), outputs: List.unmodifiable(outputs), version: -1, // Version not provided @@ -456,7 +448,7 @@ class XelisWallet extends LibXelisWallet { otherData: jsonEncode({ ...otherData, if (nonce != null) 'nonce': nonce, - if (fee != null) 'overrideFee': fee.toJsonString(), + 'overrideFee': fee.toJsonString(), }), ); @@ -465,9 +457,8 @@ class XelisWallet extends LibXelisWallet { // level: LogLevel.Debug, // ); - txns.add(txn); - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Error handling tx $jsonString: $e\n$s", // level: LogLevel.Warning, @@ -518,22 +509,29 @@ class XelisWallet extends LibXelisWallet { checkInitialized(); // Use default address if recipients list is empty - final recipients = txData.recipients?.isNotEmpty == true - ? txData.recipients! - : [( - address: 'xel:xz9574c80c4xegnvurazpmxhw5dlg2n0g9qm60uwgt75uqyx3pcsqzzra9m', - amount: Amount.zeroWith( - fractionDigits: cryptoCurrency.fractionDigits, - ), - isChange: false - )]; + final recipients = + txData.recipients?.isNotEmpty == true + ? txData.recipients! + : [ + ( + address: + 'xel:xz9574c80c4xegnvurazpmxhw5dlg2n0g9qm60uwgt75uqyx3pcsqzzra9m', + amount: Amount.zeroWith( + fractionDigits: cryptoCurrency.fractionDigits, + ), + isChange: false, + ), + ]; final asset = assetId ?? xelis_sdk.xelisAsset; // Calculate total send amount final totalSendAmount = recipients.fold( - Amount(rawValue: BigInt.zero, fractionDigits: cryptoCurrency.fractionDigits), - (sum, recipient) => sum + recipient.amount + Amount( + rawValue: BigInt.zero, + fractionDigits: cryptoCurrency.fractionDigits, + ), + (sum, recipient) => sum + recipient.amount, ); // Check balance using raw method @@ -555,28 +553,26 @@ class XelisWallet extends LibXelisWallet { // Check if we have enough for both transfers and fee if (totalSendAmount + boostedFee > balance) { final requiredAmt = await libXelisWallet!.formatCoin( - atomicAmount: (totalSendAmount + boostedFee).raw, - assetHash: asset + atomicAmount: (totalSendAmount + boostedFee).raw, + assetHash: asset, ); final availableAmt = await libXelisWallet!.formatCoin( - atomicAmount: xelBalance, - assetHash: asset + atomicAmount: xelBalance, + assetHash: asset, ); throw Exception( "Insufficient balance to cover transfers and fees. " - "Required: $requiredAmt, Available: $availableAmt" + "Required: $requiredAmt, Available: $availableAmt", ); } return txData.copyWith( fee: boostedFee, - otherData: jsonEncode({ - 'asset': asset, - }), + otherData: jsonEncode({'asset': asset}), ); - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Exception rethrown from prepareSend(): $e\n$s", // level: LogLevel.Error, @@ -587,39 +583,43 @@ class XelisWallet extends LibXelisWallet { @override Future estimateFeeFor( - Amount amount, - int feeRate, - { - double? feeMultiplier, - List recipients = const [], - String? assetId - } - ) async { + Amount amount, + int feeRate, { + double? feeMultiplier, + List recipients = const [], + String? assetId, + }) async { try { checkInitialized(); final asset = assetId ?? xelis_sdk.xelisAsset; // Default values for a new wallet or when estimation fails - final defaultDecimals = 8; + final defaultDecimals = cryptoCurrency.fractionDigits; final defaultFee = BigInt.from(0); - + // Use default address if recipients list is empty - final effectiveRecipients = recipients.isNotEmpty - ? recipients - : [( - address: 'xel:xz9574c80c4xegnvurazpmxhw5dlg2n0g9qm60uwgt75uqyx3pcsqzzra9m', - amount: amount, - isChange: false - )]; + final effectiveRecipients = + recipients.isNotEmpty + ? recipients + : [ + ( + address: + 'xel:xz9574c80c4xegnvurazpmxhw5dlg2n0g9qm60uwgt75uqyx3pcsqzzra9m', + amount: amount, + isChange: false, + ), + ]; try { final transfers = await Future.wait( effectiveRecipients.map((recipient) async { try { - final amt = double.parse(await libXelisWallet!.formatCoin( - atomicAmount: recipient.amount.raw, - assetHash: asset - )); + final amt = double.parse( + await libXelisWallet!.formatCoin( + atomicAmount: recipient.amount.raw, + assetHash: asset, + ), + ); return x_wallet.Transfer( floatAmount: amt, strAddress: recipient.address, @@ -630,7 +630,8 @@ class XelisWallet extends LibXelisWallet { // Handle formatCoin error - use default conversion debugPrint("formatCoin failed: $e, using fallback conversion"); final rawAmount = recipient.amount.raw; - final floatAmount = rawAmount / BigInt.from(10).pow(defaultDecimals); + final floatAmount = + rawAmount / BigInt.from(10).pow(defaultDecimals); return x_wallet.Transfer( floatAmount: floatAmount.toDouble(), strAddress: recipient.address, @@ -638,28 +639,30 @@ class XelisWallet extends LibXelisWallet { extraData: null, ); } - }) + }), ); - final decimals = await libXelisWallet!.getAssetDecimals( - asset: asset + final decimals = await libXelisWallet!.getAssetDecimals(asset: asset); + final estimatedFee = double.parse( + await libXelisWallet!.estimateFees(transfers: transfers), ); - final estimatedFee = double.parse(await libXelisWallet!.estimateFees(transfers: transfers)); final rawFee = (estimatedFee * pow(10, decimals)).round(); return Amount( rawValue: BigInt.from(rawFee), fractionDigits: cryptoCurrency.fractionDigits, ); } catch (e, s) { - debugPrint("Fee estimation failed: $e\n$s"); - - debugPrint("Using fallback fee: $defaultFee"); + Logging.instance.d( + "Fee estimation failed. Using fallback fee: $defaultFee", + error: e, + stackTrace: s, + ); return Amount( rawValue: defaultFee, fractionDigits: cryptoCurrency.fractionDigits, ); } - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Exception rethrown from estimateFeeFor(): $e\n$s", // level: LogLevel.Error, @@ -681,12 +684,19 @@ class XelisWallet extends LibXelisWallet { final recipient = txData.recipients!.first; final Amount sendAmount = recipient.amount; - final asset = (txData.otherData != null ? jsonDecode(txData.otherData!) : null)?['asset'] ?? xelis_sdk.xelisAsset; - - final amt = double.parse(await libXelisWallet!.formatCoin( - atomicAmount: sendAmount.raw, - assetHash: asset - )); + final asset = + (txData.otherData != null + ? jsonDecode(txData.otherData!) + : null)?['asset'] + as String? ?? + xelis_sdk.xelisAsset; + + final amt = double.parse( + await libXelisWallet!.formatCoin( + atomicAmount: sendAmount.raw, + assetHash: asset, + ), + ); // Create a transfer transaction final txJson = await libXelisWallet!.createTransfersTransaction( @@ -696,8 +706,8 @@ class XelisWallet extends LibXelisWallet { strAddress: recipient.address, assetHash: asset, extraData: null, // Add extra data if needed - ) - ] + ), + ], ); final txMap = jsonDecode(txJson); @@ -706,10 +716,10 @@ class XelisWallet extends LibXelisWallet { // Broadcast the transaction await libXelisWallet!.broadcastTransaction(txHash: txHash); - return await updateSentCachedTxData(txData: txData.copyWith( - txid: txHash, - )); - } catch (e, s) { + return await updateSentCachedTxData( + txData: txData.copyWith(txid: txHash), + ); + } catch (_) { // Logging.instance.log( // "Exception rethrown from confirmSend(): $e\n$s", // level: LogLevel.Error, @@ -739,7 +749,7 @@ class XelisWallet extends LibXelisWallet { case HistorySynced(:final topoheight): await handleHistorySynced(topoheight); } - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Error handling wallet event: $e\n$s", // level: LogLevel.Error, @@ -749,10 +759,7 @@ class XelisWallet extends LibXelisWallet { @override Future handleNewTopoHeight(int height) async { - await info.updateCachedChainHeight( - newHeight: height, - isar: mainDB.isar, - ); + await info.updateCachedChainHeight(newHeight: height, isar: mainDB.isar); } @override @@ -765,12 +772,12 @@ class XelisWallet extends LibXelisWallet { ); await updateBalance(); - + // Logging.instance.log( // "New transaction processed: ${newTxIds.first}", // level: LogLevel.Info, // ); - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Error handling new transaction: $e\n$s", // level: LogLevel.Warning, @@ -785,9 +792,9 @@ class XelisWallet extends LibXelisWallet { if (asset == xelis_sdk.xelisAsset) { await updateBalance(newBalance: event.balance); } - + // TODO: Update asset balances if needed - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Error handling balance change: $e\n$s", // level: LogLevel.Warning, @@ -869,7 +876,7 @@ class XelisWallet extends LibXelisWallet { ), ); } - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Error in refresh(): $e\n$s", // level: LogLevel.Warning, @@ -877,4 +884,4 @@ class XelisWallet extends LibXelisWallet { } }); } -} \ No newline at end of file +} diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index fea6eef53..626b83c94 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -1,46 +1,19 @@ -import 'package:isar/isar.dart'; -import '../../../models/isar/models/blockchain_data/address.dart'; -import '../../crypto_currency/intermediate/electrum_currency.dart'; -import '../wallet.dart'; -import '../wallet_mixin_interfaces/mnemonic_interface.dart'; - -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:json_annotation/json_annotation.dart'; - import 'dart:async'; import 'dart:convert'; -import 'dart:io'; -import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; import 'package:isar/isar.dart'; - +import 'package:mutex/mutex.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk; import 'package:xelis_flutter/src/api/network.dart' as x_network; import 'package:xelis_flutter/src/api/wallet.dart' as x_wallet; -import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk; -import 'package:path_provider/path_provider.dart'; -import 'package:path/path.dart' as path; - -import '../../../utilities/stack_file_system.dart'; -import '../../../models/isar/models/blockchain_data/transaction.dart'; -import '../../../models/isar/models/blockchain_data/v2/input_v2.dart'; -import '../../../models/isar/models/blockchain_data/v2/output_v2.dart'; -import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart'; - -import '../../../models/node_model.dart'; -import '../../../models/paymint/fee_object_model.dart'; -import '../../../models/balance.dart'; -import '../../../utilities/amount/amount.dart'; -import '../../../utilities/logger.dart'; +import '../../../models/isar/models/blockchain_data/address.dart'; import '../../crypto_currency/crypto_currency.dart'; -import '../../models/tx_data.dart'; - -import 'package:isar/isar.dart'; -import 'package:mutex/mutex.dart'; -import 'package:stack_wallet_backup/generate_password.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; - +import '../../crypto_currency/intermediate/electrum_currency.dart'; +import '../wallet.dart'; +import '../wallet_mixin_interfaces/mnemonic_interface.dart'; import 'external_wallet.dart'; enum XelisTableSize { @@ -48,7 +21,7 @@ enum XelisTableSize { full; bool get isLow => this == XelisTableSize.low; - + static XelisTableSize get platformDefault { if (kIsWeb) { return XelisTableSize.low; @@ -83,7 +56,7 @@ class XelisTableState { return XelisTableState( isGenerating: isGenerating ?? this.isGenerating, currentSize: currentSize ?? this.currentSize, - desiredSize: kIsWeb ? XelisTableSize.low : (desiredSize ?? this._desiredSize), + desiredSize: kIsWeb ? XelisTableSize.low : (desiredSize ?? _desiredSize), ); } @@ -170,14 +143,14 @@ final class HistorySynced extends Event { const HistorySynced(this.topoheight); } -abstract class LibXelisWallet extends ExternalWallet +abstract class LibXelisWallet + extends ExternalWallet with MnemonicInterface { LibXelisWallet(super.currency); static const String _kHasFullTablesKey = 'xelis_has_full_tables'; static const String _kGeneratingTablesKey = 'xelis_generating_tables'; static const String _kWantsFullTablesKey = 'xelis_wants_full_tables'; - static bool _isAnyWalletGeneratingTables = false; static final _initMutex = Mutex(); static final _tableGenerationMutex = Mutex(); static Completer? _tableGenerationCompleter; @@ -200,7 +173,6 @@ abstract class LibXelisWallet extends ExternalWallet } final syncMutex = Mutex(); - NodeModel? _xelisNode; Timer? timer; String? tablePath; @@ -216,9 +188,12 @@ abstract class LibXelisWallet extends ExternalWallet } Future getTableState() async { - final hasFullTables = await secureStorageInterface.read(key: _kHasFullTablesKey) == 'true'; - final isGenerating = await secureStorageInterface.read(key: _kGeneratingTablesKey) == 'true'; - final wantsFull = await secureStorageInterface.read(key: _kWantsFullTablesKey) != 'false'; + final hasFullTables = + await secureStorageInterface.read(key: _kHasFullTablesKey) == 'true'; + final isGenerating = + await secureStorageInterface.read(key: _kGeneratingTablesKey) == 'true'; + final wantsFull = + await secureStorageInterface.read(key: _kWantsFullTablesKey) != 'false'; return XelisTableState( isGenerating: isGenerating, @@ -249,21 +224,30 @@ abstract class LibXelisWallet extends ExternalWallet await for (final rawData in rawEventStream) { final json = jsonDecode(rawData); try { - final eventType = xelis_sdk.WalletEvent.fromStr(json['event'] as String); + final eventType = xelis_sdk.WalletEvent.fromStr( + json['event'] as String, + ); switch (eventType) { case xelis_sdk.WalletEvent.newTopoHeight: yield NewTopoheight(json['data']['topoheight'] as int); case xelis_sdk.WalletEvent.newAsset: yield NewAsset( - xelis_sdk.AssetData.fromJson(json['data'] as Map)); + xelis_sdk.AssetData.fromJson( + json['data'] as Map, + ), + ); case xelis_sdk.WalletEvent.newTransaction: yield NewTransaction( - xelis_sdk.TransactionEntry.fromJson( - json['data'] as Map)); + xelis_sdk.TransactionEntry.fromJson( + json['data'] as Map, + ), + ); case xelis_sdk.WalletEvent.balanceChanged: yield BalanceChanged( - xelis_sdk.BalanceChangedEvent.fromJson( - json['data'] as Map)); + xelis_sdk.BalanceChangedEvent.fromJson( + json['data'] as Map, + ), + ); case xelis_sdk.WalletEvent.rescan: yield Rescan(json['data']['start_topoheight'] as int); case xelis_sdk.WalletEvent.online: @@ -273,7 +257,7 @@ abstract class LibXelisWallet extends ExternalWallet case xelis_sdk.WalletEvent.historySynced: yield HistorySynced(json['data']['topoheight'] as int); } - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Error processing wallet event: $e\n$s", // level: LogLevel.Error, @@ -293,12 +277,12 @@ abstract class LibXelisWallet extends ExternalWallet Future handleHistorySynced(int topoheight) async {} Future handleNewAsset(xelis_sdk.AssetData asset) async {} + @override Future refresh({int? topoheight}); Future connect() async { try { - _eventSubscription = - convertRawEvents().listen(handleEvent); + _eventSubscription = convertRawEvents().listen(handleEvent); final node = getCurrentNode(); // Logging.instance.log( @@ -306,10 +290,10 @@ abstract class LibXelisWallet extends ExternalWallet // level: LogLevel.Info, // ); await libXelisWallet!.onlineMode( - daemonAddress: "${node.host}:${node.port}" + daemonAddress: "${node.host}:${node.port}", ); await super.refresh(); - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Error connecting to node: $e\n$s", // level: LogLevel.Error, @@ -319,26 +303,20 @@ abstract class LibXelisWallet extends ExternalWallet } List get standardReceivingAddressFilters => [ - FilterCondition.equalTo( - property: r"type", - value: info.mainAddressType, - ), - const FilterCondition.equalTo( - property: r"subType", - value: AddressSubType.receiving, - ), - ]; + FilterCondition.equalTo(property: r"type", value: info.mainAddressType), + const FilterCondition.equalTo( + property: r"subType", + value: AddressSubType.receiving, + ), + ]; List get standardChangeAddressFilters => [ - FilterCondition.equalTo( - property: r"type", - value: info.mainAddressType, - ), - const FilterCondition.equalTo( - property: r"subType", - value: AddressSubType.change, - ), - ]; + FilterCondition.equalTo(property: r"type", value: info.mainAddressType), + const FilterCondition.equalTo( + property: r"subType", + value: AddressSubType.change, + ), + ]; @override Future open() async { @@ -374,7 +352,7 @@ abstract class LibXelisWallet extends ExternalWallet password: password!, network: cryptoCurrency.network.xelisNetwork, precomputedTablesPath: tablePath, - l1Low: tableState.currentSize.isLow + l1Low: tableState.currentSize.isLow, ); final mnemonic = await wallet.getSeed(); @@ -382,7 +360,7 @@ abstract class LibXelisWallet extends ExternalWallet key: Wallet.mnemonicKey(walletId: walletId), value: mnemonic.trim(), ); - + await secureStorageInterface.delete( key: '_${walletId}_needs_creation', ); @@ -402,14 +380,14 @@ abstract class LibXelisWallet extends ExternalWallet seed: mnemonic.trim(), network: cryptoCurrency.network.xelisNetwork, precomputedTablesPath: tablePath, - l1Low: tableState.currentSize.isLow + l1Low: tableState.currentSize.isLow, ); await secureStorageInterface.write( key: Wallet.mnemonicKey(walletId: walletId), value: mnemonic.trim(), ); - + await secureStorageInterface.delete( key: '_${walletId}_needs_restoration', ); @@ -427,7 +405,7 @@ abstract class LibXelisWallet extends ExternalWallet ); } }); - } catch (e, s) { + } catch (_) { // Logging.instance.log( // "Failed to open/create wallet: $e\n$s", // level: LogLevel.Error, @@ -435,7 +413,7 @@ abstract class LibXelisWallet extends ExternalWallet rethrow; } }); - + debugPrint("Checking for upgradability"); if (await isTableUpgradeAvailable()) { debugPrint("Generating large tables in background"); @@ -443,16 +421,17 @@ abstract class LibXelisWallet extends ExternalWallet } } - final newReceivingAddress = await getCurrentReceivingAddress() ?? - Address( - walletId: walletId, - derivationIndex: 0, - derivationPath: null, - value: libXelisWallet!.getAddressStr(), - publicKey: [], - type: AddressType.xelis, - subType: AddressSubType.receiving, - ); + final newReceivingAddress = + await getCurrentReceivingAddress() ?? + Address( + walletId: walletId, + derivationIndex: 0, + derivationPath: null, + value: libXelisWallet!.getAddressStr(), + publicKey: [], + type: AddressType.xelis, + subType: AddressSubType.receiving, + ); await mainDB.updateOrPutAddresses([newReceivingAddress]); if (info.cachedReceivingAddress != newReceivingAddress.value) { @@ -490,7 +469,7 @@ abstract class LibXelisWallet extends ExternalWallet await libXelisWallet?.close(); libXelisWallet?.dispose(); libXelisWallet = null; - + await super.exit(); }); } @@ -505,15 +484,15 @@ abstract class LibXelisWallet extends ExternalWallet extension XelisTableManagement on LibXelisWallet { Future isTableUpgradeAvailable() async { if (kIsWeb) return false; - + final state = await getTableState(); return state.currentSize != state.desiredSize; } Future updateTablesToDesiredSize() async { if (kIsWeb) return; - - await Future.delayed(const Duration(seconds: 1)); + + await Future.delayed(const Duration(seconds: 1)); if (LibXelisWallet._tableGenerationCompleter != null) { try { await LibXelisWallet._tableGenerationCompleter!.future; @@ -522,7 +501,7 @@ extension XelisTableManagement on LibXelisWallet { // Previous generation failed, we'll try again } } - + await LibXelisWallet._tableGenerationMutex.protect(() async { // Check again after acquiring mutex if (LibXelisWallet._tableGenerationCompleter != null) { @@ -533,7 +512,7 @@ extension XelisTableManagement on LibXelisWallet { // Previous generation failed, we'll try again } } - + final state = await getTableState(); if (state.currentSize == state.desiredSize) return; @@ -547,30 +526,32 @@ extension XelisTableManagement on LibXelisWallet { l1Low: state.desiredSize.isLow, ); - await setTableState(XelisTableState( - isGenerating: false, - currentSize: state.desiredSize, - desiredSize: state.desiredSize, - )); + await setTableState( + XelisTableState( + isGenerating: false, + currentSize: state.desiredSize, + desiredSize: state.desiredSize, + ), + ); debugPrint("Table upgrade done"); LibXelisWallet._tableGenerationCompleter!.complete(); - } catch (e, s) { + } catch (e) { // Logging.instance.log( // "Failed to update tables: $e\n$s", // level: LogLevel.Error, // ); await setTableState(state.copyWith(isGenerating: false)); - + LibXelisWallet._tableGenerationCompleter!.completeError(e); } finally { if (!LibXelisWallet._tableGenerationCompleter!.isCompleted) { LibXelisWallet._tableGenerationCompleter!.completeError( - Exception('Table generation abandoned') + Exception('Table generation abandoned'), ); } LibXelisWallet._tableGenerationCompleter = null; } }); } -} \ No newline at end of file +} From c24935dabfdc2790610c117a5a0347cc49f2d283 Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 17 Mar 2025 12:01:53 -0600 Subject: [PATCH 32/50] logging change --- lib/main.dart | 353 ++++++++++++---------- lib/wallets/wallet/impl/xelis_wallet.dart | 13 +- macos/Podfile.lock | 161 ---------- 3 files changed, 199 insertions(+), 328 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 2304688fa..ccf2ecf6e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -22,8 +22,12 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:keyboard_dismisser/keyboard_dismisser.dart'; +import 'package:logger/logger.dart'; import 'package:path_provider/path_provider.dart'; import 'package:window_size/window_size.dart'; +import 'package:xelis_flutter/src/api/api.dart' as xelis_api; +import 'package:xelis_flutter/src/api/logger.dart' as xelis_logging; +import 'package:xelis_flutter/src/frb_generated.dart' as xelis_rust; import 'app_config.dart'; import 'db/db_version_migration.dart'; @@ -74,18 +78,36 @@ import 'wallets/isar/providers/all_wallets_info_provider.dart'; import 'wallets/wallet/wallet_mixin_interfaces/spark_interface.dart'; import 'widgets/crypto_notifications.dart'; -import 'package:xelis_flutter/src/frb_generated.dart' as xelis_rust; -import 'package:xelis_flutter/src/api/api.dart' as xelis_api; - -final openedFromSWBFileStringStateProvider = - StateProvider((ref) => null); +final openedFromSWBFileStringStateProvider = StateProvider( + (ref) => null, +); void startListeningToRustLogs() { - xelis_api.createLogStream().listen((logEntry) { - Logging.instance.i("[Rust Log] [${logEntry.level}] ${logEntry.tag}: ${logEntry.msg}"); - }, onError: (e) { - Logging.instance.e("Error receiving Rust logs: $e"); - }); + xelis_api.createLogStream().listen( + (logEntry) { + final Level level; + switch (logEntry.level) { + case xelis_logging.Level.error: + level = Level.error; + case xelis_logging.Level.warn: + level = Level.warning; + case xelis_logging.Level.info: + level = Level.info; + case xelis_logging.Level.debug: + level = Level.debug; + case xelis_logging.Level.trace: + level = Level.trace; + } + + Logging.instance.log( + level, + "[Xelis Rust Log] ${logEntry.tag}: ${logEntry.msg}", + ); + }, + onError: (dynamic e) { + Logging.instance.e("Error receiving Xelis Rust logs: $e"); + }, + ); } // main() is the entry point to the app. It initializes Hive (local database), @@ -96,9 +118,6 @@ void main(List args) async { await xelis_rust.RustLib.init(); WidgetsFlutterBinding.ensureInitialized(); - await xelis_api.setUpRustLogger(); - startListeningToRustLogs(); - if (Util.isDesktop && args.length == 2 && args.first == "-d") { StackFileSystem.setDesktopOverrideDir(args.last); } @@ -124,9 +143,7 @@ void main(List args) async { if (screenHeight != null) { // starting to height be 3/4 screen height or 900, whichever is smaller final height = min(screenHeight * 0.75, 900); - setWindowFrame( - Rect.fromLTWH(0, 0, 1220, height), - ); + setWindowFrame(Rect.fromLTWH(0, 0, 1220, height)); } } @@ -162,8 +179,9 @@ void main(List args) async { // node model adapter DB.instance.hive.registerAdapter(NodeModelAdapter()); - if (!DB.instance.hive - .isAdapterRegistered(lib_monero_compat.WalletInfoAdapter().typeId)) { + if (!DB.instance.hive.isAdapterRegistered( + lib_monero_compat.WalletInfoAdapter().typeId, + )) { DB.instance.hive.registerAdapter(lib_monero_compat.WalletInfoAdapter()); } @@ -184,6 +202,9 @@ void main(List args) async { level: Prefs.instance.logLevel, ); + await xelis_api.setUpRustLogger(); + startListeningToRustLogs(); + // setup lib spark logging initSparkLogging(Prefs.instance.logLevel); @@ -210,10 +231,12 @@ void main(List args) async { // Desktop migrate handled elsewhere (currently desktop_login_view.dart) if (!Util.isDesktop) { - final int dbVersion = DB.instance.get( - boxName: DB.boxNameDBInfo, - key: "hive_data_version", - ) as int? ?? + final int dbVersion = + DB.instance.get( + boxName: DB.boxNameDBInfo, + key: "hive_data_version", + ) + as int? ?? 0; if (dbVersion < Constants.currentDataVersion) { try { @@ -248,22 +271,25 @@ void main(List args) async { // verify current user preference theme and revert to default // if problems are found to prevent app being unusable - if (!(await ThemeService.instance - .verifyInstalled(themeId: Prefs.instance.themeId))) { + if (!(await ThemeService.instance.verifyInstalled( + themeId: Prefs.instance.themeId, + ))) { Prefs.instance.themeId = "light"; } // verify current user preference light brightness theme and revert to default // if problems are found to prevent app being unusable - if (!(await ThemeService.instance - .verifyInstalled(themeId: Prefs.instance.systemBrightnessLightThemeId))) { + if (!(await ThemeService.instance.verifyInstalled( + themeId: Prefs.instance.systemBrightnessLightThemeId, + ))) { Prefs.instance.systemBrightnessLightThemeId = "light"; } // verify current user preference dark brightness theme and revert to default // if problems are found to prevent app being unusable - if (!(await ThemeService.instance - .verifyInstalled(themeId: Prefs.instance.systemBrightnessDarkThemeId))) { + if (!(await ThemeService.instance.verifyInstalled( + themeId: Prefs.instance.systemBrightnessDarkThemeId, + ))) { Prefs.instance.systemBrightnessDarkThemeId = "dark"; } @@ -279,18 +305,14 @@ class MyApp extends StatelessWidget { final localeService = LocaleService(); localeService.loadLocale(); - return const KeyboardDismisser( - child: MaterialAppWithTheme(), - ); + return const KeyboardDismisser(child: MaterialAppWithTheme()); } } // Sidenote: MaterialAppWithTheme and InitView are only separated for clarity. No other reason. class MaterialAppWithTheme extends ConsumerStatefulWidget { - const MaterialAppWithTheme({ - super.key, - }); + const MaterialAppWithTheme({super.key}); @override ConsumerState createState() => @@ -364,7 +386,9 @@ class _MaterialAppWithThemeState extends ConsumerState prefs: ref.read(prefsChangeNotifierProvider), ); ref.read(priceAnd24hChangeNotifierProvider).start(true); - await ref.read(pWallets).load( + await ref + .read(pWallets) + .load( ref.read(prefsChangeNotifierProvider), ref.read(mainDBProvider), ); @@ -394,7 +418,9 @@ class _MaterialAppWithThemeState extends ConsumerState if (ref.read(prefsChangeNotifierProvider).isAutoBackupEnabled) { switch (ref.read(prefsChangeNotifierProvider).backupFrequencyType) { case BackupFrequencyType.everyTenMinutes: - ref.read(autoSWBServiceProvider).startPeriodicBackupTimer( + ref + .read(autoSWBServiceProvider) + .startPeriodicBackupTimer( duration: const Duration(minutes: 10), ); break; @@ -427,9 +453,10 @@ class _MaterialAppWithThemeState extends ConsumerState ref.read(prefsChangeNotifierProvider).systemBrightnessDarkThemeId; break; case Brightness.light: - themeId = ref - .read(prefsChangeNotifierProvider) - .systemBrightnessLightThemeId; + themeId = + ref + .read(prefsChangeNotifierProvider) + .systemBrightnessLightThemeId; break; } } else { @@ -448,9 +475,8 @@ class _MaterialAppWithThemeState extends ConsumerState ref.read(applicationThemesDirectoryPathProvider.notifier).state = StackFileSystem.themesDir!.path; - ref.read(themeProvider.state).state = ref.read(pThemeService).getTheme( - themeId: themeId, - )!; + ref.read(themeProvider.state).state = + ref.read(pThemeService).getTheme(themeId: themeId)!; if (Platform.isAndroid) { // fetch open file if it exists @@ -478,18 +504,17 @@ class _MaterialAppWithThemeState extends ConsumerState ref.read(prefsChangeNotifierProvider).systemBrightnessDarkThemeId; break; case Brightness.light: - themeId = ref - .read(prefsChangeNotifierProvider) - .systemBrightnessLightThemeId; + themeId = + ref + .read(prefsChangeNotifierProvider) + .systemBrightnessLightThemeId; break; } WidgetsBinding.instance.addPostFrameCallback((_) { if (ref.read(prefsChangeNotifierProvider).enableSystemBrightness) { ref.read(themeProvider.state).state = - ref.read(pThemeService).getTheme( - themeId: themeId, - )!; + ref.read(pThemeService).getTheme(themeId: themeId)!; } }); }; @@ -568,8 +593,8 @@ class _MaterialAppWithThemeState extends ConsumerState /// should only be called on android currently Future getOpenFile() async { // update provider with new file content state - ref.read(openedFromSWBFileStringStateProvider.state).state = - await platform.invokeMethod("getOpenFile"); + ref.read(openedFromSWBFileStringStateProvider.state).state = await platform + .invokeMethod("getOpenFile"); // call reset to clear cached value await resetOpenPath(); @@ -586,9 +611,9 @@ class _MaterialAppWithThemeState extends ConsumerState Future goToRestoreSWB(String encrypted) async { if (!ref.read(prefsChangeNotifierProvider).hasPin) { - await Navigator.of(navigatorKey.currentContext!) - .pushNamed(CreatePinView.routeName, arguments: true) - .then((value) { + await Navigator.of( + navigatorKey.currentContext!, + ).pushNamed(CreatePinView.routeName, arguments: true).then((value) { if (value is! bool || value == false) { Navigator.of(navigatorKey.currentContext!).pushNamed( RestoreFromEncryptedStringView.routeName, @@ -602,16 +627,17 @@ class _MaterialAppWithThemeState extends ConsumerState navigatorKey.currentContext!, RouteGenerator.getRoute( shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute, - builder: (_) => LockscreenView( - showBackButton: true, - routeOnSuccess: RestoreFromEncryptedStringView.routeName, - routeOnSuccessArguments: encrypted, - biometricsCancelButtonString: "CANCEL", - biometricsLocalizedReason: - "Authenticate to restore ${AppConfig.appName} backup", - biometricsAuthenticationTitle: - "Restore ${AppConfig.prefix} backup", - ), + builder: + (_) => LockscreenView( + showBackButton: true, + routeOnSuccess: RestoreFromEncryptedStringView.routeName, + routeOnSuccessArguments: encrypted, + biometricsCancelButtonString: "CANCEL", + biometricsLocalizedReason: + "Authenticate to restore ${AppConfig.appName} backup", + biometricsAuthenticationTitle: + "Restore ${AppConfig.prefix} backup", + ), settings: const RouteSettings(name: "/swbrestorelockscreen"), ), ), @@ -621,10 +647,7 @@ class _MaterialAppWithThemeState extends ConsumerState InputBorder _buildOutlineInputBorder(Color color) { return OutlineInputBorder( - borderSide: BorderSide( - width: 1, - color: color, - ), + borderSide: BorderSide(width: 1, color: color), borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius), ); } @@ -662,9 +685,7 @@ class _MaterialAppWithThemeState extends ConsumerState ), // splashFactory: NoSplash.splashFactory, splashColor: Colors.transparent, - buttonTheme: ButtonThemeData( - splashColor: colorScheme.splash, - ), + buttonTheme: ButtonThemeData(splashColor: colorScheme.splash), textButtonTheme: TextButtonThemeData( style: ButtonStyle( // splashFactory: NoSplash.splashFactory, @@ -672,8 +693,9 @@ class _MaterialAppWithThemeState extends ConsumerState minimumSize: MaterialStateProperty.all(const Size(46, 46)), // textStyle: MaterialStateProperty.all( // STextStyles.button(context)), - foregroundColor: - MaterialStateProperty.all(colorScheme.buttonTextSecondary), + foregroundColor: MaterialStateProperty.all( + colorScheme.buttonTextSecondary, + ), backgroundColor: MaterialStateProperty.all( colorScheme.buttonBackSecondary, ), @@ -690,25 +712,22 @@ class _MaterialAppWithThemeState extends ConsumerState checkboxTheme: CheckboxThemeData( splashRadius: 0, shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(Constants.size.checkboxBorderRadius), + borderRadius: BorderRadius.circular( + Constants.size.checkboxBorderRadius, + ), ), - checkColor: MaterialStateColor.resolveWith( - (state) { - if (state.contains(MaterialState.selected)) { - return colorScheme.checkboxIconChecked; - } + checkColor: MaterialStateColor.resolveWith((state) { + if (state.contains(MaterialState.selected)) { + return colorScheme.checkboxIconChecked; + } + return colorScheme.checkboxBGChecked; + }), + fillColor: MaterialStateColor.resolveWith((states) { + if (states.contains(MaterialState.selected)) { return colorScheme.checkboxBGChecked; - }, - ), - fillColor: MaterialStateColor.resolveWith( - (states) { - if (states.contains(MaterialState.selected)) { - return colorScheme.checkboxBGChecked; - } - return colorScheme.checkboxBorderEmpty; - }, - ), + } + return colorScheme.checkboxBorderEmpty; + }), ), appBarTheme: AppBarTheme( centerTitle: false, @@ -726,91 +745,101 @@ class _MaterialAppWithThemeState extends ConsumerState ), // labelStyle: STextStyles.fieldLabel(context), // hintStyle: STextStyles.fieldLabel(context), - enabledBorder: - _buildOutlineInputBorder(colorScheme.textFieldDefaultBG), - focusedBorder: - _buildOutlineInputBorder(colorScheme.textFieldDefaultBG), + enabledBorder: _buildOutlineInputBorder( + colorScheme.textFieldDefaultBG, + ), + focusedBorder: _buildOutlineInputBorder( + colorScheme.textFieldDefaultBG, + ), errorBorder: _buildOutlineInputBorder(colorScheme.textFieldDefaultBG), - disabledBorder: - _buildOutlineInputBorder(colorScheme.textFieldDefaultBG), - focusedErrorBorder: - _buildOutlineInputBorder(colorScheme.textFieldDefaultBG), + disabledBorder: _buildOutlineInputBorder( + colorScheme.textFieldDefaultBG, + ), + focusedErrorBorder: _buildOutlineInputBorder( + colorScheme.textFieldDefaultBG, + ), ), ), home: CryptoNotifications( - child: Util.isDesktop - ? FutureBuilder( - future: loadShared(), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - if (_desktopHasPassword) { - String? startupWalletId; - if (ref - .read(prefsChangeNotifierProvider) - .gotoWalletOnStartup) { - startupWalletId = ref + child: + Util.isDesktop + ? FutureBuilder( + future: loadShared(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (_desktopHasPassword) { + String? startupWalletId; + if (ref .read(prefsChangeNotifierProvider) - .startupWalletId; + .gotoWalletOnStartup) { + startupWalletId = + ref + .read(prefsChangeNotifierProvider) + .startupWalletId; + } + + return DesktopLoginView( + startupWalletId: startupWalletId, + load: load, + ); + } else { + return const IntroView(); } - - return DesktopLoginView( - startupWalletId: startupWalletId, - load: load, - ); } else { - return const IntroView(); + return const LoadingView(); } - } else { - return const LoadingView(); - } - }, - ) - : FutureBuilder( - future: load(), - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - // FlutterNativeSplash.remove(); - if (ref.read(pAllWalletsInfo).isNotEmpty || - ref.read(prefsChangeNotifierProvider).hasPin) { - // return HomeView(); - - String? startupWalletId; - if (ref - .read(prefsChangeNotifierProvider) - .gotoWalletOnStartup) { - startupWalletId = ref + }, + ) + : FutureBuilder( + future: load(), + builder: ( + BuildContext context, + AsyncSnapshot snapshot, + ) { + if (snapshot.connectionState == ConnectionState.done) { + // FlutterNativeSplash.remove(); + if (ref.read(pAllWalletsInfo).isNotEmpty || + ref.read(prefsChangeNotifierProvider).hasPin) { + // return HomeView(); + + String? startupWalletId; + if (ref .read(prefsChangeNotifierProvider) - .startupWalletId; - } - - return LockscreenView( - isInitialAppLogin: true, - routeOnSuccess: HomeView.routeName, - routeOnSuccessArguments: startupWalletId, - biometricsAuthenticationTitle: - "Unlock ${AppConfig.prefix}", - biometricsLocalizedReason: - "Unlock your ${AppConfig.appName} using biometrics", - biometricsCancelButtonString: "Cancel", - ); - } else { - if (AppConfig.appName == "Campfire" && - !CampfireMigration.didRun && - CampfireMigration.hasOldWallets) { - return const CampfireMigrateView(); + .gotoWalletOnStartup) { + startupWalletId = + ref + .read(prefsChangeNotifierProvider) + .startupWalletId; + } + + return LockscreenView( + isInitialAppLogin: true, + routeOnSuccess: HomeView.routeName, + routeOnSuccessArguments: startupWalletId, + biometricsAuthenticationTitle: + "Unlock ${AppConfig.prefix}", + biometricsLocalizedReason: + "Unlock your ${AppConfig.appName} using biometrics", + biometricsCancelButtonString: "Cancel", + ); } else { - return const IntroView(); + if (AppConfig.appName == "Campfire" && + !CampfireMigration.didRun && + CampfireMigration.hasOldWallets) { + return const CampfireMigrateView(); + } else { + return const IntroView(); + } } + } else { + // CURRENTLY DISABLED as cannot be animated + // technically not needed as FlutterNativeSplash will overlay + // anything returned here until the future completes but + // FutureBuilder requires you to return something + return const LoadingView(); } - } else { - // CURRENTLY DISABLED as cannot be animated - // technically not needed as FlutterNativeSplash will overlay - // anything returned here until the future completes but - // FutureBuilder requires you to return something - return const LoadingView(); - } - }, - ), + }, + ), ), ); } diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 0dbeb56df..0bb95e8e8 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math'; -import 'package:flutter/foundation.dart'; import 'package:isar/isar.dart'; import 'package:mutex/mutex.dart'; import 'package:stack_wallet_backup/generate_password.dart'; @@ -34,7 +33,7 @@ class XelisWallet extends LibXelisWallet { @override Future init({bool? isRestore}) async { - debugPrint("Xelis: init"); + Logging.instance.d("Xelis: init"); if (isRestore == true) { await _restoreWallet(); @@ -57,7 +56,7 @@ class XelisWallet extends LibXelisWallet { Future _createNewWallet() async { final String password = generatePassword(); - debugPrint("Xelis: storing password"); + Logging.instance.d("Xelis: storing password"); await secureStorageInterface.write( key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), value: password, @@ -626,9 +625,13 @@ class XelisWallet extends LibXelisWallet { assetHash: asset, extraData: null, ); - } catch (e) { + } catch (e, s) { // Handle formatCoin error - use default conversion - debugPrint("formatCoin failed: $e, using fallback conversion"); + Logging.instance.d( + "formatCoin failed, using fallback conversion", + error: e, + stackTrace: s, + ); final rawAmount = recipient.amount.raw; final floatAmount = rawAmount / BigInt.from(10).pow(defaultDecimals); diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 38e7c6e0c..c1dcbc7c9 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -1,194 +1,33 @@ PODS: - - camera_macos (0.0.1): - - FlutterMacOS - - coinlib_flutter (0.5.0): - - Flutter - - FlutterMacOS - - connectivity_plus (0.0.1): - - FlutterMacOS - - ReachabilitySwift - - cs_monero_flutter_libs_macos (0.0.1): - - FlutterMacOS - - desktop_drop (0.0.1): - - FlutterMacOS - - device_info_plus (0.0.1): - - FlutterMacOS - - devicelocale (0.0.1): - - FlutterMacOS - - file_picker (0.0.1): - - FlutterMacOS - flutter_libepiccash (0.0.1): - FlutterMacOS - - flutter_libsparkmobile (0.0.1): - - FlutterMacOS - - flutter_local_notifications (0.0.1): - - FlutterMacOS - - flutter_secure_storage_macos (6.1.1): - - FlutterMacOS - FlutterMacOS (1.0.0) - frostdart (0.0.1): - FlutterMacOS - - isar_flutter_libs (1.0.0): - - FlutterMacOS - lelantus (0.0.1): - FlutterMacOS - - local_auth_darwin (0.0.1): - - Flutter - - FlutterMacOS - - package_info_plus (0.0.1): - - FlutterMacOS - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - ReachabilitySwift (5.0.0) - - share_plus (0.0.1): - - FlutterMacOS - - "sqlite3 (3.46.0+1)": - - "sqlite3/common (= 3.46.0+1)" - - "sqlite3/common (3.46.0+1)" - - "sqlite3/fts5 (3.46.0+1)": - - sqlite3/common - - "sqlite3/perf-threadsafe (3.46.0+1)": - - sqlite3/common - - "sqlite3/rtree (3.46.0+1)": - - sqlite3/common - - sqlite3_flutter_libs (0.0.1): - - FlutterMacOS - - sqlite3 (~> 3.46.0) - - sqlite3/fts5 - - sqlite3/perf-threadsafe - - sqlite3/rtree - - stack_wallet_backup (0.0.1): - - FlutterMacOS - - tor_ffi_plugin (0.0.1) - - url_launcher_macos (0.0.1): - - FlutterMacOS - - wakelock_plus (0.0.1): - - FlutterMacOS - - window_size (0.0.2): - - FlutterMacOS - - xelis_flutter (0.0.1): - - FlutterMacOS DEPENDENCIES: - - camera_macos (from `Flutter/ephemeral/.symlinks/plugins/camera_macos/macos`) - - coinlib_flutter (from `Flutter/ephemeral/.symlinks/plugins/coinlib_flutter/darwin`) - - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) - - cs_monero_flutter_libs_macos (from `Flutter/ephemeral/.symlinks/plugins/cs_monero_flutter_libs_macos/macos`) - - desktop_drop (from `Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos`) - - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) - - devicelocale (from `Flutter/ephemeral/.symlinks/plugins/devicelocale/macos`) - - file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`) - flutter_libepiccash (from `Flutter/ephemeral/.symlinks/plugins/flutter_libepiccash/macos`) - - flutter_libsparkmobile (from `Flutter/ephemeral/.symlinks/plugins/flutter_libsparkmobile/macos`) - - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`) - - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - frostdart (from `Flutter/ephemeral/.symlinks/plugins/frostdart/macos`) - - isar_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos`) - lelantus (from `Flutter/ephemeral/.symlinks/plugins/lelantus/macos`) - - local_auth_darwin (from `Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin`) - - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos`) - - stack_wallet_backup (from `Flutter/ephemeral/.symlinks/plugins/stack_wallet_backup/macos`) - - tor_ffi_plugin (from `Flutter/ephemeral/.symlinks/plugins/tor_ffi_plugin/macos`) - - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) - - window_size (from `Flutter/ephemeral/.symlinks/plugins/window_size/macos`) - - xelis_flutter (from `Flutter/ephemeral/.symlinks/plugins/xelis_flutter/macos`) - -SPEC REPOS: - trunk: - - ReachabilitySwift - - sqlite3 EXTERNAL SOURCES: - camera_macos: - :path: Flutter/ephemeral/.symlinks/plugins/camera_macos/macos - coinlib_flutter: - :path: Flutter/ephemeral/.symlinks/plugins/coinlib_flutter/darwin - connectivity_plus: - :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos - cs_monero_flutter_libs_macos: - :path: Flutter/ephemeral/.symlinks/plugins/cs_monero_flutter_libs_macos/macos - desktop_drop: - :path: Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos - device_info_plus: - :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos - devicelocale: - :path: Flutter/ephemeral/.symlinks/plugins/devicelocale/macos - file_picker: - :path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos flutter_libepiccash: :path: Flutter/ephemeral/.symlinks/plugins/flutter_libepiccash/macos - flutter_libsparkmobile: - :path: Flutter/ephemeral/.symlinks/plugins/flutter_libsparkmobile/macos - flutter_local_notifications: - :path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos - flutter_secure_storage_macos: - :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos FlutterMacOS: :path: Flutter/ephemeral frostdart: :path: Flutter/ephemeral/.symlinks/plugins/frostdart/macos - isar_flutter_libs: - :path: Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos lelantus: :path: Flutter/ephemeral/.symlinks/plugins/lelantus/macos - local_auth_darwin: - :path: Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin - package_info_plus: - :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos - path_provider_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin - share_plus: - :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos - sqlite3_flutter_libs: - :path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos - stack_wallet_backup: - :path: Flutter/ephemeral/.symlinks/plugins/stack_wallet_backup/macos - tor_ffi_plugin: - :path: Flutter/ephemeral/.symlinks/plugins/tor_ffi_plugin/macos - url_launcher_macos: - :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos - wakelock_plus: - :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos - window_size: - :path: Flutter/ephemeral/.symlinks/plugins/window_size/macos - xelis_flutter: - :path: Flutter/ephemeral/.symlinks/plugins/xelis_flutter/macos SPEC CHECKSUMS: - camera_macos: c2603f5eed16f05076cf17e12030d2ce55a77839 - coinlib_flutter: 9275e8255ef67d3da33beb6e117d09ced4f46eb5 - connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747 - cs_monero_flutter_libs_macos: b901f94d39d1338f706312b026aba928d23582d4 - desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898 - device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720 - devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225 - file_picker: e716a70a9fe5fd9e09ebc922d7541464289443af flutter_libepiccash: be1560a04150c5cc85bcf08d236ec2b3d1f5d8da - flutter_libsparkmobile: df2d36af1691379c81249e7be7b68be3c81d388b - flutter_local_notifications: 4b427ffabf278fc6ea9484c97505e231166927a5 - flutter_secure_storage_macos: 59459653abe1adb92abbc8ea747d79f8d19866c9 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 frostdart: e6bf3119527ccfbcec1b8767da6ede5bb4c4f716 - isar_flutter_libs: 43385c99864c168fadba7c9adeddc5d38838ca6a lelantus: 308e42c5a648598936a07a234471dd8cf8e687a0 - local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3 - package_info_plus: f5790acc797bf17c3e959e9d6cf162cc68ff7523 - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 - share_plus: 3c787998077d6b31e839225a282e9e27edf99274 - sqlite3: 292c3e1bfe89f64e51ea7fc7dab9182a017c8630 - sqlite3_flutter_libs: 1be4459672f8168ded2d8667599b8e3ca5e72b83 - stack_wallet_backup: 6ebc60b1bdcf11cf1f1cbad9aa78332e1e15778c - tor_ffi_plugin: 2566c1ed174688cca560fa0c64b7a799c66f07cb - url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 - wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269 - window_size: 339dafa0b27a95a62a843042038fa6c3c48de195 PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 From 8e703f128c61a2d1fd4c57b4349b9f39365919ca Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 17 Mar 2025 14:28:38 -0600 Subject: [PATCH 33/50] temp libspark fix --- macos/Podfile.lock | 162 ++++++++++++++++++ pubspec.lock | 4 +- scripts/app_config/templates/pubspec.template | 2 +- 3 files changed, 165 insertions(+), 3 deletions(-) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index c1dcbc7c9..a51d63f71 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -1,33 +1,195 @@ PODS: + - camera_macos (0.0.1): + - FlutterMacOS + - coinlib_flutter (0.5.0): + - Flutter + - FlutterMacOS + - connectivity_plus (0.0.1): + - FlutterMacOS + - ReachabilitySwift + - cs_monero_flutter_libs_macos (0.0.1): + - FlutterMacOS + - desktop_drop (0.0.1): + - FlutterMacOS + - device_info_plus (0.0.1): + - FlutterMacOS + - devicelocale (0.0.1): + - FlutterMacOS + - file_picker (0.0.1): + - FlutterMacOS - flutter_libepiccash (0.0.1): - FlutterMacOS + - flutter_libsparkmobile (0.0.1): + - FlutterMacOS + - flutter_local_notifications (0.0.1): + - FlutterMacOS + - flutter_secure_storage_macos (6.1.1): + - FlutterMacOS - FlutterMacOS (1.0.0) - frostdart (0.0.1): - FlutterMacOS + - isar_flutter_libs (1.0.0): + - FlutterMacOS - lelantus (0.0.1): - FlutterMacOS + - local_auth_darwin (0.0.1): + - Flutter + - FlutterMacOS + - package_info_plus (0.0.1): + - FlutterMacOS + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - ReachabilitySwift (5.2.3) + - share_plus (0.0.1): + - FlutterMacOS + - "sqlite3 (3.46.0+1)": + - "sqlite3/common (= 3.46.0+1)" + - "sqlite3/common (3.46.0+1)" + - "sqlite3/fts5 (3.46.0+1)": + - sqlite3/common + - "sqlite3/perf-threadsafe (3.46.0+1)": + - sqlite3/common + - "sqlite3/rtree (3.46.0+1)": + - sqlite3/common + - sqlite3_flutter_libs (0.0.1): + - FlutterMacOS + - sqlite3 (~> 3.46.0) + - sqlite3/fts5 + - sqlite3/perf-threadsafe + - sqlite3/rtree + - stack_wallet_backup (0.0.1): + - FlutterMacOS + - tor_ffi_plugin (0.0.1) + - url_launcher_macos (0.0.1): + - FlutterMacOS + - wakelock_plus (0.0.1): + - FlutterMacOS + - window_size (0.0.2): + - FlutterMacOS + - xelis_flutter (0.0.1): + - FlutterMacOS DEPENDENCIES: + - camera_macos (from `Flutter/ephemeral/.symlinks/plugins/camera_macos/macos`) + - coinlib_flutter (from `Flutter/ephemeral/.symlinks/plugins/coinlib_flutter/darwin`) + - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) + - cs_monero_flutter_libs_macos (from `Flutter/ephemeral/.symlinks/plugins/cs_monero_flutter_libs_macos/macos`) + - desktop_drop (from `Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos`) + - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) + - devicelocale (from `Flutter/ephemeral/.symlinks/plugins/devicelocale/macos`) + - file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`) - flutter_libepiccash (from `Flutter/ephemeral/.symlinks/plugins/flutter_libepiccash/macos`) + - flutter_libsparkmobile (from `Flutter/ephemeral/.symlinks/plugins/flutter_libsparkmobile/macos`) + - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`) + - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - frostdart (from `Flutter/ephemeral/.symlinks/plugins/frostdart/macos`) + - isar_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos`) - lelantus (from `Flutter/ephemeral/.symlinks/plugins/lelantus/macos`) + - local_auth_darwin (from `Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin`) + - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) + - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos`) + - stack_wallet_backup (from `Flutter/ephemeral/.symlinks/plugins/stack_wallet_backup/macos`) + - tor_ffi_plugin (from `Flutter/ephemeral/.symlinks/plugins/tor_ffi_plugin/macos`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) + - window_size (from `Flutter/ephemeral/.symlinks/plugins/window_size/macos`) + - xelis_flutter (from `Flutter/ephemeral/.symlinks/plugins/xelis_flutter/macos`) + +SPEC REPOS: + trunk: + - ReachabilitySwift + - sqlite3 EXTERNAL SOURCES: + camera_macos: + :path: Flutter/ephemeral/.symlinks/plugins/camera_macos/macos + coinlib_flutter: + :path: Flutter/ephemeral/.symlinks/plugins/coinlib_flutter/darwin + connectivity_plus: + :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos + cs_monero_flutter_libs_macos: + :path: Flutter/ephemeral/.symlinks/plugins/cs_monero_flutter_libs_macos/macos + desktop_drop: + :path: Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos + device_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos + devicelocale: + :path: Flutter/ephemeral/.symlinks/plugins/devicelocale/macos + file_picker: + :path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos flutter_libepiccash: :path: Flutter/ephemeral/.symlinks/plugins/flutter_libepiccash/macos + flutter_libsparkmobile: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_libsparkmobile/macos + flutter_local_notifications: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos + flutter_secure_storage_macos: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos FlutterMacOS: :path: Flutter/ephemeral frostdart: :path: Flutter/ephemeral/.symlinks/plugins/frostdart/macos + isar_flutter_libs: + :path: Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos lelantus: :path: Flutter/ephemeral/.symlinks/plugins/lelantus/macos + local_auth_darwin: + :path: Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin + package_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + share_plus: + :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos + sqlite3_flutter_libs: + :path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos + stack_wallet_backup: + :path: Flutter/ephemeral/.symlinks/plugins/stack_wallet_backup/macos + tor_ffi_plugin: + :path: Flutter/ephemeral/.symlinks/plugins/tor_ffi_plugin/macos + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + wakelock_plus: + :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos + window_size: + :path: Flutter/ephemeral/.symlinks/plugins/window_size/macos + xelis_flutter: + :path: Flutter/ephemeral/.symlinks/plugins/xelis_flutter/macos SPEC CHECKSUMS: + camera_macos: c2603f5eed16f05076cf17e12030d2ce55a77839 + coinlib_flutter: 9275e8255ef67d3da33beb6e117d09ced4f46eb5 + connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747 + cs_monero_flutter_libs_macos: b901f94d39d1338f706312b026aba928d23582d4 + desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898 + device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720 + devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225 + file_picker: e716a70a9fe5fd9e09ebc922d7541464289443af flutter_libepiccash: be1560a04150c5cc85bcf08d236ec2b3d1f5d8da + flutter_libsparkmobile: df2d36af1691379c81249e7be7b68be3c81d388b + flutter_local_notifications: 4b427ffabf278fc6ea9484c97505e231166927a5 + flutter_secure_storage_macos: 59459653abe1adb92abbc8ea747d79f8d19866c9 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 frostdart: e6bf3119527ccfbcec1b8767da6ede5bb4c4f716 + isar_flutter_libs: 43385c99864c168fadba7c9adeddc5d38838ca6a lelantus: 308e42c5a648598936a07a234471dd8cf8e687a0 + local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3 + package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + ReachabilitySwift: 7f151ff156cea1481a8411701195ac6a984f4979 + share_plus: 76dd39142738f7a68dd57b05093b5e8193f220f7 + sqlite3: 292c3e1bfe89f64e51ea7fc7dab9182a017c8630 + sqlite3_flutter_libs: 1be4459672f8168ded2d8667599b8e3ca5e72b83 + stack_wallet_backup: 6ebc60b1bdcf11cf1f1cbad9aa78332e1e15778c + tor_ffi_plugin: 2566c1ed174688cca560fa0c64b7a799c66f07cb + url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 + wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269 + window_size: 339dafa0b27a95a62a843042038fa6c3c48de195 + xelis_flutter: 34e05f3621e46381fb1b10d7c11f63764d3f7a80 PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 diff --git a/pubspec.lock b/pubspec.lock index 95c5d28ab..5df33ec99 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -832,8 +832,8 @@ packages: dependency: "direct main" description: path: "." - ref: "28d0f6c8db56a7d14d6495e810b8705a5c438929" - resolved-ref: "28d0f6c8db56a7d14d6495e810b8705a5c438929" + ref: ca0c72cecc40fc0bfbafc0d26af675d973ab516b + resolved-ref: ca0c72cecc40fc0bfbafc0d26af675d973ab516b url: "https://github.com/cypherstack/flutter_libsparkmobile.git" source: git version: "0.0.2" diff --git a/scripts/app_config/templates/pubspec.template b/scripts/app_config/templates/pubspec.template index 965529cec..62b1947ca 100644 --- a/scripts/app_config/templates/pubspec.template +++ b/scripts/app_config/templates/pubspec.template @@ -38,7 +38,7 @@ dependencies: flutter_libsparkmobile: git: url: https://github.com/cypherstack/flutter_libsparkmobile.git - ref: 28d0f6c8db56a7d14d6495e810b8705a5c438929 + ref: ca0c72cecc40fc0bfbafc0d26af675d973ab516b # cs_monero compat (unpublished) compat: From 564c3ba715af93a23469fb859013896aefa9db42 Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 17 Mar 2025 17:14:05 -0600 Subject: [PATCH 34/50] update default themes --- .../default_themes/stack_wallet/dark.zip | Bin 1060905 -> 1157605 bytes .../default_themes/stack_wallet/light.zip | Bin 1008797 -> 1103991 bytes lib/themes/theme_service.dart | 63 ++++++++++-------- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/asset_sources/default_themes/stack_wallet/dark.zip b/asset_sources/default_themes/stack_wallet/dark.zip index df24199c441499af9ae2d0c80a9d539e9378a1b3..a859175051f203b4e828eb032ad2472f0171b8a7 100644 GIT binary patch delta 106643 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%0DGpr^y8U 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 diff --git a/asset_sources/default_themes/stack_wallet/light.zip b/asset_sources/default_themes/stack_wallet/light.zip index 9e0c82d9d0b784a00d77b720d5c8f2fc09c6a17f..b26156da8966f20dea566c649dae947ac69f81ed 100644 GIT binary patch delta 104954 zcmaf)bxa*yyXf&!yjYP96ew=Rio3hJySwWE#br~9dvSN!IHg$e;_mK6HZHgCIXAhv zIp3Qz$y)Qr`ei*nnP*KVdr086Rt!y94jus)=AY|9F9D63OtxUb%EKEK1{MJd3j_0C zOaC9DLYPV=jrs0>=ji_(L54y8D=qPbm=o_GasNYPgEUAB4puLbfKT{e00+K2Sfu|} zIuX8@^M4iPfy(hOJ9VL||08OQi}zmu5clIhfGYyqzW}WW2e5wuJ7Ix;0Xl_~{{gDl zMg9eV=NN+j3%C>go06SG!vE}$kHq~iJDekhA^ZjS3kClLh%a=6Mf$&fFJ}?`7Yg=M z#XpMR3jCX3REzkr(P z=l={O=7_HTUFR3#`OiiqMhk7g>Lq0Si!bZ8#o-Y|JzaDYb&6T&o}w45{u%!x1z}+R zU)DQ>y6C3LBxA7B)cm!%_V4)T{vV6vzdf8f*?{yf9)!>|B0b5&>ZPJNqy9^BLrk1e zjf&pkX*ucqS6%*{e&WEwFsDx9p^*R%HV&rt7GD1~n>pDyGP`+NX{e*aypavy`Y$v7 zgDIz-ay1Tv9z}~aMs+Ei@PL9kY*=MDA5vmI6@`t;2b+lE)a^t^uGjN$X@SLAroCsTU3WQ> zq7k##Y3%demEFr${CYq_%1YoxgVM{f;G^d7{iidtQ%vZJEFYP!4a7IUWzfO!!Yn?* z^U-;{_0;p?&(rS-W{7K*2T(!T<;rlJL8jRm=lxx+VuWlSkLCJaeXRi?(DF$--#t3+ zKfZXrB&TPpn8mDEmtEh#U-a9*yl&GNY`dkAY-ifD48 zdGLmoviN%FowlW}JvgLzL#At%i;X7lN=)vLy`*ZA3Z$ z%8vhKlcrT{7iiRT^kYosj3FY_R$W%iljM%P^ux6D=P7n_aC z+N?d3Uj_10Sy2l5CmPmhaLClAl+fnRxb|N9WYZXs99DH>MGr3~0swBm6##oy>NP)y z==h+#&eUvm=D@n*s&@^dx!qGwkgC0OB{&}aGT`0+2LK`;{9=1;W*Mwm=3UaGph8wKf0Cz=FvX7@=QyqAc-S$E%G#~1;A z&ts`ZPr$>KQg>jAea-ENHtRg&BEfcrf2`}t`#ICfV2_uWkvjMNNFD>}}8 z*DuHKOzdC6^-<=eYQg1#M_ioHZ}81|nCwVaA^=s@P7@dwAd30qvs!jekbKEkaA_)I zAoMzNuCFTe+_^956~G}-Kg>yE7haFi}6~nd;dYN7Dr*40+ zi60b7(G}A_E19r+ye+9o_T^5^8HxRwu4EKngf$D6aykp+RNYr|${it%8@%GtB_o3h zNWNZl4q98e<-|Cin*AwYSF;MCVK=vy0ESfpKq{=r$F}v}9+^IxEPW%x!?Q-txlLe&P zj(GNbO>#HX9+?n}fXZCvQQJ&>B8>6v=(|DZxULE98&GC&fauf=cg3J3;bdulFxgnt zqUpPVN{REWtQTdTUNg+Bv>HO7cBhXV-!*05k@ELkBqwNH@HvBPXPh~x2y=dKdopr% zK7i6j^NIBG4khTFoh=i>W)xw|LX3+f64C)Hy;e{aH~f};TmuJ@-w{gRJF5Wyl0icT zR(2}-oyy}S#3UZL?PshYkG@Bjy=H4AK3+2(HPMY`y_imKgv+*5b}xwwW0hg2Ksh>kWxCQM*D& zNxzn@yX(M}z|JKaj0)EqAC4SFOiN}M3FOGGFzIvS9?vZw!7o3+t-KA^wOi|sPL?lx zdFy<~WdXOo<*<-yd{kcm&M04_&Q$S7;s9Y&jBXRP6#FMyqIc3>0~29{(S!mWUDsE$ zrV>qe0WPM4m+&rzqK&Y#ocML83ki6mT3?~5wHmWu&%WA-IBNk6z9o)^WM8BoE=eY^Dz_@vYg(cWw7q1(D0 zMw^X~6%mOh@6^UjJQ88W{=gV7Y&RLbfaId8u4&gyA$V2SbVt&GgG%mfVfWpKh`56B zWf_hDeuqAZ>a)p75<$7PCV9G>lfE0RIOnC-Y8K(!SgyuR>Imqk~TPq${a zVz6dw^t;Gga2&t6XRjgX+PkidAdS&5{#NzO9Xv$pMng|vv13w#Ngm6$9{Kal3oEs! zk-s164-K&HgCgM^{*OX*0pRfVD_7QvKq!fyowZZ{F=(+a3#p>6?T{5WsYgHsrOKQVZetI zEmlmr&t#UTk$>-JKu=G4NSfXNfAhrb%ILHpg->X@2!}{R+NRmN84fD@_h5n;D0e+W zGR2Hl)EM5IH~by21)^+dpR;ZGelUFO2UQ9&%@EVb0R`{St$*x+CXT5H5J286OQe=a%0)J zjEgQw0UR`7#vY8?TVVq9&T}ZUIDQDvUR~+E#6*KYLS;bYQ+LkIeiO&O$Me%eR}%*? zp}Vz$n5GdbHAzL(A(jHW5yez$_S)Hx_CCuGY*>p5=}PNV~V7rp%SkCp`b61b?j9!=RD;=mTvB= zPh2~VKGlFenWq$hNVfK?CiGeLuW^!rcrq)l{_W}5m*~UI-(T))4%Z0>c_89Th}tn< z;AfL;*LhL*zZtW9cL7@tOI6Lgi?{lg4dxflK8^1si5Ed(mAM-Tv+Y))t@*Cc#$SuS z`>)TY}`bcclUC%BegDHd0vj zplP`8>*h;&e>0Q_JY-Oy@4G0OE`P7gt|Q}Mi)+}au9s8{nwn@}5k0Ycp&2$=a}wq} zibov%HB0FUTG@qfZ~Oko^9VegW3Sg#eAPP`2UKZPXE0Zzv^!tiK{L3J7e z+R{|I1zR%|5-imnjwnS1&4S!{hN*nb>b>j-2AC92MBT3H z+W<7J)BAS85`YSyGEBdiM|Vr)DD|lOsS~~NJA@_|vYLKYcDvl}mq}Z`0`%b&-dn3J6EE26{n8S=Bo5$-#^po$b%vR& zQ@b^-#WUE^=cUx}S05FFyNc3pFB|Gld^G7lrs^Ox830?X-5X>vfc!aahEC&LM6%Hl zoE9BtLR^(j`Wc+Z$OJ9DNwAX;mlpdz=&(zNwT&6Of35k!jsK)t8oiJQw!rS()~ad7Vp^^lYxn! z2jpZi(mU|S^{aUf8dx&gUKw+Q44DGst(QK{H8Lf_0Z9;TD;#fF47)HUJHDQ&#DtzZ zKp?IuJ+AeehN2qET-!B^%uui)+@(PTaZUWpM5Jrw8`3qyA0ug~So9=a9uGfDhoZuE zxbSP*xgF&ku)av2TZ)=j4W{S73a>cGR`-DG=ePD^Xzs_X0pgx}(?7TG~ zqWyaRMd0m|@dqJhIXzby&ilS<;q>{>_rSMmWV4(#z}T?x?F8A7ipiRzEsdT-;QJD4 zApG3L~AhU{+Q=#(Pp+)t(`U87E<|xMb4FFdEB0pa5;IT3B+u`+P4uEF9 zM=yMyrr5GLnZ2}jleW9qk%g0i_}|Kj|Ti<(Lb(XzI!?wqY2k)kpj-v zHhVVVod(f_-Yc^>H=0-cy?b&YSc(VxE&)N5#VM>dXQGx=j5%B12N@DP2e(xzi9F== zSZ(u9J`(g|7u@XZ^;#1(k^0%ajR%OJF+s6!7!8-yT9gST$s7VQ3X(aP8=N@s`Yk>p zCuu?BP3sprO+qtuWG2BG-0#iM5DXZs^bHTt=KtI_vKcDOKeD%vUhLxk$QR$H4x?Ys zp2LR4+jrKvBXP=q39%+8PYgw=83ZIs3S1S4=T1#1Xgp|s&GRc&SYmV{F##Nk1DO*a z8_jhFMzgbsnB^gm1~1!1(3)z}{%hxZ+Z3xFd*io=Md^(;$?@(&LdX)iYwNj8*vL;x)r3pITUt4KI3paj4&=EsETq1@G=KGWU zyX_ftVe`I%q3KYq+@F1ewHufa1AK*@y0iMZt*?Ap!ycKrc1aPNjgs^gED)~5>ob4w zH1>fbNg@HKg|Rl$r)~XW_>nJPZWCenUqHLn^$Eu*HTdJ=gMje$)G_9UonIgK#^3#uvAvBHB0RIl5_=m}o0? zjBtyn6gd%;*7rQzjwZfd)!>`*}zN3EaLwyDb-Doh>)6fS9%?Iv5?%b96CaYMaI#2Y3Vt<2~{DI14{CL{n{Vi~SDX!lXNQ0l{h`?KNcV(QYrymwsfsVI9O9k<;^!m6nw zEvb4hEL_)O^ZAW1*kP-g2GQuA>J7*&Dw$SGCC%@6&!P4X~b z5GFRMQ4X;8P&*IHiH&8KV8U-xog>jeX1jkj7V)~xMmjHUFN4xJM{&?Dgea^&OPxq$ zZ4~M)wDIQ}W#COYabU{XK;*m!@q=*(lYj>m_s)bdx1R^jS>hk<80-eepUblfznkpa zbb<%U@BF67Ix;G5H(5+SCg=X@@JQb-c)*KjXFLXiB3;wkN582&o4N#UX^)8gcoaRF zz6^he^G=0VQ>LQcQjnu=D$xN+9+b3K9)J49Fw)QZHiW5ToPu&xBF0&fI6-w4=|f6Y zLkdlQBaC@+B}_HhB9@$Obij2@hOAS=<{JWL-5;oCa$I+~X-sp-aN!bNiw$oLEt=&h zxpq~6Rmit~GfJnCTsuxKfZOwggFudc>wwkKiTdc7MW5D3H8M;w67vnn(}*NI}MgPl_nok z_agI4%&gz4c2?@ZYN7Q*)5Bu=*|6vN(cVS_o>c5);0@6dg9xB{;65L;4I3IU&%%tn zy3x?WR6vj!?S(lQt1>sOB^a<$W2s%y6iNTV#DUEfvtCIEUG*Zu9vZ+Svo59*u)|f! zuO1ig(e$RsdbvIW*}GIAqU?$~LT)h=N99+{tP*OrTMFYcX`EY06WfQ#&?a`K^amXP zLt-lkE+Q$0$7+HtPIvIBb(g0D?n`#)Wa+9F3@X!rWzqJ}I@4B<#%F244NjWRr2X_( zDm8C&&dyqq|Hym*Q5Gco$-4*V)c27c|AF~g|8r?eOl8Zo#($+N=bFi-5}$(OHrNhw z*fPLlxNgHvTK#-u`K>D=bBX->5cHZE==%7hW7=4w5>(I9F@n;#WE*~mTf@>TABfK% zL4vsq;xuD$c$X%8Pm;GV9X@nE?RyqyX6B_sJ(aB^u2i)UH_KpR%(c(KV;p&e|v$nEkrrS1Bs0%~micSCwgWaGMq z(A?fxcVF|b1pd{8Zo>()?;7V&Dm>5GY%FNvjmi+u_Cnd?#+4VGT-5>Uu<8&&od zB6lRBU?#pmbdlgv%O)XKRtZV%E@^8HH6FM;(H42NV$DSW zVq|f-u+cfyv+9F#pzk`EXH6lFK}(QHp<^%nx7t46G1XQRVbmSLskiCZb*96Iv%$;a zUh|r8ruTG)7zevvI%&*40H2EZdR~HV^_p!+Dh^a&$DJr+q|NQU**66f!pa|MzHPkM zo33)dxCc=so9ut?1&Ca=_Ggv}aW*3QP|XE0vXuXZ%2VtJ3(hR zbx2Vmy*3A5xbC_r9z#x+APKj^$C{L&Wl|+V*Q;Aqh297wBb$$c_dJKlh6>Y@s*h)K`PXHAJv#TseQW9?F{?VQ;+MWLxwU6*X!cU1d|p9 zt={a^w9>jg+~Af(0pNw%gbnRu)YQnzPM*exp(4?jB(3sn1qxc0vf#w9Tn4;`)D&`y zidMU+HSzA%3a=5$MxI8#roh8`aWRrcJ2x)&%_*0X;nA&ng}?nww&gl|ZnX{hT%EpU zhPTo9`x0ZH@-(Yq~1*-P3@K!r+j!z1s~ayTwdMW4FQ zkipW%fjTSO(nWIc20aKG$B2(Jx|e?-!l_q0x}-aMWbwRnto9=un+U%9EpZl%x5_7OrGIFWJ z82zGrKeZhN&_&=$5*6>(EH*y6rgTNbEj?l8i~Z_JL`a$@#WYZN$As0)*I4Zh(dv<* zn2n>co07}Bw73L2O#Zo%z7Hu=V+X6B6gwXcH`dv|qdcPc?7p!3YfIte;^XJJBiZ+F z=~KgOoBP&okPWAoDpDp*lbVz?Rh`s(`m-6zC-57>0qtZF)=8(Ut^WBRVpLxqYwuNt zgqm9`yPBte2<$~L4#(g=Kg&C>*!QnSSxV^!a850s=@XSzc2VU8SFz&UI_l;>#IL>+09RxT-!=-0bQQYCB`9m#9c7X=*^ z|Nimw4xti0r(uT4-UVw|GC~?(R_Wj=dSpx$HU%4KQ%3V?!3=vRKFP~66A=GjQPFWGtXB{^psa3=${U3dLJh7S5glg#3lbTo@>YW{mD zF9F3sm`LdSdPM>|p-bvdb5VbuPCT`D#k!i8!Kps))casIIZOB4<)mbg*q<-Xs4vY< zA3We^9vhfj5B8tQ1A-9W`|+M`eW}dwDmN<%A;9!fe>!V$6bA?b}ZpL!zBB_T%iB#D84D+mL$cj?vGgBA)S3E@jcDsK%en)TsPSnri-y8Lau zMgCUp8}!2}_n`aKhdCc%gzPYRBSrAaTr}({M4?SwU$=^wI$Aa!f#>P`pG%e zXrNr5%Dx_EJ@krAnK;`x%XF)vY)Z%B@Af6m#q7xpzKU;e5qM9)up+UuGQ3&8N*SeSaCF?9C;lY!BAz-0Dr-a=I5pn*{>#lMhp=3`}kCm^~k@hdfMr!zCH(!z_z zbt4^q*{`xdM;qK>9>=Q5R^`*YdC?J@UErvUuc@sK2w^@;+^sz84{+BO}4C zGCBC?%|X?DVqhQ0aHai_nQo&L}6geoSbnG93BC1fq@J5M3qEOuk zH3F311&N5TLRnnR25twd@}Z+o@gt(a`|&wW#RkiP`T$Xtn_o1WzkuF)uX-l}arCFV zM2DNTFTGJZg&P{wNpot!d@JA`t>N3n(QfmN4qO?RTKZ6{i-2j3=pBdVzCcjJ%M23)sgx$oxr&7sA*Pa`I&-5!)-e1;NXlBp}c z*K**{Zvq0}5Kw26dAg`Y!ShwPlMhU!~6)?vuQ zdpIghhOtl|J`d>&aJGPFG#@m#g_hsM1S{QM<}r@0IRJrJ3>!uKc&P>2JKpW`qvFmP zOqf_)R2BA~zeq4OJk8*mcYW2sV$A;MtL?-7%I#@9zYg`@LOUCwZ?0ag6gph=P>ei4VZ0> zje$v;vRRHUT*G!y_Y@n9s$I{P%m@}+rEM*}o}2U@7ft-!$fyqhX=TZze`51P<&hy*@Pj1xvxbJwv0;|FL+Aes4S*q`S)*vlazjc|jqLvPw#MoDqJ zuNH@3w{uj$FGZrfxQSuIghx{I5H@IfTCl7PDMi5zj4+?#W!|f@SIuB^?_NkF3!M0` z@H!Dgeu2$C@ppumc+ASmbFHNKpegpZM{sIQje1IXJlvawaD&PzYW3~M4crX z=Xr$nc8L6OaH#LB*!H4q15tkf0dh>kOo`*8jB>Ty z_OF_2r-VYYhX9KTX*TAs^itm(OYBTNQr_mQQSXu3n7PKy zTtMtk0(ex;$8Bo7=^O`Grm1kgn-RwwQ*P??J__cDwXU8ThC7tXKPs;}3pZ7aqp#1H z1asyG*}LA5+N;Tx%X4ozFl-Y>m)z~hWY2VwSVtGSIlmUzfeNXK0SJ3Q931lM;;LCu ze>VmxIXMMSj#Tk?Gd~Pf!S$T>yR1tG{ik!D?pCS2_J+)Ef(q@hH_F$nFZK}l?vD|E zqrYLV8vDxR;;`FtZEqhwJjIp}y%$WnW-n-TL*xADd-=-u<43&fABwtLHdW$bPp1`b zTofRoRa`u_aO)$I0Z^Z;?^%CDT3xYVIwzI}%E}iKyxsN@e%YG1UympGdYIfXqu*cR zplYsAaY{ps)W zsteOu)i%vswX6A?6(~Z64Qu8sqaglf50^q)OA(sQo84|jpsoz$!B@@*{^HMaee%J<#Qg&6nnPWDN-R^npKZk@fhL~}QHp=ZKx z&X#5|!-L=MTQ6Rr4q9vO*QdfApo0AbKccZz%BPv&eZ|g$qZn9kR>qo$<5}S@!tH&@ zS7^Ke(hCP1poXN#+c*}zX;^pcO!DW2y1yI56cbYWhe=6^lW4EY46%g{bVV*GL%|~N z=BVfUApAi#y1$h)yV|CS2$KGG&qHW5bj@SYrMLi>kLP^){fC`?P0~$nc}O_NO&s4; zu2zySv_n;NX70HF5y2EZG)AkvV=_A3vneyM&#bWs1iMH}6n*$YTL7^%LGw{13+j_W zB2GJYUI{h{ce^G9<>5|Rx^4H!Xz(I2JjI`lX+!46eB2mc7IJ!+W~U6NcH20hg{cmm z7y|t^Ix}4i*qN72F=H?9&&}NAR?$>j%|ragzm$VDV_v_OO3_&~rkP*O2O#}?nc}p; zmGf!@ELASBf3)wo%gm+C!`Amg_DKt%6x-){0`Cz@@XzhL``KpKYIZRUa->jpyvGbjFjd zcMfFjndNT%eBpHc1`5^gAgNd<9D$fUdol-FRj+Z}I9RQD-kchD5LV8gz8;?+{XPf3 zoR5w#FZ%Jd*U-H7-v;(gS>Oj=Lf75MhW20o+}CtJ^s@-Mv>kH2rpRUC>a*Gx22_&) zP3PNJQh`M@R2wsve3x<=Q)03|ldtt!ql+DEGn&~HlpS5KxhW>3Dg_FVmTuPOYsp$? ze6Qq0>4V}N`Qjni;>suSw80>})jakZ{zi5uu3g7Eb*x`WtrKEpAL4;r(%s{W7kfH8 z!7lm~s7m4|xA7B)OZ951eU1t{&6yz}t*~AmbQ#7++rs$9g-(>wFuKJ{cuu8$KtCjt zDk4EQff8ZSkQ+p*hlF0i84ouM@se(s>6DCiMi-D_vvk~Nmhr*8 zK1=H;kXCd65XV6sGL^#GmVjlx$D`YH} zqDo>HaZ5%pePC1Nwx-5f**)_blEcjkl9+`P{C)#BtjDloNxLgYiXe0LecU)$m48m6 zfBKRGN$M-uLMyeY64r*MWB}0CfGCxoOzUXXs?6~+li9A-72@Ec%R=Z1xSER1UG&uP zb;jE$+}%UzRZB*OfkvT6*TEQ39c{NvJW{z+Z0UjPDyl$p<_yZ#Yy7QT&n)rug^LG=u0NmkVamcX2d^_DQI{a zB!aiAySwce@kta?GU+$2f_+^zxLJC;f59+X+LOlFlDq z5)vsdU{!du?uX)P=>a~_qT$MXxq&!RikxGZ=hDhB{JKM3d$FLH2urg%@FBTKiyTq*3fH$eo#>ogKW+48iF-~E2K<{`4QahzqF)1EeFL6Q zA!`9QhfaYvL-R(@&o#isg#JJq{m60QL^?RhHuE!4;J3C#7JR3n%WL_u`ctW)xInbi zUtc`lCqwM5_U{6c=4QV?b9BE(zGRZd2wwRdkd%-60>0U?&)cwJoV5xV+BcWx8x@pC zNp!&;m5(I20OJCu3P$O&ZzjnCN%bINddn95b6CE=c4P0;3~|PC1E`V;k#o0dhnTyX zu`0Uy2dkCRo|%G*%xByR7uQWn>)KKlu{9loLyj3}f}q!~HxBLRNpdo@Rdr<&Po$b7 zid;d72t8riZpl;{*xeiH0yqmvm{l?nFTGUPOFOks00q1Olry%0Xpxhh;?r`qixXS+ z6y*669)A3Bs}NcY+6nHCM~Ibxz?5SvqeC%vl)mUEe|zr)Is!?`?aL9)`)=-k+j@a11 zUobfefL@cuMvS6??ABs8Fh z%zi<`wTitUbK-jxB-=Erl-!cTev7b(*XK<;V8E{Dx6epjup0_y2XW7%f@K_~*f)2z z<`(&EHQBH@&8Z7sy>jtz;ja&pFP~ROK9{Sn>4j_*PNScD85tF%#j3a4bVT?EmO8n4 ztsd`n{tiZexfSwTcP|nvWS#H#2OsiT^-!G_5Us1V(tUJn|6oz($2|ji_^iZ>MQ&gb z2gp04^eKNGsrNwS5A7bE*7i&;8JOZZg2Icm!wcUvVsjxCTdAbVVPg;Pt{<+x2tH~I7r?b|`kHhg(2Z#Fe% z!3Yl#OMfL&ez+Qx6Dq_P&SojTk4TBR^c44S^=jjsRl*jRL$I~WgIqCG(%GYNq~m!= z_7b})XZ60*uz0Pc>ZeBi&x2B5C+AQ4M9jzrZ_>u7i1XqmGaODw3nB$*PKlA$fd#A! zZdG^H8?EBkWWku_3K`@E`*@}K({B@et@}rIC>6y|eXYTy+|knHCo^>qU06rTAn+2+ z6T>{5hg7AzI~V4zgQLGWT`yBSz0{tqce|dHU9x|%Z!?UIYg}iATZX;+$7PJ1Uen6- zs9)WRF$KTKXPjI3O3WtUQX!Ik!HwjI0I0HULhz^qV8$Mc6)0Zszr zV%sed<;Y%YbN1q@SrwvE-IitJ8nlP+WlvHVcT6Q=1!dIY*X2oK$&MY@^p%7U^#TqW z)82}Lj~A1Lul=IDcshFT_xy41q~GadEz)kPhM$Jc_pf#*jc@42Z`M|;0_8pvh1ieD z7KEKRJ-qv1^Bq}Sy0XSodhytTZbSAmgr+zKcvp8Tl)dbHECze#=9`)8I=CY-#4xDG z#rNXs;q1c9MDz$}r9mmD67iolrF;DIS+^1vh5o6D-+u1XG92QKASg=_LO0SVn1=a# zR(QQq%hf>0@f9|5Q71_vfI7)^vR_;FSbZRa&QDsw8%UGzG*_^-&d_Si#VP(-zWvWP zOYzX*-!zgagp{`|kBRmY3nMO$(yB^SBrb47o_&l%wOE{$$ly~g1_X!YgR^5ZeNJln zR0hg;W-rb6TEECfuCQ@32sxwo$13|nv4D+ii&y=kvFWIyI^L~Zz#xw`DMBV8R$O+V zyw189Lzp>YU?^2huDMuk(_32g5epylR96PpL`D?0m%*3VB6iQ1%gL%W-{7+1n!gbI zppqQi^@AYLrr+Mp$9Ol@a{j&fpQ%C_Pq_nTgHB6Ceo@E}VT0dWdYt_WZVNLoL@ejv z>u-~xfsRir4AWWe0OpGNoPW{PrLf)i@cfrXX^C*7u`4nO`WQ8RW$%tpArZ!lFOkQt zPjpr7{NB|S{*9$k-SaOjpffU~j;AfrzV5W!`&6MNnx8t%avqAKMF$}jM;PCuDqBWv z8d%%fWOeK9_`nfmZXF?gUqw-OLZkfJcVk4`EROsx>Vy`m04YU`FosGOut=`I!HXXC zvm3r3`*o1^-s?{kiBdPrwp9aV35GH22dpW(duuSr-p~7pJ#`B%RsN!=60_CPeOfg8 z2EOzxb0w&F%Z!D#M)8^VgmeR~uv5t1?xq5Vz7;|J{L=4qPRH>PGk&II>Ckt_&7sQ~ zj#feO71Ib7KySEA*;d);kO!mnqsyn`*D#R8=0sfh$ZAIB=0eEMHww-T#cQWgHC0vG z4s-4S9bwX->Yq|gQf9sZeOeq>+}qW~Ip6FS5ctYDKpCXnT__ zAZO5eC^;YdZSu+Rht~5h)ximBo9|OGhej{?r(Wz?JJIoiE;5>D?+B;)1V7o5>4FoaGh(5PSRswG-pMP!AyS>JOzTWHt@`wX);f}*L=VATEx3cVcBNe2>u z5p7kB_cb;IvYsQ>z`V{7lbcAPiJUJdch^YZ#1Mx#Ytb+D_vgk2>?NKdx_K$=u=HK2 zmZ5?t>0deLF^)4GtD6^rBO@c9hz?>a$J70Gi)y->HFK483YOo}$_1~nZT8*7FJemk zY}}J31eatFI(g|RXpB}wn6$UJsjqwk(4Zr~Mb&S?saK`TJQHP0m*sW7er@j!BX#Hm zNLyF@EWN9B&t&~Sfz}S&^E=0rHUI3jXXylI?eqT5#@1_HcN)hTG+Y%(^yHgIu+ptt zZp6M++CQFXBQ5p44T`C62vz9Y_ou1ZD^(FU;pIq4f#+N{D6(c3jFfll~jP=W=V~k;T zb&t@3q=_F%eASSYOSyA3$I&(6w^ow~f9nqH-)PG?C6~O*F>__`G7oY+l@_48~%$uUh-txOuoDb9!+|*_?LV z+39j0g*R^%(N{xAweoqk{4I}+R>v|;)R(07Whs|(TAig)e7-gFF)yM3QS#9402)SX z9i5f<0&I^Fk%=U>={<3Y{X>kHc2AG7pw$E@2Q1J1u%{(MFNK!}S)l?NvTqlK=KfhIH1JTi?3HA4eUE)Q7u8F_ zk5@87`f5)+mfW+_6X#Zdp+>;#LNUMU^_h*;w}df=LjgY3r*U^pm%kqg%Szh(xU#-B z3${%MSSP3Bn1~GJ-L~X5l$^Dj*AG+qvtE9MdR&6ahx@;2f#c<~=G=3$F>Ns8YbXm= z$Z&FZ8Ah}KNdl&O)Lkjt@dSdcVb|4Wb6Ue!?*72I~yrZQjSoJ3~touCKW%t%% zHpg%$o;E6nS?!n{2#$b0v^A;xTI}+qO1PD7AC!;cb5tT+{^$w`ZV7ItbfweF_pC^3 ztMQ_%S~f23;;;(E5;&02`Z!Vn%uLQ^5mcIs`eq~QG>nJb|Bd=YbgV%^WrMkZdAr)^ zXvf28q3h z{zC)ku3Wn8N)q~|UqxP4Z;piA#mD2@qoT;Weos8+(v(vb53EaA4MIf?a-2P?d%({& z)a>I9omz=1$=#2ZPTM^)(5~7Q5^r@&2DtJj>;sdTY4*@DUBJ~ZJx*tV`-65dI?s|s znk}uj0v+Cf4t>{W*52VmpF$^cP6C+TAt{QM&oE74o?M*aZXufxBMJ^lfyA?H_#A06oi?D+AUL z&~VIU7GITaCs&hWopgopm8b6mt(Ju$F^7l5_~^>4ozCQrlAx@Ayg1`a2O69b)1%m9 zB+g+=HdTNAH?~Sz6U&K?tfvEeP-#zbpu+MeqCKr{EYuFelrIAYHiX5oXFU|!fv|5z zH|-FB6!of>zNC1T=x1|ZDd0FV$Lby3gt?H{M!)vc?90e=LGnTXJqFJH5O^Ds?Fm8$ zzpWMsOBH;Rif&P^BdEobB7>W}$q+p$>*=NUGc}k{dW*jEbC?1_*~@}1|C7&-ioMv; zsXPs`{mt|4l058WevCKR_?NWQhvWNXKgC^uQBVp_8#Nv=x%-Ue<^H~o%c-+covYVk zF)fk7lJjQ1)-78KGqC-X|J+UWJ627hVMDCkgt&N=+TurEFX}|6hj!YUEoIu=0_)&M zPy8gEGTvcFt3M7LIx3zhF_C24f>3y`n6(z7u%hti5(PU+RKtv}>o-G z=85s|@A+otnTwf=x~q#?Rcr6PYVG~Lzc2hLaRvkj1pX z9k*s?hU_Zw3xDo?cuX4l3w$Km~ z^#6zpP`W)G^u(7$(Q&j0iBtSLw?{~|pN7EH%EM7q?}wCgM>T)K)AdQ4M%L+Oav&t;g@e@tX^PSgI8A43EhRE%WzeFCSDGM;QWiSy7sl zK(gI-=&q|@(8LhqWn0rXP5fi9P6>$XP8KYCFZxlUh2{i4AA>@TAHX>sh0lff=*2?oAvg#*!JTKa5Ha~ z0kmk~I+6Ttu(5d0G_wdR$s+&0c`=Jn;gs3y!ffGe@pCXp%tcZ114F)S*JI{2F8Hfe z*_O_VOXPpt_skY?$b87 zw#$_L>oHKsPyFdq+i>AaH>>b#6ZRFDhWc=>@j~wYxe2|-IP=x4pVspY>HT|c(HBkn z*q4G%{}(cD`&aPA%9ma7r#l;{2j$--ny}jA7J+;Db`en{^mcc@4)_8-Hz@t`e?53y z6&l>GXZCe^dj;gkf4bNKNJj;rI;zvbSt}AZ|O}05Ho-LUfm_>UtOz%%sV12i>do|#MsIH3g>Pz3;cbarO zc7|RV?Fw%y=b=7`u&>hK<+6|l2b=ZaMDBr!D!tN!+#jWJ-R=d_&k>juy3JOXcK`}f zWDyba*f6B7))atsZ?ZV9}z#Z+m2g>KCNwH`KtuOxO^WXcsmFNoT z49T^`N&yF7{F@GFqoc1TL#pnZ+wlfhD;7FI+x1JH#vKzGzs6W#)0@D*&B>f$(OJU6 zSmM3O6Vn`FUo=#-q<6(AG z)*%|bnI(6{oc2}6FYrMjSd>nyOo$qq^jcO#CaTlTQ+^Gg%=uq>zywu0+ff2N3u(Oa zb5rcVBF@qoKHb`4mSDu)pbst9!0dGxyo3;z>30R8bCf$YxdTPsswV1$ZnkVGQsQH6 zP*l@cm%8TPGqf&}*29t9Zic&%|x^l~WA%X3=|iN;T> z-jFhJ14@rj&+%2|7r0KCosNLld!;K?1|v-x^)#+ul$t+jcQfQ{S6cCtMWS@lXaT}| zcyg@34|0Z-mpJ8EX)OKB*31}zk`b)*A%j3ZUfn97Y_MVCig%|GE^cRe;HGMi8#nhw zVuvaMYthJHZvn!OpPI^ogQ_G$VFcZYe4uYugVLwny5{00(ah092qavR%j=vR=#C4x z7S$C|$2;}fzPr`Gy$n1jrbwoe*G5CI?&7x$RAQ>D!jE0>o^vY~inxBHYWMbs%U9G? zXms}h2aH{dGE-6BLR1D*H&mK!1YYZPAuy)g9JR)zn+lwW&lQ!?huqLvtpTN}i&c%o zEnI4#t4hVZlA%91#<*W$ggdF<-;`DQ@nv#HKKyGXHjRspWrS9)Op{3Au>>&_#@}pJ z-P&i%)&mO!`)21--eVS-o(Q* z_qwKfY31-l{bzE8;=laA_eoy}vkQV>*&|>TIYJE%-sE!rIL{6|g23n8);Nb7_O&5Re+g-d@pu#i115^69 z|Je@m$t~wQi`URMg1gNaq77D?M?SoK^eW!Un3pJ?MhlE`VOwrLZ>FP65@!aVO{N!{ zwKsoXqh-=Uz*z-+W=z%vMNC@-&MxzOqyK?|*DeaY)r>@n}nyupECKj>% zh8v~3SbNhW+h=Z~oT*|lL}P+B^D~gd>^S;)d{E&)(ZYR|DZ@f83FocDxE^4DpVIl%1&)>A=#4PDp2DJb9>|)kBpR^BfIt& z`bfmzUfkkSVwtYFi4VwAPR`emTX_ z`#YgI%RKq9a=^n8MjY50&$A}M19#y|vrE!Lob@CZ%ALZ($n?|Cz{@WuRaaBr(YMfU z$pe~h-@6XM-u~#ks|7}JO&=w3{(<`Ar?1l{&j~T9Eu5SDnxDIpJ;XeEZ z!CV&lHbw~>ddHIZJz16@CY%-FiO=e|a36eU2+nL(|1Wm_0TM|?a1VXK*oSIKJx5RDt`wtEBrKx5H%urZrKD_D0w!rkQuM2a-NfKvZ5{cxV- zlwfTUW7Xhqx|P1HCYE6Q@>vZ}f6#hHnimeF)^SNZgb%b-6*mpNh{yqrIO}s+?2j~j znuMBfBZf z=-*WTf|@KuyQY!%wTd#y?$$&vMyYjOZo&cMrpQOVfG;*t9gX(UNP?W&Rz6oeOCdww z6wAYnD5NuE{0)p~v2&~`*Z+O97SaYrju0AfBpM`A4q`>d&Zn9@j_&(Q+Y^wm=yG(99iEh{#GLQ2+csABRE_$TVEU~R$yH+qP2C>1QpC6OT_Rf)11 zlw;>4HfP-0LAmV$#8)zudfKYgRs@>G+(0f-+qx!3!y<&`JK{aL-FEa>Iyf?%K@sRL zX|}1n-I-LgHU!cY8-viwM2HPQg2zPDOao5A9`7mR(Gn9thy67P^T@cyPt}k0#Mlg* z{n}k$b?$IgY)@!h`>1H_x&=(BUJr#9DSZz*d~J6&98xX(g7@vvQEfb*EUA8rljtiw z0ooQv@reK;bvI=tX3c^!`l`P3GOwIkT1T<_swS~NFvYby{?9*fwQ$sbKF~Y~LQ{O# z#lHO)1Wz&W1ON?1vRwXB;%G1bQf}(#0gv#EoxqP&Ip*_iMo9;=IounDz0)UFtFDXW zd#?SF^z31xIWd%ml-L#d5gYXr2w}sOzSAwu!2gnu8Fvb&>7QExc3TJ(XJ)r@`?pRN zza3LXp`zCxDDww)M@zzC8TM64O3)>pOjRM*jJr#~AYjUC=n2j*6tp~oo%LFLB}^k! zHubB7Z6+Ft=X6Y1rsGosi+PtYfm|-(aRX2DBQz8!q=7tXn-w3k%LUNJ`$i(i3g*AR zdc$1zzEj=m->mP^+_>P@ zR=%S^Rx-t~lX&37UZ4cDTL5w15qq68+QstWiRw?O3xc2oIoTP0Xv^JT zTvp4+FW%g*C00CfgPMOp3=5zJwv0oew)Q4%_ZmY()s~^FE-(>VsqvKesQ}m%y35>X z|A5d_iGoVp105N4e>+0D!}++=ptu~e%!l*T4K>nYA#`;VIv>1*!iiM>fP92RatAUQ zn-Zy0a-c``Wy7)`UZ}Wb+f?u?MpBqHBb!Hfg-&SE6z1*|A{AV#% z%!^ooeN|`kt+t9dSbX(~%Gna6b>E?&Y{M&7dKq#8;lEi^via~B5 z!V~K>j=v3Vnc~AEnuCJ~QNLVy+Xcb9gCfEGXXf(YrC?s}3d^w_dO3w#jb|!I&^J(x zvQ!O6F{pSpi(^bGMbW<)vK+VtU&)MX->ZI=f-O5>MZ?XF&UARDs*PF>>z1dKm~6V? zL(CyfY*M;jZWW1Zt}b}^j`|GMd{S={%l+ba`qp@*t-D5O#?ygL0a$h09y)Z|b)}g4 z)`(mz1^uYJ4BJ+?Km(2*c}_GSR(%Az!oiSIQYQe_<>r3rM|Zav5LIO5?YxY#MBVXy7Kbgy_gR9$iKCux;;^KXoBNRwEJZOmMAY zJ+pNys&!drRF6#D%4xSm*l%+kk@In-7B(;Ug~sUj0%)e$p22#^$VGH5BYtyz(V>c3rm_=LBF$G_tP5eXN2yUL= zL2I1k&EvE(D)>RmY9Pjk!Pw|*Xgbs-mJMre+z1xbjWRAs@#bv$%;ioV?;TmYrVu8+ z(k?r~(j6s>h}YG#+)ZxIpYa&%npwG=C*QSRQkvU2^R5 ziFhYHmE?P<#bJ_7tUm)hF>o=v!&SPy2sXYI_~8F;@o10;e1=+MPPKTAT1E^ z-e~AyduAU`E<7{0N#NlyAM!_oKP3oH!Zv0Wip6bUKVleOp%sI1Ks?Fg;lvYJk?m{- z6eV?JN@D{r4-~b!@v7gVDnA#q7IY`@WgZSW!eILKOQiLYt*Vp^*R3*>9cf-7N2a>+ zF^Lo(rY%Y=><^W97mbQFj(bO8Nfe6kimQSqW<{dgP48GOT3G-J;Dw|_|1Tn>Gn_IP zQ+?I>TRLmQ;Qm+*K)KUwcu#|@b}1K2!`y{$2P6jS1(IwHS3x2QA>ICR&9 zawnL*6}9dB*RC=N(q!B&1S|BaY9Bdu4rP4x}4s!SOLa z^X~40NGl+OZ;`>{$C+Jlwl9Z9#7*et9%LtwNF_F&%pahjc8%jB%t?qhHv)#rFBFz@6(UDTR1W(Ie&m)0sB6Mq4q}40Ac{2JLFU_4 zYCqp6?b#Qcr#)-ka8t%qnVN~#m8)?@vknM|HB6qT!gSbaJAgKzC}Lxp2)LkXWBPGEB!G>^mT^chGUzUgGfhQlOF@7z?lWKH4LDSJC0 z{w_rSTjhv-Fx%sBv6}soC~PlqgNcsl+dNL(JH)7-YL`y6pBBoXt3q=`X)cvE;SM4P zttt3h{xOPy^h=`pj{vUHC67 z%aGHy`7>E2J~Ld`r>Z!|<$Z}7c$x+=W))1VaimYkUVb+LomjvS%>lX*kZip_L+4*j z07#O<*{L?gBipT7NYY5@6V0YQ+8M`5RF$NF@SvA38%g5m+HjIjn_Nw7#XLJ&`Psn? zr7)NW(Ey{}a_3F2a}+GsY<#z(m{;c{gL8gxQ_Z>{LeP=<N~tTaS{5XADi#M)GK{K&BJP`h`)qeCfzY21a)S?l3r0#ieE?ps_g zUPUbsgth5vi!(1fGUod8$KL}a{=e;1kW>ukcV_ZVO+{Cmn+Fxlz$#gK{lQ5jHx_Yu z9dgt){+X*q@ylMGy6Cpj@01=a(cET3GQy&Tkd!u>Ch_e}94RsHDoMJ5wAPh8sAo4J9W>b4-tuW3s~e~Cf3x%b zKy!bKG2T7~J^QT3nSWc-bd%if_*Ozdg4<}6B~_EIXiB{(o9BwcZzEn#f9slYpvmtx z(zRf_mOq5z$VAW~y}u$lX8&qgN4Purap9fqM0NKkEyrES0;_z~y}v)}YF5OwnLi$V zC%W_wK!rA+FsH5%Lm4I3WRFD_9GYC_x6kw0&~Wf)7(O$`uB{HnWc^o5b4ikWkiAt% zGZH}vFZ$cM$LVX5cYpKhrojmqlWX4e!;^*$K%=0dOmb>sz{!=ooWt!*FLf`$Y%t|h z^_ar?rQ`164m|Zvxd@t2_{M(0%4LYa1I{}(LT_m9TN63cn&U2}L~l*zE9YNKD*1Ok z{h@(8ma|5zYK5s{c{f0uq&yNOjF~DoL{;hLEmqaPehHWM*7oDpPA<9vW^XflaM*;T z@miGG|Cg!ZEUf*RP`ilEtMQQ$_?21NSBl4ZvS%)!9|+m)4v!DZyl#goMXa29J`{F0 zWp88Ycyct-8ELWZ_T{3uC@09C>g3IvkFri2&|+uJ#0)&?VEA>Xb-ehOjOK1L2DSq? zZlkoThd|5)*D4r&6q|Q-Ph|o9fInE4;oB8V5y!sd{BcaFiDgD^mApymVbeGyOt`^+ z%mEkWPUzwNunEU4tt6XbJy9KWlB?C@pxkQVJsMW#U14&0bn)srBRXppf5>A>HIqEg z%yde9(C-Y@t@)4dbKdTbES2puIAf3_^eMJqhQOPwg-tgJkeuy}SNqm+`6E$(g{3LA z*luW)xaKPjuTI*kZAEis7QEn32kZe>4{(oHFVUckrJw!_$*}VDD`zb1bFLfpfP4dS zfMOt5e+#EF+zNgy{M~3(lYvhAzGwA38U~*sAlGaQRyT_#Ww}1m`~ZLi2ktD|V@YV7 z3H&oyllFSdOe`)EG6l|o4~8ovcmF4(P~ZfY6NDp&>6lD=N5^_0m$BQBCh1Ai%t2gz@ZDv6s zKxCl-S%uopbX4M z|E7{VhWNie;Nd6uQagcG%tL<=X(s^>JO^BzuT)`+i4Z*fdLuyYcD<-!7p^rj2?*)A zS@bJyXiP7rxr%WA;S&%H9!BYPMLCuoCaIjAmrHAn3L0E=XaIUMwsz z#^H$5R!b(D^^1%1%xB2EYkFV?0MF$RqrL@z0)}B8>D5~&Q3e}|<9AoE#42+rP!anK zbQbL^!Vjm~$>Zv3=ilVS-9`j5XW_*Iz=%c1^|V8mM!W*tsk??JFSXV5%pB5#(>H0# z`C2MwtC2b;mvPllz)0g!z;=B_6*#n=v@}^$|8-9VT`3Hp{jdAgDU;68fFyrKBN9zz zRpd!*Slq`}!B;cnZQ$)Rb%aVf9S_RA<;9woRpcV5_e$BLTwDHR=Trt`sQP6U@CgZ!3mRF_p(lH)gfAP8HO%zXs&*zfF1l}Tf0t_9xk&~ zSl6efmW1GK?Cx5D3vM%R9w;Zh`eZYYt71x8#MnmEufD<|-nUs2A9r`;DOqWOH^7#> zY4uY8R~GH~=33%-sK|RT1L9!%a*@3YF(i)oSo)l&7Ro?@GPGJ*!UId>Q9-$G^jZ2f zfRy^r=qkUB%y|bR-z& z)F@N(e{O^U=r3V!KYG152pH8u{1=8|&{BfTq>#{&;z{eg16&`Y7R#h{+c-gN$vO@~ z_%J>uQ4uP)eU6vaaA*|J@RI@GAk_mT*xjAR3W_#aQt$3@A(~w~+;yLOsRzR_X7-Lz zThlDSd2dVyY~%Z^C4k#v0XG))TUlB~xO}2sIJ1SViFuO)x~NdY-9w#YS1TGz{fPyO zGSwUu9zPQ)Nplvw+3UtWM>M78{yOJ78Ju-9Lf2fRO(418%929yYFsT$H%*fu;a#-{ zQG`@>{N)qz*Sl8AsF!|SefQ-DI5vX$yTFR>^mr|r(kOyPK}5_fO7eibKHYv<)?2tv*+O%=~5<;k&FxYsO0O(`sG(JZo@N}A?@ zbA|yWZ;NM5O~VonyV9!MsoeP7$snv6DVMeD&q(~?!0}Y0G)X0Fg`t+j_9kFg>x0wg zd%pQlz|a4}SOkU|-F@pZ!#E_eCf&BKrh*=G+4#Gn7RO$?h{BRW?&@zd=C(}8J}OTd zr)^n6_X+-oXU# z#-o%ej-x%^o)H8>DwS2HSy-+^>5ary1pi5K=7zN9|wn2$v{XOX$2(eSRxX;tWZ7_3VX|rz!|4r85Gvw73Z5 zK!F2^&I90!HN`=F1Irb5X~&Jh5Kq%6n*2TDqS)^gvZGmvJ6=v*8SUTnTi*vDdIrKA zq;ZpHelw&)qN=9yZw~LMsPJfiA2WYVg7)li zqCq#DUhH^)Aw!rA6n7iCT^?blbcba|;=I%*T?qxwa{1%LnyotmNC~cxw>T>yvMrIR zw509&W@s%BGK<|TTM_YP05&+KoK^RB9LO*;D#~)3?S%y7oLG#l232$E@&ZiuHo@@M zX7{W7K#W8#Xkz#$bKK1MbI`-6OTDezFcwq!2I(ou=ouLGzSF|@R|*gH6thcpVdBH~%SUfrh3qD1E<^!ty*#bE^`yA> zc#ymxGWahr?))C(P1|%F)i{{_+#eFe2VuaG6&M?kRW%CfFL0t&6G(jMUN!Hu*qJoh zLx!%Zn@I;GqJa0r**B}_GNPvBham!+Au_r7h^?DauK=?_ntOiuq6-#qo)lu*`EtxU zwZfLXgRQY12b|L?$?=F|rtf(giaokWgHHW00+75B|4ut*&6;BW3}k3oP5=p74ZZ>8 z!e^p)<)f3u{FS{bj%?|$r(5ZwR?xB|fpXdAns$xsm_8K42B){l%^g1YW7shrg^S8t zNavvNBn_xA;bg8!4NWUYmqFn8v2ZwqfbH%fjn#U`WwH}_v0vtv7p27b zE;EM{5e-#Z7;0sW$EQ&3Nd5fL5=&wrCT&QALTuR>xo$aucb`myd>S~eL`<_zEtKmx zkQ5jrV__n2ZWq~FcU5*G$~8xAcj|%(M_XU6M_=+vNebb_$O%_-cFZ+`_g4qWuLEfa zF2_^>Aw77R4J7C(5I%>qO*xXN5l$#a>EkHZ(tAsh$i$=Y))&u8vi&+idcc22P9bUdLcxI7rbnJRgh9`3!dd0)>uH5lxx~(+s5=hURv3h z8?S#hq1D{j48D0LGA)d9nm=7k9B4$LOI0&a*=wt0V>xv7ZGO{_>qcD$-AXlqH}yW| z>8ty1(o__g`6bB>Xev(pX%}gtV?b8nKzJ?sWMd`AGc(khF(Pc9A&Y=V_~iv$Zw--^ zt6s-xGpYp@n+5}CqEE+v>qOM4Tw{)!P$Y17|7y?hu;xz5XL1yD9xIEYA^Zw9m4G_? zg%8PO(Tx&0+xiur<*7uYV%T_f2vJDW7Ec>oz^I89sF;E z6W+hh8x4KE4ITsE6yC#pR&xA4fW9B6Ox@4#%iCMszfXamlO;y)uj}Xb@8kdBa8UkS zqiO-t3%wm&+>c)7?8RtL-!g%2nQo=nIX+KQbY_8XAe?Q#`+uN~&y4AwPayFA6p-_^ z-ScU`?ei()bDd$|^Ew&z^^`E({d!kXGrIh7e?Ioh_Vu=+=VRSo@Qai7{Q%_5m;ELO zkp4V92Ws}rN8M#@#umi!IXyZ_wR-mp@JRK1I=4GXXkBe@C#mJrT|T)SHvHpMOnwba z6@0_2E*ToGF#>+BwzNpKpFD5;-@p<+=a15>4r|7qnj_=f!?vT@*Yj}uZNHDxnx2>S zn(ohz9N&DQp7)3K=`S)I5Y*5Yu;Kd4?xRb9_j%;uSjidO*Ffmx9MR)=bk z@b&tQbF=&qmc9IAOELgj*L#*a;Nn$Gw+Iu8TL0BK!J*00`Q4uqw9O}^ZU4_0at@t< zSg2Iy?m?)9q37sjfid6InolTKXa9*qZWjJfq9MEyL&)-T#DXict6iYU$cp(*=%>Ww zHlM0&(R;qkm=yC?T4&GO!+K56^YGX2Wb1|4aqR*`A_yhm`@tz!sWQz0VC%eRj zQqM~mTI-jPvK%a&mh6uVG4ubDW&TUL`CsUoek`Q_4@0O03ma)v0M)`!Rrh~$Y4HCE z3#PGlM>Y;h=Fi-EOO^fQJ~~l8KWRXMYQ=BWPi((v!VWt`}XH8RnN;YF)+dIv{-2K{psteMaQnISZzw{#W!j`Tb=k&e|dk``}5r*yPz}ae!E)<>$s;Pv!-$J%Cllluln_3 zs-%BiQ4fe`wl!o|ZrRe|99BTZ ziJvswp2It}|I$45JgKIn_~HY|yv{nF6P&J@KXUu5z)|$}QnJ5~v@v|EnyCgAyEUp# zWo~viez`n80iQSRKbKq1?A|JR4EJ9LjE3T;Pj6FLp6(lbri}klY0Q5v zkm-8p){YtM*PdIM2r%$OSX{m)Yh1PEa4f$pV@E15$9KLt4xHHt~@j2@)(d0n8!t8U7mtCqGji<#nXgbg3 zF9N5pJ-0Lk_DlbG*nQ6TF08&O0YAGS?=PPKPoG=gnMzo@uBS}pes$h2*G&-vOH#&; z8MN1o7C&4Uvy!})ZUhrj=Ua~*HD7tZ*IqU3)?0kh*Z9o;uq;sm1sumhR?tM<&QcaHbqPF~Y2k`X@6XprrBr&4FpG zy``aM$yf-9p}3JWj@q5W|f6?gy%H17QrY&wYO!<3? zf6`pVZBIAj<6m#x>8bD#ds28()}<)5oxXgWzLeIKci##sIs(h>vv&FEwCaH|Y^w&q z?D9{8;o+Y0p-C^KePSSJleqhXwj{gfgqBa^j$<_Sc_Rg2r1e&`ZzOnM1GD$?BBTO} z`OKDi{~-R9Xt)8QZhzbxeNJEZe1Mp~?uh;F$L+t?h2Ho7W$;zY_SZO9%l7-@anJJ= zs#G{Z-Q%QM#Mu<@*6ZqQ+u>NO5 z!SR;6>*Q%N!0VJnM^Z!3|K%;U|bIa>>i5 zLS-$er$Kd#ZU);_`pV{#K0?O)U~}vvfSUDHb9Xm?jQejVCn@}4zJK9Vqe+PMEypS4 zK(omC?j49O%{!%}RqSUdFE3EyJkH1#30Q7@Wnd}NeXIQJqJPb+5PfY5VBUCsGpIxq?3a+DnPI%X6QQU zczRg#yye)_tIcz&&(E!|&*}J=)}Wb_OC{Tg^)?XP;bAY+i6oHQ@#xe=g-QxAGqqM6 zgR%NepUYJ_>l@ro>6f~zn!i0f7LiQl_OVVYZz(%0t(y>IKnQb$!C5!QO~^>^WJcF> zaR4yWExh^Uc4*YQ_b8+Gx=j51afiCVknMyV z`%L9&=LaXwar7M9jok11@&F#~^GJQ3Ui-*gsQ$5dnbkobZ3%1&OZPFr#F$8_*nH(3 z-uMsxJTlF%73jZOPP6y0dxV(I2ilrJ8neJSn=m~*(&N2hC6+7}b+$%VlBSEB3vE_u%$ zIPW?M^vf5uDAYV&M??j)p`Z{)Zh*y{8ZwYcF)qsAS(9?^bQrD0#?lM!+nF24t*2pJ zU~M8=JV9=jttMkd z9+eJBYc*dJkl^IPxlGatcTBhk5eZTV8W;DvFQx_s{*hW2^GS)1TZ)6-cOXbnXWuRO zCYF8iEletDfF=BI*xB-Hg1XAMl7Q}Je%a39Jz-TEnR+2F_u=TiRQOe%$wv0RnxXu- zptto+=kf~aif$0>QB2j*Kc}80OGw$j1U|mvlL73<{(6jZlJbNf>OvvTV>~8nkJG2` z^ljzc_M^vY{DBrKp5_5%Q9urS=j56Aza>ts{$mZ+)YC$x?-xIbgsx?Jvsl~V7uU}w zW1{#7vhxICk?&N@nqD>*Jm2^=m;g-{gzsT5geI|5waa8{XXxNMuhFzTiApb(%291& zfM4fv109Qehk3^#w!y!n3;9P%i_MKSDCnl%WYnsMTMCVmel6&f!~hjP^cUrmGO#Pg zqRtT2DxEIh{f_GI1)aJO$l6|=IkS#YGqrsL;O`b1x~6A!V_a%>>cSJ1&)F7pkbyH1 z_zE_`+Yk4=C+gO}$I$g7nmc}HqUoCyYHrz0>TK^#P+KhM`YJ*gAwHv73DvZPZj?CLxcRGSi&_fINu*4cN2DQb()1F4EZNCJB$iXYf$!9>)+@OQpzTk43 zpE9kqk+L5H_xfT1YN)JhS;t)yjl&u}Zhx|m%>bOup_e0J4M3_h^q&z!3J1aJXi`X< zG{l%{F(dYCWyj{EqRmW3J$Op#oR!y_CPU_Cb~3wa zyb46bTo_hLA23;T^Ij1zq}1Vi57SPY2y#fFI5#T(Q)z>RIxw;oQjn z#Ch7<%8!7)(pQwHwiYvAeYA z)P&DP_V-R=ghxV#ef#zvB>4(vb?pEit~MVH&#p#c;Y@ zbX<`b0Zh)@d6+p(gysyzsw}5+r!G={mK{9Izh(lT=r<;VT~I{i?6vdyf>SUVHyhmlLSQF&|JY98yq zZ7(DwW^lu9Py^7!EC=&(*HSAUf}&3i?rXvd0R|`{c0nrXpnXcOH4O!s!rK&^!%&X+ z;WOilvpdv?BOqP0oCrjNZPn9cs_P`*!; z4ovT>Zj=l~5?kFZnN{%59A{lr`0PU9iD0u?g?lT=oH2GCTf*c2mqgU`wC1f;B&44n zk2J|i5C#$=vy;jPgaRp-rhTtQE4~tp2 zDzUI4ew*G;4H{Th!FoRxU#V9DdR<+1sR(H__te`nn-aJQ#?hu6hKYGRWatq*)p7;< z!Vcjn(aZ>^@9$gh?{JfS$7!$NQwUu+XKV0Nysp{-?Y%q56mc_qzxU8u`8Vw@fg+7i zoZrwsJN>45X|u$2DXleTTE~9@h}?rov~lhj9g4R(5V@pDm0vEHPaVa7G>p%5g6A!* zI}`-TgwiRgDao;MfDL7cU>DEs$9pgmvE(&V(c*k!RN9+3;ihs1Z_y#SL9uSJx}Lm1 z7%u21T`aMa{o^4inSprl99T15fv+!tcCx-|%d@V%9vR$NLsY3oy$V%kE8U^xYABcg zeSY4)9fKJ?2A*?a+*hAG_@IGpO5<6*>qHLLIpSPSXsNV~(#s%b?-ZI)uYai|J@6aHAA*N06%tj}BU@-*1T>%7`kfC+Fvufc4^OGYD7_k*FeX2yq?y4=vhgZ_ob_gA_4q?C&W2s$bPG zg6y%TcYm4({N7{(=~Dz$)(6?THc;WvLId)!6wk9~p_akS@?I{yNBjooL*?xI|a#g9j?~@@0`J zz~(I=|9EC?xzIg<&}<`9PBI+qhoHwld2w`*N9sn5-l+Dd~#a&aR&J10ndh z%uAqx7X$g8ma|@ynUkJovRHm+`dFd`f(}`$>)`lMxfN#NnC#EG6 zkpOm1*ScD;_i}P&{FH&Uab_oj!no`c7U^2UoFriU{;SLb-m_G2;3?}tweA+i*LXD8~}~xKh`i> zQ4U(T>>3M5y`Syi_3}pp2Mw+KrJbThp!TlsHYOh$c@hG^83ccR9X-0bNNe4NAHa^z zS$!@meu^R$Y$h8LkTdud>I5eTnB(o);&Nm6lv^SnLDlS8@*6%WI;h0cOQ49b#h*3^HL?smyKVtBVbu8up42Ua zBtr6V#8fY9(FlCu1$#nG`lEN+0%&H{Yp_aDzN*L7ekpP#Jf03dVgycHPEVnTmu&(L zl^}L+X~m{(02xM_w;R>vV^QFEntU5UC%GK&>OuSC2Na;xQ1Ck;lR#ojDZ`0pX!{h{ zz}!y}+m^cfdW7#)(lE$2e_@M>2^5RuaY@icmYef!0up!gSTA7eu~e6&nSo;f;TZ)N zy^e#Mu%VrM@~-TuC_UkU1<0m&nD<2U^6TO_si6^^IEE7JktW$0rqU#SEIHi5>FHw^ z`@4yL)%K$Fw$T9h(O>=)>OD5=M$Pgcc9(u}kWK~Mnq21uD$NN;rfSKQ0yTF3zQ!U%0Q#;~cg+@|FM|=1`PfL~>`#jp+&JnUHPdVbs z)?*(>5DA^j*0R@UxU=`r?(9{)m49OGk(2%)(OFf#V~lN2ge2@;bpV!B4YdG}LiFSR zl}_DBZsZ}H9pO1;k7S5c5`=VRj)rQOdI|S;ocM}2U@{05!F9}_Ftfph-&CWVEexwq zo;!&1jeA#^6`LU?52`YfRU$oXf{mLyT4Ve~Ou~l@llkkcVubR;Jh7FrNozDAT44lR zp4}$4FyGCt;+Hmh06-oBOY#dB*4zChVV$RLXulk)Q`q09%)PwzQlTt$6grs6&8M8s ziJGeTA*=e>vN`x!AAQ9ZO*OS+frnDsmk2s+tx4bzhO~U$eYSl8Yv~tcRTlPc5^gHe zy6kEsM0AAm4!hfelJrb6h|7kqNJSqGmBOSM&1nZn2zm7zCcxs-&8#11##UtPXW!}4 z{Xa?v7MUErjNwUipgCAfBNpw%lw8+g@d4g*MMWM%)cTx24 z2bU*`i$YL}3A>0&i91gaiQZk=5_g8XXyARx|9Mm9@27a4B|%g^?wp%aP4R9t3#DYL zO)XbMJqv87`TlgI-BDoe3QtjNDaUcM@ffDyqd*wnkI8Ej15YG1e16x+(}FjIlD9|T zp-N<9(v{?=?DvZrCcF3)cI2dfPt&gjT1p3u6~>eMTRMqJ-_Y-SNbT8BbH~z9)8$YA z`X0(cWpkLKg}mg-hQjO_b0VS0?m_}-4;Xc}=wBdpe#NSM?SvDhfAQFkUK}DcoUQ+L z`MhCy?v=GfC1yaLn_^izJv?a(uLcuGG4A%5CKL8X_K9!5c5I|ik?j8fdq9N0p!%%! zr7o>#jaIkR?DU;zDXU>|-4>k%tJW1=Q`gtF*NjZJBd{!8O&)1Ec5Pd3B@89qQ42iH z)N8C;u>K3wf90O-0;@1Atnt%~F)46hc-vvl9AL&IT?#C!fhfxgm)Rr3T7tV{UIg6A z?tnp2Ow!=i=Er4ltXY8KWr0Gupi#T_r;8?lLu94lk4zcwdev@Il}Pa7;~B?3X|V)w z1!0QIS&f&wCC_WA(K$5O!hB7?AK_|#3IIOBaX@zDe`&x_p`cc4<^+MR6=YXmlT)#@ zd(c^mYed)jFg!Nj+`>lHPTGLwqdxtdg}$AX6p5%4lMr->X_{VE3AwyewZ{W z8bm6G89uQZ7oky%%A!)|{T4V=WnuG!=-5gFePxp&M1}#`J2mGLj$yAdMUU@*=Le#1i*F)q?@8{;{(l@{VFX}3jYnAUVa``9~fE3SdveHfA3&qAZWsAG3Q{)5QmOne^)u_AV_v;FPP)_eaaDD+6WeyL`Vlf+d?%S z4ip1tMn!pV@b{L2RAssE%EUqS0$dYKb(fkWg;T1|6?4_Vz(iB6I&kHr2CLU-Rlc`^wLfO+fAyS- zG2I;9t#&M2%Z2>%wi!^6huXW#LhG`w)Qe7GV75h*SQZ>{cMwe=u0mR;*_y(Hg=tr? zIUsUXGjEVTo|jX-s3S96F~va@6>p)pYloN)mY=*GwJmn|PAn^5<=q;3=7vbvcHC{^ zcG=#qsD7p5o%UvxB2iwfAvUSy}JVrwdztdrWl7V`Yz`+gW{Ta-mV)mB=NkU zke#S;lEGf<-#bGY;8NacXd^UMmHMqC_&iTPz)UyVT4^_ABhiv*D02taos2$6xUfRj zv`FmEfFU^;m4ebzc*zQ$OGRP(=Vs3EPMGFvXa9g|NANlIV@PPh_sAbWe>t0JYKk$$ z5wd66EZs$=Tv>mLrK?cQZVX<+hgczj8w_qTQ7t719VWlc`3NHHsPx?aPW~<@C~wAFk0Xie>GE(Y;oTl&h_`!^pN_1`l`%)yTHjHdk*|!RNVpJ*(nP2Tv)|uG-^OkXiOy zd{8$^Az?#rJ{d3z*wJ=mdCdSV$B3VW&^dR*zNuMLn63Q!WZ%@ROGK6+b?V1~wh8*+ z*!reTpWnvDqove!9P#cYc?a9c54#&go~C9e`v<~zDyyjewWKkby>r* zvdzdBuafsQpk0W34r45t6g6d2z_#1us3|}DX_#?>tCfwS!yc-qSQ|vD8!=8zvCMHJ z0{FyU1hgk*1zS*m#xy8Tlgjt)JWO7hQ(lhICGY)Y!WQRyau-wVj~K3=mn(RQ{z=ZM3<;IRc2aJ|d|YF# zeba3YUasBBg3mMcYEHLeo2Af@E&CjMTiR`*1L+qJ=-vYVQr~KcA11G|0wx6?&u%`? zSA5Z3u)Nr0pj2iKQr`ZhGwwsBLvoEvt8vha{1K{1*!!i!#f`JL(t+0}ens+*F z4+~Oi-d)RsT?uApfO{sI1s`0@Cpj>$q=^h1G7v0d+!gE&%&gBsKC_>fBR6c4gB-U? z^1}#m7!(&^tE5S${w$BKRP8@8t(#3XUs~u2e-Ekl*%cR~`kJj7J`>lmYS|f8wle3| z2vodT$4V^Z@V6u_qnqPUKom9Ny84_P#-KsrzaftSKW;@JF51mpH~aSnYKAXSPWVJ> zw6;SHQ5!tX*6WES3~gJdNJ&_E1y$WzpNb=Un8xMedy(LIwQ>xz*s(~R8L9=AyKT?YL1q<>}{?; z^F0X~siB~|1z?+3bT8Ri0Z$oBxdC(qf1Hy6r^+2Ag@((>*SdqJ+4=#-x~$PX|ACpw zF%~SCIwn6Efl^Bbqj87U`^Yg7x65OAme8HC(u_0m1QDVmZ2}q-Ky;- z=KvH7N>W!SSL)wB&au=9t0ow=-X|bbfqv8V+kz$4GRS!2la~6Wk1lJtyxjb>e|daZ zMJ(U_<=@eNi%R2z8PHh0a116$dIyS0*wIiC(|er|-AdZg9pkCz6^k*Vcj~>6vtvTZ zIML8q1xH`Tx?9>yM$7f1KX{s}*HF0N3m~-Du#d?x7BJX@R!UPTy@XAUg<(-_-VB~K zfSN?K<0d;nqPd0v6y&Rj*J&Qtf2`C^C3v2?AyH)@rD%-J_0O{qERFqc~RdE;eUOpim=$aM!1LZB0 z$CWKdVoqf^=^){R%2mKwl$X&KbuBg+57%!6!qZ&+K)M~=0lEx5Sjy!Vdy2{V6~&{D z0PRvuu=lnCZEs4$Xk)W^Ru|B+;giG!UE~piN+P{h7r7)`Mbepdf664s2t%fRm%bZX zH~qX$u!@B5fY3i zEM*6Sl66AQuT;#@e>K`tJUO`$wk~}S6~gmmy_(lb_N=fHjeJ++PO_EA;eUdH4hJ;I zlRGO;x?qEQjWlOUP%{;u=QL-O@3kG z#52agHHfc&nW;8_n za71LWLo{elWhs#a!5x5!zc<=yQoKn28On5FV0~@fzRc3g2_=hGzLL}21zRDVu*(LN z>`dq&r<%&RSSS;YTA~KyA3gBR1okp6eOm!sf4#?@h31Yg0#gb|M4wEgHn9W~=t;~j zE?i1lTWqbNYy~Wn)XAvOdPMm->CJh38_DYPryETf&w6*R8%+Zl&#Ie$xN{@pS#$S* zp4&ONv?rR~7ZS}8w7a93oM*zCnFLDCW!CH*>lDJ>P?L=fDZ2-hbXi!XSe-KXD z$$F;e3wh53Evu%LPy>*qfS_d|zz@YCfd;2`lAbk}s~(pK=zjYwvaY0OGCivHvuL^! z!|vg)3r3UmjEt{9nNHTT;?^G$*U5TD?+824?}cft=uNulCG8Ra9d~^XS)#!bEHB|x z3Lif8EA1K6DjHl)`=yxbE-P_Ae`(KJlovo2VB3f%yLZx_#qX&B#H+LMVoUonSuf{R zJ{df!Sf+jNilh>ggkqjgllM$rpIC7_dC%0;v1p30sN|wDlncX4%Q+}xWa;ERQ+-1i z_dG94liu&d40rj-GBw>(Ar})#A_>@i>L>46b@>cQACbvQ&ugK{m6Z48e}JpR$x_Pj zeS8x-0!!~(+1E*ZMj~S=b?=?jXBxUmTum3nBrW?SCPeiQ+9M8pmV!b8nCin_E6u?y z2qiw%EAtsw0Z7iBr)w-sg_6^`zOLd>)@Lh1_4LxjC-$Wdo(#fn0%f11rr09a8R`E>eO?Cd2^SQ!-#x^NhC+Y48cfp zo^`i9tMZ7uApM3-E_efPX9raLw_~5qTpyGgInRg;u!BDbP;wpG?L-^oJBy5p%6p@HXN;lB8Sd$0 z9Oo`@^f5TNmMcp9*zlwy4$$s*Q ztf1X_Xe6_oT~dPNj#oc+At3VN{GxAenIGN_b z8VB;X0L=ldf07w1%#DN(4BLU)g_$c%H!-oqn8C`y9MJde7zi%en52sRGFvY}uv2IO z^NzF=eZ;bWlYGSvgG-TMqI`U$hNER$O$e41_ZoE5&%(TNzl(i@40@G;1{TNtD%B2m z7)F?wWlsoM92rRE06Wi@IK=Ja<>*f)YAqC`PIm^Te?FjA$<7SP?Fmh?vu;Q(5J|Q( zK(MJf+0N)4xh?fRm(&RI!-pTBSozNGiY}cl4?E8{^I?J1@K7SDpvp&fi1ALNR-*RQ zJH$VrIXg6V1*l#Pes0K-YyctOS@HKoF`g#tHD`4?^M>i;E((dOl}^4!uCr#0DBG7j zerT2ae=k~4tZ9sy%s=sx)o=`3dD!b3j^3egrH;V75Ipd6A=#PuV4YE}9r}q1$nIUY zMzXW+x3$8Y?TpH`UCiUh6-&5@Gf zEE#1xV@l7#Jwq5Yw1aBF!M@r1(*N7=9#q zipwYuK2OwZx+;suHoiL|uaWJn8UM*-gi}v7KGfDD+gUe$R7+OG?KUUqZKU=N{3#|) zwzFn@nkozq%Z$5hr=J1-B{5UO%VfB`3JjEJBYSwA-<7CT$r__To_F|mr3JMfouXTW1zT=jgd({O)ouFwiNtbX71Ip12O+ZAXHb}Ru@ zv2Ovcv|JV)?y)K-&Vl4RyNY&L8Y{5$kprYVYc66&TF(BC^~+|XPgC`h)rdgpQ5jT@ z!0YUarn21p;FIJ&Q2&Q57ueg>-xd5ye}lNUts2be#!0T1NOdAzK|f5GRA(9kiN^uC zL$|2z9kHid*d{ZoGTakIklnk^&%>#=^}384gy1Y!e-=zvrZa|kV-)XXI^%sP1&Piw zEx&iNoY5`RuzI&^Hq~u-uw1N$hvh8ZuH8HN9Yb0t&zXin2NpCJ?>!lY(is-gf1EX! z#SKYw7Gu#?UEe`LD36S{3Mj@eskf8(?wQsJCMpkHZ4?ga-E&@bwV zLYgy>{&bvpr!kVvhq*b+8Spblf+di6C3hM*&Mpn@x^t;n3v8?$UdnNnqD-(7NzM#z z^>_`WQGMY9InLs1!3 z>USrX2lk2;=o7y_f!)y9s(L}28CbXBwMcRmq75cqjn1qt+uVk6I(eUMb@`E~J(3E= z-9%1wbJt1=^)U&$&8vo6CsLus&YTYTcqQQmy=&yJB*z(jkG!3MgoOm}M1oV6ZOl%B zwpUDNQg@0ot7pZQd#pzie-t=7Q@Vh1rSH3iHd*#1vgr<2CxT6mv+A-umY%2T<*br7 zD;wO^L&cQi4C(1Ct(6>S0S@Ie*urH<;IYhLSIgj12~w}Lp#q=jiozL&y4zOC#k8(@ zg|gr^hZk0N@CehY#9!z69_M!rQ=O0o^R%XO%r9RprJM|R5f`hEe3p%2y?)*)_a%ms^192yGQSD5-RTAoUm#Zzt*3u?lI`KSNFXz>{v(R`Ri6`br&>?>FPP|FP zwE!YMdWx)3%M>fze}h|vzIU5>;&Uee+8wdYW_KbQxLdM@_R3WxhJg!~BeDzQqUeJT z@#OfnOV>@a(~PCCX0Y z=f#5+7fy4eUpT8kY0iv}9e%aLHrXQWsM4H`OFesJ$BMhWe+VLQWDR~0l%>j3 zhJ{l26#v2H91AL+r^$3?Y)sE;3T!K1eUZ8r&zg`gw$CKdCt0kR(aC*OU*_rMluCq5 zP!);J8hOruw%ws05o0ZkNDOvyR2i2{=Ac%CJY+5Djyt}8-XmK z+hIE)kt~P zwkbKO&OpETSt(!{q2E zA$sjQG70N~mGpJNJg6xV}!$VfzFQ~aS+Jr9R z!nI+YsDQf7btF8ie!bi6Ec!@GC-B{slLS_PT6U}w$;bQ z*Re@Y8tUVHXcO6OmNBuy(v|tl2;AI)%xBH|;Iqo?CD*MF<~lc0pV4^*?@Q&iLmhlX zM+xc|K@jdHI~$OI z)HM6{Wujhl)!{oV8%CbH7*w^o67WJcM&?w(*Upzq`gdT&42l)X-fHqmUMJFpJ6*)0 zskkuQxkC>1>>@0f^uf%^!mFNJCLptm^VlraSKJ*C7VC=e=u#1rH&WJre~rD4MG((lOKrJ)(Cl2pvV*EbrcyM z45YQRAKG#`%MVqjcz2l_&$?Xz2~tohvFTf52_d-4C>U_uxnXPgi?>M6O7b%hv$;9R z&*+>jE&O@A^IX{WK*S=VcZ`fXAgB;6p1i||Smaw)Ke{6Yt=MxmLB)Y0f9|OmfpD8s zMwAr#WLcVWB&35}*MgaV^KrNy8L9 zU4vmwL(FRWSsMs;JBTZJv)g?E28VAT2zNPO7y#DS!^xR!PnTs@A90SiFxZg+t^0K% zr^tYooeJkJ!5PY9r9i8`f0XQoF1WkQB|(BQ;^t&PtL|KO92Q1dp&}9#2oHxcSW6hI zBcQd?6x%B%_cp4jcnAoxs-r6wq->CJ$Hi52KH!!DN)K2$k%KB0n~TxUs`BQW={{!Z zHBVi>OhzE!NV`h@vt~{2^bHqlR|7khM|z;J`+E>K&t;alfZ z3NXuc7tN_TyYFh!e}TX)xScSwdnEx{R2K<^u}bQ5(iuEY)l2*o6TSix@ow6Wg2!u7+(=h*Y#&&LPZfbJ za&)Kp+RloKf9qAn^634p+()u}Rwsm&?^Uto6a6B-S7LCA+U_pPQYt%`bOt@_b!0-T z{(U(~LFRp7THIZ6!|6`(-AII{*N3SEiO@7s!|a?yXe#?6aJ^6RuI_8=aQvb<(lMNs zfa4dxJFoK$^JJgS6Cs7J3?nK_eyCa&Cdmuv9@pKff2@@$k)MXksX@=nj{1h}#u$iX zp_{iav-J`NbHhwF(8~vjVcZ`Ef=XvgGPG{R@A3^aT{_nG%l{1y?j zVaGs#FD#FIg}Ai%Ru=A6#0jL|eaE-X<7{#z+`;*qP_v?<;H|pddl>QdRoJK&&oWR(G~;Bhwo`Lp#FEfr;LeC7_ ze`35NV6v#9oNG(KTqVzzSKSEMEITFXcI|+|2PExe$ z&ZWqvhxfLQ7(8Q1mWC`nYd}fSm}69vG{&Zj$<@6CWv$TFs`eBsayr#I!0#&C*jubM zK7ECq_Z~lIXE;puPv(y1r+Io!SGVP7$JTSlRL#MdeDNW9L#n}I^@ZgG)e21Ze;gD` zpHhFF)Q=ez|Bs}7J@mfC3=ZGG7WwR)5-rP#Ll(pmq570F1e9aEh1rgjXz{!v@{|&- zg&J9wEK-RKNQ_g zhRtoLryx;sqBTRo>|A=AX_fKAx%o&kB+akv&M>WEsF_!!pdMDuPG4QfPM7L-LgSh> zwN5IIf*T<0)Q}1t1+U0Xw_%`YgSzc@BeEju_3F$a%ddAMb5b-F_fGUlTP#m2hGi|5vXABn5oZE35hNO|<&1nVVid*8nMl^9svQJ=8eNjO zfbO+&0q2UncUW^QU!Oa!2R(jIwjL9a+?~Sd%WS=zSc#Dhv}(kNk`@glW}7`}(Tb6x zHXv!ynvtYT&#F^ui;bFX8R#lUvN!~J(W;*(?cH+ZgMjtKA4(jL$kIV9I6E{QG8>W~5rojk%vqWkpVr7cGFTJRHf3b^+&%f6bT7vwD6vh|dGtP! zSBLSDR0SionkJ)-t(15OcJXl=HJO)<;+ve#%zpr_<$n6$P7 z7fFuR{CV>7tsrRIe+zd6M-_E(SQgi zL7I^hOk5jF^Ey~Scc|~EF3Z!D+-N1r8|s@huPV0!Q|BUWm6J`#E2_r?{4`lFQ$j?- zEp(tt6BX&vPyp-iksb}KD6ACe(X#!i?>W+=fi-oQM0zx^f2ev8>CwWe;hrNunxXHh zKk}mibw%DIKUyZ@_td|x13hz_RF3>;JkMSA&X1Oz7w4WMKN`qeBNX}3K;}}3Mt(Fq zET8%#KN<>dEwIRs2J+W}i2P_^V`UkO{Ahqt&1mFD1FWi@&W~oDZN2Bnk7lQeO80Dt zM!7-vZ79})f7bIU00@^{-g4weyCM?5OxH^+?1Wnae0Nc)o+92&aZ{v5159>qp~TfO z{CyQS1=U&xn_R?N9CsxZ?S!duX^=e{?%X41jjeBHcV@IKE4=b&%O4T;qhw*Cp>dk4 ze59+=&zBy+SvR3NF$`7Jjh~ey zoup{xcEurnnxmIf=@eUNK-=Ma%7=#RB&jPG8Ie~(PFplHDEB5V=-6L*duF&N2e`^oXpju88xm_}$?Y+PDp^ZK z)3C#jSO!nBp@k;~dEyn#1O}EXCO)#ED#qr*J)oGS6L;`(V>#G~*yMY`5pfxW>Sm@9 zc1oOwGhDZ~OI<7L?KU~Zy1(fk$;EK3=vaGee+f)2J0;oB!UtRT7m*FE_c>>Q z=Bmqy`-FLA>(zkT+hN*ODLD?fSem|_;yRiYiF0WE}m!WB?eX;G&Bse4^FbSIM`^9yLJwch*NEG zl3szxI)i5ogUoIcO59Z+POwuRnAa8xe=?%=z`Vs~O{S)MDrD_sC_6dPxOs@F?Iu^K zS(-7iFP$g)L6Caj%4${eNY^b%25O@?3%hcn0fEiX$%#hqFuzEXX5FiA|7j0IOj0zW z6PZ^5jUL%In;~jkvc%mA=xQ4gpeCtOSv#LjTY+$i7*(iFJTFrvIne_0Hk*(efAc!Y zIre3;UgzV{jb6);SJ9#)ZuAZlkc+IFHo=N>t4;}>a}dhiq;K@wFAkD z#{1JZXAqXJYiUtJ6`l8pdf6@*--Xo8D_vmO9OSNx^yl@(xVX_n^B`>^^5=>)O z2@tZP1%@5&-ncL=cQHxDGF+|&j?VSGs&CtfETy7~Sb?7=>vd8dX~fhL>^?ZkVr>{< zw%?H?WmImZ$H$wNDLSAA$x_cNaHohisttxb}h1^@xJn+HS(S5@oH}2v}mUYLvLh7qj$Ew zNTbHQ>iRP(-%KlsvFX-{i%azJB|9K zgCu*|UMtFXjFxPB^0_irDvce291ED6$$@^JC)!{eaO^yC3X`%6qXyS^YfMT! zH~D>R?i&W6s630if8uNy?}zBRJ#&yK?v#mCI%|l?*z-JAz`Szc_{q=8t`O9x^f4}(tyWf8Oo0SV1gJx}B zV$76Zl_Aqz6|-@(@RUo128=7xSd{B&z$yc*0Tc3n{NA=FVB=0e&t&7)fR*)*_(QNs znVj#4-|h}0z;Ir-a6!m$)1=2e#ej`@4ahBmd}9D(z-Ec}>m7?Qa@9#b zY$2?RD4agoe=^-}k66l2E4UpbbNOGfI<2w#Era^9MS?&k(#~wZyu)!pse{!tuyE)w zu;B=E6$L zc5jP$f9EyzVs49@A-809)%ddOhQ*qE20r~hx&6*!PPk5X_|qrE zmjj~40dcoyP%KMlrW&!#y3dEF!TvZOI3E7`e?Qy#(Bgckmgm>;z?jEa1&mEGR{lcu z(NIbp4JnR>;fbhTScKMXe}aT4q=dOat)#;ym#G$#7OaImM;6{%Iplr$BJcNq$@>@b zepucUMuMA%M|Xs)6oU`zc8Kos$;`Pg=cWFEJBj5C0)+hTURD<_xIV*fZLx6Jt@FQx zfA_y%M2K+qfNN(!R0QUdaqEn}4rNak8tt$mX^_O4|{dwKn(Lo=qzQ71Wp`d z$$9!Kt4qE;1S<(ed7Z>}Hc)hzg|Y3|ctf(-#W?#wDlsgIUzjc{bG&q;Bi<)IPjPJR zQ@P@YCVK9-Z2AeGJf8SA+tn2%zT6VO5N4;^7kn8AD^1jt<8)9I8JBf9Zyt z0d(+=;_)8_4BA$x$jpqFY8~$%{29NmQ+5(c%Gt$6F(K}Td;^w`c|JZ!PRQ3-ySCAx zcc^G5st@j6JgfKw->9c>p4rqW8N#_n)?JT@IyK1k5EHiD`55WWlnaSHfZrL*fL7x?>KO%1E96Jd*A`nek|O-OZj+l(8m1ebVBxz`Ky=+IJuz+LfC3QZ{skf8@_tZ7P30jXpqdoBH1udO~K!9YW?#woDF#0h+BrKICCS z?&TchWS~cruOCH43gAK=+(dsjRpDo);<+2(!CcVEfh)sg(=7;i_?-IP@&{auRG#J} zD^DK@Jvd1#S4{wlMjzz7lj`GF-0g+P3peW8jYyJ8zNrUc!>~2lf4Z^Ouo)OUEjE>9 z7g2I`riIGNU`OZ_jTI5BGt^bFg`NiY&!nxQ?_qB#@0QC96IftO$jBl�@bC8)^CT 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 y4*r+E<$oIZuLlC>C+-~J!$=V(*_ delta 9296 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 diff --git a/lib/themes/theme_service.dart b/lib/themes/theme_service.dart index 1915239a5..542c6375e 100644 --- a/lib/themes/theme_service.dart +++ b/lib/themes/theme_service.dart @@ -31,9 +31,7 @@ final pThemeService = Provider((ref) { }); class ThemeService { - // dumb quick conditional based on name. Should really be done better - static const _currentDefaultThemeVersion = - AppConfig.appName == "Campfire" ? 17 : 16; + static const _currentDefaultThemeVersion = 17; ThemeService._(); static ThemeService? _instance; static ThemeService get instance => _instance ??= ThemeService._(); @@ -61,9 +59,7 @@ class ThemeService { final jsonString = utf8.decode(themeJsonFiles.first.content as List); final json = jsonDecode(jsonString) as Map; - final theme = StackTheme.fromJson( - json: Map.from(json), - ); + final theme = StackTheme.fromJson(json: Map.from(json)); try { theme.assets; @@ -96,11 +92,12 @@ class ThemeService { Future remove({required String themeId}) async { final themesDir = StackFileSystem.themesDir!; - final isarId = await db.isar.stackThemes - .where() - .themeIdEqualTo(themeId) - .idProperty() - .findFirst(); + final isarId = + await db.isar.stackThemes + .where() + .themeIdEqualTo(themeId) + .idProperty() + .findFirst(); if (isarId != null) { await db.isar.writeTxn(() async { await db.isar.stackThemes.delete(isarId); @@ -184,22 +181,27 @@ class ThemeService { try { final response = await client.get( url: Uri.parse("$baseServerUrl/themes"), - proxyInfo: Prefs.instance.useTor - ? TorService.sharedInstance.getProxyInfo() - : null, + proxyInfo: + Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); final jsonList = jsonDecode(response.body) as List; - final result = List>.from(jsonList) - .map((e) => StackThemeMetaData.fromMap(e)) - .where((e) => e.id != "light" && e.id != "dark") - .toList(); + final result = + List>.from(jsonList) + .map((e) => StackThemeMetaData.fromMap(e)) + .where((e) => e.id != "light" && e.id != "dark") + .toList(); return result; } catch (e, s) { - Logging.instance - .w("Failed to fetch themes list: ", error: e, stackTrace: s); + Logging.instance.w( + "Failed to fetch themes list: ", + error: e, + stackTrace: s, + ); rethrow; } } @@ -210,9 +212,10 @@ class ThemeService { try { final response = await client.get( url: Uri.parse("$baseServerUrl/theme/${themeMetaData.id}"), - proxyInfo: Prefs.instance.useTor - ? TorService.sharedInstance.getProxyInfo() - : null, + proxyInfo: + Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); final bytes = Uint8List.fromList(response.bodyBytes); @@ -228,8 +231,11 @@ class ThemeService { ); } } catch (e, s) { - Logging.instance - .w("Failed to fetch themes list: ", error: e, stackTrace: s); + Logging.instance.w( + "Failed to fetch themes list: ", + error: e, + stackTrace: s, + ); rethrow; } } @@ -270,9 +276,10 @@ class StackThemeMetaData { ); } catch (e, s) { Logging.instance.f( - "Failed to create instance of StackThemeMetaData using $map", - error: e, - stackTrace: s); + "Failed to create instance of StackThemeMetaData using $map", + error: e, + stackTrace: s, + ); rethrow; } } From b3e02b64de18e6a449baa34c1af1e3ec1adca924 Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 17 Mar 2025 17:16:05 -0600 Subject: [PATCH 35/50] use standard app dir --- lib/utilities/stack_file_system.dart | 23 +++++++++++++++++-- .../wallet/intermediate/lib_xelis_wallet.dart | 9 ++++---- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/lib/utilities/stack_file_system.dart b/lib/utilities/stack_file_system.dart index 67b992bbc..217b33eeb 100644 --- a/lib/utilities/stack_file_system.dart +++ b/lib/utilities/stack_file_system.dart @@ -39,8 +39,9 @@ abstract class StackFileSystem { // todo: can merge and do same as regular linux home dir? if (Util.isArmLinux) { appDirectory = await getApplicationDocumentsDirectory(); - appDirectory = - Directory("${appDirectory.path}/.${AppConfig.appDefaultDataDirName}"); + appDirectory = Directory( + "${appDirectory.path}/.${AppConfig.appDefaultDataDirName}", + ); } else if (Platform.isLinux) { if (_overrideDesktopDirPath != null) { appDirectory = Directory(_overrideDesktopDirPath!); @@ -148,6 +149,24 @@ abstract class StackFileSystem { } } + static Future applicationXelisDirectory() async { + final root = await applicationRootDirectory(); + final dir = Directory("${root.path}/xelis"); + if (!dir.existsSync()) { + await dir.create(); + } + return dir; + } + + static Future applicationXelisTableDirectory() async { + final xelis = await applicationXelisDirectory(); + final dir = Directory("${xelis.path}/table"); + if (!dir.existsSync()) { + await dir.create(); + } + return dir; + } + static Future initThemesDir() async { final root = await applicationRootDirectory(); diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 626b83c94..063c61362 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -4,12 +4,12 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:isar/isar.dart'; import 'package:mutex/mutex.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk; import 'package:xelis_flutter/src/api/network.dart' as x_network; import 'package:xelis_flutter/src/api/wallet.dart' as x_wallet; import '../../../models/isar/models/blockchain_data/address.dart'; +import '../../../utilities/stack_file_system.dart'; import '../../crypto_currency/crypto_currency.dart'; import '../../crypto_currency/intermediate/electrum_currency.dart'; import '../wallet.dart'; @@ -174,7 +174,6 @@ abstract class LibXelisWallet final syncMutex = Mutex(); Timer? timer; - String? tablePath; StreamSubscription? _eventSubscription; @@ -182,7 +181,7 @@ abstract class LibXelisWallet if (kIsWeb) { return ""; } else { - final appDir = await getApplicationSupportDirectory(); + final appDir = await StackFileSystem.applicationXelisTableDirectory(); return "${appDir.path}/"; } } @@ -326,9 +325,9 @@ abstract class LibXelisWallet wasNull = true; final tablePath = await getPrecomputedTablesPath(); final tableState = await getTableState(); - final appDir = await getApplicationDocumentsDirectory(); + final xelisDir = await StackFileSystem.applicationXelisDirectory(); final String name = walletId; - final String directory = appDir.path; + final String directory = xelisDir.path; final password = await secureStorageInterface.read( key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), ); From 5adfee831ec008d4e071ea5043c7502e29e7bfc7 Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 17 Mar 2025 17:19:07 -0600 Subject: [PATCH 36/50] Use logger --- .../wallet/intermediate/lib_xelis_wallet.dart | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 063c61362..5146c6aed 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -9,6 +9,7 @@ import 'package:xelis_flutter/src/api/network.dart' as x_network; import 'package:xelis_flutter/src/api/wallet.dart' as x_wallet; import '../../../models/isar/models/blockchain_data/address.dart'; +import '../../../utilities/logger.dart'; import '../../../utilities/stack_file_system.dart'; import '../../crypto_currency/crypto_currency.dart'; import '../../crypto_currency/intermediate/electrum_currency.dart'; @@ -344,7 +345,7 @@ abstract class LibXelisWallet libXelisWallet = await syncMutex.protect(() async { if (needsCreation == 'true') { - debugPrint("Xelis: creating new wallet"); + Logging.instance.i("Xelis: creating new wallet"); final wallet = await x_wallet.createXelisWallet( name: name, directory: directory, @@ -371,7 +372,7 @@ abstract class LibXelisWallet invalidSeedLengthCheck(seedLength); - debugPrint("Xelis: recovering wallet"); + Logging.instance.i("Xelis: recovering wallet"); final wallet = await x_wallet.createXelisWallet( name: name, directory: directory, @@ -393,7 +394,7 @@ abstract class LibXelisWallet return wallet; } else { - debugPrint("Xelis: opening existing wallet"); + Logging.instance.i("Xelis: opening existing wallet"); return await x_wallet.openXelisWallet( name: name, directory: directory, @@ -413,9 +414,9 @@ abstract class LibXelisWallet } }); - debugPrint("Checking for upgradability"); + Logging.instance.i("Xelis: Checking for upgradability"); if (await isTableUpgradeAvailable()) { - debugPrint("Generating large tables in background"); + Logging.instance.i("Xelis: Generating large tables in background"); unawaited(updateTablesToDesiredSize()); } } @@ -533,7 +534,7 @@ extension XelisTableManagement on LibXelisWallet { ), ); - debugPrint("Table upgrade done"); + Logging.instance.i("Xelis: Table upgrade done"); LibXelisWallet._tableGenerationCompleter!.complete(); } catch (e) { // Logging.instance.log( From ce5d9d43e11cf8e0c985374a63c60eb923ac186f Mon Sep 17 00:00:00 2001 From: Julian Date: Tue, 18 Mar 2025 09:04:50 -0600 Subject: [PATCH 37/50] use Platform.pathSeparator --- lib/utilities/stack_file_system.dart | 4 ++-- lib/wallets/wallet/intermediate/lib_xelis_wallet.dart | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/utilities/stack_file_system.dart b/lib/utilities/stack_file_system.dart index 217b33eeb..795ea9720 100644 --- a/lib/utilities/stack_file_system.dart +++ b/lib/utilities/stack_file_system.dart @@ -151,7 +151,7 @@ abstract class StackFileSystem { static Future applicationXelisDirectory() async { final root = await applicationRootDirectory(); - final dir = Directory("${root.path}/xelis"); + final dir = Directory("${root.path}${Platform.pathSeparator}xelis"); if (!dir.existsSync()) { await dir.create(); } @@ -160,7 +160,7 @@ abstract class StackFileSystem { static Future applicationXelisTableDirectory() async { final xelis = await applicationXelisDirectory(); - final dir = Directory("${xelis.path}/table"); + final dir = Directory("${xelis.path}${Platform.pathSeparator}table"); if (!dir.existsSync()) { await dir.create(); } diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 5146c6aed..8e5fbb3c0 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:isar/isar.dart'; @@ -183,7 +184,7 @@ abstract class LibXelisWallet return ""; } else { final appDir = await StackFileSystem.applicationXelisTableDirectory(); - return "${appDir.path}/"; + return "${appDir.path}${Platform.pathSeparator}"; } } From 6361d9f04834e206f52b471fc124f98a7ca4be9e Mon Sep 17 00:00:00 2001 From: Julian Date: Tue, 18 Mar 2025 09:05:11 -0600 Subject: [PATCH 38/50] WIP: wallet exists check --- lib/wallets/wallet/intermediate/lib_xelis_wallet.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 8e5fbb3c0..92178d93e 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -319,6 +319,15 @@ abstract class LibXelisWallet ), ]; + static Future checkWalletExists(String walletId) async { + final xelisDir = await StackFileSystem.applicationXelisDirectory(); + final walletDir = Directory( + "${xelisDir.path}${Platform.pathSeparator}$walletId", + ); + // TODO: should we check for certain files within the dir? + return await walletDir.exists(); + } + @override Future open() async { bool wasNull = false; From 2298a12afb8de7f4f9a8920a26bfb0edf88c98f0 Mon Sep 17 00:00:00 2001 From: Julian Date: Tue, 18 Mar 2025 14:48:22 -0600 Subject: [PATCH 39/50] update themes --- .../default_themes/stack_duo/dark.zip | Bin 1006992 -> 1157580 bytes .../default_themes/stack_duo/light.zip | Bin 954883 -> 1103976 bytes .../default_themes/stack_wallet/dark.zip | Bin 1157605 -> 1157580 bytes .../default_themes/stack_wallet/light.zip | Bin 1103991 -> 1103976 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/asset_sources/default_themes/stack_duo/dark.zip b/asset_sources/default_themes/stack_duo/dark.zip index 1e5f6136e3bcdb12c953ed144a203d6ac35d9fe0..8b31f4278dad0f955b95ffc1f518f76b28ec9643 100644 GIT binary patch delta 158844 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

!Bjq3OPjp22drzY785OXn z<>wt0goaT!cM#9z(L>sh8dkCKd>yTSbJ_OVeMZN?2XrH#`#XET{Y#Sd^9n?x-cYoI zlewN9SA=OTnhiMpqF0oGjaCHF!tRig02bp7FmYvGU#4eGHqlIU`8-cevGLpGRA)_5 z9G74d`wVZHg8Z-( z;Js14K$Wi@_qD}?xY+*YV*CEdqoU)dx=+$|rm^QZnJ-Tl9^kFOLX*`<5n12LiF)&u z6wQ`e>p}s~8uy8jLWzJSeOgqX-sY$Ds0p2&@w&o+z>$QvjTJzCSBS*T{Lq;$`8PHI zsb9)}sx-mXA&ZzGqak8Jd24<@ra+?~xHO#A{8oT5iM96=m+yj}&rVv?IF^J-l4^Q0 zh_L97;cRBD3)V+>vw)96^zO5wD+V#N94r;Y^WRgUGOjH{-Q9xe#>A2%#etLk8G4`H z!lNaWu)idL1aqNx5Q;=l4VVDI^UcxPp5&p)2i39b*1u$dx+)nkLTsk>{PdCaGCR2@rI$%%b|nvIC-=o z5yg2nD}qP%E1&KDu~iT4-)p5-qvLkLgbj&v6?6Kxbb7l7ZRk!271~hZ^^&< zX$RvH7KLHx*rQ}BBeuKe7c&I_q1Usgt8d-1y#U_Snx|FlPi z$j>bm`62rup&pY?47W+a`C40boH~vXwLzG!s^&3s==04QyaPKyMvT<7it08vR0>mL z)y}%~@%TzraeE*BY(8DIKBquA|Ni}zjVDEqZ41(!ZA#CbGq5%r`@-#g@RqY#Z*fKv zG0!7J#g|ezkFVl&37!TV=pf}ZS&_0IW4Z0k3KdOd#2fqc%!*B`b1(2410$Eg{DO&K zg}zvc@;n$>MgLL5?R{HcoWuo1Gx8_YJaA)@hb#6K^{sL-sy{Rp`o#@eZ@kFKtA~G4_?&L65^%ccO7E4^CxCX$eFyzu)Qsr#^uc^`|6w-a5gpd%jrcGWk%gk zoxOOoA!#t6W9_lY%MQB6^%ANCOW)0%eVQUIsJ9E@<9TIRY0Hf%b(&XiTnQ5<9hXk( zwabNGa97Xl)E=D2K+DAzn-ZdQ8!n%D=pVlSQN#Hc%hd2g*5` z;W#ZM7y;1$RBQ+Unc1CY7o?NPs)f@HR6kK;3sy-Au?7_>QH-2r)jNIK)fMXce$2lz z|LNAI%aw(3!MkF56Ym`xAMtPE>yS(m8jlecaab|n9wvu<>-}MNt|6T?%hCI#*44%2 zUqSDaQ2ccLxB1D!*BcKQi>)`=Gw8)p0t-S0M9!;AD`+3!hd>|7x1ef4b5ehFg+R1t z<36F)iQ0F*U9IRgjX1(H3W`ja2>RKm=?b*O@-R2Pjn>!ZI~$(d#!8&Goj2|9Qyg(C zCr$B9iZt32Mr_#crIOurSR=pCx6b{C2L+#qwrB&q28Z^0jVgcrDaLOY!%dr;eU^RT zM*fdxdTs$EA85Y63>>pj*-*g82(ZyVIyKmY&$&A4tac) zZ=8V3*1$j7`gxYrE9K>Sw2>}q5QqDHk{$UyQ|T#^$ldmmeV{(jC2h@Zn~k(O^c8Z@ zqBges?(@Kc&>WZ4znE>@wLZs(5oM}>*Tr;jhg}X}rs@Y$Z_DT8BO^R+oz}Ws-cw{3 zo$FO|wD~Fu4b^9OG-k*=hIkt7>Z~LT)PI>yj1xr*pfOyE2!{D6kWOWHdz>L!UU^G) z+hF1l-t6tpLyo{Kc%Es2_v;%lKGE@! zcK8BHEJ~h836`iL(cmQMJQz$`iROaG?5FjgAhg5YmMN{1kVOdi**~F8ne#XL#sfPS z`i`8kB_=S;jW`mo37aY&s!NW z8E_$$r)&21rkU`FS*68?H;LQUPqJMEl_!dRXx=~QTr|)?XAh5`viC0xjUi>;iDT5E z$K1>0uIMSfBWS9Ak0tDS!lFAjg%^R%e_Q<)?Uzr3!%_ z$B_mF8{7&unYwp?T?Qk!MJ<7{LgUMi8-*K24Z2*B)SwrkwFDSx=KcIkGiGLDt9P4E z84sirRwN4_Yalh!4QRY*EuY*6MK&Mb^IJ|9J~lJmWKQNJBwNWz2`@5qD-><!Vxe}l+W&E9Z-Xdc~xi+9bgfujW4US+c_T}rNZnGl_J#$%NiK=+G0q{jca zRnv0k-y9~Y=_1Pwhp{mOa8+Gf?0Xi$VC{0>#CG8{v>K_rZ^s=5Ih%0NIsB9TcNE?| zklYrcu;)Ed^}2pZX15@-S@9XzA!=%hWMFFA&LOYrzP&?VC~=z^$%zARW-&$2>!jG7 zUQZ~1slkSlOCf6w3E~gJ^xz$$)~0F-i@VxzC4;77!^KPuV5vL6Gv6hbHWmH+@Ahzq zLyp=eR4(w&ewn`?5Wyo`5($wPU~|j#Z$+yM3`yD0)dF6-?myWg+q>oFWQ}12N5y>0 zXP*^K2R4~_*YYs)c#{^xveiN6LMQ9D~S>6mb^7~z{z|7kE*sT zRjw~zmgB$d3;Gt_q0VhSjmwkC*6Ck#5#BO`n}*N#dZTN%=b+zDz}L4!Ze??6OBcV1 zGp6Dx$M$m>uE=iHwmij+VANK3{e7q9%cHA1(0De3#Gez1k4z`N)c$&QQFwZ~&|FNq zHlm&Z18Jh)JSF&-@U>!4=I_maGXcfa@>8q^%A$QDfqCor>Rm_D^fRlEA7Vq0c1&HV z_p#mCN<>f90%-<^EfV1M3@YhHeX&FBYBkq%>kWEK~+QKeB6_xDfEsG7Uco408o5q^lqr ztrzy3LAKwurbSrnVxFaCcOIkA94^0tLD9nJ$4X6~-xU$V^}YYcLKjbLEX80c=Zh6w znm7WhNS@|?n^>!HvRrTphOp607NF`pOjFgI&Nb=NG5IC2?<1)}3)UlFzFG5S@uNAJ zL55X$tAySk<3B4_BhMA$3F&X@Z=cTCw?I8Fc8dv7^4f{s#Wwl}tvR@jKDhXkeG5zP z9n|CPC;Vy>f9wc8PM^#BAGtqD##<$?ben%hW;=;QJcjoS;h#;Q%Zvsifi_7Jn0GFr zF59Vhn6=oJdxUhZrA9U@G$M1FjQHh?qt$-L3k_dhy+W1Xk}o(xNUebfW34YtHs`6} zuGj(^5-|+rG27ec-{^kqRP6oPUOq5+(u1ry#edBxJU5-ubZnUTumGJ1TJG)EZ7(zL zYkAt??AfT=$?7eV8X39`0J2+$ZXL1)#44&gf7f@_H7nKnVPY&pexj;v(xuoczNV^o zL{7A8bGgw|X6lhrOk!-HN-#=P_S!qc27eMXDItEhgj?`4oUv8}|ILQLs*kmn3sw}Y zoEnPhxC-f0NjNcu%({p7$=*qyquZ63!;+f%9}$~xbV{l!RY(C4V{PvrI@n+e?=Jl zKa$QeD6VCT!a#6$_uwAf-QC@t;O-2;o#4RTnL(|@#Bl{{ZHQ~>nx?b1XmAiQZvWxlixawjEuW~9KI}My&(LB5im3mvMk9l z^ZL-msV823U*^)^^hg%aseFF=rtklj<^rUe=F}T(2zk)2(F4!|a5g_`!-CX_S0+Sk z8f{naO2$VOL$+LIZ+4Fa?6PAGtHRTw%ZJ-3*2RL_$C;$CqJd1_XWsM_?Nb@KmWUIV zhGbWLokjsqKmPf(2#Cm-xsdjhkI6SZF$@8kB;ZFpn>f}*_TT*a=&md zq!s_r)Kh7^iU;^oyL|7X6nM|86DhE}>{}M3DOg+Yvu}+iRK-b|4>NFERSe;h^j?WY z4G~AERv0PC?e_c~Eg_LLM*~ycesUg^DMo0uI#@c4!o}P~O;W{t5`ej>JHM)qeIAd|#99!5_`?*KN-J>7_5q!(_yvxLr>S_BkM zubhObcd|Aa;*I*HcfB?a)0U;L*9Y>4gTv!RY=;V9m=nk2Z)!LdC`sb0M_r96Zj>1m zS+nW+%FG5SGtHDi)FWG*}uRu&lYWF-c6r5Elo*+R(>>p23yG*5Sa%)9rnDlU-T&#}n~RM;aqAf**FfBg&Iu5~Xu4X@PtFA|CT`{T1{x!C0-9?AD~ zhzdZar{vt!O4kf;U_gYqC~(Xe=&Lexh6E6UP)1gXbMi`#bg#}8D>uVf zlEjy_Q_FCbZ94s$`0#K2pZ~xt(qh!_21h}X?2du>Q*|~gIZGIe#L6V?D%oQ6?Fl{h zkU7lOmPEBl;jzI{_dhyV??Bc^5I%Tk91!V9&l*C zY;}pb<8(%8wep2iJm#;c8xe32&%yiZ6o;mo(M zf+=N|kqhJMg-OvL@XX>KtRluozX57(l!<+1Iscd&V`SK77EUv*zRpjuQ{~OWX&B!> z?&yzs2prutocGDWm5Zun;9=iK;~iW0G=EcHLXi%7c{-m@uw+Shvm~Yq_=jHK4;7qH+&mZUX4ZkUiPwN3J&n3j_?R!s~}&J)P;^k#yp-;^xzhB-?d{ z`?dyu2bTm5E`Rcc#owV|`>oGQo6#XIoIkyQ`P3RRKVISW3Gr}Wj^r*Jp$5BtkxC84 znU<~YQR-vT4Rys$WUiHIDL@-kC{;5{*k>yeVwAnkbujz;R{GNVg8FY*l?Q3#imFEb z{dugnur_o>UJ{)mJD)sisHFo(c@14~&b*ZP4;~aEI|zJ>DeetZgYtod?%GzP;MxMQ z0JqR=ka>C2{sg(qdp{+~ z{pFBN#7Sqy0aww;P!LLutfG3?g9Ya@7-9G;2wu7xUvQKEW zrj5Z2=k74%32*-$q#e$I>U7+GwI0b?oE~cdnJJteJWjrNZ#S2UqzXvH(y#nESu^?N zLuj3f-_8nl9}=R0cqw#k|4P-UGg+)_ZV5|RU!zA6uy&Z8$q)x zKA;7ZrB+)kWHf?`0n)P6`R!j~5shsXDd9gR$BxS(n)HVs5M-7jO{ENoLDYe8ilBVw zSZ}>v>_XACBX6Rk)(5=+>_u$=bY8Sn`YGlFLy_azTbPEf($2d;mVN+iuW3gQH`4u8 z+B=Y+(d~`a4=!Z1UsC}Lsi0)*mGoeMpC4c-W#@4Tyk@~q_$RRz057;UP|e$Trnl@! zt9`~np6)b9Bdg_ur>oXoA;UGyU&mZ)JEHBV%49hVsq7yO|Mucr#WLmR@V9vi$bWCm zWXDQUxSej#Td7v(hh$-l=PeD;09?jO6R3P;#SQKLQ=Xy5-hA#ljs5C1j?hjRWCW-o zJo0^9;2;Xy;~IL4=w;FcWw2L~41#N5&Ubc_zts~np1mx+Wwv2K$t8Q|^98L=pwS@Q zi|sX?Uh-!s6}{eAq^-Tn*;09kw2|w+%zLQlGm%w&GqT%*61Oy#30WP=0<}FSi2@^c zrohed24%c6!XCXu{Ps#0M`cIgS5l;l;QiTN)~N0!@fz+XPP8*`)Z{^#Gfrv?JpLmgc?4U{ z>F%)Hwlq*x_piT6(<;=0%)N41(n#vC+EqYRqbnfb!@|e9q*c9@{XL?D6M!Ot;!#59 zN4J*kRHF{%s-EpvhHHux62r}H&55b5FqRL78>v9M9u@T!@x@g*V5KEpem!Wq=O4lz znuG%4{7*DG-)HuFG6@qnQMOG=9tk8vLt-|CfG;cGXeQ!Nd9TWf&?vqyRU|X_&q{=e z7OHlHqGb1Q5Ii>GtCNmTvjAcg#}`bP>TTlCXhYfB=-$lo5_W^A{7p1t20u(a@@FTH zZOg{4;zPq7lM#PLy^3w3jX!=g$5l6w4?j-JzT3`TRcdjSKZ?0-YP{Y6RIZHT!3_nBM~&P&i3P3`s|1b{Ja4)@s%RO_#)gu0(I{AT=s9b2 zlk}m7*B^}osXUz7M$Ti9y-Jqt*wQ)o*F=EOUKmJOnZt;AWwKdiYyD*{Z8Tm^M4J$@ z?jF6|{2`tc1G6E4H-P*}`IhP;(Bl^f+;vRH3QZj|;l{zEN;E0P{cBM^$0lebUB!~6 z$gWbdCnt_LFuHZpkJjZe(+s}J9~(tdDGGD*@96OZ#J%9z3h-Le$X z;EL2oFBP80nm>uhl$1{mcRHw?X-^t(!#>e5m`I)6#ZTCE3lIX6JXUx0tG2iVvg>hE zcr`^5C0*KXVCEy~@g3QIjD74UKzcXvjDSxjE!_bY?VKI2SiuP~`I4gvhZjsr*h{G4 z+HSh(0?r%KN zVnpg=&T|(4yD!^JCM}#f+{&-(ryczslEcfFxAtI@%pO`;3tO9MS@wBaCr&Q3R6EzCuC_EA(wBvJqO;4nApKza_c#6TP$9k zhYw{ET-!AGatLU3lWr(K8ZPucx{&7!Ck;%uGZuODX2W&d5#NCgt^W+zF-Lz-#@_p% z{T&17zoLxkzmp{MFhD$i!`r#jw7vt9V1U~yDy7LYqZy~HsiN+YD|VV{#4LtyFosP> z@$el;pHHrcbE#wf4xg=YU7jtQnRx5=KG;%@ixAzuNMQfrv&}%u#YV2Pc=5#q>_UwO zR$>1S5zKa=#kwQu$n{%6t`gIWH11+RN6QA_mR%DyT4nKDaA7e zM7rc(=`_cjox@cma?nA`)MSVKcEf{KO>!<*jmrvL@->u6&&M3bzklMf+TykixEjm> zq*N5~&+>?Ny$Lc9uWy<}(R~Au03EK2>n0jf`ESC@!Pw3`_|!DoSz$L7u)j??*f@jg zt4}K&Ne*u6-mPZ$CzC!E8)mE6vLqD+juj z_kQP++UZd^Vg8p* z9)(sw#WfYKil+u;J0_GVmQ@*_4A>Q*7nU87=-bG*q%kEMq($9cSMi5CNC5q{;EQwi zMNI1V+1{p-U`dR#1z1y4Cr7-p={WwbEbkh>$gVeTBh&;OVbdV={(u^^{+ca0OtH@U zd3Q(oIuBjjJ+z4w5Zw5cTp>ya@W!fd{=2AN)k__qlCJ7+&u^mQ&@{Z9$LcMYw!H7} zyD>k?FhDc#p&hy=EXbRjgv#}w7Gu)ipm~bi+}oWD#J;Lo6u^%&CElbJH{)@#rFbI9 zH21*0TV7;o20a6g2Ld#hed8iHWNE>h4i#ZX1NT-=RTk?-mv=Euy@1lb@$IZ{!07b* z{LfwRa>=kv*I{yVp>~624xFmk%hALq_3BCVE0`=Ug?{(bop~Q*sQ;|;!Sy_7CqX3` z;-)>i;5k`Y7lqPzWFHeJ;PI2wrmpCZ#Uq;cq-h|q*o&^H9zP@3*I4b@Bv;PzM-E5a zu%NJH29!aMDEFF=kt62TFjFMg=Ugxi_;!acMi~g?@eBrTJX% zu))SHMtUId#=Lr(y2vp0w=RSFId$z@tF{wEj-{{*aVy3PjJS%tiV%mMu^_KIq zMITTC$O&Q(cres6KmA!1Tz?MIk(fy=`cK>(xBcOF z$9Qi2i+!w3F{J(z^o2afvWn`irq2mwM)C8d!uooZ+VqN0Hs@$Qb9MlS+nHJHIDzfV zr-y$tr>zd>I~@P+y5}77v_<#x{W53jwdS~WchWOTZ0s&A=;^kxw%`59S3$l}33yp* zRiD!v0XpMl?OZ8Xo3)z?skms@wJYYIx$3OU$(YD`}5zw$?JizalM z#@h{Wy3@wc2GEE5gdcc9ttU);!<9*HX%;}qQO~`<9gdx+bo&|(w?U?uP%c$7{MF|A z4%iN3Hg3g^at(v(TxB7z6EbLkNoBa>zHwqpht1~AN#}#4l!J1yQJMXr9_D*W5`DMv zqkzocup!0LH}g0#*D_P#$%P$DAOyBaLFxDEHk5{PV10>#;hs{8U`>=0l*dd+;Y(eX zCzhZRl&LNzoyu;>^vN{9^{)|I1{QU)r4dIph4a3eFnx$2wt0JvodKLnO~lE;0{<%a zukdgB{DK6w`Wv<56dWrT~D71)kc~TxNArSL}HWEHpwR8ky*rZH3Oc?q2pvQ6@34!4sOZS|XY1MpfZ-yd-#&=rI02I;(4qv9 zJKOcV@ER0>i3ruU7-B5Ca?UPRE&oEmLl=P_y|nmvc*al`5;uo(@9V41S=mQ#vwA9{RhFIG_rfZwsp_o;!EoGWDhlG!WPf8e5p$)2SS&kOXaKW{#IM zC-cES@;Qt#cFPG5xwmB1YA{ za(|>4e(OP;B!vNI7#3TpmhTvP<_$t$nA=BjW9^5>&5cx3$5fv+w^{V_$#{9w`zO*i zj3e%9UWb}3oVW2aMhy+0H}9#O&*Y$W*$lkn>|2wBz<|1sXj<8>Lv zx%kpgWC2tz+WgU!Mun-OsUm_(3?Leky>huxv-fgD8VQJZ~1JuIQ))wpzr$0sR^b+5R&^gC0{mIZjrpx&OUdJDP@e+AvS1Fx(H(K*Kq z!90JQQ}m~|RSw5B!8ajXaI=#RA|_1i4E=jZ(dHA$0<3d^mA#B%FS#|0pEIGQGBIh1 zr#hy@w2qq|C{RutiQG(NxSmGERY=QT^=}^9KfCuXRpns5wAu>lYx*H2l@@oiIGPZ< z*fO9+!tDWq{D3e=HcNAHb8FY9qunjUu7gaXo)ehK#L4vnbv0L_qeI4tR$(32S{ z#7uS4zYCjw{Q|M%+T;?qXk)zaSFTZh3_!KgiI5B(bQcPnv9X0*5BDS=ld7?1bB6iO@q2X}*U1 z5Hft7%}f_<5Od|RPm2ut4ckj5Q_nKbWg@jp`?l|*TTR%}+K}lUVNI4+0~~{GgdYT4 zFhXL9Z(#GeWoq0rJoPTo{jnT16+;t+i8WP;qA0qipu&;#cfrP-jA$;#<*jb)^3T*; z3tSE-!|dp*7th!A@8&WvROaq4(kEO&Vrku0CuOE;Rs~C%hJpB1l%fYV-VBz?Q$sic zkON#k0Imi|KAwPA%5#Kf+C!!pom&9Mv#%b>S5r#yZ?svfLF$B#U)b1<82<*T%RJLM z%~YH1-10y@{KVk8# z+hdeePIln?j%Ayo$BU~=?@I{DqgXCY{`njs(~M^y97&rM*Ag17d-?m4T;Tz*a;GrC zbUQc*>TKC7YjJTg+dCM6hJjURD|?REw8w+2Re1CP6yQd>4~>qIp;D>ZzZkGp6`~S9 zocGHrv|lakx}xPLTOedcj4iOWNG+&CkTm}OD4fY&2btcZ*>lGkVx>@0kiBYc-?wJL zN0SiY$1h`^5V4D5-w{Eiyq!TJl!`f-h`U*zC1RB5F1+hc8HjIeahmhp!Y%muu9P!< z{QPVcYhMK{Wc0**OmWwQSJ|jvKC5EosQsUlPd^xJ)i?nvnB4#g*W#?n{u_TpaHup1 zmAJ*9@5v&%B*zzxji7h^7*40eNAVTo6PGPAqHOT}L`b8z+nCHyD`OpL(Y7fA>wu`X zM(}r(i;d6!44v8c3#GFj!H2E3p_ zJMI_M@lk>+1DXUWy`8uq&E~|^j@OU;vi%OfoVpW2T8~0l6a!Ms{~Dj?Rlmt`I6#k-s##T^)tVu?1}E zF($y8M2<7QzKrI!iwaq^;)sjS_o1Aw#OjjUV5)f-(Pm8I3$1@^28ch zLjD?#p&vtwZJc%zb*wotB)YJEUi8AE-l#$1==1X(DH1QL(i+Lq)wd-(r6k~Mt$CyUpgUE4zanYD%7-~1Y7 zFM%?i( zRk#Q6waPge0t;zvcvj|iZ!cNw`eWhEWVHaeoH5ziu!0}qAaw8ecl~Qw zA3p7xWyJb(>QmBMTmcP-8NhA4h_Yjfg%{-J+2YUZe_8P${yu=Ss>2{JTlwqW?#ChE z`Z>E{@ufv{e+C+!8N9|67R(l%Ae3Dzw{RX}WI&%~pubH#naU30wta9zLL*51YH_l> z`3xuVvrI&=B3Smp8fl2mv2p_?NitiQx`w<>h_MC7mF-d3PA7?O8v#1B;mV@Njuel* z^St~`i88Qy-7)8vmEWC3RAn!1%-nj>!)I>SK-;%#s2!asC$Agz<57YImQ*4IR@we3 zU?sJMf`5dGP4tV5giX@fF%LZQy*KaCI@nmPNryZrPxGC%3H#~fLSKS9jsdh!CQB^U z-AE=T+4c(^Qd}&8&v0{H=smDLQ5n!96WU^TFd;NnOeTh_z7PKa{}LTm-bal$wuX?> z(=eWS&FYLje4ID5M?<%ZgFTNoiz9*u@cI7fFo@=iJ(rDs*K!UCaG{8;iOtWyPTlrS z=T^LjKVgYr2&9o^4o{Yu;r&cQ6vgbMq|%O zTP6GDRD_y(mmD4HthJH(`2&#fHmA(0O?h~IPt>D#`KcliZl`m)b)Tpr0SLFvqqEXl z=xGx$#=sTVKl^Xrzy5-DF%KJX`Q_@VBCmFR7T-KZSMu-__9Zl6pUO2dmZNMfPsIq@ z%-8Z;VttSt6?sAIx}xpd*iI9!h>++0|k7x?SD}$!k8|F11!)`2>UXWf_Ym;teXGh zx}KO|osV$|c>#}}!5DVXHHb1E*7&+ktCo}4@fA}uI>TXN*A(S7D{6Udbc zR~ce) zM0);b^H8xdfFpFl`-%~$b;ebE*fi#-pRd2s@A%qqs@Hw3ad;_?B}nFShn!IE35d{d zMCziti}p_Lj*Mwk826*j9H{MmXHNs~v#5|6lPnTM z#D9ia^AA3MzOAzf`FW#V-EUBOOd!4if+_MVj|r`+ZitLnmfFo0<}WF3Q_FYy0r}@| zC_M0FQh$Ez%6tZJdNN(MMxBOS0kEUD^U$r4;X&ZhC}M)C+xCSEiQ{t)6($8=qB6tXuZ;$>`LgZkF(S7rZ7-8(=p(xe>6{?&hr(G6R zLLJI?K@agHEMjp)UKWnW`?P#2WKsDpypYg+Ul#eNJzEmaBN4@e>H*%dC~&Jn3B<5E zoM&YgiOQOd%gqM#6E7qS@c}PD^7u(=T!OMpW8cwN{NbwPrGg!Z6O4E)~JjC}W@jV0`5EegZQ& zfzk12+>j}J(|PJ`GvW<{2K+M%6RxGTzjDkl6wBK8Wi>J1ytq~HBhx~s$0 z=M%7RJcpRIJ&x%kAurnkHI`u8hP0ayw3tzZdL&pQ3BWN^bwTl=)_SK}8we&Z3)1 zRtTo#*?C;!U>sG$)EVA>yiB@E9-cW+q?Ly08%RQ@Y{?sZkAWiAFP0i0Ui`vpk%j%r z0%;(+BkWy~e9H6ya5v!LKX&we)s+n>K|c5@{RgZGt7*=JhR!K%ONtOuy(6UEOFs&~ zUt>Jtre82GxathmB5-$d?CoH$Q7rPDOl1o^0{Jx!eAV2XM@8JZhvKlC4i-U&j<+@H zlBI$q7#(Ih2az=h)ybP4BNtg4>^!qUQAE?+k~LiymU(Fa0Ec@U`bE`}ol}XXwC&8l zy{(VzkT(FvW7HWg6jq3!`xK0unBtGzHY3cxs=;mM$3l^u@!JQCTxw4ehVXHmAHub- z>TjH31u4BF)Z%fNk}x=Q2d>R&n)s za8bNFBlM*g1)!>FF&Eg58^pNAkI0sADhSKMh+hBUKLL0mRrlHb#3HQ!m6>G`KM+6Y zsi3RUnn7B1H1pO@HxkcL9n>{RXaICM4gCRyY4ZU0rGjmw9s`DWTM zho!Z5Cx|2zA;kNuL0UfL#HYaV+!_adBU26 z-~5l+vt8zP-0D{0kV4(ju%1!LLzyn89F)`Hh1LcgHnZXh=GS}LG9jsH0QXc(lcNje z0s7GTjAkCl1@o_Zb6mfjFfhx1oO^MRo>5XrgtPumzW5ExaBTqT51vC>;^##MZ^;o) zpIPYS{{k=|`PRnjSS0;s*3eVtt-i|Yg|18(T$=>YKht~pF&8}l0{?oTST?-Lgxs`c z*fnN9zJDBBp4f{WCBf_TTeEfAOD7BZYvkGuKRt~cF+av?*S)=0JB%|i+lKBe8YuHt z@vv>-$|LXfpOy@|8KvVws$RC4qEBVM>q&42oLrS#d#%odp5P<*i}5JpfIF2{Guw`H zq@)@@_@oZgBF@0?hKK*q5CpOO2glUuiecvN*bD*()<`Z^;kYV)f*cYpY_$z(_)aZO zW==boiqTPM#WtN!1(TDLhfwXq>#PS|`|{1@P_=fc3n~7gm#Ldwu-id>h%nW6&J++S zXwM;iE`>Q!WuQ4MH&G zmA}bL7l<-nu-Ol*>6FOm4~X3US#TBLR})MHnRtd$*;Q;(@)kw7#%+a%RMVEIdjqU( zM&W6ESf1YTLjjAAhD@lxu5C|03#J8`@iLwzQr~VVt3>)ns6znM4KVGh6IdJItV_SZ z_;jllhB~Ho?W|>}2jfp5{71BNApq=;=6%UXwkiA7Ze6%P9uSvq+Wji^h4J+D?nQV+ zisQxTQT2poi$08Z|oPEw}niX58%ucbFwh?p(k@x4A^xz!bP;kJ7Mz| z{!aE^s`tR(0Q8OI^NFM_Ws^~lTp|_w?Bi&7lS?qN4%k`POkDFKHvLw}5YhUy&^m|= zQ@k;b>lQ^=NyWts_h#AaZkTsJt zLJi1EVFobDN$@?P(rHexstK#h$2HQ(GSM=<`GdEB&fl<}tx(^; zHI;+>jZuIBl}#51UQN0YyyJu^Rx!~%Ov|=QwAn!Y$FtKIE&UrHd%g|xwy>Og{acJS z4(oJACSvW^5EUsL(5omkQ}#rv z*nU)7zJO+KFZ7U;B~`b93kgDI@|T>o9j$+QFWp2{L>)Ss(lt9(+KNoMOouA>Hx}j9 z&1Dk%od0ph4}c#iGrWA}fB!&m0o>H{e(7A?ea%%qOQ}F7}$7&wOiJtHjwe7)DahGxie@lIo&w)Lq>9YB>HR#1E)^^SvL^4?kNU zI@2pU)7$^=FU6hnysM>*kykwaZMIT3&no6ixo}$;$CRXTi6s_z+pj7f zv@hN`^QX%@?`|7DB>T_0QY4OS&wNIv`= z+S=Zpn$MyWz07K*JFKPCi1qF}d zA6Z2;j8NiNZ$7ab5Xt!!A*j?DnSaW|JnsEKo+L9st+n0N)aM)M{_pJ;vF#EqiIQ}N zV7QC80EXa=2Vz1i8+01P{*vl9P=XzNN|EYaf2>t|yVYQ!5%U& zXAEr3$e2jD8L8j7sy{#KM>`WwtxB;LBIZo;>(mP;FG$0{TQJIL@?5kFwSG9SL#5#b z`$idn?T_zUt_B|v0Ytw4wr-~Dm_D_;gr+IZ_+A*LO>*Sx+m~Pg&P@~H;-DxX)9O8{ za@d4jvq|^7w<){`Uxn@*e zVHG8P`hUCenXM#&_%C~As)RF)e~_`@jlZ1bujM7!dsOGpB{L5mkn{(tx#z=ydCru2 zT@|^JB*at*1N?zu53@P1`_`p;#GrYA9Sp?8os}&0BWM2wel?cPRl4&h06s$yLA0oL5g!>5ZOL20(it!7 z0@pyxgTm?HqZ9q#&~^%#J2!1eqVcANMK5NKKI!DGNQBjI9S8=GaX{A-%=}&dy2At%(L$(ny6=cQfQE| ztg$5q`Sz&ws9gd=00KX;gJ9Bxnn@u%&R8g5<(E8%?AX-E7bLqLKcptCmr&`lEq>_t z#1qVeqh=e+!6;QGS6k1`FFNm2ZY9kK>C=zcGR{-xZwSooM9-YA{LoTMz^m#xvv-z? zUG9%T;QJ%EV7fdGEjr{oJ22ai!*?g@o2rX@AITgE&uL$dz01+8%Di~qHoc^J&q6uktDhV*L=IK z?U$?Fi~t|pk);=;67xlQW>0mb522ds_kC4zh8g*(+@Qwtqez{d zLT8(uqMKZ)S4}wveFSy22ooIR5%FEwPkCY49F}>IEy-(cJmS$x7}X{U&``i5Ekd^X z?b}MB4?;f{X(@7F09@Aq`JIvJ=yx2|CM4MtDel&P45Hp+6NFx_=_U&1QX*f$azQrF zn;f#h_y8Q2@vkHe*oTE=lb`h=+(E5W251|Y8ilwzE5o|BGQuYXmoPU<@e8l>TjuQc zdYB`_Z)ydsXev|pooK_FfWjzbS_>V08p&3$mArGMSM&fuVl&BmY_yQT5B1V(|CFnb z<`2iVlL>M6uLJwMJs)^3G4v`bB(rSMtqrHnYRVFpxR1uHsJvnqejHBksnZ+H zt%-aW-s4w*-!BwKOI?+9m-jT&Tz?(H8#{KMMPyX+bG!8qI%w^J0B3)N3Ko<`A#@1Q z7A^bC4I9QL6V>#MhI-!@R)1%ZmA*^thn8gghK+m~=`_Qj`tgC4J-SQKY9Ni(A*uMC z)$yJKti|0q6AT(hFu;e`!8qw3JLq6%k(B}!d`Z6J&;vMSzjl_`c{^?eFC}f0jz>M` zHEDJ)w*tcaIqG96*7Ga!qH#p#&$sIU@9$ivY4n7FYP-vRsM3+c_*b zq|^I=S}|b`*W1Oc-#3bM(rCveIm6WND2>&s^|XYpMy6H3AS&- z{x8k|fIYv0w-@>cOAdK{?*w%xpYwU9shTRTn`R2Qzce;QA7FqM9LrTCAHClVm4%pE z(6v5Fb;eof=FgwONW#0uO(g$Lo@DltEYuq=c)NdLbmq-Y5C*c=6LEy72lePUJG2L2 z`mtY}kW3sO`LN*}3_aFPq|u5?XD4RvJ%iq>9xb{Us#(;xwx*<-a=?TzCl%^!J88CS zl2oNpQ^0O9Spg5MGo%Q?C_IHC$F}k+nDL~ldIL}an`KO9i9;)1Y2z!5so7O_14xHL zIS23@;Tv-u)!E(YnmrA zxmf{0iZWJ-wpk}#h|`FRoFSs`%-jlXaQ!$&`JGLc{->I(rVHWQC;1_$F%*BmXrq9W zJhk%Cqz17rrruY5(GzTqqZxTb-ds$D4vs#`tWPooC@4x}rgdW5Ykz(_e(?|4okkur zF%J+)7HvUg+%hpy3Il$I%`dxVwMZH0d;wZEeH}15_xqynvt6+l{-Sa2`oC1>Xgebt zy-Z-_0wz~mK>(RRc6ZiDds1&mIjvI$R zPGOz+jhahfVd6A?TBm&F#SI*@@#vD|5c0t0ULs;(=?3;#HEt;SQUP$6tSReC7ZLqR zLe`7Cfj-OY(q3snIrFh|o3Adt%yR8cabY93vxJo&A;z@R-N~ET`wDm%S#MOTT8ae2 zZXzR>OOWwxO=o&Q)j>>EvP+zSBj{=JQS1VwrA6C);tX`L7VjF`AGr5N)%gfP8X6R82TD+I@o(LI=NV91dA%Gj2I^E`KQf{x(S2j zCiP4WbFhnBEjG$ibO{IROPtHQ`1>n%zN(*^)lWsMk+Fhb00Nn{i8)YbEdtN8BwVPx zUnDyfUlZZqc{RArpKHzAk+@&|j3Sa?H{wf7%ge6BbzsUWt*B&$zwQ?y+df3TOY$Hi z-PHvRpk9t+kESBwvISb@HQd^}bxh?$b~+{!(%9|0f9Q8m7Oj3l@wBdCP^pQDv<|n_)<5_ub-tzWFLP zByUvnslfr8#)g%V#`|9Is%md2jEQfhH~?2@4ji#Zvlsy~ul% z5ya33S}SKjLBwH7=3vU||zs=EMiOBd7>vb7`Zk8p})%err zAJL^wQ)4|=x~02q0dd&iJ8V>#bf#%yT_PHOeuo6!8NK#?Hu}_H(Nhh%izfz z8vi>%eKlc4C~@2AjA3^kL+&D);fy(ZaTc1v*K~DyuFCPP3vid?!6}QO+>D-S5V$X& z6X09(<1sbVo?2V*$@Pv(#IW)zsAknB4@V)`uf}FxH2!z_>%z%?MRFICc~VKtOZ3Ht1dW(Jc5uYfHdv4`woRWPOmX#-x3Omu!=|-D-gB8>I+sKyjEz zWkqM^Ustd)0Vrhm1OY-fSA-+wpgY(NC|0vNf?RZVZR8e{gR3*?n#T4yJCBXRoWoP9 z#^_1p6wn^omUaxxXZ9pQ4kp#}t=AXn67?$WTtDx9VwK#9>vblO{1rb4#tKgm$h>vw z?DQWu&3L9=lIm4teP=88wfJ#VL7onZ?2>@fNdWGUmGQuQ_~okl6&ay3D<)soUS14O zVe?2^Pi&@23O2wocb*wN!3J?NGm_ca>J&A|VfV!d23=}zedkBS- zV|0RYML{>bRR*RDxPSt|tj7iTa4jkNkR^8ame)}&b|?Q?ZTtFr)wCyJA*vd2{NXKt zjVLW3^v4UQ)taprh)^jYf+DU%UX~X^?*0Nk%v$ZH z(>mV)egUTex}M`Acg=Ug&e3)K*|XUASzWKrr@Vhrn&!99k5K+xMKUCmzB4^YAt<7X zLp>wJX%G0vzTdv?uc|^ojx{Ro5^!Pe?=hq3=ezq6`VF@7;i#fLz&vZgFuqU-jAk`+ zS^>hv&i7HR#Spp*v$oB#Tk-%SjSrvgaSYe5!O8cg2~9uL@Qi4TswAI>c%P-%!HQ^U z5tzd7J~`Aj=@oxsCepY222Xh130^L^QCxEz==|nnW&1&1?&c;OZ5S40eGMHR>o!l7 zVh*yLDV(w~8~ve=2t_fbA-M^t@z2JZFBs^jB$fB_`y?4!memT9O=WjIOTaf_G|`JcThd?{Ku>*w*EJ*HSCba9d2GIjJP zc)f8QE--xx?F8WulsbQPbnW}b#-c3TEVU;~cW0GNFP^l^$ERm}-{TEb6CGBZuL$|5 z2VmC1FNH})WWi_C&m-r6TGS~t-3c*HPzE`T#VSCVX5x1Z%GC>x{APlK!$ z^p={Ppf)0ypUM+?f90q}3HX6HofMOhUOyvkkJc|YXioc#NI>MLf}p_h?88G_s?8l^ zM;zghi2Vl~e4G<Zsp`R69=IjN7L6)1zfYn6YDU~5Lp>7@=}h?g{*2R z6tcQM#sJO=1=NbP5v)_%0XyUL{!Hb`jvzmLyZ#~$A6uC?%SZ6b*2x*C_yF!jpN=;h z`9(QcUt8bTwb@=lftBC$|F&K`i{CG<4i4V&Z#P({%UrYHKh|EF4Ef?tCmx=#2yUa_ zNZU`>G=l#}*INL^?L}?lNDCAwlv3Oa1qu{xi+h10#ibN?cV}4wr4%h%92N@2-JONv z?k5lpxN>ni2i`bs!fOBaJ*Y z-(QJ|FyJ0O3Cs2My8QF$4G~rlJet*S*_xkEj`z)SULlmK>vo%sk_fHu~+YQ zZmq{S^{3pjJ0>Dqbf@Vrx+v+3dL4BDhP;v5as5jFVmvFdL3yazkn?=uno@QOtpua5yU7UyC)PO3ff-G)y4e)z%*+{Ex^mhDy5_%#A zYQCBUFN}^HCVH>+BlQ$2OBYAxlocLBN~%Eh#1DoSSn_lYcki_h^{9U5H(7H`%Heew zXNbmr#ks-@@%5*>6rHVd51E$VPb)%NkDY|JQFqD7VV~ykof(;_h(<>bnEf4Z?ZE!> zCmi6O@0|DBK%)Gy;~@O6`@eF`UtnW+-*ekQ2As%N z_D*tuh2SGmtg2qD2kvJ**GjXfKi9miR#xk~!&5CUzpgt3R8{SeN+PDG<$q5pCf@s~ zs?Fi&pXHKsX39MrXNQpxvz+-6Yhwu$-!%hac*HF+#TDlbvBDX+WcGU;+}wxN*eZF7Wx=vuvj%m{z3w0 zOH>v{UzgKIRkUCvlDa>(+k|$KuiyOSl>2ZRB-4mPA60j;SUxtmR|FUSjg6E~2 z86yR!zhnQgq~zdAc=gKLA~zz4Xq`awL}Z=Nmkmz}a#`Qw;rl?tMoLE#QsZ)7qad7S z6Q^g}x^r@e43;OK70RNbvES!W4*tvoLTGy}pB1K7ylaiSmVmNZz|=^sbG6)Kal!x+cnGWA~*z2Gw| z+_xz+we=SKQ^(8rS>0$gLAEF6!}DMBS}Y64kymFUnsAW8XTkG~e-{5~0zld~ zX!WNO|I>02fvB!YKW?V0=B=PsdHnVgx3VC-Tucy=i0PI+{r}$N6OFbsAQ? z9XO%YokD)4nB&!8C>vx~gORAqY>QiQ+L?&AWQpY!r2;LrQ_}5X?mcqtrS!-7H}-jBDP2Ooig`xKGpPeT4xIPLY5wWOuh-%>NXHUxp!u_`C z^@cjB8v=;G*0bAcBAxKzD6NP9AopLBr5)1zV`!r za=M0~;UHr44h6qMDZm#p{g6sGXW&L~-W}#qxwxwGqJ{1g z;>^uQ0)VA8{$*2?*zC%7&l_~@>aEzsq**DQ7z-Xy;Aerk8XKr4#_?fc$ro3lc(c-Q zHMWBnXh@u7&#fb1;_M!W+c5oAlxpFz^<;|EonMlg&mV|Ql;ANgOG&MNs*xLss5x+DL9=utL{0m-=^>Jk423%L-+BwsVGA=zMz5p3c zVREFFlB2+_E$xx|c4LR>O~#K^MW-H-&FZ38MzWY8bERL4v~lL*&-sJG9OyTEl6U?k-=uj@{w02Z9O0e1N%CWqAO@cJK zcw?K|v5P8=AaCc?k?i(xET#SaGu<<0S*F-*P2548GVv&{9CX|MjkMIMwF#K(gS9qjIAqO|lE?)J*L?H74oY}~^k@zY^TF~#G=`8V^Nos8`hjpAO+ z&I8)`0ri|`b(V;)iExaM98<}={^RJa?CcX`q9itVRbIry?vr2Z@f zq=8=?P3FH`S73`44|vz?XV~Wll>PZId_ZKdGY& z+QF*BLw~~%FZ9KlKm^Z_GZSp&rCLZofMs!`G!RDWqkwOa?A|L28Qg~W6)v)Xe?cbW}t%cyCz%nf+{ zfu|)AcCOny{KDdG8_rhtJv01L_eNyjDd{TsZ_l&J)s*13k)X7zJFO^2V`}UifdW3Z zRX19$2(HSL1zJR{>LuuGZ2#{%fWun_wTs$Qir@d<%2!h8H9F#V$C|LL^hcR zf5K?GDIjdqA}Wb1M|({104u>wR{lL%=f`cfZjWcY7;opS|J?XJe!(=Qwyh(uiFrIz z!g=@yf>|YmTul@i>75xM9iqXQNY@U(6Ww zsz3F4_1;UE{|NZoj{nd``OMY!vB@_KuKVS*r*pKO=$B69n7Di=(cFDZl-4Jwy{#yA zhRl8|Lown~dn~T!|6ivL;C%Miod)+1(=d}CeT_Nbj6YJ@d^e6o$okn|X$C4Y7)|OW zpr`Rz!FL8O^rV@urY-iIz7XWAuE^`Be8LsguyT5W6S&;7@&xMdKD)NlJ@MOBJfp}d zY38!&D@O*I2I0m|A**Ix&gUo;s{(mw+foFIw$DGc9GvMAJ4b$mmxQA?EA*1T4gs^IOL zq_xQ9;$mrm_@%rd37M{NB-{5a^nDMoFfa6ddCTt*?5Cy~tB}qw3c2XICQa*FRu-L0 zZQYTj{;NK@?nu`Z2gt$e@q8BXX`dXs^G})UFnHW@NLEn0q<$NCog;Zk1+vy5czZ7k zZat(UU{4c*8d&SuU0C07{&h0?t$DpOO_n<__d_Y+2(%?CB2fuT4mUdhr{6IBnx+WzjgWCvkk@$B+ao;C3d1X0 zekmfC){wNN^op3dS7G`46uus&*^G+#fK=oEsLr1pI~Kb%DL(!V(--({>x*v>1# zt!3;_>Q9MoDon{S8{)5@xxW~>;r`10tTPvrI1q^rtc6u&n_6UtEPcsOE$A{bzns#| z+*^dqltwXqLS1xRwFJ)5D$>>~f>&r(#^2Fthph5C$o5;Fd7wQr5aK3kz_T^?0BIj+ zWSYTVjhSHw)_=~qPZ4YMh?mOmcXGc4gAAc>-O&o)6*3Cy?9e9UP)FVU6J^t*d|ok* zt4H-2m^^`t#Ac@IcvKlRuS{*3h<7gsx}Hn(X@LEh2@%DE6#tdw19xWZk$UFyvR=B? zhVQNjjl$a(XFvNo=3PouL!!e8iBiy#W#YaI>&Z~jOmBrSJ3Ir|PL~qB@@5`IO_@pT z-6F3_#LUo39^~vNG?y0xk%Ybv!pk=Ei=05Mp2s%(?ThKfgxjSifmhHvJ_m$Ze!u1? ztH;;@E|lb=m5hyU5Eo(+zF57WYn?u4W40q^3w0-Oqobkx8)r&Mmi9TkT2<9ip?+tR z1>+1U=-%<(`YHRvkzP1B#GH+NMTp{XYEJVGS+jjXW zf`p~(=12iQpb9cMgG38)*bRCYpmsqJ&C7?xiWZ<^vz2e-uF5PwoB2fHIL!xcQ+(A& zpoPu(<0k0H2XkJ>{0yOSpQJ#d5Bv!}}!Cs#|m+3!+?EQEB+NtPiN&c3W5N3>BpOEON&SvulLz)$jz4lM5 zBWI=-OvQK@PkIy8RwahiDm4cE@*Gq6o*P&~{VPO^36I9hk@g(pV`i^O(l=hOgAuO&zqWIA6a4aM+55ARC#i5Ay05Sz48a+ z1mhhq3!4vtalqGH7|7qhd8g@}yX{qK_9E{;EYo~u7w1pnt(|z5T-GZIk?+`k+J?@2 zcC11-$j%}Iae~5iuY7S_FZF@u8ZH)@0hf6-@y5Q@tS3YA?XV;oQqbj zr+lKRe$M9|TmOT3r0BIqezJ3rVlf1%eNw1frU#e{9mviir8Ou11QU$3mupCl?reu; zxm{>_G`|P)e=PkdM#n#%Dj7Z+q*Mfzi-;6A{0sbCEc{U`V2F&gaJ82g(-|#L*2$yK zC#t3W+xpiM?JwE9hI3v6j+J_gM$z(gnn+U8bX*a`7qVtP%eOZFmCt8Bpeyi6T&Qq@ z96%5uSszh=(dzsNP?a<(yk)z?Fx4!RAOAQ!?4OFv!bW~6QrqOUEYM5uvG;p~Zf&~4 zEEf(VL`??YNS$47`1)^lnQM8$G*ssfvS8z-vgvR?nI`LP zQ&EeQT^Dv2Yv`&O`b z{;LY%!D+TuSM^-X0JEhb9*w3mzPz8 ziGGKpucvCaP7p5*12Vm|XL;Ww+hNOBX)?E;rPe80v5XMAr^kDS7ulwfqa1;vCWF*A zVk5`O&$?ZL?i<0xJFMuDA^AWPkB4-T&ygVp)x~&{92XER+r_lJ{)l>ASKD6s>Vt^*Uk|Fn+Xc#hP|SeN{`4z4S9>{`~(e78YyG_Qgb&FLQU zo(mAwONIX9_z_UD60^tLEaL^dy;9A)-T&`J0)Xo@%U0KufAF@928L#u{j8g1&Z&8t zH!m6KqHR^!2q=_Qx6cK-8Hr#ykN6XYTcqWe>SlN6-v;5SS5B-}{l3JxX=7yiJ@SoE z`%@=vdydW)-Z<7G(KiI5voOvhm|)ts15-dVg+Ix7k>U=bRs-)y0h(S(eEX(+={%>b zQ1ler-xlME1>f}Yb|MLRhwz*CRxj{f$-@|jqjR3G#`a764&wdb75AI_pyfIv0By^( zw$)08!Z~_iG1p@6q?T!V&0XQ922BZ+;4XtFuCAks5}fp;4}3z4PR5Q|C`SJ5F;RtJ zoVXa}q{S_SrSPlOEy0~P_1AZ=wsg#$Vq$~V9j6ZL%Af`d z(CQX~9BeB-5C*owT?*Z!kKDqqogN(|@#5dnj~~lA=ZMkL&DzTH(xG=3t*oV&5iy2onFI)(EU@KLP@eVk7&hZ|`1k zSbkO-XnJ4n&(N6?x|qiDjj?as1ACA1h|1#l=O)hI!vAo;&g&rbxHBFec4n4lMWMCY zmktK0)|0O(JS>-!ETe~ayMknYfG)QFr%L0V=GYS|Wrhb&V^{_iaxl>0fmMOG)Rt{X z9F)n4={XLt_U9>u6MnS#G>mgtd?F^x-s$B^e2;l|8pGaTrr_@FOpg!P(rlP4gJt$RPxr3dHBQ#7|t&q%JYl zZ~P~`svJq(#&ETln;Cv39{#?pcltj5jU6-m*(3gU|4BP(!E7V7D~*eFhcP*jSn0tN* zr1w{gM{!1u|G^d$mTJ~gqM!Lr(4=v6G|?0g)qPooDNfC`6@a@f&C$kJASpu3zvIJw zk3^6CaTZIJyQjXE%k$w8MzM8 zqZyE{7P<(EFRqw4io>RyPfoFL$g+G56fwm7(;En5>4)lhDHBUhx6^X-))b~+|1&i- zq#BZbv3pXqzVOs#Fi_$o;$QmK*2?oEyv(RF*JhfS8rCbVOpTn0r!MVPM;qS-t~jL| z_d$^PvIgQrgUtTPyffLM1(8S=B`Y0wED(2IscXH-NAK;VHRxtQjtRT~SruvZCpswZl+8h)c??RGXH6y~tYxk;>q0R6dT0LS*78c@H2OQ@~j{lD`*Kt)^w(`m1Yn_`0`~x8x~Yx%SLZ1skKJ@ zg^9`gc68Y$)b%<^=a9sr)!cU5Jpx`f6lAZ4@SmO zw$DZg77t_bSYbuHnH-Y#w8udkjs0X_PD?j`yc~X{-wgSrc?#3hb>pQOT>U=KS|q?9F2~jjF-ZXGS$fI>^-%V_lK1ICa-= zzson!)V@9uRt}l)KU}V)0?3Y>?D=eYdZt!X+&IAu0F}gOKE_ydpQf4@9KU^fT zO?t2}YvdLiEFFK@C+Ff_Ocdc17IMbpTAkaeTz!K4gTMQIo_b(_36NW$w5N!|6)Ti% zoBZlk;`IFLc@UZd@W}ACpSM@^_sh7PRntczuyB)TxwE8BNSV4H+tqTv_TjE+??j1M zuSgH+Oa(OJYSo*GA1*JpuzEF|P~o2G;I=6>>lhvfnYToW1>3hHqf{d#jkaIPH6~^{*#u zd(J%VB|!^qeKZ9MrZ!z4j<{dN5NS~gfPO^OYdvj9>>G?{wgq678GEc1W|(R?!Xl8+ z0-9YZ7||5EAFx_Q>PGurSbGYBCBkcaX{twv)~K~@+1Q|k z6Xm|*wqHZttN=E(b-v;*j@5VfVSV2MLg*6bo{be*h7Qf&VhKN9B`20tBU7>Fkx!|` z>v^6%D=8uPQeHVt6YeZn%?NWsmQMxIX7(A=L}LrTjf> zCgf9^T??ox;WlHMm<@G|U2kt7d>d6K7z90n9k*Dqw~qx%F9*r$oeZHq=UWlL{qbdQ zJ{j}|_OJmwI)@ux_2p2%Q(;pbQ#Q($Lpa8786Lim&s0;46W@LQU9QV^Tzhb^Z)!%* z9wVUUBQw>5%FOaokQUh#Eg2bKcq#4}@o6kC6j-V4|2%o`qV--~MN@N@Q_3Ni)Mo#J zr^V>d3uct-PqX?OJ+D^!s>cB~WAUWxlV?#sWTLuqvHLhE;$?a9n$v<*VZNywze&o* zh8F5a>6uy9RMlML&J2@<(QNO*>rMg!{L}&Fsjxl)kK6a{4JwA~Xb(5jA>u2BaK?gg-XDqeDn^a7TW?lV_fZug^euDid=Iwr%6u@4{a6ZK4BPvNk;GqTC;n`sNM z+56#wOOH=_U+$r^2#o`f?#kv?D=~Q)$RmMe*m-%rp?OkCTstWOIV*1Cp>kIyg#2_` zBP2nLpV-NEgJ1Cpz6H%Z%8+FnL1TmOULO{ z&JSzA^$BY2V9i0(yePys5-HB3#Eq6GYa&U4g`TDJ;`1vK zzS<890(N=Kt6y+RHf>&IX!F%*6|_tap<3=Z?$E>)_an7=iLQJ&m@-u&(9DQc(FU7T zD@&dhJZR}SIV4Tv7Tq?&N`p4{dKlg8|Od$K$F!SmLIWX!hlZ{s_rH1y=m`0 zUWd8PQHAY|XY5lcahYK2^-7T#*2+?Z?ud$eGoG3Az6p0I`TR#6xM|G_%EI}%PR#`x z;lWr~bbw^Uzi*(+zFzEgS8RbQd9~;h;=IT&{o`p9ZId6M-P&g+qgz_c*Ak9k)S>cf zR6h=u$#WF3^9sz6z`aW%uG)8sr8|dt<0s}&n0xjX^)QLQXR5bE;aGXAD9r|YJe^%- zX5!4O+Uk=_26qksOuSzOm7O!$T>kO&ox2|`zV`QQ>Y-a{@kd@v7sDSr7}Rp+iofXn z%|jdL-t+FBw^=60uuz!Lm=nE#dxl*t&4#PWQGBi2cWI5oJYU-Q%-lvV8P#&?HuuCl z8TTqKk5AAYPxWsws|IcyTcuLchqO+$vIv8@@Fv}@SUw@(KDh+uc?TB~TI2Y^RLHD) z@vKmA9(|W8)IN7aXqPCVBUs8+Q!pbyic=x<5Bx-ZA#WSF7!D_N$g0F_88RMljjguc zfQ^|yVf`jH_}kxj-s+z&r_vvCSqvoftaNY*PvFUywe6>ewpRO4s};$SMEos*Z@Aj= zbUqxZWG0+I<&zwB;Lh~Ya|koMn4N@4gNKghc4OIWgTkJUS8y!XXiyDiJ#vNi$rtX=tdD!k6UMSDN&rQX)=&tE2-_9@7FTZRl zO4^Q_3(67w<)Es3C)V(-`jCJHf!#ti75sYcr(b2u~UrB*Zs>;tW6ZA+*Ceh|E7oYLQ}*4?jvuH$5t>P zB}Dd}p>!xLUThqvdhV{k|4PBh_MD>QyjOhX*kevdD9I)n`tWIzEDZA6JEkRGPV8ll z56;0?FYn3-9taixpF#n;uq@SsHFA1bOz)1=z}LfBZuOr6@n5PDCW^|~n?oOmDaMsN zZF&?(kC*pZQxCs-&^wVUG6@yMS6TA{CFh^F<8H^HLMP3qAQD^BIeigqMWt%Dlwn{e z&>2V2=MBn4~+jMaG%hJiwgC;f&ZF-F`TW0O>@7o@V^ zCLxFzbuj2a`FF+excd}w!Ga&*rxN}PhzWHn}&V^4b3<{=Dlzy`E-O1yyXw* z_N}Yei6^tKw$r60uilxzAym4UOv@EtWg%|F1c_WPQSld#h_ z1A2T>A^vMy1GVg##~sN0axs9QRo8*AR+sZw8pSZs3Re-w_mc+$cC+W=(V2+eu;)D| zjd19#yzdXUOtit-S>NM1|MJqk^Hw_~sbrF8AWh!-~2+P?& z^VKqY>hxEH)N4neu`TNXSqNqKq+?{$jj)Gsbw_O$9x-H=)?8n|GwT_+Y>t0p*9e9d6G|%?~ z*Vo5LDijPLGin8$AB#HW-s;GZy$Add!~Ap*?mMz1xbj8{_9$36NZpSN5P@Ha)^X)x#XJjU|B_p-;Bsbsf4+b$*_-Wbd z-OWP|!}<{dv06z^jY}938WH(|VTd|kCfAB9WgJ+_|3)A_<(mBMI9K0%cv5mx9Jb1l zm@%Hz0<{-csmsvyK1syP<-oUELHjM$1x27+ujn{x1TKuIK_ONeUx4{QrwU;t0-n z4Wj3Qw7UPtoM``;G0@&5F_aTfB&k9$o&aVhuI46=PXE906uQPO|DWojq5W+gEMp$_ z$>m3A*{jAM2P&kvDCgL;w=O;>+@w1B^n&RdQ)=Rq@MU{g>xPfEU$ZS4WwWvOzf7m2 zq3iYEM0Tyc4<}9!N0}?Avk>6!91bAUTmgewrxpK)X7Rg8_`_WsYLU(#k@RrQ^>AMg zZCokiNA10PKmqq_(ZJo26Y9nYb>ju~LBbyp|1nYeBhz3HH=_@?;t#{HyDcu@<|^s- z$Ov_z0(9m8)xawM!{EaO9cu504s{&@+#dkL!B+)kNr}jzTnrq^Pz3{Z04Z$;g;dy zh|*zjRM8(={_$r1{MsNBxwv`yt!?)V2-ZpG{r?vx`d)jSGoLT6t(0qS;_n&!9PscNVBW)Akg$L)?YT4-MK#Aix!rj{-D!>k@T0bm`a3eiq-$CD!M)Q*j1IPJ*!9nwmeH zAwI++QcqB=i0$>8t(iI4pz||YXr?d1>3I5`_?17<@g53tX|Abn-G*COTntGqW=gQ9 zWZ1PK-TdX>JScmmw{(YCH~~7*Ex6Gz3axqJTyu9nwt+h@rwkXAKM8YwX1}4okMc}> zX7#d4#HCB(-4+74K8O2%(`g&{m%~U0TKq!FTm%nW`BJz1mvIk-!G6{^bXdMq1Roe# zLhUN{pQmTnZsFTE4?@Zuxadb`MT6L_hQw$b%fdoncAz)O{l3Z@z&o!@7@h$me_m9% zWjbFGqt#PuXym;g)s4%-0(Q$}MY*Vs$zXkm$Gx^SXpjTjtl8eq&kh9!Z?xn&c*@Z% ziHR6hi-5`??!o!JhDv%+``qL6@u>2{zISDj#o}`2*hd;x8RFF)SMLRe^~_lWzNktI7te z1+l)2ANMepY`Lxly{Iz#`O<&mrgqcsddB~~um&e6;Tr*Jn40O;!JZ2unUwHj+C*9& zQF#8*R>)|@+4aE3rKAC^^Sh1n*_6!`2hkZH{{||t(($Chc|jprPc#;Tow}^<`#-Ks z9$7K22(p-BI>SnqKBaH$Nokpg#)JjgfNJQxm~i<~j+2N8bd$khQp|jG zh8gOv_4H0`8x-azID0PwG_#A9PtOhxthuzw0waxWqm5g#Zy|zUIy#M;vu5dS32Sg3 zyPoH|uYVjuQp>?;%RS{vRN!jf3$Bp`ua4MqqW)C_^R0Vs#YEiru)KqyxE}KtA6$CE zr$?%L+p<`KuD4qh~8veqml}PQN%=!`=mL{8}!Q?joNIV9}Qjg zFj(!tQoTkG9n0>TU@KxJiP6~I^dR-a71(>|=tp=NcwB@Jc;xGQSn-2yQ~GPyoe(#5 zD7kP>W*qByJR{mW-WMEK_=605-RHN7KgzcuWW>J%{Aglwhl&5PBrZ@AfYcD?R6?%HbZdN8&Il z_rdc?Pr(t+MSwR>n4RZpZxjU_-yw#~Fjf59WDxvWH5dH?3Hkb=O@2haJ) z1gls*q@z4yD#y&}NbU0OK`nSipVl3))I{ab=?P5A>)laxr*h`ql?&(IF(*S#BV;fA zHOWu(UhfdeiekQ@$kyOK&*jM-i+}EajA>|vHFHap(3_Gas=A$P0qG4?9nw(Q$Zfl? zQ8wb*J6~5pLNejmTmZqx{w@4lS90WEA}g`^2>L$HhxTIa-38(iOjL_iJLIbu9TR^5 z@pB2`uU6qP4IyuWB zT4k!ZS3=@Yss31l7BI-W@n{x=Hj2TufY4uDj*k6le0y2)xb}vO^q94gpaMk{45d z9{PwG)Suy)1zdr+7y2*?OLo^1j>I;z>B{s7Sg=9Q_Bs=MjGk|aDZHV(e;S^&NUlWs z;y%=HchtkUFddXb$8g`)<|ycpF&xF>E43-~uRoaP@@dkJj~MKJXY1D2 zVoeQu$7NTNt{0!+cjs_HSbJC*+CT#>weF4=WZLk=9oQa23kjFm#=8dMEQ@Pb(Ml9Q;Q}byI4V~=$DhXxB`Rh|U7djL+e!I3! z&#iWkYa<=OT-Hj!;NP(x=Y&h&@LgI_(Q8RQCj<~crUV|rPLGjBe zyP1R|fWf;b%NaoNH`4ZE?`CHO$T_tzz=C(Hu@I?4?@&!=mrKk;x!@tcv1r2V z?rXwlm!I`aXx<-J@vP9kPP$PIA{fPUZ1a0gO_JVXbinWj5i5hY<-C7?`;OCYKDfBa zuHB_$%Y=bO$<69gCT=U8Y;9}o-iq(_hAfC0%>6b@ zWQMe9Dw_-A-O7hETZ$?Jnp2?j=j!2^E zpTd*Us8e^izx`gm7j!2OWU8U7?0ad|fM1bjY3!8m^KmHPsPJWhVK^rF`Z)u+j&k^j zX!NQ|)!S9J-H8!S90vau?i5mft_88J6aag_0Wa|m1gxN@&@5XNz0bXm&1AQC0Fe>S zx%_+I*GVM)5M9H061#NKVj<-DYw+_Q2jB{w%hWFC7uE7;_&+iC+J(r=&FL`SuuCLk zIzF|b6%Gysmsg|Jwgtc|KrmG>u!KaqntE^y#@a9|xqm_M&V7c?p2&QXx;aC;mbmW>c=CcICT zQ!FuHpi4_yh%*)k0NcOt*ZwdSsxnIq4Xv5;4kc> z%_2p#%LPo1nO_XQ=h7}p)-k5SZv0rj?HXoEOU$}?e}_X=%bCNPyteSpfhO-Q<8A#` zkGk`VHtEbUmGTp_3QQa7&_jZaCq6FJbwj>|8G4_4aXbIIjbNvVhTaQeIl35yh3|8} z|9Na%LiQRm4?PgW@eM8*`O2b2Tz<&0#uQG}crFmWrbynu+Oj&o`ymJzfeqsDk81AV zd6pgb?GuQ-o1VqF-p6(|0XqDWWW)UAD)8P9JY**($3BHqNhRK7SfcZE<0HWxw_s2s$64W>9BjBYgp`o5>hmEw+VbDu@}5Ox-rI+$zWrY|)!xx80L| z7tZqZn;njj=~Ne=K#jFJ=F#ZvetiYHC-)Qi>&S$|uS83qdM&$^fwErf+>YZixp#is zt5J~b);9d1ChV2$k3X}T9U7*irv*l5&93fUO4|&zqhfRJ^j)jirF}8DS5=o?vV97_ajG;|01S)IH*KcGMDZ_#&cG!&M`)(} z^KBeRo<5tAg)}a2Ktza@bT>EIlfic++~ZoXLc))tVrJuBaUWj!XhjU!D^r5$vO91Q3e7{yGpkiT*x zTs%$YLGny?LOzKVysL=b;VsH36f-;61O3!j?1#F~;+Yh#enGG${c*`%hX zY_BfqmEun>5th)TSoV%fb<{qm*3iPwwem1xZTlg9-j*SC<7!+}$2bLlBj8Qj!%%X( z_Odouo%&;2_v@OW%D-(QjAVf`WG{}7_5FuRKNt!N05kFdC-cOpnb1o;|3wUa3uzhh zuw4bIGQ$SX;3zA|&YCTc+oenB0z&52R}@5zfrUleU=V%&qoUQ~P0cSco<-XYKjJ(X zm)IL6!lBL4f9D=0Z@I(GwDnR&K&0u?l@>+OUT}I+ufUh2$p?F=ulSok3HSo-x=rTM2vKPUx2=*9&T^b#T#}= zz50q*I;m#5!%olq83Pil(z0((!52k+ejLewU*}QMef}Q)^SVaeC}+j2RC>O@Lmgr^ z@D82hP2Myn$3T1rj;rxVY>>KH&$i7MNH1{~AcDQw^9uces^h78NX`Vx8S#(m{rYp( z){%_+iQkx91WelHqdqQE|C0Ci@0V+(cHR$x^4(mY)isGjmyG+QT5}=`XqPCO9QhFF z9i7BMnehZe8@gn)rP^~dg!G@-@qU5@Jr5TZmAz@q+yrTLbOt|QdR^Sy9$jbb_Pf&P z01Y_@w=K$0lEtmt}nOgOyUW^U=0-bZi~k zz}p*}Haavi@RM@9NKn?h(g-jL=YkcNSiIbh#VpS<)l1RuTS57(J71oQX1ab9cV1Ro013HO=@~v?lUZ)2dY=3>Box!_so*S6MR!ckoLM=Dm&ehtWf~*XT})5y2EF|6Jo|u% zR^{2|#$@1R*V;6#vx?uV51SAu?9Ka@ol750j?tS&a$i6{uYCL%ymLEIlr!lYAS37o zetP3Fe_$8n;kI1`J@De~J~9LdCp9gaRBAnxyIp@zAH>vxTEOi^SL&uPD=Z8RBDv?2 zEsR%56B_{=thoPFYz)%0ZjRMmlr%afMnej1X%z!FTBu2u9D5wT&YbF`^}g~NgKr#f zebVLu<+EI(jqOq&-)UY(#ZJol^0HzZL`ScK{VeK4{CcTJMGb#cQM=?NUKh~FAhRJ)<< z9X@#Kr1zW4&a!(}&TlBNx7Qq5@JnXuC(1m~EcRSLc&>q_4h5w5OqW2NS$h9q{lny# zHF+^BNDWbSGS`I>e}t7=L&y3S`wy~U3ByPcSX61d-bUCB(RCvM0vd&ab*_gUOn9`Q z#>OKtqwGd*JjU$BwT(8c%YyK=Uyu*)7~Z(#w&iiZ$pg~M1h%piFt*IXceuC4ruz3| zEX$T@|IFV=7DT#|pozi|V8V zq48sOB_(hq_NtAtg!Y%p&b-ngHqh$zidYUk3>$m~0CH{LuIu?)jp%xr4<2z!mn=`-AZ5E%a9fzzGgmK6~;A?pacwi-MnsY@m6})Rkz1s zH3gsnMX%-XYF$h5QL=h`9_xF7TIcUc9_>yW53@N;2XpHKw`GcL_vhE11n*W~XZv$q z*N^cE0Ctwfh%_hA>@j0?W)CKqP9?Hx6f5?u5Au%vu8}6*A?0Rhs_owsqc$qWV>W#I z^uh1dHABRD|Oo!aFZ5PUw4+#e^@RWsI3qFW4nJCa+sR&9cTo%w*Lt|T8 zb?isDm}}3DPMfm)WU7tIgB)ggKI-!+=mb680$d!EQe@~&*;Kvv{m=&8!8;}@_2s8l zzwFcLMf-FyADf$yNyXsGtlIlo`X1L7Pn~OiS50W|Z&yDxik83iE$vQj2uie%-vt6W z+;@cbjRdd$KLCqBbibYNO#Lfl@a4OKZ$!=T)&a!2pWU%Rs*fxo;qICz#!_di=J#~h z{BfdkoRJQn(>%8&A5*Y1OEFxMl&yjl74=x3wEQe*5 zDhJOVqh{doS%-d|=Whc9bUQt=1Zsa&Ew8)B`YRx!Wz+PR--Mqij+-x4v#T(U=SVpe z9Kdx>xr9tTN44$j=@UD0NVgy$iExoCEh0l%R8pxhQV7nFP)6LAb0 zk=qlVSzq#7Trdwvez{z()4JBFdUVID9~aH`p>vLlFWD0 z96a5@aq-M#c`BE1Al1Mx1NCzhu_NJ};z?pKj;gVhgOpVs7QY;1ZAdSCdBuIp={oIy zmlwZ%t<~47+TCVDGfsS7OFPj8HJIY=!G`+M_FOk$M=i`|a(KLh4%tjIgtH%6#xUaIZRCcSB#8mQ(KBwW5(+LqHBAW^1BSZ{ zvz%avL&j%VG{F*T$;hKn0`tRvzawFP_b~niBj8g_*2s|oIDPqp`g`>lwuwm{0kh>m zDg#k!Kh6XRljeDhNleFmuysH7;8F8?^B}s9#rk?#pOTyg(=!i9Bx-(H;8&DF1A^Zp zJ2Bip{Re9GVKlxFj&}xOQ@o6B;n*Bq^e*{p=RhE7Lq8Va=g6&xbGpVai`Bj6kB@#B#g^OY`)&I%k`vhPL43u#bC8JQPW#KT54SMUgzm9% z4)QDJ$MG`V9AnBDxo_aOdHy*FY$bqaJSVDbijtL>`S7fQjp&W}d$h*b{*lR{N z4nk)A8U1q*?&I?(^!|w-m$P+D@>BW8)%tp2XSQH363JtjEWt1Er!eK}engJt`bs|z zzXD_4HT+8h=WQf8Z3pni_E6@DEWH!zUXCUkXJl7lmGk_i143En9=`*-%F8Z#C&0O^ z=R_RWY?|kIPiW>VAG&9MSKv8rx~NZR`zgl@IUu{dd{9dd4SqiSzTLkVEnYVHJ6*Yt zN}-16`fFIt@AnYhgI}kQA0=Q7=!WRt=kG0qyp@QT^LVr?C%W*5Mfw{2-Y2SgBvKpV zc+Aq;2lw$L@ac(GL2k!ZYcSLyR(c)Z;hi3fJ;5;bM7P92A;j%}S_j_FW3BY>puxk6 zbPvD7ImgC3-Bm^#yKMIC<2- zG5$GM2kojc__S1izhJ4)QR601TW8n+z*q>Q9qP~VjUAa7m9>Xjjo?c;NlW}nU*Q_G z9=NOh!K@zZpxt(?l{y!kb?75o6*Jru)>&S%wDWLiR2l5CGhY44*)yYmJ1!8KGspN) zLAwm&91-hK@)5@>w7@z9kK-@@#Kv033k{EK;ZYBIK1oS`MvRcEg`cooe-Fj%Oh{** zf5H#3(XNA*Yizmwpj)kw2W8UUb4%nhk8AY{rW(>XwCu#;^$q~k7=LmY0TA!w zn5}m^;j{Cws}X?N5BC(O-^cNLz3^`A5U{s)G`VVRUMlVTti9$TlH*_NozJm2D?O&t0yl1;jp|O@8~5=qIr#1?K)sQu4cpq3b2p%C)wK4eVKWSm2!+@ zW@%AejB(-}>kAO~1oPEoO9BulEk{g}AX2&aSwH}*ag>nV5_z2QjdkQF<9`mo#mEHN z&2-0qq08wy?Z?Rb<7)jP$xgnrsfi~Zuk`F#<>5~pqvMqlp(nC);N@R`;8)LeRN_fR zFxJVMGm>3vtQaFyakH@N1d5FS?6JymP(CZY64XFgq$~Zh)y)LNjsv&>#?|M0HqMOy z^;pJAfQw}c>oAKMpgW#J&SxfkJTbNK`t1fGE^wx?qRF^5`=@nwmOwX5_{D^^z-+C$czc19+Ngfg=`@#@IHQk&3 zl&(!P_)i13Rw_K?pEm>6P=z3Gj&6V(3>R0NxyAj(`_VK*8nuBjhq6wx f~6WbSm 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

7w-asv6A%A@!>tp++5Hhjyjw!61EYu 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 delta 7453 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�C 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 V=ozSM_0aEAK@5gLI*1kh`46=rRLcMW diff --git a/asset_sources/default_themes/stack_wallet/dark.zip b/asset_sources/default_themes/stack_wallet/dark.zip index a859175051f203b4e828eb032ad2472f0171b8a7..8b31f4278dad0f955b95ffc1f518f76b28ec9643 100644 GIT binary patch delta 5537 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 ae`g^8P8S0FP`|CwFzEx(2wNhsN&6Se|Dl`! delta 5366 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 Date: Wed, 19 Mar 2025 13:07:14 -0500 Subject: [PATCH 40/50] Xelis updates. configured Unix line endings repo-wide --- lib/pages/exchange_view/send_from_view.dart | 4 +- lib/pages/pinpad_views/lock_screen_view.dart | 4 +- .../sub_widgets/favorite_card.dart | 4 +- .../sub_widgets/wallet_list_item.dart | 4 +- .../my_stack_view/coin_wallets_table.dart | 4 +- lib/utilities/test_node_connection.dart | 3 + lib/wallets/wallet/impl/xelis_wallet.dart | 82 +++-------- .../wallet/intermediate/lib_xelis_wallet.dart | 131 ++++++++---------- lib/widgets/wallet_card.dart | 4 +- pubspec.lock | 46 +++--- 10 files changed, 118 insertions(+), 168 deletions(-) diff --git a/lib/pages/exchange_view/send_from_view.dart b/lib/pages/exchange_view/send_from_view.dart index 59cf20a47..7e97017a3 100644 --- a/lib/pages/exchange_view/send_from_view.dart +++ b/lib/pages/exchange_view/send_from_view.dart @@ -35,7 +35,7 @@ import '../../wallets/crypto_currency/crypto_currency.dart'; import '../../wallets/isar/providers/wallet_info_provider.dart'; import '../../wallets/models/tx_data.dart'; import '../../wallets/wallet/impl/firo_wallet.dart'; -import '../../wallets/wallet/intermediate/lib_monero_wallet.dart'; +import '../../wallets/wallet/intermediate/external_wallet.dart'; import '../../widgets/background.dart'; import '../../widgets/conditional_parent.dart'; import '../../widgets/custom_buttons/app_bar_icon_button.dart'; @@ -277,7 +277,7 @@ class _SendFromCardState extends ConsumerState { // access to this screen but this is needed to get past an error that // would occur only to lead to another error which is why xmr/wow wallets // don't have access to this screen currently - if (wallet is LibMoneroWallet) { + if (wallet is ExternalWallet) { await wallet.init(); await wallet.open(); } diff --git a/lib/pages/pinpad_views/lock_screen_view.dart b/lib/pages/pinpad_views/lock_screen_view.dart index 5d630ba4f..c7d6bb254 100644 --- a/lib/pages/pinpad_views/lock_screen_view.dart +++ b/lib/pages/pinpad_views/lock_screen_view.dart @@ -29,7 +29,7 @@ import '../../utilities/show_loading.dart'; import '../../utilities/show_node_tor_settings_mismatch.dart'; import '../../utilities/text_styles.dart'; import '../../utilities/util.dart'; -import '../../wallets/wallet/intermediate/lib_monero_wallet.dart'; +import '../../wallets/wallet/intermediate/external_wallet.dart'; import '../../widgets/background.dart'; import '../../widgets/custom_buttons/app_bar_icon_button.dart'; import '../../widgets/custom_buttons/blue_text_button.dart'; @@ -119,7 +119,7 @@ class _LockscreenViewState extends ConsumerState { } final Future loadFuture; - if (wallet is LibMoneroWallet) { + if (wallet is ExternalWallet) { loadFuture = wallet.init().then((value) async => await (wallet).open()); } else { diff --git a/lib/pages/wallets_view/sub_widgets/favorite_card.dart b/lib/pages/wallets_view/sub_widgets/favorite_card.dart index 26e11624a..d9f730804 100644 --- a/lib/pages/wallets_view/sub_widgets/favorite_card.dart +++ b/lib/pages/wallets_view/sub_widgets/favorite_card.dart @@ -27,7 +27,7 @@ import '../../../utilities/text_styles.dart'; import '../../../utilities/util.dart'; import '../../../wallets/crypto_currency/coins/firo.dart'; import '../../../wallets/isar/providers/wallet_info_provider.dart'; -import '../../../wallets/wallet/intermediate/lib_monero_wallet.dart'; +import '../../../wallets/wallet/intermediate/external_wallet.dart'; import '../../../widgets/coin_card.dart'; import '../../../widgets/conditional_parent.dart'; import '../../wallet_view/wallet_view.dart'; @@ -132,7 +132,7 @@ class _FavoriteCardState extends ConsumerState { } final Future loadFuture; - if (wallet is LibMoneroWallet) { + if (wallet is ExternalWallet) { loadFuture = wallet.init().then((value) async => await (wallet).open()); } else { diff --git a/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart b/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart index 767770ba9..938baac71 100644 --- a/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart +++ b/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart @@ -25,7 +25,7 @@ import '../../../utilities/show_node_tor_settings_mismatch.dart'; import '../../../utilities/text_styles.dart'; import '../../../utilities/util.dart'; import '../../../wallets/crypto_currency/crypto_currency.dart'; -import '../../../wallets/wallet/intermediate/lib_monero_wallet.dart'; +import '../../../wallets/wallet/intermediate/external_wallet.dart'; import '../../../widgets/dialogs/tor_warning_dialog.dart'; import '../../../widgets/rounded_white_container.dart'; import '../../wallet_view/wallet_view.dart'; @@ -99,7 +99,7 @@ class WalletListItem extends ConsumerWidget { } final Future loadFuture; - if (wallet is LibMoneroWallet) { + if (wallet is ExternalWallet) { loadFuture = wallet.init().then((value) async => await (wallet).open()); } else { diff --git a/lib/pages_desktop_specific/my_stack_view/coin_wallets_table.dart b/lib/pages_desktop_specific/my_stack_view/coin_wallets_table.dart index 8da907ca3..aaf1d1402 100644 --- a/lib/pages_desktop_specific/my_stack_view/coin_wallets_table.dart +++ b/lib/pages_desktop_specific/my_stack_view/coin_wallets_table.dart @@ -21,7 +21,7 @@ import '../../utilities/show_loading.dart'; import '../../utilities/show_node_tor_settings_mismatch.dart'; import '../../utilities/util.dart'; import '../../wallets/crypto_currency/crypto_currency.dart'; -import '../../wallets/wallet/intermediate/lib_monero_wallet.dart'; +import '../../wallets/wallet/intermediate/external_wallet.dart'; import '../../widgets/rounded_container.dart'; import '../../widgets/wallet_info_row/wallet_info_row.dart'; import 'wallet_view/desktop_wallet_view.dart'; @@ -101,7 +101,7 @@ class CoinWalletsTable extends ConsumerWidget { } final Future loadFuture; - if (wallet is LibMoneroWallet) { + if (wallet is ExternalWallet) { loadFuture = wallet .init() .then((value) async => await (wallet).open()); diff --git a/lib/utilities/test_node_connection.dart b/lib/utilities/test_node_connection.dart index a211dd97d..7e8616ac2 100644 --- a/lib/utilities/test_node_connection.dart +++ b/lib/utilities/test_node_connection.dart @@ -305,12 +305,15 @@ Future testNodeConnection({ final daemon = xelis_sdk.DaemonClient( endPoint: "${formData.host!}:${formData.port!}", secureWebSocket: formData.useSSL ?? false, + timeout: 5000 ); daemon.connect(); final xelis_sdk.GetInfoResult networkInfo = await daemon.getInfo(); testPassed = networkInfo.height != null; + daemon.disconnect(); + Logging.instance.i( "Xelis testNodeConnection result: \"${networkInfo.toString()}\"", ); diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 0bb95e8e8..466755bae 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -4,9 +4,9 @@ import 'dart:math'; import 'package:isar/isar.dart'; import 'package:mutex/mutex.dart'; -import 'package:stack_wallet_backup/generate_password.dart'; import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk; import 'package:xelis_flutter/src/api/wallet.dart' as x_wallet; +import 'package:stack_wallet_backup/generate_password.dart'; import '../../../models/balance.dart'; import '../../../models/isar/models/blockchain_data/address.dart'; @@ -31,28 +31,6 @@ class XelisWallet extends LibXelisWallet { @override int get isarTransactionVersion => 2; - @override - Future init({bool? isRestore}) async { - Logging.instance.d("Xelis: init"); - - if (isRestore == true) { - await _restoreWallet(); - return await super.init(); - } - - final String? walletExists = await secureStorageInterface.read( - key: "${walletId}_wallet", - ); - - if (walletExists == null) { - await _createNewWallet(); - } - - await open(); - - return await super.init(); - } - Future _createNewWallet() async { final String password = generatePassword(); @@ -61,39 +39,24 @@ class XelisWallet extends LibXelisWallet { key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), value: password, ); - - await secureStorageInterface.write( - key: '${walletId}_wallet', - value: 'true', - ); - - await secureStorageInterface.write( - key: '_${walletId}_needs_creation', - value: 'true', - ); } - Future _restoreWallet() async { - final String password = generatePassword(); - - await secureStorageInterface.write( - key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), - value: password, - ); - - await secureStorageInterface.write( - key: '${walletId}_wallet', - value: 'true', - ); + @override + Future init({bool? isRestore}) async { + Logging.instance.d("Xelis: init"); - await secureStorageInterface.write( - key: '_${walletId}_needs_restoration', - value: 'true', - ); + if (isRestore == true) { + await super.init(); + return await open(openType: XelisWalletOpenType.restore); + } - if (libXelisWallet != null) { - await super.exit(); + final bool walletExists = await LibXelisWallet.checkWalletExists(walletId); + if (!walletExists) { + await _createNewWallet(); + await open(openType: XelisWalletOpenType.create); } + + return await super.init(); } @override @@ -507,20 +470,10 @@ class XelisWallet extends LibXelisWallet { try { checkInitialized(); - // Use default address if recipients list is empty final recipients = txData.recipients?.isNotEmpty == true ? txData.recipients! - : [ - ( - address: - 'xel:xz9574c80c4xegnvurazpmxhw5dlg2n0g9qm60uwgt75uqyx3pcsqzzra9m', - amount: Amount.zeroWith( - fractionDigits: cryptoCurrency.fractionDigits, - ), - isChange: false, - ), - ]; + : throw ArgumentError('Address cannot be empty.'); // in the future, support for multiple recipients will work. final asset = assetId ?? xelis_sdk.xelisAsset; @@ -596,7 +549,7 @@ class XelisWallet extends LibXelisWallet { final defaultDecimals = cryptoCurrency.fractionDigits; final defaultFee = BigInt.from(0); - // Use default address if recipients list is empty + // Use default address if recipients list is empty to ensure basic fee estimates are readily available final effectiveRecipients = recipients.isNotEmpty ? recipients @@ -816,6 +769,9 @@ class XelisWallet extends LibXelisWallet { @override Future handleOnline() async { + await updateChainHeight(); + await updateBalance(); + await updateTransactions(); GlobalEventBus.instance.fire( WalletSyncStatusChangedEvent( WalletSyncStatus.synced, diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 92178d93e..62876565b 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -32,6 +32,11 @@ enum XelisTableSize { } } +enum XelisWalletOpenType { + create, + restore +} + class XelisTableState { final bool isGenerating; final XelisTableSize currentSize; @@ -329,7 +334,7 @@ abstract class LibXelisWallet } @override - Future open() async { + Future open({XelisWalletOpenType? openType}) async { bool wasNull = false; if (libXelisWallet == null) { @@ -345,80 +350,66 @@ abstract class LibXelisWallet await LibXelisWallet._initMutex.protect(() async { try { - final needsCreation = await secureStorageInterface.read( - key: '_${walletId}_needs_creation', - ); - - final needsRestoration = await secureStorageInterface.read( - key: '_${walletId}_needs_restoration', - ); - libXelisWallet = await syncMutex.protect(() async { - if (needsCreation == 'true') { - Logging.instance.i("Xelis: creating new wallet"); - final wallet = await x_wallet.createXelisWallet( - name: name, - directory: directory, - password: password!, - network: cryptoCurrency.network.xelisNetwork, - precomputedTablesPath: tablePath, - l1Low: tableState.currentSize.isLow, - ); - - final mnemonic = await wallet.getSeed(); - await secureStorageInterface.write( - key: Wallet.mnemonicKey(walletId: walletId), - value: mnemonic.trim(), - ); - - await secureStorageInterface.delete( - key: '_${walletId}_needs_creation', - ); - - return wallet; - } else if (needsRestoration == 'true') { - final mnemonic = await getMnemonic(); - final seedLength = mnemonic.trim().split(" ").length; - - invalidSeedLengthCheck(seedLength); - - Logging.instance.i("Xelis: recovering wallet"); - final wallet = await x_wallet.createXelisWallet( - name: name, - directory: directory, - password: password!, - seed: mnemonic.trim(), - network: cryptoCurrency.network.xelisNetwork, - precomputedTablesPath: tablePath, - l1Low: tableState.currentSize.isLow, - ); - - await secureStorageInterface.write( - key: Wallet.mnemonicKey(walletId: walletId), - value: mnemonic.trim(), - ); - - await secureStorageInterface.delete( - key: '_${walletId}_needs_restoration', - ); - - return wallet; - } else { - Logging.instance.i("Xelis: opening existing wallet"); - return await x_wallet.openXelisWallet( - name: name, - directory: directory, - password: password!, - network: cryptoCurrency.network.xelisNetwork, - precomputedTablesPath: tablePath, - l1Low: tableState.currentSize.isLow, - ); + switch (openType) { + case XelisWalletOpenType.create: + Logging.instance.i("Xelis: creating new wallet"); + final wallet = await x_wallet.createXelisWallet( + name: name, + directory: directory, + password: password!, + network: cryptoCurrency.network.xelisNetwork, + precomputedTablesPath: tablePath, + l1Low: tableState.currentSize.isLow, + ); + + final mnemonic = await wallet.getSeed(); + await secureStorageInterface.write( + key: Wallet.mnemonicKey(walletId: walletId), + value: mnemonic.trim(), + ); + + return wallet; + + case XelisWalletOpenType.restore: + final mnemonic = await getMnemonic(); + final seedLength = mnemonic.trim().split(" ").length; + + invalidSeedLengthCheck(seedLength); + + Logging.instance.i("Xelis: recovering wallet"); + final wallet = await x_wallet.createXelisWallet( + name: name, + directory: directory, + password: password!, + seed: mnemonic.trim(), + network: cryptoCurrency.network.xelisNetwork, + precomputedTablesPath: tablePath, + l1Low: tableState.currentSize.isLow, + ); + + await secureStorageInterface.write( + key: Wallet.mnemonicKey(walletId: walletId), + value: mnemonic.trim(), + ); + + return wallet; + + case null: + Logging.instance.i("Xelis: opening existing wallet"); + return await x_wallet.openXelisWallet( + name: name, + directory: directory, + password: password!, + network: cryptoCurrency.network.xelisNetwork, + precomputedTablesPath: tablePath, + l1Low: tableState.currentSize.isLow, + ); } }); } catch (_) { - // Logging.instance.log( + // Logging.instance.e( // "Failed to open/create wallet: $e\n$s", - // level: LogLevel.Error, // ); rethrow; } diff --git a/lib/widgets/wallet_card.dart b/lib/widgets/wallet_card.dart index 4981dafaf..ed49e5ebb 100644 --- a/lib/widgets/wallet_card.dart +++ b/lib/widgets/wallet_card.dart @@ -28,7 +28,7 @@ import '../utilities/util.dart'; import '../wallets/isar/providers/eth/current_token_wallet_provider.dart'; import '../wallets/wallet/impl/ethereum_wallet.dart'; import '../wallets/wallet/impl/sub_wallets/eth_token_wallet.dart'; -import '../wallets/wallet/intermediate/lib_monero_wallet.dart'; +import '../wallets/wallet/intermediate/external_wallet.dart'; import '../wallets/wallet/wallet.dart'; import 'conditional_parent.dart'; import 'desktop/primary_button.dart'; @@ -111,7 +111,7 @@ class SimpleWalletCard extends ConsumerWidget { if (context.mounted) { final Future loadFuture; - if (wallet is LibMoneroWallet) { + if (wallet is ExternalWallet) { loadFuture = wallet.init().then((value) async => await (wallet).open()); } else { loadFuture = wallet.init(); diff --git a/pubspec.lock b/pubspec.lock index 5df33ec99..8bdf56e80 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -50,10 +50,10 @@ packages: dependency: transitive description: name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" async: dependency: "direct main" description: @@ -223,10 +223,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "74691599a5bc750dc96a6b4bfd48f7d9d66453eab04c7f4063134800d6a5c573" + sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99" url: "https://pub.dev" source: hosted - version: "2.4.14" + version: "2.4.15" build_runner_core: dependency: transitive description: @@ -247,10 +247,10 @@ packages: dependency: transitive description: name: built_value - sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2" + sha256: ea90e81dc4a25a043d9bee692d20ed6d1c4a1662a28c03a96417446c093ed6b4 url: "https://pub.dev" source: hosted - version: "8.9.3" + version: "8.9.5" calendar_date_picker2: dependency: "direct main" description: @@ -412,10 +412,10 @@ packages: dependency: transitive description: name: coverage - sha256: "88b0fddbe4c92910fefc09cc0248f5e7f0cd23e450ded4c28f16ab8ee8f83268" + sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.1" cross_file: dependency: transitive description: @@ -750,10 +750,10 @@ packages: dependency: "direct main" description: name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" file: dependency: transitive description: @@ -897,10 +897,10 @@ packages: dependency: transitive description: name: flutter_rust_bridge - sha256: "3292ad6085552987b8b3b9a7e5805567f4013372d302736b702801acb001ee00" + sha256: "5a5c7a5deeef2cc2ffe6076a33b0429f4a20ceac22a397297aed2b1eb067e611" url: "https://pub.dev" source: hosted - version: "2.7.1" + version: "2.9.0" flutter_secure_storage: dependency: "direct main" description: @@ -1454,10 +1454,10 @@ packages: dependency: transitive description: name: package_config - sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.0" package_info_plus: dependency: "direct main" description: @@ -1502,10 +1502,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" + sha256: "0ca7359dad67fd7063cb2892ab0c0737b2daafd807cf1acecd62374c8fae6c12" url: "https://pub.dev" source: hosted - version: "2.2.15" + version: "2.2.16" path_provider_foundation: dependency: transitive description: @@ -1662,10 +1662,10 @@ packages: dependency: transitive description: name: pub_semver - sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.2.0" pubspec_parse: dependency: transitive description: @@ -1782,10 +1782,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.0" sky_engine: dependency: transitive description: flutter @@ -1845,10 +1845,10 @@ packages: dependency: transitive description: name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" url: "https://pub.dev" source: hosted - version: "0.10.12" + version: "0.10.13" source_span: dependency: transitive description: @@ -2339,7 +2339,7 @@ packages: description: path: "." ref: "v0.1.0" - resolved-ref: "966469f2660226c33a1de77d1c5efee5459a2d4e" + resolved-ref: c685c5d3550cca414ec30d4b61259761f129dda6 url: "https://github.com/Tritonn204/xelis_flutter_ffi.git" source: git version: "0.1.0" From 8f5d17d026549579a395180cf412ef9e4f1eb6ef Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Wed, 19 Mar 2025 16:31:50 -0500 Subject: [PATCH 41/50] close on restore for all ExternalWallet instances --- .../restore_wallet_view/restore_wallet_view.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart index 82aef0d60..972012c00 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart @@ -50,7 +50,7 @@ import '../../../wallets/isar/models/wallet_info.dart'; import '../../../wallets/wallet/impl/epiccash_wallet.dart'; import '../../../wallets/wallet/impl/monero_wallet.dart'; import '../../../wallets/wallet/impl/wownero_wallet.dart'; -import '../../../wallets/wallet/intermediate/lib_monero_wallet.dart'; +import '../../../wallets/wallet/intermediate/external_wallet.dart'; import '../../../wallets/wallet/impl/xelis_wallet.dart'; import '../../../wallets/wallet/supporting/epiccash_wallet_info_extension.dart'; import '../../../wallets/wallet/wallet.dart'; @@ -391,7 +391,7 @@ class _RestoreWalletViewState extends ConsumerState { await wallet.recover(isRescan: false); - if (wallet is LibMoneroWallet) { + if (wallet is ExternalWallet) { await wallet.exit(); } From f77950de685d1e3225f53409e054d4456abea7f1 Mon Sep 17 00:00:00 2001 From: Julian Date: Thu, 20 Mar 2025 07:53:38 -0600 Subject: [PATCH 42/50] ensure fee amount is formatted correctly to String --- lib/wallets/wallet/impl/xelis_wallet.dart | 8 +++++--- lib/wallets/wallet/intermediate/lib_xelis_wallet.dart | 9 +++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 466755bae..4f6a3b271 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -4,9 +4,9 @@ import 'dart:math'; import 'package:isar/isar.dart'; import 'package:mutex/mutex.dart'; +import 'package:stack_wallet_backup/generate_password.dart'; import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk; import 'package:xelis_flutter/src/api/wallet.dart' as x_wallet; -import 'package:stack_wallet_backup/generate_password.dart'; import '../../../models/balance.dart'; import '../../../models/isar/models/blockchain_data/address.dart'; @@ -384,7 +384,7 @@ class XelisWallet extends LibXelisWallet { otherData['asset_${transfer.asset}_amount'] = transfer.amount.toString(); - otherData['asset_${transfer.asset}_fee'] = fee.toString(); + otherData['asset_${transfer.asset}_fee'] = fee.raw.toString(); if (transfer.extraData != null) { otherData['extraData_${transfer.asset}'] = transfer.extraData!.toJson(); @@ -473,7 +473,9 @@ class XelisWallet extends LibXelisWallet { final recipients = txData.recipients?.isNotEmpty == true ? txData.recipients! - : throw ArgumentError('Address cannot be empty.'); // in the future, support for multiple recipients will work. + : throw ArgumentError( + 'Address cannot be empty.', + ); // in the future, support for multiple recipients will work. final asset = assetId ?? xelis_sdk.xelisAsset; diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 62876565b..51d2b58af 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -32,10 +32,7 @@ enum XelisTableSize { } } -enum XelisWalletOpenType { - create, - restore -} +enum XelisWalletOpenType { create, restore } class XelisTableState { final bool isGenerating; @@ -370,7 +367,7 @@ abstract class LibXelisWallet ); return wallet; - + case XelisWalletOpenType.restore: final mnemonic = await getMnemonic(); final seedLength = mnemonic.trim().split(" ").length; @@ -394,7 +391,7 @@ abstract class LibXelisWallet ); return wallet; - + case null: Logging.instance.i("Xelis: opening existing wallet"); return await x_wallet.openXelisWallet( From fe437855461b3ff4cb952f99c00a41cfaf1540d3 Mon Sep 17 00:00:00 2001 From: Julian Date: Thu, 20 Mar 2025 10:04:16 -0600 Subject: [PATCH 43/50] more logging --- lib/wallets/wallet/impl/xelis_wallet.dart | 105 +++++++++--------- .../wallet/intermediate/lib_xelis_wallet.dart | 49 ++++---- 2 files changed, 76 insertions(+), 78 deletions(-) diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 4f6a3b271..febfc9463 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -77,11 +77,12 @@ class XelisWallet extends LibXelisWallet { try { await open(); - } catch (_) { - // Logging.instance.log( - // "Exception rethrown from recoverFromMnemonic(): $e\n$s", - // level: LogLevel.Error, - // ); + } catch (e, s) { + Logging.instance.e( + "Error rethrown from $runtimeType recover(isRescan: $isRescan)", + error: e, + stackTrace: s, + ); rethrow; } } @@ -129,11 +130,12 @@ class XelisWallet extends LibXelisWallet { ); await info.updateBalance(newBalance: balance, isar: mainDB.isar); } - } catch (_) { - // Logging.instance.log( - // "Error in updateBalance(): $e\n$s", - // level: LogLevel.Warning, - // ); + } catch (e, s) { + Logging.instance.e( + "Error in $runtimeType updateBalance()", + error: e, + stackTrace: s, + ); } }); } @@ -156,28 +158,29 @@ class XelisWallet extends LibXelisWallet { newHeight: height.toInt(), isar: mainDB.isar, ); - } catch (_) { - // Logging.instance.log( - // "Error in updateChainHeight(): $e\n$s", - // level: LogLevel.Warning, - // ); + } catch (e, s) { + Logging.instance.e( + "Error in $runtimeType updateChainHeight()", + error: e, + stackTrace: s, + ); } } @override Future updateNode() async { try { - final node = getCurrentNode(); final bool online = await libXelisWallet!.isOnline(); if (online == true) { await libXelisWallet!.offlineMode(); } await super.connect(); - } catch (_) { - // Logging.instance.log( - // "Error updating node: $e\n$s", - // level: LogLevel.Error, - // ); + } catch (e, s) { + Logging.instance.e( + "Error rethrown from $runtimeType updateNode()", + error: e, + stackTrace: s, + ); rethrow; } } @@ -420,11 +423,12 @@ class XelisWallet extends LibXelisWallet { // ); txns.add(txn); - } catch (_) { - // Logging.instance.log( - // "Error handling tx $jsonString: $e\n$s", - // level: LogLevel.Warning, - // ); + } catch (e, s) { + Logging.instance.w( + "Error in $runtimeType handling transaction: $jsonString", + error: e, + stackTrace: s, + ); } } await updateBalance(); @@ -707,11 +711,12 @@ class XelisWallet extends LibXelisWallet { case HistorySynced(:final topoheight): await handleHistorySynced(topoheight); } - } catch (_) { - // Logging.instance.log( - // "Error handling wallet event: $e\n$s", - // level: LogLevel.Error, - // ); + } catch (e, s) { + Logging.instance.e( + "Error in $runtimeType handleEvent($event)", + error: e, + stackTrace: s, + ); } } @@ -735,11 +740,12 @@ class XelisWallet extends LibXelisWallet { // "New transaction processed: ${newTxIds.first}", // level: LogLevel.Info, // ); - } catch (_) { - // Logging.instance.log( - // "Error handling new transaction: $e\n$s", - // level: LogLevel.Warning, - // ); + } catch (e, s) { + Logging.instance.e( + "Error in $runtimeType handleNewTransaction($tx)", + error: e, + stackTrace: s, + ); } } @@ -752,11 +758,12 @@ class XelisWallet extends LibXelisWallet { } // TODO: Update asset balances if needed - } catch (_) { - // Logging.instance.log( - // "Error handling balance change: $e\n$s", - // level: LogLevel.Warning, - // ); + } catch (e, s) { + Logging.instance.e( + "Error in $runtimeType handleBalanceChanged($event)", + error: e, + stackTrace: s, + ); } } @@ -813,10 +820,7 @@ class XelisWallet extends LibXelisWallet { Future handleNewAsset(xelis_sdk.AssetData asset) async { // TODO: Store asset information if needed // TODO: Update UI/state for new asset - // Logging.instance.log( - // "New asset detected: ${asset}", - // level: LogLevel.Info, - // ); + Logging.instance.d("New xelis asset detected: $asset"); } @override @@ -837,11 +841,12 @@ class XelisWallet extends LibXelisWallet { ), ); } - } catch (_) { - // Logging.instance.log( - // "Error in refresh(): $e\n$s", - // level: LogLevel.Warning, - // ); + } catch (e, s) { + Logging.instance.e( + "Error in $runtimeType refresh()", + error: e, + stackTrace: s, + ); } }); } diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 51d2b58af..78caa6c87 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -260,11 +260,12 @@ abstract class LibXelisWallet case xelis_sdk.WalletEvent.historySynced: yield HistorySynced(json['data']['topoheight'] as int); } - } catch (_) { - // Logging.instance.log( - // "Error processing wallet event: $e\n$s", - // level: LogLevel.Error, - // ); + } catch (e, s) { + Logging.instance.e( + "Error processing xelis wallet event: $rawData", + error: e, + stackTrace: s, + ); continue; } } @@ -284,23 +285,21 @@ abstract class LibXelisWallet Future refresh({int? topoheight}); Future connect() async { + final node = getCurrentNode(); try { _eventSubscription = convertRawEvents().listen(handleEvent); - final node = getCurrentNode(); - // Logging.instance.log( - // "Connecting to node: ${node.host}:${node.port}", - // level: LogLevel.Info, - // ); + Logging.instance.i("Connecting to node: ${node.host}:${node.port}"); await libXelisWallet!.onlineMode( daemonAddress: "${node.host}:${node.port}", ); await super.refresh(); - } catch (_) { - // Logging.instance.log( - // "Error connecting to node: $e\n$s", - // level: LogLevel.Error, - // ); + } catch (e, s) { + Logging.instance.e( + "rethrowing error connecting to node: $node", + error: e, + stackTrace: s, + ); rethrow; } } @@ -404,10 +403,12 @@ abstract class LibXelisWallet ); } }); - } catch (_) { - // Logging.instance.e( - // "Failed to open/create wallet: $e\n$s", - // ); + } catch (e, s) { + Logging.instance.e( + "Rethrowing failed $runtimeType open(openType: $openType)", + error: e, + stackTrace: s, + ); rethrow; } }); @@ -440,15 +441,7 @@ abstract class LibXelisWallet } if (wasNull) { - try { - await connect(); - } catch (e) { - // Logging.instance.log( - // "Failed to start sync: $e", - // level: LogLevel.Error, - // ); - rethrow; - } + await connect(); } unawaited(refresh()); From e4ac7d85693de4d50775d59b8ec0352f2437ce1e Mon Sep 17 00:00:00 2001 From: Julian Date: Thu, 20 Mar 2025 11:34:50 -0600 Subject: [PATCH 44/50] add missing continue; --- lib/wallets/wallet/impl/xelis_wallet.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index febfc9463..8be779fc8 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -395,6 +395,7 @@ class XelisWallet extends LibXelisWallet { } } else { // Skip unknown entry types + continue; } final txn = TransactionV2( From 176ed0f89fd9a6d4eddadbdf3bd8e469f8c4c596 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 20 Mar 2025 14:51:12 -0500 Subject: [PATCH 45/50] Xelis init/open refactor --- lib/wallets/wallet/impl/xelis_wallet.dart | 152 ++++++++++++++++-- .../wallet/intermediate/lib_xelis_wallet.dart | 132 ++------------- 2 files changed, 149 insertions(+), 135 deletions(-) diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 466755bae..36ebe2812 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -19,6 +19,8 @@ import '../../../services/event_bus/events/global/wallet_sync_status_changed_eve import '../../../services/event_bus/global_event_bus.dart'; import '../../../utilities/amount/amount.dart'; import '../../../utilities/logger.dart'; +import '../../../utilities/stack_file_system.dart'; + import '../../crypto_currency/crypto_currency.dart'; import '../../models/tx_data.dart'; import '../intermediate/lib_xelis_wallet.dart'; @@ -31,7 +33,46 @@ class XelisWallet extends LibXelisWallet { @override int get isarTransactionVersion => 2; + Future _restoreWallet() async { + final tablePath = await getPrecomputedTablesPath(); + final tableState = await getTableState(); + final xelisDir = await StackFileSystem.applicationXelisDirectory(); + final String name = walletId; + final String directory = xelisDir.path; + final password = await secureStorageInterface.read( + key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), + ); + + final mnemonic = await getMnemonic(); + final seedLength = mnemonic.trim().split(" ").length; + + invalidSeedLengthCheck(seedLength); + + Logging.instance.i("Xelis: recovering wallet"); + final wallet = await x_wallet.createXelisWallet( + name: name, + directory: directory, + password: password!, + seed: mnemonic.trim(), + network: cryptoCurrency.network.xelisNetwork, + precomputedTablesPath: tablePath, + l1Low: tableState.currentSize.isLow, + ); + + await secureStorageInterface.write( + key: Wallet.mnemonicKey(walletId: walletId), + value: mnemonic.trim(), + ); + + libXelisWallet = wallet; + } + Future _createNewWallet() async { + final tablePath = await getPrecomputedTablesPath(); + final tableState = await getTableState(); + final xelisDir = await StackFileSystem.applicationXelisDirectory(); + final String name = walletId; + final String directory = xelisDir.path; final String password = generatePassword(); Logging.instance.d("Xelis: storing password"); @@ -39,21 +80,84 @@ class XelisWallet extends LibXelisWallet { key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), value: password, ); + + final wallet = await x_wallet.createXelisWallet( + name: name, + directory: directory, + password: password!, + network: cryptoCurrency.network.xelisNetwork, + precomputedTablesPath: tablePath, + l1Low: tableState.currentSize.isLow, + ); + + final mnemonic = await wallet.getSeed(); + await secureStorageInterface.write( + key: Wallet.mnemonicKey(walletId: walletId), + value: mnemonic.trim(), + ); + + libXelisWallet = wallet; } @override Future init({bool? isRestore}) async { Logging.instance.d("Xelis: init"); - if (isRestore == true) { - await super.init(); - return await open(openType: XelisWalletOpenType.restore); - } + if (libXelisWallet == null) { + if (isRestore == true) { + await _restoreWallet(); + } else { + final bool walletExists = await LibXelisWallet.checkWalletExists(walletId); + if (!walletExists) { + await _createNewWallet(); + } else { + Logging.instance.i("Xelis: opening existing wallet"); + final tablePath = await getPrecomputedTablesPath(); + final tableState = await getTableState(); + final xelisDir = await StackFileSystem.applicationXelisDirectory(); + final String name = walletId; + final String directory = xelisDir.path; + final password = await secureStorageInterface.read( + key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), + ); + + libXelisWallet = await x_wallet.openXelisWallet( + name: name, + directory: directory, + password: password!, + network: cryptoCurrency.network.xelisNetwork, + precomputedTablesPath: tablePath, + l1Low: tableState.currentSize.isLow, + ); + + print("Assigned wallet"); + } + } - final bool walletExists = await LibXelisWallet.checkWalletExists(walletId); - if (!walletExists) { - await _createNewWallet(); - await open(openType: XelisWalletOpenType.create); + if (await isTableUpgradeAvailable()) { + unawaited(updateTablesToDesiredSize()); + } + + final newReceivingAddress = + await getCurrentReceivingAddress() ?? + Address( + walletId: walletId, + derivationIndex: 0, + derivationPath: null, + value: libXelisWallet!.getAddressStr(), + publicKey: [], + type: AddressType.xelis, + subType: AddressSubType.receiving, + ); + + await mainDB.updateOrPutAddresses([newReceivingAddress]); + + if (info.cachedReceivingAddress != newReceivingAddress.value) { + await info.updateReceivingAddress( + newAddress: newReceivingAddress.value, + isar: mainDB.isar, + ); + } } return await super.init(); @@ -88,15 +192,37 @@ class XelisWallet extends LibXelisWallet { @override Future pingCheck() async { - checkInitialized(); try { - await libXelisWallet!.getDaemonInfo(); - await handleOnline(); - return true; + final node = getCurrentNode(); + final daemon = xelis_sdk.DaemonClient( + endPoint: "${node.host!}:${node.port!}", + secureWebSocket: node.useSSL ?? false, + timeout: 5000 + ); + daemon.connect(); + + final xelis_sdk.GetInfoResult networkInfo = await daemon.getInfo(); + bool testPassed = networkInfo.height != null; + + daemon.disconnect(); + + if (testPassed) { + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.synced, + walletId, + info.coin, + ), + ); + } else { + await handleOffline(); + } + + return testPassed; } catch (_) { await handleOffline(); return false; - } + } } final _balanceUpdateMutex = Mutex(); diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index 62876565b..a20868e74 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -335,125 +335,15 @@ abstract class LibXelisWallet @override Future open({XelisWalletOpenType? openType}) async { - bool wasNull = false; - - if (libXelisWallet == null) { - wasNull = true; - final tablePath = await getPrecomputedTablesPath(); - final tableState = await getTableState(); - final xelisDir = await StackFileSystem.applicationXelisDirectory(); - final String name = walletId; - final String directory = xelisDir.path; - final password = await secureStorageInterface.read( - key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), - ); - - await LibXelisWallet._initMutex.protect(() async { - try { - libXelisWallet = await syncMutex.protect(() async { - switch (openType) { - case XelisWalletOpenType.create: - Logging.instance.i("Xelis: creating new wallet"); - final wallet = await x_wallet.createXelisWallet( - name: name, - directory: directory, - password: password!, - network: cryptoCurrency.network.xelisNetwork, - precomputedTablesPath: tablePath, - l1Low: tableState.currentSize.isLow, - ); - - final mnemonic = await wallet.getSeed(); - await secureStorageInterface.write( - key: Wallet.mnemonicKey(walletId: walletId), - value: mnemonic.trim(), - ); - - return wallet; - - case XelisWalletOpenType.restore: - final mnemonic = await getMnemonic(); - final seedLength = mnemonic.trim().split(" ").length; - - invalidSeedLengthCheck(seedLength); - - Logging.instance.i("Xelis: recovering wallet"); - final wallet = await x_wallet.createXelisWallet( - name: name, - directory: directory, - password: password!, - seed: mnemonic.trim(), - network: cryptoCurrency.network.xelisNetwork, - precomputedTablesPath: tablePath, - l1Low: tableState.currentSize.isLow, - ); - - await secureStorageInterface.write( - key: Wallet.mnemonicKey(walletId: walletId), - value: mnemonic.trim(), - ); - - return wallet; - - case null: - Logging.instance.i("Xelis: opening existing wallet"); - return await x_wallet.openXelisWallet( - name: name, - directory: directory, - password: password!, - network: cryptoCurrency.network.xelisNetwork, - precomputedTablesPath: tablePath, - l1Low: tableState.currentSize.isLow, - ); - } - }); - } catch (_) { - // Logging.instance.e( - // "Failed to open/create wallet: $e\n$s", - // ); - rethrow; - } - }); - - Logging.instance.i("Xelis: Checking for upgradability"); - if (await isTableUpgradeAvailable()) { - Logging.instance.i("Xelis: Generating large tables in background"); - unawaited(updateTablesToDesiredSize()); - } - } - - final newReceivingAddress = - await getCurrentReceivingAddress() ?? - Address( - walletId: walletId, - derivationIndex: 0, - derivationPath: null, - value: libXelisWallet!.getAddressStr(), - publicKey: [], - type: AddressType.xelis, - subType: AddressSubType.receiving, - ); - await mainDB.updateOrPutAddresses([newReceivingAddress]); - - if (info.cachedReceivingAddress != newReceivingAddress.value) { - await info.updateReceivingAddress( - newAddress: newReceivingAddress.value, - isar: mainDB.isar, - ); - } - - if (wasNull) { - try { - await connect(); - } catch (e) { - // Logging.instance.log( - // "Failed to start sync: $e", - // level: LogLevel.Error, - // ); - rethrow; - } + try { + await connect(); + } catch (e) { + // Logging.instance.log( + // "Failed to start sync: $e", + // level: LogLevel.Error, + // ); + rethrow; } - unawaited(refresh()); } @@ -467,10 +357,6 @@ abstract class LibXelisWallet _eventSubscription = null; await libXelisWallet?.offlineMode(); - await libXelisWallet?.close(); - libXelisWallet?.dispose(); - libXelisWallet = null; - await super.exit(); }); } @@ -521,6 +407,8 @@ extension XelisTableManagement on LibXelisWallet { await setTableState(state.copyWith(isGenerating: true)); try { + Logging.instance.i("Xelis: Generating large tables in background"); + final tablePath = await getPrecomputedTablesPath(); await x_wallet.updateTables( precomputedTablesPath: tablePath, From ae0631adebbcbe309f7ca68cc87e08059f68e229 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 20 Mar 2025 15:11:37 -0500 Subject: [PATCH 46/50] reversed investigative changes --- lib/wallets/wallet/impl/xelis_wallet.dart | 32 +++-------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 36ebe2812..06ee5147c 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -129,8 +129,6 @@ class XelisWallet extends LibXelisWallet { precomputedTablesPath: tablePath, l1Low: tableState.currentSize.isLow, ); - - print("Assigned wallet"); } } @@ -192,33 +190,11 @@ class XelisWallet extends LibXelisWallet { @override Future pingCheck() async { + checkInitialized(); try { - final node = getCurrentNode(); - final daemon = xelis_sdk.DaemonClient( - endPoint: "${node.host!}:${node.port!}", - secureWebSocket: node.useSSL ?? false, - timeout: 5000 - ); - daemon.connect(); - - final xelis_sdk.GetInfoResult networkInfo = await daemon.getInfo(); - bool testPassed = networkInfo.height != null; - - daemon.disconnect(); - - if (testPassed) { - GlobalEventBus.instance.fire( - WalletSyncStatusChangedEvent( - WalletSyncStatus.synced, - walletId, - info.coin, - ), - ); - } else { - await handleOffline(); - } - - return testPassed; + await libXelisWallet!.getDaemonInfo(); + await handleOnline(); + return true; } catch (_) { await handleOffline(); return false; From 78b4e2d6b70d42a7776b9f65372817dadc464f21 Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 20 Mar 2025 19:50:01 -0500 Subject: [PATCH 47/50] Added initCompleter for Xelis --- crypto_plugins/flutter_libepiccash | 2 +- lib/wallets/wallet/impl/xelis_wallet.dart | 137 +++++++++++------- .../wallet/intermediate/lib_xelis_wallet.dart | 6 +- 3 files changed, 88 insertions(+), 57 deletions(-) diff --git a/crypto_plugins/flutter_libepiccash b/crypto_plugins/flutter_libepiccash index 8830be2ba..0bb1b1ced 160000 --- a/crypto_plugins/flutter_libepiccash +++ b/crypto_plugins/flutter_libepiccash @@ -1 +1 @@ -Subproject commit 8830be2ba661828d743be12df6f33d560448ed6a +Subproject commit 0bb1b1ced6e0d3c66e383698f89825754c692986 diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index a57f03a02..42c681579 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -27,6 +27,8 @@ import '../intermediate/lib_xelis_wallet.dart'; import '../wallet.dart'; class XelisWallet extends LibXelisWallet { + Completer? _initCompleter; + XelisWallet(CryptoCurrencyNetwork network) : super(Xelis(network)); // ==================== Overrides ============================================ @@ -65,6 +67,8 @@ class XelisWallet extends LibXelisWallet { ); libXelisWallet = wallet; + + await _finishInit(); } Future _createNewWallet() async { @@ -97,68 +101,94 @@ class XelisWallet extends LibXelisWallet { ); libXelisWallet = wallet; + + await _finishInit(); + } + + Future _existingWallet() async { + print("EXISTING"); + Logging.instance.i("Xelis: opening existing wallet"); + final tablePath = await getPrecomputedTablesPath(); + final tableState = await getTableState(); + final xelisDir = await StackFileSystem.applicationXelisDirectory(); + final String name = walletId; + final String directory = xelisDir.path; + final password = await secureStorageInterface.read( + key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), + ); + + libXelisWallet = await x_wallet.openXelisWallet( + name: name, + directory: directory, + password: password!, + network: cryptoCurrency.network.xelisNetwork, + precomputedTablesPath: tablePath, + l1Low: tableState.currentSize.isLow, + ); + + await _finishInit(); + } + + Future _finishInit() async { + if (await isTableUpgradeAvailable()) { + unawaited(updateTablesToDesiredSize()); + } + + final newReceivingAddress = + await getCurrentReceivingAddress() ?? + Address( + walletId: walletId, + derivationIndex: 0, + derivationPath: null, + value: libXelisWallet!.getAddressStr(), + publicKey: [], + type: AddressType.xelis, + subType: AddressSubType.receiving, + ); + + await mainDB.updateOrPutAddresses([newReceivingAddress]); + + if (info.cachedReceivingAddress != newReceivingAddress.value) { + await info.updateReceivingAddress( + newAddress: newReceivingAddress.value, + isar: mainDB.isar, + ); + } } @override Future init({bool? isRestore}) async { Logging.instance.d("Xelis: init"); - if (libXelisWallet == null) { - if (isRestore == true) { - await _restoreWallet(); - } else { - final bool walletExists = await LibXelisWallet.checkWalletExists(walletId); - if (!walletExists) { - await _createNewWallet(); - } else { - Logging.instance.i("Xelis: opening existing wallet"); - final tablePath = await getPrecomputedTablesPath(); - final tableState = await getTableState(); - final xelisDir = await StackFileSystem.applicationXelisDirectory(); - final String name = walletId; - final String directory = xelisDir.path; - final password = await secureStorageInterface.read( - key: Wallet.mnemonicPassphraseKey(walletId: info.walletId), - ); - - libXelisWallet = await x_wallet.openXelisWallet( - name: name, - directory: directory, - password: password!, - network: cryptoCurrency.network.xelisNetwork, - precomputedTablesPath: tablePath, - l1Low: tableState.currentSize.isLow, - ); - } - } + if (_initCompleter != null) { + await _initCompleter!.future; + return super.init(); + } - if (await isTableUpgradeAvailable()) { - unawaited(updateTablesToDesiredSize()); - } + _initCompleter = Completer(); - final newReceivingAddress = - await getCurrentReceivingAddress() ?? - Address( - walletId: walletId, - derivationIndex: 0, - derivationPath: null, - value: libXelisWallet!.getAddressStr(), - publicKey: [], - type: AddressType.xelis, - subType: AddressSubType.receiving, - ); - - await mainDB.updateOrPutAddresses([newReceivingAddress]); + try { + final bool walletExists = await LibXelisWallet.checkWalletExists(walletId); - if (info.cachedReceivingAddress != newReceivingAddress.value) { - await info.updateReceivingAddress( - newAddress: newReceivingAddress.value, - isar: mainDB.isar, - ); + if (libXelisWallet == null) { + if (isRestore == true) { + await _restoreWallet(); + } else { + if (!walletExists) { + await _createNewWallet(); + } else { + await _existingWallet(); + } + } } + } catch (e) { + _initCompleter!.completeError(e); + rethrow; + } finally { + _initCompleter!.complete(); } - return await super.init(); + return super.init(); } @override @@ -191,7 +221,9 @@ class XelisWallet extends LibXelisWallet { @override Future pingCheck() async { - checkInitialized(); + if (libXelisWallet == null) { + return false; + } try { await libXelisWallet!.getDaemonInfo(); await handleOnline(); @@ -247,7 +279,7 @@ class XelisWallet extends LibXelisWallet { final Map nodeInfo = (json.decode(infoString) as Map).cast(); - pruningHeight = int.parse(nodeInfo['pruned_topoheight'].toString()); + pruningHeight = int.tryParse(nodeInfo['pruned_topoheight']?.toString() ?? '0') ?? 0; return int.parse(nodeInfo['topoheight'].toString()); } @@ -928,6 +960,7 @@ class XelisWallet extends LibXelisWallet { @override Future refresh({int? topoheight}) async { + if (libXelisWallet == null) { return; } await refreshMutex.protect(() async { try { final bool online = await libXelisWallet!.isOnline(); diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index e494d68db..ce84718ba 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -32,8 +32,6 @@ enum XelisTableSize { } } -enum XelisWalletOpenType { create, restore } - class XelisTableState { final bool isGenerating; final XelisTableSize currentSize; @@ -330,7 +328,7 @@ abstract class LibXelisWallet } @override - Future open({XelisWalletOpenType? openType}) async { + Future open() async { try { await connect(); } catch (e) { @@ -439,4 +437,4 @@ extension XelisTableManagement on LibXelisWallet { } }); } -} +} \ No newline at end of file From 4431d8c689091059e5cb25cb98de66c39574a62e Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 20 Mar 2025 19:55:46 -0500 Subject: [PATCH 48/50] re-enabled null checks for Xelis afer open() --- lib/wallets/wallet/impl/xelis_wallet.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 42c681579..1d113090a 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -221,9 +221,6 @@ class XelisWallet extends LibXelisWallet { @override Future pingCheck() async { - if (libXelisWallet == null) { - return false; - } try { await libXelisWallet!.getDaemonInfo(); await handleOnline(); @@ -960,7 +957,6 @@ class XelisWallet extends LibXelisWallet { @override Future refresh({int? topoheight}) async { - if (libXelisWallet == null) { return; } await refreshMutex.protect(() async { try { final bool online = await libXelisWallet!.isOnline(); From 03f4b2fdea5e394c9411d3065f7ebf841dbfcd8f Mon Sep 17 00:00:00 2001 From: Tritonn204 Date: Thu, 20 Mar 2025 21:22:51 -0500 Subject: [PATCH 49/50] removed init finally{} block for Xelis --- lib/wallets/wallet/impl/xelis_wallet.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 1d113090a..56b774194 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -181,11 +181,10 @@ class XelisWallet extends LibXelisWallet { } } } + _initCompleter!.complete(); } catch (e) { _initCompleter!.completeError(e); rethrow; - } finally { - _initCompleter!.complete(); } return super.init(); From 37f318a902e380ca035a7f568275490ffede554c Mon Sep 17 00:00:00 2001 From: Julian Date: Thu, 20 Mar 2025 20:47:10 -0600 Subject: [PATCH 50/50] linting, formatting, small cleanups, and an extra logging call --- crypto_plugins/flutter_libepiccash | 2 +- lib/wallets/wallet/impl/xelis_wallet.dart | 42 +++++++++++-------- .../wallet/intermediate/lib_xelis_wallet.dart | 4 +- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/crypto_plugins/flutter_libepiccash b/crypto_plugins/flutter_libepiccash index 0bb1b1ced..8830be2ba 160000 --- a/crypto_plugins/flutter_libepiccash +++ b/crypto_plugins/flutter_libepiccash @@ -1 +1 @@ -Subproject commit 0bb1b1ced6e0d3c66e383698f89825754c692986 +Subproject commit 8830be2ba661828d743be12df6f33d560448ed6a diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 56b774194..87de162f7 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -20,7 +20,6 @@ import '../../../services/event_bus/global_event_bus.dart'; import '../../../utilities/amount/amount.dart'; import '../../../utilities/logger.dart'; import '../../../utilities/stack_file_system.dart'; - import '../../crypto_currency/crypto_currency.dart'; import '../../models/tx_data.dart'; import '../intermediate/lib_xelis_wallet.dart'; @@ -88,7 +87,7 @@ class XelisWallet extends LibXelisWallet { final wallet = await x_wallet.createXelisWallet( name: name, directory: directory, - password: password!, + password: password, network: cryptoCurrency.network.xelisNetwork, precomputedTablesPath: tablePath, l1Low: tableState.currentSize.isLow, @@ -106,7 +105,6 @@ class XelisWallet extends LibXelisWallet { } Future _existingWallet() async { - print("EXISTING"); Logging.instance.i("Xelis: opening existing wallet"); final tablePath = await getPrecomputedTablesPath(); final tableState = await getTableState(); @@ -135,16 +133,16 @@ class XelisWallet extends LibXelisWallet { } final newReceivingAddress = - await getCurrentReceivingAddress() ?? - Address( - walletId: walletId, - derivationIndex: 0, - derivationPath: null, - value: libXelisWallet!.getAddressStr(), - publicKey: [], - type: AddressType.xelis, - subType: AddressSubType.receiving, - ); + await getCurrentReceivingAddress() ?? + Address( + walletId: walletId, + derivationIndex: 0, + derivationPath: null, + value: libXelisWallet!.getAddressStr(), + publicKey: [], + type: AddressType.xelis, + subType: AddressSubType.receiving, + ); await mainDB.updateOrPutAddresses([newReceivingAddress]); @@ -168,7 +166,9 @@ class XelisWallet extends LibXelisWallet { _initCompleter = Completer(); try { - final bool walletExists = await LibXelisWallet.checkWalletExists(walletId); + final bool walletExists = await LibXelisWallet.checkWalletExists( + walletId, + ); if (libXelisWallet == null) { if (isRestore == true) { @@ -182,8 +182,13 @@ class XelisWallet extends LibXelisWallet { } } _initCompleter!.complete(); - } catch (e) { + } catch (e, s) { _initCompleter!.completeError(e); + Logging.instance.e( + "Xelis init() rethrowing error", + error: e, + stackTrace: s, + ); rethrow; } @@ -227,7 +232,7 @@ class XelisWallet extends LibXelisWallet { } catch (_) { await handleOffline(); return false; - } + } } final _balanceUpdateMutex = Mutex(); @@ -275,7 +280,8 @@ class XelisWallet extends LibXelisWallet { final Map nodeInfo = (json.decode(infoString) as Map).cast(); - pruningHeight = int.tryParse(nodeInfo['pruned_topoheight']?.toString() ?? '0') ?? 0; + pruningHeight = + int.tryParse(nodeInfo['pruned_topoheight']?.toString() ?? '0') ?? 0; return int.parse(nodeInfo['topoheight'].toString()); } @@ -539,7 +545,7 @@ class XelisWallet extends LibXelisWallet { inputs: List.unmodifiable(inputs), outputs: List.unmodifiable(outputs), version: -1, // Version not provided - type: txType!, + type: txType, subType: txSubType, otherData: jsonEncode({ ...otherData, diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index ce84718ba..901223469 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -14,7 +14,6 @@ import '../../../utilities/logger.dart'; import '../../../utilities/stack_file_system.dart'; import '../../crypto_currency/crypto_currency.dart'; import '../../crypto_currency/intermediate/electrum_currency.dart'; -import '../wallet.dart'; import '../wallet_mixin_interfaces/mnemonic_interface.dart'; import 'external_wallet.dart'; @@ -153,7 +152,6 @@ abstract class LibXelisWallet static const String _kHasFullTablesKey = 'xelis_has_full_tables'; static const String _kGeneratingTablesKey = 'xelis_generating_tables'; static const String _kWantsFullTablesKey = 'xelis_wants_full_tables'; - static final _initMutex = Mutex(); static final _tableGenerationMutex = Mutex(); static Completer? _tableGenerationCompleter; @@ -437,4 +435,4 @@ extension XelisTableManagement on LibXelisWallet { } }); } -} \ No newline at end of file +}