Add isZeroCoordinatorFee
MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PostRequests/RegisterInputSuccessTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/PostRequests/RegisterInputSuccessTests.cs
@@ -35,7 +35,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PostRequests
var arenaClient = WabiSabiFactory.CreateArenaClient(arena);
var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id);
- var resp = await arenaClient.RegisterInputAsync(round.Id, coin.Outpoint, ownershipProof, CancellationToken.None);
+ var (resp, _) = await arenaClient.RegisterInputAsync(round.Id, coin.Outpoint, ownershipProof, CancellationToken.None);
AssertSingleAliceSuccessfullyRegistered(round, minAliceDeadline, resp);
await arena.StopAsync(CancellationToken.None);
@@ -56,7 +56,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend.PostRequests
var arenaClient = WabiSabiFactory.CreateArenaClient(arena);
var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id);
- var resp = await arenaClient.RegisterInputAsync(round.Id, coin.Outpoint, ownershipProof, CancellationToken.None);
+ var (resp, _) = await arenaClient.RegisterInputAsync(round.Id, coin.Outpoint, ownershipProof, CancellationToken.None);
AssertSingleAliceSuccessfullyRegistered(round, minAliceDeadline, resp);
var myAlice = Assert.Single(round.Alices);

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Client/ArenaClientTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Client/ArenaClientTests.cs
@@ -72,7 +72,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Client
wabiSabiApi);
var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id);
- var inputRegistrationResponse = await aliceArenaClient.RegisterInputAsync(round.Id, outpoint, ownershipProof, CancellationToken.None);
+ var (inputRegistrationResponse, _) = await aliceArenaClient.RegisterInputAsync(round.Id, outpoint, ownershipProof, CancellationToken.None);
var aliceId = inputRegistrationResponse.Value;
var inputVsize = Constants.P2wpkhInputVirtualSize;

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Integration/WabiSabiApiApplicationFactory.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Integration/WabiSabiApiApplicationFactory.cs
@@ -16,6 +16,7 @@ using WalletWasabi.Tor.Http;
using WalletWasabi.WabiSabi.Backend;
using WalletWasabi.WabiSabi.Backend.Banning;
using WalletWasabi.WabiSabi.Backend.Rounds;
+using WalletWasabi.WabiSabi.Backend.Rounds.CoinJoinStorage;
using WalletWasabi.WabiSabi.Client;
using WalletWasabi.WabiSabi.Models.MultipartyTransaction;
@@ -58,6 +59,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Integration
services.AddScoped<Prison>();
services.AddScoped<WabiSabiConfig>();
services.AddScoped(typeof(TimeSpan), _ => TimeSpan.FromSeconds(2));
+ services.AddScoped(s => new InMemoryCoinJoinIdStore());
});
builder.ConfigureLogging(o =>
{

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Integration/WabiSabiHttpApiIntegrationTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Integration/WabiSabiHttpApiIntegrationTests.cs
@@ -375,6 +375,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Integration
TxOut = coinToRegister.TxOut
};
services.AddScoped<IRPCClient>(s => rpc);
+ services.AddScoped(s => new InMemoryCoinJoinIdStore());
});
}).CreateClient();
@@ -383,7 +384,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Integration
var round = rounds.First(x => x.CoinjoinState is ConstructionState);
var ownershipProof = WabiSabiFactory.CreateOwnershipProof(signingKey, round.Id);
- var response = await apiClient.RegisterInputAsync(round.Id, coinToRegister.Outpoint, ownershipProof, CancellationToken.None);
+ var (response, _) = await apiClient.RegisterInputAsync(round.Id, coinToRegister.Outpoint, ownershipProof, CancellationToken.None);
Assert.NotEqual(Guid.Empty, response.Value);
}
@@ -417,7 +418,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Integration
RoundState round = rounds.First(x => x.CoinjoinState is ConstructionState);
var ownershipProof = WabiSabiFactory.CreateOwnershipProof(signingKey, round.Id);
- ArenaResponse<Guid> response = await apiClient.RegisterInputAsync(round.Id, coinToRegister.Outpoint, ownershipProof, CancellationToken.None);
+ var (response, _) = await apiClient.RegisterInputAsync(round.Id, coinToRegister.Outpoint, ownershipProof, CancellationToken.None);
Assert.NotEqual(Guid.Empty, response.Value);
}

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Models/SerializationTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Models/SerializationTests.cs
@@ -42,7 +42,8 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Models
var message = new InputRegistrationResponse(
Guid.NewGuid(),
CreateCredentialsResponse(),
- CreateCredentialsResponse());
+ CreateCredentialsResponse(),
+ true);
AssertSerialization(message);
}

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Arena.Partial.cs
WalletWasabi/WabiSabi/Backend/Rounds/Arena.Partial.cs
@@ -90,9 +90,12 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
alice.SetDeadlineRelativeTo(round.ConnectionConfirmationTimeFrame.Duration);
round.Alices.Add(alice);
+ bool isZeroCoordinatorFee = alice.IsComingFromCoinJoin;
+
return new(alice.Id,
commitAmountCredentialResponse,
- commitVsizeCredentialResponse);
+ commitVsizeCredentialResponse,
+ isZeroCoordinatorFee);
}
}

