Code formatting updates (#4502)

* Editorconfig: Add space_before_self_closing setting

This was a difference between the way dotnet-format and Rider format code. See https://www.jetbrains.com/help/rider/EditorConfig_Index.html

* Editorconfig: Keep 4 spaces indentation for Swagger JSON files

They are all formatted that way, let's keep it like that.

* Apply dotnet-format, mostly white-space related changes
This commit is contained in:
d11n
2023-01-06 14:18:07 +01:00
committed by GitHub
parent 3fa28bb46d
commit d5d0be5824
241 changed files with 1815 additions and 1715 deletions

View File

@@ -11,10 +11,14 @@ insert_final_newline = true
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
charset = utf-8 charset = utf-8
space_before_self_closing = true
[*.json] [*.json]
indent_size = 2 indent_size = 2
[swagger*.json]
indent_size = 4
# C# files # C# files
[*.cs] [*.cs]
# New line preferences # New line preferences

View File

@@ -1,4 +1,4 @@
#nullable enable #nullable enable
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;

View File

@@ -1,4 +1,4 @@
#nullable enable #nullable enable
namespace BTCPayServer.Abstractions.Contracts; namespace BTCPayServer.Abstractions.Contracts;
public interface IScopeProvider public interface IScopeProvider

View File

@@ -1,4 +1,4 @@
using System; using System;
namespace BTCPayServer.Abstractions.Contracts; namespace BTCPayServer.Abstractions.Contracts;

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using NBitcoin; using NBitcoin;

View File

@@ -9,7 +9,7 @@ public class AssetQuoteResult
public AssetQuoteResult() { } public AssetQuoteResult() { }
public AssetQuoteResult(string fromAsset, string toAsset,decimal bid, decimal ask) public AssetQuoteResult(string fromAsset, string toAsset, decimal bid, decimal ask)
{ {
FromAsset = fromAsset; FromAsset = fromAsset;
ToAsset = toAsset; ToAsset = toAsset;

View File

@@ -2,10 +2,7 @@ namespace BTCPayServer.Abstractions.Custodians;
public class AssetBalancesUnavailableException : CustodianApiException public class AssetBalancesUnavailableException : CustodianApiException
{ {
public AssetBalancesUnavailableException(System.Exception e) : base(500, "asset-balances-unavailable", $"Cannot fetch the asset balances: {e.Message}", e) public AssetBalancesUnavailableException(System.Exception e) : base(500, "asset-balances-unavailable", $"Cannot fetch the asset balances: {e.Message}", e)
{ {
} }
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
namespace BTCPayServer.Abstractions.Custodians; namespace BTCPayServer.Abstractions.Custodians;
public class CustodianApiException: Exception { public class CustodianApiException : Exception
{
public int HttpStatus { get; } public int HttpStatus { get; }
public string Code { get; } public string Code { get; }
@@ -9,7 +10,8 @@ public class CustodianApiException: Exception {
HttpStatus = httpStatus; HttpStatus = httpStatus;
Code = code; Code = code;
} }
public CustodianApiException( int httpStatus, string code, string message) : this(httpStatus, code, message, null)
public CustodianApiException(int httpStatus, string code, string message) : this(httpStatus, code, message, null)
{ {
} }
} }

View File

@@ -1,9 +1,8 @@
namespace BTCPayServer.Abstractions.Custodians; namespace BTCPayServer.Abstractions.Custodians;
public class CustodianFeatureNotImplementedException: CustodianApiException public class CustodianFeatureNotImplementedException : CustodianApiException
{ {
public CustodianFeatureNotImplementedException(string message) : base(400, "not-implemented", message) public CustodianFeatureNotImplementedException(string message) : base(400, "not-implemented", message)
{ {
} }
} }

View File

@@ -5,5 +5,4 @@ public class InsufficientFundsException : CustodianApiException
public InsufficientFundsException(string message) : base(400, "insufficient-funds", message) public InsufficientFundsException(string message) : base(400, "insufficient-funds", message)
{ {
} }
} }

View File

@@ -4,7 +4,7 @@ public class TradeNotFoundException : CustodianApiException
{ {
private string tradeId { get; } private string tradeId { get; }
public TradeNotFoundException(string tradeId) : base(404,"trade-not-found","Could not find trade ID " + tradeId) public TradeNotFoundException(string tradeId) : base(404, "trade-not-found", "Could not find trade ID " + tradeId)
{ {
this.tradeId = tradeId; this.tradeId = tradeId;
} }

View File

@@ -1,6 +1,6 @@
namespace BTCPayServer.Abstractions.Custodians; namespace BTCPayServer.Abstractions.Custodians;
public class WrongTradingPairException: CustodianApiException public class WrongTradingPairException : CustodianApiException
{ {
public const int HttpCode = 404; public const int HttpCode = 404;
public WrongTradingPairException(string fromAsset, string toAsset) : base(HttpCode, "wrong-trading-pair", $"Cannot find a trading pair for converting {fromAsset} into {toAsset}.") public WrongTradingPairException(string fromAsset, string toAsset) : base(HttpCode, "wrong-trading-pair", $"Cannot find a trading pair for converting {fromAsset} into {toAsset}.")

View File

@@ -9,8 +9,6 @@ namespace BTCPayServer.Abstractions.Custodians;
public interface ICanTrade public interface ICanTrade
{ {
/** /**
* A list of tradable asset pairs, or NULL if the custodian cannot trade/convert assets. if thr asset pair contains fiat, fiat is always put last. If both assets are a cyrptocode or both are fiat, the pair is written alphabetically. Always in uppercase. Example: ["BTC/EUR","BTC/USD", "EUR/USD", "BTC/ETH",...] * A list of tradable asset pairs, or NULL if the custodian cannot trade/convert assets. if thr asset pair contains fiat, fiat is always put last. If both assets are a cyrptocode or both are fiat, the pair is written alphabetically. Always in uppercase. Example: ["BTC/EUR","BTC/USD", "EUR/USD", "BTC/ETH",...]
*/ */

View File

@@ -6,7 +6,6 @@ namespace BTCPayServer.Abstractions.Extensions;
public static class StringExtensions public static class StringExtensions
{ {
public static bool IsValidFileName(this string fileName) public static bool IsValidFileName(this string fileName)
{ {
return !fileName.ToCharArray().Any(c => Path.GetInvalidFileNameChars().Contains(c) return !fileName.ToCharArray().Any(c => Path.GetInvalidFileNameChars().Contains(c)
@@ -41,5 +40,4 @@ public static class StringExtensions
return str.Substring(0, str.Length - 1); return str.Substring(0, str.Length - 1);
return str; return str;
} }
} }

View File

@@ -85,7 +85,7 @@ public class Form
if (field.Fields.Any()) if (field.Fields.Any())
{ {
names.AddRange(GetAllNames(field.Fields).Select(s => $"{prefix}{s}" )); names.AddRange(GetAllNames(field.Fields).Select(s => $"{prefix}{s}"));
} }
} }
@@ -139,8 +139,9 @@ public class Form
result.TryAdd(name, values); result.TryAdd(name, values);
if (keylessValue is not Dictionary<string, object> dict) continue; if (keylessValue is not Dictionary<string, object> dict)
foreach (KeyValuePair<string,object> keyValuePair in dict) continue;
foreach (KeyValuePair<string, object> keyValuePair in dict)
{ {
result.TryAdd(keyValuePair.Key, keyValuePair.Value); result.TryAdd(keyValuePair.Key, keyValuePair.Value);
} }

View File

@@ -39,7 +39,7 @@ namespace BTCPayServer.Client
parameters.Add("includeNeighbourData", v); parameters.Add("includeNeighbourData", v);
var response = var response =
await _httpClient.SendAsync( await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects", parameters, method:HttpMethod.Get), token); CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects", parameters, method: HttpMethod.Get), token);
return await HandleResponse<OnChainWalletObjectData[]>(response); return await HandleResponse<OnChainWalletObjectData[]>(response);
} }
public virtual async Task RemoveOnChainWalletObject(string storeId, string cryptoCode, OnChainWalletObjectId objectId, public virtual async Task RemoveOnChainWalletObject(string storeId, string cryptoCode, OnChainWalletObjectId objectId,
@@ -47,7 +47,7 @@ namespace BTCPayServer.Client
{ {
var response = var response =
await _httpClient.SendAsync( await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}", method:HttpMethod.Delete), token); CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}", method: HttpMethod.Delete), token);
await HandleResponse(response); await HandleResponse(response);
} }
public virtual async Task<OnChainWalletObjectData> AddOrUpdateOnChainWalletObject(string storeId, string cryptoCode, AddOnChainWalletObjectRequest request, public virtual async Task<OnChainWalletObjectData> AddOrUpdateOnChainWalletObject(string storeId, string cryptoCode, AddOnChainWalletObjectRequest request,
@@ -55,7 +55,7 @@ namespace BTCPayServer.Client
{ {
var response = var response =
await _httpClient.SendAsync( await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects", method:HttpMethod.Post, bodyPayload: request), token); CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects", method: HttpMethod.Post, bodyPayload: request), token);
return await HandleResponse<OnChainWalletObjectData>(response); return await HandleResponse<OnChainWalletObjectData>(response);
} }
public virtual async Task AddOrUpdateOnChainWalletLink(string storeId, string cryptoCode, public virtual async Task AddOrUpdateOnChainWalletLink(string storeId, string cryptoCode,
@@ -65,7 +65,7 @@ namespace BTCPayServer.Client
{ {
var response = var response =
await _httpClient.SendAsync( await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}/links", method:HttpMethod.Post, bodyPayload: request), token); CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}/links", method: HttpMethod.Post, bodyPayload: request), token);
await HandleResponse(response); await HandleResponse(response);
} }
public virtual async Task RemoveOnChainWalletLinks(string storeId, string cryptoCode, public virtual async Task RemoveOnChainWalletLinks(string storeId, string cryptoCode,
@@ -75,7 +75,7 @@ namespace BTCPayServer.Client
{ {
var response = var response =
await _httpClient.SendAsync( await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}/links/{link.Type}/{link.Id}", method:HttpMethod.Delete), token); CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}/links/{link.Type}/{link.Id}", method: HttpMethod.Delete), token);
await HandleResponse(response); await HandleResponse(response);
} }
} }

View File

@@ -63,7 +63,8 @@ namespace BTCPayServer.Client
{ {
query.Add(nameof(statusFilter), statusFilter); query.Add(nameof(statusFilter), statusFilter);
} }
if (labelFilter != null) { if (labelFilter != null)
{
query.Add(nameof(labelFilter), labelFilter); query.Add(nameof(labelFilter), labelFilter);
} }
var response = var response =

View File

@@ -24,24 +24,24 @@ namespace BTCPayServer.Client
public virtual async Task<IEnumerable<LightningAutomatedPayoutSettings>> GetStoreLightningAutomatedPayoutProcessors(string storeId, string? paymentMethod = null, public virtual async Task<IEnumerable<LightningAutomatedPayoutSettings>> GetStoreLightningAutomatedPayoutProcessors(string storeId, string? paymentMethod = null,
CancellationToken token = default) CancellationToken token = default)
{ {
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory{(paymentMethod is null? string.Empty: $"/{paymentMethod}")}"), token); var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory{(paymentMethod is null ? string.Empty : $"/{paymentMethod}")}"), token);
return await HandleResponse<IEnumerable<LightningAutomatedPayoutSettings>>(response); return await HandleResponse<IEnumerable<LightningAutomatedPayoutSettings>>(response);
} }
public virtual async Task<LightningAutomatedPayoutSettings> UpdateStoreLightningAutomatedPayoutProcessors(string storeId, string paymentMethod,LightningAutomatedPayoutSettings request, CancellationToken token = default) public virtual async Task<LightningAutomatedPayoutSettings> UpdateStoreLightningAutomatedPayoutProcessors(string storeId, string paymentMethod, LightningAutomatedPayoutSettings request, CancellationToken token = default)
{ {
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory/{paymentMethod}",null, request, HttpMethod.Put ), token); var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory/{paymentMethod}", null, request, HttpMethod.Put), token);
return await HandleResponse<LightningAutomatedPayoutSettings>(response); return await HandleResponse<LightningAutomatedPayoutSettings>(response);
} }
public virtual async Task<OnChainAutomatedPayoutSettings> UpdateStoreOnChainAutomatedPayoutProcessors(string storeId, string paymentMethod,OnChainAutomatedPayoutSettings request, CancellationToken token = default) public virtual async Task<OnChainAutomatedPayoutSettings> UpdateStoreOnChainAutomatedPayoutProcessors(string storeId, string paymentMethod, OnChainAutomatedPayoutSettings request, CancellationToken token = default)
{ {
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/OnChainAutomatedPayoutSenderFactory/{paymentMethod}",null, request, HttpMethod.Put ), token); var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/OnChainAutomatedPayoutSenderFactory/{paymentMethod}", null, request, HttpMethod.Put), token);
return await HandleResponse<OnChainAutomatedPayoutSettings>(response); return await HandleResponse<OnChainAutomatedPayoutSettings>(response);
} }
public virtual async Task<IEnumerable<OnChainAutomatedPayoutSettings>> GetStoreOnChainAutomatedPayoutProcessors(string storeId, string? paymentMethod = null, public virtual async Task<IEnumerable<OnChainAutomatedPayoutSettings>> GetStoreOnChainAutomatedPayoutProcessors(string storeId, string? paymentMethod = null,
CancellationToken token = default) CancellationToken token = default)
{ {
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/OnChainAutomatedPayoutSenderFactory{(paymentMethod is null? string.Empty: $"/{paymentMethod}")}"), token); var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/payout-processors/OnChainAutomatedPayoutSenderFactory{(paymentMethod is null ? string.Empty : $"/{paymentMethod}")}"), token);
return await HandleResponse<IEnumerable<OnChainAutomatedPayoutSettings>>(response); return await HandleResponse<IEnumerable<OnChainAutomatedPayoutSettings>>(response);
} }
} }

View File

@@ -44,7 +44,7 @@ namespace BTCPayServer.Client
{ {
using var response = await _httpClient.SendAsync( using var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/rates/configuration/preview", bodyPayload: request, CreateHttpRequest($"api/v1/stores/{storeId}/rates/configuration/preview", bodyPayload: request,
queryPayload: new Dictionary<string, object>() {{"currencyPair", currencyPair}}, queryPayload: new Dictionary<string, object>() { { "currencyPair", currencyPair } },
method: HttpMethod.Post), method: HttpMethod.Post),
token); token);
return await HandleResponse<List<StoreRatePreviewResult>>(response); return await HandleResponse<List<StoreRatePreviewResult>>(response);

View File

@@ -36,12 +36,12 @@ namespace BTCPayServer.Client
public virtual async Task<bool> LockUser(string idOrEmail, bool locked, CancellationToken token = default) public virtual async Task<bool> LockUser(string idOrEmail, bool locked, CancellationToken token = default)
{ {
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/users/{idOrEmail}/lock", null, var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/users/{idOrEmail}/lock", null,
new LockUserRequest {Locked = locked}, HttpMethod.Post), token); new LockUserRequest { Locked = locked }, HttpMethod.Post), token);
await HandleResponse(response); await HandleResponse(response);
return response.IsSuccessStatusCode; return response.IsSuccessStatusCode;
} }
public virtual async Task<ApplicationUserData[]> GetUsers( CancellationToken token = default) public virtual async Task<ApplicationUserData[]> GetUsers(CancellationToken token = default)
{ {
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/users/", null, HttpMethod.Get), token); var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/users/", null, HttpMethod.Get), token);
return await HandleResponse<ApplicationUserData[]>(response); return await HandleResponse<ApplicationUserData[]>(response);

View File

