From f99fab851572e9878f94ca65bb48035af657fb19 Mon Sep 17 00:00:00 2001 From: woodser Date: Sun, 5 May 2024 07:51:40 -0400 Subject: [PATCH] repeat try withdraw tx and fix amount details --- .../main/java/haveno/core/trade/Trade.java | 2 +- .../main/funds/withdrawal/WithdrawalView.java | 103 ++++++++++-------- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index 9ab8f24bea..352b7d06cc 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -843,7 +843,7 @@ public abstract class Trade implements Tradable, Model { public void importMultisigHex() { synchronized (walletLock) { - synchronized (HavenoUtils.getDaemonLock()) { // TODO: lock on daemon because wallet2's import_multisig calls refresh: https://github.com/monero-project/monero/issues/9312 + synchronized (HavenoUtils.getDaemonLock()) { // lock on daemon because import calls full refresh for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { try { doImportMultisigHex(); diff --git a/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java b/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java index 63f17eb73b..abdcde0b1b 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java @@ -38,12 +38,11 @@ import com.google.inject.Inject; import haveno.common.util.Tuple4; import haveno.core.locale.Res; import haveno.core.trade.HavenoUtils; -import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; +import haveno.core.trade.protocol.TradeProtocol; import haveno.core.user.DontShowAgainLookup; import haveno.core.util.validation.BtcAddressValidator; import haveno.core.xmr.listeners.XmrBalanceListener; -import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.setup.WalletsSetup; import haveno.core.xmr.wallet.XmrWalletService; import haveno.desktop.common.view.ActivatableView; @@ -72,9 +71,7 @@ import monero.wallet.model.MoneroTxConfig; import monero.wallet.model.MoneroTxWallet; import java.math.BigInteger; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import static haveno.desktop.util.FormBuilder.addTitledGroupBg; import static haveno.desktop.util.FormBuilder.addTopLabelInputTextField; @@ -107,6 +104,7 @@ public class WithdrawalView extends ActivatableView { private ToggleGroup feeToggleGroup; private boolean feeExcluded; private int rowIndex = 0; + private final static int MAX_ATTEMPTS = 3; /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, lifecycle @@ -259,44 +257,31 @@ public class WithdrawalView extends ActivatableView { // get withdraw address final String withdrawToAddress = withdrawToTextField.getText(); - // create tx + // check sufficient available balance if (amount.compareTo(BigInteger.ZERO) <= 0) throw new RuntimeException(Res.get("portfolio.pending.step5_buyer.amountTooLow")); - log.info("Creating withdraw tx"); - long startTime = System.currentTimeMillis(); - MoneroTxWallet tx = xmrWalletService.createTx(new MoneroTxConfig() - .setAccountIndex(0) - .setAmount(amount) - .setAddress(withdrawToAddress) - .setSubtractFeeFrom(feeExcluded ? null : Arrays.asList(0))); - log.info("Done creating withdraw tx in {} ms", System.currentTimeMillis() - startTime); - // create confirmation message - BigInteger receiverAmount = tx.getOutgoingTransfer().getDestinations().get(0).getAmount(); - BigInteger fee = tx.getFee(); - String messageText = Res.get("shared.sendFundsDetailsWithFee", - HavenoUtils.formatXmr(amount, true), - withdrawToAddress, - HavenoUtils.formatXmr(fee, true), - HavenoUtils.formatXmr(receiverAmount, true)); + // create tx + MoneroTxWallet tx = null; + for (int i = 0; i < MAX_ATTEMPTS; i++) { + try { + log.info("Creating withdraw tx"); + long startTime = System.currentTimeMillis(); + tx = xmrWalletService.createTx(new MoneroTxConfig() + .setAccountIndex(0) + .setAmount(amount) + .setAddress(withdrawToAddress) + .setSubtractFeeFrom(feeExcluded ? null : Arrays.asList(0))); + log.info("Done creating withdraw tx in {} ms", System.currentTimeMillis() - startTime); + break; + } catch (Exception e) { + log.warn("Error creating creating withdraw tx, attempt={}/{}, error={}", i + 1, MAX_ATTEMPTS, e.getMessage()); + if (i == MAX_ATTEMPTS - 1) throw e; + HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying + } + } // popup confirmation message - Popup popup = new Popup(); - popup.headLine(Res.get("funds.withdrawal.confirmWithdrawalRequest")) - .confirmation(messageText) - .actionButtonText(Res.get("shared.yes")) - .onAction(() -> { - if (xmrWalletService.isWalletEncrypted()) { - walletPasswordWindow.headLine(Res.get("walletPasswordWindow.headline")).onSuccess(() -> { - relayTx(tx, withdrawToAddress, amount, fee); - }).onClose(() -> { - popup.hide(); - }).hideForgotPasswordButton().show(); - } else { - relayTx(tx, withdrawToAddress, amount, fee); - } - }) - .closeButtonText(Res.get("shared.cancel")) - .show(); + popupConfirmationMessage(tx); } catch (Throwable e) { if (e.getMessage().contains("enough")) new Popup().warning(Res.get("funds.withdrawal.warn.amountExceeds")).show(); else { @@ -307,6 +292,38 @@ public class WithdrawalView extends ActivatableView { } } + private void popupConfirmationMessage(MoneroTxWallet tx) { + + // create confirmation message + String withdrawToAddress = tx.getOutgoingTransfer().getDestinations().get(0).getAddress(); + BigInteger receiverAmount = tx.getOutgoingTransfer().getDestinations().get(0).getAmount(); + BigInteger fee = tx.getFee(); + String messageText = Res.get("shared.sendFundsDetailsWithFee", + HavenoUtils.formatXmr(amount, true), + withdrawToAddress, + HavenoUtils.formatXmr(fee, true), + HavenoUtils.formatXmr(receiverAmount, true)); + + // popup confirmation message + Popup popup = new Popup(); + popup.headLine(Res.get("funds.withdrawal.confirmWithdrawalRequest")) + .confirmation(messageText) + .actionButtonText(Res.get("shared.yes")) + .onAction(() -> { + if (xmrWalletService.isWalletEncrypted()) { + walletPasswordWindow.headLine(Res.get("walletPasswordWindow.headline")).onSuccess(() -> { + relayTx(tx, withdrawToAddress, receiverAmount, fee); + }).onClose(() -> { + popup.hide(); + }).hideForgotPasswordButton().show(); + } else { + relayTx(tx, withdrawToAddress, receiverAmount, fee); + } + }) + .closeButtonText(Res.get("shared.cancel")) + .show(); + } + private void relayTx(MoneroTxWallet tx, String withdrawToAddress, BigInteger receiverAmount, BigInteger fee) { try { xmrWalletService.getWallet().relayTx(tx); @@ -318,16 +335,6 @@ public class WithdrawalView extends ActivatableView { .show(); } log.debug("onWithdraw onSuccess tx ID:{}", tx.getHash()); - - // TODO: remove this? - List trades = new ArrayList<>(tradeManager.getObservableList()); - trades.stream() - .filter(Trade::isPayoutPublished) - .forEach(trade -> xmrWalletService.getAddressEntry(trade.getId(), XmrAddressEntry.Context.TRADE_PAYOUT) - .ifPresent(addressEntry -> { - if (xmrWalletService.getBalanceForAddress(addressEntry.getAddressString()).compareTo(BigInteger.ZERO) == 0) - tradeManager.onTradeCompleted(trade); - })); } catch (Exception e) { e.printStackTrace(); new Popup().warning(e.getMessage()).show();