Compare commits

..

2 Commits

Author SHA1 Message Date
bffa0e7fe5 bump 2020-12-03 23:29:05 +09:00
6d2d917bf1 Fix sync not showing
fixes #2092
2020-12-03 23:27:25 +09:00
400 changed files with 22684 additions and 31579 deletions

View File

@ -1,63 +1,38 @@
---
name: "\U0001F41B Bug report"
about: Report a bug or a technical issue
name: Bug report
about: File a bug report
title: ''
labels: ''
assignees: ''
---
<!--
Thank you for reporting a technical issue.
This issue tracker is only for bug reports and problems.
For general questions please read our documentation docs.btcpayserver.org. You can ask technical questions in discussions https://github.com/btcpayserver/btcpayserver/discussions and general support on our community chat chat.btcpayserver.org
Please fill in as much of the template below as you're able.
-->
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce the bug**
Steps to reproduce the reported bug:
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
<!--
A clear and concise description of what you expected to happen.
-->
**Screenshots**
<!--
If applicable, add screenshots to help explain your problem.
-->
**Your BTCPay Environment (please complete the following information):**
- BTCPay Server Version: <!--[available in the right bottom corner of footer] -->
- Deployment Method: <!--[e.g. Docker, Manual, Third-Party-host]-->
- Browser: <!--[e.g. Chrome, Safari]-->
- BTCPay Server Version: [available in the right bottom corner of footer]
- Deployment Method: [e.g. Docker, Manual, Third-Party-host]
- Browser: [e.g. Chrome, Safari]
**Logs (if applicable)**
<!--
Basic logs can be found in Server Settings > Logs.
More logs https://docs.btcpayserver.org/Troubleshooting/#2-looking-through-the-logs
-->
Basic logs can be found in Server Settings > Logs. More logs https://docs.btcpayserver.org/Troubleshooting/#2-looking-through-the-logs
**Setup Parameters**
<!--
If you're reporting a deployment issue run `. btcpay-setup.sh -i` and paste the setup parameters here with your private information removed or obscured.
-->
**Additional context**
<!--
Add any other context about the problem here.
-->

View File

@ -1,11 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: 🚀 Discussions
url: https://github.com/btcpayserver/btcpayserver/discussions
about: Technical discussions, questions and feature requests
- name: 📝 Official Documentation
url: https://docs.btcpayserver.org
about: Check our documentation for answers to common questions
- name: 💬 Community Support Chat
contact_links:
- name: Community Support Chat
url: https://chat.btcpayserver.org/
about: Ask general questions and get community support in real-time
about: Ask general questions and get community support in real-time.

View File

@ -0,0 +1,23 @@
---
name: Feature request
about: Suggest a new feature or enhancement
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Sketch/Image/Wireframe/Mockup**
If applicable provide examples, wireframes, sketches or images to better explain your idea.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -0,0 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Build and pack plugins" type="CompoundRunConfigurationType">
<toRun name="Pack Test Plugin" type="DotNetProject" />
<method v="2" />
</configuration>
</component>

View File

@ -1,12 +0,0 @@
namespace BTCPayServer.Configuration
{
public class DataDirectories
{
public string DataDir { get; set; }
public string PluginDir { get; set; }
public string TempStorageDir { get; set; }
public string StorageDir { get; set; }
}
}

View File

@ -3,7 +3,6 @@ using BTCPayServer.Abstractions.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.Options;
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Operations;
@ -11,10 +10,10 @@ namespace BTCPayServer.Abstractions.Contracts
{
public abstract class BaseDbContextFactory<T> where T: DbContext
{
private readonly IOptions<DatabaseOptions> _options;
private readonly DatabaseOptions _options;
private readonly string _schemaPrefix;
public BaseDbContextFactory(IOptions<DatabaseOptions> options, string schemaPrefix)
public BaseDbContextFactory(DatabaseOptions options, string schemaPrefix)
{
_options = options;
_schemaPrefix = schemaPrefix;
@ -66,10 +65,10 @@ namespace BTCPayServer.Abstractions.Contracts
public void ConfigureBuilder(DbContextOptionsBuilder builder)
{
switch (_options.Value.DatabaseType)
switch (_options.DatabaseType)
{
case DatabaseType.Sqlite:
builder.UseSqlite(_options.Value.ConnectionString, o =>
builder.UseSqlite(_options.ConnectionString, o =>
{
if (!string.IsNullOrEmpty(_schemaPrefix))
{
@ -79,7 +78,7 @@ namespace BTCPayServer.Abstractions.Contracts
break;
case DatabaseType.Postgres:
builder
.UseNpgsql(_options.Value.ConnectionString, o =>
.UseNpgsql(_options.ConnectionString, o =>
{
o.EnableRetryOnFailure(10);
if (!string.IsNullOrEmpty(_schemaPrefix))
@ -90,7 +89,7 @@ namespace BTCPayServer.Abstractions.Contracts
.ReplaceService<IMigrationsSqlGenerator, CustomNpgsqlMigrationsSqlGenerator>();
break;
case DatabaseType.MySQL:
builder.UseMySql(_options.Value.ConnectionString, o =>
builder.UseMySql(_options.ConnectionString, o =>
{
o.EnableRetryOnFailure(10);

View File

@ -1,4 +1,3 @@
#nullable enable
using System.Threading;
using System.Threading.Tasks;
@ -6,8 +5,8 @@ namespace BTCPayServer.Abstractions.Contracts
{
public interface ISettingsRepository
{
Task<T?> GetSettingAsync<T>(string? name = null) where T : class;
Task UpdateSetting<T>(T obj, string? name = null) where T : class;
Task<T> WaitSettingsChanged<T>(CancellationToken cancellationToken = default) where T : class;
Task<T> GetSettingAsync<T>(string name = null);
Task UpdateSetting<T>(T obj, string name = null);
Task<T> WaitSettingsChanged<T>(CancellationToken cancellationToken = default);
}
}

View File

@ -21,6 +21,7 @@ namespace BTCPayServer.Abstractions.Models
public abstract string Description { get; }
public bool SystemPlugin { get; set; }
public bool SystemExtension { get; set; }
public virtual IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } = Array.Empty<IBTCPayServerPlugin.PluginDependency>();
public virtual void Execute(IApplicationBuilder applicationBuilder,

View File

@ -2,6 +2,12 @@ namespace BTCPayServer.Abstractions.Models
{
public class DatabaseOptions
{
public DatabaseOptions(DatabaseType type, string connString)
{
DatabaseType = type;
ConnectionString = connString;
}
public DatabaseType DatabaseType { get; set; }
public string ConnectionString { get; set; }
}

View File

@ -5,7 +5,7 @@ namespace BTCPayServer.Abstractions.Services
{
public abstract class PluginAction<T>:IPluginHookAction
{
public abstract string Hook { get; }
public string Hook { get; }
public Task Execute(object args)
{
return Execute(args is T args1 ? args1 : default);

View File

@ -5,8 +5,7 @@ namespace BTCPayServer.Abstractions.Services
{
public abstract class PluginHookFilter<T>:IPluginHookFilter
{
public abstract string Hook { get; }
public string Hook { get; }
public Task<object> Execute(object args)
{
return Execute(args is T args1 ? args1 : default).ContinueWith(task => task.Result as object);

View File

@ -13,7 +13,7 @@
<RepositoryType>git</RepositoryType>
</PropertyGroup>
<PropertyGroup>
<Version Condition=" '$(Version)' == '' ">1.3.0</Version>
<Version Condition=" '$(Version)' == '' ">1.2.0</Version>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<PublishRepositoryUrl>true</PublishRepositoryUrl>
@ -27,7 +27,7 @@
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NBitcoin" Version="5.0.73" />
<PackageReference Include="NBitcoin" Version="5.0.60" />
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>

View File

@ -54,17 +54,6 @@ namespace BTCPayServer.Client
return await HandleResponse<InvoiceData>(response);
}
public virtual async Task<InvoiceData> UpdateInvoice(string storeId, string invoiceId,
UpdateInvoiceRequest request, CancellationToken token = default)
{
if (request == null)
throw new ArgumentNullException(nameof(request));
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}", bodyPayload: request,
method: HttpMethod.Put), token);
return await HandleResponse<InvoiceData>(response);
}
public virtual async Task<InvoiceData> MarkInvoiceStatus(string storeId, string invoiceId,
MarkInvoiceStatusRequest request, CancellationToken token = default)
{

View File

@ -1,63 +0,0 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public virtual async Task<IEnumerable<LightningNetworkPaymentMethodData>>
GetStoreLightningNetworkPaymentMethods(string storeId,
CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork"), token);
return await HandleResponse<IEnumerable<LightningNetworkPaymentMethodData>>(response);
}
public virtual async Task<LightningNetworkPaymentMethodData> GetStoreLightningNetworkPaymentMethod(
string storeId,
string cryptoCode, CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}"), token);
return await HandleResponse<LightningNetworkPaymentMethodData>(response);
}
public virtual async Task RemoveStoreLightningNetworkPaymentMethod(string storeId,
string cryptoCode, CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}",
method: HttpMethod.Delete), token);
await HandleResponse(response);
}
public virtual async Task<LightningNetworkPaymentMethodData> UpdateStoreLightningNetworkPaymentMethod(
string storeId,
string cryptoCode, LightningNetworkPaymentMethodData paymentMethod,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}",
bodyPayload: paymentMethod, method: HttpMethod.Put), token);
return await HandleResponse<LightningNetworkPaymentMethodData>(response);
}
public virtual async Task<LightningNetworkPaymentMethodData>
UpdateStoreLightningNetworkPaymentMethodToInternalNode(string storeId,
string cryptoCode, LightningNetworkPaymentMethodData paymentMethod,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}/internal",
method: HttpMethod.Put), token);
return await HandleResponse<LightningNetworkPaymentMethodData>(response);
}
}
}

View File

@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public virtual async Task<IEnumerable<NotificationData>> GetNotifications(bool? seen = null,
CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/users/me/notifications",
seen != null ? new Dictionary<string, object>() {{nameof(seen), seen}} : null), token);
return await HandleResponse<IEnumerable<NotificationData>>(response);
}
public virtual async Task<NotificationData> GetNotification(string notificationId,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/users/me/notifications/{notificationId}"), token);
return await HandleResponse<NotificationData>(response);
}
public virtual async Task<NotificationData> UpdateNotification(string notificationId, bool? seen,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/users/me/notifications/{notificationId}",
method: HttpMethod.Put, bodyPayload: new UpdateNotification() {Seen = seen}), token);
return await HandleResponse<NotificationData>(response);
}
public virtual async Task RemoveNotification(string notificationId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/users/me/notifications/{notificationId}",
method: HttpMethod.Delete), token);
await HandleResponse(response);
}
}
}

View File

@ -1,74 +0,0 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public virtual async Task<IEnumerable<OnChainPaymentMethodData>> GetStoreOnChainPaymentMethods(string storeId,
CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain"), token);
return await HandleResponse<IEnumerable<OnChainPaymentMethodData>>(response);
}
public virtual async Task<OnChainPaymentMethodData> GetStoreOnChainPaymentMethod(string storeId,
string cryptoCode, CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}"), token);
return await HandleResponse<OnChainPaymentMethodData>(response);
}
public virtual async Task RemoveStoreOnChainPaymentMethod(string storeId,
string cryptoCode, CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}",
method: HttpMethod.Delete), token);
await HandleResponse(response);
}
public virtual async Task<OnChainPaymentMethodData> UpdateStoreOnChainPaymentMethod(string storeId,
string cryptoCode, OnChainPaymentMethodData paymentMethod,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}",
bodyPayload: paymentMethod, method: HttpMethod.Put), token);
return await HandleResponse<OnChainPaymentMethodData>(response);
}
public virtual async Task<OnChainPaymentMethodPreviewResultData>
PreviewProposedStoreOnChainPaymentMethodAddresses(
string storeId, string cryptoCode, OnChainPaymentMethodData paymentMethod, int offset = 0,
int amount = 10,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}/preview",
bodyPayload: paymentMethod,
queryPayload: new Dictionary<string, object>() {{"offset", offset}, {"amount", amount}},
method: HttpMethod.Post), token);
return await HandleResponse<OnChainPaymentMethodPreviewResultData>(response);
}
public virtual async Task<OnChainPaymentMethodPreviewResultData> PreviewStoreOnChainPaymentMethodAddresses(
string storeId, string cryptoCode, int offset = 0, int amount = 10,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}/preview",
queryPayload: new Dictionary<string, object>() {{"offset", offset}, {"amount", amount}},
method: HttpMethod.Get), token);
return await HandleResponse<OnChainPaymentMethodPreviewResultData>(response);
}
}
}

View File