@@ -2,7 +2,7 @@ using System.Collections.Generic;
namespace BTCPayServer.Client.Models; namespace BTCPayServer.Client.Models;
public class CustodianAccountResponse: CustodianAccountData public class CustodianAccountResponse : CustodianAccountData
{ {
public IDictionary<string, decimal> AssetBalances { get; set; } public IDictionary<string, decimal> AssetBalances { get; set; }

View File

@@ -1,4 +1,4 @@
using System; using System;
using BTCPayServer.Client.JsonConverters; using BTCPayServer.Client.JsonConverters;
using Newtonsoft.Json; using Newtonsoft.Json;

View File

@@ -1,4 +1,4 @@
namespace BTCPayServer.Client; namespace BTCPayServer.Client;
public class LockUserRequest public class LockUserRequest
{ {

View File

@@ -1,4 +1,4 @@
using System; using System;
using BTCPayServer.Client.JsonConverters; using BTCPayServer.Client.JsonConverters;
using Newtonsoft.Json; using Newtonsoft.Json;

View File

@@ -1,4 +1,4 @@
namespace BTCPayServer.Client.Models; namespace BTCPayServer.Client.Models;
public class RateSource public class RateSource
{ {

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace BTCPayServer.Client.Models; namespace BTCPayServer.Client.Models;

View File

@@ -1,4 +1,4 @@
namespace BTCPayServer.Client.Models; namespace BTCPayServer.Client.Models;
public class StoreRateResult public class StoreRateResult
{ {

View File

@@ -23,7 +23,7 @@ namespace BTCPayServer
internal Task ProcessTask; internal Task ProcessTask;
public async Task Process(CancellationToken cancellationToken) public async Task Process(CancellationToken cancellationToken)
{ {
retry: retry:
while (Chan.Reader.TryRead(out var item)) while (Chan.Reader.TryRead(out var item))
{ {
await item(cancellationToken); await item(cancellationToken);
@@ -52,7 +52,7 @@ namespace BTCPayServer
{ {
lock (_Queues) lock (_Queues)
{ {
retry: retry:
if (stopped) if (stopped)
return; return;
Cleanup(); Cleanup();

View File

@@ -67,7 +67,7 @@ namespace BTCPayServer.Data
public DbSet<WalletTransactionData> WalletTransactions { get; set; } public DbSet<WalletTransactionData> WalletTransactions { get; set; }
public DbSet<WebhookDeliveryData> WebhookDeliveries { get; set; } public DbSet<WebhookDeliveryData> WebhookDeliveries { get; set; }
public DbSet<WebhookData> Webhooks { get; set; } public DbSet<WebhookData> Webhooks { get; set; }
public DbSet<LightningAddressData> LightningAddresses{ get; set; } public DbSet<LightningAddressData> LightningAddresses { get; set; }
public DbSet<PayoutProcessorData> PayoutProcessors { get; set; } public DbSet<PayoutProcessorData> PayoutProcessors { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

View File

@@ -1,4 +1,4 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Data; namespace BTCPayServer.Data;

View File

@@ -1,4 +1,4 @@
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Data.Data; namespace BTCPayServer.Data.Data;

View File

@@ -1,8 +1,8 @@
using System; using System;
using Microsoft.EntityFrameworkCore.Migrations;
using BTCPayServer.Data; using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;

View File

@@ -1,4 +1,4 @@
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Rating; using BTCPayServer.Rating;

View File

@@ -23,7 +23,7 @@ namespace BTCPayServer.Services.Rates
{ {
await new SynchronizationContextRemover(); await new SynchronizationContextRemover();
var exchangeAPI = (T) await ExchangeAPI.GetExchangeAPIAsync<T>(); var exchangeAPI = (T)await ExchangeAPI.GetExchangeAPIAsync<T>();
exchangeAPI.RequestMaker = new HttpClientRequestMaker(exchangeAPI, _httpClient, cancellationToken); exchangeAPI.RequestMaker = new HttpClientRequestMaker(exchangeAPI, _httpClient, cancellationToken);
var rates = await exchangeAPI.GetTickersAsync(); var rates = await exchangeAPI.GetTickersAsync();

View File

@@ -177,7 +177,7 @@ namespace BTCPayServer.Services.Rates
var result = JsonConvert.DeserializeObject<T>(stringResult); var result = JsonConvert.DeserializeObject<T>(stringResult);
if (result is JToken json) if (result is JToken json)
{ {
if (!(json is JArray) && json["result"] is JObject {Count: > 0} pairResult) if (!(json is JArray) && json["result"] is JObject { Count: > 0 } pairResult)
{ {
return (T)(object)(pairResult); return (T)(object)(pairResult);
} }

View File

@@ -7,8 +7,8 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Rating; using BTCPayServer.Rating;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Services.Rates namespace BTCPayServer.Services.Rates
{ {

View File

@@ -165,7 +165,7 @@ retry:
wait.UntilJsIsReady(); wait.UntilJsIsReady();
int retriesLeft = 4; int retriesLeft = 4;
retry: retry:
try try
{ {
var el = driver.FindElement(selector); var el = driver.FindElement(selector);
@@ -176,7 +176,8 @@ retry:
catch (NoSuchElementException) when (retriesLeft > 0) catch (NoSuchElementException) when (retriesLeft > 0)
{ {
retriesLeft--; retriesLeft--;
if (waitTime != null) Thread.Sleep(waitTime.Value); if (waitTime != null)
Thread.Sleep(waitTime.Value);
goto retry; goto retry;
} }
wait.UntilJsIsReady(); wait.UntilJsIsReady();

View File

@@ -1077,7 +1077,8 @@ namespace BTCPayServer.Tests
{ {
MultiProcessingQueueTest t = new MultiProcessingQueueTest(); MultiProcessingQueueTest t = new MultiProcessingQueueTest();
t.Tcs = new TaskCompletionSource(); t.Tcs = new TaskCompletionSource();
q.Enqueue(queueName, async (cancellationToken) => { q.Enqueue(queueName, async (cancellationToken) =>
{
t.Started = true; t.Started = true;
try try
{ {
@@ -1774,10 +1775,10 @@ namespace BTCPayServer.Tests
{ {
foreach (var policy in Policies.AllPolicies) foreach (var policy in Policies.AllPolicies)
{ {
Assert.True( UIManageController.AddApiKeyViewModel.PermissionValueItem.PermissionDescriptions.ContainsKey(policy)); Assert.True(UIManageController.AddApiKeyViewModel.PermissionValueItem.PermissionDescriptions.ContainsKey(policy));
if (Policies.IsStorePolicy(policy)) if (Policies.IsStorePolicy(policy))
{ {
Assert.True( UIManageController.AddApiKeyViewModel.PermissionValueItem.PermissionDescriptions.ContainsKey($"{policy}:")); Assert.True(UIManageController.AddApiKeyViewModel.PermissionValueItem.PermissionDescriptions.ContainsKey($"{policy}:"));
} }
} }
} }
@@ -1804,8 +1805,8 @@ namespace BTCPayServer.Tests
PaymentMethod = new PaymentMethodId("BTC", PaymentTypes.BTCLike) PaymentMethod = new PaymentMethodId("BTC", PaymentTypes.BTCLike)
} }
}; };
var newBlob = new Serializer(null).ToString(blob).Replace( "paymentMethod\":\"BTC\"","paymentMethod\":\"ETH_ZYC\""); var newBlob = new Serializer(null).ToString(blob).Replace("paymentMethod\":\"BTC\"", "paymentMethod\":\"ETH_ZYC\"");
Assert.Empty(StoreDataExtensions.GetStoreBlob(new StoreData() {StoreBlob = newBlob}).PaymentMethodCriteria); Assert.Empty(StoreDataExtensions.GetStoreBlob(new StoreData() { StoreBlob = newBlob }).PaymentMethodCriteria);
} }
} }
} }

View File

@@ -15,8 +15,8 @@ using BTCPayServer.Lightning;
using BTCPayServer.Models.InvoicingModels; using BTCPayServer.Models.InvoicingModels;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.Payments.Lightning; using BTCPayServer.Payments.Lightning;
using BTCPayServer.Services.Custodian.Client.MockCustodian;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Custodian.Client.MockCustodian;
using BTCPayServer.Services.Notifications; using BTCPayServer.Services.Notifications;
using BTCPayServer.Services.Notifications.Blobs; using BTCPayServer.Services.Notifications.Blobs;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
@@ -206,7 +206,7 @@ namespace BTCPayServer.Tests
// Test validation for creating the app // Test validation for creating the app
await AssertValidationError(new[] { "AppName" }, await AssertValidationError(new[] { "AppName" },
async () => await client.CreatePointOfSaleApp(user.StoreId, new CreatePointOfSaleAppRequest() {})); async () => await client.CreatePointOfSaleApp(user.StoreId, new CreatePointOfSaleAppRequest() { }));
await AssertValidationError(new[] { "AppName" }, await AssertValidationError(new[] { "AppName" },
async () => await client.CreatePointOfSaleApp( async () => await client.CreatePointOfSaleApp(
user.StoreId, user.StoreId,
@@ -261,7 +261,8 @@ namespace BTCPayServer.Tests
Assert.Equal("PointOfSale", app.AppType); Assert.Equal("PointOfSale", app.AppType);
// Make sure we return a 404 if we try to get an app that doesn't exist // Make sure we return a 404 if we try to get an app that doesn't exist
await AssertHttpError(404, async () => { await AssertHttpError(404, async () =>
{
await client.GetApp("some random ID lol"); await client.GetApp("some random ID lol");
}); });
@@ -284,7 +285,8 @@ namespace BTCPayServer.Tests
// Test deleting the newly created app // Test deleting the newly created app
await client.DeleteApp(retrievedApp.Id); await client.DeleteApp(retrievedApp.Id);
await AssertHttpError(404, async () => { await AssertHttpError(404, async () =>
{
await client.GetApp(retrievedApp.Id); await client.GetApp(retrievedApp.Id);
}); });
} }
@@ -301,7 +303,7 @@ namespace BTCPayServer.Tests
// Test validation for creating the app // Test validation for creating the app
await AssertValidationError(new[] { "AppName" }, await AssertValidationError(new[] { "AppName" },
async () => await client.CreateCrowdfundApp(user.StoreId, new CreateCrowdfundAppRequest() {})); async () => await client.CreateCrowdfundApp(user.StoreId, new CreateCrowdfundAppRequest() { }));
await AssertValidationError(new[] { "AppName" }, await AssertValidationError(new[] { "AppName" },
async () => await client.CreateCrowdfundApp( async () => await client.CreateCrowdfundApp(
user.StoreId, user.StoreId,
@@ -347,7 +349,7 @@ namespace BTCPayServer.Tests
new CreateCrowdfundAppRequest() new CreateCrowdfundAppRequest()
{ {
AppName = "good name", AppName = "good name",
AnimationColors = new string[] {} AnimationColors = new string[] { }
} }
) )
); );
@@ -461,8 +463,8 @@ namespace BTCPayServer.Tests
var adminClient = await adminUser.CreateClient(Policies.Unrestricted); var adminClient = await adminUser.CreateClient(Policies.Unrestricted);
// Should be 404 if user doesn't exist // Should be 404 if user doesn't exist
await AssertHttpError(404,async () => await adminClient.GetUserByIdOrEmail("non_existing_id")); await AssertHttpError(404, async () => await adminClient.GetUserByIdOrEmail("non_existing_id"));
await AssertHttpError(404,async () => await adminClient.GetUserByIdOrEmail("doesnotexist@example.com")); await AssertHttpError(404, async () => await adminClient.GetUserByIdOrEmail("doesnotexist@example.com"));
// Try listing all users, should be fine // Try listing all users, should be fine
await adminClient.GetUsers(); await adminClient.GetUsers();
@@ -487,8 +489,8 @@ namespace BTCPayServer.Tests
await goodClient.GetUsers(); await goodClient.GetUsers();
// Should be 404 if user doesn't exist // Should be 404 if user doesn't exist
await AssertHttpError(404,async () => await goodClient.GetUserByIdOrEmail("non_existing_id")); await AssertHttpError(404, async () => await goodClient.GetUserByIdOrEmail("non_existing_id"));
await AssertHttpError(404,async () => await goodClient.GetUserByIdOrEmail("doesnotexist@example.com")); await AssertHttpError(404, async () => await goodClient.GetUserByIdOrEmail("doesnotexist@example.com"));
// Try listing all users, should be fine // Try listing all users, should be fine
await goodClient.GetUsers(); await goodClient.GetUsers();
@@ -510,20 +512,20 @@ namespace BTCPayServer.Tests
var badClient = await goodUser.CreateClient(Policies.CanCreateInvoice); var badClient = await goodUser.CreateClient(Policies.CanCreateInvoice);
// Try listing all users, should be fine // Try listing all users, should be fine
await AssertHttpError(403,async () => await badClient.GetUsers()); await AssertHttpError(403, async () => await badClient.GetUsers());
// Should be 404 if user doesn't exist // Should be 404 if user doesn't exist
await AssertHttpError(403,async () => await badClient.GetUserByIdOrEmail("non_existing_id")); await AssertHttpError(403, async () => await badClient.GetUserByIdOrEmail("non_existing_id"));
await AssertHttpError(403,async () => await badClient.GetUserByIdOrEmail("doesnotexist@example.com")); await AssertHttpError(403, async () => await badClient.GetUserByIdOrEmail("doesnotexist@example.com"));
// Try listing all users, should be fine // Try listing all users, should be fine
await AssertHttpError(403,async () => await badClient.GetUsers()); await AssertHttpError(403, async () => await badClient.GetUsers());
// Try loading 1 user by ID. Loading myself. // Try loading 1 user by ID. Loading myself.
await AssertHttpError(403,async () => await badClient.GetUserByIdOrEmail(badUser.UserId)); await AssertHttpError(403, async () => await badClient.GetUserByIdOrEmail(badUser.UserId));
// Try loading 1 user by email. Loading myself. // Try loading 1 user by email. Loading myself.
await AssertHttpError(403,async () => await badClient.GetUserByIdOrEmail(badUser.Email)); await AssertHttpError(403, async () => await badClient.GetUserByIdOrEmail(badUser.Email));
@@ -929,21 +931,21 @@ namespace BTCPayServer.Tests
}); });
await AssertAPIError("invalid-state", async () => await AssertAPIError("invalid-state", async () =>
{ {
await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest() {State = PayoutState.Completed}); await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest() { State = PayoutState.Completed });
}); });
await client.ApprovePayout(storeId, payout.Id, new ApprovePayoutRequest()); await client.ApprovePayout(storeId, payout.Id, new ApprovePayoutRequest());
await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest() {State = PayoutState.Completed}); await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest() { State = PayoutState.Completed });
Assert.Equal(PayoutState.Completed,(await client.GetStorePayouts(storeId,false)).Single(data => data.Id == payout.Id ).State ); Assert.Equal(PayoutState.Completed, (await client.GetStorePayouts(storeId, false)).Single(data => data.Id == payout.Id).State);
Assert.Null((await client.GetStorePayouts(storeId,false)).Single(data => data.Id == payout.Id ).PaymentProof ); Assert.Null((await client.GetStorePayouts(storeId, false)).Single(data => data.Id == payout.Id).PaymentProof);
foreach (var state in new []{ PayoutState.AwaitingApproval, PayoutState.Cancelled, PayoutState.Completed, PayoutState.AwaitingApproval, PayoutState.InProgress}) foreach (var state in new[] { PayoutState.AwaitingApproval, PayoutState.Cancelled, PayoutState.Completed, PayoutState.AwaitingApproval, PayoutState.InProgress })
{ {
await AssertAPIError("invalid-state", async () => await AssertAPIError("invalid-state", async () =>
{ {
await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest() {State = state}); await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest() { State = state });
}); });
} }
payout = await client.CreatePayout(storeId, new CreatePayoutThroughStoreRequest() payout = await client.CreatePayout(storeId, new CreatePayoutThroughStoreRequest()
@@ -957,49 +959,65 @@ namespace BTCPayServer.Tests
payout = await client.GetStorePayout(storeId, payout.Id); payout = await client.GetStorePayout(storeId, payout.Id);
Assert.NotNull(payout); Assert.NotNull(payout);
Assert.Equal(PayoutState.AwaitingPayment, payout.State); Assert.Equal(PayoutState.AwaitingPayment, payout.State);
await AssertValidationError(new []{"PaymentProof"}, async () => await AssertValidationError(new[] { "PaymentProof" }, async () =>
{ {
await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest() {State = PayoutState.Completed, PaymentProof = JObject.FromObject(new await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest()
{
State = PayoutState.Completed,
PaymentProof = JObject.FromObject(new
{ {
test = "zyx" test = "zyx"
})}); })
}); });
await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest() {State = PayoutState.InProgress, PaymentProof = JObject.FromObject(new });
await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest()
{
State = PayoutState.InProgress,
PaymentProof = JObject.FromObject(new
{ {
proofType = "external-proof" proofType = "external-proof"
})}); })
});
payout = await client.GetStorePayout(storeId, payout.Id); payout = await client.GetStorePayout(storeId, payout.Id);
Assert.NotNull(payout); Assert.NotNull(payout);
Assert.Equal(PayoutState.InProgress, payout.State); Assert.Equal(PayoutState.InProgress, payout.State);
Assert.True(payout.PaymentProof.TryGetValue("proofType", out var savedType)); Assert.True(payout.PaymentProof.TryGetValue("proofType", out var savedType));
Assert.Equal("external-proof",savedType); Assert.Equal("external-proof", savedType);
await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest() {State = PayoutState.AwaitingPayment, PaymentProof = JObject.FromObject(new await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest()
{
State = PayoutState.AwaitingPayment,
PaymentProof = JObject.FromObject(new
{ {
proofType = "external-proof", proofType = "external-proof",
id="finality proof", id = "finality proof",
link="proof.com" link = "proof.com"
})}); })
});
payout = await client.GetStorePayout(storeId, payout.Id); payout = await client.GetStorePayout(storeId, payout.Id);
Assert.NotNull(payout); Assert.NotNull(payout);
Assert.Null(payout.PaymentProof); Assert.Null(payout.PaymentProof);
Assert.Equal(PayoutState.AwaitingPayment, payout.State); Assert.Equal(PayoutState.AwaitingPayment, payout.State);
await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest() {State = PayoutState.Completed, PaymentProof = JObject.FromObject(new await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest()
{
State = PayoutState.Completed,
PaymentProof = JObject.FromObject(new
{ {
proofType = "external-proof", proofType = "external-proof",
id="finality proof", id = "finality proof",
link="proof.com" link = "proof.com"
})}); })
});
payout = await client.GetStorePayout(storeId, payout.Id); payout = await client.GetStorePayout(storeId, payout.Id);
Assert.NotNull(payout); Assert.NotNull(payout);
Assert.Equal(PayoutState.Completed, payout.State); Assert.Equal(PayoutState.Completed, payout.State);
Assert.True(payout.PaymentProof.TryGetValue("proofType", out savedType)); Assert.True(payout.PaymentProof.TryGetValue("proofType", out savedType));
Assert.True(payout.PaymentProof.TryGetValue("link", out var savedLink)); Assert.True(payout.PaymentProof.TryGetValue("link", out var savedLink));
Assert.True(payout.PaymentProof.TryGetValue("id", out var savedId)); Assert.True(payout.PaymentProof.TryGetValue("id", out var savedId));
Assert.Equal("external-proof",savedType); Assert.Equal("external-proof", savedType);
Assert.Equal("finality proof",savedId); Assert.Equal("finality proof", savedId);
Assert.Equal("proof.com",savedLink); Assert.Equal("proof.com", savedLink);
} }
private DateTimeOffset RoundSeconds(DateTimeOffset dateTimeOffset) private DateTimeOffset RoundSeconds(DateTimeOffset dateTimeOffset)
@@ -1593,14 +1611,16 @@ namespace BTCPayServer.Tests
// test validation that the invoice exists // test validation that the invoice exists
await AssertHttpError(404, async () => await AssertHttpError(404, async () =>
{ {
await client.RefundInvoice(user.StoreId, "lol fake invoice id", new RefundInvoiceRequest() { await client.RefundInvoice(user.StoreId, "lol fake invoice id", new RefundInvoiceRequest()
{
PaymentMethod = method.PaymentMethod, PaymentMethod = method.PaymentMethod,
RefundVariant = RefundVariant.RateThen RefundVariant = RefundVariant.RateThen
}); });
}); });
// test validation error for when invoice is not yet in the state in which it can be refunded // test validation error for when invoice is not yet in the state in which it can be refunded
var apiError = await AssertAPIError("non-refundable", () => client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest() { var apiError = await AssertAPIError("non-refundable", () => client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest()
{
PaymentMethod = method.PaymentMethod, PaymentMethod = method.PaymentMethod,
RefundVariant = RefundVariant.RateThen RefundVariant = RefundVariant.RateThen
})); }));
@@ -1613,14 +1633,16 @@ namespace BTCPayServer.Tests
}); });
// need to set the status to the one in which we can actually refund the invoice // need to set the status to the one in which we can actually refund the invoice
await client.MarkInvoiceStatus(user.StoreId, invoice.Id, new MarkInvoiceStatusRequest() { await client.MarkInvoiceStatus(user.StoreId, invoice.Id, new MarkInvoiceStatusRequest()
{
Status = InvoiceStatus.Settled Status = InvoiceStatus.Settled
}); });
// test validation for the payment method // test validation for the payment method
var validationError = await AssertValidationError(new[] { "PaymentMethod" }, async () => var validationError = await AssertValidationError(new[] { "PaymentMethod" }, async () =>
{ {
await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest() { await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest()
{
PaymentMethod = "fake payment method", PaymentMethod = "fake payment method",
RefundVariant = RefundVariant.RateThen RefundVariant = RefundVariant.RateThen
}); });
@@ -1628,7 +1650,8 @@ namespace BTCPayServer.Tests
Assert.Contains("PaymentMethod: Please select one of the payment methods which were available for the original invoice", validationError.Message); Assert.Contains("PaymentMethod: Please select one of the payment methods which were available for the original invoice", validationError.Message);
// test RefundVariant.RateThen // test RefundVariant.RateThen
var pp = await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest() { var pp = await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest()
{
PaymentMethod = method.PaymentMethod, PaymentMethod = method.PaymentMethod,
RefundVariant = RefundVariant.RateThen RefundVariant = RefundVariant.RateThen
}); });
@@ -1638,7 +1661,8 @@ namespace BTCPayServer.Tests
Assert.Equal(pp.Name, $"Refund {invoice.Id}"); Assert.Equal(pp.Name, $"Refund {invoice.Id}");
// test RefundVariant.CurrentRate // test RefundVariant.CurrentRate
pp = await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest() { pp = await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest()
{
PaymentMethod = method.PaymentMethod, PaymentMethod = method.PaymentMethod,
RefundVariant = RefundVariant.CurrentRate RefundVariant = RefundVariant.CurrentRate
}); });
@@ -1647,7 +1671,8 @@ namespace BTCPayServer.Tests
Assert.Equal(1, pp.Amount); Assert.Equal(1, pp.Amount);
// test RefundVariant.Fiat // test RefundVariant.Fiat
pp = await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest() { pp = await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest()
{
PaymentMethod = method.PaymentMethod, PaymentMethod = method.PaymentMethod,
RefundVariant = RefundVariant.Fiat, RefundVariant = RefundVariant.Fiat,
Name = "my test name" Name = "my test name"
@@ -1660,7 +1685,8 @@ namespace BTCPayServer.Tests
// test RefundVariant.Custom // test RefundVariant.Custom
validationError = await AssertValidationError(new[] { "CustomAmount", "CustomCurrency" }, async () => validationError = await AssertValidationError(new[] { "CustomAmount", "CustomCurrency" }, async () =>
{ {
await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest() { await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest()
{
PaymentMethod = method.PaymentMethod, PaymentMethod = method.PaymentMethod,
RefundVariant = RefundVariant.Custom, RefundVariant = RefundVariant.Custom,
}); });
@@ -1668,7 +1694,8 @@ namespace BTCPayServer.Tests
Assert.Contains("CustomAmount: Amount must be greater than 0", validationError.Message); Assert.Contains("CustomAmount: Amount must be greater than 0", validationError.Message);
Assert.Contains("CustomCurrency: Invalid currency", validationError.Message); Assert.Contains("CustomCurrency: Invalid currency", validationError.Message);
pp = await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest() { pp = await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest()
{
PaymentMethod = method.PaymentMethod, PaymentMethod = method.PaymentMethod,
RefundVariant = RefundVariant.Custom, RefundVariant = RefundVariant.Custom,
CustomAmount = 69420, CustomAmount = 69420,
@@ -1679,7 +1706,8 @@ namespace BTCPayServer.Tests
Assert.Equal(69420, pp.Amount); Assert.Equal(69420, pp.Amount);
// should auto-approve if currencies match // should auto-approve if currencies match
pp = await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest() { pp = await client.RefundInvoice(user.StoreId, invoice.Id, new RefundInvoiceRequest()
{
PaymentMethod = method.PaymentMethod, PaymentMethod = method.PaymentMethod,
RefundVariant = RefundVariant.Custom, RefundVariant = RefundVariant.Custom,
CustomAmount = 0.00069420m, CustomAmount = 0.00069420m,
@@ -2171,7 +2199,8 @@ namespace BTCPayServer.Tests
Assert.NotEmpty(merchantInvoices); Assert.NotEmpty(merchantInvoices);
Assert.Empty(merchantPendingInvoices); Assert.Empty(merchantPendingInvoices);
// if the test ran too many times the invoice might be on a later page // if the test ran too many times the invoice might be on a later page
if (merchantInvoices.Length < 100) Assert.Contains(merchantInvoices, i => i.Id == merchantInvoice.Id); if (merchantInvoices.Length < 100)
Assert.Contains(merchantInvoices, i => i.Id == merchantInvoice.Id);
// Amount received might be bigger because of internal implementation shit from lightning // Amount received might be bigger because of internal implementation shit from lightning
Assert.True(LightMoney.Satoshis(1000) <= invoice.AmountReceived); Assert.True(LightMoney.Satoshis(1000) <= invoice.AmountReceived);
@@ -2765,7 +2794,8 @@ namespace BTCPayServer.Tests
// transaction patch tests // transaction patch tests
var patchedTransaction = await client.PatchOnChainWalletTransaction( var patchedTransaction = await client.PatchOnChainWalletTransaction(
walletId.StoreId, walletId.CryptoCode, txdata.TransactionHash.ToString(), walletId.StoreId, walletId.CryptoCode, txdata.TransactionHash.ToString(),
new PatchOnChainTransactionRequest() { new PatchOnChainTransactionRequest()
{
Comment = "test comment", Comment = "test comment",
Labels = new List<string> Labels = new List<string>
{ {
@@ -2895,13 +2925,13 @@ namespace BTCPayServer.Tests
var users = await client.GetStoreUsers(user.StoreId); var users = await client.GetStoreUsers(user.StoreId);
var storeuser = Assert.Single(users); var storeuser = Assert.Single(users);
Assert.Equal(user.UserId,storeuser.UserId); Assert.Equal(user.UserId, storeuser.UserId);
Assert.Equal(StoreRoles.Owner,storeuser.Role); Assert.Equal(StoreRoles.Owner, storeuser.Role);
var user2= tester.NewAccount(); var user2 = tester.NewAccount();
await user2.GrantAccessAsync(false); await user2.GrantAccessAsync(false);
var user2Client =await user2.CreateClient(Policies.CanModifyStoreSettings); var user2Client = await user2.CreateClient(Policies.CanModifyStoreSettings);
//test no access to api when unrelated to store at all //test no access to api when unrelated to store at all
await AssertPermissionError(Policies.CanModifyStoreSettings, async () => await user2Client.GetStoreUsers(user.StoreId)); await AssertPermissionError(Policies.CanModifyStoreSettings, async () => await user2Client.GetStoreUsers(user.StoreId));
@@ -2923,7 +2953,7 @@ namespace BTCPayServer.Tests
await client.AddStoreUser(user.StoreId, new StoreUserData() { Role = StoreRoles.Owner, UserId = user2.UserId }); await client.AddStoreUser(user.StoreId, new StoreUserData() { Role = StoreRoles.Owner, UserId = user2.UserId });
await AssertAPIError("duplicate-store-user-role",async ()=> await AssertAPIError("duplicate-store-user-role", async () =>
await client.AddStoreUser(user.StoreId, await client.AddStoreUser(user.StoreId,
new StoreUserData() { Role = StoreRoles.Owner, UserId = user2.UserId })); new StoreUserData() { Role = StoreRoles.Owner, UserId = user2.UserId }));
await user2Client.RemoveStoreUser(user.StoreId, user.UserId); await user2Client.RemoveStoreUser(user.StoreId, user.UserId);
@@ -2985,13 +3015,13 @@ namespace BTCPayServer.Tests
Assert.True(await adminClient.LockUser(newUser.UserId, true, CancellationToken.None)); Assert.True(await adminClient.LockUser(newUser.UserId, true, CancellationToken.None));
Assert.True((await adminClient.GetUserByIdOrEmail(newUser.UserId)).Disabled); Assert.True((await adminClient.GetUserByIdOrEmail(newUser.UserId)).Disabled);
await AssertAPIError("unauthenticated",async () => await AssertAPIError("unauthenticated", async () =>
{ {
await newUserClient.GetCurrentUser(); await newUserClient.GetCurrentUser();
}); });
var newUserBasicClient = new BTCPayServerClient(newUserClient.Host, newUser.RegisterDetails.Email, var newUserBasicClient = new BTCPayServerClient(newUserClient.Host, newUser.RegisterDetails.Email,
newUser.RegisterDetails.Password); newUser.RegisterDetails.Password);
await AssertAPIError("unauthenticated",async () => await AssertAPIError("unauthenticated", async () =>
{ {
await newUserBasicClient.GetCurrentUser(); await newUserBasicClient.GetCurrentUser();
}); });
@@ -3037,17 +3067,19 @@ namespace BTCPayServer.Tests
var payout = await adminClient.CreatePayout(admin.StoreId, var payout = await adminClient.CreatePayout(admin.StoreId,
new CreatePayoutThroughStoreRequest() new CreatePayoutThroughStoreRequest()
{ {
Approved = true, PaymentMethod = "BTC_LightningNetwork", Destination = customerInvoice.BOLT11 Approved = true,
PaymentMethod = "BTC_LightningNetwork",
Destination = customerInvoice.BOLT11
}); });
Assert.Empty(await adminClient.GetStoreLightningAutomatedPayoutProcessors(admin.StoreId, "BTC_LightningNetwork")); Assert.Empty(await adminClient.GetStoreLightningAutomatedPayoutProcessors(admin.StoreId, "BTC_LightningNetwork"));
await adminClient.UpdateStoreLightningAutomatedPayoutProcessors(admin.StoreId, "BTC_LightningNetwork", await adminClient.UpdateStoreLightningAutomatedPayoutProcessors(admin.StoreId, "BTC_LightningNetwork",
new LightningAutomatedPayoutSettings() {IntervalSeconds = TimeSpan.FromSeconds(2)}); new LightningAutomatedPayoutSettings() { IntervalSeconds = TimeSpan.FromSeconds(2) });
Assert.Equal(2, Assert.Single( await adminClient.GetStoreLightningAutomatedPayoutProcessors(admin.StoreId, "BTC_LightningNetwork")).IntervalSeconds.TotalSeconds); Assert.Equal(2, Assert.Single(await adminClient.GetStoreLightningAutomatedPayoutProcessors(admin.StoreId, "BTC_LightningNetwork")).IntervalSeconds.TotalSeconds);
await TestUtils.EventuallyAsync(async () => await TestUtils.EventuallyAsync(async () =>
{ {
var payoutC = var payoutC =
(await adminClient.GetStorePayouts(admin.StoreId, false)).Single(data => data.Id == payout.Id); (await adminClient.GetStorePayouts(admin.StoreId, false)).Single(data => data.Id == payout.Id);
Assert.Equal(PayoutState.Completed , payoutC.State); Assert.Equal(PayoutState.Completed, payoutC.State);
}); });
} }
@@ -3065,7 +3097,7 @@ namespace BTCPayServer.Tests
var adminClient = await admin.CreateClient(Policies.Unrestricted); var adminClient = await admin.CreateClient(Policies.Unrestricted);
var registeredProcessors = await adminClient.GetPayoutProcessors(); var registeredProcessors = await adminClient.GetPayoutProcessors();
Assert.Equal(2,registeredProcessors.Count()); Assert.Equal(2, registeredProcessors.Count());
await adminClient.GenerateOnChainWallet(admin.StoreId, "BTC", new GenerateOnChainWalletRequest() await adminClient.GenerateOnChainWallet(admin.StoreId, "BTC", new GenerateOnChainWalletRequest()
{ {
SavePrivateKeys = true SavePrivateKeys = true
@@ -3092,7 +3124,7 @@ namespace BTCPayServer.Tests
Amount = 100, Amount = 100,
Currency = "USD", Currency = "USD",
Name = "pull payment", Name = "pull payment",
PaymentMethods = new []{ "BTC"} PaymentMethods = new[] { "BTC" }
}); });
var notapprovedPayoutWithPullPayment = await adminClient.CreatePayout(admin.StoreId, new CreatePayoutThroughStoreRequest() var notapprovedPayoutWithPullPayment = await adminClient.CreatePayout(admin.StoreId, new CreatePayoutThroughStoreRequest()
@@ -3120,25 +3152,25 @@ namespace BTCPayServer.Tests
Assert.Empty(payouts.Where(data => data.State == PayoutState.AwaitingApproval)); Assert.Empty(payouts.Where(data => data.State == PayoutState.AwaitingApproval));
Assert.Empty(payouts.Where(data => data.PaymentMethodAmount is null)); Assert.Empty(payouts.Where(data => data.PaymentMethodAmount is null));
Assert.Empty( await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC")); Assert.Empty(await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC"));
Assert.Empty( await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC")); Assert.Empty(await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC"));
Assert.Empty(await adminClient.GetPayoutProcessors(admin.StoreId)); Assert.Empty(await adminClient.GetPayoutProcessors(admin.StoreId));
await adminClient.UpdateStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC", await adminClient.UpdateStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC",
new OnChainAutomatedPayoutSettings() {IntervalSeconds = TimeSpan.FromSeconds(100000)}); new OnChainAutomatedPayoutSettings() { IntervalSeconds = TimeSpan.FromSeconds(100000) });
Assert.Equal(100000, Assert.Single( await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC")).IntervalSeconds.TotalSeconds); Assert.Equal(100000, Assert.Single(await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC")).IntervalSeconds.TotalSeconds);
var tpGen = Assert.Single(await adminClient.GetPayoutProcessors(admin.StoreId)); var tpGen = Assert.Single(await adminClient.GetPayoutProcessors(admin.StoreId));
Assert.Equal("BTC", Assert.Single(tpGen.PaymentMethods)); Assert.Equal("BTC", Assert.Single(tpGen.PaymentMethods));
//still too poor to process any payouts //still too poor to process any payouts
Assert.Empty( await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC")); Assert.Empty(await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC"));
await adminClient.RemovePayoutProcessor(admin.StoreId, tpGen.Name, tpGen.PaymentMethods.First()); await adminClient.RemovePayoutProcessor(admin.StoreId, tpGen.Name, tpGen.PaymentMethods.First());
Assert.Empty( await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC")); Assert.Empty(await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC"));
Assert.Empty(await adminClient.GetPayoutProcessors(admin.StoreId)); Assert.Empty(await adminClient.GetPayoutProcessors(admin.StoreId));
await tester.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create((await adminClient.GetOnChainWalletReceiveAddress(admin.StoreId, "BTC", true)).Address, await tester.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create((await adminClient.GetOnChainWalletReceiveAddress(admin.StoreId, "BTC", true)).Address,
@@ -3152,8 +3184,8 @@ namespace BTCPayServer.Tests
Assert.Equal(3, payouts.Length); Assert.Equal(3, payouts.Length);
}); });
await adminClient.UpdateStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC", await adminClient.UpdateStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC",
new OnChainAutomatedPayoutSettings() {IntervalSeconds = TimeSpan.FromSeconds(5)}); new OnChainAutomatedPayoutSettings() { IntervalSeconds = TimeSpan.FromSeconds(5) });
Assert.Equal(5, Assert.Single( await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC")).IntervalSeconds.TotalSeconds); Assert.Equal(5, Assert.Single(await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC")).IntervalSeconds.TotalSeconds);
await TestUtils.EventuallyAsync(async () => await TestUtils.EventuallyAsync(async () =>
{ {
Assert.Equal(2, (await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC")).Count()); Assert.Equal(2, (await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC")).Count());
@@ -3284,7 +3316,7 @@ namespace BTCPayServer.Tests
var allObjects = await client.GetOnChainWalletObjects(admin.StoreId, "BTC"); var allObjects = await client.GetOnChainWalletObjects(admin.StoreId, "BTC");
var allTests = await client.GetOnChainWalletObjects(admin.StoreId, "BTC", new GetWalletObjectsRequest() { Type = "test" }); var allTests = await client.GetOnChainWalletObjects(admin.StoreId, "BTC", new GetWalletObjectsRequest() { Type = "test" });
var twoTests2 = await client.GetOnChainWalletObjects(admin.StoreId, "BTC", new GetWalletObjectsRequest() { Type = "test", Ids = new[] { "test1", "test2", "test-unk" } }); var twoTests2 = await client.GetOnChainWalletObjects(admin.StoreId, "BTC", new GetWalletObjectsRequest() { Type = "test", Ids = new[] { "test1", "test2", "test-unk" } });
var oneTest = await client.GetOnChainWalletObjects(admin.StoreId, "BTC", new GetWalletObjectsRequest() { Type = "test", Ids=new[] { "test" } }); var oneTest = await client.GetOnChainWalletObjects(admin.StoreId, "BTC", new GetWalletObjectsRequest() { Type = "test", Ids = new[] { "test" } });
var oneTestWithoutData = await client.GetOnChainWalletObjects(admin.StoreId, "BTC", new GetWalletObjectsRequest() { Type = "test", Ids = new[] { "test" }, IncludeNeighbourData = false }); var oneTestWithoutData = await client.GetOnChainWalletObjects(admin.StoreId, "BTC", new GetWalletObjectsRequest() { Type = "test", Ids = new[] { "test" }, IncludeNeighbourData = false });
Assert.Equal(4, allObjects.Length); Assert.Equal(4, allObjects.Length);
@@ -3338,11 +3370,11 @@ namespace BTCPayServer.Tests
Assert.Equal(0.9m, Assert.Equal(0.9m,
Assert.Single(await clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, Assert.Single(await clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId,
new StoreRateConfiguration() {IsCustomScript = true, EffectiveScript = "BTC_XYZ = 1;", Spread = 10m,}, new StoreRateConfiguration() { IsCustomScript = true, EffectiveScript = "BTC_XYZ = 1;", Spread = 10m, },
new[] {"BTC_XYZ"})).Rate); new[] { "BTC_XYZ" })).Rate);
Assert.True((await clientBasic.UpdateStoreRateConfiguration(user.StoreId, Assert.True((await clientBasic.UpdateStoreRateConfiguration(user.StoreId,
new StoreRateConfiguration() { IsCustomScript = true, EffectiveScript = "BTC_XYZ = 1", Spread = 10m,})) new StoreRateConfiguration() { IsCustomScript = true, EffectiveScript = "BTC_XYZ = 1", Spread = 10m, }))
.IsCustomScript); .IsCustomScript);
config = await clientBasic.GetStoreRateConfiguration(user.StoreId); config = await clientBasic.GetStoreRateConfiguration(user.StoreId);
@@ -3354,7 +3386,7 @@ namespace BTCPayServer.Tests
Assert.NotNull((await clientBasic.GetStoreRateConfiguration(user.StoreId)).EffectiveScript); Assert.NotNull((await clientBasic.GetStoreRateConfiguration(user.StoreId)).EffectiveScript);
Assert.NotNull((await clientBasic.UpdateStoreRateConfiguration(user.StoreId, Assert.NotNull((await clientBasic.UpdateStoreRateConfiguration(user.StoreId,
new StoreRateConfiguration() { IsCustomScript = false, PreferredSource = "coingecko"})) new StoreRateConfiguration() { IsCustomScript = false, PreferredSource = "coingecko" }))
.PreferredSource); .PreferredSource);
config = await clientBasic.GetStoreRateConfiguration(user.StoreId); config = await clientBasic.GetStoreRateConfiguration(user.StoreId);
@@ -3480,10 +3512,10 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
Assert.Equal(singleAdminCustodianAccount.CustodianCode, custodian.Code); Assert.Equal(singleAdminCustodianAccount.CustodianCode, custodian.Code);
// Wrong store ID // Wrong store ID
await AssertApiError(403, "missing-permission",async () => await adminClient.GetCustodianAccount("WRONG-STORE-ID", accountId)); await AssertApiError(403, "missing-permission", async () => await adminClient.GetCustodianAccount("WRONG-STORE-ID", accountId));
// Wrong account ID // Wrong account ID
await AssertApiError(404, "custodian-account-not-found",async () => await adminClient.GetCustodianAccount(storeId, "WRONG-ACCOUNT-ID")); await AssertApiError(404, "custodian-account-not-found", async () => await adminClient.GetCustodianAccount(storeId, "WRONG-ACCOUNT-ID"));
// Manager can see, including config // Manager can see, including config
var singleManagerCustodianAccount = await managerClient.GetCustodianAccount(storeId, accountId); var singleManagerCustodianAccount = await managerClient.GetCustodianAccount(storeId, accountId);
@@ -3599,7 +3631,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
// Test: Get Asset Balances // Test: Get Asset Balances
var custodianAccountWithBalances = await adminClient.GetCustodianAccount(storeId, accountId,true); var custodianAccountWithBalances = await adminClient.GetCustodianAccount(storeId, accountId, true);
Assert.NotNull(custodianAccountWithBalances); Assert.NotNull(custodianAccountWithBalances);
Assert.NotNull(custodianAccountWithBalances.AssetBalances); Assert.NotNull(custodianAccountWithBalances.AssetBalances);
Assert.Equal(4, custodianAccountWithBalances.AssetBalances.Count); Assert.Equal(4, custodianAccountWithBalances.AssetBalances.Count);
@@ -3613,7 +3645,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
Assert.Equal(MockCustodian.BalanceUSD, custodianAccountWithBalances.AssetBalances["USD"]); Assert.Equal(MockCustodian.BalanceUSD, custodianAccountWithBalances.AssetBalances["USD"]);
// Test: Get Asset Balances omitted if we choose so // Test: Get Asset Balances omitted if we choose so
var custodianAccountWithoutBalances = await adminClient.GetCustodianAccount(storeId, accountId,false); var custodianAccountWithoutBalances = await adminClient.GetCustodianAccount(storeId, accountId, false);
Assert.NotNull(custodianAccountWithoutBalances); Assert.NotNull(custodianAccountWithoutBalances);
Assert.Null(custodianAccountWithoutBalances.AssetBalances); Assert.Null(custodianAccountWithoutBalances.AssetBalances);
@@ -3640,7 +3672,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
// Test: Trade, unauth // Test: Trade, unauth
var tradeRequest = new TradeRequestData {FromAsset = MockCustodian.TradeFromAsset, ToAsset = MockCustodian.TradeToAsset, Qty = MockCustodian.TradeQtyBought.ToString(CultureInfo.InvariantCulture)}; var tradeRequest = new TradeRequestData { FromAsset = MockCustodian.TradeFromAsset, ToAsset = MockCustodian.TradeToAsset, Qty = MockCustodian.TradeQtyBought.ToString(CultureInfo.InvariantCulture) };
await AssertHttpError(401, async () => await unauthClient.MarketTradeCustodianAccountAsset(storeId, accountId, tradeRequest)); await AssertHttpError(401, async () => await unauthClient.MarketTradeCustodianAccountAsset(storeId, accountId, tradeRequest));
// Test: Trade, auth, but wrong permission // Test: Trade, auth, but wrong permission
@@ -3654,30 +3686,30 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
Assert.Equal(MockCustodian.TradeId, newTradeResult.TradeId); Assert.Equal(MockCustodian.TradeId, newTradeResult.TradeId);
Assert.Equal(tradeRequest.FromAsset, newTradeResult.FromAsset); Assert.Equal(tradeRequest.FromAsset, newTradeResult.FromAsset);
Assert.Equal(tradeRequest.ToAsset, newTradeResult.ToAsset); Assert.Equal(tradeRequest.ToAsset, newTradeResult.ToAsset);
Assert.NotNull( newTradeResult.LedgerEntries); Assert.NotNull(newTradeResult.LedgerEntries);
Assert.Equal( 3, newTradeResult.LedgerEntries.Count); Assert.Equal(3, newTradeResult.LedgerEntries.Count);
Assert.Equal( MockCustodian.TradeQtyBought, newTradeResult.LedgerEntries[0].Qty); Assert.Equal(MockCustodian.TradeQtyBought, newTradeResult.LedgerEntries[0].Qty);
Assert.Equal( tradeRequest.ToAsset, newTradeResult.LedgerEntries[0].Asset); Assert.Equal(tradeRequest.ToAsset, newTradeResult.LedgerEntries[0].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Trade , newTradeResult.LedgerEntries[0].Type); Assert.Equal(LedgerEntryData.LedgerEntryType.Trade, newTradeResult.LedgerEntries[0].Type);
Assert.Equal( -1 * MockCustodian.TradeQtyBought * MockCustodian.BtcPriceInEuro, newTradeResult.LedgerEntries[1].Qty); Assert.Equal(-1 * MockCustodian.TradeQtyBought * MockCustodian.BtcPriceInEuro, newTradeResult.LedgerEntries[1].Qty);
Assert.Equal( tradeRequest.FromAsset, newTradeResult.LedgerEntries[1].Asset); Assert.Equal(tradeRequest.FromAsset, newTradeResult.LedgerEntries[1].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Trade , newTradeResult.LedgerEntries[1].Type); Assert.Equal(LedgerEntryData.LedgerEntryType.Trade, newTradeResult.LedgerEntries[1].Type);
Assert.Equal( -1 * MockCustodian.TradeFeeEuro, newTradeResult.LedgerEntries[2].Qty); Assert.Equal(-1 * MockCustodian.TradeFeeEuro, newTradeResult.LedgerEntries[2].Qty);
Assert.Equal( tradeRequest.FromAsset, newTradeResult.LedgerEntries[2].Asset); Assert.Equal(tradeRequest.FromAsset, newTradeResult.LedgerEntries[2].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Fee , newTradeResult.LedgerEntries[2].Type); Assert.Equal(LedgerEntryData.LedgerEntryType.Fee, newTradeResult.LedgerEntries[2].Type);
// Test: GetTradeQuote, SATS // Test: GetTradeQuote, SATS
var satsTradeRequest = new TradeRequestData {FromAsset = MockCustodian.TradeFromAsset, ToAsset = "SATS", Qty = MockCustodian.TradeQtyBought.ToString(CultureInfo.InvariantCulture)}; var satsTradeRequest = new TradeRequestData { FromAsset = MockCustodian.TradeFromAsset, ToAsset = "SATS", Qty = MockCustodian.TradeQtyBought.ToString(CultureInfo.InvariantCulture) };
await AssertApiError(400, "use-asset-synonym", async () => await tradeClient.MarketTradeCustodianAccountAsset(storeId, accountId, satsTradeRequest)); await AssertApiError(400, "use-asset-synonym", async () => await tradeClient.MarketTradeCustodianAccountAsset(storeId, accountId, satsTradeRequest));
// TODO Test: Trade with percentage qty // TODO Test: Trade with percentage qty
// Test: Trade with wrong decimal format (example: JavaScript scientific format) // Test: Trade with wrong decimal format (example: JavaScript scientific format)
var wrongQtyTradeRequest = new TradeRequestData {FromAsset = MockCustodian.TradeFromAsset, ToAsset = MockCustodian.TradeToAsset, Qty = "6.1e-7"}; var wrongQtyTradeRequest = new TradeRequestData { FromAsset = MockCustodian.TradeFromAsset, ToAsset = MockCustodian.TradeToAsset, Qty = "6.1e-7" };
await AssertApiError(400,"bad-qty-format", async () => await tradeClient.MarketTradeCustodianAccountAsset(storeId, accountId, wrongQtyTradeRequest)); await AssertApiError(400, "bad-qty-format", async () => await tradeClient.MarketTradeCustodianAccountAsset(storeId, accountId, wrongQtyTradeRequest));
// Test: Trade, wrong assets method // Test: Trade, wrong assets method
var wrongAssetsTradeRequest = new TradeRequestData {FromAsset = "WRONG", ToAsset = MockCustodian.TradeToAsset, Qty = MockCustodian.TradeQtyBought.ToString(CultureInfo.InvariantCulture)}; var wrongAssetsTradeRequest = new TradeRequestData { FromAsset = "WRONG", ToAsset = MockCustodian.TradeToAsset, Qty = MockCustodian.TradeQtyBought.ToString(CultureInfo.InvariantCulture) };
await AssertHttpError(WrongTradingPairException.HttpCode, async () => await tradeClient.MarketTradeCustodianAccountAsset(storeId, accountId, wrongAssetsTradeRequest)); await AssertHttpError(WrongTradingPairException.HttpCode, async () => await tradeClient.MarketTradeCustodianAccountAsset(storeId, accountId, wrongAssetsTradeRequest));
// Test: wrong account ID // Test: wrong account ID
@@ -3687,7 +3719,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
await AssertHttpError(403, async () => await tradeClient.MarketTradeCustodianAccountAsset("WRONG-STORE-ID", accountId, tradeRequest)); await AssertHttpError(403, async () => await tradeClient.MarketTradeCustodianAccountAsset("WRONG-STORE-ID", accountId, tradeRequest));
// Test: Trade, correct assets, wrong amount // Test: Trade, correct assets, wrong amount
var insufficientFundsTradeRequest = new TradeRequestData {FromAsset = MockCustodian.TradeFromAsset, ToAsset = MockCustodian.TradeToAsset, Qty = "0.01"}; var insufficientFundsTradeRequest = new TradeRequestData { FromAsset = MockCustodian.TradeFromAsset, ToAsset = MockCustodian.TradeToAsset, Qty = "0.01" };
await AssertApiError(400, "insufficient-funds", async () => await tradeClient.MarketTradeCustodianAccountAsset(storeId, accountId, insufficientFundsTradeRequest)); await AssertApiError(400, "insufficient-funds", async () => await tradeClient.MarketTradeCustodianAccountAsset(storeId, accountId, insufficientFundsTradeRequest));
@@ -3710,7 +3742,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
// Test: GetTradeQuote, wrong asset // Test: GetTradeQuote, wrong asset
await AssertHttpError(404, async () => await tradeClient.GetTradeQuote(storeId, accountId, "WRONG-ASSET", MockCustodian.TradeToAsset)); await AssertHttpError(404, async () => await tradeClient.GetTradeQuote(storeId, accountId, "WRONG-ASSET", MockCustodian.TradeToAsset));
await AssertHttpError(404, async () => await tradeClient.GetTradeQuote(storeId, accountId, MockCustodian.TradeFromAsset , "WRONG-ASSET")); await AssertHttpError(404, async () => await tradeClient.GetTradeQuote(storeId, accountId, MockCustodian.TradeFromAsset, "WRONG-ASSET"));
// Test: wrong account ID // Test: wrong account ID
await AssertHttpError(404, async () => await tradeClient.GetTradeQuote(storeId, "WRONG-ACCOUNT-ID", MockCustodian.TradeFromAsset, MockCustodian.TradeToAsset)); await AssertHttpError(404, async () => await tradeClient.GetTradeQuote(storeId, "WRONG-ACCOUNT-ID", MockCustodian.TradeFromAsset, MockCustodian.TradeToAsset));
@@ -3736,17 +3768,17 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
Assert.Equal(MockCustodian.TradeId, tradeResult.TradeId); Assert.Equal(MockCustodian.TradeId, tradeResult.TradeId);
Assert.Equal(tradeRequest.FromAsset, tradeResult.FromAsset); Assert.Equal(tradeRequest.FromAsset, tradeResult.FromAsset);
Assert.Equal(tradeRequest.ToAsset, tradeResult.ToAsset); Assert.Equal(tradeRequest.ToAsset, tradeResult.ToAsset);
Assert.NotNull( tradeResult.LedgerEntries); Assert.NotNull(tradeResult.LedgerEntries);
Assert.Equal( 3, tradeResult.LedgerEntries.Count); Assert.Equal(3, tradeResult.LedgerEntries.Count);
Assert.Equal( MockCustodian.TradeQtyBought, tradeResult.LedgerEntries[0].Qty); Assert.Equal(MockCustodian.TradeQtyBought, tradeResult.LedgerEntries[0].Qty);
Assert.Equal( tradeRequest.ToAsset, tradeResult.LedgerEntries[0].Asset); Assert.Equal(tradeRequest.ToAsset, tradeResult.LedgerEntries[0].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Trade , tradeResult.LedgerEntries[0].Type); Assert.Equal(LedgerEntryData.LedgerEntryType.Trade, tradeResult.LedgerEntries[0].Type);
Assert.Equal( -1 * MockCustodian.TradeQtyBought * MockCustodian.BtcPriceInEuro, tradeResult.LedgerEntries[1].Qty); Assert.Equal(-1 * MockCustodian.TradeQtyBought * MockCustodian.BtcPriceInEuro, tradeResult.LedgerEntries[1].Qty);
Assert.Equal( tradeRequest.FromAsset, tradeResult.LedgerEntries[1].Asset); Assert.Equal(tradeRequest.FromAsset, tradeResult.LedgerEntries[1].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Trade , tradeResult.LedgerEntries[1].Type); Assert.Equal(LedgerEntryData.LedgerEntryType.Trade, tradeResult.LedgerEntries[1].Type);
Assert.Equal( -1 * MockCustodian.TradeFeeEuro, tradeResult.LedgerEntries[2].Qty); Assert.Equal(-1 * MockCustodian.TradeFeeEuro, tradeResult.LedgerEntries[2].Qty);
Assert.Equal( tradeRequest.FromAsset, tradeResult.LedgerEntries[2].Asset); Assert.Equal(tradeRequest.FromAsset, tradeResult.LedgerEntries[2].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Fee , tradeResult.LedgerEntries[2].Type); Assert.Equal(LedgerEntryData.LedgerEntryType.Fee, tradeResult.LedgerEntries[2].Type);
// Test: GetTradeInfo, wrong trade ID // Test: GetTradeInfo, wrong trade ID
await AssertHttpError(404, async () => await tradeClient.GetTradeInfo(storeId, accountId, "WRONG-TRADE-ID")); await AssertHttpError(404, async () => await tradeClient.GetTradeInfo(storeId, accountId, "WRONG-TRADE-ID"));
@@ -3759,7 +3791,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
// Test: CreateWithdrawal, unauth // Test: CreateWithdrawal, unauth
var createWithdrawalRequest = new WithdrawRequestData(MockCustodian.WithdrawalPaymentMethod, MockCustodian.WithdrawalAmount ); var createWithdrawalRequest = new WithdrawRequestData(MockCustodian.WithdrawalPaymentMethod, MockCustodian.WithdrawalAmount);
await AssertHttpError(401, async () => await unauthClient.CreateWithdrawal(storeId, accountId, createWithdrawalRequest)); await AssertHttpError(401, async () => await unauthClient.CreateWithdrawal(storeId, accountId, createWithdrawalRequest));
// Test: CreateWithdrawal, auth, but wrong permission // Test: CreateWithdrawal, auth, but wrong permission
@@ -3771,7 +3803,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
// Test: CreateWithdrawal, wrong payment method // Test: CreateWithdrawal, wrong payment method
var wrongPaymentMethodCreateWithdrawalRequest = new WithdrawRequestData("WRONG-PAYMENT-METHOD", MockCustodian.WithdrawalAmount ); var wrongPaymentMethodCreateWithdrawalRequest = new WithdrawRequestData("WRONG-PAYMENT-METHOD", MockCustodian.WithdrawalAmount);
await AssertHttpError(403, async () => await withdrawalClient.CreateWithdrawal(storeId, accountId, wrongPaymentMethodCreateWithdrawalRequest)); await AssertHttpError(403, async () => await withdrawalClient.CreateWithdrawal(storeId, accountId, wrongPaymentMethodCreateWithdrawalRequest));
// Test: CreateWithdrawal, wrong account ID // Test: CreateWithdrawal, wrong account ID
@@ -3779,7 +3811,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
// Test: CreateWithdrawal, wrong store ID // Test: CreateWithdrawal, wrong store ID
// TODO it is wierd that 403 is considered normal, but it is like this for all calls where the store is wrong... I'd have preferred a 404 error, because the store cannot be found. // TODO it is wierd that 403 is considered normal, but it is like this for all calls where the store is wrong... I'd have preferred a 404 error, because the store cannot be found.
await AssertHttpError(403, async () => await withdrawalClient.CreateWithdrawal( "WRONG-STORE-ID",accountId, createWithdrawalRequest)); await AssertHttpError(403, async () => await withdrawalClient.CreateWithdrawal("WRONG-STORE-ID", accountId, createWithdrawalRequest));
// Test: CreateWithdrawal, correct payment method, wrong amount // Test: CreateWithdrawal, correct payment method, wrong amount
var wrongAmountCreateWithdrawalRequest = new WithdrawRequestData(MockCustodian.WithdrawalPaymentMethod, new decimal(0.666)); var wrongAmountCreateWithdrawalRequest = new WithdrawRequestData(MockCustodian.WithdrawalPaymentMethod, new decimal(0.666));

View File

@@ -77,7 +77,7 @@ public class MockCustodian : ICustodian, ICanDeposit, ICanTrade, ICanWithdraw
public List<AssetPairData> GetTradableAssetPairs() public List<AssetPairData> GetTradableAssetPairs()
{ {
var r = new List<AssetPairData>(); var r = new List<AssetPairData>();
r.Add(new AssetPairData("BTC", "EUR", (decimal) 0.0001)); r.Add(new AssetPairData("BTC", "EUR", (decimal)0.0001));
return r; return r;
} }

View File

@@ -555,7 +555,7 @@ namespace BTCPayServer.Tests
for (var i = 0; i < coins; i++) for (var i = 0; i < coins; i++)
{ {
bool mined = false; bool mined = false;
retry: retry:
try try
{ {
await Server.ExplorerNode.SendToAddressAsync(address, Money.Coins(denomination)); await Server.ExplorerNode.SendToAddressAsync(address, Money.Coins(denomination));

View File

@@ -1704,7 +1704,7 @@ namespace BTCPayServer.Tests
//lnurl-w support check //lnurl-w support check
s.GoToStore(s.StoreId,StoreNavPages.PullPayments); s.GoToStore(s.StoreId, StoreNavPages.PullPayments);
s.Driver.FindElement(By.Id("NewPullPayment")).Click(); s.Driver.FindElement(By.Id("NewPullPayment")).Click();
s.Driver.FindElement(By.Id("Name")).SendKeys("PP1"); s.Driver.FindElement(By.Id("Name")).SendKeys("PP1");
s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true); s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true);
@@ -1735,10 +1735,10 @@ namespace BTCPayServer.Tests
Assert.Contains(bolt2.BOLT11, s.Driver.PageSource); Assert.Contains(bolt2.BOLT11, s.Driver.PageSource);
Assert.Contains(PayoutState.Completed.GetStateString(), s.Driver.PageSource); Assert.Contains(PayoutState.Completed.GetStateString(), s.Driver.PageSource);
Assert.Equal( LightningInvoiceStatus.Paid, (await s.Server.CustomerLightningD.GetInvoice(bolt2.Id)).Status ); Assert.Equal(LightningInvoiceStatus.Paid, (await s.Server.CustomerLightningD.GetInvoice(bolt2.Id)).Status);
}); });
s.GoToStore(s.StoreId,StoreNavPages.PullPayments); s.GoToStore(s.StoreId, StoreNavPages.PullPayments);
s.Driver.FindElement(By.Id("NewPullPayment")).Click(); s.Driver.FindElement(By.Id("NewPullPayment")).Click();
s.Driver.FindElement(By.Id("Name")).SendKeys("PP1"); s.Driver.FindElement(By.Id("Name")).SendKeys("PP1");
s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), false); s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), false);
@@ -1867,7 +1867,8 @@ namespace BTCPayServer.Tests
}); });
var greenfield = await s.AsTestAccount().CreateClient(); var greenfield = await s.AsTestAccount().CreateClient();
var paymentMethods = await greenfield.GetInvoicePaymentMethods(s.StoreId, i); var paymentMethods = await greenfield.GetInvoicePaymentMethods(s.StoreId, i);
Assert.Single(paymentMethods, p => { Assert.Single(paymentMethods, p =>
{
return p.AdditionalData["providedComment"].Value<string>() == "lol2"; return p.AdditionalData["providedComment"].Value<string>() == "lol2";
}); });
// Standard invoice test // Standard invoice test
@@ -2138,13 +2139,13 @@ retry:
.FindElement(By.CssSelector($"option[value='{(int)Fido2Credential.CredentialType.LNURLAuth}']")).Click(); .FindElement(By.CssSelector($"option[value='{(int)Fido2Credential.CredentialType.LNURLAuth}']")).Click();
s.Driver.FindElement(By.Id("btn-add")).Click(); s.Driver.FindElement(By.Id("btn-add")).Click();
var links = s.Driver.FindElements(By.CssSelector(".tab-content a")).Select(element => element.GetAttribute("href")); var links = s.Driver.FindElements(By.CssSelector(".tab-content a")).Select(element => element.GetAttribute("href"));
Assert.Equal(2,links.Count()); Assert.Equal(2, links.Count());
Uri prevEndpoint = null; Uri prevEndpoint = null;
foreach (string link in links) foreach (string link in links)
{ {
var endpoint = LNURL.LNURL.Parse(link, out var tag); var endpoint = LNURL.LNURL.Parse(link, out var tag);
Assert.Equal("login",tag); Assert.Equal("login", tag);
if(endpoint.Scheme != "https") if (endpoint.Scheme != "https")
prevEndpoint = endpoint; prevEndpoint = endpoint;
} }
@@ -2157,13 +2158,13 @@ retry:
s.LogIn(user, "123456"); s.LogIn(user, "123456");
var section = s.Driver.FindElement(By.Id("lnurlauth-section")); var section = s.Driver.FindElement(By.Id("lnurlauth-section"));
links = section.FindElements(By.CssSelector(".tab-content a")).Select(element => element.GetAttribute("href")); links = section.FindElements(By.CssSelector(".tab-content a")).Select(element => element.GetAttribute("href"));
Assert.Equal(2,links.Count()); Assert.Equal(2, links.Count());
prevEndpoint = null; prevEndpoint = null;
foreach (string link in links) foreach (string link in links)
{ {
var endpoint = LNURL.LNURL.Parse(link, out var tag); var endpoint = LNURL.LNURL.Parse(link, out var tag);
Assert.Equal("login",tag); Assert.Equal("login", tag);
if(endpoint.Scheme != "https") if (endpoint.Scheme != "https")
prevEndpoint = endpoint; prevEndpoint = endpoint;
} }
request = Assert.IsType<LNAuthRequest>(await LNURL.LNURL.FetchInformation(prevEndpoint, null)); request = Assert.IsType<LNAuthRequest>(await LNURL.LNURL.FetchInformation(prevEndpoint, null));

View File

@@ -75,7 +75,7 @@ namespace BTCPayServer.Tests
public async Task CanQueryDirectProviders() public async Task CanQueryDirectProviders()
{ {
// TODO: Check once in a while whether or not they are working again // TODO: Check once in a while whether or not they are working again
string[] brokenShitcoinCasinos = {}; string[] brokenShitcoinCasinos = { };
var skipped = 0; var skipped = 0;
var factory = FastTests.CreateBTCPayRateFactory(); var factory = FastTests.CreateBTCPayRateFactory();
var directlySupported = factory.GetSupportedExchanges().Where(s => s.Source == RateSource.Direct) var directlySupported = factory.GetSupportedExchanges().Where(s => s.Source == RateSource.Direct)
@@ -225,7 +225,7 @@ namespace BTCPayServer.Tests
{ {
var uri = new Uri(url); var uri = new Uri(url);
int retryLeft = 3; int retryLeft = 3;
retry: retry:
try try
{ {
using var request = new HttpRequestMessage(HttpMethod.Get, uri); using var request = new HttpRequestMessage(HttpMethod.Get, uri);

View File

@@ -199,11 +199,11 @@ namespace BTCPayServer.Tests
var user = tester.NewAccount(); var user = tester.NewAccount();
await user.GrantAccessAsync(); await user.GrantAccessAsync();
var settingsRepo = tester.PayTester.ServiceProvider.GetRequiredService<IStoreRepository>(); var settingsRepo = tester.PayTester.ServiceProvider.GetRequiredService<IStoreRepository>();
var arbValue = await settingsRepo.GetSettingAsync<string>(user.StoreId,"arbitrary"); var arbValue = await settingsRepo.GetSettingAsync<string>(user.StoreId, "arbitrary");
Assert.Null(arbValue); Assert.Null(arbValue);
await settingsRepo.UpdateSetting(user.StoreId, "arbitrary", "saved"); await settingsRepo.UpdateSetting(user.StoreId, "arbitrary", "saved");
arbValue = await settingsRepo.GetSettingAsync<string>(user.StoreId,"arbitrary"); arbValue = await settingsRepo.GetSettingAsync<string>(user.StoreId, "arbitrary");
Assert.Equal("saved", arbValue); Assert.Equal("saved", arbValue);
await settingsRepo.UpdateSetting<TestData>(user.StoreId, "arbitrary", new TestData() { Name = "hello" }); await settingsRepo.UpdateSetting<TestData>(user.StoreId, "arbitrary", new TestData() { Name = "hello" });

View File

@@ -26,8 +26,10 @@ public class AppSales : ViewComponent
public async Task<IViewComponentResult> InvokeAsync(AppSalesViewModel vm) public async Task<IViewComponentResult> InvokeAsync(AppSalesViewModel vm)
{ {
if (vm.App == null) throw new ArgumentNullException(nameof(vm.App)); if (vm.App == null)
if (vm.InitialRendering) return View(vm); throw new ArgumentNullException(nameof(vm.App));
if (vm.InitialRendering)
return View(vm);
var stats = await _appService.GetSalesStats(vm.App); var stats = await _appService.GetSalesStats(vm.App);

View File

@@ -20,8 +20,10 @@ public class AppTopItems : ViewComponent
public async Task<IViewComponentResult> InvokeAsync(AppTopItemsViewModel vm) public async Task<IViewComponentResult> InvokeAsync(AppTopItemsViewModel vm)
{ {
if (vm.App == null) throw new ArgumentNullException(nameof(vm.App)); if (vm.App == null)
if (vm.InitialRendering) return View(vm); throw new ArgumentNullException(nameof(vm.App));
if (vm.InitialRendering)
return View(vm);
var entries = Enum.Parse<AppType>(vm.App.AppType) == AppType.Crowdfund var entries = Enum.Parse<AppType>(vm.App.AppType) == AppType.Crowdfund
? await _appService.GetPerkStats(vm.App) ? await _appService.GetPerkStats(vm.App)

View File

@@ -47,13 +47,16 @@ public class StoreLightningBalance : ViewComponent
public async Task<IViewComponentResult> InvokeAsync(StoreLightningBalanceViewModel vm) public async Task<IViewComponentResult> InvokeAsync(StoreLightningBalanceViewModel vm)
{ {
if (vm.Store == null) throw new ArgumentNullException(nameof(vm.Store)); if (vm.Store == null)
if (vm.CryptoCode == null) throw new ArgumentNullException(nameof(vm.CryptoCode)); throw new ArgumentNullException(nameof(vm.Store));
if (vm.CryptoCode == null)
throw new ArgumentNullException(nameof(vm.CryptoCode));
vm.DefaultCurrency = vm.Store.GetStoreBlob().DefaultCurrency; vm.DefaultCurrency = vm.Store.GetStoreBlob().DefaultCurrency;
vm.CurrencyData = _currencies.GetCurrencyData(vm.DefaultCurrency, true); vm.CurrencyData = _currencies.GetCurrencyData(vm.DefaultCurrency, true);
if (vm.InitialRendering) return View(vm); if (vm.InitialRendering)
return View(vm);
try try
{ {
@@ -61,12 +64,12 @@ public class StoreLightningBalance : ViewComponent
var balance = await lightningClient.GetBalance(); var balance = await lightningClient.GetBalance();
vm.Balance = balance; vm.Balance = balance;
vm.TotalOnchain = balance.OnchainBalance != null vm.TotalOnchain = balance.OnchainBalance != null
? (balance.OnchainBalance.Confirmed?? 0L) + (balance.OnchainBalance.Reserved ?? 0L) + ? (balance.OnchainBalance.Confirmed ?? 0L) + (balance.OnchainBalance.Reserved ?? 0L) +
(balance.OnchainBalance.Unconfirmed ?? 0L) (balance.OnchainBalance.Unconfirmed ?? 0L)
: null; : null;
vm.TotalOffchain = balance.OffchainBalance != null vm.TotalOffchain = balance.OffchainBalance != null
? (balance.OffchainBalance.Opening?? 0) + (balance.OffchainBalance.Local?? 0) + ? (balance.OffchainBalance.Opening ?? 0) + (balance.OffchainBalance.Local ?? 0) +
(balance.OffchainBalance.Closing?? 0) (balance.OffchainBalance.Closing ?? 0)
: null; : null;
} }
catch (NotSupportedException) catch (NotSupportedException)
@@ -89,9 +92,10 @@ public class StoreLightningBalance : ViewComponent
var existing = store.GetSupportedPaymentMethods(_networkProvider) var existing = store.GetSupportedPaymentMethods(_networkProvider)
.OfType<LightningSupportedPaymentMethod>() .OfType<LightningSupportedPaymentMethod>()
.FirstOrDefault(d => d.PaymentId == id); .FirstOrDefault(d => d.PaymentId == id);
if (existing == null) return null; if (existing == null)
return null;
if (existing.GetExternalLightningUrl() is {} connectionString) if (existing.GetExternalLightningUrl() is { } connectionString)
{ {
return _lightningClientFactory.Create(connectionString, network); return _lightningClientFactory.Create(connectionString, network);
} }

View File

@@ -34,10 +34,14 @@ public class StoreLightningServices : ViewComponent
public IViewComponentResult Invoke(StoreLightningServicesViewModel vm) public IViewComponentResult Invoke(StoreLightningServicesViewModel vm)
{ {
if (vm.Store == null) throw new ArgumentNullException(nameof(vm.Store)); if (vm.Store == null)
if (vm.CryptoCode == null) throw new ArgumentNullException(nameof(vm.CryptoCode)); throw new ArgumentNullException(nameof(vm.Store));
if (vm.LightningNodeType != LightningNodeType.Internal) return View(vm); if (vm.CryptoCode == null)
if (!User.IsInRole(Roles.ServerAdmin)) return View(vm); throw new ArgumentNullException(nameof(vm.CryptoCode));
if (vm.LightningNodeType != LightningNodeType.Internal)
return View(vm);
if (!User.IsInRole(Roles.ServerAdmin))
return View(vm);
var services = _externalServiceOptions.Value.ExternalServices.ToList() var services = _externalServiceOptions.Value.ExternalServices.ToList()
.Where(service => ExternalServices.LightningServiceTypes.Contains(service.Type)) .Where(service => ExternalServices.LightningServiceTypes.Contains(service.Type))

View File

@@ -1,5 +1,4 @@
using System; using System;
using Dapper;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -9,6 +8,7 @@ using BTCPayServer.Data;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using BTCPayServer.Services.Wallets; using BTCPayServer.Services.Wallets;
using Dapper;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -41,12 +41,15 @@ public class StoreNumbers : ViewComponent
public async Task<IViewComponentResult> InvokeAsync(StoreNumbersViewModel vm) public async Task<IViewComponentResult> InvokeAsync(StoreNumbersViewModel vm)
{ {
if (vm.Store == null) throw new ArgumentNullException(nameof(vm.Store)); if (vm.Store == null)
if (vm.CryptoCode == null) throw new ArgumentNullException(nameof(vm.CryptoCode)); throw new ArgumentNullException(nameof(vm.Store));
if (vm.CryptoCode == null)
throw new ArgumentNullException(nameof(vm.CryptoCode));
vm.WalletId = new WalletId(vm.Store.Id, vm.CryptoCode); vm.WalletId = new WalletId(vm.Store.Id, vm.CryptoCode);
if (vm.InitialRendering) return View(vm); if (vm.InitialRendering)
return View(vm);
await using var ctx = _dbContextFactory.CreateContext(); await using var ctx = _dbContextFactory.CreateContext();
var payoutsCount = await ctx.Payouts var payoutsCount = await ctx.Payouts

View File

@@ -35,15 +35,18 @@ public class StoreRecentInvoices : ViewComponent
public async Task<IViewComponentResult> InvokeAsync(StoreRecentInvoicesViewModel vm) public async Task<IViewComponentResult> InvokeAsync(StoreRecentInvoicesViewModel vm)
{ {
if (vm.Store == null) throw new ArgumentNullException(nameof(vm.Store)); if (vm.Store == null)
if (vm.CryptoCode == null) throw new ArgumentNullException(nameof(vm.CryptoCode)); throw new ArgumentNullException(nameof(vm.Store));
if (vm.InitialRendering) return View(vm); if (vm.CryptoCode == null)
throw new ArgumentNullException(nameof(vm.CryptoCode));
if (vm.InitialRendering)
return View(vm);
var userId = _userManager.GetUserId(UserClaimsPrincipal); var userId = _userManager.GetUserId(UserClaimsPrincipal);
var invoiceEntities = await _invoiceRepo.GetInvoices(new InvoiceQuery var invoiceEntities = await _invoiceRepo.GetInvoices(new InvoiceQuery
{ {
UserId = userId, UserId = userId,
StoreId = new [] { vm.Store.Id }, StoreId = new[] { vm.Store.Id },
IncludeArchived = false, IncludeArchived = false,
IncludeRefunds = true, IncludeRefunds = true,
Take = 5 Take = 5

View File

@@ -1,22 +1,22 @@
#nullable enable #nullable enable
using System; using System;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Services;
using BTCPayServer.Models.StoreViewModels; using BTCPayServer.Models.StoreViewModels;
using BTCPayServer.Services;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using Dapper;
using BTCPayServer.Services.Wallets; using BTCPayServer.Services.Wallets;
using Dapper;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using NBXplorer.Client;
using static BTCPayServer.Components.StoreRecentTransactions.StoreRecentTransactionsViewModel;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NBitcoin; using NBitcoin;
using NBXplorer.Client;
using static BTCPayServer.Components.StoreRecentTransactions.StoreRecentTransactionsViewModel;
namespace BTCPayServer.Components.StoreRecentTransactions; namespace BTCPayServer.Components.StoreRecentTransactions;
@@ -35,12 +35,15 @@ public class StoreRecentTransactions : ViewComponent
public async Task<IViewComponentResult> InvokeAsync(StoreRecentTransactionsViewModel vm) public async Task<IViewComponentResult> InvokeAsync(StoreRecentTransactionsViewModel vm)
{ {
if (vm.Store == null) throw new ArgumentNullException(nameof(vm.Store)); if (vm.Store == null)
if (vm.CryptoCode == null) throw new ArgumentNullException(nameof(vm.CryptoCode)); throw new ArgumentNullException(nameof(vm.Store));
if (vm.CryptoCode == null)
throw new ArgumentNullException(nameof(vm.CryptoCode));
vm.WalletId = new WalletId(vm.Store.Id, vm.CryptoCode); vm.WalletId = new WalletId(vm.Store.Id, vm.CryptoCode);
if (vm.InitialRendering) return View(vm); if (vm.InitialRendering)
return View(vm);
var derivationSettings = vm.Store.GetDerivationSchemeSettings(NetworkProvider, vm.CryptoCode); var derivationSettings = vm.Store.GetDerivationSchemeSettings(NetworkProvider, vm.CryptoCode);
var transactions = new List<StoreRecentTransactionViewModel>(); var transactions = new List<StoreRecentTransactionViewModel>();

View File

@@ -69,7 +69,7 @@ public class StoreWalletBalance : ViewComponent
} }
else else
{ {
using CancellationTokenSource cts = new (TimeSpan.FromSeconds(3)); using CancellationTokenSource cts = new(TimeSpan.FromSeconds(3));
var wallet = _walletProvider.GetWallet(_networkProvider.DefaultNetwork); var wallet = _walletProvider.GetWallet(_networkProvider.DefaultNetwork);
var derivation = store.GetDerivationSchemeSettings(_networkProvider, walletId.CryptoCode); var derivation = store.GetDerivationSchemeSettings(_networkProvider, walletId.CryptoCode);
if (derivation is not null) if (derivation is not null)

View File

@@ -3,13 +3,13 @@ using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Client; using BTCPayServer.Client;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Services.Apps; using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Rates; using BTCPayServer.Services.Rates;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using BTCPayServer.Abstractions.Extensions;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;

View File

@@ -11,10 +11,10 @@ using BTCPayServer.Client.Models;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.Rating;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Rates; using BTCPayServer.Services.Rates;
using BTCPayServer.Rating;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@@ -439,7 +439,8 @@ namespace BTCPayServer.Controllers.Greenfield
break; break;
case RefundVariant.Custom: case RefundVariant.Custom:
if (request.CustomAmount is null || (request.CustomAmount is decimal v && v <= 0)) { if (request.CustomAmount is null || (request.CustomAmount is decimal v && v <= 0))
{
this.ModelState.AddModelError(nameof(request.CustomAmount), "Amount must be greater than 0"); this.ModelState.AddModelError(nameof(request.CustomAmount), "Amount must be greater than 0");
} }
@@ -599,7 +600,7 @@ namespace BTCPayServer.Controllers.Greenfield
Amount = entity.Price, Amount = entity.Price,
Type = entity.Type, Type = entity.Type,
Id = entity.Id, Id = entity.Id,
CheckoutLink = request is null? null: linkGenerator.CheckoutLink(entity.Id, request.Scheme, request.Host, request.PathBase), CheckoutLink = request is null ? null : linkGenerator.CheckoutLink(entity.Id, request.Scheme, request.Host, request.PathBase),
Status = entity.Status.ToModernStatus(), Status = entity.Status.ToModernStatus(),
AdditionalStatus = entity.ExceptionStatus, AdditionalStatus = entity.ExceptionStatus,
Currency = entity.Currency, Currency = entity.Currency,

View File

@@ -20,7 +20,7 @@ namespace BTCPayServer.Controllers.Greenfield
{ {
private readonly IEnumerable<IPayoutProcessorFactory> _factories; private readonly IEnumerable<IPayoutProcessorFactory> _factories;
public GreenfieldPayoutProcessorsController(IEnumerable<IPayoutProcessorFactory>factories) public GreenfieldPayoutProcessorsController(IEnumerable<IPayoutProcessorFactory> factories)
{ {
_factories = factories; _factories = factories;
} }

View File

@@ -200,9 +200,9 @@ namespace BTCPayServer.Controllers.Greenfield
if (pp is null) if (pp is null)
return PullPaymentNotFound(); return PullPaymentNotFound();
var payouts =await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery() var payouts = await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
{ {
PullPayments = new[] {pullPaymentId}, PullPayments = new[] { pullPaymentId },
States = GetStateFilter(includeCancelled) States = GetStateFilter(includeCancelled)
}); });
return base.Ok(payouts return base.Ok(payouts
@@ -219,7 +219,8 @@ namespace BTCPayServer.Controllers.Greenfield
var payout = (await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery() var payout = (await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
{ {
PullPayments = new[] {pullPaymentId}, PayoutIds = new[] {payoutId} PullPayments = new[] { pullPaymentId },
PayoutIds = new[] { payoutId }
})).FirstOrDefault(); })).FirstOrDefault();
@@ -413,7 +414,7 @@ namespace BTCPayServer.Controllers.Greenfield
{ {
var payouts = await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery() var payouts = await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
{ {
Stores = new[] {storeId}, Stores = new[] { storeId },
States = GetStateFilter(includeCancelled) States = GetStateFilter(includeCancelled)
}); });
@@ -426,7 +427,7 @@ namespace BTCPayServer.Controllers.Greenfield
[Authorize(Policy = Policies.CanManagePullPayments, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] [Authorize(Policy = Policies.CanManagePullPayments, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
public async Task<IActionResult> CancelPayout(string storeId, string payoutId) public async Task<IActionResult> CancelPayout(string storeId, string payoutId)
{ {
var res= await _pullPaymentService.Cancel(new PullPaymentHostedService.CancelRequest(new[] { payoutId }, new []{storeId})); var res = await _pullPaymentService.Cancel(new PullPaymentHostedService.CancelRequest(new[] { payoutId }, new[] { storeId }));
return MapResult(res.First().Value); return MapResult(res.First().Value);
} }
@@ -530,7 +531,8 @@ namespace BTCPayServer.Controllers.Greenfield
var payout = (await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery() var payout = (await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
{ {
Stores = new[] {storeId}, PayoutIds = new[] {payoutId} Stores = new[] { storeId },
PayoutIds = new[] { payoutId }
})).FirstOrDefault(); })).FirstOrDefault();
if (payout is null) if (payout is null)

View File

@@ -42,9 +42,9 @@ namespace BTCPayServer.Controllers.Greenfield
await _payoutProcessorService.GetProcessors( await _payoutProcessorService.GetProcessors(
new PayoutProcessorService.PayoutProcessorQuery() new PayoutProcessorService.PayoutProcessorQuery()
{ {
Stores = new[] {storeId}, Stores = new[] { storeId },
Processors = new[] {LightningAutomatedPayoutSenderFactory.ProcessorName}, Processors = new[] { LightningAutomatedPayoutSenderFactory.ProcessorName },
PaymentMethods = paymentMethod is null ? null : new[] {paymentMethod} PaymentMethods = paymentMethod is null ? null : new[] { paymentMethod }
}); });
return Ok(configured.Select(ToModel).ToArray()); return Ok(configured.Select(ToModel).ToArray());
@@ -61,7 +61,7 @@ namespace BTCPayServer.Controllers.Greenfield
private static AutomatedPayoutBlob FromModel(LightningAutomatedPayoutSettings data) private static AutomatedPayoutBlob FromModel(LightningAutomatedPayoutSettings data)
{ {
return new AutomatedPayoutBlob() {Interval = data.IntervalSeconds}; return new AutomatedPayoutBlob() { Interval = data.IntervalSeconds };
} }
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
@@ -75,9 +75,9 @@ namespace BTCPayServer.Controllers.Greenfield
(await _payoutProcessorService.GetProcessors( (await _payoutProcessorService.GetProcessors(
new PayoutProcessorService.PayoutProcessorQuery() new PayoutProcessorService.PayoutProcessorQuery()
{ {
Stores = new[] {storeId}, Stores = new[] { storeId },
Processors = new[] {LightningAutomatedPayoutSenderFactory.ProcessorName}, Processors = new[] { LightningAutomatedPayoutSenderFactory.ProcessorName },
PaymentMethods = new[] {paymentMethod} PaymentMethods = new[] { paymentMethod }
})) }))
.FirstOrDefault(); .FirstOrDefault();
activeProcessor ??= new PayoutProcessorData(); activeProcessor ??= new PayoutProcessorData();
@@ -88,7 +88,9 @@ namespace BTCPayServer.Controllers.Greenfield
var tcs = new TaskCompletionSource(); var tcs = new TaskCompletionSource();
_eventAggregator.Publish(new PayoutProcessorUpdated() _eventAggregator.Publish(new PayoutProcessorUpdated()
{ {
Data = activeProcessor, Id = activeProcessor.Id, Processed = tcs Data = activeProcessor,
Id = activeProcessor.Id,
Processed = tcs
}); });
await tcs.Task; await tcs.Task;
return Ok(ToModel(activeProcessor)); return Ok(ToModel(activeProcessor));

View File

@@ -42,9 +42,9 @@ namespace BTCPayServer.Controllers.Greenfield
await _payoutProcessorService.GetProcessors( await _payoutProcessorService.GetProcessors(
new PayoutProcessorService.PayoutProcessorQuery() new PayoutProcessorService.PayoutProcessorQuery()
{ {
Stores = new[] {storeId}, Stores = new[] { storeId },
Processors = new[] {OnChainAutomatedPayoutSenderFactory.ProcessorName}, Processors = new[] { OnChainAutomatedPayoutSenderFactory.ProcessorName },
PaymentMethods = paymentMethod is null ? null : new[] {paymentMethod} PaymentMethods = paymentMethod is null ? null : new[] { paymentMethod }
}); });
return Ok(configured.Select(ToModel).ToArray()); return Ok(configured.Select(ToModel).ToArray());
@@ -81,9 +81,9 @@ namespace BTCPayServer.Controllers.Greenfield
(await _payoutProcessorService.GetProcessors( (await _payoutProcessorService.GetProcessors(
new PayoutProcessorService.PayoutProcessorQuery() new PayoutProcessorService.PayoutProcessorQuery()
{ {
Stores = new[] {storeId}, Stores = new[] { storeId },
Processors = new[] {OnChainAutomatedPayoutSenderFactory.ProcessorName}, Processors = new[] { OnChainAutomatedPayoutSenderFactory.ProcessorName },
PaymentMethods = new[] {paymentMethod} PaymentMethods = new[] { paymentMethod }
})) }))
.FirstOrDefault(); .FirstOrDefault();
activeProcessor ??= new PayoutProcessorData(); activeProcessor ??= new PayoutProcessorData();
@@ -94,7 +94,9 @@ namespace BTCPayServer.Controllers.Greenfield
var tcs = new TaskCompletionSource(); var tcs = new TaskCompletionSource();
_eventAggregator.Publish(new PayoutProcessorUpdated() _eventAggregator.Publish(new PayoutProcessorUpdated()
{ {
Data = activeProcessor, Id = activeProcessor.Id, Processed = tcs Data = activeProcessor,
Id = activeProcessor.Id,
Processed = tcs
}); });
await tcs.Task; await tcs.Task;
return Ok(ToModel(activeProcessor)); return Ok(ToModel(activeProcessor));

View File

@@ -47,7 +47,7 @@ namespace BTCPayServer.Controllers.GreenField
var emailSender = await _emailSenderFactory.GetEmailSender(storeId); var emailSender = await _emailSenderFactory.GetEmailSender(storeId);
if (emailSender is null) if (emailSender is null)
{ {
return this.CreateAPIError(404,"smtp-not-configured", "Store does not have an SMTP server configured."); return this.CreateAPIError(404, "smtp-not-configured", "Store does not have an SMTP server configured.");
} }
emailSender.SendEmail(to, request.Subject, request.Body); emailSender.SendEmail(to, request.Subject, request.Body);
return Ok(); return Ok();
@@ -89,7 +89,7 @@ namespace BTCPayServer.Controllers.GreenField
} }
private EmailSettings FromModel(Data.StoreData data) private EmailSettings FromModel(Data.StoreData data)
{ {
return data.GetStoreBlob().EmailSettings??new(); return data.GetStoreBlob().EmailSettings ?? new();
} }
private IActionResult StoreNotFound() private IActionResult StoreNotFound()
{ {

View File

@@ -17,18 +17,18 @@ using BTCPayServer.Models.WalletViewModels;
using BTCPayServer.Payments.PayJoin; using BTCPayServer.Payments.PayJoin;
using BTCPayServer.Payments.PayJoin.Sender; using BTCPayServer.Payments.PayJoin.Sender;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Wallets;
using BTCPayServer.Services.Labels; using BTCPayServer.Services.Labels;
using BTCPayServer.Services.Wallets;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NBitcoin; using NBitcoin;
using NBitcoin.Payment; using NBitcoin.Payment;
using NBXplorer; using NBXplorer;
using NBXplorer.Models; using NBXplorer.Models;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using StoreData = BTCPayServer.Data.StoreData; using StoreData = BTCPayServer.Data.StoreData;
using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Controllers.Greenfield namespace BTCPayServer.Controllers.Greenfield
{ {
@@ -145,12 +145,14 @@ namespace BTCPayServer.Controllers.Greenfield
{ {
bip21.QueryParams.Add(PayjoinClient.BIP21EndpointKey, bip21.QueryParams.Add(PayjoinClient.BIP21EndpointKey,
Request.GetAbsoluteUri(Url.Action(nameof(PayJoinEndpointController.Submit), "PayJoinEndpoint", Request.GetAbsoluteUri(Url.Action(nameof(PayJoinEndpointController.Submit), "PayJoinEndpoint",
new {cryptoCode}))); new { cryptoCode })));
} }
return Ok(new OnChainWalletAddressData() return Ok(new OnChainWalletAddressData()
{ {
Address = kpi.Address?.ToString(), PaymentLink = bip21.ToString(), KeyPath = kpi.KeyPath Address = kpi.Address?.ToString(),
PaymentLink = bip21.ToString(),
KeyPath = kpi.KeyPath
}); });
} }
@@ -189,7 +191,7 @@ namespace BTCPayServer.Controllers.Greenfield
var wallet = _btcPayWalletProvider.GetWallet(network); var wallet = _btcPayWalletProvider.GetWallet(network);
var walletId = new WalletId(storeId, cryptoCode); var walletId = new WalletId(storeId, cryptoCode);
var walletTransactionsInfoAsync = await _walletRepository.GetWalletTransactionsInfo(walletId, (string[] ) null); var walletTransactionsInfoAsync = await _walletRepository.GetWalletTransactionsInfo(walletId, (string[])null);
var preFiltering = true; var preFiltering = true;
if (statusFilter?.Any() is true || !string.IsNullOrWhiteSpace(labelFilter)) if (statusFilter?.Any() is true || !string.IsNullOrWhiteSpace(labelFilter))
@@ -246,7 +248,7 @@ namespace BTCPayServer.Controllers.Greenfield
var walletId = new WalletId(storeId, cryptoCode); var walletId = new WalletId(storeId, cryptoCode);
var walletTransactionsInfoAsync = var walletTransactionsInfoAsync =
(await _walletRepository.GetWalletTransactionsInfo(walletId, new[] {transactionId})).Values (await _walletRepository.GetWalletTransactionsInfo(walletId, new[] { transactionId })).Values
.FirstOrDefault(); .FirstOrDefault();
return Ok(ToModel(walletTransactionsInfoAsync, tx, wallet)); return Ok(ToModel(walletTransactionsInfoAsync, tx, wallet));
@@ -288,7 +290,7 @@ namespace BTCPayServer.Controllers.Greenfield
} }
var walletTransactionsInfo = var walletTransactionsInfo =
(await _walletRepository.GetWalletTransactionsInfo(walletId, new[] {transactionId})) (await _walletRepository.GetWalletTransactionsInfo(walletId, new[] { transactionId }))
.Values .Values
.FirstOrDefault(); .FirstOrDefault();
@@ -588,7 +590,7 @@ namespace BTCPayServer.Controllers.Greenfield
new PayjoinWallet(derivationScheme), new PayjoinWallet(derivationScheme),
psbt.PSBT, CancellationToken.None); psbt.PSBT, CancellationToken.None);
psbt.PSBT.Settings.SigningOptions = psbt.PSBT.Settings.SigningOptions =
new SigningOptions() {EnforceLowR = !(signingContext?.EnforceLowR is false)}; new SigningOptions() { EnforceLowR = !(signingContext?.EnforceLowR is false) };
payjoinPSBT = psbt.PSBT.SignAll(derivationScheme.AccountDerivation, accountKey, rootedKeyPath); payjoinPSBT = psbt.PSBT.SignAll(derivationScheme.AccountDerivation, accountKey, rootedKeyPath);
payjoinPSBT.Finalize(); payjoinPSBT.Finalize();
var payjoinTransaction = payjoinPSBT.ExtractTransaction(); var payjoinTransaction = payjoinPSBT.ExtractTransaction();

View File

@@ -43,15 +43,15 @@ namespace BTCPayServer.Controllers.Greenfield
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
[HttpDelete("~/api/v1/stores/{storeId}/payout-processors/{processor}/{paymentMethod}")] [HttpDelete("~/api/v1/stores/{storeId}/payout-processors/{processor}/{paymentMethod}")]
public async Task<IActionResult> RemoveStorePayoutProcessor( public async Task<IActionResult> RemoveStorePayoutProcessor(
string storeId,string processor,string paymentMethod) string storeId, string processor, string paymentMethod)
{ {
var matched = var matched =
(await _payoutProcessorService.GetProcessors( (await _payoutProcessorService.GetProcessors(
new PayoutProcessorService.PayoutProcessorQuery() new PayoutProcessorService.PayoutProcessorQuery()
{ {
Stores = new[] { storeId }, Stores = new[] { storeId },
Processors = new []{ processor}, Processors = new[] { processor },
PaymentMethods = new []{paymentMethod} PaymentMethods = new[] { paymentMethod }
})).FirstOrDefault(); })).FirstOrDefault();
if (matched is null) if (matched is null)
{ {

View File

@@ -58,7 +58,7 @@ namespace BTCPayServer.Controllers.GreenField
public ActionResult<List<RateSource>> GetRateSources() public ActionResult<List<RateSource>> GetRateSources()
{ {
return Ok(_rateProviderFactory.RateProviderFactory.GetSupportedExchanges().Select(provider => return Ok(_rateProviderFactory.RateProviderFactory.GetSupportedExchanges().Select(provider =>
new RateSource() {Id = provider.Id, Name = provider.DisplayName})); new RateSource() { Id = provider.Id, Name = provider.DisplayName }));
} }
[HttpPut("")] [HttpPut("")]

View File

@@ -72,7 +72,7 @@ namespace BTCPayServer.Controllers.Greenfield
private IEnumerable<StoreUserData> FromModel(Data.StoreData data) private IEnumerable<StoreUserData> FromModel(Data.StoreData data)
{ {
return data.UserStores.Select(store => new StoreUserData() { UserId = store.ApplicationUserId, Role = store.Role}); return data.UserStores.Select(store => new StoreUserData() { UserId = store.ApplicationUserId, Role = store.Role });
} }
private IActionResult StoreNotFound() private IActionResult StoreNotFound()
{ {

View File

@@ -69,7 +69,7 @@ namespace BTCPayServer.Controllers.Greenfield
[HttpGet("~/api/v1/users/{idOrEmail}")] [HttpGet("~/api/v1/users/{idOrEmail}")]
public async Task<IActionResult> GetUser(string idOrEmail) public async Task<IActionResult> GetUser(string idOrEmail)
{ {
var user = (await _userManager.FindByIdAsync(idOrEmail) ) ?? await _userManager.FindByEmailAsync(idOrEmail); var user = (await _userManager.FindByIdAsync(idOrEmail)) ?? await _userManager.FindByEmailAsync(idOrEmail);
if (user != null) if (user != null)
{ {
return Ok(await FromModel(user)); return Ok(await FromModel(user));

View File

@@ -109,7 +109,7 @@ namespace BTCPayServer.Controllers.Greenfield
} }
return ActivatorUtilities.CreateInstance<LocalBTCPayServerClient>(_serviceProvider, return ActivatorUtilities.CreateInstance<LocalBTCPayServerClient>(_serviceProvider,
new LocalHttpContextAccessor() {HttpContext = context}); new LocalHttpContextAccessor() { HttpContext = context });
} }
} }
@@ -686,7 +686,7 @@ namespace BTCPayServer.Controllers.Greenfield
{ {
return GetFromActionResult<NotificationData>( return GetFromActionResult<NotificationData>(
await GetController<GreenfieldNotificationsController>().UpdateNotification(notificationId, await GetController<GreenfieldNotificationsController>().UpdateNotification(notificationId,
new UpdateNotification() {Seen = seen})); new UpdateNotification() { Seen = seen }));
} }
public override async Task RemoveNotification(string notificationId, CancellationToken token = default) public override async Task RemoveNotification(string notificationId, CancellationToken token = default)
@@ -1056,7 +1056,7 @@ namespace BTCPayServer.Controllers.Greenfield
public override async Task<OnChainWalletTransactionData> PatchOnChainWalletTransaction(string storeId, public override async Task<OnChainWalletTransactionData> PatchOnChainWalletTransaction(string storeId,
string cryptoCode, string transactionId, string cryptoCode, string transactionId,
PatchOnChainTransactionRequest request, bool force = false,CancellationToken token = default) PatchOnChainTransactionRequest request, bool force = false, CancellationToken token = default)
{ {
return GetFromActionResult<OnChainWalletTransactionData>( return GetFromActionResult<OnChainWalletTransactionData>(
await GetController<GreenfieldStoreOnChainWalletsController>().PatchOnChainWalletTransaction(storeId, cryptoCode, transactionId, await GetController<GreenfieldStoreOnChainWalletsController>().PatchOnChainWalletTransaction(storeId, cryptoCode, transactionId,

View File

@@ -48,7 +48,7 @@ public class LightningAddressService
{ {
return await _memoryCache.GetOrCreateAsync(GetKey(username), async entry => return await _memoryCache.GetOrCreateAsync(GetKey(username), async entry =>
{ {
var result = await Get(new LightningAddressQuery() {Usernames = new[] {username}}); var result = await Get(new LightningAddressQuery() { Usernames = new[] { username } });
return result.FirstOrDefault(); return result.FirstOrDefault();
}); });
} }
@@ -61,7 +61,7 @@ public class LightningAddressService
public async Task<bool> Set(LightningAddressData data) public async Task<bool> Set(LightningAddressData data)
{ {
await using var context = _applicationDbContextFactory.CreateContext(); await using var context = _applicationDbContextFactory.CreateContext();
var result = (await GetCore(context, new LightningAddressQuery() {Usernames = new[] {data.Username}})) var result = (await GetCore(context, new LightningAddressQuery() { Usernames = new[] { data.Username } }))
.FirstOrDefault(); .FirstOrDefault();
if (result is not null) if (result is not null)
{ {
@@ -83,8 +83,9 @@ public class LightningAddressService
public async Task<bool> Remove(string username, string? storeId = null) public async Task<bool> Remove(string username, string? storeId = null)
{ {
await using var context = _applicationDbContextFactory.CreateContext(); await using var context = _applicationDbContextFactory.CreateContext();
var x = (await GetCore(context, new LightningAddressQuery() {Usernames = new[] {username}})).FirstOrDefault(); var x = (await GetCore(context, new LightningAddressQuery() { Usernames = new[] { username } })).FirstOrDefault();
if (x is null) return true; if (x is null)
return true;
if (storeId is not null && x.StoreDataId != storeId) if (storeId is not null && x.StoreDataId != storeId)
{ {
return false; return false;
@@ -98,7 +99,7 @@ public class LightningAddressService
public async Task Set(LightningAddressData data, ApplicationDbContext context) public async Task Set(LightningAddressData data, ApplicationDbContext context)
{ {
var result = (await GetCore(context, new LightningAddressQuery() {Usernames = new[] {data.Username}})) var result = (await GetCore(context, new LightningAddressQuery() { Usernames = new[] { data.Username } }))
.FirstOrDefault(); .FirstOrDefault();
if (result is not null) if (result is not null)
{ {

View File

@@ -68,8 +68,7 @@ namespace BTCPayServer
return false; return false;
} }
var newCredential = new Fido2Credential {Name = name, ApplicationUserId = userId, Type = Fido2Credential.CredentialType.LNURLAuth, Blob = pubkeyBytes}; var newCredential = new Fido2Credential() { Name = name, ApplicationUserId = userId, Type = Fido2Credential.CredentialType.LNURLAuth, Blob = pubkeyBytes };
await dbContext.Fido2Credentials.AddAsync(newCredential); await dbContext.Fido2Credentials.AddAsync(newCredential);
await dbContext.SaveChangesAsync(); await dbContext.SaveChangesAsync();
CreationStore.Remove(userId, out _); CreationStore.Remove(userId, out _);
@@ -84,7 +83,7 @@ namespace BTCPayServer
public async Task Remove(string id, string userId) public async Task Remove(string id, string userId)
{ {
await using var context = _contextFactory.CreateContext(); await using var context = _contextFactory.CreateContext();
var device = await context.Fido2Credentials.FindAsync( id); var device = await context.Fido2Credentials.FindAsync(id);
if (device == null || !device.ApplicationUserId.Equals(userId, StringComparison.InvariantCulture)) if (device == null || !device.ApplicationUserId.Equals(userId, StringComparison.InvariantCulture))
{ {
return; return;
@@ -112,7 +111,8 @@ namespace BTCPayServer
return k1; return k1;
} }
public async Task<bool> CompleteLogin(string userId, ECDSASignature sig, PubKey pubKey){ public async Task<bool> CompleteLogin(string userId, ECDSASignature sig, PubKey pubKey)
{
await using var dbContext = _contextFactory.CreateContext(); await using var dbContext = _contextFactory.CreateContext();
userId = userId.ToLowerInvariant(); userId = userId.ToLowerInvariant();
var user = await dbContext.Users.Include(applicationUser => applicationUser.Fido2Credentials) var user = await dbContext.Users.Include(applicationUser => applicationUser.Fido2Credentials)

View File

@@ -1,8 +1,8 @@
using System; using System;
using System.Globalization; using System.Globalization;
using System.Security.Claims;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Extensions;
@@ -179,8 +179,8 @@ namespace BTCPayServer.Controllers
return View("SecondaryLogin", new SecondaryLoginViewModel() return View("SecondaryLogin", new SecondaryLoginViewModel()
{ {
LoginWith2FaViewModel = twoFModel, LoginWith2FaViewModel = twoFModel,
LoginWithFido2ViewModel = fido2Devices? await BuildFido2ViewModel(model.RememberMe, user): null, LoginWithFido2ViewModel = fido2Devices ? await BuildFido2ViewModel(model.RememberMe, user) : null,
LoginWithLNURLAuthViewModel = lnurlAuthCredentials? await BuildLNURLAuthViewModel(model.RememberMe, user): null, LoginWithLNURLAuthViewModel = lnurlAuthCredentials ? await BuildLNURLAuthViewModel(model.RememberMe, user) : null,
}); });
} }
else else
@@ -212,7 +212,7 @@ namespace BTCPayServer.Controllers
if (result.IsLockedOut) if (result.IsLockedOut)
{ {
_logger.LogWarning($"User '{user.Id}' account locked out."); _logger.LogWarning($"User '{user.Id}' account locked out.");
return RedirectToAction(nameof(Lockout), new { user.LockoutEnd}); return RedirectToAction(nameof(Lockout), new { user.LockoutEnd });
} }
else else
{ {
@@ -262,7 +262,7 @@ namespace BTCPayServer.Controllers
LNURLEndpoint = new Uri(_linkGenerator.GetUriByAction( LNURLEndpoint = new Uri(_linkGenerator.GetUriByAction(
action: nameof(UILNURLAuthController.LoginResponse), action: nameof(UILNURLAuthController.LoginResponse),
controller: "UILNURLAuth", controller: "UILNURLAuth",
values: new { userId = user.Id, action="login", tag="login", k1= Encoders.Hex.EncodeData(r) }, Request.Scheme, Request.Host, Request.PathBase)) values: new { userId = user.Id, action = "login", tag = "login", k1 = Encoders.Hex.EncodeData(r) }, Request.Scheme, Request.Host, Request.PathBase))
}; };
} }
return null; return null;
@@ -431,7 +431,7 @@ namespace BTCPayServer.Controllers
else if (result.IsLockedOut) else if (result.IsLockedOut)
{ {
_logger.LogWarning("User with ID {UserId} account locked out.", user.Id); _logger.LogWarning("User with ID {UserId} account locked out.", user.Id);
return RedirectToAction(nameof(Lockout), new { user.LockoutEnd}); return RedirectToAction(nameof(Lockout), new { user.LockoutEnd });
} }
else else
{ {
@@ -501,7 +501,7 @@ namespace BTCPayServer.Controllers
{ {
_logger.LogWarning("User with ID {UserId} account locked out.", user.Id); _logger.LogWarning("User with ID {UserId} account locked out.", user.Id);
return RedirectToAction(nameof(Lockout), new { user.LockoutEnd}); return RedirectToAction(nameof(Lockout), new { user.LockoutEnd });
} }
else else
{ {

View File

@@ -306,7 +306,9 @@ namespace BTCPayServer.Controllers
var custodianAccountData = new CustodianAccountData var custodianAccountData = new CustodianAccountData
{ {
CustodianCode = vm.SelectedCustodian, StoreId = vm.StoreId, Name = custodian.Name CustodianCode = vm.SelectedCustodian,
StoreId = vm.StoreId,
Name = custodian.Name
}; };

View File

@@ -37,7 +37,7 @@ namespace BTCPayServer.Controllers
var cryptoCode = isSats ? "BTC" : request.CryptoCode; var cryptoCode = isSats ? "BTC" : request.CryptoCode;
var amount = new Money(request.Amount, isSats ? MoneyUnit.Satoshi : MoneyUnit.BTC); var amount = new Money(request.Amount, isSats ? MoneyUnit.Satoshi : MoneyUnit.BTC);
var network = _NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode).NBitcoinNetwork; var network = _NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode).NBitcoinNetwork;
var paymentMethodId = new [] {store.GetDefaultPaymentId()} var paymentMethodId = new[] { store.GetDefaultPaymentId() }
.Concat(store.GetEnabledPaymentIds(_NetworkProvider)) .Concat(store.GetEnabledPaymentIds(_NetworkProvider))
.FirstOrDefault(p => p?.ToString() == request.PaymentMethodId); .FirstOrDefault(p => p?.ToString() == request.PaymentMethodId);

View File

@@ -164,7 +164,8 @@ namespace BTCPayServer.Controllers
var receipt = InvoiceDataBase.ReceiptOptions.Merge(store.GetStoreBlob().ReceiptOptions, i.ReceiptOptions); var receipt = InvoiceDataBase.ReceiptOptions.Merge(store.GetStoreBlob().ReceiptOptions, i.ReceiptOptions);
if (receipt.Enabled is not true) return NotFound(); if (receipt.Enabled is not true)
return NotFound();
if (i.Status.ToModernStatus() != InvoiceStatus.Settled) if (i.Status.ToModernStatus() != InvoiceStatus.Settled)
{ {
return View(new InvoiceReceiptViewModel return View(new InvoiceReceiptViewModel
@@ -738,10 +739,10 @@ namespace BTCPayServer.Controllers
lang ??= storeBlob.DefaultLang; lang ??= storeBlob.DefaultLang;
var receiptEnabled = InvoiceDataBase.ReceiptOptions.Merge(storeBlob.ReceiptOptions, invoice.ReceiptOptions).Enabled is true; var receiptEnabled = InvoiceDataBase.ReceiptOptions.Merge(storeBlob.ReceiptOptions, invoice.ReceiptOptions).Enabled is true;
var receiptUrl = receiptEnabled? _linkGenerator.GetUriByAction( var receiptUrl = receiptEnabled ? _linkGenerator.GetUriByAction(
nameof(InvoiceReceipt), nameof(InvoiceReceipt),
"UIInvoice", "UIInvoice",
new {invoiceId}, new { invoiceId },
Request.Scheme, Request.Scheme,
Request.Host, Request.Host,
Request.PathBase) : null; Request.PathBase) : null;

View File

@@ -49,7 +49,8 @@ namespace BTCPayServer
TempData.SetStatusMessageModel(new StatusMessageModel TempData.SetStatusMessageModel(new StatusMessageModel
{ {
Severity = StatusMessageModel.StatusSeverity.Success, Html = "LNURL Auth was removed successfully." Severity = StatusMessageModel.StatusSeverity.Success,
Html = "LNURL Auth was removed successfully."
}); });
return RedirectToList(); return RedirectToList();
@@ -108,7 +109,8 @@ namespace BTCPayServer
return BadRequest(new LNUrlStatusResponse return BadRequest(new LNUrlStatusResponse
{ {
Reason = "The challenge could not be verified", Status = "ERROR" Reason = "The challenge could not be verified",
Status = "ERROR"
}); });
} }
@@ -132,7 +134,8 @@ namespace BTCPayServer
return BadRequest(new LNUrlStatusResponse return BadRequest(new LNUrlStatusResponse
{ {
Reason = "The challenge could not be verified", Status = "ERROR" Reason = "The challenge could not be verified",
Status = "ERROR"
}); });
} }

View File

@@ -127,11 +127,11 @@ namespace BTCPayServer
if (!BOLT11PaymentRequest.TryParse(pr, out var result, network.NBitcoinNetwork) || result is null) if (!BOLT11PaymentRequest.TryParse(pr, out var result, network.NBitcoinNetwork) || result is null)
{ {
return BadRequest(new LNUrlStatusResponse {Status = "ERROR", Reason = "Pr was not a valid BOLT11"}); return BadRequest(new LNUrlStatusResponse { Status = "ERROR", Reason = "Pr was not a valid BOLT11" });
} }
if (result.MinimumAmount < request.MinWithdrawable || result.MinimumAmount > request.MaxWithdrawable) if (result.MinimumAmount < request.MinWithdrawable || result.MinimumAmount > request.MaxWithdrawable)
return BadRequest(new LNUrlStatusResponse {Status = "ERROR", Reason = "Pr was not within bounds"}); return BadRequest(new LNUrlStatusResponse { Status = "ERROR", Reason = "Pr was not within bounds" });
var store = await _storeRepository.FindStore(pp.StoreId); var store = await _storeRepository.FindStore(pp.StoreId);
var pm = store!.GetSupportedPaymentMethods(_btcPayNetworkProvider) var pm = store!.GetSupportedPaymentMethods(_btcPayNetworkProvider)
.OfType<LightningSupportedPaymentMethod>() .OfType<LightningSupportedPaymentMethod>()
@@ -151,7 +151,7 @@ namespace BTCPayServer
}); });
if (claimResponse.Result != ClaimRequest.ClaimResult.Ok) if (claimResponse.Result != ClaimRequest.ClaimResult.Ok)
return BadRequest(new LNUrlStatusResponse {Status = "ERROR", Reason = "Pr could not be paid"}); return BadRequest(new LNUrlStatusResponse { Status = "ERROR", Reason = "Pr could not be paid" });
switch (claimResponse.PayoutData.State) switch (claimResponse.PayoutData.State)
{ {
case PayoutState.AwaitingPayment: case PayoutState.AwaitingPayment:
@@ -203,9 +203,9 @@ namespace BTCPayServer
}); });
case PayoutState.InProgress: case PayoutState.InProgress:
case PayoutState.Completed: case PayoutState.Completed:
return Ok(new LNUrlStatusResponse {Status = "OK"}); return Ok(new LNUrlStatusResponse { Status = "OK" });
case PayoutState.Cancelled: case PayoutState.Cancelled:
return BadRequest(new LNUrlStatusResponse {Status = "ERROR", Reason = "Pr could not be paid"}); return BadRequest(new LNUrlStatusResponse { Status = "ERROR", Reason = "Pr could not be paid" });
} }
return Ok(request); return Ok(request);
@@ -274,7 +274,7 @@ namespace BTCPayServer
} }
return await GetLNURL(cryptoCode, app.StoreDataId, currencyCode, null, null, return await GetLNURL(cryptoCode, app.StoreDataId, currencyCode, null, null,
() => (null, app, item, new List<string> {AppService.GetAppInternalTag(appId)}, item.Price.Value, true)); () => (null, app, item, new List<string> { AppService.GetAppInternalTag(appId) }, item.Price.Value, true));
} }
public class EditLightningAddressVM public class EditLightningAddressVM
@@ -433,10 +433,10 @@ namespace BTCPayServer
.Replace("{ItemDescription}", i.Metadata.ItemDesc ?? "", StringComparison.OrdinalIgnoreCase) .Replace("{ItemDescription}", i.Metadata.ItemDesc ?? "", StringComparison.OrdinalIgnoreCase)
.Replace("{OrderId}", i.Metadata.OrderId ?? "", StringComparison.OrdinalIgnoreCase); .Replace("{OrderId}", i.Metadata.OrderId ?? "", StringComparison.OrdinalIgnoreCase);
lnurlMetadata.Add(new[] {"text/plain", description}); lnurlMetadata.Add(new[] { "text/plain", description });
if (!string.IsNullOrEmpty(username)) if (!string.IsNullOrEmpty(username))
{ {
lnurlMetadata.Add(new[] {"text/identifier", lnAddress}); lnurlMetadata.Add(new[] { "text/identifier", lnAddress });
} }
return Ok(new LNURLPayRequest return Ok(new LNURLPayRequest
{ {
@@ -451,7 +451,7 @@ namespace BTCPayServer
Callback = new Uri(_linkGenerator.GetUriByAction( Callback = new Uri(_linkGenerator.GetUriByAction(
action: nameof(GetLNURLForInvoice), action: nameof(GetLNURLForInvoice),
controller: "UILNURL", controller: "UILNURL",
values: new {cryptoCode, invoiceId = i.Id}, Request.Scheme, Request.Host, Request.PathBase)) values: new { cryptoCode, invoiceId = i.Id }, Request.Scheme, Request.Host, Request.PathBase))
}); });
} }
@@ -508,28 +508,28 @@ namespace BTCPayServer
.Replace("{ItemDescription}", i.Metadata.ItemDesc ?? "", StringComparison.OrdinalIgnoreCase) .Replace("{ItemDescription}", i.Metadata.ItemDesc ?? "", StringComparison.OrdinalIgnoreCase)
.Replace("{OrderId}", i.Metadata.OrderId ?? "", StringComparison.OrdinalIgnoreCase); .Replace("{OrderId}", i.Metadata.OrderId ?? "", StringComparison.OrdinalIgnoreCase);
lnurlMetadata.Add(new[] {"text/plain", description}); lnurlMetadata.Add(new[] { "text/plain", description });
if (!string.IsNullOrEmpty(paymentMethodDetails.ConsumedLightningAddress)) if (!string.IsNullOrEmpty(paymentMethodDetails.ConsumedLightningAddress))
{ {
lnurlMetadata.Add(new[] {"text/identifier", paymentMethodDetails.ConsumedLightningAddress}); lnurlMetadata.Add(new[] { "text/identifier", paymentMethodDetails.ConsumedLightningAddress });
} }
var metadata = JsonConvert.SerializeObject(lnurlMetadata); var metadata = JsonConvert.SerializeObject(lnurlMetadata);
if (amount.HasValue && (amount < min || amount > max)) if (amount.HasValue && (amount < min || amount > max))
{ {
return BadRequest(new LNUrlStatusResponse {Status = "ERROR", Reason = "Amount is out of bounds."}); return BadRequest(new LNUrlStatusResponse { Status = "ERROR", Reason = "Amount is out of bounds." });
} }
LNURLPayRequest.LNURLPayRequestCallbackResponse.ILNURLPayRequestSuccessAction successAction = null; LNURLPayRequest.LNURLPayRequestCallbackResponse.ILNURLPayRequestSuccessAction successAction = null;
if ((i.ReceiptOptions?.Enabled ??blob.ReceiptOptions.Enabled ) is true) if ((i.ReceiptOptions?.Enabled ?? blob.ReceiptOptions.Enabled) is true)
{ {
successAction = successAction =
new LNURLPayRequest.LNURLPayRequestCallbackResponse.LNURLPayRequestSuccessActionUrl new LNURLPayRequest.LNURLPayRequestCallbackResponse.LNURLPayRequestSuccessActionUrl
{ {
Tag = "url", Tag = "url",
Description = "Thank you for your purchase. Here is your receipt", Description = "Thank you for your purchase. Here is your receipt",
Url = _linkGenerator.GetUriByAction(HttpContext, "InvoiceReceipt", "UIInvoice", new { invoiceId}) Url = _linkGenerator.GetUriByAction(HttpContext, "InvoiceReceipt", "UIInvoice", new { invoiceId })
}; };
} }
@@ -609,7 +609,9 @@ namespace BTCPayServer
paymentMethodDetails, pmi)); paymentMethodDetails, pmi));
return Ok(new LNURLPayRequest.LNURLPayRequestCallbackResponse return Ok(new LNURLPayRequest.LNURLPayRequestCallbackResponse
{ {
Disposable = true, Routes = Array.Empty<string>(), Pr = paymentMethodDetails.BOLT11, Disposable = true,
Routes = Array.Empty<string>(),
Pr = paymentMethodDetails.BOLT11,
SuccessAction = successAction SuccessAction = successAction
}); });
} }
@@ -625,7 +627,9 @@ namespace BTCPayServer
return Ok(new LNURLPayRequest.LNURLPayRequestCallbackResponse return Ok(new LNURLPayRequest.LNURLPayRequestCallbackResponse
{ {
Disposable = true, Routes = Array.Empty<string>(), Pr = paymentMethodDetails.BOLT11, Disposable = true,
Routes = Array.Empty<string>(),
Pr = paymentMethodDetails.BOLT11,
SuccessAction = successAction SuccessAction = successAction
}); });
} }
@@ -633,7 +637,8 @@ namespace BTCPayServer
return BadRequest(new LNUrlStatusResponse return BadRequest(new LNUrlStatusResponse
{ {
Status = "ERROR", Reason = "Invoice not in a valid payable state" Status = "ERROR",
Reason = "Invoice not in a valid payable state"
}); });
} }
@@ -650,11 +655,11 @@ namespace BTCPayServer
Message = "LNURL is required for lightning addresses but has not yet been enabled.", Message = "LNURL is required for lightning addresses but has not yet been enabled.",
Severity = StatusMessageModel.StatusSeverity.Error Severity = StatusMessageModel.StatusSeverity.Error
}); });
return RedirectToAction(nameof(UIStoresController.GeneralSettings), "UIStores", new {storeId}); return RedirectToAction(nameof(UIStoresController.GeneralSettings), "UIStores", new { storeId });
} }
var addresses = var addresses =
await _lightningAddressService.Get(new LightningAddressQuery() {StoreIds = new[] {storeId}}); await _lightningAddressService.Get(new LightningAddressQuery() { StoreIds = new[] { storeId } });
return View(new EditLightningAddressVM return View(new EditLightningAddressVM
{ {
@@ -701,7 +706,9 @@ namespace BTCPayServer
Username = vm.Add.Username, Username = vm.Add.Username,
Blob = new LightningAddressDataBlob() Blob = new LightningAddressDataBlob()
{ {
Max = vm.Add.Max, Min = vm.Add.Min, CurrencyCode = vm.Add.CurrencyCode Max = vm.Add.Max,
Min = vm.Add.Min,
CurrencyCode = vm.Add.CurrencyCode
}.SerializeBlob() }.SerializeBlob()
})) }))
{ {

View File

@@ -281,7 +281,7 @@ namespace BTCPayServer.Controllers
if (Policies.IsStorePolicy(requested.Key)) if (Policies.IsStorePolicy(requested.Key))
{ {
if ((vm.SelectiveStores && !existing.Any(p => p.Scope == vm.StoreId)) || if ((vm.SelectiveStores && !existing.Any(p => p.Scope == vm.StoreId)) ||
(!vm.SelectiveStores && existing.Any(p => !string.IsNullOrEmpty(p.Scope))) ) (!vm.SelectiveStores && existing.Any(p => !string.IsNullOrEmpty(p.Scope))))
{ {
fail = true; fail = true;
break; break;
@@ -566,7 +566,7 @@ namespace BTCPayServer.Controllers
public bool Forbidden { get; set; } public bool Forbidden { get; set; }
public ApiKeyStoreMode StoreMode { get; set; } = ApiKeyStoreMode.AllStores; public ApiKeyStoreMode StoreMode { get; set; } = ApiKeyStoreMode.AllStores;
public List<string> SpecificStores { get; set; } = new (); public List<string> SpecificStores { get; set; } = new();
} }
} }

View File

@@ -66,7 +66,7 @@ namespace BTCPayServer.Controllers
var totalPaid = payouts.Where(p => p.Entity.State != PayoutState.Cancelled).Select(p => p.Blob.Amount).Sum(); var totalPaid = payouts.Where(p => p.Entity.State != PayoutState.Cancelled).Select(p => p.Blob.Amount).Sum();
var amountDue = blob.Limit - totalPaid; var amountDue = blob.Limit - totalPaid;
ViewPullPaymentModel vm = new (pp, DateTimeOffset.UtcNow) ViewPullPaymentModel vm = new(pp, DateTimeOffset.UtcNow)
{ {
AmountFormatted = _currencyNameTable.FormatCurrency(blob.Limit, blob.Currency), AmountFormatted = _currencyNameTable.FormatCurrency(blob.Limit, blob.Currency),
AmountCollected = totalPaid, AmountCollected = totalPaid,
@@ -224,7 +224,7 @@ namespace BTCPayServer.Controllers
TempData.SetStatusMessageModel(new StatusMessageModel TempData.SetStatusMessageModel(new StatusMessageModel
{ {
Message = $"Your claim request of {_currencyNameTable.DisplayFormatCurrency(vm.ClaimedAmount, ppBlob.Currency)} to {vm.Destination} has been submitted and is awaiting {(result.PayoutData.State == PayoutState.AwaitingApproval? "approval": "payment")}.", Message = $"Your claim request of {_currencyNameTable.DisplayFormatCurrency(vm.ClaimedAmount, ppBlob.Currency)} to {vm.Destination} has been submitted and is awaiting {(result.PayoutData.State == PayoutState.AwaitingApproval ? "approval" : "payment")}.",
Severity = StatusMessageModel.StatusSeverity.Success Severity = StatusMessageModel.StatusSeverity.Success
}); });

View File

@@ -132,7 +132,7 @@ namespace BTCPayServer.Controllers
TempData.SetStatusMessageModel(new StatusMessageModel() TempData.SetStatusMessageModel(new StatusMessageModel()
{ {
Message = "Files uploaded, restart server to load plugins" , Message = "Files uploaded, restart server to load plugins",
Severity = StatusMessageModel.StatusSeverity.Success Severity = StatusMessageModel.StatusSeverity.Success
}); });
return RedirectToAction("ListPlugins"); return RedirectToAction("ListPlugins");

View File

@@ -13,8 +13,8 @@ using BTCPayServer.Models.ServerViewModels;
using BTCPayServer.Services; using BTCPayServer.Services;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore;
using MimeKit; using MimeKit;
namespace BTCPayServer.Controllers namespace BTCPayServer.Controllers
@@ -261,7 +261,7 @@ namespace BTCPayServer.Controllers
return View("Confirm", new ConfirmModel("Disable admin", return View("Confirm", new ConfirmModel("Disable admin",
$"Unable to proceed: As the user <strong>{user.Email}</strong> is the last enabled admin, it cannot be disabled.")); $"Unable to proceed: As the user <strong>{user.Email}</strong> is the last enabled admin, it cannot be disabled."));
} }
return View("Confirm", new ConfirmModel($"{(enable? "Enable" : "Disable")} user", $"The user <strong>{user.Email}</strong> will be {(enable? "enabled" : "disabled")}. Are you sure?", (enable? "Enable" : "Disable"))); return View("Confirm", new ConfirmModel($"{(enable ? "Enable" : "Disable")} user", $"The user <strong>{user.Email}</strong> will be {(enable ? "enabled" : "disabled")}. Are you sure?", (enable ? "Enable" : "Disable")));
} }
[HttpPost("server/users/{userId}/toggle")] [HttpPost("server/users/{userId}/toggle")]
@@ -275,9 +275,9 @@ namespace BTCPayServer.Controllers
TempData[WellKnownTempData.SuccessMessage] = $"User was the last enabled admin and could not be disabled."; TempData[WellKnownTempData.SuccessMessage] = $"User was the last enabled admin and could not be disabled.";
return RedirectToAction(nameof(ListUsers)); return RedirectToAction(nameof(ListUsers));
} }
await _userService.ToggleUser(userId, enable? null: DateTimeOffset.MaxValue); await _userService.ToggleUser(userId, enable ? null : DateTimeOffset.MaxValue);
TempData[WellKnownTempData.SuccessMessage] = $"User {(enable? "enabled": "disabled")}"; TempData[WellKnownTempData.SuccessMessage] = $"User {(enable ? "enabled" : "disabled")}";
return RedirectToAction(nameof(ListUsers)); return RedirectToAction(nameof(ListUsers));
} }

View File

@@ -146,7 +146,8 @@ namespace BTCPayServer.Controllers
}); });
this.TempData.SetStatusMessageModel(new StatusMessageModel() this.TempData.SetStatusMessageModel(new StatusMessageModel()
{ {
Message = "Pull payment request created", Severity = StatusMessageModel.StatusSeverity.Success Message = "Pull payment request created",
Severity = StatusMessageModel.StatusSeverity.Success
}); });
return RedirectToAction(nameof(PullPayments), new { storeId = storeId }); return RedirectToAction(nameof(PullPayments), new { storeId = storeId });
} }
@@ -194,7 +195,9 @@ namespace BTCPayServer.Controllers
var vm = this.ParseListQuery(new PullPaymentsModel var vm = this.ParseListQuery(new PullPaymentsModel
{ {
Skip = skip, Count = count, ActiveState = pullPaymentState Skip = skip,
Count = count,
ActiveState = pullPaymentState
}); });
switch (pullPaymentState) switch (pullPaymentState)
@@ -257,7 +260,8 @@ namespace BTCPayServer.Controllers
await _pullPaymentService.Cancel(new HostedServices.PullPaymentHostedService.CancelRequest(pullPaymentId)); await _pullPaymentService.Cancel(new HostedServices.PullPaymentHostedService.CancelRequest(pullPaymentId));
TempData.SetStatusMessageModel(new StatusMessageModel() TempData.SetStatusMessageModel(new StatusMessageModel()
{ {
Message = "Pull payment archived", Severity = StatusMessageModel.StatusSeverity.Success Message = "Pull payment archived",
Severity = StatusMessageModel.StatusSeverity.Success
}); });
return RedirectToAction(nameof(PullPayments), new { storeId }); return RedirectToAction(nameof(PullPayments), new { storeId });
} }
@@ -282,7 +286,8 @@ namespace BTCPayServer.Controllers
{ {
TempData.SetStatusMessageModel(new StatusMessageModel() TempData.SetStatusMessageModel(new StatusMessageModel()
{ {
Message = "No payout selected", Severity = StatusMessageModel.StatusSeverity.Error Message = "No payout selected",
Severity = StatusMessageModel.StatusSeverity.Error
}); });
return RedirectToAction(nameof(Payouts), return RedirectToAction(nameof(Payouts),
new new
@@ -362,7 +367,8 @@ namespace BTCPayServer.Controllers
TempData.SetStatusMessageModel(new StatusMessageModel() TempData.SetStatusMessageModel(new StatusMessageModel()
{ {
Message = "Payouts approved", Severity = StatusMessageModel.StatusSeverity.Success Message = "Payouts approved",
Severity = StatusMessageModel.StatusSeverity.Success
}); });
break; break;
} }
@@ -412,17 +418,19 @@ namespace BTCPayServer.Controllers
TempData.SetStatusMessageModel(new StatusMessageModel() TempData.SetStatusMessageModel(new StatusMessageModel()
{ {
Message = "Payouts marked as paid", Severity = StatusMessageModel.StatusSeverity.Success Message = "Payouts marked as paid",
Severity = StatusMessageModel.StatusSeverity.Success
}); });
break; break;
} }
case "cancel": case "cancel":
await _pullPaymentService.Cancel( await _pullPaymentService.Cancel(
new PullPaymentHostedService.CancelRequest(payoutIds, new[] {storeId})); new PullPaymentHostedService.CancelRequest(payoutIds, new[] { storeId }));
TempData.SetStatusMessageModel(new StatusMessageModel() TempData.SetStatusMessageModel(new StatusMessageModel()
{ {
Message = "Payouts archived", Severity = StatusMessageModel.StatusSeverity.Success Message = "Payouts archived",
Severity = StatusMessageModel.StatusSeverity.Success
}); });
break; break;
} }
@@ -494,7 +502,7 @@ namespace BTCPayServer.Controllers
} }
vm.PaymentMethodCount = (await payoutRequest.GroupBy(data => data.PaymentMethodId) vm.PaymentMethodCount = (await payoutRequest.GroupBy(data => data.PaymentMethodId)
.Select(datas => new {datas.Key, Count = datas.Count()}).ToListAsync()) .Select(datas => new { datas.Key, Count = datas.Count() }).ToListAsync())
.ToDictionary(datas => datas.Key, arg => arg.Count); .ToDictionary(datas => datas.Key, arg => arg.Count);
vm.PayoutStateCount = payoutRequest.GroupBy(data => data.State) vm.PayoutStateCount = payoutRequest.GroupBy(data => data.State)
.Select(e => new { e.Key, Count = e.Count() }) .Select(e => new { e.Key, Count = e.Count() })

