mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-20 13:34:37 +01:00
Add payjoin option to hot wallet setup (#2450)
* Add payjoin option to hot wallet setup Enables payjoin by default when creating a hot wallet and offers the user an opt-out. Test fix * Display PayJoin option only if it is available * Test fixes * Update hot wallet checks * Test fix after rebase * Use toggle buttons for enabling options
This commit is contained in:
parent
6b4ff4ce2c
commit
3c80621dac
12 changed files with 108 additions and 92 deletions
|
@ -77,7 +77,7 @@ namespace BTCPayServer.Tests
|
|||
|
||||
// Get enabled state from overview action
|
||||
StoreViewModel storeModel;
|
||||
response = controller.UpdateStore();
|
||||
response = await controller.UpdateStore();
|
||||
storeModel = (StoreViewModel)Assert.IsType<ViewResult>(response).Model;
|
||||
var lnNode = storeModel.LightningNodes.Find(node => node.CryptoCode == cryptoCode);
|
||||
Assert.NotNull(lnNode);
|
||||
|
@ -85,11 +85,11 @@ namespace BTCPayServer.Tests
|
|||
|
||||
WalletSetupViewModel setupVm;
|
||||
var storeId = user.StoreId;
|
||||
response = await controller.GenerateWallet(storeId, cryptoCode, WalletSetupMethod.GenerateOptions, new GenerateWalletRequest());
|
||||
response = await controller.GenerateWallet(storeId, cryptoCode, WalletSetupMethod.GenerateOptions, new WalletSetupRequest());
|
||||
Assert.IsType<ViewResult>(response);
|
||||
|
||||
// Get enabled state from overview action
|
||||
response = controller.UpdateStore();
|
||||
response = await controller.UpdateStore();
|
||||
storeModel = (StoreViewModel)Assert.IsType<ViewResult>(response).Model;
|
||||
var derivationScheme = storeModel.DerivationSchemes.Find(scheme => scheme.Crypto == cryptoCode);
|
||||
Assert.NotNull(derivationScheme);
|
||||
|
@ -98,7 +98,7 @@ namespace BTCPayServer.Tests
|
|||
// Disable wallet
|
||||
response = controller.SetWalletEnabled(storeId, cryptoCode, false).GetAwaiter().GetResult();
|
||||
Assert.IsType<RedirectToActionResult>(response);
|
||||
response = controller.UpdateStore();
|
||||
response = await controller.UpdateStore();
|
||||
storeModel = (StoreViewModel)Assert.IsType<ViewResult>(response).Model;
|
||||
derivationScheme = storeModel.DerivationSchemes.Find(scheme => scheme.Crypto == cryptoCode);
|
||||
Assert.NotNull(derivationScheme);
|
||||
|
|
|
@ -165,7 +165,7 @@ namespace BTCPayServer.Tests
|
|||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
user.ModifyStore(s => s.NetworkFeeMode = NetworkFeeMode.Never);
|
||||
await user.ModifyStore(s => s.NetworkFeeMode = NetworkFeeMode.Never);
|
||||
var apps = user.GetController<AppsController>();
|
||||
var vm = Assert.IsType<CreateAppViewModel>(Assert.IsType<ViewResult>(apps.CreateApp().Result).Model);
|
||||
vm.Name = "test";
|
||||
|
|
|
@ -238,19 +238,15 @@ namespace BTCPayServer.Tests
|
|||
var receiverSeed = s.GenerateWallet("BTC", "", true, true, format);
|
||||
var receiverWalletId = new WalletId(receiver.storeId, "BTC");
|
||||
|
||||
//payjoin is not enabled by default.
|
||||
//payjoin is enabled by default.
|
||||
var invoiceId = s.CreateInvoice(receiver.storeName);
|
||||
s.GoToInvoiceCheckout(invoiceId);
|
||||
var bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
|
||||
.GetAttribute("href");
|
||||
Assert.DoesNotContain($"{PayjoinClient.BIP21EndpointKey}=", bip21);
|
||||
Assert.Contains($"{PayjoinClient.BIP21EndpointKey}=", bip21);
|
||||
|
||||
s.GoToHome();
|
||||
s.GoToStore(receiver.storeId);
|
||||
//payjoin is not enabled by default.
|
||||
Assert.False(s.Driver.FindElement(By.Id("PayJoinEnabled")).Selected);
|
||||
s.Driver.SetCheckbox(By.Id("PayJoinEnabled"), true);
|
||||
s.Driver.FindElement(By.Id("Save")).Click();
|
||||
Assert.True(s.Driver.FindElement(By.Id("PayJoinEnabled")).Selected);
|
||||
|
||||
var sender = s.CreateNewStore();
|
||||
|
@ -519,7 +515,7 @@ namespace BTCPayServer.Tests
|
|||
address = (await nbx.GetUnusedAsync(bob.DerivationScheme, DerivationFeature.Deposit)).Address;
|
||||
tester.ExplorerNode.SendToAddress(address, Money.Coins(1.1m));
|
||||
await notifications.NextEventAsync();
|
||||
bob.ModifyStore(s => s.PayJoinEnabled = true);
|
||||
await bob.ModifyStore(s => s.PayJoinEnabled = true);
|
||||
var invoice = bob.BitPay.CreateInvoice(
|
||||
new Invoice() { Price = 0.1m, Currency = "BTC", FullNotifications = true });
|
||||
var invoiceBIP21 = new BitcoinUrlBuilder(invoice.CryptoInfo.First().PaymentUrls.BIP21,
|
||||
|
|
|
@ -125,28 +125,22 @@ namespace BTCPayServer.Tests
|
|||
CreateStoreAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public void SetNetworkFeeMode(NetworkFeeMode mode)
|
||||
public async Task SetNetworkFeeMode(NetworkFeeMode mode)
|
||||
{
|
||||
ModifyStore((store) =>
|
||||
await ModifyStore(store =>
|
||||
{
|
||||
store.NetworkFeeMode = mode;
|
||||
});
|
||||
}
|
||||
|
||||
public void ModifyStore(Action<StoreViewModel> modify)
|
||||
public async Task ModifyStore(Action<StoreViewModel> modify)
|
||||
{
|
||||
var storeController = GetController<StoresController>();
|
||||
StoreViewModel store = (StoreViewModel)((ViewResult)storeController.UpdateStore()).Model;
|
||||
var response = await storeController.UpdateStore();
|
||||
StoreViewModel store = (StoreViewModel)((ViewResult)response).Model;
|
||||
modify(store);
|
||||
storeController.UpdateStore(store).GetAwaiter().GetResult();
|
||||
}
|
||||
public Task ModifyStoreAsync(Action<StoreViewModel> modify)
|
||||
{
|
||||
var storeController = GetController<StoresController>();
|
||||
StoreViewModel store = (StoreViewModel)((ViewResult)storeController.UpdateStore()).Model;
|
||||
modify(store);
|
||||
return storeController.UpdateStore(store);
|
||||
}
|
||||
|
||||
public T GetController<T>(bool setImplicitStore = true) where T : Controller
|
||||
{
|
||||
|
@ -181,7 +175,7 @@ namespace BTCPayServer.Tests
|
|||
SupportedNetwork = parent.NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode);
|
||||
var store = parent.PayTester.GetController<StoresController>(UserId, StoreId, true);
|
||||
|
||||
var generateRequest = new GenerateWalletRequest()
|
||||
var generateRequest = new WalletSetupRequest
|
||||
{
|
||||
ScriptPubKeyType = segwit,
|
||||
SavePrivateKeys = importKeysToNBX,
|
||||
|
@ -196,7 +190,7 @@ namespace BTCPayServer.Tests
|
|||
|
||||
public Task EnablePayJoin()
|
||||
{
|
||||
return ModifyStoreAsync(s => s.PayJoinEnabled = true);
|
||||
return ModifyStore(s => s.PayJoinEnabled = true);
|
||||
}
|
||||
|
||||
public GenerateWalletResponse GenerateWalletResponseV { get; set; }
|
||||
|
|
|
@ -750,7 +750,8 @@ namespace BTCPayServer.Tests
|
|||
|
||||
// Set tolerance to 50%
|
||||
var stores = user.GetController<StoresController>();
|
||||
var vm = Assert.IsType<StoreViewModel>(Assert.IsType<ViewResult>(stores.UpdateStore()).Model);
|
||||
var response = await stores.UpdateStore();
|
||||
var vm = Assert.IsType<StoreViewModel>(Assert.IsType<ViewResult>(response).Model);
|
||||
Assert.Equal(0.0, vm.PaymentTolerance);
|
||||
vm.PaymentTolerance = 50.0;
|
||||
Assert.IsType<RedirectToActionResult>(stores.UpdateStore(vm).Result);
|
||||
|
@ -941,8 +942,8 @@ namespace BTCPayServer.Tests
|
|||
await user.GrantAccessAsync(true);
|
||||
await user.RegisterDerivationSchemeAsync("BTC");
|
||||
await user.RegisterLightningNodeAsync("BTC", LightningConnectionType.CLightning);
|
||||
user.SetNetworkFeeMode(NetworkFeeMode.Never);
|
||||
await user.ModifyStoreAsync(model => model.SpeedPolicy = SpeedPolicy.HighSpeed);
|
||||
await user.SetNetworkFeeMode(NetworkFeeMode.Never);
|
||||
await user.ModifyStore(model => model.SpeedPolicy = SpeedPolicy.HighSpeed);
|
||||
var invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(0.0001m, "BTC"));
|
||||
await tester.WaitForEvent<InvoiceNewPaymentDetailsEvent>(async () =>
|
||||
{
|
||||
|
@ -990,7 +991,8 @@ namespace BTCPayServer.Tests
|
|||
var user = tester.NewAccount();
|
||||
user.GrantAccess(true);
|
||||
var storeController = user.GetController<StoresController>();
|
||||
Assert.IsType<ViewResult>(storeController.UpdateStore());
|
||||
var storeResponse = await storeController.UpdateStore();
|
||||
Assert.IsType<ViewResult>(storeResponse);
|
||||
Assert.IsType<ViewResult>(storeController.SetupLightningNode(user.StoreId, "BTC"));
|
||||
|
||||
var testResult = storeController.SetupLightningNode(user.StoreId, new LightningNodeViewModel
|
||||
|
@ -1013,9 +1015,10 @@ namespace BTCPayServer.Tests
|
|||
new LightningNodeViewModel { ConnectionString = tester.MerchantCharge.Client.Uri.AbsoluteUri },
|
||||
"save", "BTC").GetAwaiter().GetResult());
|
||||
|
||||
storeResponse = await storeController.UpdateStore();
|
||||
var storeVm =
|
||||
Assert.IsType<StoreViewModel>(Assert
|
||||
.IsType<ViewResult>(storeController.UpdateStore()).Model);
|
||||
.IsType<ViewResult>(storeResponse).Model);
|
||||
Assert.Single(storeVm.LightningNodes.Where(l => !string.IsNullOrEmpty(l.Address)));
|
||||
}
|
||||
}
|
||||
|
@ -1128,8 +1131,8 @@ namespace BTCPayServer.Tests
|
|||
var acc = tester.NewAccount();
|
||||
acc.GrantAccess();
|
||||
acc.RegisterDerivationScheme("BTC");
|
||||
acc.ModifyStore(s => s.SpeedPolicy = SpeedPolicy.LowSpeed);
|
||||
var invoice = acc.BitPay.CreateInvoice(new Invoice()
|
||||
await acc.ModifyStore(s => s.SpeedPolicy = SpeedPolicy.LowSpeed);
|
||||
var invoice = acc.BitPay.CreateInvoice(new Invoice
|
||||
{
|
||||
Price = 5.0m,
|
||||
Currency = "USD",
|
||||
|
@ -1545,7 +1548,7 @@ namespace BTCPayServer.Tests
|
|||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
user.SetNetworkFeeMode(NetworkFeeMode.Always);
|
||||
await user.SetNetworkFeeMode(NetworkFeeMode.Always);
|
||||
var invoice =
|
||||
user.BitPay.CreateInvoice(new Invoice() { Price = 5000.0m, Currency = "USD" }, Facade.Merchant);
|
||||
var payment1 = invoice.BtcDue + Money.Coins(0.0001m);
|
||||
|
@ -1646,7 +1649,7 @@ namespace BTCPayServer.Tests
|
|||
|
||||
Logs.Tester.LogInformation(
|
||||
$"Let's test if we can RBF a normal payment without adding fees to the invoice");
|
||||
user.SetNetworkFeeMode(NetworkFeeMode.MultiplePaymentsOnly);
|
||||
await user.SetNetworkFeeMode(NetworkFeeMode.MultiplePaymentsOnly);
|
||||
invoice = user.BitPay.CreateInvoice(new Invoice() { Price = 5000.0m, Currency = "USD" }, Facade.Merchant);
|
||||
payment1 = invoice.BtcDue;
|
||||
tx1 = new uint256(tester.ExplorerNode.SendCommand("sendtoaddress", new object[]
|
||||
|
@ -1952,7 +1955,7 @@ namespace BTCPayServer.Tests
|
|||
});
|
||||
Assert.Equal(404, (int)response.StatusCode);
|
||||
|
||||
user.ModifyStore(s => s.AnyoneCanCreateInvoice = true);
|
||||
await user.ModifyStore(s => s.AnyoneCanCreateInvoice = true);
|
||||
|
||||
Logs.Tester.LogInformation("Bad store with anyone can create invoice = 403");
|
||||
response = await tester.PayTester.HttpClient.SendAsync(
|
||||
|
@ -2449,7 +2452,7 @@ namespace BTCPayServer.Tests
|
|||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
user.SetNetworkFeeMode(NetworkFeeMode.Always);
|
||||
await user.SetNetworkFeeMode(NetworkFeeMode.Always);
|
||||
var invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
{
|
||||
|
@ -2525,7 +2528,7 @@ namespace BTCPayServer.Tests
|
|||
foreach (var networkFeeMode in Enum.GetValues(typeof(NetworkFeeMode)).Cast<NetworkFeeMode>())
|
||||
{
|
||||
Logs.Tester.LogInformation($"Trying with {nameof(networkFeeMode)}={networkFeeMode}");
|
||||
user.SetNetworkFeeMode(networkFeeMode);
|
||||
await user.SetNetworkFeeMode(networkFeeMode);
|
||||
var invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
{
|
||||
|
@ -2612,7 +2615,7 @@ namespace BTCPayServer.Tests
|
|||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
user.SetNetworkFeeMode(NetworkFeeMode.Always);
|
||||
await user.SetNetworkFeeMode(NetworkFeeMode.Always);
|
||||
var invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
{
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
else if (vm.Method == WalletSetupMethod.Seed)
|
||||
{
|
||||
vm.SetupRequest = new GenerateWalletRequest();
|
||||
vm.SetupRequest = new WalletSetupRequest();
|
||||
}
|
||||
|
||||
return View(vm.ViewName, vm);
|
||||
|
@ -162,6 +162,7 @@ namespace BTCPayServer.Controllers
|
|||
store.SetSupportedPaymentMethod(paymentMethodId, strategy);
|
||||
storeBlob.SetExcluded(paymentMethodId, false);
|
||||
storeBlob.Hints.Wallet = false;
|
||||
storeBlob.PayJoinEnabled = vm.IsHotWallet && vm.SetupRequest.PayJoinEnabled;
|
||||
store.SetStoreBlob(storeBlob);
|
||||
}
|
||||
catch
|
||||
|
@ -169,7 +170,6 @@ namespace BTCPayServer.Controllers
|
|||
ModelState.AddModelError(nameof(vm.DerivationScheme), "Invalid derivation scheme");
|
||||
return View(vm.ViewName, vm);
|
||||
}
|
||||
|
||||
await _Repo.UpdateStore(store);
|
||||
_EventAggregator.Publish(new WalletChangedEvent { WalletId = new WalletId(vm.StoreId, vm.CryptoCode) });
|
||||
|
||||
|
@ -217,14 +217,20 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
else
|
||||
{
|
||||
vm.SetupRequest = new GenerateWalletRequest { SavePrivateKeys = isHotWallet };
|
||||
var canUsePayJoin = hotWallet && isHotWallet && network.SupportPayJoin;
|
||||
vm.SetupRequest = new WalletSetupRequest
|
||||
{
|
||||
SavePrivateKeys = isHotWallet,
|
||||
CanUsePayJoin = canUsePayJoin,
|
||||
PayJoinEnabled = canUsePayJoin
|
||||
};
|
||||
}
|
||||
|
||||
return View(vm.ViewName, vm);
|
||||
}
|
||||
internal GenerateWalletResponse GenerateWalletResponse;
|
||||
[HttpPost("{storeId}/onchain/{cryptoCode}/generate/{method}")]
|
||||
public async Task<IActionResult> GenerateWallet(string storeId, string cryptoCode, WalletSetupMethod method, GenerateWalletRequest request)
|
||||
public async Task<IActionResult> GenerateWallet(string storeId, string cryptoCode, WalletSetupMethod method, WalletSetupRequest request)
|
||||
{
|
||||
var checkResult = IsAvailable(cryptoCode, out var store, out var network);
|
||||
if (checkResult != null)
|
||||
|
@ -240,7 +246,6 @@ namespace BTCPayServer.Controllers
|
|||
|
||||
var client = _ExplorerProvider.GetExplorerClient(cryptoCode);
|
||||
var isImport = method == WalletSetupMethod.Seed;
|
||||
|
||||
var vm = new WalletSetupViewModel
|
||||
{
|
||||
StoreId = storeId,
|
||||
|
@ -253,7 +258,7 @@ namespace BTCPayServer.Controllers
|
|||
Source = isImport ? "SeedImported" : "NBXplorerGenerated",
|
||||
IsHotWallet = isImport ? request.SavePrivateKeys : method == WalletSetupMethod.HotWallet,
|
||||
DerivationSchemeFormat = "BTCPay",
|
||||
CanUseHotWallet = true,
|
||||
CanUseHotWallet = hotWallet,
|
||||
CanUseRPCImport = rpcImport
|
||||
};
|
||||
|
||||
|
@ -370,7 +375,6 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
var (hotWallet, rpcImport) = await CanUseHotWallet();
|
||||
var isHotWallet = await IsHotWallet(vm.CryptoCode, derivation);
|
||||
|
||||
vm.CanUseHotWallet = hotWallet;
|
||||
vm.CanUseRPCImport = rpcImport;
|
||||
|
@ -381,13 +385,13 @@ namespace BTCPayServer.Controllers
|
|||
vm.DerivationScheme = derivation.AccountDerivation.ToString();
|
||||
vm.KeyPath = derivation.GetSigningAccountKeySettings().AccountKeyPath?.ToString();
|
||||
vm.Config = ProtectString(derivation.ToJson());
|
||||
vm.IsHotWallet = isHotWallet;
|
||||
vm.IsHotWallet = derivation.IsHotWallet;
|
||||
|
||||
return View(vm);
|
||||
}
|
||||
|
||||
[HttpGet("{storeId}/onchain/{cryptoCode}/replace")]
|
||||
public async Task<IActionResult> ReplaceWallet(string storeId, string cryptoCode)
|
||||
public ActionResult ReplaceWallet(string storeId, string cryptoCode)
|
||||
{
|
||||
var checkResult = IsAvailable(cryptoCode, out var store, out var network);
|
||||
if (checkResult != null)
|
||||
|
@ -396,9 +400,8 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
var derivation = GetExistingDerivationStrategy(cryptoCode, store);
|
||||
var isHotWallet = await IsHotWallet(cryptoCode, derivation);
|
||||
var walletType = isHotWallet ? "hot" : "watch-only";
|
||||
var additionalText = isHotWallet
|
||||
var walletType = derivation.IsHotWallet ? "hot" : "watch-only";
|
||||
var additionalText = derivation.IsHotWallet
|
||||
? ""
|
||||
: " or imported into an external wallet. If you no longer have access to your private key (recovery seed), immediately replace the wallet";
|
||||
var description =
|
||||
|
@ -435,7 +438,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/onchain/{cryptoCode}/delete")]
|
||||
public async Task<IActionResult> DeleteWallet(string storeId, string cryptoCode)
|
||||
public ActionResult DeleteWallet(string storeId, string cryptoCode)
|
||||
{
|
||||
var checkResult = IsAvailable(cryptoCode, out var store, out var network);
|
||||
if (checkResult != null)
|
||||
|
@ -444,9 +447,8 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
var derivation = GetExistingDerivationStrategy(cryptoCode, store);
|
||||
var isHotWallet = await IsHotWallet(cryptoCode, derivation);
|
||||
var walletType = isHotWallet ? "hot" : "watch-only";
|
||||
var additionalText = isHotWallet
|
||||
var walletType = derivation.IsHotWallet ? "hot" : "watch-only";
|
||||
var additionalText = derivation.IsHotWallet
|
||||
? ""
|
||||
: " or imported into an external wallet. If you no longer have access to your private key (recovery seed), immediately replace the wallet";
|
||||
var description =
|
||||
|
@ -582,11 +584,5 @@ namespace BTCPayServer.Controllers
|
|||
return await stream.ReadToEndAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> IsHotWallet(string cryptoCode, DerivationSchemeSettings derivation)
|
||||
{
|
||||
return derivation.IsHotWallet && await _ExplorerProvider.GetExplorerClient(cryptoCode)
|
||||
.GetMetadataAsync<string>(derivation.AccountDerivation, WellknownMetadataKeys.MasterHDKey) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -466,7 +466,6 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
|
@ -558,12 +557,9 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpGet]
|
||||
[Route("{storeId}")]
|
||||
public IActionResult UpdateStore()
|
||||
|
||||
[HttpGet("{storeId}")]
|
||||
public async Task<IActionResult> UpdateStore()
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
if (store == null)
|
||||
|
@ -586,12 +582,17 @@ namespace BTCPayServer.Controllers
|
|||
vm.PayJoinEnabled = storeBlob.PayJoinEnabled;
|
||||
vm.HintWallet = storeBlob.Hints.Wallet;
|
||||
vm.HintLightning = storeBlob.Hints.Lightning;
|
||||
|
||||
(bool canUseHotWallet, _) = await CanUseHotWallet();
|
||||
vm.CanUsePayJoin = canUseHotWallet && store
|
||||
.GetSupportedPaymentMethods(_NetworkProvider)
|
||||
.OfType<DerivationSchemeSettings>()
|
||||
.Any(settings => settings.Network.SupportPayJoin && settings.IsHotWallet);
|
||||
|
||||
return View(vm);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[Route("{storeId}")]
|
||||
|
||||
[HttpPost("{storeId}")]
|
||||
public async Task<IActionResult> UpdateStore(StoreViewModel model, string command = null)
|
||||
{
|
||||
bool needUpdate = false;
|
||||
|
@ -635,11 +636,7 @@ namespace BTCPayServer.Controllers
|
|||
{
|
||||
var problematicPayjoinEnabledMethods = CurrentStore.GetSupportedPaymentMethods(_NetworkProvider)
|
||||
.OfType<DerivationSchemeSettings>()
|
||||
.Where(settings =>
|
||||
settings.Network.SupportPayJoin &&
|
||||
string.IsNullOrEmpty(_ExplorerProvider.GetExplorerClient(settings.Network)
|
||||
.GetMetadata<string>(settings.AccountDerivation,
|
||||
WellknownMetadataKeys.Mnemonic)))
|
||||
.Where(settings => settings.Network.SupportPayJoin && !settings.IsHotWallet)
|
||||
.Select(settings => settings.PaymentId.CryptoCode)
|
||||
.ToArray();
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@ namespace BTCPayServer.Models.StoreViewModels
|
|||
|
||||
[Display(Name = "Enable Payjoin/P2EP")]
|
||||
public bool PayJoinEnabled { get; set; }
|
||||
public bool CanUsePayJoin { get; set; }
|
||||
|
||||
public bool HintWallet { get; set; }
|
||||
public bool HintLightning { get; set; }
|
||||
|
|
10
BTCPayServer/Models/StoreViewModels/WalletSetupRequest.cs
Normal file
10
BTCPayServer/Models/StoreViewModels/WalletSetupRequest.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using NBXplorer.Models;
|
||||
|
||||
namespace BTCPayServer.Models.StoreViewModels
|
||||
{
|
||||
public class WalletSetupRequest : GenerateWalletRequest
|
||||
{
|
||||
public bool PayJoinEnabled { get; set; }
|
||||
public bool CanUsePayJoin { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
using NBXplorer.Models;
|
||||
|
||||
namespace BTCPayServer.Models.StoreViewModels
|
||||
{
|
||||
public enum WalletSetupMethod
|
||||
|
@ -18,7 +16,7 @@ namespace BTCPayServer.Models.StoreViewModels
|
|||
public class WalletSetupViewModel : DerivationSchemeViewModel
|
||||
{
|
||||
public WalletSetupMethod? Method { get; set; }
|
||||
public GenerateWalletRequest SetupRequest { get; set; }
|
||||
public WalletSetupRequest SetupRequest { get; set; }
|
||||
public string StoreId { get; set; }
|
||||
public bool IsHotWallet { get; set; }
|
||||
|
||||
|
|
|
@ -175,22 +175,27 @@
|
|||
</div>
|
||||
|
||||
<h4 class="mt-5 mb-3">Payment</h4>
|
||||
<div class="form-group form-check">
|
||||
<input asp-for="AnyoneCanCreateInvoice" type="checkbox" class="form-check-input" />
|
||||
<label asp-for="AnyoneCanCreateInvoice" class="form-check-label"></label>
|
||||
<div class="form-group d-flex align-items-center">
|
||||
<input asp-for="AnyoneCanCreateInvoice" type="checkbox" class="btcpay-toggle me-2" />
|
||||
<label asp-for="AnyoneCanCreateInvoice" class="form-label mb-0 me-1"></label>
|
||||
<a href="https://docs.btcpayserver.org/FAQ/FAQ-Stores/#allow-anyone-to-create-invoice" target="_blank">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="form-group form-check">
|
||||
<input asp-for="PayJoinEnabled" type="checkbox" class="form-check-input" />
|
||||
<label asp-for="PayJoinEnabled" class="form-check-label"></label>
|
||||
<a href="https://docs.btcpayserver.org/Payjoin/" target="_blank">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
</a>
|
||||
<span asp-validation-for="PayJoinEnabled" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@if (Model.CanUsePayJoin)
|
||||
{
|
||||
<div class="form-group">
|
||||
<div class="d-flex align-items-center">
|
||||
<input asp-for="PayJoinEnabled" type="checkbox" class="btcpay-toggle me-2"/>
|
||||
<label asp-for="PayJoinEnabled" class="form-label mb-0 me-1"></label>
|
||||
<a href="https://docs.btcpayserver.org/Payjoin/" target="_blank">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
</a>
|
||||
</div>
|
||||
<span asp-validation-for="PayJoinEnabled" class="text-danger"></span>
|
||||
</div>
|
||||
}
|
||||
<div class="form-group mt-4">
|
||||
<label asp-for="NetworkFeeMode" class="form-label"></label>
|
||||
<a href="https://docs.btcpayserver.org/FAQ/FAQ-Stores/#add-network-fee-to-invoice-vary-with-mining-fees" target="_blank">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@using NBitcoin
|
||||
@model NBXplorer.Models.GenerateWalletRequest
|
||||
@model WalletSetupRequest
|
||||
|
||||
@{
|
||||
var method = ViewData["Method"];
|
||||
|
@ -55,6 +55,22 @@
|
|||
else
|
||||
{
|
||||
<input asp-for="SavePrivateKeys" type="hidden" value="@isHotWallet" />
|
||||
|
||||
@if (Model.CanUsePayJoin)
|
||||
{
|
||||
<div class="form-group mt-4">
|
||||
<label asp-for="PayJoinEnabled">Enable PayJoin</label>
|
||||
<input type="checkbox" asp-for="PayJoinEnabled" class="btcpay-toggle ml-2" />
|
||||
<span asp-validation-for="PayJoinEnabled" class="text-danger"></span>
|
||||
<p class="text-muted pt-2">
|
||||
PayJoin enhances the privacy for you and your customers.
|
||||
Enabling it gives your customers the option to use PayJoin during checkout.
|
||||
<a href="https://docs.btcpayserver.org/Payjoin/" target="_blank">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
<div class="mb-4">
|
||||
|
|
Loading…
Add table
Reference in a new issue