MODIFY
WalletWasabi/WabiSabi/Client/AliceClient.cs
WalletWasabi/WabiSabi/Client/AliceClient.cs
@@ -21,7 +21,8 @@ namespace WalletWasabi.WabiSabi.Client
SmartCoin coin,
BitcoinSecret bitcoinSecret,
IEnumerable<Credential> issuedAmountCredentials,
- IEnumerable<Credential> issuedVsizeCredentials)
+ IEnumerable<Credential> issuedVsizeCredentials,
+ bool isPayingZeroCoordinationFee)
{
AliceId = aliceId;
RoundId = roundState.Id;
@@ -34,6 +35,7 @@ namespace WalletWasabi.WabiSabi.Client
IssuedVsizeCredentials = issuedVsizeCredentials;
MaxVsizeAllocationPerAlice = roundState.MaxVsizeAllocationPerAlice;
ConfirmationTimeout = roundState.ConnectionConfirmationTimeout / 2;
+ IsPayingZeroCoordinationFee = isPayingZeroCoordinationFee;
}
public Guid AliceId { get; }
@@ -47,6 +49,7 @@ namespace WalletWasabi.WabiSabi.Client
public IEnumerable<Credential> IssuedVsizeCredentials { get; private set; }
private long MaxVsizeAllocationPerAlice { get; }
private TimeSpan ConfirmationTimeout { get; }
+ private bool IsPayingZeroCoordinationFee { get; }
public static async Task<AliceClient> CreateRegisterAndConfirmInputAsync(
RoundState roundState,
@@ -89,8 +92,8 @@ namespace WalletWasabi.WabiSabi.Client
new OwnershipIdentifier(identificationKey, signingKey.PubKey.WitHash.ScriptPubKey),
new CoinJoinInputCommitmentData("CoinJoinCoordinatorIdentifier", roundState.Id));
- var response = await arenaClient.RegisterInputAsync(roundState.Id, coin.Coin.Outpoint, ownershipProof, cancellationToken).ConfigureAwait(false);
- aliceClient = new(response.Value, roundState, arenaClient, coin, bitcoinSecret, response.IssuedAmountCredentials, response.IssuedVsizeCredentials);
+ var (response, isPayingZeroCoordinationFee) = await arenaClient.RegisterInputAsync(roundState.Id, coin.Coin.Outpoint, ownershipProof, cancellationToken).ConfigureAwait(false);
+ aliceClient = new(response.Value, roundState, arenaClient, coin, bitcoinSecret, response.IssuedAmountCredentials, response.IssuedVsizeCredentials, isPayingZeroCoordinationFee);
coin.CoinJoinInProgress = true;
Logger.LogInfo($"Round ({roundState.Id}), Alice ({aliceClient.AliceId}): Registered {coin.OutPoint}.");
@@ -130,7 +133,7 @@ namespace WalletWasabi.WabiSabi.Client
private async Task ConfirmConnectionAsync(RoundStateUpdater roundStatusUpdater, CancellationToken cancellationToken)
{
- var coordinationFeeRate = SmartCoin.Transaction.Transaction.IsLikelyCoinjoin() ? CoordinationFeeRate.Zero : CoordinationFeeRate;
+ var coordinationFeeRate = IsPayingZeroCoordinationFee ? CoordinationFeeRate.Zero : CoordinationFeeRate;
long[] amountsToRequest = { SmartCoin.EffectiveValue(FeeRate, coordinationFeeRate).Satoshi };
long[] vsizesToRequest = { MaxVsizeAllocationPerAlice - SmartCoin.ScriptPubKey.EstimateInputVsize() };

MODIFY
WalletWasabi/WabiSabi/Client/ArenaClient.cs
WalletWasabi/WabiSabi/Client/ArenaClient.cs
@@ -28,7 +28,7 @@ namespace WalletWasabi.WabiSabi.Client
public WabiSabiClient VsizeCredentialClient { get; }
public IWabiSabiApiRequestHandler RequestHandler { get; }
- public async Task<ArenaResponse<Guid>> RegisterInputAsync(
+ public async Task<(ArenaResponse<Guid> ArenaResponse, bool IsPayingZeroCoordinationFee)> RegisterInputAsync(
uint256 roundId,
OutPoint outPoint,
OwnershipProof ownershipProof,
@@ -49,7 +49,7 @@ namespace WalletWasabi.WabiSabi.Client
var realAmountCredentials = AmountCredentialClient.HandleResponse(inputRegistrationResponse.AmountCredentials, zeroAmountCredentialRequestData.CredentialsResponseValidation);
var realVsizeCredentials = VsizeCredentialClient.HandleResponse(inputRegistrationResponse.VsizeCredentials, zeroVsizeCredentialRequestData.CredentialsResponseValidation);
- return new(inputRegistrationResponse.AliceId, realAmountCredentials, realVsizeCredentials);
+ return (new(inputRegistrationResponse.AliceId, realAmountCredentials, realVsizeCredentials), inputRegistrationResponse.IsPayingZeroCoordinationFee);
}
public async Task RemoveInputAsync(uint256 roundId, Guid aliceId, CancellationToken cancellationToken)

MODIFY
WalletWasabi/WabiSabi/Client/ArenaResponse.cs
WalletWasabi/WabiSabi/Client/ArenaResponse.cs
@@ -11,6 +11,7 @@ namespace WalletWasabi.WabiSabi.Client
IssuedAmountCredentials = realAmountCredentials.ToArray();
IssuedVsizeCredentials = realVsizeCredentials.ToArray();
}
+
public IEnumerable<Credential> IssuedAmountCredentials { get; }
public IEnumerable<Credential> IssuedVsizeCredentials { get; }
}

