initial logic for insufficient balance handling
MODIFY
WalletWasabi.Fluent/ViewModels/Dialogs/InsufficientBalanceDialogViewModel.cs
WalletWasabi.Fluent/ViewModels/Dialogs/InsufficientBalanceDialogViewModel.cs
@@ -10,35 +10,23 @@ namespace WalletWasabi.Fluent.ViewModels.Dialogs
[NavigationMetaData(Title = "Insufficient Balance")]
public partial class InsufficientBalanceDialogViewModel : DialogViewModelBase<bool>
{
- public InsufficientBalanceDialogViewModel(BalanceType type, BuildTransactionResult transaction, decimal usdExchangeRate)
+ public InsufficientBalanceDialogViewModel(BalanceType type)
{
- var destinationAmount = transaction.CalculateDestinationAmount().ToDecimal(MoneyUnit.BTC);
- var btcAmountText = $"{destinationAmount} bitcoins ";
- var fiatAmountText = destinationAmount.GenerateFiatText(usdExchangeRate, "USD");
- AmountText = $"{btcAmountText}{fiatAmountText}";
-
- var fee = transaction.Fee;
- var btcFeeText = $"{fee.ToDecimal(MoneyUnit.Satoshi)} sats ";
- var fiatFeeText = fee.ToDecimal(MoneyUnit.BTC).GenerateFiatText(usdExchangeRate, "USD");
- FeeText = $"{btcFeeText}{fiatFeeText}";
-
- Caption = type switch
+ Question = type switch
{
- BalanceType.Private => $"There are not enough private funds to cover the transaction fee. Alternatively you could:",
- BalanceType.Pocket => $"There are not enough funds selected to cover the transaction fee. Alternatively you could:",
- _ => $"There are not enough funds available to cover the transaction fee. Alternatively you could:",
+ BalanceType.Private => $"There are not enough private funds to cover the transaction fee. Instead of an extra cost, Wasabi can subtract the transaction fee from the amount.",
+ BalanceType.Pocket => $"There are not enough funds selected to cover the transaction fee. Instead of an extra cost, Wasabi can subtract the transaction fee from the amount.",
+ _ => $"There are not enough funds available to cover the transaction fee. Instead of an extra cost, Wasabi can subtract the transaction fee from the amount.",
};
+ Question += "\n\nWould you like to do this instead?";
+
NextCommand = ReactiveCommand.Create(() => Close(result: true));
CancelCommand = ReactiveCommand.Create(() => Close(DialogResultKind.Cancel));
SetupCancel(enableCancel: false, enableCancelOnEscape: true, enableCancelOnPressed: true);
}
- public string AmountText { get; set; }
-
- public string FeeText { get; set; }
-
- public string Caption { get; }
+ public string Question { get; }
}
}

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/TransactionInfo.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/TransactionInfo.cs
@@ -28,5 +28,9 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
public IPayjoinClient? PayJoinClient { get; set; }
public bool UserDidntRequestOptimisation { get; set; }
+
+ public bool IsPayJoin => PayJoinClient is { };
+
+ public bool IsPrivatePocketUsed { get; set; }
}
}

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/TransactionPreviewViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/TransactionPreviewViewModel.cs
@@ -108,7 +108,9 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
var targetAnonymitySet = _wallet.ServiceConfiguration.GetMixUntilAnonymitySetValue();
var mixedCoins = _wallet.Coins.Where(x => x.HdPubKey.AnonymitySet >= targetAnonymitySet).ToList();
var totalMixedCoinsAmount = Money.FromUnit(mixedCoins.Sum(coin => coin.Amount), MoneyUnit.Satoshi);
+
transactionInfo.Coins = mixedCoins;
+ transactionInfo.IsPrivatePocketUsed = true;
var feeDialogResult = await NavigateDialogAsync(new SendFeeViewModel(_wallet, transactionInfo, true));
@@ -126,6 +128,7 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
privacyControlDialogResult.Result is { })
{
transactionInfo.Coins = privacyControlDialogResult.Result;
+ transactionInfo.IsPrivatePocketUsed = false;
}
}
}
@@ -136,19 +139,68 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
var transactionInfo = _info;
- var targetAnonymitySet = _wallet.ServiceConfiguration.GetMixUntilAnonymitySetValue();
- var mixedCoins = _wallet.Coins.Where(x => x.HdPubKey.AnonymitySet >= targetAnonymitySet).ToList();
- var totalMixedCoinsAmount = Money.FromUnit(mixedCoins.Sum(coin => coin.Amount), MoneyUnit.Satoshi);
-
try
{
- if (transactionInfo.PayJoinClient is { })
+ return await Task.Run(() => TransactionHelpers.BuildTransaction(_wallet, transactionInfo));
+ }
+ catch (InsufficientBalanceException)
+ {
+ if (transactionInfo.IsPayJoin)
+ {
+ if (_wallet.Coins.Sum(x => x.Amount) > transactionInfo.Amount)
+ {
+ var result2 = await NavigateDialogAsync(new InsufficientBalanceDialogViewModel(BalanceType.Private), NavigationTarget.DialogScreen);
+
+ if (result2.Result)
+ {
+ var privacyControlDialogResult = await NavigateDialogAsync(new PrivacyControlViewModel(_wallet, transactionInfo));
+
+ if (privacyControlDialogResult.Kind == DialogResultKind.Normal && privacyControlDialogResult.Result is { })
+ {
+ transactionInfo.Coins = privacyControlDialogResult.Result;
+ return await BuildTransactionAsync();
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ //TODO: error message
+
+ Navigate().BackTo<SendViewModel>();
+ return null;
+ }
+ }
+
+ var dialog = new InsufficientBalanceDialogViewModel(BalanceType.Private);
+ var result = await NavigateDialogAsync(dialog, NavigationTarget.DialogScreen);
+
+ if (result.Result)
+ {
+ return await Task.Run(() => TransactionHelpers.BuildTransaction(_wallet, transactionInfo, subtractFee: true));
+ }
+ else
{
- return await BuildTransactionAsPayJoinAsync(transactionInfo);
+ if (_wallet.Coins.Sum(x => x.Amount) > transactionInfo.Amount)
+ {
+ var privacyControlDialogResult =
+ await NavigateDialogAsync(new PrivacyControlViewModel(_wallet, transactionInfo));
+
+ if (privacyControlDialogResult.Kind == DialogResultKind.Normal &&
+ privacyControlDialogResult.Result is { })
+ {
+ transactionInfo.Coins = privacyControlDialogResult.Result;
+ return await BuildTransactionAsync();
+ }
}
else
{
- return await BuildTransactionAsNormalAsync(transactionInfo, totalMixedCoinsAmount);
+ Navigate().BackTo<SendViewModel>();
+ return null;
+ }
}
}
catch (Exception ex)
@@ -206,41 +258,6 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
}
}
- private async Task<BuildTransactionResult> BuildTransactionAsNormalAsync(TransactionInfo transactionInfo, Money totalMixedCoinsAmount)
- {
- try
- {
- var txRes = await Task.Run(() => TransactionHelpers.BuildTransaction(_wallet, transactionInfo));
-
- return txRes;
- }
- catch (InsufficientBalanceException)
- {
- return null;
-
- // @soosr - need help here ;)
- /*
- var txRes = await Task.Run(() => TransactionHelpers.BuildTransaction(_wallet, transactionInfo.Address,
- totalMixedCoinsAmount, transactionInfo.Labels, transactionInfo.FeeRate!, transactionInfo.Coins,
- subtractFee: true));
-
- var dialog = new InsufficientBalanceDialogViewModel(BalanceType.Private, txRes,
- _wallet.Synchronizer.UsdExchangeRate);
-
- var result = await NavigateDialogAsync(dialog, NavigationTarget.DialogScreen);
-
- if (result.Result)
- {
-
- await NavigateDialogAsync(new OptimisePrivacyViewModel(_wallet, transactionInfo, txRes));
- }
- else
- {
- await NavigateDialogAsync(new PrivacyControlViewModel(_wallet, transactionInfo));
- }*/
- }
- }
-
private async Task<BuildTransactionResult> BuildTransactionAsPayJoinAsync(TransactionInfo transactionInfo)
{
try

initial logic for insufficient balance handling