Allow decimal to fee/sat
MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
@@ -46,7 +46,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
private string _feeText;
private decimal _usdFee;
private Money _estimatedBtcFee;
- private Money _satoshiPerByteFeeRate;
+ private FeeRate _satoshiPerByteFeeRate;
private decimal _feePercentage;
private ObservableAsPropertyHelper<decimal> _usdExchangeRate;
private Money _allSelectedAmount;
@@ -306,14 +306,14 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
}
}
- if (SatoshiPerByteFeeRate is null || SatoshiPerByteFeeRate.Satoshi < 1)
+ if (SatoshiPerByteFeeRate is null || SatoshiPerByteFeeRate.SatoshiPerByte < 1)
{
SetWarningMessage("Invalid fee rate, must be greater than or equal to one.");
return;
}
bool useCustomFee = !IsSliderFeeUsed;
- FeeRate feeRate = new FeeRate((decimal)SatoshiPerByteFeeRate.Satoshi);
+ FeeRate feeRate = SatoshiPerByteFeeRate;
var label = Label;
var operation = new WalletService.Operation(script, amount, label);
@@ -337,7 +337,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
MainWindowViewModel.Instance.StatusBar.TryRemoveStatus(StatusBarStatus.DequeuingSelectedCoins);
}
- BuildTransactionResult result = await Task.Run(() => Global.WalletService.BuildTransaction(Password, new[] { operation }, feeTarget: null, feeRate: Money.Satoshis(feeRate.SatoshiPerByte), allowUnconfirmed: true, allowedInputs: selectedCoinReferences));
+ BuildTransactionResult result = await Task.Run(() => Global.WalletService.BuildTransaction(Password, new[] { operation }, feeTarget: null, feeRate: feeRate, allowUnconfirmed: true, allowedInputs: selectedCoinReferences));
if (IsTransactionBuilder)
{
@@ -631,15 +631,20 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
SatoshiPerByteFeeRate = null;
if (allFeeEstimate != null)
{
- if (decimal.TryParse(UserFeeText, out decimal userFee))
+ /* In decimal ',' means order of magnitude.
+ * User could think it is decimal point but 3,5 means 35 Satoshi.
+ * For this reason we treat ',' as an invalid character.
+ */
+
+ if (!UserFeeText.Contains(",") && decimal.TryParse(UserFeeText, out decimal userFee))
{
- SatoshiPerByteFeeRate = Money.Satoshis(userFee);
+ SatoshiPerByteFeeRate = new FeeRate(userFee);
feeTarget = Constants.SevenDaysConfirmationTarget;
foreach (var feeEstimate in allFeeEstimate.Estimations)
{
var target = feeEstimate.Key;
var fee = feeEstimate.Value;
- if (SatoshiPerByteFeeRate.Satoshi > fee)
+ if (SatoshiPerByteFeeRate.SatoshiPerByte > fee)
{
feeTarget = target;
break;
@@ -685,7 +690,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
switch (FeeDisplayFormat)
{
case FeeDisplayFormat.SatoshiPerByte:
- FeeText = $"(~ {SatoshiPerByteFeeRate.Satoshi} sat/byte)";
+ FeeText = $"(~ {SatoshiPerByteFeeRate.SatoshiPerByte} sat/byte)";
FeeToolTip = "Expected fee rate in satoshi / vbyte.";
break;
@@ -738,7 +743,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
if (IsSliderFeeUsed)
{
SatoshiPerByteFeeRate = allFeeEstimate.GetFeeRate(feeTarget);
- UserFeeText = SatoshiPerByteFeeRate.Satoshi.ToString();
+ UserFeeText = SatoshiPerByteFeeRate.SatoshiPerByte.ToString();
}
IEnumerable<SmartCoin> selectedCoins = CoinList.Coins.Where(cvm => cvm.IsSelected).Select(x => x.Model);
@@ -773,7 +778,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
if (SatoshiPerByteFeeRate != null)
{
- EstimatedBtcFee = Money.Satoshis(vsize * SatoshiPerByteFeeRate);
+ EstimatedBtcFee = SatoshiPerByteFeeRate.GetTotalFee(vsize);
}
else
{
@@ -971,7 +976,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
set => this.RaiseAndSetIfChanged(ref _estimatedBtcFee, value);
}
- public Money SatoshiPerByteFeeRate
+ public FeeRate SatoshiPerByteFeeRate
{
get => _satoshiPerByteFeeRate;
set => this.RaiseAndSetIfChanged(ref _satoshiPerByteFeeRate, value);

MODIFY
WalletWasabi/Extensions/NBitcoinExtensions.cs
WalletWasabi/Extensions/NBitcoinExtensions.cs
@@ -273,5 +273,10 @@ namespace NBitcoin
}
list.Sort((x, y) => map[x].Amount.CompareTo(map[y].Amount));
}
+
+ public static Money GetTotalFee(this FeeRate me, int vsize)
+ {
+ return Money.Satoshis(Math.Round(me.SatoshiPerByte * vsize));
+ }
}
}

MODIFY
WalletWasabi/Models/AllFeeEstimate.cs
WalletWasabi/Models/AllFeeEstimate.cs
@@ -39,14 +39,14 @@ namespace WalletWasabi.Models
_hashCode = null;
}
- public Money GetFeeRate(int feeTarget)
+ public FeeRate GetFeeRate(int feeTarget)
{
// Where the target is still under or equal to the requested target.
- int satoshiPerByte = Estimations
+ decimal satoshiPerByte = Estimations
.Last(x => x.Key <= feeTarget) // The last should be the largest feeTarget.
.Value;
- return Money.Satoshis(satoshiPerByte);
+ return new FeeRate(satoshiPerByte);
}
#region Equality

MODIFY
WalletWasabi/Services/WalletService.cs
WalletWasabi/Services/WalletService.cs
@@ -1032,7 +1032,7 @@ namespace WalletWasabi.Services
public BuildTransactionResult BuildTransaction(string password,
Operation[] toSend,
int? feeTarget = null,
- Money feeRate = null,
+ FeeRate feeRate = null,
bool allowUnconfirmed = false,
int? subtractFeeFromAmountIndex = null,
Script customChange = null,
@@ -1115,14 +1115,9 @@ namespace WalletWasabi.Services
// 4. Get and calculate fee
Logger.LogInfo<WalletService>("Calculating dynamic transaction fee...");
- Money feePerBytes = null;
- using (var client = new WasabiClient(Synchronizer.WasabiClient.TorClient.DestinationUriAction, Synchronizer.WasabiClient.TorClient.TorSocks5EndPoint))
- {
- Money fr = feeTarget.HasValue ? Synchronizer.GetFeeRate(feeTarget.Value) : feeRate;
+ FeeRate feePerBytes = (feeTarget != null && feeTarget.HasValue) ? Synchronizer.GetFeeRate(feeTarget.Value) : feeRate;
- Money sanityCheckedFeeRate = Math.Max(fr, 2); // Use the sanity check that under 2 satoshi per bytes should not be displayed. To correct possible rounding errors.
- feePerBytes = new Money(sanityCheckedFeeRate);
- }
+ feePerBytes = feePerBytes.SatoshiPerByte < 1 ? new FeeRate(1m) : feePerBytes; // Use the sanity check that under 2 satoshi per bytes should not be displayed. To correct possible rounding errors.
bool spendAll = spendAllCount == 1;
int inNum;
@@ -1133,7 +1128,7 @@ namespace WalletWasabi.Services
else
{
int expectedMinTxSize = 1 * Constants.P2wpkhInputSizeInBytes + 1 * Constants.OutputSizeInBytes + 10;
- inNum = SelectCoinsToSpend(allowedSmartCoinInputs, toSend.Select(x => x.Amount).Sum() + feePerBytes * expectedMinTxSize).Count();
+ inNum = SelectCoinsToSpend(allowedSmartCoinInputs, toSend.Select(x => x.Amount).Sum() + feePerBytes.GetTotalFee(expectedMinTxSize)).Count();
}
// https://bitcoincore.org/en/segwit_wallet_dev/#transaction-fee-estimation
@@ -1141,7 +1136,7 @@ namespace WalletWasabi.Services
int outNum = spendAll ? toSend.Length : toSend.Length + 1; // number of addresses to send + 1 for change
int vSize = NBitcoinHelpers.CalculateVsizeAssumeSegwit(inNum, outNum);
Logger.LogInfo<WalletService>($"Estimated tx size: {vSize} vbytes.");
- Money fee = feePerBytes * vSize;
+ Money fee = feePerBytes.GetTotalFee(vSize);
Logger.LogInfo<WalletService>($"Fee: {fee.Satoshi} Satoshi.");
// 5. How much to spend?

MODIFY
WalletWasabi/Services/WasabiSynchronizer.cs
WalletWasabi/Services/WasabiSynchronizer.cs
@@ -350,7 +350,7 @@ namespace WalletWasabi.Services
ResponseArrivedIsGenSocksServFail?.Invoke(this, false);
}
- public Money GetFeeRate(int feeTarget)
+ public FeeRate GetFeeRate(int feeTarget)
{
if (AllFeeEstimate is null)
{

Allow decimal to fee/sat