diff --git a/crypto_plugins/flutter_libepiccash b/crypto_plugins/flutter_libepiccash index f677dec0b..cd12741de 160000 --- a/crypto_plugins/flutter_libepiccash +++ b/crypto_plugins/flutter_libepiccash @@ -1 +1 @@ -Subproject commit f677dec0b34d3f9fe8fce2bc8ff5c508c3f3bb9a +Subproject commit cd12741de19e4faef39a23b7d543a2452524990a diff --git a/crypto_plugins/flutter_liblelantus b/crypto_plugins/flutter_liblelantus index 9cd241b5e..ec3cf5e8e 160000 --- a/crypto_plugins/flutter_liblelantus +++ b/crypto_plugins/flutter_liblelantus @@ -1 +1 @@ -Subproject commit 9cd241b5ea142e21c01dd7639b42603281c43287 +Subproject commit ec3cf5e8e1b90e006188aa8c323d4cd52dbfa9b9 diff --git a/crypto_plugins/flutter_libmonero b/crypto_plugins/flutter_libmonero index e48952185..26a152fea 160000 --- a/crypto_plugins/flutter_libmonero +++ b/crypto_plugins/flutter_libmonero @@ -1 +1 @@ -Subproject commit e48952185556a10f182184fd572bcb04365f5831 +Subproject commit 26a152fea3ca4b8c3f1130392a02f579c2ff218c diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart index 3e5d3e3e4..e7ce8b505 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart @@ -196,7 +196,9 @@ class _AddEditNodeViewState extends ConsumerState { case Coin.nano: case Coin.banano: - //TODO: check network/node + case Coin.stellar: + throw UnimplementedError(); + //TODO: check network/node } if (showFlushBar && mounted) { @@ -736,6 +738,7 @@ class _NodeFormState extends ConsumerState { case Coin.nano: case Coin.banano: case Coin.eCash: + case Coin.stellar: return false; case Coin.ethereum: diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart index fa69871cb..819b9f5d7 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart @@ -172,7 +172,9 @@ class _NodeDetailsViewState extends ConsumerState { case Coin.nano: case Coin.banano: - //TODO: check network/node + case Coin.stellar: + throw UnimplementedError(); + //TODO: check network/node } if (testPassed) { diff --git a/lib/services/coins/coin_service.dart b/lib/services/coins/coin_service.dart index 00a52eba5..ffb97a0a7 100644 --- a/lib/services/coins/coin_service.dart +++ b/lib/services/coins/coin_service.dart @@ -27,6 +27,7 @@ import 'package:stackwallet/services/coins/monero/monero_wallet.dart'; import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart'; import 'package:stackwallet/services/coins/nano/nano_wallet.dart'; import 'package:stackwallet/services/coins/particl/particl_wallet.dart'; +import 'package:stackwallet/services/coins/stellar/stellar_wallet.dart'; import 'package:stackwallet/services/coins/wownero/wownero_wallet.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; @@ -218,6 +219,15 @@ abstract class CoinServiceAPI { cachedClient: cachedClient, tracker: tracker); + case Coin.stellar: + return StellarWallet( + walletId: walletId, + walletName: walletName, + coin: coin, + secureStore: secureStorageInterface, + tracker: tracker, + ); + case Coin.wownero: return WowneroWallet( walletId: walletId, diff --git a/lib/services/coins/stellar/stellar_wallet.dart b/lib/services/coins/stellar/stellar_wallet.dart new file mode 100644 index 000000000..b7efcce68 --- /dev/null +++ b/lib/services/coins/stellar/stellar_wallet.dart @@ -0,0 +1,656 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:decimal/decimal.dart'; +import 'package:http/http.dart' as http; +import 'package:isar/isar.dart'; +import 'package:stackwallet/models/balance.dart' as SWBalance; +import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart' as SWTransaction; +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart' as SWAddress; +import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart'; +import 'package:stackwallet/models/paymint/fee_object_model.dart'; +import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart'; +import 'package:stackwallet/services/coins/coin_service.dart'; +import 'package:stackwallet/services/mixins/coin_control_interface.dart'; +import 'package:stackwallet/utilities/amount/amount.dart'; +import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; +import 'package:tuple/tuple.dart'; + +import '../../../db/isar/main_db.dart'; +import '../../../models/node_model.dart'; +import '../../../utilities/constants.dart'; +import '../../../utilities/default_nodes.dart'; +import '../../../utilities/enums/coin_enum.dart'; +import '../../../utilities/flutter_secure_storage_interface.dart'; +import '../../../utilities/logger.dart'; +import '../../../utilities/prefs.dart'; +import '../../event_bus/events/global/node_connection_status_changed_event.dart'; +import '../../event_bus/events/global/updated_in_background_event.dart'; +import '../../event_bus/events/global/wallet_sync_status_changed_event.dart'; +import '../../event_bus/global_event_bus.dart'; +import '../../mixins/wallet_cache.dart'; +import '../../mixins/wallet_db.dart'; +import '../../node_service.dart'; +import '../../transaction_notification_tracker.dart'; + +import 'package:stellar_flutter_sdk/stellar_flutter_sdk.dart'; + +const int MINIMUM_CONFIRMATIONS = 1; + +class StellarWallet extends CoinServiceAPI + with WalletCache, WalletDB, CoinControlInterface { + + StellarWallet({ + required String walletId, + required String walletName, + required Coin coin, + required TransactionNotificationTracker tracker, + required SecureStorageInterface secureStore, + MainDB? mockableOverride, + }) { + txTracker = tracker; + _walletId = walletId; + _walletName = walletName; + _coin = coin; + _secureStore = secureStore; + initCache(walletId, coin); + initWalletDB(mockableOverride: mockableOverride); + } + + late final TransactionNotificationTracker txTracker; + late SecureStorageInterface _secureStore; + + final StellarSDK stellarSdk = StellarSDK.PUBLIC; + + @override + bool get isFavorite => _isFavorite ??= getCachedIsFavorite(); + bool? _isFavorite; + + @override + set isFavorite(bool isFavorite) { + _isFavorite = isFavorite; + updateCachedIsFavorite(isFavorite); + } + + @override + bool get shouldAutoSync => _shouldAutoSync; + bool _shouldAutoSync = true; + + Timer? timer; + + final _prefs = Prefs.instance; + + @override + set shouldAutoSync(bool shouldAutoSync) { + if (_shouldAutoSync != shouldAutoSync) { + _shouldAutoSync = shouldAutoSync; + if (!shouldAutoSync) { + timer?.cancel(); + timer = null; + stopNetworkAlivePinging(); + } else { + startNetworkAlivePinging(); + refresh(); + } + } + } + + Timer? _networkAliveTimer; + + void startNetworkAlivePinging() { + // call once on start right away + _periodicPingCheck(); + + // then periodically check + _networkAliveTimer = Timer.periodic( + Constants.networkAliveTimerDuration, + (_) async { + _periodicPingCheck(); + }, + ); + } + + void stopNetworkAlivePinging() { + _networkAliveTimer?.cancel(); + _networkAliveTimer = null; + } + + void _periodicPingCheck() async { + bool hasNetwork = await testNetworkConnection(); + + if (_isConnected != hasNetwork) { + NodeConnectionStatus status = hasNetwork + ? NodeConnectionStatus.connected + : NodeConnectionStatus.disconnected; + + GlobalEventBus.instance.fire( + NodeConnectionStatusChangedEvent( + status, + walletId, + coin, + ), + ); + + _isConnected = hasNetwork; + if (hasNetwork) { + unawaited(refresh()); + } + } + } + + @override + String get walletName => _walletName; + late String _walletName; + + @override + set walletName(String name) => _walletName = name; + + @override + SWBalance.Balance get balance => _balance ??= getCachedBalance(); + SWBalance.Balance? _balance; + + @override + Coin get coin => _coin; + late Coin _coin; + + @override + Future confirmSend({required Map txData}) { + // TODO: implement confirmSend + throw UnimplementedError(); + } + + Future get _currentReceivingAddress => + db.getAddresses(walletId) + .filter() + .typeEqualTo(SWAddress.AddressType.unknown) + .and() + .subTypeEqualTo(SWAddress.AddressSubType.unknown) + .sortByDerivationIndexDesc() + .findFirst(); + + @override + Future get currentReceivingAddress async => + (await _currentReceivingAddress)?.value ?? await getAddressSW(); + + Future getBaseFee() async { + final nodeURI = Uri.parse("${getCurrentNode().host}:${getCurrentNode().port}"); + final httpClient = http.Client(); + FeeStatsResponse fsp = await FeeStatsRequestBuilder(httpClient, nodeURI).execute(); + return int.parse(fsp.lastLedgerBaseFee); + } + + @override + Future estimateFeeFor(Amount amount, int feeRate) async { + var baseFee = await getBaseFee(); + int fee = 100; + switch (feeRate) { + case 0: + fee = baseFee * 10; + case 1: + case 2: + fee = baseFee * 50; + case 3: + fee = baseFee * 100; + case 4: + fee = baseFee * 200; + default: + fee = baseFee * 50; + } + return Amount(rawValue: BigInt.from(fee), fractionDigits: coin.decimals); + } + + @override + Future exit() { + // TODO: implement exit + throw UnimplementedError(); + } + + NodeModel? _xlmNode; + + NodeModel getCurrentNode() { + if (_xlmNode != null) { + return _xlmNode!; + } else if (NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: coin) != null) { + return NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: coin)!; + } else { + return DefaultNodes.getNodeFor(coin); + } + } + + @override + Future get fees async { + final nodeURI = Uri.parse("${getCurrentNode().host}:${getCurrentNode().port}"); + final httpClient = http.Client(); + FeeStatsResponse fsp = await FeeStatsRequestBuilder(httpClient, nodeURI).execute(); + return FeeObject( + numberOfBlocksFast: 0, + numberOfBlocksAverage: 0, + numberOfBlocksSlow: 0, + fast: int.parse(fsp.lastLedgerBaseFee) * 100, + medium: int.parse(fsp.lastLedgerBaseFee) * 50, + slow: int.parse(fsp.lastLedgerBaseFee) * 10 + ); + } + + @override + Future fullRescan(int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) async { + await _prefs.init(); + await updateTransactions(); + await updateChainHeight(); + await updateBalance(); + } + + @override + Future generateNewAddress() { + // TODO: implement generateNewAddress + throw UnimplementedError(); + } + + @override + bool get hasCalledExit => _hasCalledExit; + bool _hasCalledExit = false; + + @override + Future initializeExisting() async { + await _prefs.init(); + } + + @override + Future initializeNew() async { + if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) { + throw Exception( + "Attempted to overwrite mnemonic on generate new wallet!"); + } + + await _prefs.init(); + + String mnemonic = await Wallet.generate24WordsMnemonic(); + final mnemonicArray = mnemonic.split(" "); + await _secureStore.write( + key: '${_walletId}_mnemonic', + value: mnemonicArray.join(" ") + ); + await _secureStore.write( + key: '${_walletId}_mnemonicPassphrase', + value: "" + ); + + Wallet wallet = await Wallet.from(mnemonic); + KeyPair keyPair = await wallet.getKeyPair(index: 0); + String address = keyPair.accountId; + + final swAddress = SWAddress.Address( + walletId: walletId, + value: address, + publicKey: keyPair.publicKey, + derivationIndex: 0, + derivationPath: null, + type: SWAddress.AddressType.unknown, // TODO: set type + subType: SWAddress.AddressSubType.unknown + ); + + await db.putAddress(swAddress); + + await Future.wait([ + updateCachedId(walletId), + updateCachedIsFavorite(false) + ]); + } + + Future getAddressSW() async { + var mnemonic = await _secureStore.read( + key: '${_walletId}_mnemonic' + ); + var wallet = await Wallet.from(mnemonic!); + var keyPair = await wallet.getKeyPair(index: 0); + return Future.value(keyPair.accountId); + } + + @override + bool get isConnected => _isConnected; + bool _isConnected = false; + + @override + bool get isRefreshing => refreshMutex; + bool refreshMutex = false; + + @override + // TODO: implement maxFee + Future get maxFee => throw UnimplementedError(); + + @override + Future> get mnemonic => mnemonicString.then((value) => value!.split(" ")); + + @override + Future get mnemonicPassphrase => _secureStore.read(key: '${_walletId}_mnemonicPassphrase'); + + @override + Future get mnemonicString => _secureStore.read(key: '${_walletId}_mnemonic'); + + @override + Future> prepareSend({required String address, required Amount amount, Map? args}) async { + try { + final feeRate = args?["feeRate"]; + var fee = 1000; + if (feeRate is FeeRateType) { + final theFees = await fees; + switch (feeRate) { + case FeeRateType.fast: + fee = theFees.fast; + case FeeRateType.slow: + fee = theFees.slow; + case FeeRateType.average: + default: + fee = theFees.medium; + } + } + Map txData = { + "fee": fee, + "address": address, + "recipientAmt": amount, + }; + + Logging.instance.log("prepare send: $txData", level: LogLevel.Info); + return txData; + } catch (e, s) { + Logging.instance.log("Error getting fees $e - $s", level: LogLevel.Error); + rethrow; + } + } + + @override + Future recoverFromMnemonic({required String mnemonic, String? mnemonicPassphrase, required int maxUnusedAddressGap, required int maxNumberOfIndexesToCheck, required int height}) async { + if ((await mnemonicString) != null || + (await this.mnemonicPassphrase) != null) { + throw Exception("Attempted to overwrite mnemonic on restore!"); + } + + var wallet = await Wallet.from(mnemonic); + var keyPair = await wallet.getKeyPair(index: 0); + var address = keyPair.accountId; + + await _secureStore.write( + key: '${_walletId}_mnemonic', value: mnemonic.trim()); + await _secureStore.write( + key: '${_walletId}_mnemonicPassphrase', + value: mnemonicPassphrase ?? "", + ); + + final swAddress = SWAddress.Address( + walletId: walletId, + value: address, + publicKey: keyPair.publicKey, + derivationIndex: 0, + derivationPath: null, + type: SWAddress.AddressType.unknown, // TODO: set type + subType: SWAddress.AddressSubType.unknown + ); + + await db.putAddress(swAddress); + + await Future.wait([ + updateCachedId(walletId), + updateCachedIsFavorite(false) + ]); + } + + Future updateChainHeight() async { + final height = await stellarSdk.ledgers + .order(RequestBuilderOrder.DESC) + .limit(1) + .execute() + .then((value) => value.records!.first.sequence); + await updateCachedChainHeight(height); + } + + Future updateTransactions() async { + List> transactionList = []; + Page payments = await stellarSdk.payments.forAccount(await getAddressSW()).order(RequestBuilderOrder.DESC).execute(); + for (OperationResponse response in payments.records!) { + if (response is PaymentOperationResponse) { + var por = response; + SWTransaction.TransactionType type; + if (por.sourceAccount == await getAddressSW()) { + type = SWTransaction.TransactionType.outgoing; + } else { + type = SWTransaction.TransactionType.incoming; + } + final amount = Amount( + rawValue: BigInt.parse(float.parse(por.amount!).toStringAsFixed(7).replaceAll(".", "")), + fractionDigits: 7, + ); + int fee = 0; + int height = 0; + var transaction = por.transaction; + if (transaction != null) { + fee = transaction.feeCharged!; + height = transaction.ledger; + } + var theTransaction = SWTransaction.Transaction( + walletId: walletId, + txid: por.transactionHash!, + timestamp: DateTime.parse(por.createdAt!).millisecondsSinceEpoch ~/ 1000, + type: type, + subType: SWTransaction.TransactionSubType.none, + amount: 0, + amountString: amount.toJsonString(), + fee: fee, + height: height, + isCancelled: false, + isLelantus: false, + slateId: "", + otherData: "", + inputs: [], + outputs: [], + nonce: 0, + numberOfMessages: null, + ); + SWAddress.Address? receivingAddress = await _currentReceivingAddress; + SWAddress.Address address = type == SWTransaction.TransactionType.incoming + ? receivingAddress! + : SWAddress.Address( + walletId: walletId, + value: por.sourceAccount!, + publicKey: KeyPair.fromAccountId(por.sourceAccount!).publicKey, + derivationIndex: 0, + derivationPath: null, + type: SWAddress.AddressType.unknown, // TODO: set type + subType: SWAddress.AddressSubType.unknown + ); + Tuple2 tuple = Tuple2(theTransaction, address); + transactionList.add(tuple); + } else if (response is CreateAccountOperationResponse) { + var caor = response; + SWTransaction.TransactionType type; + if (caor.sourceAccount == await getAddressSW()) { + type = SWTransaction.TransactionType.outgoing; + } else { + type = SWTransaction.TransactionType.incoming; + } + final amount = Amount( + rawValue: BigInt.parse(float.parse(caor.startingBalance!).toStringAsFixed(7).replaceAll(".", "")), + fractionDigits: 7, + ); + int fee = 0; + int height = 0; + var transaction = caor.transaction; + if (transaction != null) { + fee = transaction.feeCharged!; + height = transaction.ledger; + } + var theTransaction = SWTransaction.Transaction( + walletId: walletId, + txid: caor.transactionHash!, + timestamp: DateTime.parse(caor.createdAt!).millisecondsSinceEpoch ~/ 1000, + type: type, + subType: SWTransaction.TransactionSubType.none, + amount: 0, + amountString: amount.toJsonString(), + fee: fee, + height: height, + isCancelled: false, + isLelantus: false, + slateId: "", + otherData: "", + inputs: [], + outputs: [], + nonce: 0, + numberOfMessages: null, + ); + SWAddress.Address? receivingAddress = await _currentReceivingAddress; + SWAddress.Address address = type == SWTransaction.TransactionType.incoming + ? receivingAddress! + : SWAddress.Address( + walletId: walletId, + value: caor.sourceAccount!, + publicKey: KeyPair.fromAccountId(caor.sourceAccount!).publicKey, + derivationIndex: 0, + derivationPath: null, + type: SWAddress.AddressType.unknown, // TODO: set type + subType: SWAddress.AddressSubType.unknown + ); + Tuple2 tuple = Tuple2(theTransaction, address); + transactionList.add(tuple); + } + } + await db.addNewTransactionData(transactionList, walletId); + } + + Future updateBalance() async { + AccountResponse accountResponse = await stellarSdk.accounts.account(await getAddressSW()); + for (Balance balance in accountResponse.balances) { + switch (balance.assetType) { + case Asset.TYPE_NATIVE: + _balance = SWBalance.Balance( + total: Amount( + rawValue: BigInt.from(float.parse(balance.balance) * 10000000 - 10000000), // Minus 1 XLM for account activation fee + fractionDigits: 7, + ), + spendable: Amount( + rawValue: BigInt.from(float.parse(balance.balance) * 10000000 - 10000000), // Minus 1 XLM for account activation fee + fractionDigits: 7, + ), + blockedTotal: Amount( + rawValue: BigInt.from(0), + fractionDigits: 7, + ), + pendingSpendable: Amount( + rawValue: BigInt.from(0), + fractionDigits: 7, + ), + ); + Logging.instance.log(_balance, level: LogLevel.Info); + await updateCachedBalance(_balance!); + } + } + } + + @override + Future refresh() async { + if (refreshMutex) { + Logging.instance.log( + "$walletId $walletName refreshMutex denied", + level: LogLevel.Info, + ); + return; + } else { + refreshMutex = true; + } + + try { + await _prefs.init(); + + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.syncing, + walletId, + coin, + ), + ); + + await updateChainHeight(); + await updateTransactions(); + await updateBalance(); + + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.synced, + walletId, + coin, + ), + ); + + if (shouldAutoSync) { + timer ??= Timer.periodic(const Duration(seconds: 30), (timer) async { + Logging.instance.log( + "Periodic refresh check for $walletId $walletName in object instance: $hashCode", + level: LogLevel.Info); + + await refresh(); + GlobalEventBus.instance.fire( + UpdatedInBackgroundEvent( + "New data found in $walletId $walletName in background!", + walletId, + ), + ); + }); + } + } catch (e, s) { + Logging.instance.log( + "Failed to refresh stellar wallet $walletId: '$walletName': $e\n$s", + level: LogLevel.Warning, + ); + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.unableToSync, + walletId, + coin, + ), + ); + } + + refreshMutex = false; + } + + @override + int get storedChainHeight => getCachedChainHeight(); + + @override + Future testNetworkConnection() { + // TODO: implement testNetworkConnection + throw UnimplementedError(); + } + + @override + Future> get transactions => db.getTransactions(walletId).findAll(); + + @override + Future updateNode(bool shouldRefresh) async { + _xlmNode = NodeService(secureStorageInterface: _secureStore) + .getPrimaryNodeFor(coin: coin) ?? + DefaultNodes.getNodeFor(coin); + + if (shouldRefresh) { + unawaited(refresh()); + } + } + + @override + Future updateSentCachedTxData(Map txData) { + // TODO: implement updateSentCachedTxData + throw UnimplementedError(); + } + + @override + // TODO: implement utxos + Future> get utxos => throw UnimplementedError(); + + @override + bool validateAddress(String address) { + return RegExp(r"^[G][A-Z0-9]{55}$").hasMatch(address); + } + + @override + String get walletId => _walletId; + late String _walletId; +} \ No newline at end of file diff --git a/lib/themes/color_theme.dart b/lib/themes/color_theme.dart index bcfa45ac9..87020ada7 100644 --- a/lib/themes/color_theme.dart +++ b/lib/themes/color_theme.dart @@ -28,6 +28,7 @@ class CoinThemeColorDefault { Color get namecoin => const Color(0xFF91B1E1); Color get wownero => const Color(0xFFED80C1); Color get particl => const Color(0xFF8175BD); + Color get stellar => const Color(0xFFE8E8E8); // TODO: find color Color get nano => const Color(0xFF209CE9); Color get banano => const Color(0xFFFBDD11); @@ -62,6 +63,8 @@ class CoinThemeColorDefault { return wownero; case Coin.particl: return particl; + case Coin.stellar: + return stellar; case Coin.nano: return nano; case Coin.banano: diff --git a/lib/themes/stack_colors.dart b/lib/themes/stack_colors.dart index b9e58a5ca..f653b7eac 100644 --- a/lib/themes/stack_colors.dart +++ b/lib/themes/stack_colors.dart @@ -1707,6 +1707,8 @@ class StackColors extends ThemeExtension { return _coin.wownero; case Coin.particl: return _coin.particl; + case Coin.stellar: + return _coin.stellar; case Coin.nano: return _coin.nano; case Coin.banano: diff --git a/lib/utilities/address_utils.dart b/lib/utilities/address_utils.dart index 0093e1d00..c2e759524 100644 --- a/lib/utilities/address_utils.dart +++ b/lib/utilities/address_utils.dart @@ -105,6 +105,8 @@ class AddressUtils { return Address.validateAddress(address, namecoin, namecoin.bech32!); case Coin.particl: return Address.validateAddress(address, particl); + case Coin.stellar: + return RegExp(r"^[G][A-Z0-9]{55}$").hasMatch(address); case Coin.nano: return NanoAccounts.isValid(NanoAccountType.NANO, address); case Coin.banano: diff --git a/lib/utilities/amount/amount_unit.dart b/lib/utilities/amount/amount_unit.dart index 91fef8bc7..37939f1cc 100644 --- a/lib/utilities/amount/amount_unit.dart +++ b/lib/utilities/amount/amount_unit.dart @@ -50,6 +50,7 @@ enum AmountUnit { case Coin.dogecoin: case Coin.eCash: case Coin.epicCash: + case Coin.stellar: // TODO: check if this is correct return AmountUnit.values.sublist(0, 4); case Coin.monero: diff --git a/lib/utilities/block_explorers.dart b/lib/utilities/block_explorers.dart index 7ff0cf349..ae27fae02 100644 --- a/lib/utilities/block_explorers.dart +++ b/lib/utilities/block_explorers.dart @@ -54,6 +54,8 @@ Uri getDefaultBlockExplorerUrlFor({ return Uri.parse("https://chainz.cryptoid.info/nmc/tx.dws?$txid.htm"); case Coin.particl: return Uri.parse("https://chainz.cryptoid.info/part/tx.dws?$txid.htm"); + case Coin.stellar: + return Uri.parse("https://stellarchain.io/tx/$txid"); case Coin.nano: return Uri.parse("https://www.nanolooker.com/block/$txid"); case Coin.banano: diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart index 2dd7be287..665ae3169 100644 --- a/lib/utilities/constants.dart +++ b/lib/utilities/constants.dart @@ -43,6 +43,7 @@ abstract class Constants { BigInt.parse("1000000000000000000000000000000"); // 1*10^30 static final BigInt _satsPerCoinBanano = BigInt.parse("100000000000000000000000000000"); // 1*10^29 + static final BigInt _satsPerCoinStellar = BigInt.from(10000000); // https://developers.stellar.org/docs/fundamentals-and-concepts/stellar-data-structures/assets#amount-precision static final BigInt _satsPerCoin = BigInt.from(100000000); static const int _decimalPlaces = 8; static const int _decimalPlacesNano = 30; @@ -51,6 +52,7 @@ abstract class Constants { static const int _decimalPlacesMonero = 12; static const int _decimalPlacesEthereum = 18; static const int _decimalPlacesECash = 2; + static const int _decimalPlacesStellar = 7; static const int notificationsMax = 0xFFFFFFFF; static const Duration networkAliveTimerDuration = Duration(seconds: 10); @@ -96,6 +98,9 @@ abstract class Constants { case Coin.eCash: return _satsPerCoinECash; + + case Coin.stellar: + return _satsPerCoinStellar; } } @@ -133,6 +138,9 @@ abstract class Constants { case Coin.eCash: return _decimalPlacesECash; + + case Coin.stellar: + return _decimalPlacesStellar; } } @@ -155,6 +163,7 @@ abstract class Constants { case Coin.namecoin: case Coin.particl: case Coin.nano: + case Coin.stellar: values.addAll([24, 12]); break; case Coin.banano: @@ -214,6 +223,9 @@ abstract class Constants { case Coin.nano: // TODO: Verify this case Coin.banano: // TODO: Verify this return 1; + + case Coin.stellar: + return 5; } } @@ -241,6 +253,7 @@ abstract class Constants { case Coin.nano: case Coin.banano: + case Coin.stellar: return 24; case Coin.monero: diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart index c8ff94120..5ad9cd39a 100644 --- a/lib/utilities/default_nodes.dart +++ b/lib/utilities/default_nodes.dart @@ -181,6 +181,18 @@ abstract class DefaultNodes { isFailover: true, isDown: false); + static NodeModel get stellar => NodeModel( + host: "https://horizon.stellar.org", + port: 443, + name: defaultName, + id: _nodeId(Coin.stellar), + useSSL: true, + enabled: true, + coinName: Coin.stellar.name, + isFailover: true, + isDown: false + ); + static NodeModel get nano => NodeModel( host: "https://rainstorm.city/api", port: 443, @@ -301,6 +313,9 @@ abstract class DefaultNodes { case Coin.particl: return particl; + case Coin.stellar: + return stellar; + case Coin.nano: return nano; diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart index c656b2c62..e66822738 100644 --- a/lib/utilities/enums/coin_enum.dart +++ b/lib/utilities/enums/coin_enum.dart @@ -27,6 +27,7 @@ import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart' import 'package:stackwallet/services/coins/nano/nano_wallet.dart' as nano; import 'package:stackwallet/services/coins/particl/particl_wallet.dart' as particl; +import 'package:stackwallet/services/coins/stellar/stellar_wallet.dart' as xlm; import 'package:stackwallet/services/coins/wownero/wownero_wallet.dart' as wow; import 'package:stackwallet/utilities/constants.dart'; @@ -44,6 +45,7 @@ enum Coin { namecoin, nano, particl, + stellar, wownero, /// @@ -84,6 +86,8 @@ extension CoinExt on Coin { return "Monero"; case Coin.particl: return "Particl"; + case Coin.stellar: + return "Stellar"; case Coin.wownero: return "Wownero"; case Coin.namecoin: @@ -127,6 +131,8 @@ extension CoinExt on Coin { return "XMR"; case Coin.particl: return "PART"; + case Coin.stellar: + return "XLM"; case Coin.wownero: return "WOW"; case Coin.namecoin: @@ -171,6 +177,8 @@ extension CoinExt on Coin { return "monero"; case Coin.particl: return "particl"; + case Coin.stellar: + return "stellar"; case Coin.wownero: return "wownero"; case Coin.namecoin: @@ -215,6 +223,7 @@ extension CoinExt on Coin { case Coin.wownero: case Coin.nano: case Coin.banano: + case Coin.stellar: return false; } } @@ -242,6 +251,7 @@ extension CoinExt on Coin { case Coin.firoTestNet: case Coin.nano: case Coin.banano: + case Coin.stellar: return false; } } @@ -262,6 +272,7 @@ extension CoinExt on Coin { case Coin.nano: case Coin.banano: case Coin.eCash: + case Coin.stellar: return false; case Coin.dogecoinTestNet: @@ -289,6 +300,7 @@ extension CoinExt on Coin { case Coin.nano: case Coin.banano: case Coin.eCash: + case Coin.stellar: return this; case Coin.dogecoinTestNet: @@ -345,6 +357,9 @@ extension CoinExt on Coin { case Coin.particl: return particl.MINIMUM_CONFIRMATIONS; + case Coin.stellar: + return xlm.MINIMUM_CONFIRMATIONS; + case Coin.wownero: return wow.MINIMUM_CONFIRMATIONS; @@ -404,6 +419,10 @@ Coin coinFromPrettyName(String name) { case "particl": return Coin.particl; + case "Stellar": + case "stellar": + return Coin.stellar; + case "Namecoin": case "namecoin": return Coin.namecoin; @@ -481,6 +500,8 @@ Coin coinFromTickerCaseInsensitive(String ticker) { return Coin.namecoin; case "part": return Coin.particl; + case "xlm": + return Coin.stellar; case "tltc": return Coin.litecoinTestNet; case "tbtc": diff --git a/lib/utilities/enums/derive_path_type_enum.dart b/lib/utilities/enums/derive_path_type_enum.dart index f3e7f86df..1dbd3f79b 100644 --- a/lib/utilities/enums/derive_path_type_enum.dart +++ b/lib/utilities/enums/derive_path_type_enum.dart @@ -49,6 +49,7 @@ extension DerivePathTypeExt on DerivePathType { case Coin.wownero: case Coin.nano: case Coin.banano: + case Coin.stellar: throw UnsupportedError( "$coin does not use bitcoin style derivation paths"); } diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart index 9214e3e0a..b906320d3 100644 --- a/lib/widgets/node_card.dart +++ b/lib/widgets/node_card.dart @@ -194,7 +194,9 @@ class _NodeCardState extends ConsumerState { case Coin.nano: case Coin.banano: - //TODO: check network/node + case Coin.stellar: + throw UnimplementedError(); + //TODO: check network/node } if (testPassed) { diff --git a/lib/widgets/node_options_sheet.dart b/lib/widgets/node_options_sheet.dart index 16e87581c..f8b788fed 100644 --- a/lib/widgets/node_options_sheet.dart +++ b/lib/widgets/node_options_sheet.dart @@ -177,7 +177,9 @@ class NodeOptionsSheet extends ConsumerWidget { case Coin.nano: case Coin.banano: - //TODO: check network/node + case Coin.stellar: + throw UnimplementedError(); + //TODO: check network/node } if (testPassed) { diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index b044b4b00..b741c3c0a 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,9 +6,6 @@ import FlutterMacOS import Foundation import connectivity_plus -import cw_monero -import cw_shared_external -import cw_wownero import desktop_drop import device_info_plus import devicelocale @@ -16,10 +13,10 @@ import flutter_libepiccash import flutter_local_notifications import flutter_secure_storage_macos import isar_flutter_libs -import lelantus import package_info_plus import path_provider_foundation import share_plus +import shared_preferences_foundation import stack_wallet_backup import url_launcher_macos import wakelock_macos @@ -27,9 +24,6 @@ import window_size func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) - CwMoneroPlugin.register(with: registry.registrar(forPlugin: "CwMoneroPlugin")) - CwSharedExternalPlugin.register(with: registry.registrar(forPlugin: "CwSharedExternalPlugin")) - CwWowneroPlugin.register(with: registry.registrar(forPlugin: "CwWowneroPlugin")) DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin")) @@ -37,10 +31,10 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) - LelantusPlugin.register(with: registry.registrar(forPlugin: "LelantusPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) StackWalletBackupPlugin.register(with: registry.registrar(forPlugin: "StackWalletBackupPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin")) diff --git a/pubspec.lock b/pubspec.lock index e260cb994..2987cff3e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -37,18 +37,18 @@ packages: dependency: transitive description: name: args - sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" asn1lib: dependency: transitive description: name: asn1lib - sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039 + sha256: b74e3842a52c61f8819a1ec8444b4de5419b41a7465e69d4aa681445377398b0 url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" async: dependency: "direct main" description: @@ -146,10 +146,10 @@ packages: dependency: transitive description: name: build - sha256: "43865b79fbb78532e4bff7c33087aa43b1d488c4fdef014eaef568af6d8016dc" + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" build_config: dependency: transitive description: @@ -170,26 +170,26 @@ packages: dependency: transitive description: name: build_resolvers - sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95 + sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.1" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "220ae4553e50d7c21a17c051afc7b183d28a24a420502e842f303f8e4e6edced" + sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" url: "https://pub.dev" source: hosted - version: "2.4.4" + version: "2.4.6" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: "88a57f2ac99849362e73878334caa9f06ee25f31d2adced882b8337838c84e1e" + sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41" url: "https://pub.dev" source: hosted - version: "7.2.9" + version: "7.2.10" built_collection: dependency: transitive description: @@ -202,10 +202,10 @@ packages: dependency: transitive description: name: built_value - sha256: "7dd62d9faf105c434f3d829bbe9c4be02ec67f5ed94832222116122df67c5452" + sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166" url: "https://pub.dev" source: hosted - version: "8.6.0" + version: "8.6.1" characters: dependency: transitive description: @@ -242,10 +242,10 @@ packages: dependency: transitive description: name: code_builder - sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe" + sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189" url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "4.5.0" collection: dependency: transitive description: @@ -298,10 +298,10 @@ packages: dependency: "direct main" description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" cryptography: dependency: transitive description: @@ -314,10 +314,10 @@ packages: dependency: transitive description: name: csslib - sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f" + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" url: "https://pub.dev" source: hosted - version: "0.17.3" + version: "1.0.0" cw_core: dependency: "direct main" description: @@ -382,18 +382,18 @@ packages: dependency: transitive description: name: dart_style - sha256: f4f1f73ab3fd2afcbcca165ee601fe980d966af6a21b5970c6c9376955c528ad + sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" dartx: dependency: transitive description: name: dartx - sha256: "45d7176701f16c5a5e00a4798791c1964bc231491b879369c818dd9a9c764871" + sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" dbus: dependency: transitive description: @@ -406,10 +406,10 @@ packages: dependency: "direct main" description: name: decimal - sha256: eece91944f523657c75a3a008a90ec7f7eb3986191153a78570c7d0ac8ef3d01 + sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.3" dependency_validator: dependency: "direct dev" description: @@ -450,14 +450,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.0" + dio: + dependency: transitive + description: + name: dio + sha256: "3866d67f93523161b643187af65f5ac08bc991a5bcdaf41a2d587fe4ccb49993" + url: "https://pub.dev" + source: hosted + version: "5.3.0" dropdown_button2: dependency: "direct main" description: name: dropdown_button2 - sha256: "374f2390161bf782b4896f0b1b24cbb2b5daaa1cfb11047c3307461dcdf44e07" + sha256: "83c54a5022f898d63e3abe21240b64b937e676103207287e6705d3f9bb04d654" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.6" eip1559: dependency: transitive description: @@ -542,10 +550,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf" + sha256: b1729fc96627dd44012d0a901558177418818d6bd428df59dcfeb594e5f66432 url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "5.3.2" fixnum: dependency: transitive description: @@ -606,10 +614,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" flutter_local_notifications: dependency: "direct main" description: @@ -670,10 +678,10 @@ packages: dependency: "direct main" description: name: flutter_rounded_date_picker - sha256: e7143cc5cbf3aec1536286653e38b0809abc99fb76c91bd910dbd98ae003d890 + sha256: e6aa2dc5d3b44e8bbe85ef901be69eac59ba4136427f11f4c8b2a303e1e774e7 url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.4" flutter_secure_storage: dependency: "direct main" description: @@ -821,10 +829,10 @@ packages: dependency: transitive description: name: html - sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8" + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" url: "https://pub.dev" source: hosted - version: "0.15.3" + version: "0.15.4" http: dependency: "direct main" description: @@ -948,15 +956,15 @@ packages: path: "crypto_plugins/flutter_liblelantus" relative: true source: path - version: "0.0.2" + version: "0.0.1" lints: dependency: transitive description: name: lints - sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015" + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" local_auth: dependency: "direct main" description: @@ -977,10 +985,10 @@ packages: dependency: "direct main" description: name: lottie - sha256: "23522951540d20a57a60202ed7022e6376bed206a4eee1c347a91f58bd57eb9f" + sha256: "0793a5866062e5cc8a8b24892fa94c3095953ea914a7fdf790f550dd7537fe60" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.5.0" matcher: dependency: transitive description: @@ -1033,10 +1041,10 @@ packages: dependency: "direct dev" description: name: mockito - sha256: "8b46d7eb40abdda92d62edd01546051f0c27365e65608c284de336dccfef88cc" + sha256: "7d5b53bcd556c1bc7ffbe4e4d5a19c3e112b7e925e9e172dd7c6ad0630812616" url: "https://pub.dev" source: hosted - version: "5.4.1" + version: "5.4.2" mocktail: dependency: transitive description: @@ -1145,10 +1153,10 @@ packages: dependency: transitive description: name: path_provider_foundation - sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" + sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.2.4" path_provider_linux: dependency: transitive description: @@ -1169,50 +1177,50 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 + sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" url: "https://pub.dev" source: hosted - version: "2.1.6" + version: "2.1.7" permission_handler: dependency: "direct main" description: name: permission_handler - sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8" + sha256: "63e5216aae014a72fe9579ccd027323395ce7a98271d9defa9d57320d001af81" url: "https://pub.dev" source: hosted - version: "10.2.0" + version: "10.4.3" permission_handler_android: dependency: transitive description: name: permission_handler_android - sha256: d8cc6a62ded6d0f49c6eac337e080b066ee3bce4d405bd9439a61e1f1927bfe8 + sha256: "2ffaf52a21f64ac9b35fe7369bb9533edbd4f698e5604db8645b1064ff4cf221" url: "https://pub.dev" source: hosted - version: "10.2.1" + version: "10.3.3" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - sha256: ee96ac32f5a8e6f80756e25b25b9f8e535816c8e6665a96b6d70681f8c4f7e85 + sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5" url: "https://pub.dev" source: hosted - version: "9.0.8" + version: "9.1.4" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface - sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84" + sha256: "7c6b1500385dd1d2ca61bb89e2488ca178e274a69144d26bbd65e33eae7c02a9" url: "https://pub.dev" source: hosted - version: "3.9.0" + version: "3.11.3" permission_handler_windows: dependency: transitive description: name: permission_handler_windows - sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b + sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098 url: "https://pub.dev" source: hosted - version: "0.1.2" + version: "0.1.3" petitparser: dependency: transitive description: @@ -1221,6 +1229,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.4.0" + pinenacl: + dependency: transitive + description: + name: pinenacl + sha256: "3a5503637587d635647c93ea9a8fecf48a420cc7deebe6f1fc85c2a5637ab327" + url: "https://pub.dev" + source: hosted + version: "0.5.1" platform: dependency: transitive description: @@ -1233,10 +1249,10 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" pointycastle: dependency: "direct main" description: @@ -1349,6 +1365,62 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" + shared_preferences: + dependency: transitive + description: + name: shared_preferences + sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4 + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d + url: "https://pub.dev" + source: hosted + version: "2.3.0" shelf: dependency: transitive description: @@ -1390,18 +1462,18 @@ packages: dependency: transitive description: name: source_gen - sha256: "373f96cf5a8744bc9816c1ff41cf5391bbdbe3d7a96fe98c622b6738a8a7bd33" + sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" source_helper: dependency: transitive description: name: source_helper - sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f" + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.4" source_map_stack_trace: dependency: transitive description: @@ -1451,6 +1523,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.2+1" + stellar_flutter_sdk: + dependency: "direct main" + description: + name: stellar_flutter_sdk + sha256: "7a9b7dc76018bbd0b9c828045cf0e26e07ec44208fb1a1733273de2390205475" + url: "https://pub.dev" + source: hosted + version: "1.6.0" stream_channel: dependency: transitive description: @@ -1555,14 +1635,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + toml: + dependency: transitive + description: + name: toml + sha256: "69756bc12eccf279b72217a87310d217efc4b3752f722e890f672801f19ac485" + url: "https://pub.dev" + source: hosted + version: "0.13.1" tuple: dependency: "direct main" description: name: tuple - sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa" + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" typed_data: dependency: transitive description: @@ -1579,22 +1667,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.2" + unorm_dart: + dependency: transitive + description: + name: unorm_dart + sha256: "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b" + url: "https://pub.dev" + source: hosted + version: "0.2.0" url_launcher: dependency: "direct main" description: name: url_launcher - sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3 + sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e" url: "https://pub.dev" source: hosted - version: "6.1.11" + version: "6.1.12" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: eed4e6a1164aa9794409325c3b707ff424d4d1c2a785e7db67f8bbda00e36e51 + sha256: "78cb6dea3e93148615109e58e42c35d1ffbf5ef66c44add673d0ab75f12ff3af" url: "https://pub.dev" source: hosted - version: "6.0.35" + version: "6.0.37" url_launcher_ios: dependency: transitive description: @@ -1615,34 +1711,34 @@ packages: dependency: transitive description: name: url_launcher_macos - sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e" + sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.6" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370" + sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "6bb1e5d7fe53daf02a8fee85352432a40b1f868a81880e99ec7440113d5cfcab" + sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4 url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.0.18" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771" + sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.0.7" uuid: dependency: "direct main" description: @@ -1768,18 +1864,18 @@ packages: dependency: transitive description: name: win32 - sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" + sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee url: "https://pub.dev" source: hosted - version: "4.1.4" + version: "5.0.5" win32_registry: dependency: transitive description: name: win32_registry - sha256: "1c52f994bdccb77103a6231ad4ea331a244dbcef5d1f37d8462f713143b0bfae" + sha256: e4506d60b7244251bc59df15656a3093501c37fb5af02105a944d73eb95be4c9 url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" window_size: dependency: "direct main" description: @@ -1831,4 +1927,4 @@ packages: version: "1.0.0" sdks: dart: ">=3.0.2 <4.0.0" - flutter: ">=3.10.3" + flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index f5b4cf27b..3419bc282 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -138,6 +138,7 @@ dependencies: desktop_drop: ^0.4.1 nanodart: ^2.0.0 basic_utils: ^5.5.4 + stellar_flutter_sdk: ^1.5.8 dev_dependencies: flutter_test: