Skip to content

Commit 706779c

Browse files
committed
fix: account for Firo OP_RETURN in fee previews
1 parent c9035e4 commit 706779c

6 files changed

Lines changed: 200 additions & 28 deletions

File tree

lib/pages/send_view/send_view.dart

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,12 @@ class _SendViewState extends ConsumerState<SendView> {
184184
// onChanged handler reading stale null value.
185185
if (paymentData.additionalParams.containsKey('op_return')) {
186186
final data = paymentData.additionalParams['op_return'];
187-
ref.read(pOpReturnData.notifier).state = data;
187+
_setOpReturnData(data);
188188
Logging.instance.i(
189189
"Extracted OP_RETURN data from URI, length: ${data!.length ~/ 2} bytes",
190190
);
191191
} else {
192-
ref.read(pOpReturnData.notifier).state = null;
192+
_setOpReturnData(null);
193193
}
194194

195195
_setValidAddressProviders(_address);
@@ -541,11 +541,50 @@ class _SendViewState extends ConsumerState<SendView> {
541541
Map<Amount, String> cachedFiroSparkFees = {};
542542
Map<Amount, String> cachedFiroPublicFees = {};
543543

544+
void _setOpReturnData(String? data) {
545+
if (!mounted) {
546+
return;
547+
}
548+
ref.read(pOpReturnData.notifier).state = data;
549+
}
550+
551+
Amount _addOpReturnFeeIfNeeded({
552+
required Amount fee,
553+
required BigInt feeRate,
554+
required FiroWallet wallet,
555+
}) {
556+
final opReturnData = ref.read(pOpReturnData);
557+
if (opReturnData == null ||
558+
opReturnData.isEmpty ||
559+
ref.read(publicPrivateBalanceStateProvider) != BalanceType.public) {
560+
return fee;
561+
}
562+
563+
final extraOutputVSize = AddressUtils.opReturnOutputVSizeFromHex(
564+
opReturnData,
565+
);
566+
final extraFee = wallet.estimateTxFee(
567+
vSize: extraOutputVSize,
568+
feeRatePerKB: feeRate,
569+
);
570+
571+
return fee +
572+
Amount(
573+
rawValue: BigInt.from(extraFee),
574+
fractionDigits: coin.fractionDigits,
575+
);
576+
}
577+
544578
Future<String> calculateFees(Amount amount) async {
579+
final hasOpReturnData =
580+
isFiro &&
581+
ref.read(publicPrivateBalanceStateProvider) == BalanceType.public &&
582+
(ref.read(pOpReturnData)?.isNotEmpty ?? false);
583+
545584
if (isFiro) {
546585
switch (ref.read(publicPrivateBalanceStateProvider.state).state) {
547586
case BalanceType.public:
548-
if (cachedFiroPublicFees[amount] != null) {
587+
if (!hasOpReturnData && cachedFiroPublicFees[amount] != null) {
549588
return cachedFiroPublicFees[amount]!;
550589
}
551590
break;
@@ -607,10 +646,18 @@ class _SendViewState extends ConsumerState<SendView> {
607646
switch (ref.read(publicPrivateBalanceStateProvider.state).state) {
608647
case BalanceType.public:
609648
fee = await firoWallet.estimateFeeFor(amount, feeRate);
610-
cachedFiroPublicFees[amount] = ref
649+
fee = _addOpReturnFeeIfNeeded(
650+
fee: fee,
651+
feeRate: feeRate,
652+
wallet: firoWallet,
653+
);
654+
final formatted = ref
611655
.read(pAmountFormatter(coin))
612656
.format(fee, withUnitName: true, indicatePrecisionLoss: false);
613-
return cachedFiroPublicFees[amount]!;
657+
if (!hasOpReturnData) {
658+
cachedFiroPublicFees[amount] = formatted;
659+
}
660+
return formatted;
614661

615662
case BalanceType.private:
616663
fee = await firoWallet.estimateFeeForSpark(amount);
@@ -1146,6 +1193,9 @@ class _SendViewState extends ConsumerState<SendView> {
11461193
}
11471194

11481195
void clearSendForm() {
1196+
if (!mounted) {
1197+
return;
1198+
}
11491199
sendToController.text = "";
11501200
cryptoAmountController.text = "";
11511201
baseAmountController.text = "";
@@ -1155,10 +1205,8 @@ class _SendViewState extends ConsumerState<SendView> {
11551205
memoController.text = "";
11561206
_address = "";
11571207
_addressToggleFlag = false;
1158-
ref.read(pOpReturnData.notifier).state = null;
1159-
if (mounted) {
1160-
setState(() {});
1161-
}
1208+
_setOpReturnData(null);
1209+
setState(() {});
11621210
}
11631211

11641212
String _getSendAllTitle(
@@ -1758,8 +1806,7 @@ class _SendViewState extends ConsumerState<SendView> {
17581806
if (parsed != null) {
17591807
_applyUri(parsed);
17601808
} else {
1761-
ref.read(pOpReturnData.notifier).state =
1762-
null;
1809+
_setOpReturnData(null);
17631810
await _checkSparkNameAndOrSetAddress(
17641811
newValue,
17651812
);

lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
1414
import '../../../models/paymint/fee_object_model.dart';
1515
import '../../../providers/providers.dart';
1616
import '../../../providers/ui/fee_rate_type_state_provider.dart';
17+
import '../../../providers/ui/preview_tx_button_state_provider.dart';
1718
import '../../../providers/wallet/public_private_balance_state_provider.dart';
1819
import '../../../themes/stack_colors.dart';
20+
import '../../../utilities/address_utils.dart';
1921
import '../../../utilities/amount/amount.dart';
2022
import '../../../utilities/amount/amount_formatter.dart';
2123
import '../../../utilities/constants.dart';
@@ -78,12 +80,54 @@ class _TransactionFeeSelectionSheetState
7880
"Calculating...",
7981
];
8082

83+
Amount _addFiroOpReturnFee({
84+
required Amount fee,
85+
required BigInt feeRate,
86+
required FiroWallet wallet,
87+
required CryptoCurrency coin,
88+
}) {
89+
final opReturnData = ref.read(pOpReturnData);
90+
if (opReturnData == null ||
91+
opReturnData.isEmpty ||
92+
ref.read(publicPrivateBalanceStateProvider) != BalanceType.public) {
93+
return fee;
94+
}
95+
96+
final extraOutputVSize = AddressUtils.opReturnOutputVSizeFromHex(
97+
opReturnData,
98+
);
99+
final extraFee = wallet.estimateTxFee(
100+
vSize: extraOutputVSize,
101+
feeRatePerKB: feeRate,
102+
);
103+
104+
return fee +
105+
Amount(
106+
rawValue: BigInt.from(extraFee),
107+
fractionDigits: coin.fractionDigits,
108+
);
109+
}
110+
81111
Future<Amount> feeFor({
82112
required Amount amount,
83113
required FeeRateType feeRateType,
84114
required BigInt feeRate,
85115
required CryptoCurrency coin,
86116
}) async {
117+
if (!widget.isToken &&
118+
coin is Firo &&
119+
ref.read(publicPrivateBalanceStateProvider) == BalanceType.public &&
120+
(ref.read(pOpReturnData)?.isNotEmpty ?? false)) {
121+
final wallet = ref.read(pWallets).getWallet(walletId) as FiroWallet;
122+
final fee = await wallet.estimateFeeFor(amount, feeRate);
123+
return _addFiroOpReturnFee(
124+
fee: fee,
125+
feeRate: feeRate,
126+
wallet: wallet,
127+
coin: coin,
128+
);
129+
}
130+
87131
switch (feeRateType) {
88132
case FeeRateType.fast:
89133
if (ref.read(feeSheetSessionCacheProvider).fast[amount] == null) {

lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -847,16 +847,25 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
847847
}
848848

849849
void clearSendForm() {
850+
if (!mounted) {
851+
return;
852+
}
850853
sendToController.text = "";
851854
cryptoAmountController.text = "";
852855
baseAmountController.text = "";
853856
memoController.text = "";
854857
nonceController.text = "";
855858
_address = "";
856859
_addressToggleFlag = false;
857-
if (mounted) {
858-
setState(() {});
860+
_setOpReturnData(null);
861+
setState(() {});
862+
}
863+
864+
void _setOpReturnData(String? data) {
865+
if (!mounted) {
866+
return;
859867
}
868+
ref.read(pOpReturnData.notifier).state = data;
860869
}
861870

862871
void _cryptoAmountChanged() async {
@@ -921,11 +930,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
921930

922931
if (paymentData != null &&
923932
paymentData.coin?.uriScheme == coin.uriScheme) {
924-
ref.read(pOpReturnData.notifier).state =
925-
paymentData.additionalParams['op_return'];
933+
_setOpReturnData(paymentData.additionalParams['op_return']);
926934
_applyUri(paymentData);
927935
} else {
928-
ref.read(pOpReturnData.notifier).state = null;
936+
_setOpReturnData(null);
929937
_address = qrCodeData.split("\n").first.trim();
930938
sendToController.text = _address ?? "";
931939

@@ -1054,11 +1062,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
10541062
);
10551063
if (paymentData != null &&
10561064
paymentData.coin?.uriScheme == coin.uriScheme) {
1057-
ref.read(pOpReturnData.notifier).state =
1058-
paymentData.additionalParams['op_return'];
1065+
_setOpReturnData(paymentData.additionalParams['op_return']);
10591066
_applyUri(paymentData);
10601067
} else {
1061-
ref.read(pOpReturnData.notifier).state = null;
1068+
_setOpReturnData(null);
10621069
if (coin is Epiccash) {
10631070
content = AddressUtils().formatEpicCashAddress(content);
10641071
}
@@ -1075,7 +1082,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
10751082
});
10761083
}
10771084
} catch (e) {
1078-
ref.read(pOpReturnData.notifier).state = null;
1085+
_setOpReturnData(null);
10791086
// If parsing fails, treat it as a plain address.
10801087
if (coin is Epiccash) {
10811088
// strip http:// and https:// if content contains @
@@ -1769,11 +1776,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
17691776
logging: Logging.instance,
17701777
);
17711778
if (parsed != null) {
1772-
ref.read(pOpReturnData.notifier).state =
1773-
parsed.additionalParams['op_return'];
1779+
_setOpReturnData(parsed.additionalParams['op_return']);
17741780
_applyUri(parsed);
17751781
} else {
1776-
ref.read(pOpReturnData.notifier).state = null;
1782+
_setOpReturnData(null);
17771783
await _checkSparkNameAndOrSetAddress(newValue);
17781784
}
17791785
} else {
@@ -1827,8 +1833,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
18271833
onTap: () {
18281834
sendToController.text = "";
18291835
_address = "";
1830-
ref.read(pOpReturnData.notifier).state =
1831-
null;
1836+
_setOpReturnData(null);
18321837
_setValidAddressProviders(_address);
18331838
setState(() {
18341839
_addressToggleFlag = false;

lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send_fee_form.dart

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
33

44
import '../../../../pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart';
55
import '../../../../providers/providers.dart';
6+
import '../../../../providers/ui/preview_tx_button_state_provider.dart';
67
import '../../../../providers/wallet/desktop_fee_providers.dart';
78
import '../../../../providers/wallet/public_private_balance_state_provider.dart';
89
import '../../../../themes/stack_colors.dart';
10+
import '../../../../utilities/address_utils.dart';
911
import '../../../../utilities/amount/amount.dart';
1012
import '../../../../utilities/enums/fee_rate_type_enum.dart';
1113
import '../../../../utilities/eth_commons.dart';
@@ -67,6 +69,33 @@ class _DesktopSendFeeFormState extends ConsumerState<DesktopSendFeeForm> {
6769

6870
(FeeRateType, String?, String?)? feeSelectionResult;
6971

72+
Amount _addFiroOpReturnFee({
73+
required Amount fee,
74+
required BigInt feeRate,
75+
required FiroWallet wallet,
76+
}) {
77+
final opReturnData = ref.read(pOpReturnData);
78+
if (opReturnData == null ||
79+
opReturnData.isEmpty ||
80+
ref.read(publicPrivateBalanceStateProvider) != BalanceType.public) {
81+
return fee;
82+
}
83+
84+
final extraOutputVSize = AddressUtils.opReturnOutputVSizeFromHex(
85+
opReturnData,
86+
);
87+
final extraFee = wallet.estimateTxFee(
88+
vSize: extraOutputVSize,
89+
feeRatePerKB: feeRate,
90+
);
91+
92+
return fee +
93+
Amount(
94+
rawValue: BigInt.from(extraFee),
95+
fractionDigits: cryptoCurrency.fractionDigits,
96+
);
97+
}
98+
7099
@override
71100
void initState() {
72101
super.initState();
@@ -156,6 +185,30 @@ class _DesktopSendFeeFormState extends ConsumerState<DesktopSendFeeForm> {
156185
required BigInt feeRate,
157186
required CryptoCurrency coin,
158187
}) async {
188+
if (!widget.isToken &&
189+
coin is Firo &&
190+
ref.read(
191+
publicPrivateBalanceStateProvider,
192+
) ==
193+
BalanceType.public &&
194+
(ref.read(pOpReturnData)?.isNotEmpty ??
195+
false)) {
196+
final wallet =
197+
ref
198+
.read(pWallets)
199+
.getWallet(widget.walletId)
200+
as FiroWallet;
201+
final fee = await wallet.estimateFeeFor(
202+
amount,
203+
feeRate,
204+
);
205+
return _addFiroOpReturnFee(
206+
fee: fee,
207+
feeRate: feeRate,
208+
wallet: wallet,
209+
);
210+
}
211+
159212
if (ref
160213
.read(
161214
widget.isToken
@@ -220,12 +273,16 @@ class _DesktopSendFeeFormState extends ConsumerState<DesktopSendFeeForm> {
220273
final fee = await tokenWallet
221274
.estimateFeeFor(amount, feeRate);
222275
ref
223-
.read(tokenFeeSessionCacheProvider)
276+
.read(
277+
tokenFeeSessionCacheProvider,
278+
)
224279
.average[amount] =
225280
fee;
226281
} catch (_) {
227282
// Token wallet not available.
228-
debugPrint("Token fee estimation not available");
283+
debugPrint(
284+
"Token fee estimation not available",
285+
);
229286
}
230287
}
231288
}

lib/providers/ui/preview_tx_button_state_provider.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ final pValidSparkSendToAddress = StateProvider.autoDispose<bool>((_) => false);
2323

2424
final pIsExchangeAddress = StateProvider<bool>((_) => false);
2525

26-
final pOpReturnData = StateProvider<String?>((_) => null);
26+
final pOpReturnData = StateProvider.autoDispose<String?>((_) => null);
2727

2828
// MWC Transaction Method Provider.
2929
final pSelectedMwcTransactionMethod = StateProvider<MwcTransactionMethod>(

0 commit comments

Comments
 (0)