diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties
index e0c28fb8dd..f8ef28949c 100644
--- a/core/src/main/resources/i18n/displayStrings.properties
+++ b/core/src/main/resources/i18n/displayStrings.properties
@@ -1040,11 +1040,13 @@ funds.withdrawal.inputs=Inputs selection
 funds.withdrawal.useAllInputs=Use all available inputs
 funds.withdrawal.useCustomInputs=Use custom inputs
 funds.withdrawal.receiverAmount=Receiver's amount
+funds.withdrawal.sendMax=Send max available
 funds.withdrawal.senderAmount=Sender's amount
 funds.withdrawal.feeExcluded=Amount excludes mining fee
 funds.withdrawal.feeIncluded=Amount includes mining fee
 funds.withdrawal.fromLabel=Withdraw from address
 funds.withdrawal.toLabel=Withdraw to address
+funds.withdrawal.maximum=MAX
 funds.withdrawal.memoLabel=Withdrawal memo
 funds.withdrawal.memo=Optionally fill memo
 funds.withdrawal.withdrawButton=Withdraw selected
diff --git a/core/src/main/resources/i18n/displayStrings_es.properties b/core/src/main/resources/i18n/displayStrings_es.properties
index 990ef7941c..bd4ee417a2 100644
--- a/core/src/main/resources/i18n/displayStrings_es.properties
+++ b/core/src/main/resources/i18n/displayStrings_es.properties
@@ -848,6 +848,7 @@ funds.withdrawal.inputs=Selección de entradas
 funds.withdrawal.useAllInputs=Usar todos los entradas disponibles
 funds.withdrawal.useCustomInputs=Usar entradas personalizados
 funds.withdrawal.receiverAmount=Cantidad del receptor
+funds.withdrawal.sendMax=Enviar máximo disponible
 funds.withdrawal.senderAmount=Cantidad del emisor
 funds.withdrawal.feeExcluded=La cantidad no incluye comisión de minado
 funds.withdrawal.feeIncluded=La cantidad incluye comisión de minado
diff --git a/core/src/main/resources/i18n/displayStrings_fr.properties b/core/src/main/resources/i18n/displayStrings_fr.properties
index 462bcef554..8d3b4ce468 100644
--- a/core/src/main/resources/i18n/displayStrings_fr.properties
+++ b/core/src/main/resources/i18n/displayStrings_fr.properties
@@ -849,6 +849,7 @@ funds.withdrawal.inputs=Sélection de la valeur à saisir
 funds.withdrawal.useAllInputs=Utiliser toutes les valeurs disponibles
 funds.withdrawal.useCustomInputs=Utiliser une valeur de saisie personnalisée
 funds.withdrawal.receiverAmount=Montant du destinataire
+funds.withdrawal.sendMax=Envoyer max disponible
 funds.withdrawal.senderAmount=Montant de l'expéditeur
 funds.withdrawal.feeExcluded=Montant excluant les frais de minage
 funds.withdrawal.feeIncluded=Montant incluant frais de minage
diff --git a/core/src/main/resources/i18n/displayStrings_it.properties b/core/src/main/resources/i18n/displayStrings_it.properties
index 97b7fb6b15..044873db1a 100644
--- a/core/src/main/resources/i18n/displayStrings_it.properties
+++ b/core/src/main/resources/i18n/displayStrings_it.properties
@@ -847,6 +847,7 @@ funds.withdrawal.inputs=Selezione input
 funds.withdrawal.useAllInputs=Utilizza tutti gli input disponibili
 funds.withdrawal.useCustomInputs=Utilizza input personalizzati
 funds.withdrawal.receiverAmount=Importo del destinatario
+funds.withdrawal.sendMax=Inviare massimo disponibile
 funds.withdrawal.senderAmount=Importo del mittente
 funds.withdrawal.feeExcluded=L'importo esclude la commissione di mining
 funds.withdrawal.feeIncluded=L'importo include la commissione di mining
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 abdcde0b1b..c5e40d9348 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
@@ -35,7 +35,7 @@
 package haveno.desktop.main.funds.withdrawal;
 
 import com.google.inject.Inject;