View File

@@ -38,7 +38,8 @@ namespace BTCPayServer.Controllers
}; };
// Widget data // Widget data
if (!vm.WalletEnabled && !vm.LightningEnabled) return View(vm); if (!vm.WalletEnabled && !vm.LightningEnabled)
return View(vm);
var userId = GetUserId(); var userId = GetUserId();
var apps = await _appService.GetAllApps(userId, false, store.Id); var apps = await _appService.GetAllApps(userId, false, store.Id);

View File

@@ -31,7 +31,7 @@ namespace BTCPayServer.Controllers
TempData.SetStatusMessageModel(new StatusMessageModel TempData.SetStatusMessageModel(new StatusMessageModel
{ {
Severity = StatusMessageModel.StatusSeverity.Warning, Severity = StatusMessageModel.StatusSeverity.Warning,
Html = $"You need to configure email settings before this feature works. <a class='alert-link' href='{Url.Action("StoreEmailSettings", new {storeId})}'>Configure now</a>." Html = $"You need to configure email settings before this feature works. <a class='alert-link' href='{Url.Action("StoreEmailSettings", new { storeId })}'>Configure now</a>."
}); });
} }
@@ -48,7 +48,8 @@ namespace BTCPayServer.Controllers
var item = command[(command.IndexOf(":", StringComparison.InvariantCultureIgnoreCase) + 1)..]; var item = command[(command.IndexOf(":", StringComparison.InvariantCultureIgnoreCase) + 1)..];
var index = int.Parse(item, CultureInfo.InvariantCulture); var index = int.Parse(item, CultureInfo.InvariantCulture);
vm.Rules.RemoveAt(index); vm.Rules.RemoveAt(index);
} else if (command == "add") }
else if (command == "add")
{ {
vm.Rules.Add(new StoreEmailRule()); vm.Rules.Add(new StoreEmailRule());
@@ -71,7 +72,7 @@ namespace BTCPayServer.Controllers
Severity = StatusMessageModel.StatusSeverity.Success, Severity = StatusMessageModel.StatusSeverity.Success,
Message = "Store email rules saved" Message = "Store email rules saved"
}); });
return RedirectToAction("StoreEmails", new {storeId}); return RedirectToAction("StoreEmails", new { storeId });
} }
public class StoreEmailRuleViewModel public class StoreEmailRuleViewModel