MODIFY
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
WalletWasabi/WabiSabi/Client/CoinJoinClient.cs
@@ -118,8 +118,10 @@ namespace WalletWasabi.WabiSabi.Client
// Calculate outputs values
roundState = await RoundStatusUpdater.CreateRoundAwaiter(rs => rs.Id == roundState.Id, cancellationToken).ConfigureAwait(false);
constructionState = roundState.Assert<ConstructionState>();
+
AmountDecomposer amountDecomposer = new(roundState.FeeRate, roundState.CoordinationFeeRate, roundState.CoinjoinState.Parameters.AllowedOutputAmounts.Min, Constants.P2wpkhOutputSizeInBytes, (int)availableVsize);
var theirCoins = constructionState.Inputs.Except(registeredCoins);
+
var outputValues = amountDecomposer.Decompose(registeredCoins, theirCoins);
// Get all locked internal keys we have and assert we have enough.

MODIFY
WalletWasabi/WabiSabi/Models/InputRegistrationResponse.cs
WalletWasabi/WabiSabi/Models/InputRegistrationResponse.cs
@@ -5,6 +5,7 @@ namespace WalletWasabi.WabiSabi.Models
public record InputRegistrationResponse(
Guid AliceId,
CredentialsResponse AmountCredentials,
- CredentialsResponse VsizeCredentials
+ CredentialsResponse VsizeCredentials,
+ bool IsPayingZeroCoordinationFee
);
}

Add isZeroCoordinatorFee