What changed, and why it matters
This commit is a large but straightforward code reorganization: it moves wallet-related view model classes from one namespace/folder (BTCPayServer.Models.WalletViewModels) into a new plugin-specific location (BTCPayServer.Plugins.Wallets.Views.ViewModels) and updates all references accordingly. There is no functional change to how the application behaves, no security fix, and no vulnerability introduced in the diff itself.
No security action required. Treat as routine maintenance/refactoring. Reviewers may optionally verify that the moved view models remain binary-compatible with serialized data and that no stale using statements remain, but the diff shows consistent namespace updates.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change is a pure refactor: delete files under BTCPayServer/Models/WalletViewModels and recreate them under BTCPayServer/Plugins/Wallets/Views/ViewModels with identical or near-identical content, adjusting using statements for moved base interfaces (e.g., IHasBackAndReturnUrl remains in BTCPayServer.Models). Controllers, services, tests, and Razor views are updated to use the new namespace. The only non-refactor edit is a removal of an unused ISettingsAccessor
Changed components
BTCPayServer.Plugins.WalletsBTCPayServer.Controllers (wallet/payout/pull-payment controllers)BTCPayServer.Services.LabelsBTCPayServer.Services.WalletRepositoryBTCPayServer Razor views for wallets, pull payments, and payoutsInspect captured patch +882 / −878
diff --git a/BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs b/BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs
index 3352d94..a343130 100644
--- a/BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs
+++ b/BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs
@@ -10,7 +10,7 @@ using BTCPayServer.Hosting;
using BTCPayServer.Lightning;
using BTCPayServer.Models.AppViewModels;
using BTCPayServer.Models.StoreViewModels;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.Payments;
using BTCPayServer.Plugins.PointOfSale;
using BTCPayServer.Plugins.PointOfSale.Controllers;
diff --git a/BTCPayServer.Tests/AltcoinTests/ElementsTests.cs b/BTCPayServer.Tests/AltcoinTests/ElementsTests.cs
index 3fb54d5..0f3acd4 100644
--- a/BTCPayServer.Tests/AltcoinTests/ElementsTests.cs
+++ b/BTCPayServer.Tests/AltcoinTests/ElementsTests.cs
@@ -2,7 +2,7 @@ using System;
using System.Linq;
using System.Threading.Tasks;
using BTCPayServer.Controllers;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.Plugins.Altcoins;
using BTCPayServer.Services.Wallets;
using Microsoft.AspNetCore.Mvc;
@@ -48,12 +48,12 @@ namespace BTCPayServer.Tests
{
tester.ActivateLBTC();
await tester.StartAsync();
-
+
//https://github.com/ElementsProject/elements/issues/956
await tester.LBTCExplorerNode.SendCommandAsync("rescanblockchain");
var user = tester.NewAccount();
await user.GrantAccessAsync();
-
+
await tester.LBTCExplorerNode.GenerateAsync(4);
//no tether on our regtest, lets create it and set it
var tether = tester.NetworkProvider.GetNetwork<ElementsBTCPayNetwork>("USDT");
@@ -69,7 +69,7 @@ namespace BTCPayServer.Tests
user.RegisterDerivationScheme("LBTC");
user.RegisterDerivationScheme("USDT");
-
+
//test: register 2 assets on the same elements network and make sure paying an invoice on one does not affect the other in any way
var invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(0.1m, "BTC"));
Assert.Equal(3, invoice.SupportedTransactionCurrencies.Count);
@@ -98,7 +98,7 @@ namespace BTCPayServer.Tests
Assert.Equal("paid", localInvoice.Status);
Assert.Single(localInvoice.CryptoInfo.Single(info => info.CryptoCode.Equals("USDT", StringComparison.InvariantCultureIgnoreCase)).Payments);
});
-
+
var lbtcBip21 = new BitcoinUrlBuilder(invoice.CryptoInfo.Single(info => info.CryptoCode == "LBTC").PaymentUrls.BIP21, lbtc.NBitcoinNetwork);
//precision = 8, 0.1 = 0.1
diff --git a/BTCPayServer.Tests/ThirdPartyTests.cs b/BTCPayServer.Tests/ThirdPartyTests.cs
index 971f1db..74b2adc 100644
--- a/BTCPayServer.Tests/ThirdPartyTests.cs
+++ b/BTCPayServer.Tests/ThirdPartyTests.cs
@@ -11,7 +11,7 @@ using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.Hosting;
using BTCPayServer.Models.StoreViewModels;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.Rating;
using BTCPayServer.Services.Fees;
using BTCPayServer.Services.Rates;
diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs
index b6c4694..b69d77e 100644
--- a/BTCPayServer.Tests/UnitTest1.cs
+++ b/BTCPayServer.Tests/UnitTest1.cs
@@ -31,7 +31,7 @@ using BTCPayServer.Models.InvoicingModels;
using BTCPayServer.Models.ManageViewModels;
using BTCPayServer.Models.ServerViewModels;
using BTCPayServer.Models.StoreViewModels;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.Payments;
using BTCPayServer.Payments.Bitcoin;
using BTCPayServer.Payments.PayJoin.Sender;
diff --git a/BTCPayServer/Components/StoreRecentTransactions/StoreRecentTransactionViewModel.cs b/BTCPayServer/Components/StoreRecentTransactions/StoreRecentTransactionViewModel.cs
index 120944b..89b2791 100644
--- a/BTCPayServer/Components/StoreRecentTransactions/StoreRecentTransactionViewModel.cs
+++ b/BTCPayServer/Components/StoreRecentTransactions/StoreRecentTransactionViewModel.cs
@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
namespace BTCPayServer.Components.StoreRecentTransactions;
diff --git a/BTCPayServer/Controllers/GreenField/GreenfieldStoreOnChainWalletsController.cs b/BTCPayServer/Controllers/GreenField/GreenfieldStoreOnChainWalletsController.cs
index b0bdada..e297207 100644
--- a/BTCPayServer/Controllers/GreenField/GreenfieldStoreOnChainWalletsController.cs
+++ b/BTCPayServer/Controllers/GreenField/GreenfieldStoreOnChainWalletsController.cs
@@ -12,7 +12,7 @@ using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.Payments;
using BTCPayServer.Payments.Bitcoin;
using BTCPayServer.Payments.PayJoin;
diff --git a/BTCPayServer/Controllers/UIPaymentRequestController.cs b/BTCPayServer/Controllers/UIPaymentRequestController.cs
index 577d139..abbad9b 100644
--- a/BTCPayServer/Controllers/UIPaymentRequestController.cs
+++ b/BTCPayServer/Controllers/UIPaymentRequestController.cs
@@ -15,7 +15,7 @@ using BTCPayServer.Forms;
using BTCPayServer.Forms.Models;
using BTCPayServer.Models;
using BTCPayServer.Models.PaymentRequestViewModels;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.PaymentRequest;
using BTCPayServer.Plugins.Wallets;
using BTCPayServer.Services;
diff --git a/BTCPayServer/Controllers/UIPullPaymentController.cs b/BTCPayServer/Controllers/UIPullPaymentController.cs
index f6aa41b..8bf6c13 100644
--- a/BTCPayServer/Controllers/UIPullPaymentController.cs
+++ b/BTCPayServer/Controllers/UIPullPaymentController.cs
@@ -11,7 +11,7 @@ using BTCPayServer.Controllers.Greenfield;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
using BTCPayServer.Models;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.Payments;
using BTCPayServer.Payouts;
using BTCPayServer.Services;
diff --git a/BTCPayServer/Controllers/UIStorePullPaymentsController.PullPayments.cs b/BTCPayServer/Controllers/UIStorePullPaymentsController.PullPayments.cs
index 52c0811..2a38bdc 100644
--- a/BTCPayServer/Controllers/UIStorePullPaymentsController.PullPayments.cs
+++ b/BTCPayServer/Controllers/UIStorePullPaymentsController.PullPayments.cs
@@ -10,7 +10,7 @@ using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.PayoutProcessors;
using BTCPayServer.Payouts;
using BTCPayServer.Services;
diff --git a/BTCPayServer/Controllers/UIStoresController.Labels.cs b/BTCPayServer/Controllers/UIStoresController.Labels.cs
index 2a84297..91dab26 100644
--- a/BTCPayServer/Controllers/UIStoresController.Labels.cs
+++ b/BTCPayServer/Controllers/UIStoresController.Labels.cs
@@ -5,7 +5,7 @@ using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Client;
using BTCPayServer.Data;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
diff --git a/BTCPayServer/Extensions/ControllerBaseExtensions.cs b/BTCPayServer/Extensions/ControllerBaseExtensions.cs
index ca11a30..73b3da7 100644
--- a/BTCPayServer/Extensions/ControllerBaseExtensions.cs
+++ b/BTCPayServer/Extensions/ControllerBaseExtensions.cs
@@ -4,7 +4,7 @@ using BTCPayServer.Models;
using BTCPayServer.Models.InvoicingModels;
using BTCPayServer.Models.PaymentRequestViewModels;
using BTCPayServer.Models.ServerViewModels;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
diff --git a/BTCPayServer/HostedServices/PullPaymentHostedService.cs b/BTCPayServer/HostedServices/PullPaymentHostedService.cs
index b8386b0..e8766ef 100644
--- a/BTCPayServer/HostedServices/PullPaymentHostedService.cs
+++ b/BTCPayServer/HostedServices/PullPaymentHostedService.cs
@@ -10,7 +10,7 @@ using BTCPayServer.Data;
using BTCPayServer.Events;
using BTCPayServer.Lightning;
using BTCPayServer.Logging;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.Payouts;
using BTCPayServer.Rating;
using BTCPayServer.Services;
diff --git a/BTCPayServer/Models/PaymentRequestViewModels/ListPaymentRequestsViewModel.cs b/BTCPayServer/Models/PaymentRequestViewModels/ListPaymentRequestsViewModel.cs
index 82c0608..8d50f2b 100644
--- a/BTCPayServer/Models/PaymentRequestViewModels/ListPaymentRequestsViewModel.cs
+++ b/BTCPayServer/Models/PaymentRequestViewModels/ListPaymentRequestsViewModel.cs
@@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations;
using System.Linq;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.Services;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Rates;
diff --git a/BTCPayServer/Models/WalletViewModels/ListTransactionsViewModel.cs b/BTCPayServer/Models/WalletViewModels/ListTransactionsViewModel.cs
deleted file mode 100644
index f036ab6..0000000
--- a/BTCPayServer/Models/WalletViewModels/ListTransactionsViewModel.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-using System.Collections.Generic;
-using BTCPayServer.Data;
-using BTCPayServer.Services.Invoices;
-using BTCPayServer.Services.Wallets;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class ListTransactionsViewModel : BasePagingViewModel
- {
- public class TransactionViewModel
- {
- public DateTimeOffset Timestamp { get; set; }
- public bool IsConfirmed { get; set; }
- public bool CanBumpFee { get; set; }
- public string Comment { get; set; }
- public string Id { get; set; }
- public string Link { get; set; }
- public bool Positive { get; set; }
- public string Balance { get; set; }
- public HashSet<TransactionTagModel> Tags { get; set; } = new();
- public string Rate { get; set; }
- public List<string> Rates { get; set; } = new();
- public RateBook WalletRateBook { get; set; }
- public RateBook InvoiceRateBook { get; set; }
- public string InvoiceId { get; set; }
- public TransactionHistoryLine HistoryLine { get; set; }
- }
- public HashSet<(string Text, string Color, string TextColor, long UsageCount)> Labels { get; set; } = new();
- public List<(string Text, string Color, string TextColor, long UsageCount)> PopularLabels { get; set; } = new();
- public List<TransactionViewModel> Transactions { get; set; } = new();
- public override int CurrentPageCount => Transactions.Count;
- public string CryptoCode { get; set; }
- public PendingTransaction[] PendingTransactions { get; set; }
- public List<string> Rates { get; set; }
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/ListWalletsViewModel.cs b/BTCPayServer/Models/WalletViewModels/ListWalletsViewModel.cs
deleted file mode 100644
index 60e4652..0000000
--- a/BTCPayServer/Models/WalletViewModels/ListWalletsViewModel.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.Collections.Generic;
-using NBitcoin;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class ListWalletsViewModel
- {
- public class WalletViewModel
- {
- public string StoreName { get; set; }
- public string StoreId { get; set; }
- public string CryptoCode { get; set; }
- public string Balance { get; set; }
- public WalletId Id { get; set; }
- }
-
- public Dictionary<BTCPayNetwork, IMoney> BalanceForCryptoCode { get; set; } = new Dictionary<BTCPayNetwork, IMoney>();
- public List<WalletViewModel> Wallets { get; set; } = new List<WalletViewModel>();
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/PayoutsModel.cs b/BTCPayServer/Models/WalletViewModels/PayoutsModel.cs
deleted file mode 100644
index c425592..0000000
--- a/BTCPayServer/Models/WalletViewModels/PayoutsModel.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using BTCPayServer.Client.Models;
-using BTCPayServer.Payouts;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class PayoutsModel : BasePagingViewModel
- {
- public string PullPaymentId { get; set; }
- public string Command { get; set; }
- public Dictionary<PayoutState, int> PayoutStateCount { get; set; }
- public Dictionary<string, int> PayoutMethodCount { get; set; }
- public string PayoutMethodId { get; set; }
-
- public List<PayoutModel> Payouts { get; set; }
- public override int CurrentPageCount => Payouts.Count;
- public IEnumerable<PayoutMethodId> PayoutMethods { get; set; }
- public PayoutState PayoutState { get; set; }
- public string PullPaymentName { get; set; }
- public bool HasPayoutProcessor { get; set; }
-
- public class PayoutModel
- {
- public string PayoutId { get; set; }
- public bool Selected { get; set; }
- public DateTimeOffset Date { get; set; }
- public string PullPaymentId { get; set; }
- public string Source { get; set; }
- public string SourceLink { get; set; }
- public string Destination { get; set; }
- public string Amount { get; set; }
- public string ProofLink { get; set; }
- }
-
- public string[] GetSelectedPayouts(PayoutState state)
- {
- return Payouts.Where(model => model.Selected).Select(model => model.PayoutId)
- .ToArray();
- }
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/PullPaymentsModel.cs b/BTCPayServer/Models/WalletViewModels/PullPaymentsModel.cs
deleted file mode 100644
index 3fc8be2..0000000
--- a/BTCPayServer/Models/WalletViewModels/PullPaymentsModel.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.ComponentModel.DataAnnotations;
-using BTCPayServer.Client.Models;
-using BTCPayServer.Data;
-using Microsoft.AspNetCore.Mvc.Rendering;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class PullPaymentsModel : BasePagingViewModel
- {
- public class PullPaymentModel
- {
- public class ProgressModel
- {
- public int CompletedPercent { get; set; }
- public int AwaitingPercent { get; set; }
- public string CompletedFormatted { get; set; }
- public string AwaitingFormatted { get; set; }
- public string LimitFormatted { get; set; }
- public string EndIn { get; set; }
- public decimal Awaiting { get; set; }
- public decimal Completed { get; set; }
- public decimal Limit { get; set; }
- }
- public string Id { get; set; }
- public string Name { get; set; }
- public string ProgressText { get; set; }
- public ProgressModel Progress { get; set; }
- public DateTimeOffset StartDate { get; set; }
- public DateTimeOffset? EndDate { get; set; }
- public bool AutoApproveClaims { get; set; }
- public bool Archived { get; set; } = false;
- }
-
- public List<PullPaymentModel> PullPayments { get; set; } = new List<PullPaymentModel>();
- public override int CurrentPageCount => PullPayments.Count;
- public PullPaymentState ActiveState { get; set; } = PullPaymentState.Active;
- }
-
- public class NewPullPaymentModel
- {
- [MaxLength(30)]
- [Display(Name = "Name")]
- public string Name { get; set; }
-
- [Display(Name = "Description")]
- public string Description { get; set; }
-
- [Required]
- [Display(Name = "Amount")]
- public decimal Amount { get; set; }
-
- [Required]
- [ReadOnly(true)]
- [Display(Name = "Currency")]
- public string Currency { get; set; }
-
- [Display(Name = "Payout Methods")]
- public IEnumerable<string> PayoutMethods { get; set; }
- public IEnumerable<SelectListItem> PayoutMethodsItem { get; set; }
- [Display(Name = "Minimum acceptable expiration time for BOLT11 for refunds")]
- [Range(0, 365 * 10)]
- public long BOLT11Expiration { get; set; } = 30;
- [Display(Name = "Automatically approve claims")]
- public bool AutoApproveClaims { get; set; }
- }
-
- public class UpdatePullPaymentModel
- {
- [Display(Name = "Id")]
- public string Id { get; set; }
-
- public UpdatePullPaymentModel()
- {
- }
-
- public UpdatePullPaymentModel(Data.PullPaymentData data)
- {
- if (data == null)
- {
- return;
- }
-
- Id = data.Id;
- var blob = data.GetBlob();
- Name = blob.Name;
- Description = blob.Description;
- }
-
- [MaxLength(30)]
- [Display(Name = "Name")]
- public string Name { get; set; }
-
- [Display(Name = "Memo")]
- public string Description { get; set; }
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/RescanWalletModel.cs b/BTCPayServer/Models/WalletViewModels/RescanWalletModel.cs
deleted file mode 100644
index 6f54f8a..0000000
--- a/BTCPayServer/Models/WalletViewModels/RescanWalletModel.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.ComponentModel;
-using System.ComponentModel.DataAnnotations;
-using NBXplorer.Models;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class RescanWalletModel
- {
- public bool IsServerAdmin { get; set; }
- public bool IsSupportedByCurrency { get; set; }
- public bool IsFullySync { get; set; }
- public bool Ok => IsServerAdmin && IsSupportedByCurrency && IsFullySync;
-
- [Range(1000, 10_000)]
- [DisplayName("Batch size")]
- public int BatchSize { get; set; } = 3000;
- [Range(0, 10_000_000)]
- [DisplayName("Starting index")]
- public int StartingIndex { get; set; } = 0;
-
- [Range(100, 100000)]
- [DisplayName("Gap limit")]
- public int GapLimit { get; set; } = 10000;
-
- public int? Progress { get; set; }
- public string PreviousError { get; set; }
- public ScanUTXOProgress LastSuccess { get; internal set; }
- public string TimeOfScan { get; internal set; }
- public string RemainingTime { get; internal set; }
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/ReservedAddressesViewModel.cs b/BTCPayServer/Models/WalletViewModels/ReservedAddressesViewModel.cs
deleted file mode 100644
index b61a911..0000000
--- a/BTCPayServer/Models/WalletViewModels/ReservedAddressesViewModel.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace BTCPayServer.Models.WalletViewModels;
-
-public class ReservedAddressesViewModel
-{
- public string WalletId { get; set; }
- public string CryptoCode { get; set; }
- public List<ReservedAddress> Addresses { get; set; }
-}
-
-public class ReservedAddress
-{
- public string Address { get; set; }
- public List<TransactionTagModel> Labels { get; set; } = new();
- public DateTimeOffset? ReservedAt { get; set; }
-}
-
diff --git a/BTCPayServer/Models/WalletViewModels/SignWithSeedViewModel.cs b/BTCPayServer/Models/WalletViewModels/SignWithSeedViewModel.cs
deleted file mode 100644
index 7c33f79..0000000
--- a/BTCPayServer/Models/WalletViewModels/SignWithSeedViewModel.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System;
-using System.ComponentModel.DataAnnotations;
-using NBitcoin;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class SignWithSeedViewModel : IHasBackAndReturnUrl
- {
- public SigningContextModel SigningContext { get; set; } = new SigningContextModel();
-
- [Required]
- [Display(Name = "BIP39 Seed (12/24 word mnemonic phrase) or HD private key (xprv...)")]
- public string SeedOrKey { get; set; }
-
- public bool UseHotWallet { get; set; }
-
- [Display(Name = "Optional seed passphrase")]
- public string Passphrase { get; set; }
-
- public string BackUrl { get; set; }
- public string ReturnUrl { get; set; }
-
- public ExtKey GetExtKey(Network network)
- {
- ExtKey extKey = null;
- try
- {
- var mnemonic = new Mnemonic(SeedOrKey);
- extKey = mnemonic.DeriveExtKey(Passphrase);
- }
- catch (Exception)
- {
- }
-
- if (extKey == null)
- {
- try
- {
- extKey = ExtKey.Parse(SeedOrKey, network);
- }
- catch (Exception)
- {
- }
- }
- return extKey;
- }
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/SigningContextModel.cs b/BTCPayServer/Models/WalletViewModels/SigningContextModel.cs
deleted file mode 100644
index 66db599..0000000
--- a/BTCPayServer/Models/WalletViewModels/SigningContextModel.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using NBitcoin;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class SigningContextModel
- {
- public SigningContextModel()
- {
-
- }
- public SigningContextModel(PSBT psbt)
- {
- PSBT = psbt.ToBase64();
- }
- public string PSBT { get; set; }
- public string OriginalPSBT { get; set; }
- public string PayJoinBIP21 { get; set; }
- public bool? EnforceLowR { get; set; }
- public string ChangeAddress { get; set; }
-
- public string PendingTransactionId { get; set; }
- public long BalanceChangeFromReplacement { get; set; }
- public string Comment { get; set; }
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/TransactionTagModel.cs b/BTCPayServer/Models/WalletViewModels/TransactionTagModel.cs
deleted file mode 100644
index ec0741d..0000000
--- a/BTCPayServer/Models/WalletViewModels/TransactionTagModel.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class TransactionTagModel
- {
- public string Text { get; internal set; }
- public string Color { get; internal set; }
- public string TextColor { get; internal set; }
- public string Link { get; internal set; }
- public string Tooltip { get; internal set; } = String.Empty;
-
- public override bool Equals(object obj)
- {
- TransactionTagModel item = obj as TransactionTagModel;
- if (item == null)
- return false;
- return Text.Equals(item.Text, StringComparison.OrdinalIgnoreCase);
- }
-
- public static bool operator ==(TransactionTagModel a, TransactionTagModel b)
- {
- if (System.Object.ReferenceEquals(a, b))
- return true;
- if (((object)a == null) || ((object)b == null))
- return false;
- return a.Text == b.Text;
- }
-
- public static bool operator !=(TransactionTagModel a, TransactionTagModel b)
- {
- return !(a == b);
- }
-
- public override int GetHashCode()
- {
- return Text.GetHashCode(StringComparison.OrdinalIgnoreCase);
- }
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/WalletBumpFeeViewModel.cs b/BTCPayServer/Models/WalletViewModels/WalletBumpFeeViewModel.cs
deleted file mode 100644
index 61463c3..0000000
--- a/BTCPayServer/Models/WalletViewModels/WalletBumpFeeViewModel.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using System.Linq;
-using Microsoft.AspNetCore.Mvc.Rendering;
-using NBitcoin;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class WalletBumpFeeViewModel
- {
- public string ReturnUrl { get; set; }
- [Display(Name = "Transaction Id")]
- public uint256 TransactionId { get; set; }
- public List<SelectListItem> BumpFeeMethods { get; set; } = new();
- public string[] Outpoints { get; set; }
- public string[] TransactionHashes { get; set; }
- public List<WalletSendModel.FeeRateOption> RecommendedSatoshiPerByte { get; set; }
- [Display]
- public decimal? FeeSatoshiPerByte { get; set; }
- [Display]
- public decimal? CurrentFeeSatoshiPerByte { get; set; }
- public bool IsMultiSigOnServer { get; set; }
- [Display(Name = "Fee bump method")]
- public string BumpMethod { get; set; }
-
- public string Command { get; set; }
-#nullable enable
- public record BumpTarget(HashSet<OutPoint> Outpoints, HashSet<uint256> TxIds)
- {
-
- public uint256? GetSingleTransactionId()
- => this switch
- {
- { TxIds: { Count: 1 } ids, Outpoints: { Count: 0 } } => ids.First(),
- { TxIds: { Count: 0 }, Outpoints: { Count: 1 } outpoints } => outpoints.First().Hash,
- _ => null
- };
- public HashSet<uint256> GetTransactionIds()
- => (TxIds.Concat(Outpoints.Select(o => o.Hash))).ToHashSet();
-
- public BumpTarget Filter(HashSet<uint256> elligibleTxs)
- => new BumpTarget(
- Outpoints.Where(o => elligibleTxs.Contains(o.Hash)).ToHashSet(),
- TxIds.Where(t => elligibleTxs.Contains(t)).ToHashSet());
-
- public List<OutPoint> GetMatchedOutpoints(IEnumerable<OutPoint> outpoints)
- {
- List<OutPoint> matches = new();
- HashSet<uint256> bumpedTxs = new();
- foreach (var outpoint in outpoints)
- {
- if (Outpoints.Contains(outpoint))
- {
- matches.Add(outpoint);
- bumpedTxs.Add(outpoint.Hash);
- }
- else if (TxIds.Contains(outpoint.Hash) && bumpedTxs.Add(outpoint.Hash))
- {
- matches.Add(outpoint);
- }
- }
- return matches;
- }
- }
-
- public BumpTarget GetBumpTarget()
- {
- if (TransactionId is not null)
- return new BumpTarget(new(), new([TransactionId]));
- HashSet<OutPoint> outpoints = new();
- HashSet<uint256> txids = new();
- foreach (var o in Outpoints ?? [])
- {
- try
- {
- outpoints.Add(OutPoint.Parse(o));
- }
- catch { }
- }
- foreach (var o in TransactionHashes ?? [])
- {
- try
- {
- txids.Add(uint256.Parse(o));
- }
- catch { }
- }
- return new BumpTarget(outpoints, txids);
- }
-#nullable restore
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/WalletLabelsModel.cs b/BTCPayServer/Models/WalletViewModels/WalletLabelsModel.cs
deleted file mode 100644
index c7d548f..0000000
--- a/BTCPayServer/Models/WalletViewModels/WalletLabelsModel.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Collections.Generic;
-
-namespace BTCPayServer.Models.WalletViewModels;
-
-public class WalletLabelsModel
-{
- public WalletId WalletId { get; set; }
- public IEnumerable<WalletLabelModel> Labels { get; set; }
-}
-
-public class WalletLabelModel
-{
- public string Label { get; set; }
- public string Color { get; set; }
- public string TextColor { get; set; }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/WalletModel.cs b/BTCPayServer/Models/WalletViewModels/WalletModel.cs
deleted file mode 100644
index cd9338c..0000000
--- a/BTCPayServer/Models/WalletViewModels/WalletModel.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class WalletModel
- {
- public string ServerUrl { get; set; }
- public string CryptoCurrency
- {
- get;
- set;
- }
- public string DefaultAddress { get; set; }
- public string DefaultAmount { get; set; }
-
- public decimal? Rate { get; set; }
- public int Divisibility { get; set; }
- public string Fiat { get; set; }
- public string RateError { get; set; }
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/WalletPSBTCombineViewModel.cs b/BTCPayServer/Models/WalletViewModels/WalletPSBTCombineViewModel.cs
deleted file mode 100644
index 305bb64..0000000
--- a/BTCPayServer/Models/WalletViewModels/WalletPSBTCombineViewModel.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using System;
-using System.ComponentModel.DataAnnotations;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc.ModelBinding;
-using NBitcoin;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class WalletPSBTCombineViewModel : IHasBackAndReturnUrl
- {
- public string OtherPSBT { get; set; }
- [Display(Name = "PSBT to combine with…")]
- public string PSBT { get; set; }
- [Display(Name = "Upload PSBT from file…")]
- public IFormFile UploadedPSBTFile { get; set; }
-
- public string BackUrl { get; set; }
- public string ReturnUrl { get; set; }
-
- public PSBT GetSourcePSBT(Network network, ModelStateDictionary modelState)
- {
- if (network is null)
- return null;
- if (!string.IsNullOrEmpty(OtherPSBT))
- {
- try
- {
- return NBitcoin.PSBT.Parse(OtherPSBT, network);
- }
- catch (Exception ex)
- { modelState.AddModelError(nameof(OtherPSBT), ex.Message); }
- }
- return null;
- }
- public async Task<PSBT> GetPSBT(Network network, ModelStateDictionary modelState)
- {
- if (UploadedPSBTFile != null)
- {
- if (UploadedPSBTFile.Length > 500 * 1024)
- return null;
- byte[] bytes = new byte[UploadedPSBTFile.Length];
- using (var stream = UploadedPSBTFile.OpenReadStream())
- {
- await stream.ReadAsync(bytes, 0, (int)UploadedPSBTFile.Length);
- }
- try
- {
- if (network is null)
- return null;
- return NBitcoin.PSBT.Load(bytes, network);
- }
- catch (FormatException ex)
- {
- modelState.AddModelError(nameof(UploadedPSBTFile), ex.Message);
- return null;
- }
- }
- if (!string.IsNullOrEmpty(PSBT))
- {
- try
- {
- if (network is null)
- return null;
- return NBitcoin.PSBT.Parse(PSBT, network);
- }
- catch (FormatException ex)
- {
- modelState.AddModelError(nameof(UploadedPSBTFile), ex.Message);
- }
- }
- return null;
- }
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/WalletPSBTReadyViewModel.cs b/BTCPayServer/Models/WalletViewModels/WalletPSBTReadyViewModel.cs
deleted file mode 100644
index 3dd71bb..0000000
--- a/BTCPayServer/Models/WalletViewModels/WalletPSBTReadyViewModel.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using NBitcoin;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class WalletPSBTReadyViewModel : IHasBackAndReturnUrl
- {
- public SigningContextModel SigningContext { get; set; } = new SigningContextModel();
- public string SigningKey { get; set; }
- public bool UseHotWallet { get; set; }
- public string SigningKeyPath { get; set; }
-
- public class DestinationViewModel
- {
- public bool Positive { get; set; }
- public string Destination { get; set; }
- public StringAmounts Balance { get; set; }
- public IEnumerable<TransactionTagModel> Labels { get; set; } = new List<TransactionTagModel>();
- }
-
- public class InputViewModel
- {
- public int Index { get; set; }
- public string Error { get; set; }
- public bool Positive { get; set; }
- public StringAmounts BalanceChange { get; set; }
- public IEnumerable<TransactionTagModel> Labels { get; set; } = new List<TransactionTagModel>();
- }
- public class AmountViewModel
- {
- public bool Positive { get; set; }
- public StringAmounts BalanceChange { get; set; }
- }
- public AmountViewModel ReplacementBalanceChange { get; set; }
- public bool HasErrors => Inputs.Count == 0 || Inputs.Any(i => !string.IsNullOrEmpty(i.Error));
- public StringAmounts BalanceChange { get; set; }
- public bool CanCalculateBalance { get; set; }
- public bool Positive { get; set; }
- public List<DestinationViewModel> Destinations { get; set; } = new List<DestinationViewModel>();
- public List<InputViewModel> Inputs { get; set; } = new List<InputViewModel>();
- public string FeeRate { get; set; }
- public string BackUrl { get; set; }
- public string ReturnUrl { get; set; }
-
- internal void SetErrors(IList<PSBTError> errors)
- {
- foreach (var err in errors)
- {
- Inputs[(int)err.InputIndex].Error = err.Message;
- }
- }
-
- public record StringAmounts(string CryptoAmount, string FiatAmount);
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs b/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs
deleted file mode 100644
index bcea95d..0000000
--- a/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs
+++ /dev/null
@@ -1,108 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using System.IO;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc.ModelBinding;
-using NBitcoin;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class WalletPSBTViewModel : WalletPSBTReadyViewModel
- {
- public string CryptoCode { get; set; }
- public string Decoded { get; set; }
- string _FileName;
- public string PSBTHex { get; set; }
- public bool NBXSeedAvailable { get; set; }
-
- public string FileName
- {
- get
- {
- return string.IsNullOrEmpty(_FileName) ? "psbt-export.psbt" : _FileName;
- }
- set
- {
- _FileName = value;
- }
- }
- [Display(Name = "PSBT content")]
- public string PSBT { get; set; }
- public List<string> Errors { get; set; } = new List<string>();
-
- [Display(Name = "Upload PSBT from file…")]
- public IFormFile UploadedPSBTFile { get; set; }
-
-
- #nullable enable
- public async Task<PSBT?> GetPSBT(Network? network, ModelStateDictionary modelState)
- {
- var psbt = await GetPSBTCore(network, modelState);
- if (psbt != null)
- {
- Decoded = psbt.ToString();
- PSBTHex = psbt.ToHex();
- PSBT = psbt.ToBase64();
- if (SigningContext is null)
- SigningContext = new SigningContextModel(psbt);
- else
- SigningContext.PSBT = psbt.ToBase64();
- }
- return psbt;
- }
- public bool InvalidPSBT { get; set; }
-
- async Task<PSBT?> GetPSBTCore(Network? network, ModelStateDictionary modelState)
- {
- if (UploadedPSBTFile != null)
- {
- if (UploadedPSBTFile.Length > 500 * 1024)
- return null;
-
- try
- {
- byte[] bytes = new byte[UploadedPSBTFile.Length];
- await using (var stream = UploadedPSBTFile.OpenReadStream())
- {
- await stream.ReadAsync(bytes, 0, (int)UploadedPSBTFile.Length);
- }
- if (network is null)
- return null;
- return NBitcoin.PSBT.Load(bytes, network);
- }
- catch (Exception ex)
- {
- using var stream = new StreamReader(UploadedPSBTFile.OpenReadStream());
- PSBT = await stream.ReadToEndAsync();
- modelState.Remove(nameof(PSBT));
- modelState.AddModelError(nameof(PSBT), ex.Message);
- InvalidPSBT = true;
- }
- }
- if (SigningContext != null && !string.IsNullOrEmpty(SigningContext.PSBT))
- {
- PSBT = SigningContext.PSBT;
- modelState.Remove(nameof(PSBT));
- InvalidPSBT = false;
- }
- if (!string.IsNullOrEmpty(PSBT))
- {
- try
- {
- InvalidPSBT = false;
- if (network is null)
- return null;
- return NBitcoin.PSBT.Parse(PSBT, network);
- }
- catch (Exception ex) when (!InvalidPSBT)
- {
- modelState.AddModelError(nameof(PSBT), ex.Message);
- InvalidPSBT = true;
- }
- }
- return null;
- }
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/WalletSendModel.cs b/BTCPayServer/Models/WalletViewModels/WalletSendModel.cs
deleted file mode 100644
index ac2fe09..0000000
--- a/BTCPayServer/Models/WalletViewModels/WalletSendModel.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class WalletSendModel : IHasBackAndReturnUrl
- {
- public enum ThreeStateBool
- {
- Maybe,
- Yes,
- No
- }
- public class FeeRateOption
- {
- public TimeSpan Target { get; set; }
- public decimal FeeRate { get; set; }
- }
- public List<TransactionOutput> Outputs { get; set; } = new();
- public class TransactionOutput
- {
- [Display(Name = "Destination Address")]
- [Required]
- public string DestinationAddress { get; set; }
-
- [Display(Name = "Amount")]
- [Required]
- [Range(1E-08, 21E6)]
- public decimal? Amount { get; set; }
-
- [Display(Name = "Subtract fees from amount")]
- public bool SubtractFeesFromOutput { get; set; }
-
- public string PayoutId { get; set; }
-
- public string[] Labels { get; set; } = Array.Empty<string>();
- }
- public decimal CurrentBalance { get; set; }
- public decimal ImmatureBalance { get; set; }
-
- public string CryptoCode { get; set; }
-
- public List<FeeRateOption> RecommendedSatoshiPerByte { get; set; }
-
- [Display(Name = "Fee rate (sat/vB)")]
- [Required]
- public decimal? FeeSatoshiPerByte { get; set; }
-
- [Display(Name = "Don't create UTXO change")]
- public bool NoChange { get; set; }
- public decimal? Rate { get; set; }
- public int FiatDivisibility { get; set; }
- public int CryptoDivisibility { get; set; }
- public string Fiat { get; set; }
- public string RateError { get; set; }
- [Display(Name = "Always include non-witness UTXO if available")]
- public bool AlwaysIncludeNonWitnessUTXO { get; set; }
-
- public bool NBXSeedAvailable { get; set; }
- [Display(Name = "PayJoin BIP21")]
- public string PayJoinBIP21 { get; set; }
- public bool InputSelection { get; set; }
- public InputSelectionOption[] InputsAvailable { get; set; }
-
- [Display(Name = "UTXOs to spend from")]
- public IEnumerable<string> SelectedInputs { get; set; }
-
- public string BackUrl { get; set; }
- public string ReturnUrl { get; set; }
- public bool IsMultiSigOnServer { get; set; }
-
- [Display(Name = "Transaction Comment")]
- [MaxLength(200)]
- public string Comment { get; set; }
-
- public class InputSelectionOption
- {
- public IEnumerable<TransactionTagModel> Labels { get; set; }
- public string Comment { get; set; }
- public decimal Amount { get; set; }
- public string Outpoint { get; set; }
- public string Link { get; set; }
- public long Confirmations { get; set; }
- public DateTimeOffset? Timestamp { get; set; }
- }
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/WalletSendVaultModel.cs b/BTCPayServer/Models/WalletViewModels/WalletSendVaultModel.cs
deleted file mode 100644
index fd6c9ac..0000000
--- a/BTCPayServer/Models/WalletViewModels/WalletSendVaultModel.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class WalletSendVaultModel : IHasBackAndReturnUrl
- {
- public string WalletId { get; set; }
- public string BackUrl { get; set; }
- public string ReturnUrl { get; set; }
- public SigningContextModel SigningContext { get; set; } = new();
- }
-}
diff --git a/BTCPayServer/Models/WalletViewModels/WalletSigningOptionsModel.cs b/BTCPayServer/Models/WalletViewModels/WalletSigningOptionsModel.cs
deleted file mode 100644
index ab373a4..0000000
--- a/BTCPayServer/Models/WalletViewModels/WalletSigningOptionsModel.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace BTCPayServer.Models.WalletViewModels
-{
- public class WalletSigningOptionsModel : IHasBackAndReturnUrl
- {
- public SigningContextModel SigningContext { get; set; }
- public string BackUrl { get; set; }
- public string ReturnUrl { get; set; }
- }
-}
diff --git a/BTCPayServer/Plugins/Wallets/Controllers/UIWalletsController.PSBT.cs b/BTCPayServer/Plugins/Wallets/Controllers/UIWalletsController.PSBT.cs
index 3fb9aed..1bb7a9b 100644
--- a/BTCPayServer/Plugins/Wallets/Controllers/UIWalletsController.PSBT.cs
+++ b/BTCPayServer/Plugins/Wallets/Controllers/UIWalletsController.PSBT.cs
@@ -9,7 +9,7 @@ using BTCPayServer.Abstractions.Models;
using BTCPayServer.BIP78.Sender;
using BTCPayServer.Data;
using BTCPayServer.ModelBinders;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.Payments.PayJoin.Sender;
using BTCPayServer.Plugins.Wallets;
using BTCPayServer.Services;
diff --git a/BTCPayServer/Plugins/Wallets/Controllers/UIWalletsController.cs b/BTCPayServer/Plugins/Wallets/Controllers/UIWalletsController.cs
index 362e652..71a1b2b 100644
--- a/BTCPayServer/Plugins/Wallets/Controllers/UIWalletsController.cs
+++ b/BTCPayServer/Plugins/Wallets/Controllers/UIWalletsController.cs
@@ -19,7 +19,7 @@ using BTCPayServer.Data;
using BTCPayServer.HostedServices;
using BTCPayServer.ModelBinders;
using BTCPayServer.Models;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.Payments;
using BTCPayServer.Payments.Bitcoin;
using BTCPayServer.Payments.PayJoin;
@@ -45,7 +45,7 @@ using NBXplorer;
using NBXplorer.DerivationStrategy;
using NBXplorer.Models;
using Newtonsoft.Json;
-using static BTCPayServer.Models.WalletViewModels.WalletBumpFeeViewModel;
+using static BTCPayServer.Plugins.Wallets.Views.ViewModels.WalletBumpFeeViewModel;
using StoreData = BTCPayServer.Data.StoreData;
namespace BTCPayServer.Controllers
diff --git a/BTCPayServer/Plugins/Wallets/HotwalletSafe.cs b/BTCPayServer/Plugins/Wallets/HotwalletSafe.cs
index 1c36854..1ae0fe2 100644
--- a/BTCPayServer/Plugins/Wallets/HotwalletSafe.cs
+++ b/BTCPayServer/Plugins/Wallets/HotwalletSafe.cs
@@ -15,7 +15,6 @@ namespace BTCPayServer.Plugins.Wallets;
public class HotwalletSafe(
StoreRepository storeRepository,
IAuthorizationService authorizationService,
- ISettingsAccessor<PoliciesSettings> policies,
ExplorerClientProvider explorerClientProvider,
PaymentMethodHandlerDictionary handlers)
{
diff --git a/BTCPayServer/Plugins/Wallets/Views/UIWallets/ListWallets.cshtml b/BTCPayServer/Plugins/Wallets/Views/UIWallets/ListWallets.cshtml
index 121a1dc..cb5727b 100644
--- a/BTCPayServer/Plugins/Wallets/Views/UIWallets/ListWallets.cshtml
+++ b/BTCPayServer/Plugins/Wallets/Views/UIWallets/ListWallets.cshtml
@@ -1,5 +1,5 @@
@using BTCPayServer.Client
-@model BTCPayServer.Models.WalletViewModels.ListWalletsViewModel
+@model BTCPayServer.Plugins.Wallets.Views.ViewModels.ListWalletsViewModel
@{
ViewData.SetLayoutModel(new(nameof(WalletsNavPages.Index), StringLocalizer["Wallets"]));
}
diff --git a/BTCPayServer/Plugins/Wallets/Views/UIWallets/ReservedAddresses.cshtml b/BTCPayServer/Plugins/Wallets/Views/UIWallets/ReservedAddresses.cshtml
index 3f43175..4299d57 100644
--- a/BTCPayServer/Plugins/Wallets/Views/UIWallets/ReservedAddresses.cshtml
+++ b/BTCPayServer/Plugins/Wallets/Views/UIWallets/ReservedAddresses.cshtml
@@ -1,4 +1,3 @@
-@using BTCPayServer.Client
@using BTCPayServer.Components.LabelManager
@using BTCPayServer.Services
@model ReservedAddressesViewModel
diff --git a/BTCPayServer/Plugins/Wallets/Views/UIWallets/SigningContext.cshtml b/BTCPayServer/Plugins/Wallets/Views/UIWallets/SigningContext.cshtml
index 59422d7..7134835 100644
--- a/BTCPayServer/Plugins/Wallets/Views/UIWallets/SigningContext.cshtml
+++ b/BTCPayServer/Plugins/Wallets/Views/UIWallets/SigningContext.cshtml
@@ -1,4 +1,4 @@
-@model BTCPayServer.Models.WalletViewModels.SigningContextModel
+@model BTCPayServer.Plugins.Wallets.Views.ViewModels.SigningContextModel
@if (Model != null)
{
diff --git a/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletPSBT.cshtml b/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletPSBT.cshtml
index 47b0687..d8e7114 100644
--- a/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletPSBT.cshtml
+++ b/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletPSBT.cshtml
@@ -1,4 +1,3 @@
-@using BTCPayServer.Client
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
@model WalletPSBTViewModel
@{
diff --git a/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletPSBTDecoded.cshtml b/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletPSBTDecoded.cshtml
index a1f0579..c0ad291 100644
--- a/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletPSBTDecoded.cshtml
+++ b/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletPSBTDecoded.cshtml
@@ -1,5 +1,3 @@
-@using BTCPayServer.Controllers
-@using BTCPayServer.Client
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
@model WalletPSBTViewModel
@{
diff --git a/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletReceive.cshtml b/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletReceive.cshtml
index dab5dd5..a96239e 100644
--- a/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletReceive.cshtml
+++ b/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletReceive.cshtml
@@ -1,6 +1,5 @@
@inject BTCPayServerEnvironment env
@using BTCPayServer.Controllers
-@using BTCPayServer.Client
@using BTCPayServer.Services
@model BTCPayServer.Controllers.WalletReceiveViewModel
@{
diff --git a/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletSigningOptions.cshtml b/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletSigningOptions.cshtml
index c2c139a..9145d8e 100644
--- a/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletSigningOptions.cshtml
+++ b/BTCPayServer/Plugins/Wallets/Views/UIWallets/WalletSigningOptions.cshtml
@@ -1,4 +1,3 @@
-@using BTCPayServer.Client
@model WalletSigningOptionsModel
@inject BTCPayNetworkProvider BTCPayNetworkProvider
@{
diff --git a/BTCPayServer/Plugins/Wallets/Views/UIWallets/_ViewImports.cshtml b/BTCPayServer/Plugins/Wallets/Views/UIWallets/_ViewImports.cshtml
index c5c9083..131e7ae 100644
--- a/BTCPayServer/Plugins/Wallets/Views/UIWallets/_ViewImports.cshtml
+++ b/BTCPayServer/Plugins/Wallets/Views/UIWallets/_ViewImports.cshtml
@@ -1,4 +1,4 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Plugins.Wallets
@using BTCPayServer.Views.Wallets
-@using BTCPayServer.Models.WalletViewModels
+@using BTCPayServer.Plugins.Wallets.Views.ViewModels
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/ListTransactionsViewModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/ListTransactionsViewModel.cs
new file mode 100644
index 0000000..d79ae5c
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/ListTransactionsViewModel.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using BTCPayServer.Data;
+using BTCPayServer.Models;
+using BTCPayServer.Services.Invoices;
+using BTCPayServer.Services.Wallets;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class ListTransactionsViewModel : BasePagingViewModel
+ {
+ public class TransactionViewModel
+ {
+ public DateTimeOffset Timestamp { get; set; }
+ public bool IsConfirmed { get; set; }
+ public bool CanBumpFee { get; set; }
+ public string Comment { get; set; }
+ public string Id { get; set; }
+ public string Link { get; set; }
+ public bool Positive { get; set; }
+ public string Balance { get; set; }
+ public HashSet<TransactionTagModel> Tags { get; set; } = new();
+ public string Rate { get; set; }
+ public List<string> Rates { get; set; } = new();
+ public RateBook WalletRateBook { get; set; }
+ public RateBook InvoiceRateBook { get; set; }
+ public string InvoiceId { get; set; }
+ public TransactionHistoryLine HistoryLine { get; set; }
+ }
+ public HashSet<(string Text, string Color, string TextColor, long UsageCount)> Labels { get; set; } = new();
+ public List<(string Text, string Color, string TextColor, long UsageCount)> PopularLabels { get; set; } = new();
+ public List<TransactionViewModel> Transactions { get; set; } = new();
+ public override int CurrentPageCount => Transactions.Count;
+ public string CryptoCode { get; set; }
+ public PendingTransaction[] PendingTransactions { get; set; }
+ public List<string> Rates { get; set; }
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/ListWalletsViewModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/ListWalletsViewModel.cs
new file mode 100644
index 0000000..cef1ab2
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/ListWalletsViewModel.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using NBitcoin;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class ListWalletsViewModel
+ {
+ public class WalletViewModel
+ {
+ public string StoreName { get; set; }
+ public string StoreId { get; set; }
+ public string CryptoCode { get; set; }
+ public string Balance { get; set; }
+ public WalletId Id { get; set; }
+ }
+
+ public Dictionary<BTCPayNetwork, IMoney> BalanceForCryptoCode { get; set; } = new Dictionary<BTCPayNetwork, IMoney>();
+ public List<WalletViewModel> Wallets { get; set; } = new List<WalletViewModel>();
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/PayoutsModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/PayoutsModel.cs
new file mode 100644
index 0000000..3135315
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/PayoutsModel.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using BTCPayServer.Client.Models;
+using BTCPayServer.Models;
+using BTCPayServer.Payouts;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class PayoutsModel : BasePagingViewModel
+ {
+ public string PullPaymentId { get; set; }
+ public string Command { get; set; }
+ public Dictionary<PayoutState, int> PayoutStateCount { get; set; }
+ public Dictionary<string, int> PayoutMethodCount { get; set; }
+ public string PayoutMethodId { get; set; }
+
+ public List<PayoutModel> Payouts { get; set; }
+ public override int CurrentPageCount => Payouts.Count;
+ public IEnumerable<PayoutMethodId> PayoutMethods { get; set; }
+ public PayoutState PayoutState { get; set; }
+ public string PullPaymentName { get; set; }
+ public bool HasPayoutProcessor { get; set; }
+
+ public class PayoutModel
+ {
+ public string PayoutId { get; set; }
+ public bool Selected { get; set; }
+ public DateTimeOffset Date { get; set; }
+ public string PullPaymentId { get; set; }
+ public string Source { get; set; }
+ public string SourceLink { get; set; }
+ public string Destination { get; set; }
+ public string Amount { get; set; }
+ public string ProofLink { get; set; }
+ }
+
+ public string[] GetSelectedPayouts(PayoutState state)
+ {
+ return Payouts.Where(model => model.Selected).Select(model => model.PayoutId)
+ .ToArray();
+ }
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/PullPaymentsModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/PullPaymentsModel.cs
new file mode 100644
index 0000000..f4939c3
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/PullPaymentsModel.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using BTCPayServer.Client.Models;
+using BTCPayServer.Data;
+using BTCPayServer.Models;
+using Microsoft.AspNetCore.Mvc.Rendering;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class PullPaymentsModel : BasePagingViewModel
+ {
+ public class PullPaymentModel
+ {
+ public class ProgressModel
+ {
+ public int CompletedPercent { get; set; }
+ public int AwaitingPercent { get; set; }
+ public string CompletedFormatted { get; set; }
+ public string AwaitingFormatted { get; set; }
+ public string LimitFormatted { get; set; }
+ public string EndIn { get; set; }
+ public decimal Awaiting { get; set; }
+ public decimal Completed { get; set; }
+ public decimal Limit { get; set; }
+ }
+ public string Id { get; set; }
+ public string Name { get; set; }
+ public string ProgressText { get; set; }
+ public ProgressModel Progress { get; set; }
+ public DateTimeOffset StartDate { get; set; }
+ public DateTimeOffset? EndDate { get; set; }
+ public bool AutoApproveClaims { get; set; }
+ public bool Archived { get; set; } = false;
+ }
+
+ public List<PullPaymentModel> PullPayments { get; set; } = new List<PullPaymentModel>();
+ public override int CurrentPageCount => PullPayments.Count;
+ public PullPaymentState ActiveState { get; set; } = PullPaymentState.Active;
+ }
+
+ public class NewPullPaymentModel
+ {
+ [MaxLength(30)]
+ [Display(Name = "Name")]
+ public string Name { get; set; }
+
+ [Display(Name = "Description")]
+ public string Description { get; set; }
+
+ [Required]
+ [Display(Name = "Amount")]
+ public decimal Amount { get; set; }
+
+ [Required]
+ [ReadOnly(true)]
+ [Display(Name = "Currency")]
+ public string Currency { get; set; }
+
+ [Display(Name = "Payout Methods")]
+ public IEnumerable<string> PayoutMethods { get; set; }
+ public IEnumerable<SelectListItem> PayoutMethodsItem { get; set; }
+ [Display(Name = "Minimum acceptable expiration time for BOLT11 for refunds")]
+ [Range(0, 365 * 10)]
+ public long BOLT11Expiration { get; set; } = 30;
+ [Display(Name = "Automatically approve claims")]
+ public bool AutoApproveClaims { get; set; }
+ }
+
+ public class UpdatePullPaymentModel
+ {
+ [Display(Name = "Id")]
+ public string Id { get; set; }
+
+ public UpdatePullPaymentModel()
+ {
+ }
+
+ public UpdatePullPaymentModel(Data.PullPaymentData data)
+ {
+ if (data == null)
+ {
+ return;
+ }
+
+ Id = data.Id;
+ var blob = data.GetBlob();
+ Name = blob.Name;
+ Description = blob.Description;
+ }
+
+ [MaxLength(30)]
+ [Display(Name = "Name")]
+ public string Name { get; set; }
+
+ [Display(Name = "Memo")]
+ public string Description { get; set; }
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/RescanWalletModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/RescanWalletModel.cs
new file mode 100644
index 0000000..7734f43
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/RescanWalletModel.cs
@@ -0,0 +1,31 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using NBXplorer.Models;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class RescanWalletModel
+ {
+ public bool IsServerAdmin { get; set; }
+ public bool IsSupportedByCurrency { get; set; }
+ public bool IsFullySync { get; set; }
+ public bool Ok => IsServerAdmin && IsSupportedByCurrency && IsFullySync;
+
+ [Range(1000, 10_000)]
+ [DisplayName("Batch size")]
+ public int BatchSize { get; set; } = 3000;
+ [Range(0, 10_000_000)]
+ [DisplayName("Starting index")]
+ public int StartingIndex { get; set; } = 0;
+
+ [Range(100, 100000)]
+ [DisplayName("Gap limit")]
+ public int GapLimit { get; set; } = 10000;
+
+ public int? Progress { get; set; }
+ public string PreviousError { get; set; }
+ public ScanUTXOProgress LastSuccess { get; internal set; }
+ public string TimeOfScan { get; internal set; }
+ public string RemainingTime { get; internal set; }
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/ReservedAddressesViewModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/ReservedAddressesViewModel.cs
new file mode 100644
index 0000000..b1c241b
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/ReservedAddressesViewModel.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels;
+
+public class ReservedAddressesViewModel
+{
+ public string WalletId { get; set; }
+ public string CryptoCode { get; set; }
+ public List<ReservedAddress> Addresses { get; set; }
+}
+
+public class ReservedAddress
+{
+ public string Address { get; set; }
+ public List<TransactionTagModel> Labels { get; set; } = new();
+ public DateTimeOffset? ReservedAt { get; set; }
+}
+
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/SignWithSeedViewModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/SignWithSeedViewModel.cs
new file mode 100644
index 0000000..5741f79
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/SignWithSeedViewModel.cs
@@ -0,0 +1,49 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using BTCPayServer.Models;
+using NBitcoin;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class SignWithSeedViewModel : IHasBackAndReturnUrl
+ {
+ public SigningContextModel SigningContext { get; set; } = new SigningContextModel();
+
+ [Required]
+ [Display(Name = "BIP39 Seed (12/24 word mnemonic phrase) or HD private key (xprv...)")]
+ public string SeedOrKey { get; set; }
+
+ public bool UseHotWallet { get; set; }
+
+ [Display(Name = "Optional seed passphrase")]
+ public string Passphrase { get; set; }
+
+ public string BackUrl { get; set; }
+ public string ReturnUrl { get; set; }
+
+ public ExtKey GetExtKey(Network network)
+ {
+ ExtKey extKey = null;
+ try
+ {
+ var mnemonic = new Mnemonic(SeedOrKey);
+ extKey = mnemonic.DeriveExtKey(Passphrase);
+ }
+ catch (Exception)
+ {
+ }
+
+ if (extKey == null)
+ {
+ try
+ {
+ extKey = ExtKey.Parse(SeedOrKey, network);
+ }
+ catch (Exception)
+ {
+ }
+ }
+ return extKey;
+ }
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/SigningContextModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/SigningContextModel.cs
new file mode 100644
index 0000000..53dee6c
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/SigningContextModel.cs
@@ -0,0 +1,25 @@
+using NBitcoin;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class SigningContextModel
+ {
+ public SigningContextModel()
+ {
+
+ }
+ public SigningContextModel(PSBT psbt)
+ {
+ PSBT = psbt.ToBase64();
+ }
+ public string PSBT { get; set; }
+ public string OriginalPSBT { get; set; }
+ public string PayJoinBIP21 { get; set; }
+ public bool? EnforceLowR { get; set; }
+ public string ChangeAddress { get; set; }
+
+ public string PendingTransactionId { get; set; }
+ public long BalanceChangeFromReplacement { get; set; }
+ public string Comment { get; set; }
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/TransactionTagModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/TransactionTagModel.cs
new file mode 100644
index 0000000..99c7ba0
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/TransactionTagModel.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class TransactionTagModel
+ {
+ public string Text { get; internal set; }
+ public string Color { get; internal set; }
+ public string TextColor { get; internal set; }
+ public string Link { get; internal set; }
+ public string Tooltip { get; internal set; } = String.Empty;
+
+ public override bool Equals(object obj)
+ {
+ TransactionTagModel item = obj as TransactionTagModel;
+ if (item == null)
+ return false;
+ return Text.Equals(item.Text, StringComparison.OrdinalIgnoreCase);
+ }
+
+ public static bool operator ==(TransactionTagModel a, TransactionTagModel b)
+ {
+ if (System.Object.ReferenceEquals(a, b))
+ return true;
+ if (((object)a == null) || ((object)b == null))
+ return false;
+ return a.Text == b.Text;
+ }
+
+ public static bool operator !=(TransactionTagModel a, TransactionTagModel b)
+ {
+ return !(a == b);
+ }
+
+ public override int GetHashCode()
+ {
+ return Text.GetHashCode(StringComparison.OrdinalIgnoreCase);
+ }
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletBumpFeeViewModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletBumpFeeViewModel.cs
new file mode 100644
index 0000000..30f0afb
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletBumpFeeViewModel.cs
@@ -0,0 +1,92 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using NBitcoin;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class WalletBumpFeeViewModel
+ {
+ public string ReturnUrl { get; set; }
+ [Display(Name = "Transaction Id")]
+ public uint256 TransactionId { get; set; }
+ public List<SelectListItem> BumpFeeMethods { get; set; } = new();
+ public string[] Outpoints { get; set; }
+ public string[] TransactionHashes { get; set; }
+ public List<WalletSendModel.FeeRateOption> RecommendedSatoshiPerByte { get; set; }
+ [Display]
+ public decimal? FeeSatoshiPerByte { get; set; }
+ [Display]
+ public decimal? CurrentFeeSatoshiPerByte { get; set; }
+ public bool IsMultiSigOnServer { get; set; }
+ [Display(Name = "Fee bump method")]
+ public string BumpMethod { get; set; }
+
+ public string Command { get; set; }
+#nullable enable
+ public record BumpTarget(HashSet<OutPoint> Outpoints, HashSet<uint256> TxIds)
+ {
+
+ public uint256? GetSingleTransactionId()
+ => this switch
+ {
+ { TxIds: { Count: 1 } ids, Outpoints: { Count: 0 } } => ids.First(),
+ { TxIds: { Count: 0 }, Outpoints: { Count: 1 } outpoints } => outpoints.First().Hash,
+ _ => null
+ };
+ public HashSet<uint256> GetTransactionIds()
+ => (TxIds.Concat(Outpoints.Select(o => o.Hash))).ToHashSet();
+
+ public BumpTarget Filter(HashSet<uint256> elligibleTxs)
+ => new BumpTarget(
+ Outpoints.Where(o => elligibleTxs.Contains(o.Hash)).ToHashSet(),
+ TxIds.Where(t => elligibleTxs.Contains(t)).ToHashSet());
+
+ public List<OutPoint> GetMatchedOutpoints(IEnumerable<OutPoint> outpoints)
+ {
+ List<OutPoint> matches = new();
+ HashSet<uint256> bumpedTxs = new();
+ foreach (var outpoint in outpoints)
+ {
+ if (Outpoints.Contains(outpoint))
+ {
+ matches.Add(outpoint);
+ bumpedTxs.Add(outpoint.Hash);
+ }
+ else if (TxIds.Contains(outpoint.Hash) && bumpedTxs.Add(outpoint.Hash))
+ {
+ matches.Add(outpoint);
+ }
+ }
+ return matches;
+ }
+ }
+
+ public BumpTarget GetBumpTarget()
+ {
+ if (TransactionId is not null)
+ return new BumpTarget(new(), new([TransactionId]));
+ HashSet<OutPoint> outpoints = new();
+ HashSet<uint256> txids = new();
+ foreach (var o in Outpoints ?? [])
+ {
+ try
+ {
+ outpoints.Add(OutPoint.Parse(o));
+ }
+ catch { }
+ }
+ foreach (var o in TransactionHashes ?? [])
+ {
+ try
+ {
+ txids.Add(uint256.Parse(o));
+ }
+ catch { }
+ }
+ return new BumpTarget(outpoints, txids);
+ }
+#nullable restore
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletLabelsModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletLabelsModel.cs
new file mode 100644
index 0000000..878eeeb
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletLabelsModel.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels;
+
+public class WalletLabelsModel
+{
+ public WalletId WalletId { get; set; }
+ public IEnumerable<WalletLabelModel> Labels { get; set; }
+}
+
+public class WalletLabelModel
+{
+ public string Label { get; set; }
+ public string Color { get; set; }
+ public string TextColor { get; set; }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletModel.cs
new file mode 100644
index 0000000..55318ea
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletModel.cs
@@ -0,0 +1,19 @@
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class WalletModel
+ {
+ public string ServerUrl { get; set; }
+ public string CryptoCurrency
+ {
+ get;
+ set;
+ }
+ public string DefaultAddress { get; set; }
+ public string DefaultAmount { get; set; }
+
+ public decimal? Rate { get; set; }
+ public int Divisibility { get; set; }
+ public string Fiat { get; set; }
+ public string RateError { get; set; }
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletPSBTCombineViewModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletPSBTCombineViewModel.cs
new file mode 100644
index 0000000..b9762a6
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletPSBTCombineViewModel.cs
@@ -0,0 +1,76 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Threading.Tasks;
+using BTCPayServer.Models;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using NBitcoin;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class WalletPSBTCombineViewModel : IHasBackAndReturnUrl
+ {
+ public string OtherPSBT { get; set; }
+ [Display(Name = "PSBT to combine with…")]
+ public string PSBT { get; set; }
+ [Display(Name = "Upload PSBT from file…")]
+ public IFormFile UploadedPSBTFile { get; set; }
+
+ public string BackUrl { get; set; }
+ public string ReturnUrl { get; set; }
+
+ public PSBT GetSourcePSBT(Network network, ModelStateDictionary modelState)
+ {
+ if (network is null)
+ return null;
+ if (!string.IsNullOrEmpty(OtherPSBT))
+ {
+ try
+ {
+ return NBitcoin.PSBT.Parse(OtherPSBT, network);
+ }
+ catch (Exception ex)
+ { modelState.AddModelError(nameof(OtherPSBT), ex.Message); }
+ }
+ return null;
+ }
+ public async Task<PSBT> GetPSBT(Network network, ModelStateDictionary modelState)
+ {
+ if (UploadedPSBTFile != null)
+ {
+ if (UploadedPSBTFile.Length > 500 * 1024)
+ return null;
+ byte[] bytes = new byte[UploadedPSBTFile.Length];
+ using (var stream = UploadedPSBTFile.OpenReadStream())
+ {
+ await stream.ReadAsync(bytes, 0, (int)UploadedPSBTFile.Length);
+ }
+ try
+ {
+ if (network is null)
+ return null;
+ return NBitcoin.PSBT.Load(bytes, network);
+ }
+ catch (FormatException ex)
+ {
+ modelState.AddModelError(nameof(UploadedPSBTFile), ex.Message);
+ return null;
+ }
+ }
+ if (!string.IsNullOrEmpty(PSBT))
+ {
+ try
+ {
+ if (network is null)
+ return null;
+ return NBitcoin.PSBT.Parse(PSBT, network);
+ }
+ catch (FormatException ex)
+ {
+ modelState.AddModelError(nameof(UploadedPSBTFile), ex.Message);
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletPSBTReadyViewModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletPSBTReadyViewModel.cs
new file mode 100644
index 0000000..cd108c5
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletPSBTReadyViewModel.cs
@@ -0,0 +1,57 @@
+using System.Collections.Generic;
+using System.Linq;
+using BTCPayServer.Models;
+using NBitcoin;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class WalletPSBTReadyViewModel : IHasBackAndReturnUrl
+ {
+ public SigningContextModel SigningContext { get; set; } = new SigningContextModel();
+ public string SigningKey { get; set; }
+ public bool UseHotWallet { get; set; }
+ public string SigningKeyPath { get; set; }
+
+ public class DestinationViewModel
+ {
+ public bool Positive { get; set; }
+ public string Destination { get; set; }
+ public StringAmounts Balance { get; set; }
+ public IEnumerable<TransactionTagModel> Labels { get; set; } = new List<TransactionTagModel>();
+ }
+
+ public class InputViewModel
+ {
+ public int Index { get; set; }
+ public string Error { get; set; }
+ public bool Positive { get; set; }
+ public StringAmounts BalanceChange { get; set; }
+ public IEnumerable<TransactionTagModel> Labels { get; set; } = new List<TransactionTagModel>();
+ }
+ public class AmountViewModel
+ {
+ public bool Positive { get; set; }
+ public StringAmounts BalanceChange { get; set; }
+ }
+ public AmountViewModel ReplacementBalanceChange { get; set; }
+ public bool HasErrors => Inputs.Count == 0 || Inputs.Any(i => !string.IsNullOrEmpty(i.Error));
+ public StringAmounts BalanceChange { get; set; }
+ public bool CanCalculateBalance { get; set; }
+ public bool Positive { get; set; }
+ public List<DestinationViewModel> Destinations { get; set; } = new List<DestinationViewModel>();
+ public List<InputViewModel> Inputs { get; set; } = new List<InputViewModel>();
+ public string FeeRate { get; set; }
+ public string BackUrl { get; set; }
+ public string ReturnUrl { get; set; }
+
+ internal void SetErrors(IList<PSBTError> errors)
+ {
+ foreach (var err in errors)
+ {
+ Inputs[(int)err.InputIndex].Error = err.Message;
+ }
+ }
+
+ public record StringAmounts(string CryptoAmount, string FiatAmount);
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletPSBTViewModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletPSBTViewModel.cs
new file mode 100644
index 0000000..5a71b52
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletPSBTViewModel.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using NBitcoin;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class WalletPSBTViewModel : WalletPSBTReadyViewModel
+ {
+ public string CryptoCode { get; set; }
+ public string Decoded { get; set; }
+ string _FileName;
+ public string PSBTHex { get; set; }
+ public bool NBXSeedAvailable { get; set; }
+
+ public string FileName
+ {
+ get
+ {
+ return string.IsNullOrEmpty(_FileName) ? "psbt-export.psbt" : _FileName;
+ }
+ set
+ {
+ _FileName = value;
+ }
+ }
+ [Display(Name = "PSBT content")]
+ public string PSBT { get; set; }
+ public List<string> Errors { get; set; } = new List<string>();
+
+ [Display(Name = "Upload PSBT from file…")]
+ public IFormFile UploadedPSBTFile { get; set; }
+
+
+ #nullable enable
+ public async Task<PSBT?> GetPSBT(Network? network, ModelStateDictionary modelState)
+ {
+ var psbt = await GetPSBTCore(network, modelState);
+ if (psbt != null)
+ {
+ Decoded = psbt.ToString();
+ PSBTHex = psbt.ToHex();
+ PSBT = psbt.ToBase64();
+ if (SigningContext is null)
+ SigningContext = new SigningContextModel(psbt);
+ else
+ SigningContext.PSBT = psbt.ToBase64();
+ }
+ return psbt;
+ }
+ public bool InvalidPSBT { get; set; }
+
+ async Task<PSBT?> GetPSBTCore(Network? network, ModelStateDictionary modelState)
+ {
+ if (UploadedPSBTFile != null)
+ {
+ if (UploadedPSBTFile.Length > 500 * 1024)
+ return null;
+
+ try
+ {
+ byte[] bytes = new byte[UploadedPSBTFile.Length];
+ await using (var stream = UploadedPSBTFile.OpenReadStream())
+ {
+ await stream.ReadAsync(bytes, 0, (int)UploadedPSBTFile.Length);
+ }
+ if (network is null)
+ return null;
+ return NBitcoin.PSBT.Load(bytes, network);
+ }
+ catch (Exception ex)
+ {
+ using var stream = new StreamReader(UploadedPSBTFile.OpenReadStream());
+ PSBT = await stream.ReadToEndAsync();
+ modelState.Remove(nameof(PSBT));
+ modelState.AddModelError(nameof(PSBT), ex.Message);
+ InvalidPSBT = true;
+ }
+ }
+ if (SigningContext != null && !string.IsNullOrEmpty(SigningContext.PSBT))
+ {
+ PSBT = SigningContext.PSBT;
+ modelState.Remove(nameof(PSBT));
+ InvalidPSBT = false;
+ }
+ if (!string.IsNullOrEmpty(PSBT))
+ {
+ try
+ {
+ InvalidPSBT = false;
+ if (network is null)
+ return null;
+ return NBitcoin.PSBT.Parse(PSBT, network);
+ }
+ catch (Exception ex) when (!InvalidPSBT)
+ {
+ modelState.AddModelError(nameof(PSBT), ex.Message);
+ InvalidPSBT = true;
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletSendModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletSendModel.cs
new file mode 100644
index 0000000..440013e
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletSendModel.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using BTCPayServer.Models;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class WalletSendModel : IHasBackAndReturnUrl
+ {
+ public enum ThreeStateBool
+ {
+ Maybe,
+ Yes,
+ No
+ }
+ public class FeeRateOption
+ {
+ public TimeSpan Target { get; set; }
+ public decimal FeeRate { get; set; }
+ }
+ public List<TransactionOutput> Outputs { get; set; } = new();
+ public class TransactionOutput
+ {
+ [Display(Name = "Destination Address")]
+ [Required]
+ public string DestinationAddress { get; set; }
+
+ [Display(Name = "Amount")]
+ [Required]
+ [Range(1E-08, 21E6)]
+ public decimal? Amount { get; set; }
+
+ [Display(Name = "Subtract fees from amount")]
+ public bool SubtractFeesFromOutput { get; set; }
+
+ public string PayoutId { get; set; }
+
+ public string[] Labels { get; set; } = Array.Empty<string>();
+ }
+ public decimal CurrentBalance { get; set; }
+ public decimal ImmatureBalance { get; set; }
+
+ public string CryptoCode { get; set; }
+
+ public List<FeeRateOption> RecommendedSatoshiPerByte { get; set; }
+
+ [Display(Name = "Fee rate (sat/vB)")]
+ [Required]
+ public decimal? FeeSatoshiPerByte { get; set; }
+
+ [Display(Name = "Don't create UTXO change")]
+ public bool NoChange { get; set; }
+ public decimal? Rate { get; set; }
+ public int FiatDivisibility { get; set; }
+ public int CryptoDivisibility { get; set; }
+ public string Fiat { get; set; }
+ public string RateError { get; set; }
+ [Display(Name = "Always include non-witness UTXO if available")]
+ public bool AlwaysIncludeNonWitnessUTXO { get; set; }
+
+ public bool NBXSeedAvailable { get; set; }
+ [Display(Name = "PayJoin BIP21")]
+ public string PayJoinBIP21 { get; set; }
+ public bool InputSelection { get; set; }
+ public InputSelectionOption[] InputsAvailable { get; set; }
+
+ [Display(Name = "UTXOs to spend from")]
+ public IEnumerable<string> SelectedInputs { get; set; }
+
+ public string BackUrl { get; set; }
+ public string ReturnUrl { get; set; }
+ public bool IsMultiSigOnServer { get; set; }
+
+ [Display(Name = "Transaction Comment")]
+ [MaxLength(200)]
+ public string Comment { get; set; }
+
+ public class InputSelectionOption
+ {
+ public IEnumerable<TransactionTagModel> Labels { get; set; }
+ public string Comment { get; set; }
+ public decimal Amount { get; set; }
+ public string Outpoint { get; set; }
+ public string Link { get; set; }
+ public long Confirmations { get; set; }
+ public DateTimeOffset? Timestamp { get; set; }
+ }
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletSendVaultModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletSendVaultModel.cs
new file mode 100644
index 0000000..46fdc2b
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletSendVaultModel.cs
@@ -0,0 +1,12 @@
+using BTCPayServer.Models;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class WalletSendVaultModel : IHasBackAndReturnUrl
+ {
+ public string WalletId { get; set; }
+ public string BackUrl { get; set; }
+ public string ReturnUrl { get; set; }
+ public SigningContextModel SigningContext { get; set; } = new();
+ }
+}
diff --git a/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletSigningOptionsModel.cs b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletSigningOptionsModel.cs
new file mode 100644
index 0000000..38beef0
--- /dev/null
+++ b/BTCPayServer/Plugins/Wallets/Views/ViewModels/WalletSigningOptionsModel.cs
@@ -0,0 +1,11 @@
+using BTCPayServer.Models;
+
+namespace BTCPayServer.Plugins.Wallets.Views.ViewModels
+{
+ public class WalletSigningOptionsModel : IHasBackAndReturnUrl
+ {
+ public SigningContextModel SigningContext { get; set; }
+ public string BackUrl { get; set; }
+ public string ReturnUrl { get; set; }
+ }
+}
diff --git a/BTCPayServer/Services/Labels/LabelService.cs b/BTCPayServer/Services/Labels/LabelService.cs
index 27503d7..b34c05b 100644
--- a/BTCPayServer/Services/Labels/LabelService.cs
+++ b/BTCPayServer/Services/Labels/LabelService.cs
@@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
diff --git a/BTCPayServer/Services/WalletRepository.cs b/BTCPayServer/Services/WalletRepository.cs
index 50df4c5..bbc5364 100644
--- a/BTCPayServer/Services/WalletRepository.cs
+++ b/BTCPayServer/Services/WalletRepository.cs
@@ -7,7 +7,7 @@ using System.Linq.Expressions;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Data;
-using BTCPayServer.Models.WalletViewModels;
+using BTCPayServer.Plugins.Wallets.Views.ViewModels;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Wallets;
using Dapper;
@@ -761,7 +761,7 @@ namespace BTCPayServer.Services
ArgumentNullException.ThrowIfNull(id);
oldLabel = oldLabel.Trim();
newLabel = newLabel.Trim().Truncate(MaxLabelSize);
-
+
if (oldLabel == newLabel)
return true;
@@ -771,14 +771,14 @@ namespace BTCPayServer.Services
await using var ctx = _ContextFactory.CreateContext();
var connection = ctx.Database.GetDbConnection();
-
+
// Update all links from old label to new label
var updated = await connection.ExecuteAsync(
"""
- UPDATE "WalletObjectLinks"
- SET "AId" = @NewLabel
- WHERE "WalletId" = @WalletId
- AND "AType" = @LabelType
+ UPDATE "WalletObjectLinks"
+ SET "AId" = @NewLabel
+ WHERE "WalletId" = @WalletId
+ AND "AType" = @LabelType
AND "AId" = @OldLabel
""",
new { WalletId = id.ToString(), LabelType = WalletObjectData.Types.Label, OldLabel = oldLabel, NewLabel = newLabel });
diff --git a/BTCPayServer/Views/UIAccount/_ViewImports.cshtml b/BTCPayServer/Views/UIAccount/_ViewImports.cshtml
index 9d7e22d..5dd2fdc 100644
--- a/BTCPayServer/Views/UIAccount/_ViewImports.cshtml
+++ b/BTCPayServer/Views/UIAccount/_ViewImports.cshtml
@@ -1,2 +1,2 @@
@using BTCPayServer.Views.Wallets
-@using BTCPayServer.Models.WalletViewModels
+@using BTCPayServer.Plugins.Wallets.Views.ViewModels
diff --git a/BTCPayServer/Views/UIPullPayment/EditPullPayment.cshtml b/BTCPayServer/Views/UIPullPayment/EditPullPayment.cshtml
index a88e085..296ba00 100644
--- a/BTCPayServer/Views/UIPullPayment/EditPullPayment.cshtml
+++ b/BTCPayServer/Views/UIPullPayment/EditPullPayment.cshtml
@@ -1,5 +1,5 @@
@using BTCPayServer.Views.Stores
-@model BTCPayServer.Models.WalletViewModels.UpdatePullPaymentModel
+@model BTCPayServer.Plugins.Wallets.Views.ViewModels.UpdatePullPaymentModel
@{
var storeId = Context.GetStoreData().Id;
ViewData.SetLayoutModel(new(nameof(StoreNavPages.Create), StringLocalizer["Edit Pull Payment"]));
diff --git a/BTCPayServer/Views/UIStorePullPayments/NewPullPayment.cshtml b/BTCPayServer/Views/UIStorePullPayments/NewPullPayment.cshtml
index 1f99427..5e661c6 100644
--- a/BTCPayServer/Views/UIStorePullPayments/NewPullPayment.cshtml
+++ b/BTCPayServer/Views/UIStorePullPayments/NewPullPayment.cshtml
@@ -1,6 +1,6 @@
@using BTCPayServer.Client
@using BTCPayServer.Views.Stores
-@model BTCPayServer.Models.WalletViewModels.NewPullPaymentModel
+@model BTCPayServer.Plugins.Wallets.Views.ViewModels.NewPullPaymentModel
@{
var storeId = Context.GetStoreData().Id;
ViewData.SetLayoutModel(new(nameof(StoreNavPages.PullPayments), StringLocalizer["Create Pull Payment"]));
diff --git a/BTCPayServer/Views/UIStorePullPayments/Payouts.cshtml b/BTCPayServer/Views/UIStorePullPayments/Payouts.cshtml
index 5e52456..ff0769d 100644
--- a/BTCPayServer/Views/UIStorePullPayments/Payouts.cshtml
+++ b/BTCPayServer/Views/UIStorePullPayments/Payouts.cshtml
@@ -2,7 +2,7 @@
@using BTCPayServer.Payouts
@using BTCPayServer.Views.Stores
@using BTCPayServer.Client
-@model BTCPayServer.Models.WalletViewModels.PayoutsModel
+@model BTCPayServer.Plugins.Wallets.Views.ViewModels.PayoutsModel
@inject PayoutMethodHandlerDictionary PayoutHandlers;
@{
diff --git a/BTCPayServer/Views/UIStorePullPayments/PullPayments.cshtml b/BTCPayServer/Views/UIStorePullPayments/PullPayments.cshtml
index 92af46a..b3bd3eb 100644
--- a/BTCPayServer/Views/UIStorePullPayments/PullPayments.cshtml
+++ b/BTCPayServer/Views/UIStorePullPayments/PullPayments.cshtml
@@ -2,7 +2,7 @@
@using BTCPayServer.Client
@using BTCPayServer.Client.Models
@using ExchangeSharp
-@model BTCPayServer.Models.WalletViewModels.PullPaymentsModel
+@model BTCPayServer.Plugins.Wallets.Views.ViewModels.PullPaymentsModel
@{
var storeId = Context.GetStoreData().Id;
var nextStartDateSortOrder = (string)ViewData["NextStartSortOrder"];
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.