-import haveno.common.util.Tuple4;
+import haveno.common.util.Tuple3;
 import haveno.core.locale.Res;
 import haveno.core.trade.HavenoUtils;
 import haveno.core.trade.TradeManager;
@@ -48,6 +48,7 @@ import haveno.core.xmr.wallet.XmrWalletService;
 import haveno.desktop.common.view.ActivatableView;
 import haveno.desktop.common.view.FxmlView;
 import haveno.desktop.components.BusyAnimation;
+import haveno.desktop.components.HyperlinkWithIcon;
 import haveno.desktop.components.TitledGroupBg;
 import haveno.desktop.main.overlays.popups.Popup;
 import haveno.desktop.main.overlays.windows.TxDetails;
@@ -60,13 +61,11 @@ import javafx.beans.value.ChangeListener;
 import javafx.fxml.FXML;
 import javafx.scene.control.Label;
 import javafx.scene.control.TextField;
-import javafx.scene.control.RadioButton;
-import javafx.scene.control.ToggleGroup;
-import javafx.scene.control.Toggle;
 import javafx.scene.control.Button;
 import javafx.scene.layout.GridPane;
 import javafx.scene.layout.StackPane;
 import javafx.scene.layout.VBox;
+import monero.common.MoneroUtils;
 import monero.wallet.model.MoneroTxConfig;
 import monero.wallet.model.MoneroTxWallet;
 
@@ -90,7 +89,6 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
 
     private Label amountLabel;
     private TextField amountTextField, withdrawToTextField, withdrawMemoTextField;
-    private RadioButton feeExcludedRadioButton, feeIncludedRadioButton;
 
     private final XmrWalletService xmrWalletService;
     private final TradeManager tradeManager;
@@ -100,11 +98,9 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
     private BigInteger amount = BigInteger.ZERO;
     private ChangeListener<String> amountListener;
     private ChangeListener<Boolean> amountFocusListener;
-    private ChangeListener<Toggle> feeToggleGroupListener;
-    private ToggleGroup feeToggleGroup;
-    private boolean feeExcluded;
     private int rowIndex = 0;
     private final static int MAX_ATTEMPTS = 3;
+    boolean sendMax = false;
 
     ///////////////////////////////////////////////////////////////////////////////////////////
     // Constructor, lifecycle
@@ -141,20 +137,15 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
         withdrawToTextField = addTopLabelInputTextField(gridPane, ++rowIndex,
                 Res.get("funds.withdrawal.toLabel", Res.getBaseCurrencyCode())).second;
 
-        feeToggleGroup = new ToggleGroup();
-
-        final Tuple4<Label, TextField, RadioButton, RadioButton> feeTuple3 = FormBuilder.addTopLabelTextFieldRadioButtonRadioButton(gridPane, ++rowIndex, feeToggleGroup,
+        final Tuple3<Label, TextField, HyperlinkWithIcon> feeTuple3 = FormBuilder.addTopLabelTextFieldHyperLink(gridPane, ++rowIndex, "",
                 Res.get("funds.withdrawal.receiverAmount", Res.getBaseCurrencyCode()),
-                "",
-                Res.get("funds.withdrawal.feeExcluded"),
-                Res.get("funds.withdrawal.feeIncluded"),
+                Res.get("funds.withdrawal.sendMax"),
                 0);
 
         amountLabel = feeTuple3.first;
         amountTextField = feeTuple3.second;
         amountTextField.setMinWidth(180);
-        feeExcludedRadioButton = feeTuple3.third;
-        feeIncludedRadioButton = feeTuple3.fourth;
+        HyperlinkWithIcon sendMaxLink = feeTuple3.third;
 
         withdrawMemoTextField = addTopLabelInputTextField(gridPane, ++rowIndex,
                 Res.get("funds.withdrawal.memoLabel", Res.getBaseCurrencyCode())).second;
@@ -175,6 +166,12 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
             }).start();
         });
 
