Allow excluding unconfirmed UTXOs when creating a new transaction with Greenfield API

See original request: https://github.com/btcpayserver/btcpayserver/discussions/3737
This commit is contained in:
Umar Bolatov 2022-06-09 20:58:51 -07:00 committed by Andrew Camilleri
parent fd3d389557
commit d0e01768ab
6 changed files with 37 additions and 4 deletions

View file

@ -26,5 +26,6 @@ namespace BTCPayServer.Client.Models
public List<CreateOnChainTransactionRequestDestination> Destinations { get; set; }
[JsonProperty("rbf")]
public bool? RBF { get; set; } = null;
public bool ExcludeUnconfirmed { get; set; } = false;
}
}

View file

@ -2078,6 +2078,18 @@ namespace BTCPayServer.Tests
Assert.True((await tester.ExplorerNode.TestMempoolAcceptAsync(tx)).IsAllowed);
createTxRequest.NoChange = false;
// Validation for excluding unconfirmed UTXOs and manually selecting inputs at the same time
await AssertValidationError(new[] { "ExcludeUnconfirmed" }, async () =>
{
createTxRequest.SelectedInputs = new List<OutPoint>();
createTxRequest.ExcludeUnconfirmed = true;
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
});
createTxRequest.SelectedInputs = null;
createTxRequest.ExcludeUnconfirmed = false;
//coin selection
await AssertValidationError(new[] { nameof(createTxRequest.SelectedInputs) }, async () =>
{

View file

@ -376,10 +376,20 @@ namespace BTCPayServer.Controllers.Greenfield
return this.CreateValidationError(ModelState);
}
if (request.SelectedInputs != null && request.ExcludeUnconfirmed == true)
{
ModelState.AddModelError(
nameof(request.ExcludeUnconfirmed),
"Can't automatically exclude unconfirmed UTXOs while selection custom inputs"
);
return this.CreateValidationError(ModelState);
}
var explorerClient = _explorerClientProvider.GetExplorerClient(cryptoCode);
var wallet = _btcPayWalletProvider.GetWallet(network);
var utxos = await wallet.GetUnspentCoins(derivationScheme.AccountDerivation);
var utxos = await wallet.GetUnspentCoins(derivationScheme.AccountDerivation, request.ExcludeUnconfirmed);
if (request.SelectedInputs != null || !utxos.Any())
{
utxos = utxos.Where(coin => request.SelectedInputs?.Contains(coin.OutPoint) ?? true)

View file

@ -615,7 +615,7 @@ namespace BTCPayServer.Controllers
var walletTransactionsInfoAsync = await WalletRepository.GetWalletTransactionsInfo(walletId);
var utxos = await _walletProvider.GetWallet(network)
.GetUnspentCoins(schemeSettings.AccountDerivation, cancellation);
.GetUnspentCoins(schemeSettings.AccountDerivation, false, cancellation);
vm.InputsAvailable = utxos.Select(coin =>
{
walletTransactionsInfoAsync.TryGetValue(coin.OutPoint.Hash.ToString(), out var info);

View file

@ -245,11 +245,15 @@ namespace BTCPayServer.Services.Wallets
public async Task<ReceivedCoin[]> GetUnspentCoins(DerivationStrategyBase derivationStrategy, CancellationToken cancellation = default(CancellationToken))
public async Task<ReceivedCoin[]> GetUnspentCoins(
DerivationStrategyBase derivationStrategy,
bool excludeUnconfirmed = false,
CancellationToken cancellation = default(CancellationToken)
)
{
ArgumentNullException.ThrowIfNull(derivationStrategy);
return (await GetUTXOChanges(derivationStrategy, cancellation))
.GetUnspentUTXOs()
.GetUnspentUTXOs(excludeUnconfirmed)
.Select(c => new ReceivedCoin()
{
KeyPath = c.KeyPath,

View file

@ -870,6 +870,12 @@
"nullable": true,
"description": "Whether to enable RBF for the transaction. Leave blank to have it random (beneficial to privacy)"
},
"excludeUnconfirmed": {
"type": "boolean",
"default": false,
"nullable": true,
"description": "Whether to exclude unconfirmed UTXOs from the transaction."
},
"selectedInputs": {
"nullable": true,
"description": "Restrict the creation of the transactions from the outpoints provided ONLY (coin selection)",