@ -1,109 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
using NBitcoin;
namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public virtual async Task<OnChainWalletOverviewData> ShowOnChainWalletOverview(string storeId, string cryptoCode,
CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}/wallet"), token);
return await HandleResponse<OnChainWalletOverviewData>(response);
}
public virtual async Task<OnChainWalletAddressData> GetOnChainWalletReceiveAddress(string storeId, string cryptoCode, bool forceGenerate = false,
CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}/wallet/address", new Dictionary<string, object>()
{
{"forceGenerate", forceGenerate}
}), token);
return await HandleResponse<OnChainWalletAddressData>(response);
}
public virtual async Task UnReserveOnChainWalletReceiveAddress(string storeId, string cryptoCode,
CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}/wallet/address",method:HttpMethod.Delete), token);
await HandleResponse(response);
}
public virtual async Task<IEnumerable<OnChainWalletTransactionData>> ShowOnChainWalletTransactions(
string storeId, string cryptoCode, TransactionStatus[] statusFilter = null,
CancellationToken token = default)
{
var query = new Dictionary<string, object>();
if (statusFilter?.Any() is true)
{
query.Add(nameof(statusFilter), statusFilter);
}
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}/wallet/transactions", query), token);
return await HandleResponse<IEnumerable<OnChainWalletTransactionData>>(response);
}
public virtual async Task<OnChainWalletTransactionData> GetOnChainWalletTransaction(
string storeId, string cryptoCode, string transactionId,
CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}/wallet/transactions/{transactionId}"), token);
return await HandleResponse<OnChainWalletTransactionData>(response);
}
public virtual async Task<IEnumerable<OnChainWalletUTXOData>> GetOnChainWalletUTXOs(string storeId,
string cryptoCode,
CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}/wallet/utxos"), token);
return await HandleResponse<IEnumerable<OnChainWalletUTXOData>>(response);
}
public virtual async Task<OnChainWalletTransactionData> CreateOnChainTransaction(string storeId,
string cryptoCode, CreateOnChainTransactionRequest request,
CancellationToken token = default)
{
if (!request.ProceedWithBroadcast)
{
throw new ArgumentOutOfRangeException(nameof(request.ProceedWithBroadcast),
"Please use CreateOnChainTransactionButDoNotBroadcast when wanting to only create the transaction");
}
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}/wallet/transactions", null, request, HttpMethod.Post), token);
return await HandleResponse<OnChainWalletTransactionData>(response);
}
public virtual async Task<Transaction> CreateOnChainTransactionButDoNotBroadcast(string storeId,
string cryptoCode, CreateOnChainTransactionRequest request, Network network,
CancellationToken token = default)
{
if (request.ProceedWithBroadcast)
{
throw new ArgumentOutOfRangeException(nameof(request.ProceedWithBroadcast),
"Please use CreateOnChainTransaction when wanting to also broadcast the transaction");
}
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}/wallet/transactions", null, request, HttpMethod.Post), token);
return Transaction.Parse(await HandleResponse<string>(response), network);
}
}
}

View File

@ -9,7 +9,7 @@ namespace BTCPayServer.Client.Models
{
public class CreateInvoiceRequest
{
[JsonConverter(typeof(NumericStringJsonConverter))]
[JsonProperty(ItemConverterType = typeof(NumericStringJsonConverter))]
public decimal Amount { get; set; }
public string Currency { get; set; }
public JObject Metadata { get; set; }
@ -17,7 +17,6 @@ namespace BTCPayServer.Client.Models
public class CheckoutOptions
{
[JsonConverter(typeof(StringEnumConverter))]
public SpeedPolicy? SpeedPolicy { get; set; }
@ -31,11 +30,6 @@ namespace BTCPayServer.Client.Models
public TimeSpan? Monitoring { get; set; }
public double? PaymentTolerance { get; set; }
[JsonProperty("redirectURL")]
public string RedirectURL { get; set; }
public bool? RedirectAutomatically { get; set; }
public string DefaultLanguage { get; set; }
}
}
}

View File

@ -17,7 +17,7 @@ namespace BTCPayServer.Client.Models
Description = description;
Expiry = expiry;
}
[JsonConverter(typeof(BTCPayServer.Client.JsonConverters.LightMoneyJsonConverter))]
[JsonConverter(typeof(LightMoneyJsonConverter))]
public LightMoney Amount { get; set; }
public string Description { get; set; }
[JsonConverter(typeof(JsonConverters.TimeSpanJsonConverter.Seconds))]

View File

@ -1,30 +0,0 @@
using System.Collections.Generic;
using BTCPayServer.JsonConverters;
using NBitcoin;
using NBitcoin.JsonConverters;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models
{
public class CreateOnChainTransactionRequest
{
public class CreateOnChainTransactionRequestDestination
{
public string Destination { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal? Amount { get; set; }
public bool SubtractFromAmount { get; set; }
}
[JsonConverter(typeof(FeeRateJsonConverter))]
public FeeRate FeeRate { get; set; }
public bool ProceedWithPayjoin { get; set; }= true;
public bool ProceedWithBroadcast { get; set; } = true;
public bool NoChange { get; set; } = false;
[JsonProperty(ItemConverterType = typeof(OutpointJsonConverter))]
public List<OutPoint> SelectedInputs { get; set; } = null;
public List<CreateOnChainTransactionRequestDestination> Destinations { get; set; }
[JsonProperty("rbf")]
public bool? RBF { get; set; } = null;
}
}

View File

@ -10,7 +10,8 @@ namespace BTCPayServer.Client.Models
}
public GreenfieldAPIError(string code, string message)
{
code = code ?? "generic-error";
if (code == null)
throw new ArgumentNullException(nameof(code));
if (message == null)
throw new ArgumentNullException(nameof(message));
Code = code;

View File

@ -7,7 +7,6 @@ namespace BTCPayServer.Client.Models
public class InvoiceData : CreateInvoiceRequest
{
public string Id { get; set; }
public string CheckoutLink { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public InvoiceStatus Status { get; set; }
[JsonConverter(typeof(StringEnumConverter))]

View File

@ -1,14 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Client.Models
{
public class LabelData
{
public string Type { get; set; }
public string Text { get; set; }
[JsonExtensionData] public Dictionary<string, JToken> AdditionalData { get; set; }
}
}

View File

@ -1,28 +0,0 @@
namespace BTCPayServer.Client.Models
{
public class LightningNetworkPaymentMethodData
{
/// <summary>
/// Whether the payment method is enabled
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// Crypto code of the payment method
/// </summary>
public string CryptoCode { get; set; }
public string ConnectionString { get; set; }
public LightningNetworkPaymentMethodData()
{
}
public LightningNetworkPaymentMethodData(string cryptoCode, string connectionString, bool enabled)
{
Enabled = enabled;
CryptoCode = cryptoCode;
ConnectionString = connectionString;
}
}
}

View File

@ -1,16 +0,0 @@
using System;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models
{
public class NotificationData
{
public string Id { get; set; }
public string Body { get; set; }
public bool Seen { get; set; }
public Uri Link { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset CreatedTime { get; set; }
}
}

View File

@ -1,39 +0,0 @@
using NBitcoin;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models
{
public class OnChainPaymentMethodData
{
/// <summary>
/// Whether the payment method is enabled
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// Crypto code of the payment method
/// </summary>
public string CryptoCode { get; set; }
/// <summary>
/// The derivation scheme
/// </summary>
public string DerivationScheme { get; set; }
public string Label { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.KeyPathJsonConverter))]
public RootedKeyPath AccountKeyPath { get; set; }
public OnChainPaymentMethodData()
{
}
public OnChainPaymentMethodData(string cryptoCode, string derivationScheme, bool enabled)
{
Enabled = enabled;
CryptoCode = cryptoCode;
DerivationScheme = derivationScheme;
}
}
}

View File

@ -1,23 +0,0 @@
using System.Collections.Generic;
namespace BTCPayServer.Client.Models
{
public class OnChainPaymentMethodPreviewResultData
{
/// <summary>
/// a list of addresses generated by the derivation scheme
/// </summary>
public IList<OnChainPaymentMethodPreviewResultAddressItem> Addresses { get; set; } =
new List<OnChainPaymentMethodPreviewResultAddressItem>();
public class OnChainPaymentMethodPreviewResultAddressItem
{
/// <summary>
/// The key path relative to the account key path.
/// </summary>
public string KeyPath { get; set; }
//The address generated at the key path
public string Address { get; set; }
}
}
}

View File

@ -1,13 +0,0 @@
using NBitcoin;
using NBitcoin.JsonConverters;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models
{
public class OnChainWalletAddressData
{
public string Address { get; set; }
[JsonConverter(typeof(KeyPathJsonConverter))]
public KeyPath KeyPath { get; set; }
}
}

View File

@ -1,12 +0,0 @@
using BTCPayServer.JsonConverters;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models
{
public class OnChainWalletOverviewData
{
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Balance { get; set; }
}
}

View File

@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using BTCPayServer.JsonConverters;
using NBitcoin;
using NBitcoin.JsonConverters;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models
{
public class OnChainWalletTransactionData
{
[JsonConverter(typeof(UInt256JsonConverter))]
public uint256 TransactionHash { get; set; }
public string Comment { get; set; }
public Dictionary<string, LabelData> Labels { get; set; } = new Dictionary<string, LabelData>();
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Amount { get; set; }
[JsonConverter(typeof(UInt256JsonConverter))]
public uint256 BlockHash { get; set; }
public int? BlockHeight { get; set; }
public int Confirmations { get; set; }
[JsonConverter(typeof(DateTimeToUnixTimeConverter))]
public DateTimeOffset Timestamp { get; set; }
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public TransactionStatus Status { get; set; }
}
}

View File

@ -1,20 +0,0 @@
using System.Collections.Generic;
using BTCPayServer.JsonConverters;
using NBitcoin;
using NBitcoin.JsonConverters;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models
{
public class OnChainWalletUTXOData
{
public string Comment { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Amount { get; set; }
[JsonConverter(typeof(OutpointJsonConverter))]
public OutPoint Outpoint { get; set; }
public string Link { get; set; }
public Dictionary<string, LabelData> Labels { get; set; }
}
}

View File

@ -41,8 +41,7 @@ namespace BTCPayServer.Client.Models
public bool ShowRecommendedFee { get; set; } = true;
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public int RecommendedFeeBlockTarget { get; set; } = 1;
public string DefaultPaymentMethod { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string DefaultLang { get; set; } = "en";

View File

@ -1,9 +0,0 @@
namespace BTCPayServer.Client.Models
{
public enum TransactionStatus
{
Unconfirmed,
Confirmed,
Replaced
}
}

View File

@ -1,9 +0,0 @@
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Client.Models
{
public class UpdateInvoiceRequest
{
public JObject Metadata { get; set; }
}
}

View File

@ -1,7 +0,0 @@
namespace BTCPayServer.Client.Models
{
public class UpdateNotification
{
public bool? Seen { get; set; }
}
}

View File

@ -21,8 +21,6 @@ namespace BTCPayServer.Client
public const string CanModifyPaymentRequests = "btcpay.store.canmodifypaymentrequests";
public const string CanModifyProfile = "btcpay.user.canmodifyprofile";
public const string CanViewProfile = "btcpay.user.canviewprofile";
public const string CanManageNotificationsForUser = "btcpay.user.canmanagenotificationsforuser";
public const string CanViewNotificationsForUser = "btcpay.user.canviewnotificationsforuser";
public const string CanCreateUser = "btcpay.server.cancreateuser";
public const string CanManagePullPayments = "btcpay.store.canmanagepullpayments";
public const string Unrestricted = "unrestricted";
@ -41,8 +39,6 @@ namespace BTCPayServer.Client
yield return CanModifyProfile;
yield return CanViewProfile;
yield return CanCreateUser;
yield return CanManageNotificationsForUser;
yield return CanViewNotificationsForUser;
yield return Unrestricted;
yield return CanUseInternalLightningNode;
yield return CanCreateLightningInvoiceInternalNode;
@ -172,7 +168,6 @@ namespace BTCPayServer.Client
case Policies.CanViewPaymentRequests when this.Policy == Policies.CanViewStoreSettings:
case Policies.CanCreateLightningInvoiceInternalNode when this.Policy == Policies.CanUseInternalLightningNode:
case Policies.CanCreateLightningInvoiceInStore when this.Policy == Policies.CanUseLightningNodeInStore:
case Policies.CanViewNotificationsForUser when this.Policy == Policies.CanManageNotificationsForUser:
return true;
default:
return false;

View File

@ -11,7 +11,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Argoneum",
BlockExplorerLink = NetworkType == ChainName.Mainnet
BlockExplorerLink = NetworkType == NetworkType.Mainnet
? "https://chainz.cryptoid.info/agm/tx.dws?{0}"
: "https://chainz.cryptoid.info/agm-test/tx.dws?{0}",
NBXplorerNetwork = nbxplorerNetwork,
@ -23,7 +23,7 @@ namespace BTCPayServer
},
CryptoImagePath = "imlegacy/argoneum.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("421'")
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("421'")
: new KeyPath("1'")
});
}

View File

@ -1,29 +0,0 @@
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitBPlus()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("XBC");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "BPlus",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://chainz.cryptoid.info/xbc/tx.dws?{0}" : "https://chainz.cryptoid.info/xbc/tx.dws?{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "bplus-fix-it",
DefaultRateRules = new[]
{
"XBC_X = XBC_BTC * BTC_X",
"XBC_BTC = cryptopia(XBC_BTC)"
},
CryptoImagePath = "imlegacy/xbc.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("65'") : new KeyPath("1'")
});
}
}
}

View File

@ -4,14 +4,14 @@ namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitBGold()
public void InitBitcoinGold()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("BTG");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "BGold",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://btgexplorer.com/tx/{0}" : "https://testnet.btgexplorer.com/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://explorer.bitcoingold.org/insight/tx/{0}/" : "https://test-explorer.bitcoingold.org/insight/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "bitcoingold",
DefaultRateRules = new[]
@ -22,7 +22,7 @@ namespace BTCPayServer
CryptoImagePath = "imlegacy/btg.svg",
LightningImagePath = "imlegacy/btg-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("156'") : new KeyPath("1'")
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("156'") : new KeyPath("1'")
});
}
}

View File

@ -0,0 +1,29 @@
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitBitcoinplus()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("XBC");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Bitcoinplus",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://chainz.cryptoid.info/xbc/tx.dws?{0}" : "https://chainz.cryptoid.info/xbc/tx.dws?{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "bitcoinplus",
DefaultRateRules = new[]
{
"XBC_X = XBC_BTC * BTC_X",
"XBC_BTC = cryptopia(XBC_BTC)"
},
CryptoImagePath = "imlegacy/bitcoinplus.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("65'") : new KeyPath("1'")
});
}
}
}

