@@ -14,6 +14,7 @@ import 'package:decimal/decimal.dart';
1414import 'package:flutter/material.dart' ;
1515import 'package:flutter/services.dart' ;
1616import 'package:flutter_riverpod/flutter_riverpod.dart' ;
17+ import 'package:flutter_svg/flutter_svg.dart' ;
1718
1819import '../../models/isar/models/isar_models.dart' ;
1920import '../../models/send_view_auto_fill_data.dart' ;
@@ -28,7 +29,9 @@ import '../../utilities/amount/amount_formatter.dart';
2829import '../../utilities/amount/amount_input_formatter.dart' ;
2930import '../../utilities/barcode_scanner_interface.dart' ;
3031import '../../utilities/clipboard_interface.dart' ;
32+ import '../../utilities/assets.dart' ;
3133import '../../utilities/constants.dart' ;
34+ import '../../utilities/enums/fee_rate_type_enum.dart' ;
3235import '../../utilities/logger.dart' ;
3336import '../../utilities/prefs.dart' ;
3437import '../../utilities/text_styles.dart' ;
@@ -340,10 +343,45 @@ class _SolTokenSendViewState extends ConsumerState<SolTokenSendView> {
340343 }
341344
342345 Future <String > calculateFees () async {
343- // TODO: Implement Solana fee calculation.
344- // For now, return a placeholder fee
345- cachedFees = "0.000005 SOL" ;
346- return cachedFees;
346+ try {
347+ final wallet = ref.read (pCurrentSolanaTokenWallet);
348+ if (wallet == null ) {
349+ return "0.000005 SOL" ;
350+ }
351+
352+ final feeObject = await wallet.fees;
353+
354+ late final BigInt feeRate;
355+
356+ switch (ref.read (feeRateTypeMobileStateProvider.state).state) {
357+ case FeeRateType .fast:
358+ feeRate = feeObject.fast;
359+ break ;
360+ case FeeRateType .average:
361+ feeRate = feeObject.medium;
362+ break ;
363+ case FeeRateType .slow:
364+ feeRate = feeObject.slow;
365+ break ;
366+ default :
367+ feeRate = BigInt .from (- 1 );
368+ }
369+
370+ final Amount fee = await wallet.estimateFeeFor (Amount .zero, feeRate);
371+ cachedFees = ref
372+ .read (pAmountFormatter (Solana (CryptoCurrencyNetwork .main)))
373+ .format (fee, withUnitName: true , indicatePrecisionLoss: false );
374+
375+ return cachedFees;
376+ } catch (e, s) {
377+ Logging .instance.w (
378+ "Failed to calculate Solana token fees: " ,
379+ error: e,
380+ stackTrace: s,
381+ );
382+ // Return minimum fee as fallback.
383+ return "0.000005 SOL" ;
384+ }
347385 }
348386
349387 Future <void > _previewTransaction () async {
@@ -522,6 +560,7 @@ class _SolTokenSendViewState extends ConsumerState<SolTokenSendView> {
522560 @override
523561 void initState () {
524562 ref.refresh (feeSheetSessionCacheProvider);
563+ ref.read (feeRateTypeMobileStateProvider.state).state = FeeRateType .slow;
525564
526565 _calculateFeesFuture = calculateFees ();
527566 _data = widget.autoFillData;
@@ -1114,38 +1153,100 @@ class _SolTokenSendViewState extends ConsumerState<SolTokenSendView> {
11141153 ),
11151154 ),
11161155 onPressed: () {
1117- // TODO: Implement fee selection for Solana.
1156+ showModalBottomSheet <dynamic >(
1157+ backgroundColor: Colors .transparent,
1158+ context: context,
1159+ shape: const RoundedRectangleBorder (
1160+ borderRadius: BorderRadius .vertical (
1161+ top: Radius .circular (20 ),
1162+ ),
1163+ ),
1164+ builder: (_) =>
1165+ TransactionFeeSelectionSheet (
1166+ walletId: walletId,
1167+ isToken: true ,
1168+ amount:
1169+ (Decimal .tryParse (
1170+ cryptoAmountController
1171+ .text,
1172+ ) ??
1173+ Decimal .zero)
1174+ .toAmount (
1175+ fractionDigits:
1176+ tokenWallet
1177+ .tokenDecimals,
1178+ ),
1179+ updateChosen: (String fee) {
1180+ setState (() {
1181+ _calculateFeesFuture = Future (
1182+ () => fee,
1183+ );
1184+ });
1185+ },
1186+ ),
1187+ );
11181188 },
11191189 child: Row (
11201190 mainAxisAlignment:
11211191 MainAxisAlignment .spaceBetween,
11221192 children: [
1123- FutureBuilder (
1124- future: _calculateFeesFuture,
1125- builder: (context, snapshot) {
1126- if (snapshot.connectionState ==
1127- ConnectionState .done &&
1128- snapshot.hasData) {
1129- return Text (
1130- "~${snapshot .data !}" ,
1131- style: STextStyles .itemSubtitle (
1132- context,
1133- ),
1134- );
1135- } else {
1136- return AnimatedText (
1137- stringsToLoopThrough: const [
1138- "Calculating" ,
1139- "Calculating." ,
1140- "Calculating.." ,
1141- "Calculating..." ,
1142- ],
1143- style: STextStyles .itemSubtitle (
1144- context,
1145- ),
1146- );
1147- }
1148- },
1193+ Row (
1194+ children: [
1195+ Text (
1196+ ref
1197+ .watch (
1198+ feeRateTypeMobileStateProvider
1199+ .state,
1200+ )
1201+ .state
1202+ .prettyName,
1203+ style: STextStyles .itemSubtitle12 (
1204+ context,
1205+ ),
1206+ ),
1207+ const SizedBox (width: 10 ),
1208+ FutureBuilder (
1209+ future: _calculateFeesFuture,
1210+ builder: (context, snapshot) {
1211+ if (snapshot.connectionState ==
1212+ ConnectionState .done &&
1213+ snapshot.hasData) {
1214+ return Text (
1215+ "~${snapshot .data !}" ,
1216+ style:
1217+ STextStyles .itemSubtitle (
1218+ context,
1219+ ),
1220+ );
1221+ } else {
1222+ return AnimatedText (
1223+ stringsToLoopThrough:
1224+ const [
1225+ "Calculating" ,
1226+ "Calculating." ,
1227+ "Calculating.." ,
1228+ "Calculating..." ,
1229+ ],
1230+ style:
1231+ STextStyles .itemSubtitle (
1232+ context,
1233+ ),
1234+ );
1235+ }
1236+ },
1237+ ),
1238+ ],
1239+ ),
1240+ SvgPicture .asset (
1241+ Assets .svg.chevronDown,
1242+ width: 8 ,
1243+ height: 4 ,
1244+ colorFilter: ColorFilter .mode (
1245+ Theme .of (context)
1246+ .extension < StackColors > ()!
1247+ .textSubtitle2,
1248+ BlendMode .srcIn,
1249+ ),
11491250 ),
11501251 ],
11511252 ),
0 commit comments