+        sendMaxLink.setOnAction(event -> {
+            sendMax = true;
+            amount = null; // set amount when tx created
+            amountTextField.setText(Res.get("funds.withdrawal.maximum"));
+        });
+
         balanceListener = new XmrBalanceListener() {
             @Override
             public void onBalanceChanged(BigInteger balance) {
@@ -183,6 +180,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
         };
         amountListener = (observable, oldValue, newValue) -> {
             if (amountTextField.focusedProperty().get()) {
+                sendMax = false; // disable max if amount changed while focused
                 try {
                     amount = HavenoUtils.parseXmr(amountTextField.getText());
                 } catch (Throwable t) {
@@ -191,7 +189,9 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
             }
         };
         amountFocusListener = (observable, oldValue, newValue) -> {
-            if (oldValue && !newValue) {
+
+            // parse amount on focus out unless sending max
+            if (oldValue && !newValue && !sendMax) {
                 if (amount.compareTo(BigInteger.ZERO) > 0)
                     amountTextField.setText(HavenoUtils.formatXmr(amount));
                 else
@@ -199,14 +199,6 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
             }
         };
         amountLabel.setText(Res.get("funds.withdrawal.receiverAmount"));
-        feeExcludedRadioButton.setToggleGroup(feeToggleGroup);
-        feeIncludedRadioButton.setToggleGroup(feeToggleGroup);
-        feeToggleGroupListener = (observable, oldValue, newValue) -> {
-            feeExcluded = newValue == feeExcludedRadioButton;
-            amountLabel.setText(feeExcluded ?
-                    Res.get("funds.withdrawal.receiverAmount") :
-                    Res.get("funds.withdrawal.senderAmount"));
-        };
     }
 
 
@@ -229,9 +221,6 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
         amountTextField.textProperty().addListener(amountListener);
         amountTextField.focusedProperty().addListener(amountFocusListener);
         xmrWalletService.addBalanceListener(balanceListener);
-        feeToggleGroup.selectedToggleProperty().addListener(feeToggleGroupListener);
-
-        if (feeToggleGroup.getSelectedToggle() == null) feeToggleGroup.selectToggle(feeExcludedRadioButton);
 
         GUIUtil.requestFocus(withdrawToTextField);
     }
@@ -242,7 +231,6 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
         xmrWalletService.removeBalanceListener(balanceListener);
         amountTextField.textProperty().removeListener(amountListener);
         amountTextField.focusedProperty().removeListener(amountFocusListener);
-        feeToggleGroup.selectedToggleProperty().removeListener(feeToggleGroupListener);
     }
 
 
@@ -254,8 +242,14 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
         if (GUIUtil.isReadyForTxBroadcastOrShowPopup(xmrWalletService)) {
             try {
 
-                // get withdraw address
+                // validate address
                 final String withdrawToAddress = withdrawToTextField.getText();
+                if (!MoneroUtils.isValidAddress(withdrawToAddress, XmrWalletService.getMoneroNetworkType())) {
+                    throw new IllegalArgumentException(Res.get("validation.xmr.invalidAddress"));
+                }
+
+                // set max amount if requested
+                if (sendMax) amount = xmrWalletService.getAvailableBalance();
 
                 // check sufficient available balance
                 if (amount.compareTo(BigInteger.ZERO) <= 0) throw new RuntimeException(Res.get("portfolio.pending.step5_buyer.amountTooLow"));
@@ -270,10 +264,11 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
                                 .setAccountIndex(0)
                                 .setAmount(amount)
                                 .setAddress(withdrawToAddress)
-                                .setSubtractFeeFrom(feeExcluded ? null : Arrays.asList(0)));
+                                .setSubtractFeeFrom(sendMax ? Arrays.asList(0) : null));
                         log.info("Done creating withdraw tx in {} ms", System.currentTimeMillis() - startTime);
                         break;
                     } catch (Exception e) {
+                        if (isNotEnoughMoney(e.getMessage())) throw 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
@@ -283,15 +278,17 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
                 // popup confirmation message
                 popupConfirmationMessage(tx);
             } catch (Throwable e) {
-                if (e.getMessage().contains("enough")) new Popup().warning(Res.get("funds.withdrawal.warn.amountExceeds")).show();
-                else {
-                    e.printStackTrace();
-                    new Popup().warning(e.getMessage()).show();
-                }
+                e.printStackTrace();
+                if (isNotEnoughMoney(e.getMessage())) new Popup().warning(Res.get("funds.withdrawal.notEnoughFunds")).show();
+                else new Popup().warning(e.getMessage()).show();
             }
         }
     }
 