View File

@ -12,7 +12,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Bitcore",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://insight.bitcore.cc/tx/{0}" : "https://insight.bitcore.cc/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://insight.bitcore.cc/tx/{0}" : "https://insight.bitcore.cc/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "bitcore",
DefaultRateRules = new[]
@ -23,7 +23,7 @@ namespace BTCPayServer
CryptoImagePath = "imlegacy/bitcore.svg",
LightningImagePath = "imlegacy/bitcore-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("160'") : new KeyPath("1'")
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("160'") : new KeyPath("1'")
});
}
}

View File

@ -11,7 +11,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Chaincoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet
BlockExplorerLink = NetworkType == NetworkType.Mainnet
? "https://explorer.chaincoin.org/Explorer/Transaction/{0}"
: "https://test.explorer.chaincoin.org/Explorer/Transaction/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
@ -24,7 +24,7 @@ namespace BTCPayServer
CryptoImagePath = "imlegacy/chaincoin.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
//https://github.com/satoshilabs/slips/blob/master/slip-0044.md
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("711'")
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("711'")
: new KeyPath("1'")
});
}

View File

@ -12,7 +12,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Dash",
BlockExplorerLink = NetworkType == ChainName.Mainnet
BlockExplorerLink = NetworkType == NetworkType.Mainnet
? "https://insight.dash.org/insight/tx/{0}"
: "https://testnet-insight.dashevo.org/insight/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
@ -20,12 +20,12 @@ namespace BTCPayServer
DefaultRateRules = new[]
{
"DASH_X = DASH_BTC * BTC_X",
"DASH_BTC = bitfinex(DSH_BTC)"
"DASH_BTC = bittrex(DASH_BTC)"
},
CryptoImagePath = "imlegacy/dash.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
//https://github.com/satoshilabs/slips/blob/master/slip-0044.md
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("5'")
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("5'")
: new KeyPath("1'")
});
}

View File

@ -12,7 +12,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Dogecoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://dogechain.info/tx/{0}" : "https://dogechain.info/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://dogechain.info/tx/{0}" : "https://dogechain.info/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "dogecoin",
DefaultRateRules = new[]
@ -22,7 +22,7 @@ namespace BTCPayServer
},
CryptoImagePath = "imlegacy/dogecoin.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("3'") : new KeyPath("1'")
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("3'") : new KeyPath("1'")
});
}
}

View File

@ -12,7 +12,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Feathercoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://explorer.feathercoin.com/tx/{0}" : "https://explorer.feathercoin.com/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://explorer.feathercoin.com/tx/{0}" : "https://explorer.feathercoin.com/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "feathercoin",
DefaultRateRules = new[]
@ -22,7 +22,7 @@ namespace BTCPayServer
},
CryptoImagePath = "imlegacy/feathercoin.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("8'") : new KeyPath("1'")
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("8'") : new KeyPath("1'")
});
}
}

View File

@ -11,7 +11,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Groestlcoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet
BlockExplorerLink = NetworkType == NetworkType.Mainnet
? "https://chainz.cryptoid.info/grs/tx.dws?{0}.htm"
: "https://chainz.cryptoid.info/grs-test/tx.dws?{0}.htm",
NBXplorerNetwork = nbxplorerNetwork,
@ -24,10 +24,9 @@ namespace BTCPayServer
CryptoImagePath = "imlegacy/groestlcoin.png",
LightningImagePath = "imlegacy/groestlcoin-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("17'") : new KeyPath("1'"),
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("17'") : new KeyPath("1'"),
SupportRBF = true,
SupportPayJoin = true,
VaultSupported = true
SupportPayJoin = true
});
}
}

View File

@ -13,7 +13,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Litecoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet
BlockExplorerLink = NetworkType == NetworkType.Mainnet
? "https://live.blockcypher.com/ltc/tx/{0}/"
: "http://explorer.litecointools.com/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
@ -26,9 +26,9 @@ namespace BTCPayServer
CryptoImagePath = "imlegacy/litecoin.svg",
LightningImagePath = "imlegacy/litecoin-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("2'") : new KeyPath("1'"),
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("2'") : new KeyPath("1'"),
//https://github.com/pooler/electrum-ltc/blob/0d6989a9d2fb2edbea421c116e49d1015c7c5a91/electrum_ltc/constants.py
ElectrumMapping = NetworkType == ChainName.Mainnet
ElectrumMapping = NetworkType == NetworkType.Mainnet
? new Dictionary<uint, DerivationType>()
{
{0x0488b21eU, DerivationType.Legacy },

View File

@ -12,7 +12,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Monacoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://mona.insight.monaco-ex.org/insight/tx/{0}" : "https://testnet-mona.insight.monaco-ex.org/insight/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://mona.insight.monaco-ex.org/insight/tx/{0}" : "https://testnet-mona.insight.monaco-ex.org/insight/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "monacoin",
DefaultRateRules = new[]
@ -23,7 +23,7 @@ namespace BTCPayServer
CryptoImagePath = "imlegacy/monacoin.png",
LightningImagePath = "imlegacy/mona-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("22'") : new KeyPath("1'")
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("22'") : new KeyPath("1'")
});
}
}

View File

@ -12,7 +12,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "MonetaryUnit",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://explorer.monetaryunit.org/#/MUE/mainnet/tx/{0}" : "https://explorer.monetaryunit.org/#/MUE/mainnet/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://explorer.monetaryunit.org/#/MUE/mainnet/tx/{0}" : "https://explorer.monetaryunit.org/#/MUE/mainnet/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "monetaryunit",
DefaultRateRules = new[]
@ -22,7 +22,7 @@ namespace BTCPayServer
},
CryptoImagePath = "imlegacy/monetaryunit.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("31'") : new KeyPath("1'")
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("31'") : new KeyPath("1'")
});
}
}

View File

@ -12,7 +12,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Polis",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://blockbook.polispay.org/tx/{0}" : "https://blockbook.polispay.org/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://blockbook.polispay.org/tx/{0}" : "https://blockbook.polispay.org/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "polis",
DefaultRateRules = new[]
@ -22,7 +22,7 @@ namespace BTCPayServer
},
CryptoImagePath = "imlegacy/polis.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1997'") : new KeyPath("1'")
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("1997'") : new KeyPath("1'")
});
}
}

View File

@ -12,7 +12,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Ufo",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://chainz.cryptoid.info/ufo/tx.dws?{0}" : "https://chainz.cryptoid.info/ufo/tx.dws?{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://chainz.cryptoid.info/ufo/tx.dws?{0}" : "https://chainz.cryptoid.info/ufo/tx.dws?{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "ufo",
DefaultRateRules = new[]
@ -22,7 +22,7 @@ namespace BTCPayServer
},
CryptoImagePath = "imlegacy/ufo.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("202'") : new KeyPath("1'")
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("202'") : new KeyPath("1'")
});
}
}

View File

@ -12,7 +12,7 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Viacoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://explorer.viacoin.org/tx/{0}" : "https://explorer.viacoin.org/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://explorer.viacoin.org/tx/{0}" : "https://explorer.viacoin.org/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "viacoin",
DefaultRateRules = new[]
@ -22,7 +22,7 @@ namespace BTCPayServer
},
CryptoImagePath = "imlegacy/viacoin.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("14'") : new KeyPath("1'")
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("14'") : new KeyPath("1'")
});
}
}

View File

@ -13,20 +13,20 @@ namespace BTCPayServer
DisplayName = "Ethereum",
DefaultRateRules = new[] {"ETH_X = ETH_BTC * BTC_X", "ETH_BTC = kraken(ETH_BTC)"},
BlockExplorerLink =
NetworkType == ChainName.Mainnet
NetworkType == NetworkType.Mainnet
? "https://etherscan.io/address/{0}"
: "https://ropsten.etherscan.io/address/{0}",
CryptoImagePath = "/imlegacy/eth.png",
ShowSyncSummary = true,
CoinType = NetworkType == ChainName.Mainnet? 60 : 1,
ChainId = NetworkType == ChainName.Mainnet ? 1 : 3,
CoinType = NetworkType == NetworkType.Mainnet? 60 : 1,
ChainId = NetworkType == NetworkType.Mainnet ? 1 : 3,
Divisibility = 18,
});
}
public void InitERC20()
{
if (NetworkType != ChainName.Mainnet)
if (NetworkType != NetworkType.Mainnet)
{
Add(new ERC20BTCPayNetwork()
{
@ -60,13 +60,13 @@ namespace BTCPayServer
"USDT20_BTC = bitfinex(UST_BTC)",
},
BlockExplorerLink =
NetworkType == ChainName.Mainnet
NetworkType == NetworkType.Mainnet
? "https://etherscan.io/address/{0}#tokentxns"
: "https://ropsten.etherscan.io/address/{0}#tokentxns",
CryptoImagePath = "/imlegacy/liquid-tether.svg",
ShowSyncSummary = false,
CoinType = NetworkType == ChainName.Mainnet? 60 : 1,
ChainId = NetworkType == ChainName.Mainnet ? 1 : 3,
CoinType = NetworkType == NetworkType.Mainnet? 60 : 1,
ChainId = NetworkType == NetworkType.Mainnet ? 1 : 3,
SmartContractAddress = "0xdAC17F958D2ee523a2206206994597C13D831ec7",
Divisibility = 6
});

View File

@ -13,7 +13,7 @@ namespace BTCPayServer
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("LBTC");
Add(new ElementsBTCPayNetwork()
{
AssetId = NetworkType == ChainName.Mainnet ? ElementsParams<Liquid>.PeggedAssetId : ElementsParams<Liquid.LiquidRegtest>.PeggedAssetId,
AssetId = NetworkType == NetworkType.Mainnet ? ElementsParams<Liquid>.PeggedAssetId : ElementsParams<Liquid.LiquidRegtest>.PeggedAssetId,
CryptoCode = "LBTC",
NetworkCryptoCode = "LBTC",
DisplayName = "Liquid Bitcoin",
@ -22,12 +22,12 @@ namespace BTCPayServer
"LBTC_X = LBTC_BTC * BTC_X",
"LBTC_BTC = 1",
},
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://blockstream.info/liquid/tx/{0}" : "https://blockstream.info/testnet/liquid/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://blockstream.info/liquid/tx/{0}" : "https://blockstream.info/testnet/liquid/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "liquidnetwork",
CryptoImagePath = "imlegacy/liquid.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
SupportRBF = true
});
}

View File

@ -21,12 +21,12 @@ namespace BTCPayServer
},
AssetId = new uint256("ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"),
DisplayName = "Liquid Tether",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://blockstream.info/liquid/tx/{0}" : "https://blockstream.info/testnet/liquid/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://blockstream.info/liquid/tx/{0}" : "https://blockstream.info/testnet/liquid/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "liquidnetwork",
CryptoImagePath = "imlegacy/liquid-tether.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
SupportRBF = true,
SupportLightning = false
});
@ -45,12 +45,12 @@ namespace BTCPayServer
Divisibility = 2,
AssetId = new uint256("aa775044c32a7df391902b3659f46dfe004ccb2644ce2ddc7dba31e889391caf"),
DisplayName = "Ethiopian Birr",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://blockstream.info/liquid/tx/{0}" : "https://blockstream.info/testnet/liquid/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://blockstream.info/liquid/tx/{0}" : "https://blockstream.info/testnet/liquid/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "liquidnetwork",
CryptoImagePath = "imlegacy/etb.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
SupportRBF = true,
SupportLightning = false
});
@ -68,12 +68,12 @@ namespace BTCPayServer
},
AssetId = new uint256("0e99c1a6da379d1f4151fb9df90449d40d0608f6cb33a5bcbfc8c265f42bab0a"),
DisplayName = "Liquid CAD",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://blockstream.info/liquid/tx/{0}" : "https://blockstream.info/testnet/liquid/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://blockstream.info/liquid/tx/{0}" : "https://blockstream.info/testnet/liquid/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "liquidnetwork",
CryptoImagePath = "imlegacy/lcad.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
SupportRBF = true,
SupportLightning = false
});

View File

