Wallet: Generate receive address automatically (#6122)

* Wallet: Generate receive address automatically

This circumvents landing on a blank page with only the "generate address" button and automatically generates a new address, unless the Unreserve action was used.

* Fix close button leading to same page

* Fix tests

* Remove unreserve feature

---------

Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
This commit is contained in:
d11n
2024-09-13 15:03:45 +02:00
committed by GitHub
parent f07ed53f7e
commit 2f7a5c2967
4 changed files with 12 additions and 40 deletions

View File

@@ -547,7 +547,6 @@ retry:
{ {
walletId ??= WalletId; walletId ??= WalletId;
GoToWallet(walletId, WalletsNavPages.Receive); GoToWallet(walletId, WalletsNavPages.Receive);
Driver.FindElement(By.Id("generateButton")).Click();
var addressStr = Driver.FindElement(By.Id("Address")).GetAttribute("data-text"); var addressStr = Driver.FindElement(By.Id("Address")).GetAttribute("data-text");
var address = BitcoinAddress.Create(addressStr, ((BTCPayNetwork)Server.NetworkProvider.GetNetwork(walletId.CryptoCode)).NBitcoinNetwork); var address = BitcoinAddress.Create(addressStr, ((BTCPayNetwork)Server.NetworkProvider.GetNetwork(walletId.CryptoCode)).NBitcoinNetwork);
for (var i = 0; i < coins; i++) for (var i = 0; i < coins; i++)

View File

@@ -1631,7 +1631,6 @@ namespace BTCPayServer.Tests
s.GenerateWallet("BTC", "", false, true); s.GenerateWallet("BTC", "", false, true);
var walletId = new WalletId(storeId, "BTC"); var walletId = new WalletId(storeId, "BTC");
s.GoToWallet(walletId, WalletsNavPages.Receive); s.GoToWallet(walletId, WalletsNavPages.Receive);
s.Driver.FindElement(By.Id("generateButton")).Click();
var addressStr = s.Driver.FindElement(By.Id("Address")).GetAttribute("data-text"); var addressStr = s.Driver.FindElement(By.Id("Address")).GetAttribute("data-text");
var address = BitcoinAddress.Create(addressStr, var address = BitcoinAddress.Create(addressStr,
((BTCPayNetwork)s.Server.NetworkProvider.GetNetwork("BTC")).NBitcoinNetwork); ((BTCPayNetwork)s.Server.NetworkProvider.GetNetwork("BTC")).NBitcoinNetwork);
@@ -1836,7 +1835,6 @@ namespace BTCPayServer.Tests
s.Driver.FindElement(By.Id("WalletNav-Receive")).Click(); s.Driver.FindElement(By.Id("WalletNav-Receive")).Click();
//generate a receiving address //generate a receiving address
s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
Assert.True(s.Driver.FindElement(By.CssSelector("#address-tab .qr-container")).Displayed); Assert.True(s.Driver.FindElement(By.CssSelector("#address-tab .qr-container")).Displayed);
// no previous page in the wizard, hence no back button // no previous page in the wizard, hence no back button
Assert.True(s.Driver.ElementDoesNotExist(By.Id("GoBack"))); Assert.True(s.Driver.ElementDoesNotExist(By.Id("GoBack")));
@@ -1858,10 +1856,6 @@ namespace BTCPayServer.Tests
Assert.NotNull(s.Driver.FindElement(By.CssSelector("[data-value='test-label']"))); Assert.NotNull(s.Driver.FindElement(By.CssSelector("[data-value='test-label']")));
}); });
//unreserve
s.Driver.FindElement(By.CssSelector("button[value=unreserve-current-address]")).Click();
//generate it again, should be the same one as before as nothing got used in the meantime
s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
Assert.True(s.Driver.FindElement(By.CssSelector("#address-tab .qr-container")).Displayed); Assert.True(s.Driver.FindElement(By.CssSelector("#address-tab .qr-container")).Displayed);
Assert.Equal(receiveAddr, s.Driver.FindElement(By.Id("Address")).GetAttribute("data-text")); Assert.Equal(receiveAddr, s.Driver.FindElement(By.Id("Address")).GetAttribute("data-text"));
TestUtils.Eventually(() => TestUtils.Eventually(() =>

View File

@@ -14,7 +14,6 @@ using BTCPayServer.Client;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Logging;
using BTCPayServer.ModelBinders; using BTCPayServer.ModelBinders;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Models.WalletViewModels; using BTCPayServer.Models.WalletViewModels;
@@ -34,16 +33,13 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.WebUtilities; using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using NBitcoin; using NBitcoin;
using NBXplorer; using NBXplorer;
using NBXplorer.Client;
using NBXplorer.DerivationStrategy; using NBXplorer.DerivationStrategy;
using NBXplorer.Models; using NBXplorer.Models;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using StoreData = BTCPayServer.Data.StoreData; using StoreData = BTCPayServer.Data.StoreData;
namespace BTCPayServer.Controllers namespace BTCPayServer.Controllers
@@ -330,7 +326,7 @@ namespace BTCPayServer.Controllers
if (network == null) if (network == null)
return NotFound(); return NotFound();
var store = GetCurrentStore(); var store = GetCurrentStore();
var address = _walletReceiveService.Get(walletId)?.Address; var address = (await _walletReceiveService.GetOrGenerate(walletId)).Address;
var allowedPayjoin = paymentMethod.IsHotWallet && store.GetStoreBlob().PayJoinEnabled; var allowedPayjoin = paymentMethod.IsHotWallet && store.GetStoreBlob().PayJoinEnabled;
var bip21 = network.GenerateBIP21(address?.ToString(), null); var bip21 = network.GenerateBIP21(address?.ToString(), null);
if (allowedPayjoin) if (allowedPayjoin)
@@ -354,7 +350,7 @@ namespace BTCPayServer.Controllers
Address = address?.ToString(), Address = address?.ToString(),
CryptoImage = GetImage(network), CryptoImage = GetImage(network),
PaymentLink = bip21.ToString(), PaymentLink = bip21.ToString(),
ReturnUrl = returnUrl ?? HttpContext.Request.GetTypedHeaders().Referer?.AbsolutePath, ReturnUrl = returnUrl,
SelectedLabels = labels ?? Array.Empty<string>() SelectedLabels = labels ?? Array.Empty<string>()
}); });
} }
@@ -373,18 +369,6 @@ namespace BTCPayServer.Controllers
return NotFound(); return NotFound();
switch (command) switch (command)
{ {
case "unreserve-current-address":
var address = await _walletReceiveService.UnReserveAddress(walletId);
if (!string.IsNullOrEmpty(address))
{
TempData.SetStatusMessageModel(new StatusMessageModel
{
AllowDismiss = true,
Message = $"Address {address} was unreserved.",
Severity = StatusMessageModel.StatusSeverity.Success,
});
}
break;
case "generate-new-address": case "generate-new-address":
await _walletReceiveService.GetOrGenerate(walletId, true); await _walletReceiveService.GetOrGenerate(walletId, true);
break; break;

View File

@@ -31,12 +31,8 @@
<input type="hidden" asp-for="ReturnUrl" /> <input type="hidden" asp-for="ReturnUrl" />
@if (string.IsNullOrEmpty(Model.Address)) @if (string.IsNullOrEmpty(Model.Address))
{ {
<div class="d-grid gap-3 col-sm-10 col-md-8 col-lg-7 col-xxl-6 mx-auto"> <div class="payment-box mb-3">
<button id="generateButton" class="btn btn-primary" type="submit" name="command" value="generate-new-address">Generate next available @Model.CryptoCode address</button> <button id="generateButton" class="btn btn-primary w-100" type="submit" name="command" value="generate-new-address">Generate next available @Model.CryptoCode address</button>
@if (env.CheatMode)
{
<button type="submit" name="command" value="fill-wallet" class="btn btn-info">Cheat Mode: Send transactions to this wallet</button>
}
</div> </div>
} }
else else
@@ -49,13 +45,8 @@
<input type="text" class="form-control" readonly="readonly" asp-for="PaymentLink" id="payment-link"/> <input type="text" class="form-control" readonly="readonly" asp-for="PaymentLink" id="payment-link"/>
</div> </div>
<div class="row mt-4"> <div class="row mt-4">
<div class="col-12 col-sm-6">
<button type="submit" name="command" value="generate-new-address" class="btn btn-primary w-100">Generate another address</button> <button type="submit" name="command" value="generate-new-address" class="btn btn-primary w-100">Generate another address</button>
</div> </div>
<div class="col-12 col-sm-6 mt-4 mt-sm-0">
<button type="submit" name="command" value="unreserve-current-address" class="btn btn-secondary w-100">Unreserve this address</button>
</div>
</div>
</noscript> </noscript>
<div class="nav flex-wrap align-items-center justify-content-center gap-2 mb-4"> <div class="nav flex-wrap align-items-center justify-content-center gap-2 mb-4">
<a class="btcpay-pill active" data-bs-toggle="tab" href="#address-tab">Address</a> <a class="btcpay-pill active" data-bs-toggle="tab" href="#address-tab">Address</a>
@@ -104,11 +95,15 @@
</div> </div>
</div> </div>
</div> </div>
<div class="mt-4">
<div class="d-grid gap-3 mt-4">
<button type="submit" name="command" value="generate-new-address" class="btn btn-primary w-100">Generate another address</button> <button type="submit" name="command" value="generate-new-address" class="btn btn-primary w-100">Generate another address</button>
<button type="submit" name="command" value="unreserve-current-address" class="btn btn-secondary w-100">Unreserve this address</button>
</div> </div>
</div> </div>
} }
@if (env.CheatMode)
{
<div class="payment-box mt-3">
<button type="submit" name="command" value="fill-wallet" class="btn btn-outline-info w-100">Cheat Mode: Send funds to this wallet</button>
</div>
}
</form> </form>