diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md index b6ac94d8..48b61a6a 100644 --- a/android/CHANGELOG.md +++ b/android/CHANGELOG.md @@ -6,6 +6,18 @@ follow [https://changelog.md/](https://changelog.md/) guidelines. ## [Unreleased] + +## [49.1] - 2022-03-17 + +### FIXED +- Bug when fetching legacy Contact model after SQLDelight upgrade (on 49) +- Use of Math.toIntExact() which isn't supported on lower api levels (introduced in SQLDelight +upgrade) +- MuunAmountInput handling of SATs (currencies without decimals) +- Incorrect handling of changeCurrency and useAllFunds in send flow, introduced in our send payment +flow rewrite (48.2) +- Minor copy change when copying a LN payment hash to clipboard + ## [49] - 2022-03-16 ### ADDED @@ -13,6 +25,15 @@ follow [https://changelog.md/](https://changelog.md/) guidelines. - Extra metadata for rare crash scenario - Multiple route hints support in our invoices +### CHANGED +- Upgrade gradle to 7.3.3 to support JDK17 (ARM support) +- Upgrade AGP to 7.0.4 for gradle 7.3 compat +- Upgrade SQDelight to 1.5.3 for gradle 7.3 compat (hughe refactor and rework of data layer) +- Upgrade Kotlin to 1.6.10 for gradle 7.3 compat +- Upgrade Dagger to 2.40.5 for gradle 7.3 compat +- Upgrade checkstyle to 9.2.1 +- Make libwallet it's own gradle project to work nicely with AndroidStudio + ### FIXED - Show new outgoing operation badge animation when using deeplink + process death/app not started - Rare crash probably due to quick flurry of click events diff --git a/android/apollo/src/main/java/io/muun/apollo/data/db/contact/ContactDao.java b/android/apollo/src/main/java/io/muun/apollo/data/db/contact/ContactDao.java index 1b72d7d6..cb20ed2d 100644 --- a/android/apollo/src/main/java/io/muun/apollo/data/db/contact/ContactDao.java +++ b/android/apollo/src/main/java/io/muun/apollo/data/db/contact/ContactDao.java @@ -105,8 +105,8 @@ private Contact fromAllFields( lastName, profilePictureUrl ), - Math.toIntExact(maxAddressVersion), - PublicKey.deserializeFromBase58(publicKeyPath, publicKeyPath), + (int) maxAddressVersion, + PublicKey.deserializeFromBase58(publicKeyPath, serializedPublicKey), cosigningPublicKey, lastDerivationIndex ); diff --git a/android/apolloui/build.gradle b/android/apolloui/build.gradle index 7ab77144..44c4fcf0 100644 --- a/android/apolloui/build.gradle +++ b/android/apolloui/build.gradle @@ -80,8 +80,8 @@ android { applicationId "io.muun.apollo" minSdkVersion 19 targetSdkVersion 30 - versionCode 900 - versionName "49" + versionCode 901 + versionName "49.1" // Needed to make sure these classes are available in the main DEX file for API 19 // See: https://spin.atomicobject.com/2018/07/16/support-kitkat-multidex/ diff --git a/android/apolloui/src/main/AndroidManifest.xml b/android/apolloui/src/main/AndroidManifest.xml index bbd07227..4881ab82 100644 --- a/android/apolloui/src/main/AndroidManifest.xml +++ b/android/apolloui/src/main/AndroidManifest.xml @@ -363,8 +363,8 @@ */ private void handleAndroidSupremeLocalizationBug(StringBuilder s, DecorationHandler handler) { - if (decimalSeparator != '.') { + if (decimalSeparator != '.' && maxFractionalDigits != 0) { replace(s, start, start + after, '.', decimalSeparator); diff --git a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/fragments/home/HomeFragment.kt b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/fragments/home/HomeFragment.kt index 1830676d..77a15c9f 100644 --- a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/fragments/home/HomeFragment.kt +++ b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/fragments/home/HomeFragment.kt @@ -208,20 +208,12 @@ class HomeFragment: SingleFragment(), HomeView { balanceView.setBalance(homeState) setChevronAnimation(homeState.utxoSetState) - // We want one of the cards to "occupy space" (aka be invisible not gone) to avoid visual - // jumps/glitches - taprootCard.visibility = View.GONE - securityCenterCard.visibility = View.INVISIBLE - - blockClock.visibility = View.GONE - // Due to (complex) business logic reasons, only 1 of these cards is currently displayed var displayedMuunHomeCard: MuunHomeCard? = null - val taprootStatus = homeState.taprootFeatureStatus if (!homeState.user.isRecoverable) { displayedMuunHomeCard = securityCenterCard - } else when (taprootStatus) { + } else when (homeState.taprootFeatureStatus) { UserActivatedFeatureStatus.OFF -> { } // Do nothing UserActivatedFeatureStatus.CAN_PREACTIVATE -> displayedMuunHomeCard = taprootCard UserActivatedFeatureStatus.CAN_ACTIVATE -> displayedMuunHomeCard = taprootCard @@ -232,12 +224,16 @@ class HomeFragment: SingleFragment(), HomeView { blockClock.value = homeState.blocksToTaproot - displayedMuunHomeCard?.let { - it.visibility = View.VISIBLE - if (it == taprootCard) { - // Avoid having 2x height when taprootCard is shown (see visual jump comment above) + if (displayedMuunHomeCard != null) { + displayedMuunHomeCard.visibility = View.VISIBLE + if (displayedMuunHomeCard == taprootCard) { securityCenterCard.visibility = View.GONE + } else { + taprootCard.visibility = View.GONE } + } else { + securityCenterCard.visibility = View.GONE + taprootCard.visibility = View.GONE } } diff --git a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/home/HomeActivity.java b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/home/HomeActivity.java index 6ca61cd5..41f1699e 100644 --- a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/home/HomeActivity.java +++ b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/home/HomeActivity.java @@ -115,20 +115,19 @@ protected void initializeUi() { bottomNav.setOnNavigationItemSelectedListener(item -> { - final Bundle bundle = new Bundle(); + final Bundle bundle = new Bundle(); - if (item.getItemId() == R.id.security_center_fragment) { - final SecurityCenterFragmentArgs args = new SecurityCenterFragmentArgs - .Builder(SECURITY_CENTER_ORIGIN.SHIELD_BUTTON) - .build(); + if (item.getItemId() == R.id.security_center_fragment) { + final SecurityCenterFragmentArgs args = new SecurityCenterFragmentArgs + .Builder(SECURITY_CENTER_ORIGIN.SHIELD_BUTTON) + .build(); - bundle.putAll(args.toBundle()); - } + bundle.putAll(args.toBundle()); + } - navigateToItem(item.getItemId(), bundle); - return true; - } - ); + navigateToItem(item.getItemId(), bundle); + return true; + }); bottomNav.setOnNavigationItemReselectedListener(item -> { // do nothing here, it will prevent recreating same fragment }); diff --git a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/home/HomePresenter.java b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/home/HomePresenter.java index a48b5c60..73fa3fb8 100644 --- a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/home/HomePresenter.java +++ b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/home/HomePresenter.java @@ -88,6 +88,10 @@ public void onActivityCreated() { fetchRealTimeData.runForced(); } + /** + * Call to report activity was destroyed. + * TODO: this should have a base presenter method associated + */ public void onActivityDestroyed() { operationsCache.stop(); } @@ -147,10 +151,16 @@ public void navigateToOperations() { navigator.navigateToOperations((Activity) view); } + /** + * Navigate to send feedbback screen. + */ public void navigateToSendFeedbackScreen() { navigator.navigateToSendGenericFeedback(getContext()); } + /** + * Avoid showing taproot celebration again. + */ public void reportTaprootCelebrationShown() { userSel.setPendingTaprootCelebration(false); } diff --git a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/new_operation/NewOperationActivity.kt b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/new_operation/NewOperationActivity.kt index a535eb31..bfb1e87e 100644 --- a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/new_operation/NewOperationActivity.kt +++ b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/new_operation/NewOperationActivity.kt @@ -346,10 +346,10 @@ class NewOperationActivity : SingleFragmentActivity(), Ne val paymentContext = state.resolved.paymentContext amountInput.setExchangeRateProvider(paymentContext.buildExchangeRateProvider()) - amountInput.setOnChangeListener { amount: MonetaryAmount -> + amountInput.setOnChangeListener { oldAmount: MonetaryAmount, newAmount: MonetaryAmount -> amountInput.setAmountError(false) actionButton.isEnabled = true - presenter.updateAmount(amount, state) + presenter.updateAmount(oldAmount, newAmount, state) } useAllFundsView.isEnabled = !balance.isZero diff --git a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/new_operation/NewOperationPresenter.kt b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/new_operation/NewOperationPresenter.kt index 7b12601d..16c133d8 100644 --- a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/new_operation/NewOperationPresenter.kt +++ b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/new_operation/NewOperationPresenter.kt @@ -269,15 +269,15 @@ class NewOperationPresenter @Inject constructor( return true } - fun updateAmount(amount: MonetaryAmount, state: EnterAmountState) { + fun updateAmount(oldAmount: MonetaryAmount, newAmount: MonetaryAmount, state: EnterAmountState) { // This is our way of detecting a currency change. Since the feature is abstracted into // MuunAmountInput and the exposed API reports the new amount. - if (amount.currency.currencyCode != state.amount.inInputCurrency.currency) { - state.changeCurrency(amount.currency.currencyCode) + if (newAmount.currency.currencyCode != state.amount.inInputCurrency.currency) { + state.changeCurrencyWithAmount(newAmount.currency.currencyCode, oldAmount.toLibwallet()) } - if (!state.partialValidate(amount.toLibwallet())) { + if (!state.partialValidate(newAmount.toLibwallet())) { view.setAmountInputError() } } diff --git a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/operation_detail/OperationDetailActivity.java b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/operation_detail/OperationDetailActivity.java index 6e9623de..059bb4a4 100644 --- a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/operation_detail/OperationDetailActivity.java +++ b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/operation_detail/OperationDetailActivity.java @@ -285,7 +285,7 @@ private void setIncomingSwapOperation(final UiOperation operation) { swapPaymentHashItem.setVisibility( !TextUtils.isEmpty(paymentHash) ? View.VISIBLE : View.GONE ); - swapPaymentHashItem.setOnIconClickListener(view -> onCopyPreimageToClipboard(paymentHash)); + swapPaymentHashItem.setOnIconClickListener(v -> onCopyPaymentHashToClipboard(paymentHash)); final String preimage = operation.getPreimage(); swapPreimageItem.setDescription(preimage); @@ -351,6 +351,11 @@ private void onCopyPreimageToClipboard(String preimage) { showTextToast(getString(R.string.operation_detail_preimage_copied)); } + private void onCopyPaymentHashToClipboard(String paymentHash) { + presenter.copySwapPreimageToClipboard(paymentHash); + showTextToast(getString(R.string.operation_detail_preimage_copied)); + } + private void onCopyTransactionIdToClipboard(String transactionId) { presenter.copyTransactionIdToClipboard(transactionId); showTextToast(getString(R.string.operation_detail_txid_copied)); diff --git a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/select_amount/SelectAmountActivity.kt b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/select_amount/SelectAmountActivity.kt index a2269753..74506d3b 100644 --- a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/select_amount/SelectAmountActivity.kt +++ b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/select_amount/SelectAmountActivity.kt @@ -111,7 +111,7 @@ class SelectAmountActivity : BaseActivity(), SelectAmount override fun setExchangeRateProvider(exchangeRateProvider: ExchangeRateProvider) { amountInput.setExchangeRateProvider(exchangeRateProvider) - amountInput.setOnChangeListener(this::onAmountChange) + amountInput.setOnChangeListener { _, newAmount -> onAmountChange(newAmount) } amountInput.isEnabled = true amountInput.requestFocusInput() } diff --git a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/view/MuunAmountInput.java b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/view/MuunAmountInput.java index 865b6baf..8258670b 100644 --- a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/view/MuunAmountInput.java +++ b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/view/MuunAmountInput.java @@ -46,9 +46,9 @@ public interface OnChangeListener { /** * This method is called to notify you that the amount in this input has changed. The - * param value holds the new amount. + * param values hold the old and the new amount. */ - void onChange(MonetaryAmount value); + void onChange(MonetaryAmount oldValue, MonetaryAmount newValue); } static final ViewProps viewProps @@ -104,7 +104,7 @@ public interface OnChangeListener { private DecimalFormatSymbols symbols; private boolean isMakingInternalChange; - private boolean isCurrentyChangingCurrency; + private boolean isCurrentlyChangingCurrency; public MuunAmountInput(Context context) { super(context); @@ -277,16 +277,17 @@ private void onNumberInputChange(String numberString) { newValue = newValue.divide(BitcoinUtils.SATOSHIS_PER_BITCOIN); } + final MonetaryAmount oldValue = value; value = newValue; // Once we start typing, text should have this color, unless overruled by setAmountError inputAmount.setTextColor(normalNumberColor); - if (!isCurrentyChangingCurrency) { + if (!isCurrentlyChangingCurrency) { valueBeforeCurrencyChange = newValue; } - notifyChange(); + notifyChange(oldValue, newValue); } private void onCurrencyInputChange(String newCode) { @@ -309,17 +310,18 @@ private void onCurrencyInputChange(String newCode) { newValue = Money.of(value.getNumber(), newCode); } + final MonetaryAmount oldValue = value; value = newValue; adjustFractionalDigits(); updateCurrencyCodeText(); updateAmountText(true); - notifyChange(); + notifyChange(oldValue, newValue); } - private void notifyChange() { + private void notifyChange(MonetaryAmount oldValue, MonetaryAmount newValue) { if (onChangeListener != null) { - onChangeListener.onChange(value); + onChangeListener.onChange(oldValue, newValue); } } @@ -352,7 +354,7 @@ private void updateCurrencyCodeText(BitcoinUnit bitcoinUnit) { private void updateAmountText(boolean isDueToCurrencyChange) { isMakingInternalChange = true; - isCurrentyChangingCurrency = isDueToCurrencyChange; + isCurrentlyChangingCurrency = isDueToCurrencyChange; if (value.isPositive()) { final String text = MoneyHelper.formatInputMonetaryAmount( @@ -372,7 +374,7 @@ private void updateAmountText(boolean isDueToCurrencyChange) { inputAmount.setText(""); } - isCurrentyChangingCurrency = false; + isCurrentlyChangingCurrency = false; isMakingInternalChange = false; } diff --git a/android/apolloui/src/main/res/layout/fragment_home.xml b/android/apolloui/src/main/res/layout/fragment_home.xml index 6acee25f..13e5f452 100644 --- a/android/apolloui/src/main/res/layout/fragment_home.xml +++ b/android/apolloui/src/main/res/layout/fragment_home.xml @@ -88,7 +88,7 @@ android:layout_height="wrap_content" android:layout_marginTop="32dp" android:layout_marginBottom="64dp" - android:visibility="invisible" + android:visibility="gone" tools:visibility="visible" /> - Por el momento, sólo se puede pagar a facturas que incluyan un monto. Por favor, crea o solicita una nueva. + Por el momento, sólo se puede pagar a facturas que incluyan un monto. Por favor, + crea o solicita una nueva. No es posible pagar esta factura @@ -295,6 +296,9 @@ Preimagen del pago copiada al portapapeles + + Hash del pago copiado al portapapeles + Identificador copiado al portapapeles @@ -1382,10 +1386,10 @@ ¿Cómo se puede cancelar esta transacción? - Esta transacción tiene RBF (replace-by-fee) activado. RBF le permite al remitente incrementar - la comisión original para una confirmación más rápida, pero también puede usarlo para - cancelar la transacción. A menos que conozcas y confíes en el remitente, considéralo - un riesgo hasta que se confirme la transacción. + Esta transacción tiene RBF (replace-by-fee) activado. RBF le permite al remitente + incrementar la comisión original para una confirmación más rápida, pero también puede + usarlo para cancelar la transacción. A menos que conozcas y confíes en el remitente, + considéralo un riesgo hasta que se confirme la transacción. Turbo channels diff --git a/android/apolloui/src/main/res/values/strings.xml b/android/apolloui/src/main/res/values/strings.xml index 2908de8d..78a96343 100644 --- a/android/apolloui/src/main/res/values/strings.xml +++ b/android/apolloui/src/main/res/values/strings.xml @@ -146,7 +146,8 @@ This invoice doesn\’t include an amount - At the moment, you can only pay to invoices that include an amount. Please, create or request a new one. + At the moment, you can only pay to invoices that include an amount. Please, create or + request a new one. Unable to pay this invoice @@ -290,6 +291,7 @@ Invoice copied to clipboard Payment preimage copied to clipboard + Payment hash copied to clipboard Transaction ID copied to clipboard Amount copied to clipboard Network fee copied to clipboard @@ -1333,13 +1335,14 @@ How can this transaction be canceled? This transaction has RBF (replace-by-fee) enabled. RBF allows the sender to raise the - original fee for faster confirmation, but they can also use it to cancel the transaction. Unless - you know and trust the sender, consider it a risk until the transaction is confirmed. + original fee for faster confirmation, but they can also use it to cancel the transaction. + Unless you know and trust the sender, consider it a risk until the transaction is confirmed. Turbo channels - Learn more about the trade-offs of turbo channels. + Learn more about the + trade-offs of turbo channels. Disable turbo channels? diff --git a/android/apolloui/src/test/java/io/muun/apollo/presentation/model/text_decoration/MoneyDecorationTest.kt b/android/apolloui/src/test/java/io/muun/apollo/presentation/model/text_decoration/MoneyDecorationTest.kt index a6990a02..0569a7f2 100644 --- a/android/apolloui/src/test/java/io/muun/apollo/presentation/model/text_decoration/MoneyDecorationTest.kt +++ b/android/apolloui/src/test/java/io/muun/apollo/presentation/model/text_decoration/MoneyDecorationTest.kt @@ -138,12 +138,20 @@ class MoneyDecorationTest { Given(it, "|123", 0).add(".").expect("|123") + // Test input initializes with some amount + + Given(it, "|", 0).add("0").expect("0|") + + Given(it, "0|", 0).add("0").expect("0|") + + Given(it, "|", 0).add("2000").expect("2_000|") + // This is kindof a benevolent, simple paste - Given(it, "44|", 0).add("123.123").expect("44123|") + Given(it, "44|", 0).add("123.123").expect("44_123|") - Given(it, "4|4", 0).add("123.123").expect("4123|4") + Given(it, "4|4", 0).add("123.123").expect("41_23|4") - Given(it, "|44", 0).add("123.123").expect("123|44") + Given(it, "|44", 0).add("123.123").expect("12_3|44") // TODO test paste } diff --git a/libwallet/newop/context.go b/libwallet/newop/context.go index 0fdc7e44..7f03666a 100644 --- a/libwallet/newop/context.go +++ b/libwallet/newop/context.go @@ -21,10 +21,11 @@ func (c *PaymentContext) toBitcoinAmount(sats int64, inputCurrency string) *Bitc NewMonetaryAmountFromSatoshis(sats), inputCurrency, ) - return amount.toBitcoinAmount( - c.ExchangeRateWindow, - c.PrimaryCurrency, - ) + return &BitcoinAmount{ + InSat: sats, + InInputCurrency: amount, + InPrimaryCurrency: c.ExchangeRateWindow.convert(amount, c.PrimaryCurrency), + } } func newPaymentAnalyzer(context *PaymentContext) *operation.PaymentAnalyzer { diff --git a/libwallet/newop/state.go b/libwallet/newop/state.go index b63914fe..939c78db 100644 --- a/libwallet/newop/state.go +++ b/libwallet/newop/state.go @@ -193,7 +193,7 @@ func (s *StartState) resolveBip70(uri *libwallet.MuunPaymentURI, network *libwal } next.emit() - // If the error contains the expired string, that means that the invoice has expired + // If the error contains the expired string, that means that the invoice has expired } else if strings.Contains(err.Error(), "failed to unmarshal payment request") { next := &ErrorState{ BaseState: s.BaseState, @@ -202,7 +202,7 @@ func (s *StartState) resolveBip70(uri *libwallet.MuunPaymentURI, network *libwal } next.emit() - // In any other case we display the invalid address message + // In any other case we display the invalid address message } else { next := &ErrorState{ BaseState: s.BaseState, @@ -299,7 +299,7 @@ func (s *ResolveState) setContextWithTime(context *PaymentContext, now time.Time amount := amount.toBitcoinAmount(context.ExchangeRateWindow, context.PrimaryCurrency) return s.emitValidate(&Resolved{ - BaseState: s.BaseState, + BaseState: s.BaseState, PaymentIntent: s.PaymentIntent, PaymentContext: context, PresetAmount: amount, @@ -353,7 +353,7 @@ func (s *ResolveState) emitValidateLightning(context *PaymentContext, invoice *l func (s *ResolveState) emitValidate(resolved *Resolved, amount *BitcoinAmount, context *PaymentContext) error { nextState := &ValidateState{ - Resolved: resolved, + Resolved: resolved, AmountInfo: &AmountInfo{ TotalBalance: context.toBitcoinAmount(context.totalBalance(), "BTC"), Amount: amount, @@ -443,27 +443,47 @@ func (s *EnterAmountState) PartialValidate(inputAmount *MonetaryAmount) (bool, e minAmount = 0 } - if amountInSat < minAmount || amountInSat > s.TotalBalance.InSat { + if amountInSat < minAmount || amountInSat > s.TotalBalance.InSat { return false, nil } return true, nil } +// ChangeCurrency is deprecated. Prefer the newer, ChangeCurrencyWithAmount(currency, inputAmount) func (s *EnterAmountState) ChangeCurrency(currency string) error { + return s.ChangeCurrencyWithAmount(currency, s.Amount.InInputCurrency) +} + +// ChangeCurrencyWithAmount respond to the user action of changing the current input currency to a new one, +// while also updating the input amount, needed for performing the necessary conversion. +// Note: this state machine doesn't receive partial updates for the input amount each time the +// user types or deletes a digit, so ChangeCurrencyWithAmount needs to receive the updates input amount. +func (s *EnterAmountState) ChangeCurrencyWithAmount(currency string, inputAmount *MonetaryAmount) error { exchangeRateWindow := s.PaymentContext.ExchangeRateWindow - amount := &BitcoinAmount{ - InSat: s.Amount.InSat, - InInputCurrency: exchangeRateWindow.convert(s.Amount.InInputCurrency, currency), - InPrimaryCurrency: s.Amount.InPrimaryCurrency, + + newTotalBalance := s.PaymentContext.toBitcoinAmount( + s.PaymentContext.totalBalance(), + currency, + ) + + var amount *BitcoinAmount + // IF amount == balance THEN tffa/useAllFunds + // See EnterAmount transition. + if inputAmount.String() == s.TotalBalance.InInputCurrency.String() { + amount = newTotalBalance + } else { + amount = &BitcoinAmount{ + InSat: int64(inputAmount.toBtc(exchangeRateWindow)), + InInputCurrency: exchangeRateWindow.convert(inputAmount, currency), + InPrimaryCurrency: exchangeRateWindow.convert(inputAmount, s.PaymentContext.PrimaryCurrency), + } } + nextState := &EnterAmountState{ Resolved: s.Resolved, Amount: amount, - TotalBalance: s.PaymentContext.toBitcoinAmount( - s.PaymentContext.totalBalance(), - currency, - ), + TotalBalance: newTotalBalance, } nextState.emitUpdate(UpdateInPlace) @@ -761,8 +781,8 @@ func (s *ValidateLightningState) Continue() error { return s.emitBalanceError(OperationErrorAmountGreaterThanBalance, analysis, inputCurrency) - case operation.AnalysisStatusAmountTooSmall: - return s.emitError(OperationErrorAmountTooSmall) + case operation.AnalysisStatusAmountTooSmall: + return s.emitError(OperationErrorAmountTooSmall) default: return fmt.Errorf("unrecognized analysis status: %v", analysis.Status)