@ -24,15 +24,31 @@ namespace BTCPayServer
});
}
public override List<TransactionInformation> FilterValidTransactions(List<TransactionInformation> transactionInformationSet)
public override GetTransactionsResponse FilterValidTransactions(GetTransactionsResponse response)
{
return transactionInformationSet.FindAll(information =>
information.Outputs.Any(output =>
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId) ||
information.Inputs.Any(output =>
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId));
TransactionInformationSet Filter(TransactionInformationSet transactionInformationSet)
{
return new TransactionInformationSet()
{
Transactions =
transactionInformationSet.Transactions.FindAll(information =>
information.Outputs.Any(output =>
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId) ||
information.Inputs.Any(output =>
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId))
};
}
return new GetTransactionsResponse()
{
Height = response.Height,
ConfirmedTransactions = Filter(response.ConfirmedTransactions),
ReplacedTransactions = Filter(response.ReplacedTransactions),
UnconfirmedTransactions = Filter(response.UnconfirmedTransactions)
};
}
public override string GenerateBIP21(string cryptoInfoAddress, Money cryptoInfoDue)
{
//precision 0: 10 = 0.00000010

View File

@ -12,7 +12,7 @@ namespace BTCPayServer
DisplayName = "Monero",
Divisibility = 12,
BlockExplorerLink =
NetworkType == ChainName.Mainnet
NetworkType == NetworkType.Mainnet
? "https://www.exploremonero.com/transaction/{0}"
: "https://testnet.xmrchain.net/tx/{0}",
DefaultRateRules = new[]

View File

@ -18,29 +18,25 @@ namespace BTCPayServer
{
static BTCPayDefaultSettings()
{
_Settings = new Dictionary<ChainName, BTCPayDefaultSettings>();
}
static readonly Dictionary<ChainName, BTCPayDefaultSettings> _Settings;
public static BTCPayDefaultSettings GetDefaultSettings(ChainName chainType)
{
if (_Settings.TryGetValue(chainType, out var v))
return v;
lock (_Settings)
_Settings = new Dictionary<NetworkType, BTCPayDefaultSettings>();
foreach (var chainType in new[] { NetworkType.Mainnet, NetworkType.Testnet, NetworkType.Regtest })
{
if (_Settings.TryGetValue(chainType, out v))
return v;
var settings = new BTCPayDefaultSettings();
_Settings.Add(chainType, settings);
settings.DefaultDataDirectory = StandardConfiguration.DefaultDataDirectory.GetDirectory("BTCPayServer", NBXplorerDefaultSettings.GetFolderName(chainType));
settings.DefaultPluginDirectory =
StandardConfiguration.DefaultDataDirectory.GetDirectory("BTCPayServer", "Plugins");
settings.DefaultConfigurationFile = Path.Combine(settings.DefaultDataDirectory, "settings.config");
settings.DefaultPort = (chainType == ChainName.Mainnet ? 23000 :
chainType == ChainName.Regtest ? 23002
: 23001);
settings.DefaultPort = (chainType == NetworkType.Mainnet ? 23000 :
chainType == NetworkType.Regtest ? 23002 :
chainType == NetworkType.Testnet ? 23001 : throw new NotSupportedException(chainType.ToString()));
}
}
static readonly Dictionary<NetworkType, BTCPayDefaultSettings> _Settings;
public static BTCPayDefaultSettings GetDefaultSettings(NetworkType chainType)
{
return _Settings[chainType];
}
@ -57,13 +53,13 @@ namespace BTCPayServer
public bool SupportRBF { get; internal set; }
public string LightningImagePath { get; set; }
public BTCPayDefaultSettings DefaultSettings { get; set; }
public KeyPath CoinType { get; set; }
public KeyPath CoinType { get; internal set; }
public Dictionary<uint, DerivationType> ElectrumMapping = new Dictionary<uint, DerivationType>();
public virtual bool WalletSupported { get; set; } = true;
public virtual bool ReadonlyWallet { get; set; } = false;
public virtual bool VaultSupported { get; set; } = false;
public int MaxTrackedConfirmation { get; internal set; } = 6;
public string UriScheme { get; internal set; }
public bool SupportPayJoin { get; set; } = false;
@ -126,9 +122,9 @@ namespace BTCPayServer
return $"{UriScheme}:{cryptoInfoAddress}?amount={cryptoInfoDue.ToString(false, true)}";
}
public virtual List<TransactionInformation> FilterValidTransactions(List<TransactionInformation> transactionInformationSet)
public virtual GetTransactionsResponse FilterValidTransactions(GetTransactionsResponse response)
{
return transactionInformationSet;
return response;
}
}
@ -136,7 +132,7 @@ namespace BTCPayServer
{
private string _blockExplorerLink;
public bool ShowSyncSummary { get; set; } = true;
public string CryptoCode { get; set; }
public string CryptoCode { get; internal set; }
public string BlockExplorerLink
{
@ -165,7 +161,7 @@ namespace BTCPayServer
}
public string CryptoImagePath { get; set; }
public string[] DefaultRateRules { get; set; } = Array.Empty<string>();
public string[] DefaultRateRules { get; internal set; } = Array.Empty<string>();
public override string ToString()
{
return CryptoCode;

View File

@ -13,20 +13,17 @@ namespace BTCPayServer
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Bitcoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://blockstream.info/tx/{0}" :
NetworkType == Bitcoin.Instance.Signet.ChainName ? "https://explorer.bc-2.jp/"
: "https://blockstream.info/testnet/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://blockstream.info/tx/{0}" : "https://blockstream.info/testnet/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "bitcoin",
CryptoImagePath = "imlegacy/bitcoin.svg",
LightningImagePath = "imlegacy/bitcoin-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("0'") : new KeyPath("1'"),
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("0'") : new KeyPath("1'"),
SupportRBF = true,
SupportPayJoin = true,
VaultSupported = true,
//https://github.com/spesmilo/electrum/blob/11733d6bc271646a00b69ff07657119598874da4/electrum/constants.py
ElectrumMapping = NetworkType == ChainName.Mainnet
ElectrumMapping = NetworkType == NetworkType.Mainnet
? new Dictionary<uint, DerivationType>()
{
{0x0488b21eU, DerivationType.Legacy }, // xpub

View File

@ -8,7 +8,8 @@ namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
protected readonly Dictionary<string, BTCPayNetworkBase> _Networks = new Dictionary<string, BTCPayNetworkBase>();
readonly Dictionary<string, BTCPayNetworkBase> _Networks = new Dictionary<string, BTCPayNetworkBase>();
private readonly NBXplorerNetworkProvider _NBXplorerNetworkProvider;
public NBXplorerNetworkProvider NBXplorerNetworkProvider
@ -35,8 +36,8 @@ namespace BTCPayServer
}
public ChainName NetworkType { get; private set; }
public BTCPayNetworkProvider(ChainName networkType)
public NetworkType NetworkType { get; private set; }
public BTCPayNetworkProvider(NetworkType networkType)
{
_NBXplorerNetworkProvider = new NBXplorerNetworkProvider(networkType);
NetworkType = networkType;
@ -47,7 +48,7 @@ namespace BTCPayServer
InitLitecoin();
InitBitcore();
InitDogecoin();
InitBGold();
InitBitcoinGold();
InitMonacoin();
InitDash();
InitFeathercoin();
@ -78,7 +79,7 @@ namespace BTCPayServer
}
// Disabled because of https://twitter.com/Cryptopia_NZ/status/1085084168852291586
//InitBPlus();
//InitBitcoinplus();
//InitUfo();
#endif
}
@ -132,4 +133,4 @@ namespace BTCPayServer
return network as T;
}
}
}
}

View File

@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../Build/Version.csproj" Condition="Exists('../Build/Version.csproj')" />
<Import Project="../Build/Common.csproj" />
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="NBXplorer.Client" Version="3.0.20" />
<PackageReference Include="NBXplorer.Client" Version="3.0.19" />
</ItemGroup>
<ItemGroup Condition="'$(Altcoins)' != 'true'">
<Compile Remove="Altcoins\**\*.cs"></Compile>

View File