+    private static boolean isNotEnoughMoney(String errorMsg) {
+        return errorMsg.contains("not enough");
+    }
+
     private void popupConfirmationMessage(MoneroTxWallet tx) {
 
         // create confirmation message
@@ -347,6 +344,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
     ///////////////////////////////////////////////////////////////////////////////////////////
 
     private void reset() {
+        sendMax = false;
         amount = BigInteger.ZERO;
         amountTextField.setText("");
         amountTextField.setPromptText(Res.get("funds.withdrawal.setAmount"));
diff --git a/desktop/src/main/java/haveno/desktop/util/FormBuilder.java b/desktop/src/main/java/haveno/desktop/util/FormBuilder.java
index ba698752a4..cae26b805a 100644
--- a/desktop/src/main/java/haveno/desktop/util/FormBuilder.java
+++ b/desktop/src/main/java/haveno/desktop/util/FormBuilder.java
@@ -1159,35 +1159,28 @@ public class FormBuilder {
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////
-    // Label + TextField + RadioButton + RadioButton
+    // Label + TextField + HyperlinkWithIcon
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    public static Tuple4<Label, TextField, RadioButton, RadioButton> addTopLabelTextFieldRadioButtonRadioButton(GridPane gridPane,
-                                                                                                                int rowIndex,
-                                                                                                                ToggleGroup toggleGroup,
-                                                                                                                String title,
-                                                                                                                String textFieldTitle,
-                                                                                                                String radioButtonTitle1,
-                                                                                                                String radioButtonTitle2,
-                                                                                                                double top) {
+    public static Tuple3<Label, TextField, HyperlinkWithIcon> addTopLabelTextFieldHyperLink(GridPane gridPane,
+                                                                                            int rowIndex,
+                                                                                            String title,
+                                                                                            String textFieldTitle,
+                                                                                            String maxButtonTitle,
+                                                                                            double top) {
         TextField textField = new HavenoTextField();
         textField.setPromptText(textFieldTitle);
 
-        RadioButton radioButton1 = new AutoTooltipRadioButton(radioButtonTitle1);
-        radioButton1.setToggleGroup(toggleGroup);
-        radioButton1.setPadding(new Insets(6, 0, 0, 0));
-
-        RadioButton radioButton2 = new AutoTooltipRadioButton(radioButtonTitle2);
-        radioButton2.setToggleGroup(toggleGroup);
-        radioButton2.setPadding(new Insets(6, 0, 0, 0));
+        HyperlinkWithIcon maxLink = new ExternalHyperlink(maxButtonTitle);
 
         HBox hBox = new HBox();
         hBox.setSpacing(10);
-        hBox.getChildren().addAll(textField, radioButton1, radioButton2);
+        hBox.getChildren().addAll(textField, maxLink);
+        hBox.setAlignment(Pos.CENTER_LEFT);
 
         final Tuple2<Label, VBox> labelVBoxTuple2 = addTopLabelWithVBox(gridPane, rowIndex, title, hBox, top);
 
-        return new Tuple4<>(labelVBoxTuple2.first, textField, radioButton1, radioButton2);
+        return new Tuple3<>(labelVBoxTuple2.first, textField, maxLink);
     }