View File

@@ -186,7 +186,7 @@ namespace BTCPayServer.Controllers
[HttpPost("{storeId}/users/{userId}/delete")] [HttpPost("{storeId}/users/{userId}/delete")]
public async Task<IActionResult> DeleteStoreUserPost(string storeId, string userId) public async Task<IActionResult> DeleteStoreUserPost(string storeId, string userId)
{ {
if(await _Repo.RemoveStoreUser(storeId, userId)) if (await _Repo.RemoveStoreUser(storeId, userId))
TempData[WellKnownTempData.SuccessMessage] = "User removed successfully."; TempData[WellKnownTempData.SuccessMessage] = "User removed successfully.";
else else
{ {

View File

@@ -95,7 +95,8 @@ namespace BTCPayServer.Controllers
private string GetUserId() => _userManager.GetUserId(User); private string GetUserId() => _userManager.GetUserId(User);
private SelectList GetExchangesSelectList(string selected) { private SelectList GetExchangesSelectList(string selected)
{
var exchanges = _rateFactory.RateProviderFactory var exchanges = _rateFactory.RateProviderFactory
.GetSupportedExchanges() .GetSupportedExchanges()
.Where(r => !string.IsNullOrWhiteSpace(r.Name)) .Where(r => !string.IsNullOrWhiteSpace(r.Name))

View File

@@ -120,7 +120,8 @@ namespace BTCPayServer.Controllers
builder.SendFees(bumpFee); builder.SendFees(bumpFee);
builder.SendAll(returnAddress); builder.SendAll(returnAddress);
try { try
{
var psbt = builder.BuildPSBT(false); var psbt = builder.BuildPSBT(false);
psbt = (await explorer.UpdatePSBTAsync(new UpdatePSBTRequest() psbt = (await explorer.UpdatePSBTAsync(new UpdatePSBTRequest()
{ {
@@ -143,7 +144,9 @@ namespace BTCPayServer.Controllers
{ "returnUrl", returnUrl } { "returnUrl", returnUrl }
} }
}); });
} catch (Exception ex) { }
catch (Exception ex)
{
TempData[WellKnownTempData.ErrorMessage] = ex.Message; TempData[WellKnownTempData.ErrorMessage] = ex.Message;
return LocalRedirect(returnUrl); return LocalRedirect(returnUrl);

View File

@@ -11,8 +11,10 @@ using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models; using BTCPayServer.Abstractions.Models;
using BTCPayServer.BIP78.Sender; using BTCPayServer.BIP78.Sender;
using BTCPayServer.Client; using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Logging;
using BTCPayServer.ModelBinders; using BTCPayServer.ModelBinders;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Models.WalletViewModels; using BTCPayServer.Models.WalletViewModels;
@@ -23,24 +25,22 @@ using BTCPayServer.Services.Labels;
using BTCPayServer.Services.Rates; using BTCPayServer.Services.Rates;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using BTCPayServer.Services.Wallets; using BTCPayServer.Services.Wallets;
using BTCPayServer.Services.Wallets.Export;
using Dapper; using Dapper;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using NBitcoin; using NBitcoin;
using BTCPayServer.Client.Models;
using BTCPayServer.Logging;
using BTCPayServer.Services.Wallets.Export;
using Microsoft.AspNetCore.Http;
using NBXplorer; using NBXplorer;
using NBXplorer.Client; using NBXplorer.Client;
using NBXplorer.DerivationStrategy; using NBXplorer.DerivationStrategy;
using NBXplorer.Models; using NBXplorer.Models;
using Newtonsoft.Json; using Newtonsoft.Json;
using StoreData = BTCPayServer.Data.StoreData;
using Microsoft.AspNetCore.Routing;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using StoreData = BTCPayServer.Data.StoreData;
namespace BTCPayServer.Controllers namespace BTCPayServer.Controllers
{ {
@@ -476,7 +476,8 @@ namespace BTCPayServer.Controllers
(int)network.NBitcoinNetwork.Consensus.GetExpectedBlocksFor(time)); (int)network.NBitcoinNetwork.Consensus.GetExpectedBlocksFor(time));
return new WalletSendModel.FeeRateOption() return new WalletSendModel.FeeRateOption()
{ {
Target = time, FeeRate = result.SatoshiPerByte Target = time,
FeeRate = result.SatoshiPerByte
}; };
} }
catch (Exception) catch (Exception)
@@ -781,13 +782,13 @@ namespace BTCPayServer.Controllers
{ {
message += $"<br/><br/>{errorMessage}"; message += $"<br/><br/>{errorMessage}";
} }
else if(message is null && errorMessage is not null) else if (message is null && errorMessage is not null)
{ {
message = errorMessage; message = errorMessage;
} }
TempData.SetStatusMessageModel(new StatusMessageModel() TempData.SetStatusMessageModel(new StatusMessageModel()
{ {
Severity =someFailed? StatusMessageModel.StatusSeverity.Warning: Severity = someFailed ? StatusMessageModel.StatusSeverity.Warning :
StatusMessageModel.StatusSeverity.Success, StatusMessageModel.StatusSeverity.Success,
Html = message Html = message
}); });
@@ -846,7 +847,7 @@ namespace BTCPayServer.Controllers
private void LoadFromBIP21(WalletSendModel vm, string bip21, BTCPayNetwork network) private void LoadFromBIP21(WalletSendModel vm, string bip21, BTCPayNetwork network)
{ {
vm.Outputs ??= new (); vm.Outputs ??= new();
try try
{ {
var uriBuilder = new NBitcoin.Payment.BitcoinUrlBuilder(bip21, network.NBitcoinNetwork); var uriBuilder = new NBitcoin.Payment.BitcoinUrlBuilder(bip21, network.NBitcoinNetwork);
@@ -1294,7 +1295,7 @@ namespace BTCPayServer.Controllers
return NotFound(); return NotFound();
var wallet = _walletProvider.GetWallet(paymentMethod.Network); var wallet = _walletProvider.GetWallet(paymentMethod.Network);
var walletTransactionsInfoAsync = WalletRepository.GetWalletTransactionsInfo(walletId, (string[] ) null); var walletTransactionsInfoAsync = WalletRepository.GetWalletTransactionsInfo(walletId, (string[])null);
var input = await wallet.FetchTransactionHistory(paymentMethod.AccountDerivation, null, null); var input = await wallet.FetchTransactionHistory(paymentMethod.AccountDerivation, null, null);
var walletTransactionsInfo = await walletTransactionsInfoAsync; var walletTransactionsInfo = await walletTransactionsInfoAsync;
var export = new TransactionsExport(wallet, walletTransactionsInfo); var export = new TransactionsExport(wallet, walletTransactionsInfo);

View File

@@ -275,7 +275,7 @@ public class BitcoinLikePayoutHandler : IPayoutHandler
&& data.State == PayoutState.AwaitingPayment) && data.State == PayoutState.AwaitingPayment)
.ToListAsync(); .ToListAsync();
var pullPaymentIds = payouts.Select(data => data.PullPaymentDataId).Distinct().Where(s => s!= null).ToArray(); var pullPaymentIds = payouts.Select(data => data.PullPaymentDataId).Distinct().Where(s => s != null).ToArray();
var storeId = payouts.First().StoreDataId; var storeId = payouts.First().StoreDataId;
var network = _btcPayNetworkProvider.GetNetwork<BTCPayNetwork>(paymentMethodId.CryptoCode); var network = _btcPayNetworkProvider.GetNetwork<BTCPayNetwork>(paymentMethodId.CryptoCode);
List<string> bip21 = new List<string>(); List<string> bip21 = new List<string>();

View File

@@ -44,7 +44,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike
public bool CanHandle(PaymentMethodId paymentMethod) public bool CanHandle(PaymentMethodId paymentMethod)
{ {
return (paymentMethod.PaymentType == LightningPaymentType.Instance || paymentMethod.PaymentType == LNURLPayPaymentType.Instance ) && return (paymentMethod.PaymentType == LightningPaymentType.Instance || paymentMethod.PaymentType == LNURLPayPaymentType.Instance) &&
_btcPayNetworkProvider.GetNetwork<BTCPayNetwork>(paymentMethod.CryptoCode)?.SupportLightning is true; _btcPayNetworkProvider.GetNetwork<BTCPayNetwork>(paymentMethod.CryptoCode)?.SupportLightning is true;
} }

View File

@@ -303,7 +303,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike
// ignored // ignored
} }
} }
else if(result.Result == PayResult.Unknown) else if (result.Result == PayResult.Unknown)
{ {
payoutData.State = PayoutState.InProgress; payoutData.State = PayoutState.InProgress;
message = "The payment has been initiated but is still in-flight."; message = "The payment has been initiated but is still in-flight.";

View File

@@ -179,7 +179,7 @@ namespace BTCPayServer.Data
return rules; return rules;
} }
public static JObject RecommendedExchanges = new () public static JObject RecommendedExchanges = new()
{ {
{ "EUR", "kraken" }, { "EUR", "kraken" },
{ "USD", "kraken" }, { "USD", "kraken" },

View File

@@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Mvc
scheme, host, pathbase); scheme, host, pathbase);
} }
public static string PayoutLink(this LinkGenerator urlHelper, string walletIdOrStoreId, string pullPaymentId, PayoutState payoutState,string scheme, HostString host, string pathbase) public static string PayoutLink(this LinkGenerator urlHelper, string walletIdOrStoreId, string pullPaymentId, PayoutState payoutState, string scheme, HostString host, string pathbase)
{ {
WalletId.TryParse(walletIdOrStoreId, out var wallet); WalletId.TryParse(walletIdOrStoreId, out var wallet);
return urlHelper.GetUriByAction( return urlHelper.GetUriByAction(

View File

@@ -15,7 +15,7 @@ public class FormDataService
public static readonly Form StaticFormEmail = new() public static readonly Form StaticFormEmail = new()
{ {
Fields = new List<Field>() {Field.Create("Enter your email", "buyerEmail", null, true, null, "email")} Fields = new List<Field>() { Field.Create("Enter your email", "buyerEmail", null, true, null, "email") }
}; };
public static readonly Form StaticFormAddress = new() public static readonly Form StaticFormAddress = new()

View File

@@ -4,7 +4,7 @@ using BTCPayServer.Abstractions.Form;
namespace BTCPayServer.Forms; namespace BTCPayServer.Forms;
public class HtmlFieldsetFormProvider: IFormComponentProvider public class HtmlFieldsetFormProvider : IFormComponentProvider
{ {
public string View => "Forms/FieldSetElement"; public string View => "Forms/FieldSetElement";

View File

@@ -6,7 +6,7 @@ using BTCPayServer.Validation;
namespace BTCPayServer.Forms; namespace BTCPayServer.Forms;
public class HtmlInputFormProvider: FormComponentProviderBase public class HtmlInputFormProvider : FormComponentProviderBase
{ {
public override void Register(Dictionary<string, IFormComponentProvider> typeToComponentProvider) public override void Register(Dictionary<string, IFormComponentProvider> typeToComponentProvider)
{ {

View File

@@ -23,7 +23,7 @@ namespace BTCPayServer.HostedServices
protected BaseAsyncService(ILogger logger) protected BaseAsyncService(ILogger logger)
{ {
Logs = new Logs() { PayServer = logger, Events = logger, Configuration = logger}; Logs = new Logs() { PayServer = logger, Events = logger, Configuration = logger };
} }
public virtual Task StartAsync(CancellationToken cancellationToken) public virtual Task StartAsync(CancellationToken cancellationToken)

View File

@@ -29,7 +29,7 @@ namespace BTCPayServer.HostedServices
public EventHostedServiceBase(EventAggregator eventAggregator, ILogger logger) public EventHostedServiceBase(EventAggregator eventAggregator, ILogger logger)
{ {
_EventAggregator = eventAggregator; _EventAggregator = eventAggregator;
Logs = new Logs() { PayServer = logger, Events = logger, Configuration = logger}; Logs = new Logs() { PayServer = logger, Events = logger, Configuration = logger };
} }
readonly Channel<object> _Events = Channel.CreateUnbounded<object>(); readonly Channel<object> _Events = Channel.CreateUnbounded<object>();

View File

@@ -26,7 +26,7 @@ namespace BTCPayServer.HostedServices
Invoice = invoice; Invoice = invoice;
} }
public InvoiceEntity Invoice { get; set; } public InvoiceEntity Invoice { get; set; }
public List<object> Events { get; set; } = new (); public List<object> Events { get; set; } = new();
bool _dirty; bool _dirty;
@@ -68,7 +68,7 @@ namespace BTCPayServer.HostedServices
Logs = logs; Logs = logs;
} }
readonly CompositeDisposable _leases = new (); readonly CompositeDisposable _leases = new();
private void UpdateInvoice(UpdateInvoiceContext context) private void UpdateInvoice(UpdateInvoiceContext context)

View File

@@ -257,7 +257,7 @@ namespace BTCPayServer.HostedServices
payoutHandler.StartBackgroundCheck(Subscribe); payoutHandler.StartBackgroundCheck(Subscribe);
} }
return new[] {Loop()}; return new[] { Loop() };
} }
private void Subscribe(params Type[] events) private void Subscribe(params Type[] events)
@@ -428,7 +428,7 @@ namespace BTCPayServer.HostedServices
switch (req.Request.State) switch (req.Request.State)
{ {
case PayoutState.Completed or PayoutState.InProgress case PayoutState.Completed or PayoutState.InProgress
when payout.State is not PayoutState.AwaitingPayment and not PayoutState.Completed and not PayoutState.InProgress : when payout.State is not PayoutState.AwaitingPayment and not PayoutState.Completed and not PayoutState.InProgress:
case PayoutState.AwaitingPayment when payout.State is not PayoutState.InProgress: case PayoutState.AwaitingPayment when payout.State is not PayoutState.InProgress:
req.Completion.SetResult(MarkPayoutRequest.PayoutPaidResult.InvalidState); req.Completion.SetResult(MarkPayoutRequest.PayoutPaidResult.InvalidState);
return; return;
@@ -526,7 +526,7 @@ namespace BTCPayServer.HostedServices
: await ctx.Payouts.GetPayoutInPeriod(pp, now) : await ctx.Payouts.GetPayoutInPeriod(pp, now)
.Where(p => p.State != PayoutState.Cancelled).ToListAsync(); .Where(p => p.State != PayoutState.Cancelled).ToListAsync();
var payouts = payoutsRaw?.Select(o => new {Entity = o, Blob = o.GetBlob(_jsonSerializerSettings)}); var payouts = payoutsRaw?.Select(o => new { Entity = o, Blob = o.GetBlob(_jsonSerializerSettings) });
var limit = ppBlob?.Limit ?? 0; var limit = ppBlob?.Limit ?? 0;
var totalPayout = payouts?.Select(p => p.Blob.Amount)?.Sum(); var totalPayout = payouts?.Select(p => p.Blob.Amount)?.Sum();
var claimed = req.ClaimRequest.Value is decimal v ? v : limit - (totalPayout ?? 0); var claimed = req.ClaimRequest.Value is decimal v ? v : limit - (totalPayout ?? 0);
@@ -554,7 +554,8 @@ namespace BTCPayServer.HostedServices
}; };
var payoutBlob = new PayoutBlob() var payoutBlob = new PayoutBlob()
{ {
Amount = claimed, Destination = req.ClaimRequest.Destination.ToString() Amount = claimed,
Destination = req.ClaimRequest.Destination.ToString()
}; };
payout.SetBlob(payoutBlob, _jsonSerializerSettings); payout.SetBlob(payoutBlob, _jsonSerializerSettings);
await ctx.Payouts.AddAsync(payout); await ctx.Payouts.AddAsync(payout);
@@ -616,7 +617,7 @@ namespace BTCPayServer.HostedServices
List<PayoutData> payouts = null; List<PayoutData> payouts = null;
if (cancel.PullPaymentId != null) if (cancel.PullPaymentId != null)
{ {
ctx.PullPayments.Attach(new Data.PullPaymentData() {Id = cancel.PullPaymentId, Archived = true}) ctx.PullPayments.Attach(new Data.PullPaymentData() { Id = cancel.PullPaymentId, Archived = true })
.Property(o => o.Archived).IsModified = true; .Property(o => o.Archived).IsModified = true;
payouts = await ctx.Payouts payouts = await ctx.Payouts
.Where(p => p.PullPaymentDataId == cancel.PullPaymentId) .Where(p => p.PullPaymentDataId == cancel.PullPaymentId)

View File

@@ -4,15 +4,15 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Controllers; using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.Controllers.Greenfield; using BTCPayServer.Controllers.Greenfield;
using BTCPayServer.Data;
using BTCPayServer.Events; using BTCPayServer.Events;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Mails; using BTCPayServer.Services.Mails;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using BTCPayServer.Services.Invoices;
using InvoiceData = BTCPayServer.Client.Models.InvoiceData; using InvoiceData = BTCPayServer.Client.Models.InvoiceData;
namespace BTCPayServer.HostedServices; namespace BTCPayServer.HostedServices;
@@ -63,7 +63,7 @@ public class StoreEmailRuleProcessorSender : EventHostedServiceBase
var sender = await _emailSenderFactory.GetEmailSender(invoiceEvent.Invoice.StoreId); var sender = await _emailSenderFactory.GetEmailSender(invoiceEvent.Invoice.StoreId);
foreach (UIStoresController.StoreEmailRule actionableRule in actionableRules) foreach (UIStoresController.StoreEmailRule actionableRule in actionableRules)
{ {
var recipients = (actionableRule.To?.Split(",", StringSplitOptions.RemoveEmptyEntries)??Array.Empty<string>()) var recipients = (actionableRule.To?.Split(",", StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>())
.Select(o => .Select(o =>
{ {
MailboxAddressValidator.TryParse(o, out var mb); MailboxAddressValidator.TryParse(o, out var mb);

View File

@@ -82,7 +82,7 @@ namespace BTCPayServer.HostedServices
break; break;
} }
case InvoiceEvent {Name: InvoiceEvent.ReceivedPayment} invoiceEvent when case InvoiceEvent { Name: InvoiceEvent.ReceivedPayment } invoiceEvent when
invoiceEvent.Payment.GetPaymentMethodId()?.PaymentType == BitcoinPaymentType.Instance && invoiceEvent.Payment.GetPaymentMethodId()?.PaymentType == BitcoinPaymentType.Instance &&
invoiceEvent.Payment.GetCryptoPaymentData() is BitcoinLikePaymentData bitcoinLikePaymentData: invoiceEvent.Payment.GetCryptoPaymentData() is BitcoinLikePaymentData bitcoinLikePaymentData:
{ {

View File

@@ -343,11 +343,12 @@ namespace BTCPayServer.Hosting
} }
var storeids = lightningAddressSettings.StoreToItemMap.Keys.ToArray(); var storeids = lightningAddressSettings.StoreToItemMap.Keys.ToArray();
var existingStores = (await ctx.Stores.Where(data => storeids.Contains(data.Id)).Select(data => data.Id ).ToArrayAsync()).ToHashSet(); var existingStores = (await ctx.Stores.Where(data => storeids.Contains(data.Id)).Select(data => data.Id).ToArrayAsync()).ToHashSet();
foreach (var storeMap in lightningAddressSettings.StoreToItemMap) foreach (var storeMap in lightningAddressSettings.StoreToItemMap)
{ {
if (!existingStores.Contains(storeMap.Key)) continue; if (!existingStores.Contains(storeMap.Key))
continue;
foreach (var storeitem in storeMap.Value) foreach (var storeitem in storeMap.Value)
{ {
if (lightningAddressSettings.Items.TryGetValue(storeitem, out var val)) if (lightningAddressSettings.Items.TryGetValue(storeitem, out var val))
@@ -404,14 +405,14 @@ WHERE cte.""Id""=p.""Id""
var queryable = ctx.Payouts.Where(data => data.StoreDataId == null); var queryable = ctx.Payouts.Where(data => data.StoreDataId == null);
var count = await queryable.CountAsync(); var count = await queryable.CountAsync();
_logger.LogInformation($"Migrating {count} payouts to have a store id explicitly"); _logger.LogInformation($"Migrating {count} payouts to have a store id explicitly");
for (int i = 0; i < count; i+=1000) for (int i = 0; i < count; i += 1000)
{ {
await queryable.Include(data => data.PullPaymentData).Skip(i).Take(1000) await queryable.Include(data => data.PullPaymentData).Skip(i).Take(1000)
.ForEachAsync(data => data.StoreDataId = data.PullPaymentData.StoreId); .ForEachAsync(data => data.StoreDataId = data.PullPaymentData.StoreId);
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
_logger.LogInformation($"Migrated {i+1000}/{count} payouts to have a store id explicitly"); _logger.LogInformation($"Migrated {i + 1000}/{count} payouts to have a store id explicitly");
} }
} }
} }

View File

@@ -4,7 +4,7 @@ namespace BTCPayServer.Models.CustodianAccountViewModels
{ {
public class ViewCustodianAccountBalancesViewModel public class ViewCustodianAccountBalancesViewModel
{ {
public Dictionary<string,AssetBalanceInfo> AssetBalances { get; set; } public Dictionary<string, AssetBalanceInfo> AssetBalances { get; set; }
public string AssetBalanceExceptionMessage { get; set; } public string AssetBalanceExceptionMessage { get; set; }
public string StoreId { get; set; } public string StoreId { get; set; }

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