GreenField API: Wallet API (#2246)

* GreenField: Wallet API

* more work

* wip

* rough fiunish of transaction sending api

* Allow to create tx without broadcasting and small fixes

* Refactor Wallet Receive feature ad add greenfield api for address reserve for wallet

* add wallet api client

* add docs

* fix json converter tags

* fixes and add wallet tests

* fix tests

* fix rebase

* fixes

* just pass the tests already

* ugggh

* small cleanup

* revert int support in numeric string converter and make block id as native number in json

* fix LN endpoint

* try fix flaky test

* Revert "try fix flaky test"

This reverts commit 2e0d256325b892f7741325dcbab01196f74d182a.

* try fix other flaky test

* return proepr error if fee rate could not be fetched

* try fix test again

* reduce fee related logic for wallet api

* try reduce code changes for pr scope

* change auth logic for initial release of wallet api
This commit is contained in:
Andrew Camilleri
2021-03-11 13:34:52 +01:00
committed by GitHub
parent 1f7992e5da
commit cdfdad3e3d
30 changed files with 1936 additions and 191 deletions

View File

@@ -8,6 +8,7 @@ using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
using BTCPayServer.ModelBinders;
@@ -31,6 +32,7 @@ using NBXplorer;
using NBXplorer.DerivationStrategy;
using NBXplorer.Models;
using Newtonsoft.Json;
using StoreData = BTCPayServer.Data.StoreData;
namespace BTCPayServer.Controllers
{
@@ -50,7 +52,7 @@ namespace BTCPayServer.Controllers
private readonly IAuthorizationService _authorizationService;
private readonly IFeeProviderFactory _feeRateProvider;
private readonly BTCPayWalletProvider _walletProvider;
private readonly WalletReceiveStateService _WalletReceiveStateService;
private readonly WalletReceiveService _walletReceiveService;
private readonly EventAggregator _EventAggregator;
private readonly SettingsRepository _settingsRepository;
private readonly DelayedTransactionBroadcaster _broadcaster;
@@ -75,7 +77,7 @@ namespace BTCPayServer.Controllers
ExplorerClientProvider explorerProvider,
IFeeProviderFactory feeRateProvider,
BTCPayWalletProvider walletProvider,
WalletReceiveStateService walletReceiveStateService,
WalletReceiveService walletReceiveService,
EventAggregator eventAggregator,
SettingsRepository settingsRepository,
DelayedTransactionBroadcaster broadcaster,
@@ -97,7 +99,7 @@ namespace BTCPayServer.Controllers
ExplorerClientProvider = explorerProvider;
_feeRateProvider = feeRateProvider;
_walletProvider = walletProvider;
_WalletReceiveStateService = walletReceiveStateService;
_walletReceiveService = walletReceiveService;
_EventAggregator = eventAggregator;
_settingsRepository = settingsRepository;
_broadcaster = broadcaster;
@@ -361,7 +363,7 @@ namespace BTCPayServer.Controllers
if (network == null)
return NotFound();
var address = _WalletReceiveStateService.Get(walletId)?.Address;
var address = _walletReceiveService.Get(walletId)?.Address;
return View(new WalletReceiveViewModel()
{
CryptoCode = walletId.CryptoCode,
@@ -383,29 +385,22 @@ namespace BTCPayServer.Controllers
var network = this.NetworkProvider.GetNetwork<BTCPayNetwork>(walletId?.CryptoCode);
if (network == null)
return NotFound();
var wallet = _walletProvider.GetWallet(network);
switch (command)
{
case "unreserve-current-address":
KeyPathInformation cachedAddress = _WalletReceiveStateService.Get(walletId);
if (cachedAddress == null)
var address = await _walletReceiveService.UnReserveAddress(walletId);
if (!string.IsNullOrEmpty(address))
{
break;
TempData.SetStatusMessageModel(new StatusMessageModel()
{
AllowDismiss = true,
Message = $"Address {address} was unreserved.",
Severity = StatusMessageModel.StatusSeverity.Success,
});
}
var address = cachedAddress.ScriptPubKey.GetDestinationAddress(network.NBitcoinNetwork);
ExplorerClientProvider.GetExplorerClient(network)
.CancelReservation(cachedAddress.DerivationStrategy, new[] { cachedAddress.KeyPath });
this.TempData.SetStatusMessageModel(new StatusMessageModel()
{
AllowDismiss = true,
Message = $"Address {address} was unreserved.",
Severity = StatusMessageModel.StatusSeverity.Success,
});
_WalletReceiveStateService.Remove(walletId);
break;
case "generate-new-address":
var reserve = (await wallet.ReserveAddressAsync(paymentMethod.AccountDerivation));
_WalletReceiveStateService.Set(walletId, reserve);
await _walletReceiveService.GetOrGenerate(walletId, true);
break;
}
return RedirectToAction(nameof(WalletReceive), new { walletId });
@@ -413,11 +408,8 @@ namespace BTCPayServer.Controllers
private async Task<bool> CanUseHotWallet()
{
var isAdmin = (await _authorizationService.AuthorizeAsync(User, Policies.CanModifyServerSettings)).Succeeded;
if (isAdmin)
return true;
var policies = await _settingsRepository.GetSettingAsync<PoliciesSettings>();
return policies?.AllowHotWalletForAll is true;
return (await _authorizationService.CanUseHotWallet(policies, User)).HotWallet;
}
[HttpGet]
@@ -667,7 +659,7 @@ namespace BTCPayServer.Controllers
if (!ModelState.IsValid)
return View(vm);
DerivationSchemeSettings derivationScheme = GetDerivationSchemeSettings(walletId);
CreatePSBTResponse psbt = null;
@@ -907,7 +899,7 @@ namespace BTCPayServer.Controllers
return View(nameof(SignWithSeed), viewModel);
}
var changed = PSBTChanged(psbt, () => psbt.SignAll(settings.AccountDerivation, signingKey, rootedKeyPath, new SigningOptions()
var changed = psbt.PSBTChanged( () => psbt.SignAll(settings.AccountDerivation, signingKey, rootedKeyPath, new SigningOptions()
{
EnforceLowR = !(viewModel.SigningContext?.EnforceLowR is false)
}));
@@ -926,15 +918,6 @@ namespace BTCPayServer.Controllers
});
}
private bool PSBTChanged(PSBT psbt, Action act)
{
var before = psbt.ToBase64();
act();
var after = psbt.ToBase64();
return before != after;
}
private string ValueToString(Money v, BTCPayNetworkBase network)
{
return v.ToString() + " " + network.CryptoCode;
@@ -1041,11 +1024,7 @@ namespace BTCPayServer.Controllers
internal DerivationSchemeSettings GetDerivationSchemeSettings(WalletId walletId)
{
var paymentMethod = CurrentStore
.GetSupportedPaymentMethods(NetworkProvider)
.OfType<DerivationSchemeSettings>()
.FirstOrDefault(p => p.PaymentId.PaymentType == Payments.PaymentTypes.BTCLike && p.PaymentId.CryptoCode == walletId.CryptoCode);
return paymentMethod;
return CurrentStore.GetDerivationSchemeSettings(NetworkProvider, walletId.CryptoCode);
}
private static async Task<string> GetBalanceString(BTCPayWallet wallet, DerivationStrategyBase derivationStrategy)