Add fees to send
MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
@@ -146,7 +146,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
return;
}
- var result = await Task.Run(async () => await Global.WalletService.BuildTransactionAsync(Password, new[] { operation }, Fee, allowUnconfirmed: true, allowedInputs: selectedCoinReferences));
+ var result = await Task.Run(() => Global.WalletService.BuildTransaction(Password, new[] { operation }, Fee, allowUnconfirmed: true, allowedInputs: selectedCoinReferences));
await Task.Run(async () => await Global.WalletService.SendTransactionAsync(result.Transaction));

MODIFY
WalletWasabi.Tests/RegTests.cs
WalletWasabi.Tests/RegTests.cs
@@ -779,7 +779,7 @@ namespace WalletWasabi.Tests
}
var scp = new Key().ScriptPubKey;
- var res2 = await wallet.BuildTransactionAsync(password, new[] { new WalletService.Operation(scp, Money.Coins(0.05m), "foo") }, 5, false);
+ var res2 = wallet.BuildTransaction(password, new[] { new WalletService.Operation(scp, Money.Coins(0.05m), "foo") }, 5, false);
Assert.NotNull(res2.Transaction);
Assert.Single(res2.OuterWalletOutputs);
@@ -800,7 +800,7 @@ namespace WalletWasabi.Tests
Script receive = wallet.GetReceiveKey("Basic").GetP2wpkhScript();
Money amountToSend = wallet.Coins.Where(x => !x.SpentOrCoinJoinInProgress).Sum(x => x.Amount) / 2;
- var res = await wallet.BuildTransactionAsync(password, new[] { new WalletService.Operation(receive, amountToSend, "foo") }, 1008, allowUnconfirmed: true);
+ var res = wallet.BuildTransaction(password, new[] { new WalletService.Operation(receive, amountToSend, "foo") }, 1008, allowUnconfirmed: true);
foreach (SmartCoin coin in res.SpentCoins)
{
@@ -848,7 +848,7 @@ namespace WalletWasabi.Tests
receive = wallet.GetReceiveKey("SubtractFeeFromAmount").GetP2wpkhScript();
amountToSend = wallet.Coins.Where(x => !x.SpentOrCoinJoinInProgress).Sum(x => x.Amount) / 3;
- res = await wallet.BuildTransactionAsync(password, new[] { new WalletService.Operation(receive, amountToSend, "foo") }, 1008, allowUnconfirmed: true, subtractFeeFromAmountIndex: 0);
+ res = wallet.BuildTransaction(password, new[] { new WalletService.Operation(receive, amountToSend, "foo") }, 1008, allowUnconfirmed: true, subtractFeeFromAmountIndex: 0);
Assert.Equal(2, res.InnerWalletOutputs.Count());
Assert.Empty(res.OuterWalletOutputs);
@@ -881,7 +881,7 @@ namespace WalletWasabi.Tests
#region LowFee
- res = await wallet.BuildTransactionAsync(password, new[] { new WalletService.Operation(receive, amountToSend, "foo") }, 1008, allowUnconfirmed: true);
+ res = wallet.BuildTransaction(password, new[] { new WalletService.Operation(receive, amountToSend, "foo") }, 1008, allowUnconfirmed: true);
Assert.Equal(2, res.InnerWalletOutputs.Count());
Assert.Empty(res.OuterWalletOutputs);
@@ -914,7 +914,7 @@ namespace WalletWasabi.Tests
#region MediumFee
- res = await wallet.BuildTransactionAsync(password, new[] { new WalletService.Operation(receive, amountToSend, "foo") }, 144, allowUnconfirmed: true);
+ res = wallet.BuildTransaction(password, new[] { new WalletService.Operation(receive, amountToSend, "foo") }, 144, allowUnconfirmed: true);
Assert.Equal(2, res.InnerWalletOutputs.Count());
Assert.Empty(res.OuterWalletOutputs);
@@ -947,7 +947,7 @@ namespace WalletWasabi.Tests
#region HighFee
- res = await wallet.BuildTransactionAsync(password, new[] { new WalletService.Operation(receive, amountToSend, "foo") }, 2, allowUnconfirmed: true);
+ res = wallet.BuildTransaction(password, new[] { new WalletService.Operation(receive, amountToSend, "foo") }, 2, allowUnconfirmed: true);
Assert.Equal(2, res.InnerWalletOutputs.Count());
Assert.Empty(res.OuterWalletOutputs);
@@ -986,7 +986,7 @@ namespace WalletWasabi.Tests
#region MaxAmount
receive = wallet.GetReceiveKey("MaxAmount").GetP2wpkhScript();
- res = await wallet.BuildTransactionAsync(password, new[] { new WalletService.Operation(receive, Money.Zero, "foo") }, 1008, allowUnconfirmed: true);
+ res = wallet.BuildTransaction(password, new[] { new WalletService.Operation(receive, Money.Zero, "foo") }, 1008, allowUnconfirmed: true);
Assert.Single(res.InnerWalletOutputs);
Assert.Empty(res.OuterWalletOutputs);
@@ -1014,7 +1014,7 @@ namespace WalletWasabi.Tests
receive = wallet.GetReceiveKey("InputSelection").GetP2wpkhScript();
var inputCountBefore = res.SpentCoins.Count();
- res = await wallet.BuildTransactionAsync(password, new[] { new WalletService.Operation(receive, Money.Zero, "foo") }, 1008,
+ res = wallet.BuildTransaction(password, new[] { new WalletService.Operation(receive, Money.Zero, "foo") }, 1008,
allowUnconfirmed: true,
allowedInputs: wallet.Coins.Where(x => !x.SpentOrCoinJoinInProgress).Select(x => new TxoRef(x.TransactionId, x.Index)).Take(1));
@@ -1034,7 +1034,7 @@ namespace WalletWasabi.Tests
Assert.Single(res.Transaction.Transaction.Outputs);
- res = await wallet.BuildTransactionAsync(password, new[] { new WalletService.Operation(receive, Money.Zero, "foo") }, 1008,
+ res = wallet.BuildTransaction(password, new[] { new WalletService.Operation(receive, Money.Zero, "foo") }, 1008,
allowUnconfirmed: true,
allowedInputs: new[] { res.SpentCoins.Select(x => new TxoRef(x.TransactionId, x.Index)).First() });
@@ -1050,14 +1050,14 @@ namespace WalletWasabi.Tests
#region Labeling
- res = await wallet.BuildTransactionAsync(password, new[] { new WalletService.Operation(receive, Money.Zero, "my label") }, 1008,
+ res = wallet.BuildTransaction(password, new[] { new WalletService.Operation(receive, Money.Zero, "my label") }, 1008,
allowUnconfirmed: true);
Assert.Single(res.InnerWalletOutputs);
Assert.Equal($"{Helpers.Constants.ChangeOfSpecialLabelStart}my label{Helpers.Constants.ChangeOfSpecialLabelEnd}", res.InnerWalletOutputs.Single().Label);
amountToSend = wallet.Coins.Where(x => !x.SpentOrCoinJoinInProgress).Sum(x => x.Amount) / 3;
- res = await wallet.BuildTransactionAsync(password, new[] {
+ res = wallet.BuildTransaction(password, new[] {
new WalletService.Operation(new Key().ScriptPubKey, amountToSend, "outgoing"),
new WalletService.Operation(new Key().ScriptPubKey, amountToSend, "outgoing2")
}, 1008,
@@ -1094,7 +1094,7 @@ namespace WalletWasabi.Tests
// covers:
// disallow unconfirmed with allowed inputs
// feeTarget < 2 // NOTE: need to correct alowing 0 and 1
- res = await wallet.BuildTransactionAsync(password, toSend, 0, false, allowedInputs: allowedInputs);
+ res = wallet.BuildTransaction(password, toSend, 0, false, allowedInputs: allowedInputs);
activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive);
Assert.Single(res.InnerWalletOutputs);
@@ -1124,7 +1124,7 @@ namespace WalletWasabi.Tests
// covers:
// customchange
// feePc > 1
- res = await wallet.BuildTransactionAsync(password, new[] { new WalletService.Operation(new Key().ScriptPubKey, Money.Coins(0.0003m), "outgoing") }, 2, customChange: new Key().ScriptPubKey);
+ res = wallet.BuildTransaction(password, new[] { new WalletService.Operation(new Key().ScriptPubKey, Money.Coins(0.0003m), "outgoing") }, 2, customChange: new Key().ScriptPubKey);
Assert.True(res.FeePercentOfSent > 1);
@@ -1195,49 +1195,49 @@ namespace WalletWasabi.Tests
Logger.TurnOff();
// toSend cannot be null
- await Assert.ThrowsAsync<ArgumentNullException>(async () => await wallet.BuildTransactionAsync(null, null, 0));
+ Assert.Throws<ArgumentNullException>(() => wallet.BuildTransaction(null, null, 0));
// toSend cannot have a null element
- await Assert.ThrowsAsync<ArgumentNullException>(async () => await wallet.BuildTransactionAsync(null, new[] { (WalletService.Operation)null }, 0));
+ Assert.Throws<ArgumentNullException>(() => wallet.BuildTransaction(null, new[] { (WalletService.Operation)null }, 0));
// toSend cannot have a zero elements
- await Assert.ThrowsAsync<ArgumentException>(async () => await wallet.BuildTransactionAsync(null, new WalletService.Operation[0], 0));
+ Assert.Throws<ArgumentException>(() => wallet.BuildTransaction(null, new WalletService.Operation[0], 0));
// feeTarget has to be in the range 0 to 1008
- await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await wallet.BuildTransactionAsync(null, validOperationList, -10));
- await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await wallet.BuildTransactionAsync(null, validOperationList, 2000));
+ Assert.Throws<ArgumentOutOfRangeException>(() => wallet.BuildTransaction(null, validOperationList, -10));
+ Assert.Throws<ArgumentOutOfRangeException>(() => wallet.BuildTransaction(null, validOperationList, 2000));
// subtractFeeFromAmountIndex has to be valid
- await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await wallet.BuildTransactionAsync(null, validOperationList, 2, false, -10));
- await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await wallet.BuildTransactionAsync(null, validOperationList, 2, false, 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => wallet.BuildTransaction(null, validOperationList, 2, false, -10));
+ Assert.Throws<ArgumentOutOfRangeException>(() => wallet.BuildTransaction(null, validOperationList, 2, false, 1));
// toSend amount sum has to be in range 0 to 2099999997690000
- await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await wallet.BuildTransactionAsync(null, invalidOperationList, 2));
+ Assert.Throws<ArgumentOutOfRangeException>(() => wallet.BuildTransaction(null, invalidOperationList, 2));
// toSend negative sum amount
var operations = new[]{
new WalletService.Operation(scp, -10000, "") };
- await Assert.ThrowsAsync<ArgumentException>(async () => await wallet.BuildTransactionAsync(null, operations, 2));
+ Assert.Throws<ArgumentException>(() => wallet.BuildTransaction(null, operations, 2));
// toSend negative operation amount
operations = new[]{
new WalletService.Operation(scp, 20000, ""),
new WalletService.Operation(scp, -10000, "") };
- await Assert.ThrowsAsync<ArgumentException>(async () => await wallet.BuildTransactionAsync(null, operations, 2));
+ Assert.Throws<ArgumentException>(() => wallet.BuildTransaction(null, operations, 2));
// allowedInputs cannot be empty
- await Assert.ThrowsAsync<ArgumentException>(async () => await wallet.BuildTransactionAsync(null, validOperationList, 2, false, null, null, new TxoRef[0]));
+ Assert.Throws<ArgumentException>(() => wallet.BuildTransaction(null, validOperationList, 2, false, null, null, new TxoRef[0]));
// "Only one element can contain Money.Zero
var toSendWithTwoZeros = new[]{
new WalletService.Operation(scp, Money.Zero, "zero"),
new WalletService.Operation(scp, Money.Zero, "zero") };
- await Assert.ThrowsAsync<ArgumentException>(async () => await wallet.BuildTransactionAsync(password, toSendWithTwoZeros, 1008, false));
+ Assert.Throws<ArgumentException>(() => wallet.BuildTransaction(password, toSendWithTwoZeros, 1008, false));
// cannot specify spend all and custom change
var spendAll = new[]{
new WalletService.Operation(scp, Money.Zero, "spendAll") };
- await Assert.ThrowsAsync<ArgumentException>(async () => await wallet.BuildTransactionAsync(password, spendAll, 1008, false, customChange: new Key().ScriptPubKey));
+ Assert.Throws<ArgumentException>(() => wallet.BuildTransaction(password, spendAll, 1008, false, customChange: new Key().ScriptPubKey));
// Get some money, make it confirm.
var key = wallet.GetReceiveKey("foo label");
@@ -1266,24 +1266,24 @@ namespace WalletWasabi.Tests
operations = new[]{
new WalletService.Operation(scp, Money.Coins(1m), ""),
new WalletService.Operation(scp, Money.Coins(0.5m), "") };
- await Assert.ThrowsAsync<InsufficientBalanceException>(async () => await wallet.BuildTransactionAsync(password, operations, 2, false, 0));
+ Assert.Throws<InsufficientBalanceException>(() => wallet.BuildTransaction(password, operations, 2, false, 0));
// No enough money (only one confirmed coin, no unconfirmed allowed)
operations = new[] { new WalletService.Operation(scp, Money.Coins(1.5m), "") };
- await Assert.ThrowsAsync<InsufficientBalanceException>(async () => await wallet.BuildTransactionAsync(null, operations, 2));
+ Assert.Throws<InsufficientBalanceException>(() => wallet.BuildTransaction(null, operations, 2));
// No enough money (only one confirmed coin, unconfirmed allowed)
- await Assert.ThrowsAsync<InsufficientBalanceException>(async () => await wallet.BuildTransactionAsync(null, operations, 2, true));
+ Assert.Throws<InsufficientBalanceException>(() => wallet.BuildTransaction(null, operations, 2, true));
// Add new money with no confirmation
var txid2 = await rpc.SendToAddressAsync(key.GetP2wpkhAddress(network), Money.Coins(2m));
await Task.Delay(1000); // Wait tx to arrive and get processed.
// Enough money (one confirmed coin and one unconfirmed coin, unconfirmed are NOT allowed)
- await Assert.ThrowsAsync<InsufficientBalanceException>(async () => await wallet.BuildTransactionAsync(null, operations, 2, false));
+ Assert.Throws<InsufficientBalanceException>(() => wallet.BuildTransaction(null, operations, 2, false));
// Enough money (one confirmed coin and one unconfirmed coin, unconfirmed are allowed)
- var btx = await wallet.BuildTransactionAsync(password, operations, 2, true);
+ var btx = wallet.BuildTransaction(password, operations, 2, true);
Assert.Equal(2, btx.SpentCoins.Count());
Assert.Equal(1, btx.SpentCoins.Count(c => c.Confirmed));
Assert.Equal(1, btx.SpentCoins.Count(c => !c.Confirmed));
@@ -1292,14 +1292,14 @@ namespace WalletWasabi.Tests
operations = new[]{
new WalletService.Operation(scp, Money.Zero, ""),
new WalletService.Operation(scp, Money.Zero, "") };
- await Assert.ThrowsAsync<ArgumentException>(async () => await wallet.BuildTransactionAsync(null, operations, 2));
+ Assert.Throws<ArgumentException>(() => wallet.BuildTransaction(null, operations, 2));
// `Custom change` and `spend all` cannot be specified at the same time
- await Assert.ThrowsAsync<ArgumentException>(async () => await wallet.BuildTransactionAsync(null, operations, 2, false, null, Script.Empty));
+ Assert.Throws<ArgumentException>(() => wallet.BuildTransaction(null, operations, 2, false, null, Script.Empty));
Logger.TurnOn();
operations = new[] { new WalletService.Operation(scp, Money.Coins(0.5m), "") };
- btx = await wallet.BuildTransactionAsync(password, operations, 2);
+ btx = wallet.BuildTransaction(password, operations, 2);
}
finally
{
@@ -1381,12 +1381,12 @@ namespace WalletWasabi.Tests
// Send money before reorg.
var operations = new[]{
new WalletService.Operation(scp, Money.Coins(0.011m), "") };
- var btx1 = await wallet.BuildTransactionAsync(password, operations, 2);
+ var btx1 = wallet.BuildTransaction(password, operations, 2);
await wallet.SendTransactionAsync(btx1.Transaction);
operations = new[]{
new WalletService.Operation(scp, Money.Coins(0.012m), "") };
- var btx2 = await wallet.BuildTransactionAsync(password, operations, 2, allowUnconfirmed: true);
+ var btx2 = wallet.BuildTransaction(password, operations, 2, allowUnconfirmed: true);
await wallet.SendTransactionAsync(btx2.Transaction);
// Test synchronization after fork.
@@ -1406,12 +1406,12 @@ namespace WalletWasabi.Tests
// are reintroduced when we generate a new block though the rpc call
operations = new[]{
new WalletService.Operation(scp, Money.Coins(0.013m), "") };
- var btx3 = await wallet.BuildTransactionAsync(password, operations, 2);
+ var btx3 = wallet.BuildTransaction(password, operations, 2);
await wallet.SendTransactionAsync(btx3.Transaction);
operations = new[]{
new WalletService.Operation(scp, Money.Coins(0.014m), "") };
- var btx4 = await wallet.BuildTransactionAsync(password, operations, 2, allowUnconfirmed: true);
+ var btx4 = wallet.BuildTransaction(password, operations, 2, allowUnconfirmed: true);
await wallet.SendTransactionAsync(btx4.Transaction);
// Test synchronization after fork with different transactions.
@@ -1552,12 +1552,12 @@ namespace WalletWasabi.Tests
new WalletService.Operation(new Key().ScriptPubKey, Money.Coins(0.01m), ""),
new WalletService.Operation(new Key().ScriptPubKey, Money.Coins(0.01m), "")
};
- var tx1Res = await wallet.BuildTransactionAsync(password, operations, 2, allowUnconfirmed: true);
+ var tx1Res = wallet.BuildTransaction(password, operations, 2, allowUnconfirmed: true);
Assert.Equal(2, tx1Res.OuterWalletOutputs.Single(x => x.ScriptPubKey == key.GetP2wpkhScript()).Mixin);
// Spend the unconfirmed coin (send it to ourself)
operations = new[] { new WalletService.Operation(key.PubKey.WitHash.ScriptPubKey, Money.Coins(0.5m), "") };
- tx1Res = await wallet.BuildTransactionAsync(password, operations, 2, allowUnconfirmed: true);
+ tx1Res = wallet.BuildTransaction(password, operations, 2, allowUnconfirmed: true);
await wallet.SendTransactionAsync(tx1Res.Transaction);
while (wallet.Coins.Count != 3)
@@ -1577,7 +1577,7 @@ namespace WalletWasabi.Tests
// Spend the unconfirmed and unspent coin (send it to ourself)
operations = new[] { new WalletService.Operation(key.PubKey.WitHash.ScriptPubKey, Money.Coins(0.5m), "") };
- var tx2Res = await wallet.BuildTransactionAsync(password, operations, 2, allowUnconfirmed: true, subtractFeeFromAmountIndex: 0);
+ var tx2Res = wallet.BuildTransaction(password, operations, 2, allowUnconfirmed: true, subtractFeeFromAmountIndex: 0);
await wallet.SendTransactionAsync(tx2Res.Transaction);
while (wallet.Coins.Count != 4)
@@ -1618,7 +1618,7 @@ namespace WalletWasabi.Tests
// Test coin basic count.
var coinCount = wallet.Coins.Count;
var to = wallet.GetReceiveKey("foo");
- var res = await wallet.BuildTransactionAsync(password, new[] { new WalletService.Operation(to.GetP2wpkhScript(), Money.Coins(0.2345m), "bar") }, 2, allowUnconfirmed: true);
+ var res = wallet.BuildTransaction(password, new[] { new WalletService.Operation(to.GetP2wpkhScript(), Money.Coins(0.2345m), "bar") }, 2, allowUnconfirmed: true);
await wallet.SendTransactionAsync(res.Transaction);
Assert.Equal(coinCount + 2, wallet.Coins.Count);
Assert.Equal(2, wallet.Coins.Count(x => !x.Confirmed));
@@ -2780,8 +2780,10 @@ namespace WalletWasabi.Tests
Assert.Empty(chaumianClient1.State.GetAllWaitingCoins());
Assert.NotEmpty(chaumianClient1.State.GetAllRegisteredCoins());
await Task.Delay(3000); // Make sure to wait until times out.
- Assert.NotEmpty(chaumianClient1.State.GetAllQueuedCoins());
- Assert.NotEmpty(chaumianClient1.State.GetAllWaitingCoins());
+ IEnumerable<(uint256 txid, uint index)> collection = chaumianClient1.State.GetAllQueuedCoins();
+ Assert.NotEmpty(collection);
+ IEnumerable<(uint256 txid, uint index)> collection1 = chaumianClient1.State.GetAllWaitingCoins();
+ Assert.NotEmpty(collection1);
Assert.Empty(chaumianClient1.State.GetAllRegisteredCoins());
}
finally

