diff --git a/assets/images/tari.png b/assets/images/tari.png new file mode 100644 index 000000000..b7302b204 Binary files /dev/null and b/assets/images/tari.png differ diff --git a/cw_core/lib/crypto_currency.dart b/cw_core/lib/crypto_currency.dart index 4e5367b82..454c35261 100644 --- a/cw_core/lib/crypto_currency.dart +++ b/cw_core/lib/crypto_currency.dart @@ -234,7 +234,7 @@ class CryptoCurrency extends EnumerableItem with Serializable implemen static const zano = CryptoCurrency(title: 'ZANO', tag: 'ZANO', fullName: 'Zano', raw: 96, name: 'zano', iconPath: 'assets/images/zano_icon.png', decimals: 12); static const flip = CryptoCurrency(title: 'FLIP', tag: 'ETH', fullName: 'Chainflip', raw: 97, name: 'flip', iconPath: 'assets/images/flip_icon.png', decimals: 18); static const deuro = CryptoCurrency(title: 'DEURO', tag: 'ETH', fullName: 'Digital Euro', raw: 98, name: 'deuro', iconPath: 'assets/images/deuro_icon.png', decimals: 18); - static const tari = CryptoCurrency(title: 'tXTR', fullName: 'Tari', raw: 99, name: 'tari', iconPath: 'assets/images/.png', decimals: 18); // ToDo + static const tari = CryptoCurrency(title: 'tXTR', fullName: 'Tari', raw: 99, name: 'tari', iconPath: 'assets/images/tari.png', decimals: 8); static final Map _rawCurrencyMap = [...all, ...havenCurrencies].fold>({}, (acc, item) { diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart index 38fcde9e1..0f9ac249f 100644 --- a/cw_core/lib/node.dart +++ b/cw_core/lib/node.dart @@ -106,6 +106,7 @@ class Node extends HiveObject with Keyable { case WalletType.decred: return Uri.parse( "http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") || path!.isEmpty ? path : "/$path"}"); + case WalletType.tari: // ToDo: Maybe connect to node case WalletType.none: throw Exception('Unexpected type ${type.toString()} for Node uri'); } @@ -170,6 +171,8 @@ class Node extends HiveObject with Keyable { return requestZanoNode(); case WalletType.decred: return requestDecredNode(); + case WalletType.tari: + return requestTariNode(); case WalletType.none: return false; } @@ -373,6 +376,21 @@ class Node extends HiveObject with Keyable { return false; } } + + Future requestTariNode() async { + if (uri.host == "default-tari-seed-nodes") { + // Just show default port as ok. The wallet will connect to a list of known + // nodes automatically. + return true; + } + try { + final socket = await Socket.connect(uri.host, uri.port, timeout: Duration(seconds: 5)); + socket.destroy(); + return true; + } catch (_) { + return false; + } + } } /// https://github.com/ManyMath/digest_auth/ diff --git a/cw_core/lib/wallet_type.dart b/cw_core/lib/wallet_type.dart index 46f0b2163..b62c425d0 100644 --- a/cw_core/lib/wallet_type.dart +++ b/cw_core/lib/wallet_type.dart @@ -139,7 +139,7 @@ WalletType deserializeFromInt(int raw) { case 13: return WalletType.decred; case 14: - return WalletType.decred; + return WalletType.tari; default: throw Exception( 'Unexpected token: $raw for WalletType deserializeFromInt'); diff --git a/cw_tari/lib/tari_wallet.dart b/cw_tari/lib/tari_wallet.dart index ca834bcd8..8d1c77a14 100644 --- a/cw_tari/lib/tari_wallet.dart +++ b/cw_tari/lib/tari_wallet.dart @@ -13,6 +13,7 @@ import 'package:cw_tari/tari_balance.dart'; import 'package:cw_tari/tari_transaction_history.dart'; import 'package:cw_tari/tari_transaction_info.dart'; import 'package:cw_tari/tari_wallet_addresses.dart'; +import 'package:cw_tari/transaction_credentials.dart'; import 'package:mobx/mobx.dart'; import 'package:tari/tari.dart' as tari; @@ -37,6 +38,7 @@ abstract class TariWalletBase }), super(walletInfo) { this.walletInfo = walletInfo; + transactionHistory = TariTransactionHistory(); } final tari.TariWallet _walletFfi; @@ -54,6 +56,8 @@ abstract class TariWalletBase late ObservableMap balance; Future init() async { + walletInfo.address = _walletFfi.getEmojiID().emojiId; + await walletAddresses.init(); await transactionHistory.init(); @@ -94,7 +98,9 @@ abstract class TariWalletBase try { syncStatus = AttemptingSyncStatus(); - // ToDo + _walletFfi.startRecovery((_, int status, int val1, int val2) { + print('recoveryCallback called $status $val1 $val2'); + }); syncStatus = SyncedSyncStatus(); } catch (e) { @@ -104,6 +110,9 @@ abstract class TariWalletBase @override Future createTransaction(Object credentials) async { + final tariCredentials = credentials as TariTransactionCredentials; + + // _walletFfi.sendTx(destination, amount, feePerGram, message, isOneSided) // ToDo throw UnimplementedError(); } @@ -129,7 +138,7 @@ abstract class TariWalletBase } @override - String? get seed => _walletFfi.getMnemonic(); + String get seed => _walletFfi.getMnemonic(); @override String? get privateKey => null; diff --git a/cw_tari/lib/tari_wallet_service.dart b/cw_tari/lib/tari_wallet_service.dart index 2940bb09e..d0f744f30 100644 --- a/cw_tari/lib/tari_wallet_service.dart +++ b/cw_tari/lib/tari_wallet_service.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:cw_core/pathForWallet.dart'; -import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_credentials.dart'; @@ -11,6 +10,7 @@ import 'package:cw_core/wallet_type.dart'; import 'package:cw_tari/callback.dart'; import 'package:cw_tari/tari_wallet.dart'; import 'package:hive/hive.dart'; +import 'package:tari/ffi.dart' as tariffi; import 'package:tari/tari.dart' as tari; class TariNewWalletCredentials extends WalletCredentials { @@ -73,7 +73,7 @@ class TariWalletService extends WalletService< try { final path = await pathForWallet(name: credentials.name, type: getType()); - final connection = tari.getTorConnection(); + final connection = tariffi.FFITariTransportConfig(); final config = tari.getWalletConfig( path: path, transport: connection, @@ -125,7 +125,7 @@ class TariWalletService extends WalletService< Future openWallet(String name, String password) async { try { final path = await pathForWallet(name: name, type: getType()); - final connection = tari.getTorConnection(); + final connection = tariffi.FFITariTransportConfig(); final config = tari.getWalletConfig( path: path, transport: connection, @@ -225,7 +225,7 @@ class TariWalletService extends WalletService< try { final path = await pathForWallet(name: credentials.name, type: getType()); - final connection = tari.getTorConnection(); + final connection = tariffi.FFITariTransportConfig(); final config = tari.getWalletConfig( path: path, transport: connection, @@ -234,7 +234,6 @@ class TariWalletService extends WalletService< commsConfig: config, passphrase: credentials.password!, mnemonic: credentials.mnemonic, - seedPassphrase: credentials.passphrase ?? "", logPath: "$path/logs/wallet.log", callbackReceivedTransaction: CallbackPlaceholders.callbackReceivedTransaction, callbackReceivedTransactionReply: CallbackPlaceholders.callbackReceivedTransactionReply, diff --git a/cw_tari/lib/transaction_credentials.dart b/cw_tari/lib/transaction_credentials.dart new file mode 100644 index 000000000..a8391351e --- /dev/null +++ b/cw_tari/lib/transaction_credentials.dart @@ -0,0 +1,8 @@ +import 'package:cw_core/output_info.dart'; + +class TariTransactionCredentials { + TariTransactionCredentials(this.outputs, {this.feeRate}); + + final List outputs; + final int? feeRate; +} diff --git a/cw_tari/pubspec.yaml b/cw_tari/pubspec.yaml index 8eeeb3fdb..7c4e7005e 100644 --- a/cw_tari/pubspec.yaml +++ b/cw_tari/pubspec.yaml @@ -23,5 +23,6 @@ dev_dependencies: flutter_lints: ^5.0.0 build_runner: ^2.4.7 mobx_codegen: ^2.0.7 + mockito: ^5.4.5 flutter: diff --git a/cw_tari/test/mock/path_provider.dart b/cw_tari/test/mock/path_provider.dart new file mode 100644 index 000000000..7902d5bf0 --- /dev/null +++ b/cw_tari/test/mock/path_provider.dart @@ -0,0 +1,29 @@ +import 'package:mockito/mockito.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +class MockPathProviderPlatform extends Mock + with MockPlatformInterfaceMixin + implements PathProviderPlatform { + Future getTemporaryPath() => throw UnimplementedError(); + + Future getApplicationSupportPath() => throw UnimplementedError(); + + Future getLibraryPath() => throw UnimplementedError(); + + Future getApplicationDocumentsPath() async => "./test/data"; + + Future getExternalStoragePath() => throw UnimplementedError(); + + Future> getExternalCachePaths() => throw UnimplementedError(); + + Future getDownloadsPath() => throw UnimplementedError(); + + @override + Future getApplicationCachePath() => throw UnimplementedError(); + + @override + Future?> getExternalStoragePaths({StorageDirectory? type}) => + throw UnimplementedError(); +} diff --git a/cw_tari/test/tari_wallet_service_test.dart b/cw_tari/test/tari_wallet_service_test.dart new file mode 100644 index 000000000..9774f2e4f --- /dev/null +++ b/cw_tari/test/tari_wallet_service_test.dart @@ -0,0 +1,99 @@ +import 'dart:io'; + +import 'package:cw_core/wallet_base.dart'; +import 'package:cw_core/wallet_info.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:cw_tari/tari_wallet_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:hive/hive.dart'; +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; + +import 'mock/path_provider.dart'; + +Future main() async { + print(Directory.current); + + group("TariWalletService Tests", () { + Hive.init('./test/data/db'); + late TariWalletService walletService; + + setUpAll(() async { + PathProviderPlatform.instance = MockPathProviderPlatform(); + + final Box walletInfoSource = + await Hive.openBox('testWalletInfo'); + + walletService = TariWalletService(walletInfoSource); + }); + + tearDownAll(() { + Directory('./test/data').deleteSync(recursive: true); + }); + + group("Create wallet", () { + test("Create Tari Wallet", () async { + final credentials = _getTestCreateCredentials(name: 'Create Wallet'); + final wallet = await walletService.create(credentials); + + expect(wallet.seed.split(" ").length, 24); + }); + }); + + group("Restore wallet", () { + test('Tari Seed', () async { + final credentials = _getTestRestoreCredentials( + name: 'Restore Wallet', + mnemonic: + 'park snow bring damp venture palm rocket cactus hole hunt save broken swallow coach state relief census pride penalty sound jazz romance obvious canyon'); + + final wallet = await walletService.restoreFromSeed(credentials); + expect(wallet.walletAddresses.primaryAddress, + '๐ŸŒˆ๐ŸŒŠ๐Ÿ๐Ÿšฒ๐ŸŒ๐Ÿ˜ฑ๐Ÿ’ฆ๐Ÿ”ซ๐Ÿ‹๐Ÿ“Ž๐Ÿ‘ฃ๐Ÿ›๐ŸŒ™๐Ÿค–๐Ÿ‘€๐Ÿ’ป๐ŸŒŠ๐Ÿฐ๐Ÿ†๐ŸŽท๐Ÿคข๐Ÿšœ๐ŸŽท๐ŸŽฏ๐Ÿบ๐Ÿ‘พ๐Ÿ›ต๐Ÿผ๐ŸŽฐ๐Ÿ’๐Ÿšฝ๐Ÿ””๐Ÿ‘๐ŸŽฐ๐Ÿ”จ๐Ÿฆ€๐Ÿฃ๐Ÿ๐Ÿญ๐Ÿ˜‡๐ŸŽป๐Ÿ€๐Ÿ’จ๐Ÿ‘–๐Ÿ‘›๐Ÿ’๐Ÿ”ง๐Ÿ๐ŸŽ๐Ÿฏ๐Ÿฐ๐Ÿš๐ŸŒฝ๐Ÿงข๐ŸŽก๐Ÿš‚๐ŸŽก๐Ÿฉ๐Ÿฎ๐Ÿšข๐Ÿšฆ๐Ÿ’ผ๐Ÿค ๐Ÿ’๐Ÿค ๐ŸŽ“๐Ÿ”’'); + }); + }); + }); +} + +TariRestoreWalletFromSeedCredentials _getTestRestoreCredentials({ + required String name, + required String mnemonic, +}) { + final credentials = TariRestoreWalletFromSeedCredentials( + name: name, mnemonic: mnemonic, passphrase: '', password: "test"); + + credentials.walletInfo = WalletInfo.external( + id: WalletBase.idFor(name, WalletType.monero), + name: name, + type: WalletType.monero, + isRecovery: true, + restoreHeight: credentials.height ?? 0, + date: DateTime.now(), + path: '', + dirPath: '', + address: '', + ); + return credentials; +} + +TariNewWalletCredentials _getTestCreateCredentials({ + required String name, +}) { + final credentials = TariNewWalletCredentials( + name: name, + password: "test", + passphrase: '', + ); + + credentials.walletInfo = WalletInfo.external( + id: WalletBase.idFor(name, WalletType.tari), + name: name, + type: WalletType.tari, + isRecovery: false, + restoreHeight: credentials.height ?? 0, + date: DateTime.now(), + path: '', + dirPath: '', + address: '', + ); + return credentials; +} diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d3ba59827..e83f934f3 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -198,40 +198,40 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/wakelock_plus/ios" SPEC CHECKSUMS: - connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d + connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90 - cw_decred: 9c0e1df74745b51a1289ec5e91fb9e24b68fa14a - cw_mweb: 22cd01dfb8ad2d39b15332006f22046aaa8352a3 - device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7 - device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 - devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926 + cw_decred: a02cf30175a46971c1e2fa22c48407534541edc6 + cw_mweb: 3aea2fb35b2bd04d8b2d21b83216f3b8fb768d85 + device_display_brightness: 04374ebd653619292c1d996f00f42877ea19f17f + device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89 + devicelocale: bd64aa714485a8afdaded0892c1e7d5b7f680cf8 DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 - fast_scanner: 44c00940355a51258cd6c2085734193cd23d95bc - file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 + fast_scanner: 2cb1ad3e69e645e9980fb4961396ce5804caa3e3 + file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 - flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb - flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83 - flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be - fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f - in_app_review: a31b5257259646ea78e0e35fc914979b0031d011 - integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 + flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 + flutter_local_authentication: 989278c681612f1ee0e36019e149137f114b9d7f + flutter_mailer: 3a8cd4f36c960fb04528d5471097270c19fec1c4 + flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418 + fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1 + in_app_review: 5596fe56fab799e8edb3561c03d053363ab13457 + integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 - package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 + package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 + path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8 - sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986 - share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12 + sensitive_clipboard: 161e9abc3d56b3131309d8a321eb4690a803c16b + share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + sp_scanner: b1bc9321690980bdb44bba7ec85d5543e716d1b5 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 - uni_links: d97da20c7701486ba192624d99bffaaffcfc298a - universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6 - url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe - wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56 + uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152 + universal_ble: ff19787898040d721109c6324472e5dd4bc86adc + url_launcher_ios: 694010445543906933d732453a59da0a173ae33d + wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 PODFILE CHECKSUM: e448f662d4c41f0c0b1ccbb78afd57dbf895a597 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index d9ff6b66e..c70ecef49 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ CFEFC24F82F78FE747DF1D22 /* LnurlPayInfo.swift in Resources */ = {isa = PBXBuildFile; fileRef = 58C22CBD8C22B9D6023D59F8 /* LnurlPayInfo.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; }; D0D7A0D4E13F31C4E02E235B /* ReceivePayment.swift in Resources */ = {isa = PBXBuildFile; fileRef = 91C524F800843E0A3F17E004 /* ReceivePayment.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; }; D3AD73A327249AFE8F016A51 /* BreezSDK.swift in Resources */ = {isa = PBXBuildFile; fileRef = ABD6FCBB0F4244B090459128 /* BreezSDK.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; }; + D756D0B62DB7AC0C006F8689 /* TariWallet.xcframework in CopyFiles */ = {isa = PBXBuildFile; fileRef = D76455EF2DB7A0B000929BAA /* TariWallet.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; F5EE19868D6F10D814BF73AD /* SDKNotificationService.swift in Resources */ = {isa = PBXBuildFile; fileRef = 41102141140E57B1DC27FBA1 /* SDKNotificationService.swift */; settings = {ASSET_TAGS = (BreezSDK, ); }; }; /* End PBXBuildFile section */ @@ -43,6 +44,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + D756D0B62DB7AC0C006F8689 /* TariWallet.xcframework in CopyFiles */, CE918BF82D533ECE007F186E /* MoneroWallet.xcframework in CopyFiles */, CE918BFA2D533ED4007F186E /* WowneroWallet.xcframework in CopyFiles */, CE918BFC2D533ED8007F186E /* ZanoWallet.xcframework in CopyFiles */, @@ -89,6 +91,7 @@ CE918BF92D533ED4007F186E /* WowneroWallet.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = WowneroWallet.xcframework; sourceTree = ""; }; CE918BFB2D533ED8007F186E /* ZanoWallet.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = ZanoWallet.xcframework; sourceTree = ""; }; D139E30AEB36740C21C00A9E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + D76455EF2DB7A0B000929BAA /* TariWallet.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = TariWallet.xcframework; sourceTree = ""; }; D7CD6B6020744E8FA471915D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DCEA540E3586164FB47AD13E /* LnurlPayInvoice.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LnurlPayInvoice.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/Task/LnurlPayInvoice.swift"; sourceTree = ""; }; F42258C3697CFE3C8C8D1933 /* ServiceLogger.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ServiceLogger.swift; path = "../.symlinks/plugins/breez_sdk/ios/bindings-swift/Sources/BreezSDK/ServiceLogger.swift"; sourceTree = ""; }; @@ -110,6 +113,7 @@ 06957875428D0F5AAE053765 /* Frameworks */ = { isa = PBXGroup; children = ( + D76455EF2DB7A0B000929BAA /* TariWallet.xcframework */, CE918BFB2D533ED8007F186E /* ZanoWallet.xcframework */, CE918BF92D533ED4007F186E /* WowneroWallet.xcframework */, CE918BF72D533ECE007F186E /* MoneroWallet.xcframework */, diff --git a/lib/src/screens/dashboard/widgets/menu_widget.dart b/lib/src/screens/dashboard/widgets/menu_widget.dart index dbf55d046..3ff14e1de 100644 --- a/lib/src/screens/dashboard/widgets/menu_widget.dart +++ b/lib/src/screens/dashboard/widgets/menu_widget.dart @@ -39,7 +39,8 @@ class MenuWidgetState extends State { this.tronIcon = Image.asset('assets/images/trx_icon.png'), this.wowneroIcon = Image.asset('assets/images/wownero_icon.png'), this.zanoIcon = Image.asset('assets/images/zano_icon.png'), - this.decredIcon = Image.asset('assets/images/decred_menu.png'); + this.decredIcon = Image.asset('assets/images/decred_menu.png'), + this.tariIcon = Image.asset('assets/images/tari.png'); final largeScreen = 731; @@ -66,6 +67,7 @@ class MenuWidgetState extends State { Image wowneroIcon; Image zanoIcon; Image decredIcon; + Image tariIcon; @override void initState() { @@ -254,6 +256,8 @@ class MenuWidgetState extends State { return zanoIcon; case WalletType.decred: return decredIcon; + case WalletType.tari: + return tariIcon; default: throw Exception('No icon for ${type.toString()}'); } diff --git a/lib/tari/cw_tari.dart b/lib/tari/cw_tari.dart index e75ece680..2c8ce7549 100644 --- a/lib/tari/cw_tari.dart +++ b/lib/tari/cw_tari.dart @@ -5,9 +5,8 @@ class CWTari extends Tari { return []; // ToDo } - WalletService createTariWalletService(Box walletInfoSource) { - return TariWalletService(walletInfoSource); - } + WalletService createTariWalletService(Box walletInfoSource) => + TariWalletService(walletInfoSource); WalletCredentials createTariNewWalletCredentials( {required String name, diff --git a/lib/utils/address_formatter.dart b/lib/utils/address_formatter.dart index f2083c772..5a728b07f 100644 --- a/lib/utils/address_formatter.dart +++ b/lib/utils/address_formatter.dart @@ -16,6 +16,8 @@ class AddressFormatter { final isMWEB = address.startsWith('ltcmweb'); final chunkSize = walletType != null ? _getChunkSize(walletType) : 4; + if (walletType == WalletType.tari) return Text(address, style: evenTextStyle,); + if (shouldTruncate) { return _buildTruncatedAddress( address: cleanAddress, @@ -158,4 +160,4 @@ class AddressFormatter { return 4; } } -} \ No newline at end of file +} diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 689f0ea03..72576eb4d 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -2,6 +2,8 @@ PODS: - connectivity_plus (0.0.1): - FlutterMacOS - ReachabilitySwift + - cw_decred (0.0.1): + - FlutterMacOS - cw_mweb (0.0.1): - FlutterMacOS - device_info_plus (0.0.1): @@ -44,6 +46,7 @@ PODS: DEPENDENCIES: - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) + - cw_decred (from `Flutter/ephemeral/.symlinks/plugins/cw_decred/macos`) - cw_mweb (from `Flutter/ephemeral/.symlinks/plugins/cw_mweb/macos`) - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) - devicelocale (from `Flutter/ephemeral/.symlinks/plugins/devicelocale/macos`) @@ -70,6 +73,8 @@ SPEC REPOS: EXTERNAL SOURCES: connectivity_plus: :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos + cw_decred: + :path: Flutter/ephemeral/.symlinks/plugins/cw_decred/macos cw_mweb: :path: Flutter/ephemeral/.symlinks/plugins/cw_mweb/macos device_info_plus: @@ -106,26 +111,27 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos SPEC CHECKSUMS: - connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747 - cw_mweb: 7440b12ead811dda972a9918442ea2a458e8742c - device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f - devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225 - fast_scanner: d31bae07e2653403a69dac99fb710c1722b16a97 - flutter_inappwebview_macos: bdf207b8f4ebd58e86ae06cd96b147de99a67c9b - flutter_local_authentication: 85674893931e1c9cfa7c9e4f5973cb8c56b018b0 - flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea + connectivity_plus: e74b9f74717d2d99d45751750e266e55912baeb5 + cw_decred: 246ada7e0020a6b29e769f7a26653fcfc0ad752f + cw_mweb: 4746a3b5cc5bd4afe6fadd2481c4f7b239e391d0 + device_info_plus: b0fafc687fb901e2af612763340f1b0d4352f8e5 + devicelocale: 456a07c045d3113938aa4983065bd8526e2af792 + fast_scanner: a4ead8e56f185cd565e25250fdb97fa669ea1d2e + flutter_inappwebview_macos: c2d68649f9f8f1831bfcd98d73fd6256366d9d1d + flutter_local_authentication: 2f9a2682f498abcc12d7e9729b5007a947170fdc + flutter_secure_storage_macos: 3dacac420d84c4d0dc5e868194ee43c8664ec797 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - in_app_review: a6a031b9acd03c7d103e341aa334adf2c493fb93 + in_app_review: 0599bccaed5e02f6bed2b0d30d16f86b63ed8638 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 - package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + package_info_plus: f0052d280d17aa382b932f399edf32507174e870 + path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda - share_plus: 1fa619de8392a4398bfaf176d441853922614e89 - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - sp_scanner: 269d96e0ec3173e69156be7239b95182be3b8303 - universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6 - url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 - wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269 + share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + sp_scanner: d9316427b628dd86d6e9e3c5d42ed6b4b410157c + universal_ble: ff19787898040d721109c6324472e5dd4bc86adc + url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673 + wakelock_plus: 21ddc249ac4b8d018838dbdabd65c5976c308497 PODFILE CHECKSUM: 65ec1541137fb5b35d00490dec1bb48d4d9586bb diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index f28097b88..47cc00a2b 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -15,7 +15,7 @@ @@ -31,7 +31,7 @@ @@ -54,7 +54,7 @@ @@ -71,7 +71,7 @@ diff --git a/scripts/android/pubspec_gen.sh b/scripts/android/pubspec_gen.sh index b980f877d..8e74c8bb2 100755 --- a/scripts/android/pubspec_gen.sh +++ b/scripts/android/pubspec_gen.sh @@ -10,7 +10,7 @@ case $APP_ANDROID_TYPE in CONFIG_ARGS="--monero" ;; $CAKEWALLET) - CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron --wownero --zano --decred" + CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron --wownero --zano --decred --tari" ;; esac diff --git a/scripts/ios/app_config.sh b/scripts/ios/app_config.sh index b642d67e4..1b04b3acc 100755 --- a/scripts/ios/app_config.sh +++ b/scripts/ios/app_config.sh @@ -31,7 +31,7 @@ case $APP_IOS_TYPE in ;; $CAKEWALLET) - CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron --wownero --zano --decred" + CONFIG_ARGS="--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron --wownero --zano --decred --tari" ;; esac diff --git a/scripts/ios/gen_framework_tari.sh b/scripts/ios/gen_framework_tari.sh new file mode 100755 index 000000000..720c460eb --- /dev/null +++ b/scripts/ios/gen_framework_tari.sh @@ -0,0 +1,157 @@ +#!/bin/sh +set -e + +IOS_DIR="$(pwd)/../../ios" +DYLIB_PATH="$(pwd)/../../scripts/tari" +TMP_DIR="${IOS_DIR}/tmp" + +rm -rf "${IOS_DIR:?}/TariWallet.xcframework" +rm -rf "${IOS_DIR:?}/TariWallet.framework" +rm -rf "$TMP_DIR" +mkdir -p "$TMP_DIR" + +write_info_plist() { + framework_bundle="$1" + framework_name="$2" + target="$3" + plist_path="${framework_bundle}/Info.plist" + + if [[ "x$target" = "xiossimulator" ]]; then + platform="iPhoneSimulator" + dtplatformname="iphonesimulator" + dtsdkname="iphonesimulator17.4" + else + platform="iPhoneOS" + dtplatformname="iphoneos" + dtsdkname="iphoneos17.4" + fi + + cat > "$plist_path" < + + + + BuildMachineOSBuild + 23E224 + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${framework_name} + CFBundleIdentifier + com.fotolockr.${framework_name} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${framework_name} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ??? + CFBundleSupportedPlatforms + + ${platform} + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21E210 + DTPlatformName + ${dtplatformname} + DTPlatformVersion + 17.4 + DTSDKBuild + 21E210 + DTSDKName + ${dtsdkname} + DTXcode + 1530 + DTXcodeBuild + 15E204a + MinimumOSVersion + 16.0 + UIDeviceFamily + + 1 + 2 + + UIRequiredDeviceCapabilities + + arm64 + + + +EOF + plutil -convert binary1 "$plist_path" +} + +create_framework() { + framework_name="$2" + target="$3" + out_dir="$4" + + echo "Creating ${framework_name}.framework for target ${target} in ${out_dir}..." + + framework_bundle="${out_dir}/${framework_name}.framework" + + rm -rf "$framework_bundle" + mkdir -p "$framework_bundle" + + input_dylib="${DYLIB_PATH}/aarch64-apple-ios/libminotari_wallet_ffi.dylib" + if [[ ! -f "$input_dylib" ]]; then + echo "Error: Input dylib not found: $input_dylib" + exit 1 + fi + + lipo -create "$input_dylib" -output "${framework_bundle}/${framework_name}" + echo "Created binary: ${framework_bundle}/${framework_name}" + + write_info_plist "$framework_bundle" "$framework_name" "$target" +} + +create_xcframework() { + framework_name="$1" + device_framework="$2" + simulator_framework="$3" + xcframework_output="$4" + + echo "Creating ${xcframework_output} by bundling:" + echo " Device framework: ${device_framework}" + echo " Simulator framework: ${simulator_framework}" + + xcodebuild -create-xcframework \ + -framework "$device_framework" \ + -output "$xcframework_output" + + echo "Created XCFramework: ${xcframework_output}" +} + +wallets=("tari") +framework_names=("TariWallet") + +for i in "${!wallets[@]}"; do + wallet="${wallets[$i]}" + framework_name="${framework_names[$i]}" + + device_out="${TMP_DIR}/${framework_name}_device" + simulator_out="${TMP_DIR}/${framework_name}_simulator" + rm -rf "$device_out" "$simulator_out" + mkdir -p "$device_out" "$simulator_out" + + create_framework "$wallet" "$framework_name" "ios" "$device_out" +# create_framework "$wallet" "$framework_name" "iossimulator" "$simulator_out" + + device_framework="${device_out}/${framework_name}.framework" + simulator_framework="${simulator_out}/${framework_name}.framework" + xcframework_output="${IOS_DIR}/${framework_name}.xcframework" + rm -rf "$xcframework_output" + + create_xcframework "$framework_name" "$device_framework" "$simulator_framework" "$xcframework_output" +done + +echo "All XCFrameworks created successfully." + +rm -rf "$TMP_DIR" diff --git a/tool/configure.dart b/tool/configure.dart index 9f104a992..faa677576 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -11,6 +11,7 @@ const tronOutputPath = 'lib/tron/tron.dart'; const wowneroOutputPath = 'lib/wownero/wownero.dart'; const zanoOutputPath = 'lib/zano/zano.dart'; const decredOutputPath = 'lib/decred/decred.dart'; +const tariOutputPath = 'lib/tari/tari.dart'; const walletTypesPath = 'lib/wallet_types.g.dart'; const secureStoragePath = 'lib/core/secure_storage.dart'; const pubspecDefaultPath = 'pubspec_default.yaml'; @@ -1386,7 +1387,7 @@ abstract class Decred { } Future generateTari(bool hasImplementation) async { - final outputFile = File(decredOutputPath); + final outputFile = File(tariOutputPath); const tariCommonHeaders = """ import 'package:cw_core/crypto_amount_format.dart'; import 'package:cw_core/transaction_priority.dart'; @@ -1674,7 +1675,7 @@ Future generateWalletTypes({ outputContent += '\tWalletType.wownero,\n'; } - if (hasWownero) { + if (hasTari) { outputContent += '\tWalletType.tari,\n'; }