@ -6,13 +6,15 @@ namespace BTCPayServer.Data
public class APIKeyData
{
[MaxLength(50)]
public string Id { get; set; }
public string Id
{
get;
set;
}
[MaxLength(50)]
public string StoreId { get; set; }
[MaxLength(50)] public string StoreId { get; set; }
[MaxLength(50)]
public string UserId { get; set; }
[MaxLength(50)] public string UserId { get; set; }
public APIKeyType Type { get; set; } = APIKeyType.Legacy;
@ -21,7 +23,6 @@ namespace BTCPayServer.Data
public ApplicationUser User { get; set; }
public string Label { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<APIKeyData>()

View File

@ -10,11 +10,25 @@ namespace BTCPayServer.Data
/// For not having exceptions thrown by two address on different network, we suffix by "#CRYPTOCODE"
/// </summary>
[Obsolete("Use GetHash instead")]
public string Address { get; set; }
public InvoiceData InvoiceData { get; set; }
public string InvoiceDataId { get; set; }
public DateTimeOffset? CreatedTime { get; set; }
public string Address
{
get; set;
}
public InvoiceData InvoiceData
{
get; set;
}
public string InvoiceDataId
{
get; set;
}
public DateTimeOffset? CreatedTime
{
get; set;
}
internal static void OnModelCreating(ModelBuilder builder)
{

View File

@ -8,24 +8,22 @@ namespace BTCPayServer.Data
{
public string Id { get; set; }
public string Name { get; set; }
public string StoreDataId { get; set; }
public string StoreDataId
{
get; set;
}
public string AppType { get; set; }
public StoreData StoreData { get; set; }
public DateTimeOffset Created { get; set; }
public StoreData StoreData
{
get; set;
}
public DateTimeOffset Created
{
get; set;
}
public bool TagAllInvoices { get; set; }
public string Settings { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<AppData>()
.HasOne(o => o.StoreData)
.WithMany(i => i.Apps).OnDelete(DeleteBehavior.Cascade);
builder.Entity<AppData>()
.HasOne(a => a.StoreData);
}
// utility methods
public T GetSettings<T>() where T : class, new()
{
if (String.IsNullOrEmpty(Settings))
@ -37,5 +35,14 @@ namespace BTCPayServer.Data
{
Settings = value == null ? null : JsonConvert.SerializeObject(value);
}
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<AppData>()
.HasOne(o => o.StoreData)
.WithMany(i => i.Apps).OnDelete(DeleteBehavior.Cascade);
builder.Entity<AppData>()
.HasOne(a => a.StoreData);
}
}
}

View File

@ -30,36 +30,43 @@ namespace BTCPayServer.Data
_designTime = designTime;
}
public DbSet<AddressInvoiceData> AddressInvoices { get; set; }
public DbSet<APIKeyData> ApiKeys { get; set; }
public DbSet<AppData> Apps { get; set; }
public DbSet<StoredFile> Files { get; set; }
public DbSet<HistoricalAddressInvoiceData> HistoricalAddressInvoices { get; set; }
public DbSet<InvoiceEventData> InvoiceEvents { get; set; }
public DbSet<InvoiceSearchData> InvoiceSearches { get; set; }
public DbSet<InvoiceWebhookDeliveryData> InvoiceWebhookDeliveries { get; set; }
public DbSet<InvoiceData> Invoices { get; set; }
public DbSet<NotificationData> Notifications { get; set; }
public DbSet<OffchainTransactionData> OffchainTransactions { get; set; }
public DbSet<PairedSINData> PairedSINData { get; set; }
public DbSet<PairingCodeData> PairingCodes { get; set; }
public DbSet<PayjoinLock> PayjoinLocks { get; set; }
public DbSet<PaymentRequestData> PaymentRequests { get; set; }
public DbSet<PaymentData> Payments { get; set; }
public DbSet<PayoutData> Payouts { get; set; }
public DbSet<PendingInvoiceData> PendingInvoices { get; set; }
public DbSet<InvoiceData> Invoices
{
get; set;
}
public DbSet<RefundData> Refunds
{
get; set;
}
public DbSet<PlannedTransaction> PlannedTransactions { get; set; }
public DbSet<PayjoinLock> PayjoinLocks { get; set; }
public DbSet<AppData> Apps { get; set; }
public DbSet<InvoiceEventData> InvoiceEvents { get; set; }
public DbSet<OffchainTransactionData> OffchainTransactions { get; set; }
public DbSet<HistoricalAddressInvoiceData> HistoricalAddressInvoices { get; set; }
public DbSet<PendingInvoiceData> PendingInvoices { get; set; }
public DbSet<PaymentData> Payments { get; set; }
public DbSet<PaymentRequestData> PaymentRequests { get; set; }
public DbSet<PullPaymentData> PullPayments { get; set; }
public DbSet<RefundData> Refunds { get; set; }
public DbSet<SettingData> Settings { get; set; }
public DbSet<StoreWebhookData> StoreWebhooks { get; set; }
public DbSet<StoreData> Stores { get; set; }
public DbSet<U2FDevice> U2FDevices { get; set; }
public DbSet<UserStore> UserStore { get; set; }
public DbSet<PayoutData> Payouts { get; set; }
public DbSet<WalletData> Wallets { get; set; }
public DbSet<WalletTransactionData> WalletTransactions { get; set; }
public DbSet<WebhookDeliveryData> WebhookDeliveries { get; set; }
public DbSet<StoreData> Stores { get; set; }
public DbSet<UserStore> UserStore { get; set; }
public DbSet<AddressInvoiceData> AddressInvoices { get; set; }
public DbSet<SettingData> Settings { get; set; }
public DbSet<PairingCodeData> PairingCodes { get; set; }
public DbSet<PairedSINData> PairedSINData { get; set; }
public DbSet<APIKeyData> ApiKeys { get; set; }
public DbSet<StoredFile> Files { get; set; }
public DbSet<U2FDevice> U2FDevices { get; set; }
public DbSet<NotificationData> Notifications { get; set; }
public DbSet<StoreWebhookData> StoreWebhooks { get; set; }
public DbSet<WebhookData> Webhooks { get; set; }
public DbSet<WebhookDeliveryData> WebhookDeliveries { get; set; }
public DbSet<InvoiceWebhookDeliveryData> InvoiceWebhookDeliveries { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
@ -71,40 +78,29 @@ namespace BTCPayServer.Data
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// some of the data models don't have OnModelCreating for now, commenting them
AddressInvoiceData.OnModelCreating(builder);
Data.UserStore.OnModelCreating(builder);
NotificationData.OnModelCreating(builder);
InvoiceData.OnModelCreating(builder);
PaymentData.OnModelCreating(builder);
Data.UserStore.OnModelCreating(builder);
APIKeyData.OnModelCreating(builder);
AppData.OnModelCreating(builder);
//StoredFile.OnModelCreating(builder);
AddressInvoiceData.OnModelCreating(builder);
PairingCodeData.OnModelCreating(builder);
PendingInvoiceData.OnModelCreating(builder);
Data.PairedSINData.OnModelCreating(builder);
HistoricalAddressInvoiceData.OnModelCreating(builder);
InvoiceEventData.OnModelCreating(builder);
InvoiceSearchData.OnModelCreating(builder);
InvoiceWebhookDeliveryData.OnModelCreating(builder);
InvoiceData.OnModelCreating(builder);
NotificationData.OnModelCreating(builder);
//OffchainTransactionData.OnModelCreating(builder);
Data.PairedSINData.OnModelCreating(builder);
PairingCodeData.OnModelCreating(builder);
//PayjoinLock.OnModelCreating(builder);
PaymentRequestData.OnModelCreating(builder);
PaymentData.OnModelCreating(builder);
PayoutData.OnModelCreating(builder);
PendingInvoiceData.OnModelCreating(builder);
//PlannedTransaction.OnModelCreating(builder);
PullPaymentData.OnModelCreating(builder);
RefundData.OnModelCreating(builder);
//SettingData.OnModelCreating(builder);
StoreWebhookData.OnModelCreating(builder);
//StoreData.OnModelCreating(builder);
U2FDevice.OnModelCreating(builder);
Data.UserStore.OnModelCreating(builder);
//WalletData.OnModelCreating(builder);
WalletTransactionData.OnModelCreating(builder);
WebhookDeliveryData.OnModelCreating(builder);
//WebhookData.OnModelCreating(builder);
PullPaymentData.OnModelCreating(builder);
PayoutData.OnModelCreating(builder);
RefundData.OnModelCreating(builder);
U2FDevice.OnModelCreating(builder);
Data.WebhookDeliveryData.OnModelCreating(builder);
Data.StoreWebhookData.OnModelCreating(builder);
Data.InvoiceWebhookDeliveryData.OnModelCreating(builder);
if (Database.IsSqlite() && !_designTime)
{

View File

@ -1,13 +1,12 @@
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Abstractions.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace BTCPayServer.Data
{
public class ApplicationDbContextFactory : BaseDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContextFactory(IOptions<DatabaseOptions> options) : base(options, "")
public ApplicationDbContextFactory(DatabaseOptions options) : base(options, "")
{
}

View File

@ -7,14 +7,27 @@ namespace BTCPayServer.Data
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
public bool RequiresEmailConfirmation { get; set; }
public List<StoredFile> StoredFiles { get; set; }
public List<NotificationData> Notifications { get; set; }
public List<UserStore> UserStores
{
get;
set;
}
public bool RequiresEmailConfirmation
{
get; set;
}
public List<StoredFile> StoredFiles
{
get;
set;
}
public List<U2FDevice> U2FDevices { get; set; }
public List<APIKeyData> APIKeys { get; set; }
public DateTimeOffset? Created { get; set; }
public string DisabledNotifications { get; set; }
public List<NotificationData> Notifications { get; set; }
public List<UserStore> UserStores { get; set; }
}
}

View File

@ -5,23 +5,39 @@ namespace BTCPayServer.Data
{
public class HistoricalAddressInvoiceData
{
public string InvoiceDataId { get; set; }
public InvoiceData InvoiceData { get; set; }
public string InvoiceDataId
{
get; set;
}
public InvoiceData InvoiceData
{
get; set;
}
/// <summary>
/// Some crypto currencies share same address prefix
/// For not having exceptions thrown by two address on different network, we suffix by "#CRYPTOCODE"
/// </summary>
[Obsolete("Use GetCryptoCode instead")]
public string Address { get; set; }
public string Address
{
get; set;
}
[Obsolete("Use GetCryptoCode instead")]
public string CryptoCode { get; set; }
public DateTimeOffset Assigned { get; set; }
public DateTimeOffset? UnAssigned { get; set; }
public DateTimeOffset Assigned
{
get; set;
}
public DateTimeOffset? UnAssigned
{
get; set;
}
internal static void OnModelCreating(ModelBuilder builder)
{

View File

@ -7,40 +7,84 @@ namespace BTCPayServer.Data
{
public class InvoiceData
{
public string Id { get; set; }
public string StoreDataId
{
get; set;
}
public StoreData StoreData
{
get; set;
}
public string StoreDataId { get; set; }
public StoreData StoreData { get; set; }
public string Id
{
get; set;
}
public DateTimeOffset Created { get; set; }
public List<PaymentData> Payments { get; set; }
public List<InvoiceEventData> Events { get; set; }
public DateTimeOffset Created
{
get; set;
}
public List<PaymentData> Payments
{
get; set;
}
public List<HistoricalAddressInvoiceData> HistoricalAddressInvoices { get; set; }
public List<InvoiceEventData> Events
{
get; set;
}
public byte[] Blob { get; set; }
public string ItemCode { get; set; }
public string OrderId { get; set; }
public string Status { get; set; }
public string ExceptionStatus { get; set; }
public string CustomerEmail { get; set; }
public List<AddressInvoiceData> AddressInvoices { get; set; }
public List<HistoricalAddressInvoiceData> HistoricalAddressInvoices
{
get; set;
}
public byte[] Blob
{
get; set;
}
public string ItemCode
{
get;
set;
}
public string OrderId
{
get;
set;
}
public string Status
{
get;
set;
}
public string ExceptionStatus
{
get;
set;
}
public string CustomerEmail
{
get;
set;
}
public List<AddressInvoiceData> AddressInvoices
{
get; set;
}
public bool Archived { get; set; }
public List<PendingInvoiceData> PendingInvoices { get; set; }
public List<InvoiceSearchData> InvoiceSearchData { get; set; }
public List<RefundData> Refunds { get; set; }
public string CurrentRefundId { get; set; }
[ForeignKey("Id,CurrentRefundId")]
public RefundData CurrentRefund { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<InvoiceData>()
.HasOne(o => o.StoreData)
.WithMany(a => a.Invoices).OnDelete(DeleteBehavior.Cascade);
builder.Entity<InvoiceData>().HasIndex(o => o.StoreDataId);
builder.Entity<InvoiceData>().HasIndex(o => o.OrderId);
builder.Entity<InvoiceData>()
.HasOne(o => o.CurrentRefund);
}

View File

@ -5,14 +5,23 @@ namespace BTCPayServer.Data
{
public class InvoiceEventData
{
public string InvoiceDataId { get; set; }
public InvoiceData InvoiceData { get; set; }
public string InvoiceDataId
{
get; set;
}
public InvoiceData InvoiceData
{
get; set;
}
public string UniqueId { get; set; }
public DateTimeOffset Timestamp { get; set; }
public DateTimeOffset Timestamp
{
get; set;
}
public string Message { get; set; }
public EventSeverity Severity { get; set; } = EventSeverity.Info;
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<InvoiceEventData>()
@ -27,7 +36,7 @@ namespace BTCPayServer.Data
#pragma warning restore CS0618
});
}
public enum EventSeverity
{
Info,
@ -35,7 +44,7 @@ namespace BTCPayServer.Data
Success,
Warning
}
public string GetCssClass()
{
return Severity switch

View File

@ -1,37 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BTCPayServer.Data
{
public class InvoiceSearchData
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
[ForeignKey(nameof(InvoiceData))]
public string InvoiceDataId { get; set; }
public InvoiceData InvoiceData { get; set; }
public string Value { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<InvoiceSearchData>()
.HasOne(o => o.InvoiceData)
.WithMany(a => a.InvoiceSearchData)
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<InvoiceSearchData>()
.HasIndex(data => data.Value);
builder.Entity<InvoiceSearchData>()
.Property(a => a.Id)
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("MySql:ValueGeneratedOnAdd", true)
.HasAnnotation("Sqlite:Autoincrement", true);
}
}
}

View File

@ -1,3 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Data
@ -8,8 +11,6 @@ namespace BTCPayServer.Data
public InvoiceData Invoice { get; set; }
public string DeliveryId { get; set; }
public WebhookDeliveryData Delivery { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<InvoiceWebhookDeliveryData>()

View File

@ -19,7 +19,6 @@ namespace BTCPayServer.Data
public bool Seen { get; set; }
public byte[] Blob { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<NotificationData>()

View File

@ -5,16 +5,32 @@ namespace BTCPayServer.Data
{
public class PairedSINData
{
public string Id { get; set; }
public string Id
{
get; set;
}
public string StoreDataId { get; set; }
public string StoreDataId
{
get; set;
}
public StoreData StoreData { get; set; }
public string Label { get; set; }
public DateTimeOffset PairingTime { get; set; }
public string SIN { get; set; }
public string Label
{
get;
set;
}
public DateTimeOffset PairingTime
{
get;
set;
}
public string SIN
{
get; set;
}
internal static void OnModelCreating(ModelBuilder builder)
{

View File

@ -5,17 +5,45 @@ namespace BTCPayServer.Data
{
public class PairingCodeData
{
public string Id { get; set; }
public string Id
{
get; set;
}
[Obsolete("Unused")]
public string Facade { get; set; }
public string StoreDataId { get; set; }
public DateTimeOffset Expiration { get; set; }
public string Label { get; set; }
public string SIN { get; set; }
public DateTime DateCreated { get; set; }
public string TokenValue { get; set; }
public string Facade
{
get; set;
}
public string StoreDataId
{
get; set;
}
public DateTimeOffset Expiration
{
get;
set;
}
public string Label
{
get;
set;
}
public string SIN
{
get;
set;
}
public DateTime DateCreated
{
get;
set;
}
public string TokenValue
{
get;
set;
}
internal static void OnModelCreating(ModelBuilder builder)
{

View File

@ -4,13 +4,28 @@ namespace BTCPayServer.Data
{
public class PaymentData
{
public string Id { get; set; }
public string InvoiceDataId { get; set; }
public InvoiceData InvoiceData { get; set; }
public string Id
{
get; set;
}
public byte[] Blob { get; set; }
public bool Accounted { get; set; }
public string InvoiceDataId
{
get; set;
}
public InvoiceData InvoiceData
{
get; set;
}
public byte[] Blob
{
get; set;
}
public bool Accounted
{
get; set;
}
internal static void OnModelCreating(ModelBuilder builder)
{

View File

@ -6,7 +6,10 @@ namespace BTCPayServer.Data
public class PaymentRequestData
{
public string Id { get; set; }
public DateTimeOffset Created { get; set; }
public DateTimeOffset Created
{
get; set;
}
public string StoreDataId { get; set; }
public bool Archived { get; set; }
@ -16,7 +19,6 @@ namespace BTCPayServer.Data
public byte[] Blob { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<PaymentRequestData>()

View File

@ -21,7 +21,18 @@ namespace BTCPayServer.Data
public string Destination { get; set; }
public byte[] Blob { get; set; }
public byte[] Proof { get; set; }
public bool IsInPeriod(PullPaymentData pp, DateTimeOffset now)
{
var period = pp.GetPeriod(now);
if (period is { } p)
{
return p.Start <= Date && (p.End is DateTimeOffset end ? Date < end : true);
}
else
{
return false;
}
}
internal static void OnModelCreating(ModelBuilder builder)
{
@ -38,20 +49,6 @@ namespace BTCPayServer.Data
builder.Entity<PayoutData>()
.HasIndex(o => o.State);
}
// utility methods
public bool IsInPeriod(PullPaymentData pp, DateTimeOffset now)
{
var period = pp.GetPeriod(now);
if (period is { } p)
{
return p.Start <= Date && (p.End is DateTimeOffset end ? Date < end : true);
}
else
{
return false;
}
}
}
public enum PayoutState

View File

@ -4,7 +4,10 @@ namespace BTCPayServer.Data
{
public class PendingInvoiceData
{
public string Id { get; set; }
public string Id
{
get; set;
}
public InvoiceData InvoiceData { get; set; }
internal static void OnModelCreating(ModelBuilder builder)

View File

@ -7,7 +7,8 @@ namespace BTCPayServer.Data
{
[Key]
[MaxLength(100)]
public string Id { get; set; } // Id in the format [cryptocode]-[txid]
// Id in the format [cryptocode]-[txid]
public string Id { get; set; }
public DateTimeOffset BroadcastAt { get; set; }
public byte[] Blob { get; set; }
}

View File

@ -8,6 +8,53 @@ using NBitcoin;
namespace BTCPayServer.Data
{
public static class PayoutExtensions
{
public static IQueryable<PayoutData> GetPayoutInPeriod(this IQueryable<PayoutData> payouts, PullPaymentData pp)
{
return GetPayoutInPeriod(payouts, pp, DateTimeOffset.UtcNow);
}
public static IQueryable<PayoutData> GetPayoutInPeriod(this IQueryable<PayoutData> payouts, PullPaymentData pp, DateTimeOffset now)
{
var request = payouts.Where(p => p.PullPaymentDataId == pp.Id);
var period = pp.GetPeriod(now);
if (period is { } p)
{
var start = p.Start;
if (p.End is DateTimeOffset end)
{
return request.Where(p => p.Date >= start && p.Date < end);
}
else
{
return request.Where(p => p.Date >= start);
}
}
else
{
return request.Where(p => false);
}
}
public static string GetStateString(this PayoutState state)
{
switch (state)
{
case PayoutState.AwaitingApproval:
return "Awaiting Approval";
case PayoutState.AwaitingPayment:
return "Awaiting Payment";
case PayoutState.InProgress:
return "In Progress";
case PayoutState.Completed:
return "Completed";
case PayoutState.Cancelled:
return "Cancelled";
default:
throw new ArgumentOutOfRangeException(nameof(state), state, null);
}
}
}
public class PullPaymentData
{
[Key]
@ -24,16 +71,6 @@ namespace BTCPayServer.Data
public List<PayoutData> Payouts { get; set; }
public byte[] Blob { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<PullPaymentData>()
.HasIndex(o => o.StoreId);
builder.Entity<PullPaymentData>()
.HasOne(o => o.StoreData)
.WithMany(o => o.PullPayments).OnDelete(DeleteBehavior.Cascade);
}
public (DateTimeOffset Start, DateTimeOffset? End)? GetPeriod(DateTimeOffset now)
{
if (now < StartDate)
@ -84,54 +121,14 @@ namespace BTCPayServer.Data
{
return !Archived && !IsExpired(now) && HasStarted(now);
}
}
public static class PayoutExtensions
{
public static IQueryable<PayoutData> GetPayoutInPeriod(this IQueryable<PayoutData> payouts, PullPaymentData pp)
internal static void OnModelCreating(ModelBuilder builder)
{
return GetPayoutInPeriod(payouts, pp, DateTimeOffset.UtcNow);
}
public static IQueryable<PayoutData> GetPayoutInPeriod(this IQueryable<PayoutData> payouts, PullPaymentData pp, DateTimeOffset now)
{
var request = payouts.Where(p => p.PullPaymentDataId == pp.Id);
var period = pp.GetPeriod(now);
if (period is { } p)
{
var start = p.Start;
if (p.End is DateTimeOffset end)
{
return request.Where(p => p.Date >= start && p.Date < end);
}
else
{
return request.Where(p => p.Date >= start);
}
}
else
{
return request.Where(p => false);
}
}
public static string GetStateString(this PayoutState state)
{
switch (state)
{
case PayoutState.AwaitingApproval:
return "Awaiting Approval";
case PayoutState.AwaitingPayment:
return "Awaiting Payment";
case PayoutState.InProgress:
return "In Progress";
case PayoutState.Completed:
return "Completed";
case PayoutState.Cancelled:
return "Cancelled";
default:
throw new ArgumentOutOfRangeException(nameof(state), state, null);
}
builder.Entity<PullPaymentData>()
.HasIndex(o => o.StoreId);
builder.Entity<PullPaymentData>()
.HasOne(o => o.StoreData)
.WithMany(o => o.PullPayments).OnDelete(DeleteBehavior.Cascade);
}
}
}

View File

@ -13,7 +13,6 @@ namespace BTCPayServer.Data
public PullPaymentData PullPaymentData { get; set; }
public InvoiceData InvoiceData { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<RefundData>()

View File

@ -2,8 +2,14 @@ namespace BTCPayServer.Data
{
public class SettingData
{
public string Id { get; set; }
public string Id
{
get; set;
}
public string Value { get; set; }
public string Value
{
get; set;
}
}
}

View File

@ -5,6 +5,7 @@ using BTCPayServer.Client.Models;
namespace BTCPayServer.Data
{
public class StoreData
{
public string Id { get; set; }
@ -42,4 +43,6 @@ namespace BTCPayServer.Data
public List<PairedSINData> PairedSINs { get; set; }
public IEnumerable<APIKeyData> APIKeys { get; set; }
}
}

View File

@ -1,4 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.EntityFrameworkCore;
using System.Linq;
namespace BTCPayServer.Data
{
@ -9,7 +13,6 @@ namespace BTCPayServer.Data
public WebhookData Webhook { get; set; }
public StoreData Store { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<StoreWebhookData>()

View File

@ -12,6 +12,9 @@ namespace BTCPayServer.Data
public string StorageFileName { get; set; }
public DateTime Timestamp { get; set; }
public string ApplicationUserId { get; set; }
public ApplicationUser ApplicationUser { get; set; }
public ApplicationUser ApplicationUser
{
get; set;
}
}
}

View File

@ -4,13 +4,28 @@ namespace BTCPayServer.Data
{
public class UserStore
{
public string ApplicationUserId { get; set; }
public ApplicationUser ApplicationUser { get; set; }
public string StoreDataId { get; set; }
public StoreData StoreData { get; set; }
public string Role { get; set; }
public string ApplicationUserId
{
get; set;
}
public ApplicationUser ApplicationUser
{
get; set;
}
public string StoreDataId
{
get; set;
}
public StoreData StoreData
{
get; set;
}
public string Role
{
get;
set;
}
internal static void OnModelCreating(ModelBuilder builder)
{

View File

@ -1,4 +1,6 @@
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
namespace BTCPayServer.Data
{
@ -9,8 +11,6 @@ namespace BTCPayServer.Data
public string TransactionId { get; set; }
public string Labels { get; set; }
public byte[] Blob { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<WalletTransactionData>()
@ -26,4 +26,11 @@ namespace BTCPayServer.Data
.WithMany(w => w.WalletTransactions).OnDelete(DeleteBehavior.Cascade);
}
}
public class WalletTransactionInfo
{
public string Comment { get; set; } = string.Empty;
[JsonIgnore]
public HashSet<string> Labels { get; set; } = new HashSet<string>();
}
}

View File

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Data
{
@ -7,7 +10,11 @@ namespace BTCPayServer.Data
{
[Key]
[MaxLength(25)]
public string Id { get; set; }
public string Id
{
get;
set;
}
[Required]
public byte[] Blob { get; set; }
public List<WebhookDeliveryData> Deliveries { get; set; }

View File

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Data
@ -15,12 +18,13 @@ namespace BTCPayServer.Data
public WebhookData Webhook { get; set; }
[Required]
public DateTimeOffset Timestamp { get; set; }
public DateTimeOffset Timestamp
{
get; set;
}
[Required]
public byte[] Blob { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<WebhookDeliveryData>()

View File

@ -11,16 +11,13 @@ namespace BTCPayServer.Migrations
{
protected override void Up(MigrationBuilder migrationBuilder)
{
int? maxLength = this.IsMySql(migrationBuilder.ActiveProvider) ? (int?)255 : null;
migrationBuilder.DropTable(
name: "RefundAddresses");
migrationBuilder.AddColumn<string>(
name: "CurrentRefundId",
table: "Invoices",
nullable: true,
maxLength: maxLength);
nullable: true);
migrationBuilder.CreateTable(
name: "Notifications",
@ -76,7 +73,7 @@ namespace BTCPayServer.Migrations
PullPaymentDataId = table.Column<string>(maxLength: 30, nullable: true),
State = table.Column<string>(maxLength: 20, nullable: false),
PaymentMethodId = table.Column<string>(maxLength: 20, nullable: false),
Destination = table.Column<string>(maxLength: maxLength, nullable: true),
Destination = table.Column<string>(nullable: true),
Blob = table.Column<byte[]>(nullable: true),
Proof = table.Column<byte[]>(nullable: true)
},
@ -95,8 +92,8 @@ namespace BTCPayServer.Migrations
name: "Refunds",
columns: table => new
{
InvoiceDataId = table.Column<string>(maxLength: maxLength, nullable: false),
PullPaymentDataId = table.Column<string>(maxLength: maxLength, nullable: false)
InvoiceDataId = table.Column<string>(nullable: false),
PullPaymentDataId = table.Column<string>(nullable: false)
},
constraints: table =>
{

View File

@ -27,8 +27,8 @@ namespace BTCPayServer.Migrations
name: "StoreWebhooks",
columns: table => new
{
StoreId = table.Column<string>(maxLength: 50, nullable: false),
WebhookId = table.Column<string>(maxLength: 25, nullable: false)
StoreId = table.Column<string>(nullable: false),
WebhookId = table.Column<string>(nullable: false)
},
constraints: table =>
{
@ -71,8 +71,8 @@ namespace BTCPayServer.Migrations
name: "InvoiceWebhookDeliveries",
columns: table => new
{
InvoiceId = table.Column<string>(maxLength: 255, nullable: false),
DeliveryId = table.Column<string>(maxLength: 100, nullable: false)
InvoiceId = table.Column<string>(nullable: false),
DeliveryId = table.Column<string>(nullable: false)
},
constraints: table =>
{

View File

@ -1,36 +0,0 @@
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
namespace BTCPayServer.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20201208054211_invoicesorderindex")]
public partial class invoicesorderindex : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
if (!migrationBuilder.IsSqlite())
{
migrationBuilder.AlterColumn<string>(
name: "OrderId",
table: "Invoices",
maxLength: 100,
nullable: true,
oldClrType: typeof(string));
}
migrationBuilder.CreateIndex(
name: "IX_Invoices_OrderId",
table: "Invoices",
column: "OrderId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Invoices_OrderId",
table: "Invoices");
}
}
}

View File

@ -1,55 +0,0 @@
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BTCPayServer.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20201228225040_AddingInvoiceSearchesTable")]
public partial class AddingInvoiceSearchesTable : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "InvoiceSearches",
columns: table => new
{
Id = table.Column<int>(nullable: false)
// manually added
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.Annotation("MySql:ValueGeneratedOnAdd", true)
.Annotation("Sqlite:Autoincrement", true),
// eof manually added
InvoiceDataId = table.Column<string>(maxLength: 255, nullable: true),
Value = table.Column<string>(maxLength: 512, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_InvoiceSearches", x => x.Id);
table.ForeignKey(
name: "FK_InvoiceSearches_Invoices_InvoiceDataId",
column: x => x.InvoiceDataId,
principalTable: "Invoices",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_InvoiceSearches_InvoiceDataId",
table: "InvoiceSearches",
column: "InvoiceDataId");
migrationBuilder.CreateIndex(
name: "IX_InvoiceSearches_Value",
table: "InvoiceSearches",
column: "Value");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "InvoiceSearches");
}
}
}

View File

@ -4,7 +4,6 @@ using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BTCPayServer.Migrations
{
@ -229,8 +228,6 @@ namespace BTCPayServer.Migrations
b.HasKey("Id");
b.HasIndex("OrderId");
b.HasIndex("StoreDataId");
b.HasIndex("Id", "CurrentRefundId");
@ -260,30 +257,6 @@ namespace BTCPayServer.Migrations
b.ToTable("InvoiceEvents");
});
modelBuilder.Entity("BTCPayServer.Data.InvoiceSearchData", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasAnnotation("MySql:ValueGeneratedOnAdd", true)
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("Sqlite:Autoincrement", true);
b.Property<string>("InvoiceDataId")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("InvoiceDataId");
b.HasIndex("Value");
b.ToTable("InvoiceSearches");
});
modelBuilder.Entity("BTCPayServer.Data.InvoiceWebhookDeliveryData", b =>
{
b.Property<string>("InvoiceId")
@ -988,14 +961,6 @@ namespace BTCPayServer.Migrations
.IsRequired();
});
modelBuilder.Entity("BTCPayServer.Data.InvoiceSearchData", b =>
{
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
.WithMany("InvoiceSearchData")
.HasForeignKey("InvoiceDataId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("BTCPayServer.Data.InvoiceWebhookDeliveryData", b =>
{
b.HasOne("BTCPayServer.Data.WebhookDeliveryData", "Delivery")

View File

@ -43,7 +43,6 @@ namespace BTCPayServer.PluginPacker
}
ZipFile.CreateFromDirectory(directory, outputFile + ".btcpay", CompressionLevel.Optimal, false);
File.WriteAllText(outputFile + ".btcpay.json", json);
Console.WriteLine($"Created {outputFile}.btcpay at {directory}");
}
private static Type[] GetAllExtensionTypesFromAssembly(Assembly assembly)

View File

@ -1,8 +1,9 @@
using System.Reflection;
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Plugins.Test.Migrations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Options;
namespace BTCPayServer.Plugins.Test
{
@ -22,7 +23,7 @@ namespace BTCPayServer.Plugins.Test
public class TestPluginDbContextFactory : BaseDbContextFactory<TestPluginDbContext>
{
public TestPluginDbContextFactory(IOptions<DatabaseOptions> options) : base(options, "BTCPayServer.Plugins.Test")
public TestPluginDbContextFactory(DatabaseOptions options) : base(options, "BTCPayServer.Plugins.Test")
{
}

View File

@ -6,7 +6,7 @@
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.6.0" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
<PackageReference Include="NBitcoin" Version="5.0.73" />
<PackageReference Include="NBitcoin" Version="5.0.60" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="DigitalRuby.ExchangeSharp" Version="0.6.3" />
</ItemGroup>

File diff suppressed because one or more lines are too long

View File

@ -1,31 +1,60 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Configuration;
using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.Events;
using BTCPayServer.HostedServices;
using BTCPayServer.Lightning;
using BTCPayServer.Models;
using BTCPayServer.Models.AccountViewModels;
using BTCPayServer.Models.AppViewModels;
using BTCPayServer.Models.InvoicingModels;
using BTCPayServer.Models.ServerViewModels;
using BTCPayServer.Models.StoreViewModels;
using BTCPayServer.Models.WalletViewModels;
using BTCPayServer.Payments;
using BTCPayServer.Payments.Bitcoin;
using BTCPayServer.Payments.Lightning;
using BTCPayServer.Rating;
using BTCPayServer.Security.Bitpay;
using BTCPayServer.Services;
using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Rates;
using BTCPayServer.Tests.Logging;
using BTCPayServer.U2F.Models;
using BTCPayServer.Validation;
using ExchangeSharp;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NBitcoin;
using NBitcoin.Scripting.Parser;
using NBitcoin.DataEncoders;
using NBitcoin.Payment;
using NBitpayClient;
using NBXplorer.DerivationStrategy;
using NBXplorer.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
using OpenQA.Selenium;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
using RatesViewModel = BTCPayServer.Models.StoreViewModels.RatesViewModel;
namespace BTCPayServer.Tests
{
@ -42,7 +71,7 @@ namespace BTCPayServer.Tests
[Trait("Integration", "Integration")]
[Trait("Altcoins", "Altcoins")]
[Trait("Lightning", "Lightning")]
public async Task CanSetupWallet()
public async Task CanAddDerivationSchemes()
{
using (var tester = ServerTester.Create())
{
@ -50,7 +79,7 @@ namespace BTCPayServer.Tests
tester.ActivateLightning();
await tester.StartAsync();
var user = tester.NewAccount();
user.GrantAccess(true);
user.GrantAccess();
user.RegisterDerivationScheme("BTC");
user.RegisterDerivationScheme("LTC");
user.RegisterLightningNode("BTC", LightningConnectionType.CLightning);
@ -69,37 +98,37 @@ namespace BTCPayServer.Tests
Assert.Equal(3, invoice.CryptoInfo.Length);
var controller = user.GetController<StoresController>();
var lightningVm = (LightningNodeViewModel)Assert.IsType<ViewResult>(controller.AddLightningNode(user.StoreId, "BTC")).Model;
Assert.True(lightningVm.Enabled);
lightningVm.Enabled = false;
controller.AddLightningNode(user.StoreId, lightningVm, "save", "BTC").GetAwaiter().GetResult();
lightningVm = (LightningNodeViewModel)Assert.IsType<ViewResult>(controller.AddLightningNode(user.StoreId, "BTC")).Model;
Assert.False(lightningVm.Enabled);
WalletSetupViewModel setupVm;
var storeId = user.StoreId;
var cryptoCode = "BTC";
var response = await controller.GenerateWallet(storeId, cryptoCode, WalletSetupMethod.GenerateOptions, new GenerateWalletRequest());
Assert.IsType<ViewResult>(response);
// Get setup view model from modify action
response = await controller.ModifyWallet(new WalletSetupViewModel { StoreId = storeId, CryptoCode = cryptoCode });
setupVm = (WalletSetupViewModel)Assert.IsType<ViewResult>(response).Model;
Assert.True(setupVm.Enabled);
var lightningVM =
(LightningNodeViewModel)Assert.IsType<ViewResult>(controller.AddLightningNode(user.StoreId, "BTC"))
.Model;
Assert.True(lightningVM.Enabled);
lightningVM.Enabled = false;
controller.AddLightningNode(user.StoreId, lightningVM, "save", "BTC").GetAwaiter().GetResult();
lightningVM =
(LightningNodeViewModel)Assert.IsType<ViewResult>(controller.AddLightningNode(user.StoreId, "BTC"))
.Model;
Assert.False(lightningVM.Enabled);
// Only Enabling/Disabling the payment method must redirect to store page
setupVm.Enabled = false;
response = controller.UpdateWallet(setupVm).GetAwaiter().GetResult();
Assert.IsType<RedirectToActionResult>(response);
var derivationVM = (DerivationSchemeViewModel)Assert
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
Assert.True(derivationVM.Enabled);
derivationVM.Enabled = false;
Assert.IsType<RedirectToActionResult>(controller.AddDerivationScheme(user.StoreId, derivationVM, "BTC")
.GetAwaiter().GetResult());
derivationVM = (DerivationSchemeViewModel)Assert
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
Assert.False(derivationVM.Enabled);
response = await controller.ModifyWallet(new WalletSetupViewModel { StoreId = storeId, CryptoCode = cryptoCode });
setupVm = (WalletSetupViewModel)Assert.IsType<ViewResult>(response).Model;
Assert.False(setupVm.Enabled);
var oldScheme = setupVm.DerivationScheme;
// Clicking next without changing anything should send to the confirmation screen
derivationVM = (DerivationSchemeViewModel)Assert
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
derivationVM = (DerivationSchemeViewModel)Assert.IsType<ViewResult>(controller
.AddDerivationScheme(user.StoreId, derivationVM, "BTC").GetAwaiter().GetResult()).Model;
Assert.True(derivationVM.Confirmation);
invoice = user.BitPay.CreateInvoice(
new Invoice
new Invoice()
{
Price = 1.5m,
Currency = "USD",
@ -113,57 +142,76 @@ namespace BTCPayServer.Tests
Assert.Equal("LTC", invoice.CryptoInfo[0].CryptoCode);
// Removing the derivation scheme, should redirect to store page
response = controller.ConfirmDeleteWallet(user.StoreId, "BTC").GetAwaiter().GetResult();
Assert.IsType<RedirectToActionResult>(response);
var oldScheme = derivationVM.DerivationScheme;
derivationVM = (DerivationSchemeViewModel)Assert
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
derivationVM.DerivationScheme = null;
Assert.IsType<RedirectToActionResult>(controller.AddDerivationScheme(user.StoreId, derivationVM, "BTC")
.GetAwaiter().GetResult());
// Setting it again should show the confirmation page
response = await controller.UpdateWallet(new WalletSetupViewModel {StoreId = storeId, CryptoCode = cryptoCode, DerivationScheme = oldScheme });
setupVm = (WalletSetupViewModel)Assert.IsType<ViewResult>(response).Model;
Assert.True(setupVm.Confirmation);
// Setting it again should redirect to the confirmation page
derivationVM = (DerivationSchemeViewModel)Assert
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
derivationVM.DerivationScheme = oldScheme;
derivationVM = (DerivationSchemeViewModel)Assert.IsType<ViewResult>(controller
.AddDerivationScheme(user.StoreId, derivationVM, "BTC").GetAwaiter().GetResult()).Model;
Assert.True(derivationVM.Confirmation);
// The following part posts a wallet update, confirms it and checks the result
// cobo vault file
//cobo vault file
var content = "{\"ExtPubKey\":\"xpub6CEqRFZ7yZxCFXuEWZBAdnC8bdvu9SRHevaoU2SsW9ZmKhrCShmbpGZWwaR15hdLURf8hg47g4TpPGaqEU8hw5LEJCE35AUhne67XNyFGBk\",\"MasterFingerprint\":\"7a7563b5\",\"DerivationPath\":\"M\\/84'\\/0'\\/0'\",\"CoboVaultFirmwareVersion\":\"1.2.0(BTC-Only)\"}";
response = await controller.UpdateWallet(new WalletSetupViewModel {StoreId = storeId, CryptoCode = cryptoCode, WalletFile = TestUtils.GetFormFile("cobovault.json", content)});
setupVm = (WalletSetupViewModel)Assert.IsType<ViewResult>(response).Model;
Assert.True(setupVm.Confirmation);
response = await controller.UpdateWallet(setupVm);
Assert.IsType<RedirectToActionResult>(response);
response = await controller.ModifyWallet(new WalletSetupViewModel { StoreId = storeId, CryptoCode = cryptoCode });
setupVm = (WalletSetupViewModel)Assert.IsType<ViewResult>(response).Model;
Assert.Equal("CoboVault", setupVm.Source);
derivationVM = (DerivationSchemeViewModel)Assert
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
derivationVM.WalletFile = TestUtils.GetFormFile("wallet3.json", content);
derivationVM.Enabled = true;
derivationVM = (DerivationSchemeViewModel)Assert.IsType<ViewResult>(controller
.AddDerivationScheme(user.StoreId, derivationVM, "BTC").GetAwaiter().GetResult()).Model;
Assert.True(derivationVM.Confirmation);
Assert.IsType<RedirectToActionResult>(controller.AddDerivationScheme(user.StoreId, derivationVM, "BTC")
.GetAwaiter().GetResult());
//wasabi wallet file
content =
"{\r\n \"EncryptedSecret\": \"6PYWBQ1zsukowsnTNA57UUx791aBuJusm7E4egXUmF5WGw3tcdG3cmTL57\",\r\n \"ChainCode\": \"waSIVbn8HaoovoQg/0t8IS1+ZCxGsJRGFT21i06nWnc=\",\r\n \"MasterFingerprint\": \"7a7563b5\",\r\n \"ExtPubKey\": \"xpub6CEqRFZ7yZxCFXuEWZBAdnC8bdvu9SRHevaoU2SsW9ZmKhrCShmbpGZWwaR15hdLURf8hg47g4TpPGaqEU8hw5LEJCE35AUhne67XNyFGBk\",\r\n \"PasswordVerified\": false,\r\n \"MinGapLimit\": 21,\r\n \"AccountKeyPath\": \"84'/0'/0'\",\r\n \"BlockchainState\": {\r\n \"Network\": \"RegTest\",\r\n \"Height\": \"0\"\r\n },\r\n \"HdPubKeys\": []\r\n}";
derivationVM = (DerivationSchemeViewModel)Assert
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
derivationVM.WalletFile = TestUtils.GetFormFile("wallet4.json", content);
derivationVM.Enabled = true;
derivationVM = (DerivationSchemeViewModel)Assert.IsType<ViewResult>(controller
.AddDerivationScheme(user.StoreId, derivationVM, "BTC").GetAwaiter().GetResult()).Model;
Assert.True(derivationVM.Confirmation);
Assert.IsType<RedirectToActionResult>(controller.AddDerivationScheme(user.StoreId, derivationVM, "BTC")
.GetAwaiter().GetResult());
// wasabi wallet file
content = "{\r\n \"EncryptedSecret\": \"6PYWBQ1zsukowsnTNA57UUx791aBuJusm7E4egXUmF5WGw3tcdG3cmTL57\",\r\n \"ChainCode\": \"waSIVbn8HaoovoQg/0t8IS1+ZCxGsJRGFT21i06nWnc=\",\r\n \"MasterFingerprint\": \"7a7563b5\",\r\n \"ExtPubKey\": \"xpub6CEqRFZ7yZxCFXuEWZBAdnC8bdvu9SRHevaoU2SsW9ZmKhrCShmbpGZWwaR15hdLURf8hg47g4TpPGaqEU8hw5LEJCE35AUhne67XNyFGBk\",\r\n \"PasswordVerified\": false,\r\n \"MinGapLimit\": 21,\r\n \"AccountKeyPath\": \"84'/0'/0'\",\r\n \"BlockchainState\": {\r\n \"Network\": \"RegTest\",\r\n \"Height\": \"0\"\r\n },\r\n \"HdPubKeys\": []\r\n}";
response = await controller.UpdateWallet(new WalletSetupViewModel {StoreId = storeId, CryptoCode = cryptoCode, WalletFile = TestUtils.GetFormFile("wasabi.json", content)});
setupVm = (WalletSetupViewModel)Assert.IsType<ViewResult>(response).Model;
Assert.True(setupVm.Confirmation);
response = await controller.UpdateWallet(setupVm);
Assert.IsType<RedirectToActionResult>(response);
response = await controller.ModifyWallet(new WalletSetupViewModel { StoreId = storeId, CryptoCode = cryptoCode });
setupVm = (WalletSetupViewModel)Assert.IsType<ViewResult>(response).Model;
Assert.Equal("WasabiFile", setupVm.Source);
// Can we upload coldcard settings? (Should fail, we are giving a mainnet file to a testnet network)
content = "{\"keystore\": {\"ckcc_xpub\": \"xpub661MyMwAqRbcGVBsTGeNZN6QGVHmMHLdSA4FteGsRrEriu4pnVZMZWnruFFFXkMnyoBjyHndD3Qwcfz4MPzBUxjSevweNFQx7SAYZATtcDw\", \"xpub\": \"ypub6WWc2gWwHbdnAAyJDnR4SPL1phRh7REqrPBfZeizaQ1EmTshieRXJC3Z5YoU4wkcdKHEjQGkh6AYEzCQC1Kz3DNaWSwdc1pc8416hAjzqyD\", \"label\": \"Coldcard Import 0x60d1af8b\", \"ckcc_xfp\": 1624354699, \"type\": \"hardware\", \"hw_type\": \"coldcard\", \"derivation\": \"m/49'/0'/0'\"}, \"wallet_type\": \"standard\", \"use_encryption\": false, \"seed_version\": 17}";
response = await controller.UpdateWallet(new WalletSetupViewModel {StoreId = storeId, CryptoCode = cryptoCode, WalletFile = TestUtils.GetFormFile("coldcard-ypub.json", content)});
setupVm = (WalletSetupViewModel)Assert.IsType<ViewResult>(response).Model;
Assert.False(setupVm.Confirmation); // Should fail, we are giving a mainnet file to a testnet network
derivationVM = (DerivationSchemeViewModel)Assert
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
content =
"{\"keystore\": {\"ckcc_xpub\": \"xpub661MyMwAqRbcGVBsTGeNZN6QGVHmMHLdSA4FteGsRrEriu4pnVZMZWnruFFFXkMnyoBjyHndD3Qwcfz4MPzBUxjSevweNFQx7SAYZATtcDw\", \"xpub\": \"ypub6WWc2gWwHbdnAAyJDnR4SPL1phRh7REqrPBfZeizaQ1EmTshieRXJC3Z5YoU4wkcdKHEjQGkh6AYEzCQC1Kz3DNaWSwdc1pc8416hAjzqyD\", \"label\": \"Coldcard Import 0x60d1af8b\", \"ckcc_xfp\": 1624354699, \"type\": \"hardware\", \"hw_type\": \"coldcard\", \"derivation\": \"m/49'/0'/0'\"}, \"wallet_type\": \"standard\", \"use_encryption\": false, \"seed_version\": 17}";
derivationVM.WalletFile = TestUtils.GetFormFile("wallet.json", content);
derivationVM = (DerivationSchemeViewModel)Assert.IsType<ViewResult>(controller
.AddDerivationScheme(user.StoreId, derivationVM, "BTC").GetAwaiter().GetResult()).Model;
Assert.False(derivationVM
.Confirmation); // Should fail, we are giving a mainnet file to a testnet network
// And with a good file? (upub)
content = "{\"keystore\": {\"ckcc_xpub\": \"tpubD6NzVbkrYhZ4YHNiuTdTmHRmbcPRLfqgyneZFCL1mkzkUBjXriQShxTh9HL34FK2mhieasJVk9EzJrUfkFqRNQBjiXgx3n5BhPkxKBoFmaS\", \"xpub\": \"upub5DBYp1qGgsTrkzCptMGZc2x18pquLwGrBw6nS59T4NViZ4cni1mGowQzziy85K8vzkp1jVtWrSkLhqk9KDfvrGeB369wGNYf39kX8rQfiLn\", \"label\": \"Coldcard Import 0x60d1af8b\", \"ckcc_xfp\": 1624354699, \"type\": \"hardware\", \"hw_type\": \"coldcard\", \"derivation\": \"m/49'/0'/0'\"}, \"wallet_type\": \"standard\", \"use_encryption\": false, \"seed_version\": 17}";
response = await controller.UpdateWallet(new WalletSetupViewModel {StoreId = storeId, CryptoCode = cryptoCode, WalletFile = TestUtils.GetFormFile("coldcard-upub.json", content)});
setupVm = (WalletSetupViewModel)Assert.IsType<ViewResult>(response).Model;
Assert.True(setupVm.Confirmation);
response = await controller.UpdateWallet(setupVm);
Assert.IsType<RedirectToActionResult>(response);
response = await controller.ModifyWallet(new WalletSetupViewModel { StoreId = storeId, CryptoCode = cryptoCode });
setupVm = (WalletSetupViewModel)Assert.IsType<ViewResult>(response).Model;
Assert.Equal("ElectrumFile", setupVm.Source);
content =
"{\"keystore\": {\"ckcc_xpub\": \"tpubD6NzVbkrYhZ4YHNiuTdTmHRmbcPRLfqgyneZFCL1mkzkUBjXriQShxTh9HL34FK2mhieasJVk9EzJrUfkFqRNQBjiXgx3n5BhPkxKBoFmaS\", \"xpub\": \"upub5DBYp1qGgsTrkzCptMGZc2x18pquLwGrBw6nS59T4NViZ4cni1mGowQzziy85K8vzkp1jVtWrSkLhqk9KDfvrGeB369wGNYf39kX8rQfiLn\", \"label\": \"Coldcard Import 0x60d1af8b\", \"ckcc_xfp\": 1624354699, \"type\": \"hardware\", \"hw_type\": \"coldcard\", \"derivation\": \"m/49'/0'/0'\"}, \"wallet_type\": \"standard\", \"use_encryption\": false, \"seed_version\": 17}";
derivationVM = (DerivationSchemeViewModel)Assert
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
derivationVM.WalletFile = TestUtils.GetFormFile("wallet2.json", content);
derivationVM.Enabled = true;
derivationVM = (DerivationSchemeViewModel)Assert.IsType<ViewResult>(controller
.AddDerivationScheme(user.StoreId, derivationVM, "BTC").GetAwaiter().GetResult()).Model;
Assert.True(derivationVM.Confirmation);
Assert.IsType<RedirectToActionResult>(controller.AddDerivationScheme(user.StoreId, derivationVM, "BTC")
.GetAwaiter().GetResult());
// Now let's check that no data has been lost in the process
var store = tester.PayTester.StoreRepository.FindStore(storeId).GetAwaiter().GetResult();
var store = tester.PayTester.StoreRepository.FindStore(user.StoreId).GetAwaiter().GetResult();
var onchainBTC = store.GetSupportedPaymentMethods(tester.PayTester.Networks)
#pragma warning disable CS0618 // Type or member is obsolete
.OfType<DerivationSchemeSettings>().First(o => o.PaymentId.IsBTCOnChain);
@ -238,7 +286,7 @@ namespace BTCPayServer.Tests
await tester.StartAsync();
await tester.EnsureChannelsSetup();
var user = tester.NewAccount();
user.GrantAccess(true);
user.GrantAccess();
user.RegisterLightningNode("BTC", LightningConnectionType.Charge);
user.RegisterDerivationScheme("BTC");
user.RegisterDerivationScheme("LTC");
@ -246,6 +294,7 @@ namespace BTCPayServer.Tests
var invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(100, "BTC"));
Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count);
invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(100, "BTC")
{
SupportedTransactionCurrencies = new Dictionary<string, InvoiceSupportedTransactionCurrency>()
@ -429,21 +478,21 @@ namespace BTCPayServer.Tests
//there should be three now
invoiceId = s.CreateInvoice(store.storeName, 10, "USD", "a@g.com");
s.GoToInvoiceCheckout(invoiceId);
var currencyDropdownButton = s.Driver.FindElement(By.ClassName("payment__currencies"));
var currencyDropdownButton = s.Driver.WaitForElement(By.ClassName("payment__currencies"));
Assert.Contains("BTC", currencyDropdownButton.Text);
currencyDropdownButton.Click();
var elements = s.Driver.FindElement(By.ClassName("vex-content")).FindElements(By.ClassName("vexmenuitem"));
Assert.Equal(3, elements.Count);
elements.Single(element => element.Text.Contains("LTC")).Click();
currencyDropdownButton = s.Driver.FindElement(By.ClassName("payment__currencies"));
currencyDropdownButton = s.Driver.WaitForElement(By.ClassName("payment__currencies"));
Assert.Contains("LTC", currencyDropdownButton.Text);
currencyDropdownButton.Click();
elements = s.Driver.FindElement(By.ClassName("vex-content")).FindElements(By.ClassName("vexmenuitem"));
elements.Single(element => element.Text.Contains("Lightning")).Click();
currencyDropdownButton = s.Driver.FindElement(By.ClassName("payment__currencies"));
currencyDropdownButton = s.Driver.WaitForElement(By.ClassName("payment__currencies"));
Assert.Contains("Lightning", currencyDropdownButton.Text);
s.Driver.Quit();
@ -739,7 +788,7 @@ noninventoryitem:
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result);
//inventoryitem has 1 item available
await tester.WaitForEvent<AppInventoryUpdaterHostedService.UpdateAppInventory>(() =>
await tester.WaitForEvent<InvoiceEvent>(() =>
{
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "inventoryitem").Result);
@ -822,11 +871,11 @@ normal:
{
#pragma warning disable CS0618
var dummy = new Key().PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.RegTest).ToString();
var networkProvider = new BTCPayNetworkProvider(ChainName.Regtest);
var networkProvider = new BTCPayNetworkProvider(NetworkType.Regtest);
var paymentMethodHandlerDictionary = new PaymentMethodHandlerDictionary(new IPaymentMethodHandler[]
{
new BitcoinLikePaymentHandler(null, networkProvider, null, null, null),
new LightningLikePaymentHandler(null, null, networkProvider, null, null, null),
new LightningLikePaymentHandler(null, null, networkProvider, null, null),
});
var networkBTC = networkProvider.GetNetwork("BTC");
var networkLTC = networkProvider.GetNetwork("LTC");
@ -902,9 +951,9 @@ normal:
[Trait("Altcoins", "Altcoins")]
public void CanParseDerivationScheme()
{
var testnetNetworkProvider = new BTCPayNetworkProvider(ChainName.Testnet);
var regtestNetworkProvider = new BTCPayNetworkProvider(ChainName.Regtest);
var mainnetNetworkProvider = new BTCPayNetworkProvider(ChainName.Mainnet);
var testnetNetworkProvider = new BTCPayNetworkProvider(NetworkType.Testnet);
var regtestNetworkProvider = new BTCPayNetworkProvider(NetworkType.Regtest);
var mainnetNetworkProvider = new BTCPayNetworkProvider(NetworkType.Mainnet);
var testnetParser = new DerivationSchemeParser(testnetNetworkProvider.GetNetwork<BTCPayNetwork>("BTC"));
var mainnetParser = new DerivationSchemeParser(mainnetNetworkProvider.GetNetwork<BTCPayNetwork>("BTC"));
NBXplorer.DerivationStrategy.DerivationStrategyBase result;
@ -991,99 +1040,6 @@ normal:
Assert.Equal(
"tpubDDdeNbNDRgqestPX5XEJM8ELAq6eR5cne5RPbBHHvWSSiLHNHehsrn1kGCijMnHFSsFFQMqHcdMfGzDL3pWHRasPMhcGRqZ4tFankQ3i4ok-[legacy]",
parsed.ToString());
//let's test output descriptor parsing support
//we don't support every descriptor, only the ones which represent an HD wallet with stndard derivation paths
Assert.Throws<FormatException>(() => mainnetParser.ParseOutputDescriptor("pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)"));
Assert.Throws<FormatException>(() => mainnetParser.ParseOutputDescriptor("pkh(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)"));
Assert.Throws<FormatException>(() => mainnetParser.ParseOutputDescriptor("wpkh(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9)"));
Assert.Throws<FormatException>(() => mainnetParser.ParseOutputDescriptor("sh(wpkh(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))"));
Assert.Throws<FormatException>(() => mainnetParser.ParseOutputDescriptor("combo(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)"));
Assert.Throws<FormatException>(() => mainnetParser.ParseOutputDescriptor("sh(wsh(pkh(02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13)))"));
Assert.Throws<FormatException>(() => mainnetParser.ParseOutputDescriptor("multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)"));
Assert.Throws<FormatException>(() => mainnetParser.ParseOutputDescriptor("sh(multi(2,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01,03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe))"));
Assert.Throws<FormatException>(() => mainnetParser.ParseOutputDescriptor("sh(sortedmulti(2,03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01))"));
//let's see what we actually support now
//standard legacy hd wallet
var parsedDescriptor = mainnetParser.ParseOutputDescriptor(
"pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*)");
Assert.Equal(KeyPath.Parse("44'/0'/0'"),Assert.Single(parsedDescriptor.Item2).KeyPath);
Assert.Equal( HDFingerprint.Parse("d34db33f"),Assert.Single(parsedDescriptor.Item2).MasterFingerprint);
Assert.Equal("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL-[legacy]",parsedDescriptor.Item1.ToString() );
//masterfingerprint and key path are optional
parsedDescriptor = mainnetParser.ParseOutputDescriptor(
"pkh([d34db33f]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*)");
Assert.Equal("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL-[legacy]",parsedDescriptor.Item1.ToString() );
//a master fingerprint must always be present if youre providing rooted path
Assert.Throws<ParsingException>(() => mainnetParser.ParseOutputDescriptor("pkh([44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*)"));
parsedDescriptor = mainnetParser.ParseOutputDescriptor(
"pkh(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*)");
Assert.Equal("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL-[legacy]",parsedDescriptor.Item1.ToString() );
//but a different deriv path from standard (0/*) is not supported
Assert.Throws<FormatException>(() => mainnetParser.ParseOutputDescriptor("pkh(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*)"));
//p2sh-segwit hd wallet
parsedDescriptor = mainnetParser.ParseOutputDescriptor(
"sh(wpkh([d34db33f/49'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*))");
Assert.Equal(KeyPath.Parse("49'/0'/0'"),Assert.Single(parsedDescriptor.Item2).KeyPath);
Assert.Equal( HDFingerprint.Parse("d34db33f"),Assert.Single(parsedDescriptor.Item2).MasterFingerprint);
Assert.Equal("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL-[p2sh]",parsedDescriptor.Item1.ToString() );
//segwit hd wallet
parsedDescriptor = mainnetParser.ParseOutputDescriptor(
"wpkh([d34db33f/84'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*)");
Assert.Equal(KeyPath.Parse("84'/0'/0'"),Assert.Single(parsedDescriptor.Item2).KeyPath);
Assert.Equal( HDFingerprint.Parse("d34db33f"),Assert.Single(parsedDescriptor.Item2).MasterFingerprint);
Assert.Equal("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL",parsedDescriptor.Item1.ToString() );
//multisig tests
//legacy
parsedDescriptor = mainnetParser.ParseOutputDescriptor(
"sh(multi(1,[d34db33f/45'/0]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,[d34db33f/45'/0]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*))");
Assert.Equal(2, parsedDescriptor.Item2.Length);
var strat = Assert.IsType<MultisigDerivationStrategy>(Assert.IsType<P2SHDerivationStrategy>(parsedDescriptor.Item1).Inner);
Assert.True(strat.IsLegacy);
Assert.Equal(1,strat.RequiredSignatures);
Assert.Equal(2,strat.Keys.Count());
Assert.False(strat.LexicographicOrder);
Assert.Equal("1-of-xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL-xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL-[legacy]-[keeporder]",parsedDescriptor.Item1.ToString() );
//segwit
parsedDescriptor = mainnetParser.ParseOutputDescriptor(
"wsh(multi(1,[d34db33f/48'/0'/0'/2']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,[d34db33f/48'/0'/0'/2']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*))");
Assert.Equal(2, parsedDescriptor.Item2.Length);
strat = Assert.IsType<MultisigDerivationStrategy>(Assert.IsType<P2WSHDerivationStrategy>(parsedDescriptor.Item1).Inner);
Assert.False(strat.IsLegacy);
Assert.Equal(1,strat.RequiredSignatures);
Assert.Equal(2,strat.Keys.Count());
Assert.False(strat.LexicographicOrder);
Assert.Equal("1-of-xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL-xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL-[keeporder]",parsedDescriptor.Item1.ToString() );
//segwit-p2sh
parsedDescriptor = mainnetParser.ParseOutputDescriptor(
"sh(wsh(multi(1,[d34db33f/48'/0'/0'/2']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,[d34db33f/48'/0'/0'/2']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*)))");
Assert.Equal(2, parsedDescriptor.Item2.Length);
strat = Assert.IsType<MultisigDerivationStrategy>(Assert.IsType<P2WSHDerivationStrategy>(Assert.IsType<P2SHDerivationStrategy>(parsedDescriptor.Item1).Inner).Inner);
Assert.False(strat.IsLegacy);
Assert.Equal(1,strat.RequiredSignatures);
Assert.Equal(2,strat.Keys.Count());
Assert.False(strat.LexicographicOrder);
Assert.Equal("1-of-xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL-xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL-[keeporder]-[p2sh]",parsedDescriptor.Item1.ToString() );
//sorted
parsedDescriptor = mainnetParser.ParseOutputDescriptor(
"sh(sortedmulti(1,[d34db33f/48'/0'/0'/1']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,[d34db33f/48'/0'/0'/1']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*))");
Assert.Equal("1-of-xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL-xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL-[legacy]",parsedDescriptor.Item1.ToString() );
}
}
}

Some files were not shown because too many files have changed in this diff Show More