MODIFY
WalletWasabi/Models/AllFeeEstimate.cs
WalletWasabi/Models/AllFeeEstimate.cs
@@ -39,6 +39,16 @@ namespace WalletWasabi.Models
_hashCode = null;
}
+ public Money GetFeeRate(int feeTarget)
+ {
+ int staoshiPerByte = Estimations
+ .Where(x => x.Key <= feeTarget) // Where the target is still under or equals to the the requested target.
+ .Last() // The last should be the largest feeTarget.
+ .Value;
+
+ return Money.Satoshis(staoshiPerByte);
+ }
+
#region Equality
public override bool Equals(object obj) => obj is AllFeeEstimate && this == (AllFeeEstimate)obj;

MODIFY
WalletWasabi/Services/WalletService.cs
WalletWasabi/Services/WalletService.cs
@@ -714,7 +714,7 @@ namespace WalletWasabi.Services
/// <exception cref="ArgumentException"></exception>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public async Task<BuildTransactionResult> BuildTransactionAsync(string password,
+ public BuildTransactionResult BuildTransaction(string password,
Operation[] toSend,
int feeTarget,
bool allowUnconfirmed = false,
@@ -801,8 +801,7 @@ namespace WalletWasabi.Services
Money feePerBytes = null;
using (var client = new WasabiClient(Synchronizer.WasabiClient.TorClient.DestinationUri, Synchronizer.WasabiClient.TorClient.TorSocks5EndPoint))
{
- var fees = await client.GetFeesAsync(feeTarget);
- Money feeRate = fees.Single().Value.Conservative;
+ Money feeRate = Synchronizer.GetFeeRate(feeTarget);
Money sanityCheckedFeeRate = Math.Max(feeRate, 2); // Use the sanity check that under 2 satoshi per bytes should not be displayed. To correct possible rounding errors.
feePerBytes = new Money(sanityCheckedFeeRate);
}

MODIFY
WalletWasabi/Services/WasabiSynchronizer.cs
WalletWasabi/Services/WasabiSynchronizer.cs
@@ -499,6 +499,11 @@ namespace WalletWasabi.Services
public int CountFilters() => Index.Count;
+ public Money GetFeeRate(int feeTarget)
+ {
+ return AllFeeEstimate.GetFeeRate(feeTarget);
+ }
+
#endregion Methods
#region IDisposable Support

Add fees to send