fix: auto format code and remove electrumx coin control

This commit is contained in:
julian 2023-07-27 08:11:20 -06:00
parent 526025f0f0
commit 6f2ddf7423
2 changed files with 158 additions and 215 deletions

View file

@ -1,30 +1,17 @@
import 'dart:async';
import 'dart:convert';
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 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/models/balance.dart' as SWBalance;
import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'
as SWAddress;
import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart'
as SWTransaction;
import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
import 'package:stackwallet/models/node_model.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/prefs.dart';
import 'package:stackwallet/models/paymint/fee_object_model.dart';
import 'package:stackwallet/services/coins/coin_service.dart';
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart';
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
@ -33,14 +20,20 @@ import 'package:stackwallet/services/mixins/wallet_cache.dart';
import 'package:stackwallet/services/mixins/wallet_db.dart';
import 'package:stackwallet/services/node_service.dart';
import 'package:stackwallet/services/transaction_notification_tracker.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/prefs.dart';
import 'package:stellar_flutter_sdk/stellar_flutter_sdk.dart';
import 'package:tuple/tuple.dart';
const int MINIMUM_CONFIRMATIONS = 1;
class StellarWallet extends CoinServiceAPI
with WalletCache, WalletDB, CoinControlInterface {
class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
late StellarSDK stellarSdk;
late Network stellarNetwork;
@ -116,7 +109,7 @@ class StellarWallet extends CoinServiceAPI
// then periodically check
_networkAliveTimer = Timer.periodic(
Constants.networkAliveTimerDuration,
(_) async {
(_) async {
_periodicPingCheck();
},
);
@ -165,68 +158,68 @@ class StellarWallet extends CoinServiceAPI
Coin get coin => _coin;
late Coin _coin;
Future<bool> accoutExists(String accountId) async {
Future<bool> _accountExists(String accountId) async {
bool exists = false;
try {
AccountResponse receiverAccount = await stellarSdk.accounts
.account(accountId);
AccountResponse receiverAccount =
await stellarSdk.accounts.account(accountId);
if (receiverAccount.accountId != "") {
exists = true;
}
} catch(e, s) {
Logging.instance.log("Error getting account ${e.toString()} - ${s.toString()}", level: LogLevel.Error);
} catch (e, s) {
Logging.instance.log(
"Error getting account ${e.toString()} - ${s.toString()}",
level: LogLevel.Error);
}
return exists;
}
@override
Future<String> confirmSend({required Map<String, dynamic> txData}) async {
final secretSeed = await _secureStore.read(
key: '${_walletId}_secretSeed'
);
final secretSeed = await _secureStore.read(key: '${_walletId}_secretSeed');
KeyPair senderKeyPair = KeyPair.fromSecretSeed(secretSeed!);
AccountResponse sender = await stellarSdk.accounts.account(senderKeyPair.accountId);
AccountResponse sender =
await stellarSdk.accounts.account(senderKeyPair.accountId);
final amountToSend = txData['recipientAmt'] as Amount;
//First check if account exists, can be skipped, but if the account does not exist,
// the transaction fee will be charged when the transaction fails.
bool validAccount = await accoutExists(txData['address'] as String);
bool validAccount = await _accountExists(txData['address'] as String);
Transaction transaction;
if (!validAccount) {
//Fund the account, user must ensure account is correct
CreateAccountOperationBuilder createAccBuilder =
CreateAccountOperationBuilder(
txData['address'] as String, amountToSend.decimal.toString()
);
CreateAccountOperationBuilder(
txData['address'] as String, amountToSend.decimal.toString());
transaction = TransactionBuilder(sender)
.addOperation(createAccBuilder.build())
.build();
} else {
transaction = TransactionBuilder(sender)
.addOperation(PaymentOperationBuilder(
txData['address'] as String, Asset.NATIVE,
amountToSend.decimal.toString())
.build()
).build();
.addOperation(PaymentOperationBuilder(txData['address'] as String,
Asset.NATIVE, amountToSend.decimal.toString())
.build())
.build();
}
transaction.sign(senderKeyPair, stellarNetwork);
try {
SubmitTransactionResponse response = await stellarSdk.submitTransaction(transaction);
SubmitTransactionResponse response =
await stellarSdk.submitTransaction(transaction);
if (!response.success) {
throw("Unable to send transaction");
throw ("Unable to send transaction");
}
return response.hash!;
} catch(e, s) {
} catch (e, s) {
Logging.instance.log("Error sending TX $e - $s", level: LogLevel.Error);
rethrow;
}
}
Future<SWAddress.Address?> get _currentReceivingAddress =>
db.getAddresses(walletId)
Future<SWAddress.Address?> get _currentReceivingAddress => db
.getAddresses(walletId)
.filter()
.typeEqualTo(SWAddress.AddressType.unknown)
.and()
@ -242,7 +235,8 @@ class StellarWallet extends CoinServiceAPI
// final nodeURI = Uri.parse("${getCurrentNode().host}:${getCurrentNode().port}");
final nodeURI = Uri.parse(getCurrentNode().host);
final httpClient = http.Client();
FeeStatsResponse fsp = await FeeStatsRequestBuilder(httpClient, nodeURI).execute();
FeeStatsResponse fsp =
await FeeStatsRequestBuilder(httpClient, nodeURI).execute();
return int.parse(fsp.lastLedgerBaseFee);
}
@ -279,8 +273,11 @@ class StellarWallet extends CoinServiceAPI
NodeModel getCurrentNode() {
if (_xlmNode != null) {
return _xlmNode!;
} else if (NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: coin) != null) {
return NodeService(secureStorageInterface: _secureStore).getPrimaryNodeFor(coin: coin)!;
} else if (NodeService(secureStorageInterface: _secureStore)
.getPrimaryNodeFor(coin: coin) !=
null) {
return NodeService(secureStorageInterface: _secureStore)
.getPrimaryNodeFor(coin: coin)!;
} else {
return DefaultNodes.getNodeFor(coin);
}
@ -291,9 +288,9 @@ class StellarWallet extends CoinServiceAPI
// final nodeURI = Uri.parse("${getCurrentNode().host}:${getCurrentNode().port}");
final nodeURI = Uri.parse(getCurrentNode().host);
final httpClient = http.Client();
FeeStatsResponse fsp = await FeeStatsRequestBuilder(httpClient, nodeURI).execute();
FeeStatsResponse fsp =
await FeeStatsRequestBuilder(httpClient, nodeURI).execute();
return FeeObject(
numberOfBlocksFast: 0,
@ -301,12 +298,12 @@ class StellarWallet extends CoinServiceAPI
numberOfBlocksSlow: 0,
fast: int.parse(fsp.lastLedgerBaseFee) * 100,
medium: int.parse(fsp.lastLedgerBaseFee) * 50,
slow: int.parse(fsp.lastLedgerBaseFee) * 10
);
slow: int.parse(fsp.lastLedgerBaseFee) * 10);
}
@override
Future<void> fullRescan(int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) async {
Future<void> fullRescan(
int maxUnusedAddressGap, int maxNumberOfIndexesToCheck) async {
await _prefs.init();
await updateTransactions();
await updateChainHeight();
@ -338,25 +335,16 @@ class StellarWallet extends CoinServiceAPI
await _prefs.init();
String mnemonic = await Wallet.generate24WordsMnemonic();
await _secureStore.write(
key: '${_walletId}_mnemonic',
value: mnemonic
);
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: ""
);
await _secureStore.write(key: '${_walletId}_mnemonic', value: mnemonic);
await _secureStore.write(key: '${_walletId}_mnemonicPassphrase', value: "");
Wallet wallet = await Wallet.from(mnemonic);
KeyPair keyPair = await wallet.getKeyPair(index: 0);
String address = keyPair.accountId;
String secretSeed = keyPair.secretSeed; //This will be required for sending a tx
String secretSeed =
keyPair.secretSeed; //This will be required for sending a tx
await _secureStore.write(
key: '${_walletId}_secretSeed',
value: secretSeed
);
await _secureStore.write(key: '${_walletId}_secretSeed', value: secretSeed);
final swAddress = SWAddress.Address(
walletId: walletId,
@ -365,21 +353,16 @@ class StellarWallet extends CoinServiceAPI
derivationIndex: 0,
derivationPath: null,
type: SWAddress.AddressType.unknown, // TODO: set type
subType: SWAddress.AddressSubType.unknown
);
subType: SWAddress.AddressSubType.unknown);
await db.putAddress(swAddress);
await Future.wait([
updateCachedId(walletId),
updateCachedIsFavorite(false)
]);
await Future.wait(
[updateCachedId(walletId), updateCachedIsFavorite(false)]);
}
Future<String> getAddressSW() async {
var mnemonic = await _secureStore.read(
key: '${_walletId}_mnemonic'
);
var mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic');
Wallet wallet = await Wallet.from(mnemonic!);
KeyPair keyPair = await wallet.getKeyPair(index: 0);
@ -400,16 +383,22 @@ class StellarWallet extends CoinServiceAPI
Future<int> get maxFee => throw UnimplementedError();
@override
Future<List<String>> get mnemonic => mnemonicString.then((value) => value!.split(" "));
Future<List<String>> get mnemonic =>
mnemonicString.then((value) => value!.split(" "));
@override
Future<String?> get mnemonicPassphrase => _secureStore.read(key: '${_walletId}_mnemonicPassphrase');
Future<String?> get mnemonicPassphrase =>
_secureStore.read(key: '${_walletId}_mnemonicPassphrase');
@override
Future<String?> get mnemonicString => _secureStore.read(key: '${_walletId}_mnemonic');
Future<String?> get mnemonicString =>
_secureStore.read(key: '${_walletId}_mnemonic');
@override
Future<Map<String, dynamic>> prepareSend({required String address, required Amount amount, Map<String, dynamic>? args}) async {
Future<Map<String, dynamic>> prepareSend(
{required String address,
required Amount amount,
Map<String, dynamic>? args}) async {
try {
final feeRate = args?["feeRate"];
var fee = 1000;
@ -440,13 +429,12 @@ class StellarWallet extends CoinServiceAPI
}
@override
Future<void> recoverFromMnemonic({
required String mnemonic,
String? mnemonicPassphrase,
required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck,
required int height
}) async {
Future<void> 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!");
@ -463,10 +451,7 @@ class StellarWallet extends CoinServiceAPI
key: '${_walletId}_mnemonicPassphrase',
value: mnemonicPassphrase ?? "",
);
await _secureStore.write(
key: '${_walletId}_secretSeed',
value: secretSeed
);
await _secureStore.write(key: '${_walletId}_secretSeed', value: secretSeed);
final swAddress = SWAddress.Address(
walletId: walletId,
@ -475,15 +460,12 @@ class StellarWallet extends CoinServiceAPI
derivationIndex: 0,
derivationPath: null,
type: SWAddress.AddressType.unknown, // TODO: set type
subType: SWAddress.AddressSubType.unknown
);
subType: SWAddress.AddressSubType.unknown);
await db.putAddress(swAddress);
await Future.wait([
updateCachedId(walletId),
updateCachedIsFavorite(false)
]);
await Future.wait(
[updateCachedId(walletId), updateCachedIsFavorite(false)]);
}
Future<void> updateChainHeight() async {
@ -491,20 +473,22 @@ class StellarWallet extends CoinServiceAPI
.order(RequestBuilderOrder.DESC)
.limit(1)
.execute()
.then((value) => value.records!.first.sequence).onError((error, stackTrace) =>
throw("Error getting chain height"));
.then((value) => value.records!.first.sequence)
.onError((error, stackTrace) => throw ("Error getting chain height"));
await updateCachedChainHeight(height);
}
Future<void> updateTransactions() async {
try {
List<Tuple2<SWTransaction.Transaction, SWAddress.Address?>> transactionList = [];
List<Tuple2<SWTransaction.Transaction, SWAddress.Address?>>
transactionList = [];
Page<OperationResponse> payments = await stellarSdk.payments
.forAccount(await getAddressSW()).order(RequestBuilderOrder.DESC)
.execute().onError((error, stackTrace) =>
throw("Could not fetch transactions"));
.forAccount(await getAddressSW())
.order(RequestBuilderOrder.DESC)
.execute()
.onError(
(error, stackTrace) => throw ("Could not fetch transactions"));
for (OperationResponse response in payments.records!) {
// PaymentOperationResponse por;
@ -515,8 +499,7 @@ class StellarWallet extends CoinServiceAPI
"ALL TRANSACTIONS IS ${por.transactionSuccessful}",
level: LogLevel.Info);
Logging.instance.log(
"THIS TX HASH IS ${por.transactionHash}",
Logging.instance.log("THIS TX HASH IS ${por.transactionHash}",
level: LogLevel.Info);
SWTransaction.TransactionType type;
@ -526,14 +509,18 @@ class StellarWallet extends CoinServiceAPI
type = SWTransaction.TransactionType.incoming;
}
final amount = Amount(
rawValue: BigInt.parse(float.parse(por.amount!).toStringAsFixed(coin.decimals).replaceAll(".", "")),
fractionDigits: coin.decimals,
);
rawValue: BigInt.parse(float
.parse(por.amount!)
.toStringAsFixed(coin.decimals)
.replaceAll(".", "")),
fractionDigits: coin.decimals,
);
int fee = 0;
int height = 0;
//Query the transaction linked to the payment,
// por.transaction returns a null sometimes
TransactionResponse tx = await stellarSdk.transactions.transaction(por.transactionHash!);
TransactionResponse tx =
await stellarSdk.transactions.transaction(por.transactionHash!);
if (tx.hash.isNotEmpty) {
fee = tx.feeCharged!;
@ -542,7 +529,8 @@ class StellarWallet extends CoinServiceAPI
var theTransaction = SWTransaction.Transaction(
walletId: walletId,
txid: por.transactionHash!,
timestamp: DateTime.parse(por.createdAt!).millisecondsSinceEpoch ~/ 1000,
timestamp:
DateTime.parse(por.createdAt!).millisecondsSinceEpoch ~/ 1000,
type: type,
subType: SWTransaction.TransactionSubType.none,
amount: 0,
@ -559,18 +547,20 @@ class StellarWallet extends CoinServiceAPI
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<SWTransaction.Transaction, SWAddress.Address> tuple = Tuple2(theTransaction, address);
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<SWTransaction.Transaction, SWAddress.Address> tuple =
Tuple2(theTransaction, address);
transactionList.add(tuple);
} else if (response is CreateAccountOperationResponse) {
CreateAccountOperationResponse caor = response;
@ -581,12 +571,16 @@ class StellarWallet extends CoinServiceAPI
type = SWTransaction.TransactionType.incoming;
}
final amount = Amount(
rawValue: BigInt.parse(float.parse(caor.startingBalance!).toStringAsFixed(coin.decimals).replaceAll(".", "")),
rawValue: BigInt.parse(float
.parse(caor.startingBalance!)
.toStringAsFixed(coin.decimals)
.replaceAll(".", "")),
fractionDigits: coin.decimals,
);
int fee = 0;
int height = 0;
TransactionResponse tx = await stellarSdk.transactions.transaction(caor.transactionHash!);
TransactionResponse tx =
await stellarSdk.transactions.transaction(caor.transactionHash!);
if (tx.hash.isNotEmpty) {
fee = tx.feeCharged!;
height = tx.ledger;
@ -594,7 +588,8 @@ class StellarWallet extends CoinServiceAPI
var theTransaction = SWTransaction.Transaction(
walletId: walletId,
txid: caor.transactionHash!,
timestamp: DateTime.parse(caor.createdAt!).millisecondsSinceEpoch ~/ 1000,
timestamp:
DateTime.parse(caor.createdAt!).millisecondsSinceEpoch ~/ 1000,
type: type,
subType: SWTransaction.TransactionSubType.none,
amount: 0,
@ -611,17 +606,20 @@ class StellarWallet extends CoinServiceAPI
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<SWTransaction.Transaction, SWAddress.Address> tuple = Tuple2(theTransaction, address);
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<SWTransaction.Transaction, SWAddress.Address> tuple =
Tuple2(theTransaction, address);
transactionList.add(tuple);
}
}
@ -631,12 +629,12 @@ class StellarWallet extends CoinServiceAPI
"Exception rethrown from updateTransactions(): $e\n$s",
level: LogLevel.Error);
}
}
Future<void> updateBalance() async {
try {
AccountResponse accountResponse = await stellarSdk.accounts.account(await getAddressSW());
AccountResponse accountResponse =
await stellarSdk.accounts.account(await getAddressSW());
for (Balance balance in accountResponse.balances) {
switch (balance.assetType) {
case Asset.TYPE_NATIVE:
@ -662,9 +660,9 @@ class StellarWallet extends CoinServiceAPI
await updateCachedBalance(_balance!);
}
}
} catch(e, s) {
} catch (e, s) {
Logging.instance.log(
"ERROR GETTING BALANCE $e\$s",
"ERROR GETTING BALANCE $e\n$s",
level: LogLevel.Info,
);
}
@ -747,12 +745,13 @@ class StellarWallet extends CoinServiceAPI
}
@override
Future<List<SWTransaction.Transaction>> get transactions => db.getTransactions(walletId).findAll();
Future<List<SWTransaction.Transaction>> get transactions =>
db.getTransactions(walletId).findAll();
@override
Future<void> updateNode(bool shouldRefresh) async {
_xlmNode = NodeService(secureStorageInterface: _secureStore)
.getPrimaryNodeFor(coin: coin) ??
.getPrimaryNodeFor(coin: coin) ??
DefaultNodes.getNodeFor(coin);
if (shouldRefresh) {
@ -784,14 +783,14 @@ class StellarWallet extends CoinServiceAPI
);
final address = txData["address"] is String
? await db.getAddress(walletId, txData["address"] as String)
: null;
? await db.getAddress(walletId, txData["address"] as String)
: null;
await db.addNewTransactionData(
[
Tuple2(transaction, address),
],
walletId,
[
Tuple2(transaction, address),
],
walletId,
);
}

View file

@ -956,7 +956,7 @@ packages:
path: "crypto_plugins/flutter_liblelantus"
relative: true
source: path
version: "0.0.1"
version: "0.0.2"
lints:
dependency: transitive
description:
@ -1365,62 +1365,6 @@ 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:
@ -1927,4 +1871,4 @@ packages:
version: "1.0.0"
sdks:
dart: ">=3.0.2 <4.0.0"
flutter: ">=3.10.0"
flutter: ">=3.10.3"