From f294edd1a961daddb997e2296747e093f92aad80 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 2 Sep 2025 10:48:48 +0000 Subject: [PATCH 1/2] Add exact amount button and improve large number parsing Co-authored-by: charl --- assets/translations/en.json | 1 + lib/generated/codegen_loader.g.dart | 1 + lib/shared/utils/utils.dart | 6 ++++-- .../taker/coin_item/taker_form_sell_item.dart | 12 +++++++++++ .../tests/utils/convert_fract_rat_test.dart | 21 +++++++++++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index f245d8d4f4..9fa91a467e 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -468,6 +468,7 @@ "nothingFound": "Nothing found", "half": "Half", "max": "Max", + "exact": "Exact", "reactivating": "Reactivating", "weFailedCoinActivate": "We failed to activate {} :(", "failedActivate": "Failed to activate", diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index f1e2508eb7..a18ede914c 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -465,6 +465,7 @@ abstract class LocaleKeys { static const nothingFound = 'nothingFound'; static const half = 'half'; static const max = 'max'; + static const exact = 'exact'; static const reactivating = 'reactivating'; static const weFailedCoinActivate = 'weFailedCoinActivate'; static const failedActivate = 'failedActivate'; diff --git a/lib/shared/utils/utils.dart b/lib/shared/utils/utils.dart index 6f321637ff..c25a668ff0 100644 --- a/lib/shared/utils/utils.dart +++ b/lib/shared/utils/utils.dart @@ -139,9 +139,11 @@ Rational? fract2rat(Map? fract, [bool willLog = true]) { if (fract == null) return null; try { + final String numerStr = fract['numer'].toString(); + final String denomStr = fract['denom'].toString(); final rat = Rational( - BigInt.from(double.parse(fract['numer'])), - BigInt.from(double.parse(fract['denom'])), + BigInt.parse(numerStr), + BigInt.parse(denomStr), ); return rat; } catch (e) { diff --git a/lib/views/dex/simple/form/taker/coin_item/taker_form_sell_item.dart b/lib/views/dex/simple/form/taker/coin_item/taker_form_sell_item.dart index cef689793d..c58567daec 100644 --- a/lib/views/dex/simple/form/taker/coin_item/taker_form_sell_item.dart +++ b/lib/views/dex/simple/form/taker/coin_item/taker_form_sell_item.dart @@ -50,6 +50,8 @@ class _SellHeader extends StatelessWidget { actions: [ Flexible(child: _AvailableGroup()), const SizedBox(width: 8), + _ExactButton(), + const SizedBox(width: 3), _MaxButton(), const SizedBox(width: 3), _HalfButton(), @@ -85,3 +87,13 @@ class _MaxButton extends DexSmallButton { context.read().add(TakerAmountButtonClick(1)); }); } + +class _ExactButton extends DexSmallButton { + _ExactButton() + : super(LocaleKeys.exact.tr(), (context) { + final state = context.read().state; + final order = state.selectedOrder; + if (order == null) return; + context.read().add(TakerSetSellAmount(order.maxVolume)); + }); +} diff --git a/test_units/tests/utils/convert_fract_rat_test.dart b/test_units/tests/utils/convert_fract_rat_test.dart index 4955892a10..76731755b7 100644 --- a/test_units/tests/utils/convert_fract_rat_test.dart +++ b/test_units/tests/utils/convert_fract_rat_test.dart @@ -34,4 +34,25 @@ void testRatToFracAndViseVersa() { Rational? result = fract2rat(invalidFract, false); expect(result, isNull); }); + + test('fract2rat handles very large integers without precision loss', () { + // 10^50 / 10^20 = 10^30 + final numer = '100000000000000000000000000000000000000000000000000'; + final denom = '100000000000000000000'; + final rat = fract2rat({'numer': numer, 'denom': denom}, false)!; + expect(rat.numerator, BigInt.parse(numer)); + expect(rat.denominator, BigInt.parse(denom)); + // Ensure round-trip + final back = rat2fract(rat, false)!; + expect(back['numer'], numer); + expect(back['denom'], denom); + }); + + test('fract2rat correctly parses strings that would overflow double', () { + final numer = '340282366920938463463374607431768211457'; // > 2^128 + final denom = '1'; + final rat = fract2rat({'numer': numer, 'denom': denom}, false)!; + expect(rat.numerator, BigInt.parse(numer)); + expect(rat.denominator, BigInt.one); + }); } From 8f1dbfffceca65a435f087aebd46ddd4a974e62b Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 2 Sep 2025 11:41:26 +0000 Subject: [PATCH 2/2] Auto-fill sell amount when order is selected in taker form Co-authored-by: charl --- lib/bloc/taker_form/taker_bloc.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/bloc/taker_form/taker_bloc.dart b/lib/bloc/taker_form/taker_bloc.dart index b884f82514..01e7ddc976 100644 --- a/lib/bloc/taker_form/taker_bloc.dart +++ b/lib/bloc/taker_form/taker_bloc.dart @@ -233,6 +233,11 @@ class TakerBloc extends Bloc { autovalidate: switchingCoin ? () => false : null, )); + // Auto-fill the exact maker amount when an order is selected + if (event.order != null) { + add(TakerSetSellAmount(event.order!.maxVolume)); + } + if (!state.autovalidate) add(TakerVerifyOrderVolume()); await _autoActivateCoin(state.selectedOrder?.coin);