WabiSabi API Client
ADD
WalletWasabi.Tests/UnitTests/WabiSabi/Client/WabiSabiApiClientTests.cs
+using Moq;
+using NBitcoin;
+using System.Threading.Tasks;
+using WalletWasabi.BitcoinCore.Rpc;
+using WalletWasabi.Crypto;
+using WalletWasabi.Crypto.Randomness;
+using WalletWasabi.Tests.Helpers;
+using WalletWasabi.WabiSabi.Backend;
+using WalletWasabi.WabiSabi.Backend.Banning;
+using WalletWasabi.WabiSabi.Backend.PostRequests;
+using WalletWasabi.WabiSabi.Backend.Rounds;
+using WalletWasabi.WabiSabi.Client;
+using WalletWasabi.WabiSabi.Crypto;
+using Xunit;
+
+namespace WalletWasabi.Tests.UnitTests.WabiSabi.Client
+{
+ public class WabiSabiApiClientTests
+ {
+ [Fact]
+ public async Task RegisterInputAsyncTest()
+ {
+ var config = new WabiSabiConfig();
+ var round = WabiSabiFactory.CreateRound(config);
+ using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(config, round);
+
+ using var key = new Key();
+ var outpoint = BitcoinFactory.CreateOutPoint();
+
+ var mockRpc = new Mock<IRPCClient>();
+ mockRpc.Setup(rpc => rpc.GetTxOutAsync(outpoint.Hash, (int)outpoint.N, true))
+ .ReturnsAsync(new NBitcoin.RPC.GetTxOutResponse{
+ IsCoinBase = false,
+ Confirmations = 200,
+ TxOut = new TxOut(Money.Coins(1m), key.PubKey.WitHash.GetAddress(Network.Main)),
+ });
+ await using var coordinator = new PostRequestHandler(config, new Prison(), arena, mockRpc.Object);
+
+ var rnd = new InsecureRandom();
+ var amountClient = new WabiSabiClient(round.AmountCredentialIssuerParameters, 2, rnd, 4300000000000ul);
+ var weightClient = new WabiSabiClient(round.WeightCredentialIssuerParameters, 2, rnd, 2000ul);
+
+ var apiClient = new WabiSabiApiClient(amountClient, weightClient, coordinator);
+
+ await apiClient.RegisterInputAsync(Money.Coins(1m), outpoint, key, round.Id, round.Hash);
+ }
+ }
+}
\ No newline at end of file

ADD
WalletWasabi/WabiSabi/Backend/PostRequests/IRequestHandler.cs
+using System.Threading.Tasks;
+using WalletWasabi.WabiSabi.Models;
+
+namespace WalletWasabi.WabiSabi.Backend.PostRequests
+{
+ public interface IRequestHandler
+ {
+ Task<InputsRegistrationResponse> RegisterInputAsync(InputsRegistrationRequest request);
+ Task<ConnectionConfirmationResponse> ConfirmConnectionAsync(ConnectionConfirmationRequest request);
+ Task<OutputRegistrationResponse> RegisterOutputAsync(OutputRegistrationRequest request);
+ Task RemoveInputAsync(InputsRemovalRequest request);
+ Task SignTransactionAsync(TransactionSignaturesRequest request);
+ }
+}

MODIFY
WalletWasabi/WabiSabi/Backend/PostRequests/PostRequestHandler.cs
WalletWasabi/WabiSabi/Backend/PostRequests/PostRequestHandler.cs
@@ -14,7 +14,7 @@ using WalletWasabi.WabiSabi.Models;
namespace WalletWasabi.WabiSabi.Backend.PostRequests
{
- public class PostRequestHandler : IAsyncDisposable
+ public class PostRequestHandler : IAsyncDisposable, IRequestHandler
{
public PostRequestHandler(WabiSabiConfig config, Prison prison, Arena arena, IRPCClient rpc)
{

ADD
WalletWasabi/WabiSabi/Client/WabiSabiApiClient.cs
+using NBitcoin;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using WalletWasabi.Crypto;
+using WalletWasabi.WabiSabi.Backend.PostRequests;
+using WalletWasabi.WabiSabi.Crypto;
+using WalletWasabi.WabiSabi.Models;
+
+namespace WalletWasabi.WabiSabi.Client
+{
+ public class WabiSabiApiClient
+ {
+ public WabiSabiApiClient(WabiSabiClient wabiSabiClientAmount, WabiSabiClient wabiSabiClientWeight, IRequestHandler requestHandler)
+ {
+ WabiSabiClientAmount = wabiSabiClientAmount;
+ WabiSabiClientWeight = wabiSabiClientWeight;
+ RequestHandler = requestHandler;
+ }
+
+ public WabiSabiClient WabiSabiClientAmount { get; }
+ public WabiSabiClient WabiSabiClientWeight { get; }
+ public IRequestHandler RequestHandler { get; }
+
+ public Task RegisterInputAsync(Money amount, OutPoint outPoint, Key key, Guid roundId, uint256 roundHash) =>
+ RegisterInputAsync(
+ new[] { amount },
+ new[] { outPoint },
+ new[] { key },
+ roundId,
+ roundHash);
+
+ public async Task RegisterInputAsync(
+ IEnumerable<Money> amounts,
+ IEnumerable<OutPoint> outPoints,
+ IEnumerable<Key> keys,
+ Guid roundId,
+ uint256 roundHash)
+ {
+ static byte[] GenerateOwnershipProof(Key key, uint256 roundHash) => OwnershipProof.GenerateCoinJoinInputProof(
+ key,
+ new CoinJoinInputCommitmentData("CoinJoinCoordinatorIdentifier", roundHash)).ToBytes();
+
+ var registrableInputs = outPoints
+ .Zip(keys, (outPoint, key) => (outPoint, key))
+ .Select(x => new InputRoundSignaturePair(x.outPoint, GenerateOwnershipProof(x.key, roundHash)));
+
+ var (zeroAmountCredentialRequest, zeroAmountCredentialResponseValidation) = WabiSabiClientAmount.CreateRequestForZeroAmount();
+ var (zeroWeightCredentialRequest, zeroWeightCredentialResponseValidation) = WabiSabiClientWeight.CreateRequestForZeroAmount();
+
+ var inputRegistrationResponse = await RequestHandler.RegisterInputAsync(
+ new InputsRegistrationRequest(
+ roundId,
+ registrableInputs,
+ zeroAmountCredentialRequest,
+ zeroWeightCredentialRequest));
+
+ WabiSabiClientAmount.HandleResponse(inputRegistrationResponse.AmountCredentials, zeroAmountCredentialResponseValidation);
+ WabiSabiClientWeight.HandleResponse(inputRegistrationResponse.WeightCredentials, zeroWeightCredentialResponseValidation);
+ }
+ }
+}
\ No newline at end of file

WabiSabi API Client