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_size = 4
charset = utf-8
space_before_self_closing = true
[*.json]
indent_size = 2
[swagger*.json]
indent_size = 4
# C# files
[*.cs]
# New line preferences

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ public class 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;
ToAsset = toAsset;

View File

@@ -2,10 +2,7 @@ namespace BTCPayServer.Abstractions.Custodians;
public class AssetBalancesUnavailableException : CustodianApiException
{
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;
namespace BTCPayServer.Abstractions.Custodians;
public class CustodianApiException: Exception {
public class CustodianApiException : Exception
{
public int HttpStatus { get; }
public string Code { get; }
@@ -9,7 +10,8 @@ public class CustodianApiException: Exception {
HttpStatus = httpStatus;
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;
public class CustodianFeatureNotImplementedException: CustodianApiException
public class CustodianFeatureNotImplementedException : CustodianApiException
{
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)
{
}
}

View File

@@ -4,7 +4,7 @@ public class TradeNotFoundException : CustodianApiException
{
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;
}

View File

@@ -1,6 +1,6 @@
namespace BTCPayServer.Abstractions.Custodians;
public class WrongTradingPairException: CustodianApiException
public class WrongTradingPairException : CustodianApiException
{
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}.")

View File

@@ -9,8 +9,6 @@ namespace BTCPayServer.Abstractions.Custodians;
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",...]
*/

View File

@@ -6,7 +6,6 @@ namespace BTCPayServer.Abstractions.Extensions;
public static class StringExtensions
{
public static bool IsValidFileName(this string fileName)
{
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;
}
}

View File

@@ -85,7 +85,7 @@ public class Form
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);
if (keylessValue is not Dictionary<string, object> dict) continue;
foreach (KeyValuePair<string,object> keyValuePair in dict)
if (keylessValue is not Dictionary<string, object> dict)
continue;
foreach (KeyValuePair<string, object> keyValuePair in dict)
{
result.TryAdd(keyValuePair.Key, keyValuePair.Value);
}

View File

@@ -8,7 +8,7 @@ public class AuthorizationFilterHandle
public AuthorizationHandlerContext Context { get; }
public PolicyRequirement Requirement { get; }
public HttpContext HttpContext { get; }
public bool Success { get; private set; }
public bool Success { get; private set; }
public AuthorizationFilterHandle(
AuthorizationHandlerContext context,

View File

@@ -82,7 +82,7 @@ namespace BTCPayServer.Client
return await HandleResponse<TradeQuoteResponseData>(response);
}
public virtual async Task<WithdrawalResponseData> CreateWithdrawal(string storeId, string accountId, WithdrawRequestData request, CancellationToken token = default)
public virtual async Task<WithdrawalResponseData> CreateWithdrawal(string storeId, string accountId, WithdrawRequestData request, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/custodian-accounts/{accountId}/withdrawals", bodyPayload: request, method: HttpMethod.Post), token);
return await HandleResponse<WithdrawalResponseData>(response);

View File

@@ -39,7 +39,7 @@ namespace BTCPayServer.Client
parameters.Add("includeNeighbourData", v);
var response =
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);
}
public virtual async Task RemoveOnChainWalletObject(string storeId, string cryptoCode, OnChainWalletObjectId objectId,
@@ -47,7 +47,7 @@ namespace BTCPayServer.Client
{
var response =
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);
}
public virtual async Task<OnChainWalletObjectData> AddOrUpdateOnChainWalletObject(string storeId, string cryptoCode, AddOnChainWalletObjectRequest request,
@@ -55,7 +55,7 @@ namespace BTCPayServer.Client
{
var response =
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);
}
public virtual async Task AddOrUpdateOnChainWalletLink(string storeId, string cryptoCode,
@@ -65,7 +65,7 @@ namespace BTCPayServer.Client
{
var response =
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);
}
public virtual async Task RemoveOnChainWalletLinks(string storeId, string cryptoCode,
@@ -75,7 +75,7 @@ namespace BTCPayServer.Client
{
var response =
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);
}
}

View File

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

View File

@@ -24,24 +24,24 @@ namespace BTCPayServer.Client
public virtual async Task<IEnumerable<LightningAutomatedPayoutSettings>> GetStoreLightningAutomatedPayoutProcessors(string storeId, string? paymentMethod = null,
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);
}
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);
}
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);
}
public virtual async Task<IEnumerable<OnChainAutomatedPayoutSettings>> GetStoreOnChainAutomatedPayoutProcessors(string storeId, string? paymentMethod = null,
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);
}
}

View File

@@ -44,7 +44,7 @@ namespace BTCPayServer.Client
{
using var response = await _httpClient.SendAsync(
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),
token);
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)
{
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);
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);
return await HandleResponse<ApplicationUserData[]>(response);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -67,7 +67,7 @@ namespace BTCPayServer.Data
public DbSet<WalletTransactionData> WalletTransactions { get; set; }
public DbSet<WebhookDeliveryData> WebhookDeliveries { 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; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

View File

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

View File

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

View File

@@ -1,8 +1,8 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
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.Tasks;
using BTCPayServer.Rating;

View File

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

View File

@@ -177,7 +177,7 @@ namespace BTCPayServer.Services.Rates
var result = JsonConvert.DeserializeObject<T>(stringResult);
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);
}

View File

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

View File

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

View File

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

View File

@@ -15,8 +15,8 @@ using BTCPayServer.Lightning;
using BTCPayServer.Models.InvoicingModels;
using BTCPayServer.Payments;
using BTCPayServer.Payments.Lightning;
using BTCPayServer.Services.Custodian.Client.MockCustodian;
using BTCPayServer.Services;
using BTCPayServer.Services.Custodian.Client.MockCustodian;
using BTCPayServer.Services.Notifications;
using BTCPayServer.Services.Notifications.Blobs;
using BTCPayServer.Services.Stores;
@@ -206,7 +206,7 @@ namespace BTCPayServer.Tests
// Test validation for creating the app
await AssertValidationError(new[] { "AppName" },
async () => await client.CreatePointOfSaleApp(user.StoreId, new CreatePointOfSaleAppRequest() {}));
async () => await client.CreatePointOfSaleApp(user.StoreId, new CreatePointOfSaleAppRequest() { }));
await AssertValidationError(new[] { "AppName" },
async () => await client.CreatePointOfSaleApp(
user.StoreId,
@@ -261,7 +261,8 @@ namespace BTCPayServer.Tests
Assert.Equal("PointOfSale", app.AppType);
// 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");
});
@@ -284,7 +285,8 @@ namespace BTCPayServer.Tests
// Test deleting the newly created app
await client.DeleteApp(retrievedApp.Id);
await AssertHttpError(404, async () => {
await AssertHttpError(404, async () =>
{
await client.GetApp(retrievedApp.Id);
});
}
@@ -301,7 +303,7 @@ namespace BTCPayServer.Tests
// Test validation for creating the app
await AssertValidationError(new[] { "AppName" },
async () => await client.CreateCrowdfundApp(user.StoreId, new CreateCrowdfundAppRequest() {}));
async () => await client.CreateCrowdfundApp(user.StoreId, new CreateCrowdfundAppRequest() { }));
await AssertValidationError(new[] { "AppName" },
async () => await client.CreateCrowdfundApp(
user.StoreId,
@@ -347,7 +349,7 @@ namespace BTCPayServer.Tests
new CreateCrowdfundAppRequest()
{
AppName = "good name",
AnimationColors = new string[] {}
AnimationColors = new string[] { }
}
)
);
@@ -377,7 +379,7 @@ namespace BTCPayServer.Tests
new CreateCrowdfundAppRequest()
{
AppName = "good name",
Sounds = new string[] { " ", " ", " " }
Sounds = new string[] { " ", " ", " " }
}
)
);
@@ -461,8 +463,8 @@ namespace BTCPayServer.Tests
var adminClient = await adminUser.CreateClient(Policies.Unrestricted);
// 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("doesnotexist@example.com"));
await AssertHttpError(404, async () => await adminClient.GetUserByIdOrEmail("non_existing_id"));
await AssertHttpError(404, async () => await adminClient.GetUserByIdOrEmail("doesnotexist@example.com"));
// Try listing all users, should be fine
await adminClient.GetUsers();
@@ -487,8 +489,8 @@ namespace BTCPayServer.Tests
await goodClient.GetUsers();
// 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("doesnotexist@example.com"));
await AssertHttpError(404, async () => await goodClient.GetUserByIdOrEmail("non_existing_id"));
await AssertHttpError(404, async () => await goodClient.GetUserByIdOrEmail("doesnotexist@example.com"));
// Try listing all users, should be fine
await goodClient.GetUsers();
@@ -510,20 +512,20 @@ namespace BTCPayServer.Tests
var badClient = await goodUser.CreateClient(Policies.CanCreateInvoice);
// 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
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("non_existing_id"));
await AssertHttpError(403, async () => await badClient.GetUserByIdOrEmail("doesnotexist@example.com"));
// 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.
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.
await AssertHttpError(403,async () => await badClient.GetUserByIdOrEmail(badUser.Email));
await AssertHttpError(403, async () => await badClient.GetUserByIdOrEmail(badUser.Email));
@@ -922,28 +924,28 @@ namespace BTCPayServer.Tests
var address = await tester.ExplorerNode.GetNewAddressAsync();
var payout = await client.CreatePayout(storeId, new CreatePayoutThroughStoreRequest()
{
Approved = false,
PaymentMethod = "BTC",
Amount = 0.0001m,
Destination = address.ToString()
Approved = false,
PaymentMethod = "BTC",
Amount = 0.0001m,
Destination = address.ToString()
});
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.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.Null((await client.GetStorePayouts(storeId,false)).Single(data => data.Id == payout.Id ).PaymentProof );
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.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 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()
@@ -957,49 +959,65 @@ namespace BTCPayServer.Tests
payout = await client.GetStorePayout(storeId, payout.Id);
Assert.NotNull(payout);
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
{
test = "zyx"
})
});
});
await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest()
{
await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest() {State = PayoutState.Completed, PaymentProof = JObject.FromObject(new
State = PayoutState.InProgress,
PaymentProof = JObject.FromObject(new
{
test = "zyx"
})});
proofType = "external-proof"
})
});
await client.MarkPayout(storeId, payout.Id, new MarkPayoutRequest() {State = PayoutState.InProgress, PaymentProof = JObject.FromObject(new
{
proofType = "external-proof"
})});
payout = await client.GetStorePayout(storeId, payout.Id);
Assert.NotNull(payout);
Assert.Equal(PayoutState.InProgress, payout.State);
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()
{
proofType = "external-proof",
id="finality proof",
link="proof.com"
})});
State = PayoutState.AwaitingPayment,
PaymentProof = JObject.FromObject(new
{
proofType = "external-proof",
id = "finality proof",
link = "proof.com"
})
});
payout = await client.GetStorePayout(storeId, payout.Id);
Assert.NotNull(payout);
Assert.Null(payout.PaymentProof);
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()
{
proofType = "external-proof",
id="finality proof",
link="proof.com"
})});
State = PayoutState.Completed,
PaymentProof = JObject.FromObject(new
{
proofType = "external-proof",
id = "finality proof",
link = "proof.com"
})
});
payout = await client.GetStorePayout(storeId, payout.Id);
Assert.NotNull(payout);
Assert.Equal(PayoutState.Completed, payout.State);
Assert.True(payout.PaymentProof.TryGetValue("proofType", out savedType));
Assert.True(payout.PaymentProof.TryGetValue("link", out var savedLink));
Assert.True(payout.PaymentProof.TryGetValue("id", out var savedId));
Assert.Equal("external-proof",savedType);
Assert.Equal("finality proof",savedId);
Assert.Equal("proof.com",savedLink);
Assert.Equal("external-proof", savedType);
Assert.Equal("finality proof", savedId);
Assert.Equal("proof.com", savedLink);
}
private DateTimeOffset RoundSeconds(DateTimeOffset dateTimeOffset)
@@ -1397,7 +1415,7 @@ namespace BTCPayServer.Tests
{
Assert.Equal(Invoice.STATUS_PAID, user.BitPay.GetInvoice(invoiceId).Status);
if (!partialPayment)
Assert.Equal(PaymentRequestData.PaymentRequestStatus.Completed, (await client.GetPaymentRequest(user.StoreId, paymentTestPaymentRequest.Id)).Status);
Assert.Equal(PaymentRequestData.PaymentRequestStatus.Completed, (await client.GetPaymentRequest(user.StoreId, paymentTestPaymentRequest.Id)).Status);
});
}
await Pay(invoiceId);
@@ -1593,14 +1611,16 @@ namespace BTCPayServer.Tests
// test validation that the invoice exists
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,
RefundVariant = RefundVariant.RateThen
});
});
// 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,
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
await client.MarkInvoiceStatus(user.StoreId, invoice.Id, new MarkInvoiceStatusRequest() {
await client.MarkInvoiceStatus(user.StoreId, invoice.Id, new MarkInvoiceStatusRequest()
{
Status = InvoiceStatus.Settled
});
// test validation for the payment method
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",
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);
// 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,
RefundVariant = RefundVariant.RateThen
});
@@ -1638,7 +1661,8 @@ namespace BTCPayServer.Tests
Assert.Equal(pp.Name, $"Refund {invoice.Id}");
// 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,
RefundVariant = RefundVariant.CurrentRate
});
@@ -1647,7 +1671,8 @@ namespace BTCPayServer.Tests
Assert.Equal(1, pp.Amount);
// 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,
RefundVariant = RefundVariant.Fiat,
Name = "my test name"
@@ -1660,7 +1685,8 @@ namespace BTCPayServer.Tests
// test RefundVariant.Custom
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,
RefundVariant = RefundVariant.Custom,
});
@@ -1668,7 +1694,8 @@ namespace BTCPayServer.Tests
Assert.Contains("CustomAmount: Amount must be greater than 0", 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,
RefundVariant = RefundVariant.Custom,
CustomAmount = 69420,
@@ -1679,7 +1706,8 @@ namespace BTCPayServer.Tests
Assert.Equal(69420, pp.Amount);
// 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,
RefundVariant = RefundVariant.Custom,
CustomAmount = 0.00069420m,
@@ -2171,7 +2199,8 @@ namespace BTCPayServer.Tests
Assert.NotEmpty(merchantInvoices);
Assert.Empty(merchantPendingInvoices);
// 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
Assert.True(LightMoney.Satoshis(1000) <= invoice.AmountReceived);
@@ -2503,10 +2532,10 @@ namespace BTCPayServer.Tests
await nonAdminUserClient.GetStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC");
});
await AssertPermissionError("btcpay.server.canuseinternallightningnode", () => nonAdminUserClient.UpdateStoreLightningNetworkPaymentMethod(nonAdminUser.StoreId, "BTC", new UpdateLightningNetworkPaymentMethodRequest()
{
Enabled = method.Enabled,
ConnectionString = method.ConnectionString
}));
{
Enabled = method.Enabled,
ConnectionString = method.ConnectionString
}));
settings = await tester.PayTester.GetService<SettingsRepository>().GetSettingAsync<PoliciesSettings>();
settings.AllowLightningInternalNodeForAll = true;
@@ -2663,10 +2692,10 @@ namespace BTCPayServer.Tests
// Validation for excluding unconfirmed UTXOs and manually selecting inputs at the same time
await AssertValidationError(new[] { "ExcludeUnconfirmed" }, async () =>
{
createTxRequest.SelectedInputs = new List<OutPoint>();
createTxRequest.ExcludeUnconfirmed = true;
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
createTxRequest.SelectedInputs = new List<OutPoint>();
createTxRequest.ExcludeUnconfirmed = true;
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
});
createTxRequest.SelectedInputs = null;
createTxRequest.ExcludeUnconfirmed = false;
@@ -2765,7 +2794,8 @@ namespace BTCPayServer.Tests
// transaction patch tests
var patchedTransaction = await client.PatchOnChainWalletTransaction(
walletId.StoreId, walletId.CryptoCode, txdata.TransactionHash.ToString(),
new PatchOnChainTransactionRequest() {
new PatchOnChainTransactionRequest()
{
Comment = "test comment",
Labels = new List<string>
{
@@ -2895,13 +2925,13 @@ namespace BTCPayServer.Tests
var users = await client.GetStoreUsers(user.StoreId);
var storeuser = Assert.Single(users);
Assert.Equal(user.UserId,storeuser.UserId);
Assert.Equal(StoreRoles.Owner,storeuser.Role);
Assert.Equal(user.UserId, storeuser.UserId);
Assert.Equal(StoreRoles.Owner, storeuser.Role);
var user2= tester.NewAccount();
var user2 = tester.NewAccount();
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
await AssertPermissionError(Policies.CanModifyStoreSettings, async () => await user2Client.GetStoreUsers(user.StoreId));
@@ -2923,9 +2953,9 @@ namespace BTCPayServer.Tests
await client.AddStoreUser(user.StoreId, new StoreUserData() { Role = StoreRoles.Owner, UserId = user2.UserId });
await AssertAPIError("duplicate-store-user-role",async ()=>
await client.AddStoreUser(user.StoreId,
new StoreUserData() { Role = StoreRoles.Owner, UserId = user2.UserId }));
await AssertAPIError("duplicate-store-user-role", async () =>
await client.AddStoreUser(user.StoreId,
new StoreUserData() { Role = StoreRoles.Owner, UserId = user2.UserId }));
await user2Client.RemoveStoreUser(user.StoreId, user.UserId);
@@ -2985,16 +3015,16 @@ namespace BTCPayServer.Tests
Assert.True(await adminClient.LockUser(newUser.UserId, true, CancellationToken.None));
Assert.True((await adminClient.GetUserByIdOrEmail(newUser.UserId)).Disabled);
await AssertAPIError("unauthenticated",async () =>
{
await newUserClient.GetCurrentUser();
});
await AssertAPIError("unauthenticated", async () =>
{
await newUserClient.GetCurrentUser();
});
var newUserBasicClient = new BTCPayServerClient(newUserClient.Host, newUser.RegisterDetails.Email,
newUser.RegisterDetails.Password);
await AssertAPIError("unauthenticated",async () =>
{
await newUserBasicClient.GetCurrentUser();
});
await AssertAPIError("unauthenticated", async () =>
{
await newUserBasicClient.GetCurrentUser();
});
Assert.True(await adminClient.LockUser(newUser.UserId, false, CancellationToken.None));
Assert.False((await adminClient.GetUserByIdOrEmail(newUser.UserId)).Disabled);
@@ -3037,17 +3067,19 @@ namespace BTCPayServer.Tests
var payout = await adminClient.CreatePayout(admin.StoreId,
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"));
await adminClient.UpdateStoreLightningAutomatedPayoutProcessors(admin.StoreId, "BTC_LightningNetwork",
new LightningAutomatedPayoutSettings() {IntervalSeconds = TimeSpan.FromSeconds(2)});
Assert.Equal(2, Assert.Single( await adminClient.GetStoreLightningAutomatedPayoutProcessors(admin.StoreId, "BTC_LightningNetwork")).IntervalSeconds.TotalSeconds);
new LightningAutomatedPayoutSettings() { IntervalSeconds = TimeSpan.FromSeconds(2) });
Assert.Equal(2, Assert.Single(await adminClient.GetStoreLightningAutomatedPayoutProcessors(admin.StoreId, "BTC_LightningNetwork")).IntervalSeconds.TotalSeconds);
await TestUtils.EventuallyAsync(async () =>
{
var payoutC =
(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 registeredProcessors = await adminClient.GetPayoutProcessors();
Assert.Equal(2,registeredProcessors.Count());
Assert.Equal(2, registeredProcessors.Count());
await adminClient.GenerateOnChainWallet(admin.StoreId, "BTC", new GenerateOnChainWalletRequest()
{
SavePrivateKeys = true
@@ -3092,7 +3124,7 @@ namespace BTCPayServer.Tests
Amount = 100,
Currency = "USD",
Name = "pull payment",
PaymentMethods = new []{ "BTC"}
PaymentMethods = new[] { "BTC" }
});
var notapprovedPayoutWithPullPayment = await adminClient.CreatePayout(admin.StoreId, new CreatePayoutThroughStoreRequest()
@@ -3120,55 +3152,55 @@ namespace BTCPayServer.Tests
Assert.Empty(payouts.Where(data => data.State == PayoutState.AwaitingApproval));
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.GetPayoutProcessors(admin.StoreId));
Assert.Empty(await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC"));
Assert.Empty(await adminClient.GetPayoutProcessors(admin.StoreId));
await adminClient.UpdateStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC",
new OnChainAutomatedPayoutSettings() {IntervalSeconds = TimeSpan.FromSeconds(100000)});
Assert.Equal(100000, Assert.Single( await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC")).IntervalSeconds.TotalSeconds);
await adminClient.UpdateStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC",
new OnChainAutomatedPayoutSettings() { IntervalSeconds = TimeSpan.FromSeconds(100000) });
Assert.Equal(100000, Assert.Single(await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC")).IntervalSeconds.TotalSeconds);
var tpGen = Assert.Single(await adminClient.GetPayoutProcessors(admin.StoreId));
Assert.Equal("BTC", Assert.Single(tpGen.PaymentMethods));
//still too poor to process any payouts
Assert.Empty( await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC"));
var tpGen = Assert.Single(await adminClient.GetPayoutProcessors(admin.StoreId));
Assert.Equal("BTC", Assert.Single(tpGen.PaymentMethods));
//still too poor to process any payouts
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.GetPayoutProcessors(admin.StoreId));
Assert.Empty(await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC"));
Assert.Empty(await adminClient.GetPayoutProcessors(admin.StoreId));
await tester.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create((await adminClient.GetOnChainWalletReceiveAddress(admin.StoreId, "BTC", true)).Address,
tester.ExplorerClient.Network.NBitcoinNetwork), Money.Coins(0.000012m));
await tester.ExplorerNode.GenerateAsync(1);
await TestUtils.EventuallyAsync(async () =>
{
Assert.Single(await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC"));
await tester.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create((await adminClient.GetOnChainWalletReceiveAddress(admin.StoreId, "BTC", true)).Address,
tester.ExplorerClient.Network.NBitcoinNetwork), Money.Coins(0.000012m));
await tester.ExplorerNode.GenerateAsync(1);
await TestUtils.EventuallyAsync(async () =>
{
Assert.Single(await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC"));
payouts = await adminClient.GetStorePayouts(admin.StoreId);
Assert.Equal(3, payouts.Length);
});
await adminClient.UpdateStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC",
new OnChainAutomatedPayoutSettings() {IntervalSeconds = TimeSpan.FromSeconds(5)});
Assert.Equal(5, Assert.Single( await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC")).IntervalSeconds.TotalSeconds);
await TestUtils.EventuallyAsync(async () =>
{
Assert.Equal(2, (await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC")).Count());
payouts = await adminClient.GetStorePayouts(admin.StoreId);
Assert.Single(payouts.Where(data => data.State == PayoutState.InProgress));
});
payouts = await adminClient.GetStorePayouts(admin.StoreId);
Assert.Equal(3, payouts.Length);
});
await adminClient.UpdateStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC",
new OnChainAutomatedPayoutSettings() { IntervalSeconds = TimeSpan.FromSeconds(5) });
Assert.Equal(5, Assert.Single(await adminClient.GetStoreOnChainAutomatedPayoutProcessors(admin.StoreId, "BTC")).IntervalSeconds.TotalSeconds);
await TestUtils.EventuallyAsync(async () =>
{
Assert.Equal(2, (await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC")).Count());
payouts = await adminClient.GetStorePayouts(admin.StoreId);
Assert.Single(payouts.Where(data => data.State == PayoutState.InProgress));
});
await tester.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create((await adminClient.GetOnChainWalletReceiveAddress(admin.StoreId, "BTC", true)).Address,
tester.ExplorerClient.Network.NBitcoinNetwork), Money.Coins(0.01m));
await TestUtils.EventuallyAsync(async () =>
{
Assert.Equal(4, (await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC")).Count());
payouts = await adminClient.GetStorePayouts(admin.StoreId);
Assert.Empty(payouts.Where(data => data.State != PayoutState.InProgress));
});
await tester.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create((await adminClient.GetOnChainWalletReceiveAddress(admin.StoreId, "BTC", true)).Address,
tester.ExplorerClient.Network.NBitcoinNetwork), Money.Coins(0.01m));
await TestUtils.EventuallyAsync(async () =>
{
Assert.Equal(4, (await adminClient.ShowOnChainWalletTransactions(admin.StoreId, "BTC")).Count());
payouts = await adminClient.GetStorePayouts(admin.StoreId);
Assert.Empty(payouts.Where(data => data.State != PayoutState.InProgress));
});
}
[Fact(Timeout = 60 * 2 * 1000)]
@@ -3284,7 +3316,7 @@ namespace BTCPayServer.Tests
var allObjects = await client.GetOnChainWalletObjects(admin.StoreId, "BTC");
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 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 });
Assert.Equal(4, allObjects.Length);
@@ -3338,11 +3370,11 @@ namespace BTCPayServer.Tests
Assert.Equal(0.9m,
Assert.Single(await clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId,
new StoreRateConfiguration() {IsCustomScript = true, EffectiveScript = "BTC_XYZ = 1;", Spread = 10m,},
new[] {"BTC_XYZ"})).Rate);
new StoreRateConfiguration() { IsCustomScript = true, EffectiveScript = "BTC_XYZ = 1;", Spread = 10m, },
new[] { "BTC_XYZ" })).Rate);
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);
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.UpdateStoreRateConfiguration(user.StoreId,
new StoreRateConfiguration() { IsCustomScript = false, PreferredSource = "coingecko"}))
new StoreRateConfiguration() { IsCustomScript = false, PreferredSource = "coingecko" }))
.PreferredSource);
config = await clientBasic.GetStoreRateConfiguration(user.StoreId);
@@ -3397,22 +3429,22 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
var storeId = store.Id;
// Load a custodian, we use the first one we find.
var custodians = tester.PayTester.GetService<IEnumerable<ICustodian>>();
var custodians = tester.PayTester.GetService<IEnumerable<ICustodian>>();
var custodian = custodians.First();
// List custodian accounts
// Unauth
await AssertHttpError(401, async () => await unauthClient.GetCustodianAccounts(storeId));
// Auth, but wrong permission
await AssertHttpError(403, async () => await authedButLackingPermissionsClient.GetCustodianAccounts(storeId));
// Auth, but wrong permission
await AssertHttpError(403, async () => await authedButLackingPermissionsClient.GetCustodianAccounts(storeId));
// Auth, correct permission, empty result
var emptyCustodianAccounts = await viewerOnlyClient.GetCustodianAccounts(storeId);
Assert.Empty(emptyCustodianAccounts);
// Auth, correct permission, empty result
var emptyCustodianAccounts = await viewerOnlyClient.GetCustodianAccounts(storeId);
Assert.Empty(emptyCustodianAccounts);
// Create custodian account
// Create custodian account
JObject config = JObject.Parse(@"{
'WithdrawToAddressNamePerPaymentMethod': {
@@ -3480,10 +3512,10 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
Assert.Equal(singleAdminCustodianAccount.CustodianCode, custodian.Code);
// 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
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
var singleManagerCustodianAccount = await managerClient.GetCustodianAccount(storeId, accountId);
@@ -3572,7 +3604,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
await admin.GrantAccessAsync(true);
var unauthClient = new BTCPayServerClient(tester.PayTester.ServerUri);
var authClientNoPermissions = await admin.CreateClient(Policies.CanViewInvoices);
var authClientNoPermissions = await admin.CreateClient(Policies.CanViewInvoices);
var adminClient = await admin.CreateClient(Policies.Unrestricted);
var managerClient = await admin.CreateClient(Policies.CanManageCustodianAccounts);
var withdrawalClient = await admin.CreateClient(Policies.CanWithdrawFromCustodianAccounts);
@@ -3584,11 +3616,11 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
var storeId = store.Id;
// Load a custodian, we use the first one we find.
var custodians = tester.PayTester.GetService<IEnumerable<ICustodian>>();
var custodians = tester.PayTester.GetService<IEnumerable<ICustodian>>();
var mockCustodian = custodians.First(c => c.Code == "mock");
// Create custodian account
var createCustodianAccountRequest = new CreateCustodianAccountRequest();
// Create custodian account
var createCustodianAccountRequest = new CreateCustodianAccountRequest();
createCustodianAccountRequest.CustodianCode = mockCustodian.Code;
var custodianAccountData = await managerClient.CreateCustodianAccount(storeId, createCustodianAccountRequest);
@@ -3599,7 +3631,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
// 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.AssetBalances);
Assert.Equal(4, custodianAccountWithBalances.AssetBalances.Count);
@@ -3613,7 +3645,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
Assert.Equal(MockCustodian.BalanceUSD, custodianAccountWithBalances.AssetBalances["USD"]);
// 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.Null(custodianAccountWithoutBalances.AssetBalances);
@@ -3640,7 +3672,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
// 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));
// Test: Trade, auth, but wrong permission
@@ -3654,30 +3686,30 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
Assert.Equal(MockCustodian.TradeId, newTradeResult.TradeId);
Assert.Equal(tradeRequest.FromAsset, newTradeResult.FromAsset);
Assert.Equal(tradeRequest.ToAsset, newTradeResult.ToAsset);
Assert.NotNull( newTradeResult.LedgerEntries);
Assert.Equal( 3, newTradeResult.LedgerEntries.Count);
Assert.Equal( MockCustodian.TradeQtyBought, newTradeResult.LedgerEntries[0].Qty);
Assert.Equal( tradeRequest.ToAsset, newTradeResult.LedgerEntries[0].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Trade , newTradeResult.LedgerEntries[0].Type);
Assert.Equal( -1 * MockCustodian.TradeQtyBought * MockCustodian.BtcPriceInEuro, newTradeResult.LedgerEntries[1].Qty);
Assert.Equal( tradeRequest.FromAsset, newTradeResult.LedgerEntries[1].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Trade , newTradeResult.LedgerEntries[1].Type);
Assert.Equal( -1 * MockCustodian.TradeFeeEuro, newTradeResult.LedgerEntries[2].Qty);
Assert.Equal( tradeRequest.FromAsset, newTradeResult.LedgerEntries[2].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Fee , newTradeResult.LedgerEntries[2].Type);
Assert.NotNull(newTradeResult.LedgerEntries);
Assert.Equal(3, newTradeResult.LedgerEntries.Count);
Assert.Equal(MockCustodian.TradeQtyBought, newTradeResult.LedgerEntries[0].Qty);
Assert.Equal(tradeRequest.ToAsset, newTradeResult.LedgerEntries[0].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Trade, newTradeResult.LedgerEntries[0].Type);
Assert.Equal(-1 * MockCustodian.TradeQtyBought * MockCustodian.BtcPriceInEuro, newTradeResult.LedgerEntries[1].Qty);
Assert.Equal(tradeRequest.FromAsset, newTradeResult.LedgerEntries[1].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Trade, newTradeResult.LedgerEntries[1].Type);
Assert.Equal(-1 * MockCustodian.TradeFeeEuro, newTradeResult.LedgerEntries[2].Qty);
Assert.Equal(tradeRequest.FromAsset, newTradeResult.LedgerEntries[2].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Fee, newTradeResult.LedgerEntries[2].Type);
// 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));
// TODO Test: Trade with percentage qty
// Test: Trade with wrong decimal format (example: JavaScript scientific format)
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));
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));
// 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));
// Test: wrong account ID
@@ -3687,15 +3719,15 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
await AssertHttpError(403, async () => await tradeClient.MarketTradeCustodianAccountAsset("WRONG-STORE-ID", accountId, tradeRequest));
// 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));
// Test: GetTradeQuote, unauth
await AssertHttpError(401, async () => await unauthClient.GetTradeQuote(storeId, accountId, MockCustodian.TradeFromAsset, MockCustodian.TradeToAsset));
await AssertHttpError(401, async () => await unauthClient.GetTradeQuote(storeId, accountId, MockCustodian.TradeFromAsset, MockCustodian.TradeToAsset));
// Test: GetTradeQuote, auth, but wrong permission
await AssertHttpError(403, async () => await managerClient.GetTradeQuote(storeId, accountId, MockCustodian.TradeFromAsset, MockCustodian.TradeToAsset));
await AssertHttpError(403, async () => await managerClient.GetTradeQuote(storeId, accountId, MockCustodian.TradeFromAsset, MockCustodian.TradeToAsset));
// Test: GetTradeQuote, auth, correct permission
var tradeQuote = await tradeClient.GetTradeQuote(storeId, accountId, MockCustodian.TradeFromAsset, MockCustodian.TradeToAsset);
@@ -3706,27 +3738,27 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
Assert.Equal(MockCustodian.BtcPriceInEuro, tradeQuote.Ask);
// Test: GetTradeQuote, SATS
await AssertApiError(400, "use-asset-synonym", async () => await tradeClient.GetTradeQuote(storeId, accountId, MockCustodian.TradeFromAsset, "SATS"));
await AssertApiError(400, "use-asset-synonym", async () => await tradeClient.GetTradeQuote(storeId, accountId, MockCustodian.TradeFromAsset, "SATS"));
// 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, MockCustodian.TradeFromAsset , "WRONG-ASSET"));
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"));
// 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));
// Test: wrong store ID
await AssertHttpError(403, async () => await tradeClient.GetTradeQuote("WRONG-STORE-ID", accountId, MockCustodian.TradeFromAsset, MockCustodian.TradeToAsset));
await AssertHttpError(403, async () => await tradeClient.GetTradeQuote("WRONG-STORE-ID", accountId, MockCustodian.TradeFromAsset, MockCustodian.TradeToAsset));
// Test: GetTradeInfo, unauth
await AssertHttpError(401, async () => await unauthClient.GetTradeInfo(storeId, accountId, MockCustodian.TradeId));
await AssertHttpError(401, async () => await unauthClient.GetTradeInfo(storeId, accountId, MockCustodian.TradeId));
// Test: GetTradeInfo, auth, but wrong permission
await AssertHttpError(403, async () => await managerClient.GetTradeInfo(storeId, accountId, MockCustodian.TradeId));
await AssertHttpError(403, async () => await managerClient.GetTradeInfo(storeId, accountId, MockCustodian.TradeId));
// Test: GetTradeInfo, auth, correct permission
var tradeResult = await tradeClient.GetTradeInfo(storeId, accountId, MockCustodian.TradeId);
@@ -3736,17 +3768,17 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
Assert.Equal(MockCustodian.TradeId, tradeResult.TradeId);
Assert.Equal(tradeRequest.FromAsset, tradeResult.FromAsset);
Assert.Equal(tradeRequest.ToAsset, tradeResult.ToAsset);
Assert.NotNull( tradeResult.LedgerEntries);
Assert.Equal( 3, tradeResult.LedgerEntries.Count);
Assert.Equal( MockCustodian.TradeQtyBought, tradeResult.LedgerEntries[0].Qty);
Assert.Equal( tradeRequest.ToAsset, tradeResult.LedgerEntries[0].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Trade , tradeResult.LedgerEntries[0].Type);
Assert.Equal( -1 * MockCustodian.TradeQtyBought * MockCustodian.BtcPriceInEuro, tradeResult.LedgerEntries[1].Qty);
Assert.Equal( tradeRequest.FromAsset, tradeResult.LedgerEntries[1].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Trade , tradeResult.LedgerEntries[1].Type);
Assert.Equal( -1 * MockCustodian.TradeFeeEuro, tradeResult.LedgerEntries[2].Qty);
Assert.Equal( tradeRequest.FromAsset, tradeResult.LedgerEntries[2].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Fee , tradeResult.LedgerEntries[2].Type);
Assert.NotNull(tradeResult.LedgerEntries);
Assert.Equal(3, tradeResult.LedgerEntries.Count);
Assert.Equal(MockCustodian.TradeQtyBought, tradeResult.LedgerEntries[0].Qty);
Assert.Equal(tradeRequest.ToAsset, tradeResult.LedgerEntries[0].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Trade, tradeResult.LedgerEntries[0].Type);
Assert.Equal(-1 * MockCustodian.TradeQtyBought * MockCustodian.BtcPriceInEuro, tradeResult.LedgerEntries[1].Qty);
Assert.Equal(tradeRequest.FromAsset, tradeResult.LedgerEntries[1].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Trade, tradeResult.LedgerEntries[1].Type);
Assert.Equal(-1 * MockCustodian.TradeFeeEuro, tradeResult.LedgerEntries[2].Qty);
Assert.Equal(tradeRequest.FromAsset, tradeResult.LedgerEntries[2].Asset);
Assert.Equal(LedgerEntryData.LedgerEntryType.Fee, tradeResult.LedgerEntries[2].Type);
// Test: GetTradeInfo, 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
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));
// Test: CreateWithdrawal, auth, but wrong permission
@@ -3771,7 +3803,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
// 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));
// Test: CreateWithdrawal, wrong account ID
@@ -3779,7 +3811,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
// 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.
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
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()
{
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;
}

View File

@@ -395,9 +395,9 @@ namespace BTCPayServer.Tests
s.GoToWallet(receiverWalletId, WalletsNavPages.Transactions);
Assert.Contains(invoiceId, s.Driver.PageSource);
Assert.Contains("payjoin", s.Driver.PageSource);
//this label does not always show since input gets used
// Assert.Contains("payjoin-exposed", s.Driver.PageSource);
});
//this label does not always show since input gets used
// Assert.Contains("payjoin-exposed", s.Driver.PageSource);
});
}
}

View File

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

View File

@@ -1704,7 +1704,7 @@ namespace BTCPayServer.Tests
//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("Name")).SendKeys("PP1");
s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true);
@@ -1715,7 +1715,7 @@ namespace BTCPayServer.Tests
s.FindAlertMessage(StatusMessageModel.StatusSeverity.Success);
s.Driver.FindElement(By.LinkText("View")).Click();
s.Driver.FindElement(By.CssSelector("#lnurlwithdraw-button")).Click();
var lnurl = new Uri(LNURL.LNURL.Parse(s.Driver.FindElement(By.Id("qr-code-data-input")).GetAttribute("value"), out _).ToString().Replace("https", "http"));
var lnurl = new Uri(LNURL.LNURL.Parse(s.Driver.FindElement(By.Id("qr-code-data-input")).GetAttribute("value"), out _).ToString().Replace("https", "http"));
s.Driver.FindElement(By.CssSelector("button[data-bs-dismiss='modal']")).Click();
var info = Assert.IsType<LNURLWithdrawRequest>(await LNURL.LNURL.FetchInformation(lnurl, s.Server.PayTester.HttpClient));
Assert.Equal(info.MaxWithdrawable, new LightMoney(0.0000001m, LightMoneyUnit.BTC));
@@ -1735,10 +1735,10 @@ namespace BTCPayServer.Tests
Assert.Contains(bolt2.BOLT11, 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("Name")).SendKeys("PP1");
s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), false);
@@ -1749,7 +1749,7 @@ namespace BTCPayServer.Tests
s.FindAlertMessage(StatusMessageModel.StatusSeverity.Success);
s.Driver.FindElement(By.LinkText("View")).Click();
s.Driver.FindElement(By.CssSelector("#lnurlwithdraw-button")).Click();
lnurl = new Uri(LNURL.LNURL.Parse(s.Driver.FindElement(By.Id("qr-code-data-input")).GetAttribute("value"), out _).ToString().Replace("https", "http"));
lnurl = new Uri(LNURL.LNURL.Parse(s.Driver.FindElement(By.Id("qr-code-data-input")).GetAttribute("value"), out _).ToString().Replace("https", "http"));
s.Driver.FindElement(By.CssSelector("button[data-bs-dismiss='modal']")).Click();
info = Assert.IsType<LNURLWithdrawRequest>(await LNURL.LNURL.FetchInformation(lnurl, s.Server.PayTester.HttpClient));
@@ -1867,7 +1867,8 @@ namespace BTCPayServer.Tests
});
var greenfield = await s.AsTestAccount().CreateClient();
var paymentMethods = await greenfield.GetInvoicePaymentMethods(s.StoreId, i);
Assert.Single(paymentMethods, p => {
Assert.Single(paymentMethods, p =>
{
return p.AdditionalData["providedComment"].Value<string>() == "lol2";
});
// Standard invoice test
@@ -2138,32 +2139,32 @@ retry:
.FindElement(By.CssSelector($"option[value='{(int)Fido2Credential.CredentialType.LNURLAuth}']")).Click();
s.Driver.FindElement(By.Id("btn-add")).Click();
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;
foreach (string link in links)
{
var endpoint = LNURL.LNURL.Parse(link, out var tag);
Assert.Equal("login",tag);
if(endpoint.Scheme != "https")
Assert.Equal("login", tag);
if (endpoint.Scheme != "https")
prevEndpoint = endpoint;
}
var linkingKey = new Key();
var request = Assert.IsType<LNAuthRequest>(await LNURL.LNURL.FetchInformation(prevEndpoint, null));
_ = await request.SendChallenge(linkingKey, new HttpClient());
TestUtils.Eventually(() => s.FindAlertMessage());
TestUtils.Eventually(() => s.FindAlertMessage());
s.Logout();
s.LogIn(user, "123456");
var section = s.Driver.FindElement(By.Id("lnurlauth-section"));
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;
foreach (string link in links)
{
var endpoint = LNURL.LNURL.Parse(link, out var tag);
Assert.Equal("login",tag);
if(endpoint.Scheme != "https")
Assert.Equal("login", tag);
if (endpoint.Scheme != "https")
prevEndpoint = endpoint;
}
request = Assert.IsType<LNAuthRequest>(await LNURL.LNURL.FetchInformation(prevEndpoint, null));

View File

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

View File

@@ -199,11 +199,11 @@ namespace BTCPayServer.Tests
var user = tester.NewAccount();
await user.GrantAccessAsync();
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);
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);
await settingsRepo.UpdateSetting<TestData>(user.StoreId, "arbitrary", new TestData() { Name = "hello" });
@@ -1934,8 +1934,8 @@ namespace BTCPayServer.Tests
Assert.Contains($",orderId,{invoice.Id},", paidresult.Content);
Assert.Contains($",On-Chain,BTC,0.0991,0.0001,5000.0", paidresult.Content);
Assert.Contains($",USD,5.00", paidresult.Content); // Seems hacky but some plateform does not render this decimal the same
Assert.Contains("0,,\"Some \"\", description\",New (paidPartial),new,paidPartial",
paidresult.Content);
Assert.Contains("0,,\"Some \"\", description\",New (paidPartial),new,paidPartial",
paidresult.Content);
});
}
@@ -2157,7 +2157,7 @@ namespace BTCPayServer.Tests
Assert.Equal("paidPartial", localInvoice.ExceptionStatus.ToString());
Assert.Equal(1, localInvoice.CryptoInfo[0].TxCount);
Assert.NotEqual(localInvoice.BitcoinAddress, invoice.BitcoinAddress); //New address
Assert.True(IsMapped(invoice, ctx));
Assert.True(IsMapped(invoice, ctx));
Assert.True(IsMapped(localInvoice, ctx));
invoiceEntity = repo.GetInvoice(invoice.Id, true).GetAwaiter().GetResult();
@@ -2175,7 +2175,7 @@ namespace BTCPayServer.Tests
Assert.Equal(firstPayment + secondPayment, localInvoice.BtcPaid);
Assert.Equal(Money.Zero, localInvoice.BtcDue);
Assert.Equal(localInvoice.BitcoinAddress, invoiceAddress.ToString()); //no new address generated
Assert.True(IsMapped(localInvoice, ctx));
Assert.True(IsMapped(localInvoice, ctx));
Assert.False((bool)((JValue)localInvoice.ExceptionStatus).Value);
});

View File

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

View File

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

View File

@@ -47,13 +47,16 @@ public class StoreLightningBalance : ViewComponent
public async Task<IViewComponentResult> InvokeAsync(StoreLightningBalanceViewModel vm)
{
if (vm.Store == null) throw new ArgumentNullException(nameof(vm.Store));
if (vm.CryptoCode == null) throw new ArgumentNullException(nameof(vm.CryptoCode));
if (vm.Store == null)
throw new ArgumentNullException(nameof(vm.Store));
if (vm.CryptoCode == null)
throw new ArgumentNullException(nameof(vm.CryptoCode));
vm.DefaultCurrency = vm.Store.GetStoreBlob().DefaultCurrency;
vm.CurrencyData = _currencies.GetCurrencyData(vm.DefaultCurrency, true);
if (vm.InitialRendering) return View(vm);
if (vm.InitialRendering)
return View(vm);
try
{
@@ -61,12 +64,12 @@ public class StoreLightningBalance : ViewComponent
var balance = await lightningClient.GetBalance();
vm.Balance = balance;
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)
: null;
vm.TotalOffchain = balance.OffchainBalance != null
? (balance.OffchainBalance.Opening?? 0) + (balance.OffchainBalance.Local?? 0) +
(balance.OffchainBalance.Closing?? 0)
? (balance.OffchainBalance.Opening ?? 0) + (balance.OffchainBalance.Local ?? 0) +
(balance.OffchainBalance.Closing ?? 0)
: null;
}
catch (NotSupportedException)
@@ -89,9 +92,10 @@ public class StoreLightningBalance : ViewComponent
var existing = store.GetSupportedPaymentMethods(_networkProvider)
.OfType<LightningSupportedPaymentMethod>()
.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);
}

View File

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

View File

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

View File

@@ -35,31 +35,34 @@ public class StoreRecentInvoices : ViewComponent
public async Task<IViewComponentResult> InvokeAsync(StoreRecentInvoicesViewModel vm)
{
if (vm.Store == null) throw new ArgumentNullException(nameof(vm.Store));
if (vm.CryptoCode == null) throw new ArgumentNullException(nameof(vm.CryptoCode));
if (vm.InitialRendering) return View(vm);
if (vm.Store == null)
throw new ArgumentNullException(nameof(vm.Store));
if (vm.CryptoCode == null)
throw new ArgumentNullException(nameof(vm.CryptoCode));
if (vm.InitialRendering)
return View(vm);
var userId = _userManager.GetUserId(UserClaimsPrincipal);
var invoiceEntities = await _invoiceRepo.GetInvoices(new InvoiceQuery
{
UserId = userId,
StoreId = new [] { vm.Store.Id },
IncludeArchived = false,
IncludeRefunds = true,
Take = 5
});
{
UserId = userId,
StoreId = new[] { vm.Store.Id },
IncludeArchived = false,
IncludeRefunds = true,
Take = 5
});
vm.Invoices = (from invoice in invoiceEntities
let state = invoice.GetInvoiceState()
select new StoreRecentInvoiceViewModel
{
Date = invoice.InvoiceTime,
Status = state,
HasRefund = invoice.Refunds.Any(),
InvoiceId = invoice.Id,
OrderId = invoice.Metadata.OrderId ?? string.Empty,
AmountCurrency = _currencyNameTable.DisplayFormatCurrency(invoice.Price, invoice.Currency),
}).ToList();
let state = invoice.GetInvoiceState()
select new StoreRecentInvoiceViewModel
{
Date = invoice.InvoiceTime,
Status = state,
HasRefund = invoice.Refunds.Any(),
InvoiceId = invoice.Id,
OrderId = invoice.Metadata.OrderId ?? string.Empty,
AmountCurrency = _currencyNameTable.DisplayFormatCurrency(invoice.Price, invoice.Currency),
}).ToList();
return View(vm);
}

View File

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

View File

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

View File

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

View File

@@ -276,7 +276,7 @@ namespace BTCPayServer.Controllers.Greenfield
}
catch (CustodianApiException e)
{
return this.CreateAPIError(e.HttpStatus, e.Code,
return this.CreateAPIError(e.HttpStatus, e.Code,
e.Message);
}
}

View File

@@ -11,10 +11,10 @@ using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
using BTCPayServer.Payments;
using BTCPayServer.Rating;
using BTCPayServer.Services;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Rates;
using BTCPayServer.Rating;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Http;
@@ -439,7 +439,8 @@ namespace BTCPayServer.Controllers.Greenfield
break;
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");
}
@@ -599,7 +600,7 @@ namespace BTCPayServer.Controllers.Greenfield
Amount = entity.Price,
Type = entity.Type,
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(),
AdditionalStatus = entity.ExceptionStatus,
Currency = entity.Currency,

View File

@@ -313,9 +313,9 @@ namespace BTCPayServer.Controllers.Greenfield
try
{
var param = new CreateInvoiceParams(request.Amount, request.Description, request.Expiry)
{
PrivateRouteHints = request.PrivateRouteHints,
DescriptionHashOnly = request.DescriptionHashOnly
{
PrivateRouteHints = request.PrivateRouteHints,
DescriptionHashOnly = request.DescriptionHashOnly
};
var invoice = await lightningClient.CreateInvoice(param, cancellationToken);
return Ok(ToModel(invoice));

View File

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

View File

@@ -200,9 +200,9 @@ namespace BTCPayServer.Controllers.Greenfield
if (pp is null)
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)
});
return base.Ok(payouts
@@ -219,7 +219,8 @@ namespace BTCPayServer.Controllers.Greenfield
var payout = (await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
{
PullPayments = new[] {pullPaymentId}, PayoutIds = new[] {payoutId}
PullPayments = new[] { pullPaymentId },
PayoutIds = new[] { payoutId }
})).FirstOrDefault();
@@ -291,7 +292,7 @@ namespace BTCPayServer.Controllers.Greenfield
ModelState.AddModelError(nameof(request.Amount), $"Amount too small (should be at least {ppBlob.MinimumClaim})");
return this.CreateValidationError(ModelState);
}
var result = await _pullPaymentService.Claim(new ClaimRequest()
var result = await _pullPaymentService.Claim(new ClaimRequest()
{
Destination = destination.destination,
PullPaymentId = pullPaymentId,
@@ -299,7 +300,7 @@ namespace BTCPayServer.Controllers.Greenfield
PaymentMethodId = paymentMethodId,
});
return HandleClaimResult(result);
return HandleClaimResult(result);
}
[HttpPost("~/api/v1/stores/{storeId}/payouts")]
@@ -413,7 +414,7 @@ namespace BTCPayServer.Controllers.Greenfield
{
var payouts = await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
{
Stores = new[] {storeId},
Stores = new[] { storeId },
States = GetStateFilter(includeCancelled)
});
@@ -426,7 +427,7 @@ namespace BTCPayServer.Controllers.Greenfield
[Authorize(Policy = Policies.CanManagePullPayments, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
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);
}
@@ -530,7 +531,8 @@ namespace BTCPayServer.Controllers.Greenfield
var payout = (await _pullPaymentService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
{
Stores = new[] {storeId}, PayoutIds = new[] {payoutId}
Stores = new[] { storeId },
PayoutIds = new[] { payoutId }
})).FirstOrDefault();
if (payout is null)

View File

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

View File

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

View File

@@ -23,7 +23,7 @@ namespace BTCPayServer.Controllers.GreenField
private readonly EmailSenderFactory _emailSenderFactory;
private readonly StoreRepository _storeRepository;
public GreenfieldStoreEmailController(EmailSenderFactory emailSenderFactory, StoreRepository storeRepository)
public GreenfieldStoreEmailController(EmailSenderFactory emailSenderFactory, StoreRepository storeRepository)
{
_emailSenderFactory = emailSenderFactory;
_storeRepository = storeRepository;
@@ -47,7 +47,7 @@ namespace BTCPayServer.Controllers.GreenField
var emailSender = await _emailSenderFactory.GetEmailSender(storeId);
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);
return Ok();
@@ -89,7 +89,7 @@ namespace BTCPayServer.Controllers.GreenField
}
private EmailSettings FromModel(Data.StoreData data)
{
return data.GetStoreBlob().EmailSettings??new();
return data.GetStoreBlob().EmailSettings ?? new();
}
private IActionResult StoreNotFound()
{

View File

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

View File

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

View File

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

View File

@@ -72,7 +72,7 @@ namespace BTCPayServer.Controllers.Greenfield
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()
{

View File

@@ -69,7 +69,7 @@ namespace BTCPayServer.Controllers.Greenfield
[HttpGet("~/api/v1/users/{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)
{
return Ok(await FromModel(user));

View File

@@ -109,7 +109,7 @@ namespace BTCPayServer.Controllers.Greenfield
}
return ActivatorUtilities.CreateInstance<LocalBTCPayServerClient>(_serviceProvider,
new LocalHttpContextAccessor() {HttpContext = context});
new LocalHttpContextAccessor() { HttpContext = context });
}
}
@@ -141,7 +141,7 @@ namespace BTCPayServer.Controllers.Greenfield
_serviceProvider.GetService<StoreRepository>(),
_serviceProvider.GetService<IPluginHookService>()));
var controller = _serviceProvider.GetService<T>();
var controller = _serviceProvider.GetService<T>();
controller.ControllerContext.HttpContext = _httpContextAccessor.HttpContext;
var authInterface = typeof(IAuthorizationService);
var type = controller.GetType();
@@ -686,7 +686,7 @@ namespace BTCPayServer.Controllers.Greenfield
{
return GetFromActionResult<NotificationData>(
await GetController<GreenfieldNotificationsController>().UpdateNotification(notificationId,
new UpdateNotification() {Seen = seen}));
new UpdateNotification() { Seen = seen }));
}
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,
string cryptoCode, string transactionId,
PatchOnChainTransactionRequest request, bool force = false,CancellationToken token = default)
PatchOnChainTransactionRequest request, bool force = false, CancellationToken token = default)
{
return GetFromActionResult<OnChainWalletTransactionData>(
await GetController<GreenfieldStoreOnChainWalletsController>().PatchOnChainWalletTransaction(storeId, cryptoCode, transactionId,

View File

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

View File

@@ -38,16 +38,16 @@ namespace BTCPayServer
public async Task<byte[]> RequestCreation(string userId)
{
await using var dbContext = _contextFactory.CreateContext();
var user = await dbContext.Users.Include(applicationUser => applicationUser.Fido2Credentials)
.FirstOrDefaultAsync(applicationUser => applicationUser.Id == userId);
if (user == null)
{
return null;
}
var k1 = RandomUtils.GetBytes(32);
CreationStore.AddOrReplace(userId, k1);
return k1;
await using var dbContext = _contextFactory.CreateContext();
var user = await dbContext.Users.Include(applicationUser => applicationUser.Fido2Credentials)
.FirstOrDefaultAsync(applicationUser => applicationUser.Id == userId);
if (user == null)
{
return null;
}
var k1 = RandomUtils.GetBytes(32);
CreationStore.AddOrReplace(userId, k1);
return k1;
}
public async Task<bool> CompleteCreation(string name, string userId, ECDSASignature sig, PubKey pubKey)
@@ -58,7 +58,7 @@ namespace BTCPayServer
var user = await dbContext.Users.Include(applicationUser => applicationUser.Fido2Credentials)
.FirstOrDefaultAsync(applicationUser => applicationUser.Id == userId);
var pubkeyBytes = pubKey.ToBytes();
if (!CreationStore.TryGetValue(userId.ToLowerInvariant(), out var k1) || user == null || await dbContext.Fido2Credentials.AnyAsync(credential => credential.Type == Fido2Credential.CredentialType.LNURLAuth && credential.Blob == pubkeyBytes))
if (!CreationStore.TryGetValue(userId.ToLowerInvariant(), out var k1) || user == null || await dbContext.Fido2Credentials.AnyAsync(credential => credential.Type == Fido2Credential.CredentialType.LNURLAuth && credential.Blob == pubkeyBytes))
{
return false;
}
@@ -68,8 +68,7 @@ namespace BTCPayServer
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.SaveChangesAsync();
CreationStore.Remove(userId, out _);
@@ -84,7 +83,7 @@ namespace BTCPayServer
public async Task Remove(string id, string userId)
{
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))
{
return;
@@ -112,7 +111,8 @@ namespace BTCPayServer
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();
userId = userId.ToLowerInvariant();
var user = await dbContext.Users.Include(applicationUser => applicationUser.Fido2Credentials)

View File

@@ -1,8 +1,8 @@
using System;
using System.Globalization;
using System.Security.Claims;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Extensions;
@@ -160,7 +160,7 @@ namespace BTCPayServer.Controllers
var fido2Devices = await _fido2Service.HasCredentials(user.Id);
var lnurlAuthCredentials = await _lnurlAuthService.HasCredentials(user.Id);
if (!await _userManager.IsLockedOutAsync(user) && (fido2Devices || lnurlAuthCredentials))
if (!await _userManager.IsLockedOutAsync(user) && (fido2Devices || lnurlAuthCredentials))
{
if (await _userManager.CheckPasswordAsync(user, model.Password))
{
@@ -179,8 +179,8 @@ namespace BTCPayServer.Controllers
return View("SecondaryLogin", new SecondaryLoginViewModel()
{
LoginWith2FaViewModel = twoFModel,
LoginWithFido2ViewModel = fido2Devices? await BuildFido2ViewModel(model.RememberMe, user): null,
LoginWithLNURLAuthViewModel = lnurlAuthCredentials? await BuildLNURLAuthViewModel(model.RememberMe, user): null,
LoginWithFido2ViewModel = fido2Devices ? await BuildFido2ViewModel(model.RememberMe, user) : null,
LoginWithLNURLAuthViewModel = lnurlAuthCredentials ? await BuildLNURLAuthViewModel(model.RememberMe, user) : null,
});
}
else
@@ -212,7 +212,7 @@ namespace BTCPayServer.Controllers
if (result.IsLockedOut)
{
_logger.LogWarning($"User '{user.Id}' account locked out.");
return RedirectToAction(nameof(Lockout), new { user.LockoutEnd});
return RedirectToAction(nameof(Lockout), new { user.LockoutEnd });
}
else
{
@@ -262,7 +262,7 @@ namespace BTCPayServer.Controllers
LNURLEndpoint = new Uri(_linkGenerator.GetUriByAction(
action: nameof(UILNURLAuthController.LoginResponse),
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;
@@ -431,7 +431,7 @@ namespace BTCPayServer.Controllers
else if (result.IsLockedOut)
{
_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
{
@@ -501,7 +501,7 @@ namespace BTCPayServer.Controllers
{
_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
{

View File

@@ -306,7 +306,9 @@ namespace BTCPayServer.Controllers
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 amount = new Money(request.Amount, isSats ? MoneyUnit.Satoshi : MoneyUnit.BTC);
var network = _NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode).NBitcoinNetwork;
var paymentMethodId = new [] {store.GetDefaultPaymentId()}
var paymentMethodId = new[] { store.GetDefaultPaymentId() }
.Concat(store.GetEnabledPaymentIds(_NetworkProvider))
.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);
if (receipt.Enabled is not true) return NotFound();
if (receipt.Enabled is not true)
return NotFound();
if (i.Status.ToModernStatus() != InvoiceStatus.Settled)
{
return View(new InvoiceReceiptViewModel
@@ -738,10 +739,10 @@ namespace BTCPayServer.Controllers
lang ??= storeBlob.DefaultLang;
var receiptEnabled = InvoiceDataBase.ReceiptOptions.Merge(storeBlob.ReceiptOptions, invoice.ReceiptOptions).Enabled is true;
var receiptUrl = receiptEnabled? _linkGenerator.GetUriByAction(
var receiptUrl = receiptEnabled ? _linkGenerator.GetUriByAction(
nameof(InvoiceReceipt),
"UIInvoice",
new {invoiceId},
new { invoiceId },
Request.Scheme,
Request.Host,
Request.PathBase) : null;
@@ -777,7 +778,7 @@ namespace BTCPayServer.Controllers
MaxTimeMinutes = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalMinutes,
ItemDesc = invoice.Metadata.ItemDesc,
Rate = ExchangeRate(paymentMethod),
MerchantRefLink = invoice.RedirectURL?.AbsoluteUri ?? receiptUrl ?? "/",
MerchantRefLink = invoice.RedirectURL?.AbsoluteUri ?? receiptUrl ?? "/",
ReceiptLink = receiptUrl,
RedirectAutomatically = invoice.RedirectAutomatically,
StoreName = store.StoreName,

View File

@@ -106,7 +106,7 @@ namespace BTCPayServer.Controllers
return new DataWrapper<InvoiceResponse>(resp) { Facade = "pos/invoice" };
}
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(BitpayCreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string>? additionalTags = null, CancellationToken cancellationToken = default, Action<InvoiceEntity>? entityManipulator = null)
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(BitpayCreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string>? additionalTags = null, CancellationToken cancellationToken = default, Action<InvoiceEntity>? entityManipulator = null)
{
var storeBlob = store.GetStoreBlob();
var entity = _InvoiceRepository.CreateNewInvoice();
@@ -209,7 +209,7 @@ namespace BTCPayServer.Controllers
return await CreateInvoiceCoreRaw(invoiceRequest, storeData, request.GetAbsoluteRoot(), additionalTags, cancellationToken);
}
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(CreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string>? additionalTags = null, CancellationToken cancellationToken = default, Action<InvoiceEntity>? entityManipulator = null)
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(CreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string>? additionalTags = null, CancellationToken cancellationToken = default, Action<InvoiceEntity>? entityManipulator = null)
{
var storeBlob = store.GetStoreBlob();
var entity = _InvoiceRepository.CreateNewInvoice();
@@ -253,7 +253,7 @@ namespace BTCPayServer.Controllers
return await CreateInvoiceCoreRaw(entity, store, excludeFilter, invoice.AdditionalSearchTerms, cancellationToken, entityManipulator);
}
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(InvoiceEntity entity, StoreData store, IPaymentFilter? invoicePaymentMethodFilter, string[]? additionalSearchTerms = null, CancellationToken cancellationToken = default, Action<InvoiceEntity>? entityManipulator = null)
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(InvoiceEntity entity, StoreData store, IPaymentFilter? invoicePaymentMethodFilter, string[]? additionalSearchTerms = null, CancellationToken cancellationToken = default, Action<InvoiceEntity>? entityManipulator = null)
{
InvoiceLogs logs = new InvoiceLogs();
logs.Write("Creation of invoice starting", InvoiceEventData.EventSeverity.Info);

View File

@@ -49,7 +49,8 @@ namespace BTCPayServer
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();
@@ -108,7 +109,8 @@ namespace BTCPayServer
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
{
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)
{
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)
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 pm = store!.GetSupportedPaymentMethods(_btcPayNetworkProvider)
.OfType<LightningSupportedPaymentMethod>()
@@ -151,49 +151,49 @@ namespace BTCPayServer
});
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)
{
case PayoutState.AwaitingPayment:
{
var client =
_lightningLikePaymentHandler.CreateLightningClient(pm, network);
var payResult = await UILightningLikePayoutController.TrypayBolt(client,
claimResponse.PayoutData.GetBlob(_btcPayNetworkJsonSerializerSettings),
claimResponse.PayoutData, result, pmi, cancellationToken);
switch (payResult.Result)
{
case PayResult.Ok:
case PayResult.Unknown:
await _pullPaymentHostedService.MarkPaid(new MarkPayoutRequest()
{
PayoutId = claimResponse.PayoutData.Id,
State = claimResponse.PayoutData.State,
Proof = claimResponse.PayoutData.GetProofBlobJson()
});
var client =
_lightningLikePaymentHandler.CreateLightningClient(pm, network);
var payResult = await UILightningLikePayoutController.TrypayBolt(client,
claimResponse.PayoutData.GetBlob(_btcPayNetworkJsonSerializerSettings),
claimResponse.PayoutData, result, pmi, cancellationToken);
return Ok(new LNUrlStatusResponse
{
Status = "OK",
Reason = payResult.Message
});
case PayResult.CouldNotFindRoute:
case PayResult.Error:
default:
await _pullPaymentHostedService.Cancel(
new PullPaymentHostedService.CancelRequest(new string[]
switch (payResult.Result)
{
case PayResult.Ok:
case PayResult.Unknown:
await _pullPaymentHostedService.MarkPaid(new MarkPayoutRequest()
{
claimResponse.PayoutData.Id
}, null));
PayoutId = claimResponse.PayoutData.Id,
State = claimResponse.PayoutData.State,
Proof = claimResponse.PayoutData.GetProofBlobJson()
});
return Ok(new LNUrlStatusResponse
{
Status = "ERROR",
Reason = payResult.Message
});
return Ok(new LNUrlStatusResponse
{
Status = "OK",
Reason = payResult.Message
});
case PayResult.CouldNotFindRoute:
case PayResult.Error:
default:
await _pullPaymentHostedService.Cancel(
new PullPaymentHostedService.CancelRequest(new string[]
{
claimResponse.PayoutData.Id
}, null));
return Ok(new LNUrlStatusResponse
{
Status = "ERROR",
Reason = payResult.Message
});
}
}
}
case PayoutState.AwaitingApproval:
return Ok(new LNUrlStatusResponse
{
@@ -203,9 +203,9 @@ namespace BTCPayServer
});
case PayoutState.InProgress:
case PayoutState.Completed:
return Ok(new LNUrlStatusResponse {Status = "OK"});
return Ok(new LNUrlStatusResponse { Status = "OK" });
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);
@@ -274,7 +274,7 @@ namespace BTCPayServer
}
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
@@ -416,7 +416,7 @@ namespace BTCPayServer
if (i.Type != InvoiceType.TopUp)
{
min = i.GetPaymentMethod(pmi).Calculate().Due.ToDecimal(MoneyUnit.Satoshi);
max = item?.Price?.Type == ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Minimum ? null : min;
max = item?.Price?.Type == ViewPointOfSaleViewModel.Item.ItemPrice.ItemPriceType.Minimum ? null : min;
}
if (!string.IsNullOrEmpty(username))
@@ -433,10 +433,10 @@ namespace BTCPayServer
.Replace("{ItemDescription}", i.Metadata.ItemDesc ?? "", 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))
{
lnurlMetadata.Add(new[] {"text/identifier", lnAddress});
lnurlMetadata.Add(new[] { "text/identifier", lnAddress });
}
return Ok(new LNURLPayRequest
{
@@ -451,7 +451,7 @@ namespace BTCPayServer
Callback = new Uri(_linkGenerator.GetUriByAction(
action: nameof(GetLNURLForInvoice),
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("{OrderId}", i.Metadata.OrderId ?? "", StringComparison.OrdinalIgnoreCase);
lnurlMetadata.Add(new[] {"text/plain", description});
lnurlMetadata.Add(new[] { "text/plain", description });
if (!string.IsNullOrEmpty(paymentMethodDetails.ConsumedLightningAddress))
{
lnurlMetadata.Add(new[] {"text/identifier", paymentMethodDetails.ConsumedLightningAddress});
lnurlMetadata.Add(new[] { "text/identifier", paymentMethodDetails.ConsumedLightningAddress });
}
var metadata = JsonConvert.SerializeObject(lnurlMetadata);
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;
if ((i.ReceiptOptions?.Enabled ??blob.ReceiptOptions.Enabled ) is true)
if ((i.ReceiptOptions?.Enabled ?? blob.ReceiptOptions.Enabled) is true)
{
successAction =
new LNURLPayRequest.LNURLPayRequestCallbackResponse.LNURLPayRequestSuccessActionUrl
{
Tag = "url",
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));
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
});
}
@@ -625,7 +627,9 @@ namespace BTCPayServer
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
});
}
@@ -633,7 +637,8 @@ namespace BTCPayServer
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.",
Severity = StatusMessageModel.StatusSeverity.Error
});
return RedirectToAction(nameof(UIStoresController.GeneralSettings), "UIStores", new {storeId});
return RedirectToAction(nameof(UIStoresController.GeneralSettings), "UIStores", new { storeId });
}
var addresses =
await _lightningAddressService.Get(new LightningAddressQuery() {StoreIds = new[] {storeId}});
await _lightningAddressService.Get(new LightningAddressQuery() { StoreIds = new[] { storeId } });
return View(new EditLightningAddressVM
{
@@ -696,14 +701,16 @@ namespace BTCPayServer
if (await _lightningAddressService.Set(new LightningAddressData()
{
StoreDataId = storeId,
Username = vm.Add.Username,
Blob = new LightningAddressDataBlob()
{
StoreDataId = storeId,
Username = vm.Add.Username,
Blob = new LightningAddressDataBlob()
{
Max = vm.Add.Max, Min = vm.Add.Min, CurrencyCode = vm.Add.CurrencyCode
}.SerializeBlob()
}))
Max = vm.Add.Max,
Min = vm.Add.Min,
CurrencyCode = vm.Add.CurrencyCode
}.SerializeBlob()
}))
{
TempData.SetStatusMessageModel(new StatusMessageModel
{

View File

@@ -281,7 +281,7 @@ namespace BTCPayServer.Controllers
if (Policies.IsStorePolicy(requested.Key))
{
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;
break;
@@ -566,7 +566,7 @@ namespace BTCPayServer.Controllers
public bool Forbidden { get; set; }
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 amountDue = blob.Limit - totalPaid;
ViewPullPaymentModel vm = new (pp, DateTimeOffset.UtcNow)
ViewPullPaymentModel vm = new(pp, DateTimeOffset.UtcNow)
{
AmountFormatted = _currencyNameTable.FormatCurrency(blob.Limit, blob.Currency),
AmountCollected = totalPaid,
@@ -224,7 +224,7 @@ namespace BTCPayServer.Controllers
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
});

View File

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

View File

@@ -13,8 +13,8 @@ using BTCPayServer.Models.ServerViewModels;
using BTCPayServer.Services;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore;
using MimeKit;
namespace BTCPayServer.Controllers
@@ -261,7 +261,7 @@ namespace BTCPayServer.Controllers
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."));
}
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")]
@@ -275,9 +275,9 @@ namespace BTCPayServer.Controllers
TempData[WellKnownTempData.SuccessMessage] = $"User was the last enabled admin and could not be disabled.";
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));
}

View File

@@ -146,7 +146,8 @@ namespace BTCPayServer.Controllers
});
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 });
}
@@ -194,7 +195,9 @@ namespace BTCPayServer.Controllers
var vm = this.ParseListQuery(new PullPaymentsModel
{
Skip = skip, Count = count, ActiveState = pullPaymentState
Skip = skip,
Count = count,
ActiveState = pullPaymentState
});
switch (pullPaymentState)
@@ -257,7 +260,8 @@ namespace BTCPayServer.Controllers
await _pullPaymentService.Cancel(new HostedServices.PullPaymentHostedService.CancelRequest(pullPaymentId));
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 });
}
@@ -282,7 +286,8 @@ namespace BTCPayServer.Controllers
{
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = "No payout selected", Severity = StatusMessageModel.StatusSeverity.Error
Message = "No payout selected",
Severity = StatusMessageModel.StatusSeverity.Error
});
return RedirectToAction(nameof(Payouts),
new
@@ -307,122 +312,125 @@ namespace BTCPayServer.Controllers
{
case "approve-pay":
case "approve":
{
await using var ctx = this._dbContextFactory.CreateContext();
ctx.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var payouts =
await GetPayoutsForPaymentMethod(paymentMethodId, ctx, payoutIds, storeId, cancellationToken);
var failed = false;
for (int i = 0; i < payouts.Count; i++)
{
var payout = payouts[i];
if (payout.State != PayoutState.AwaitingApproval)
continue;
var rateResult = await _pullPaymentService.GetRate(payout, null, cancellationToken);
if (rateResult.BidAsk == null)
await using var ctx = this._dbContextFactory.CreateContext();
ctx.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var payouts =
await GetPayoutsForPaymentMethod(paymentMethodId, ctx, payoutIds, storeId, cancellationToken);
var failed = false;
for (int i = 0; i < payouts.Count; i++)
{
this.TempData.SetStatusMessageModel(new StatusMessageModel()
var payout = payouts[i];
if (payout.State != PayoutState.AwaitingApproval)
continue;
var rateResult = await _pullPaymentService.GetRate(payout, null, cancellationToken);
if (rateResult.BidAsk == null)
{
Message = $"Rate unavailable: {rateResult.EvaluatedRule}",
Severity = StatusMessageModel.StatusSeverity.Error
});
failed = true;
this.TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = $"Rate unavailable: {rateResult.EvaluatedRule}",
Severity = StatusMessageModel.StatusSeverity.Error
});
failed = true;
break;
}
var approveResult = await _pullPaymentService.Approve(
new HostedServices.PullPaymentHostedService.PayoutApproval()
{
PayoutId = payout.Id,
Revision = payout.GetBlob(_jsonSerializerSettings).Revision,
Rate = rateResult.BidAsk.Ask
});
if (approveResult.Result != PullPaymentHostedService.PayoutApproval.Result.Ok)
{
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = PullPaymentHostedService.PayoutApproval.GetErrorMessage(approveResult.Result),
Severity = StatusMessageModel.StatusSeverity.Error
});
failed = true;
break;
}
}
if (failed)
{
break;
}
var approveResult = await _pullPaymentService.Approve(
new HostedServices.PullPaymentHostedService.PayoutApproval()
{
PayoutId = payout.Id,
Revision = payout.GetBlob(_jsonSerializerSettings).Revision,
Rate = rateResult.BidAsk.Ask
});
if (approveResult.Result != PullPaymentHostedService.PayoutApproval.Result.Ok)
if (command == "approve-pay")
{
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = PullPaymentHostedService.PayoutApproval.GetErrorMessage(approveResult.Result),
Severity = StatusMessageModel.StatusSeverity.Error
});
failed = true;
break;
goto case "pay";
}
}
if (failed)
{
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = "Payouts approved",
Severity = StatusMessageModel.StatusSeverity.Success
});
break;
}
if (command == "approve-pay")
{
goto case "pay";
}
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = "Payouts approved", Severity = StatusMessageModel.StatusSeverity.Success
});
break;
}
case "pay":
{
if (handler is { })
return await handler?.InitiatePayment(paymentMethodId, payoutIds);
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = "Paying via this payment method is not supported",
Severity = StatusMessageModel.StatusSeverity.Error
});
break;
}
if (handler is { })
return await handler?.InitiatePayment(paymentMethodId, payoutIds);
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = "Paying via this payment method is not supported",
Severity = StatusMessageModel.StatusSeverity.Error
});
break;
}
case "mark-paid":
{
await using var ctx = this._dbContextFactory.CreateContext();
ctx.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var payouts =
await GetPayoutsForPaymentMethod(paymentMethodId, ctx, payoutIds, storeId, cancellationToken);
for (int i = 0; i < payouts.Count; i++)
{
var payout = payouts[i];
if (payout.State != PayoutState.AwaitingPayment)
continue;
var result =
await _pullPaymentService.MarkPaid(new MarkPayoutRequest() { PayoutId = payout.Id });
if (result != MarkPayoutRequest.PayoutPaidResult.Ok)
await using var ctx = this._dbContextFactory.CreateContext();
ctx.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var payouts =
await GetPayoutsForPaymentMethod(paymentMethodId, ctx, payoutIds, storeId, cancellationToken);
for (int i = 0; i < payouts.Count; i++)
{
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = MarkPayoutRequest.GetErrorMessage(result),
Severity = StatusMessageModel.StatusSeverity.Error
});
return RedirectToAction(nameof(Payouts),
new
{
storeId = storeId,
pullPaymentId = vm.PullPaymentId,
paymentMethodId = paymentMethodId.ToString()
});
}
}
var payout = payouts[i];
if (payout.State != PayoutState.AwaitingPayment)
continue;
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = "Payouts marked as paid", Severity = StatusMessageModel.StatusSeverity.Success
});
break;
}
var result =
await _pullPaymentService.MarkPaid(new MarkPayoutRequest() { PayoutId = payout.Id });
if (result != MarkPayoutRequest.PayoutPaidResult.Ok)
{
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = MarkPayoutRequest.GetErrorMessage(result),
Severity = StatusMessageModel.StatusSeverity.Error
});
return RedirectToAction(nameof(Payouts),
new
{
storeId = storeId,
pullPaymentId = vm.PullPaymentId,
paymentMethodId = paymentMethodId.ToString()
});
}
}
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = "Payouts marked as paid",
Severity = StatusMessageModel.StatusSeverity.Success
});
break;
}
case "cancel":
await _pullPaymentService.Cancel(
new PullPaymentHostedService.CancelRequest(payoutIds, new[] {storeId}));
new PullPaymentHostedService.CancelRequest(payoutIds, new[] { storeId }));
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = "Payouts archived", Severity = StatusMessageModel.StatusSeverity.Success
Message = "Payouts archived",
Severity = StatusMessageModel.StatusSeverity.Success
});
break;
}
@@ -480,7 +488,7 @@ namespace BTCPayServer.Controllers
vm.Payouts = new List<PayoutsModel.PayoutModel>();
await using var ctx = _dbContextFactory.CreateContext();
var payoutRequest =
ctx.Payouts.Where(p => p.StoreDataId == storeId && (p.PullPaymentDataId == null || !p.PullPaymentData.Archived));
ctx.Payouts.Where(p => p.StoreDataId == storeId && (p.PullPaymentDataId == null || !p.PullPaymentData.Archived));
if (pullPaymentId != null)
{
payoutRequest = payoutRequest.Where(p => p.PullPaymentDataId == vm.PullPaymentId);
@@ -494,7 +502,7 @@ namespace BTCPayServer.Controllers
}
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);
vm.PayoutStateCount = payoutRequest.GroupBy(data => data.State)
.Select(e => new { e.Key, Count = e.Count() })

View File

@@ -33,12 +33,13 @@ namespace BTCPayServer.Controllers
StoreId = CurrentStore.Id,
StoreName = CurrentStore.StoreName,
CryptoCode = cryptoCode,
Network = _NetworkProvider.DefaultNetwork,
Network = _NetworkProvider.DefaultNetwork,
IsSetUp = walletEnabled || lightningEnabled
};
// Widget data
if (!vm.WalletEnabled && !vm.LightningEnabled) return View(vm);
if (!vm.WalletEnabled && !vm.LightningEnabled)
return View(vm);
var userId = GetUserId();
var apps = await _appService.GetAllApps(userId, false, store.Id);
@@ -69,7 +70,7 @@ namespace BTCPayServer.Controllers
if (store == null)
return NotFound();
var vm = new StoreNumbersViewModel { Store = store, CryptoCode = cryptoCode };
var vm = new StoreNumbersViewModel { Store = store, CryptoCode = cryptoCode };
return ViewComponent("StoreNumbers", new { vm });
}
@@ -80,7 +81,7 @@ namespace BTCPayServer.Controllers
if (store == null)
return NotFound();
var vm = new StoreRecentTransactionsViewModel { Store = store, CryptoCode = cryptoCode };
var vm = new StoreRecentTransactionsViewModel { Store = store, CryptoCode = cryptoCode };
return ViewComponent("StoreRecentTransactions", new { vm });
}
@@ -91,7 +92,7 @@ namespace BTCPayServer.Controllers
if (store == null)
return NotFound();
var vm = new StoreRecentInvoicesViewModel { Store = store, CryptoCode = cryptoCode };
var vm = new StoreRecentInvoicesViewModel { Store = store, CryptoCode = cryptoCode };
return ViewComponent("StoreRecentInvoices", new { vm });
}
}

View File

@@ -31,7 +31,7 @@ namespace BTCPayServer.Controllers
TempData.SetStatusMessageModel(new StatusMessageModel
{
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 index = int.Parse(item, CultureInfo.InvariantCulture);
vm.Rules.RemoveAt(index);
} else if (command == "add")
}
else if (command == "add")
{
vm.Rules.Add(new StoreEmailRule());
@@ -71,7 +72,7 @@ namespace BTCPayServer.Controllers
Severity = StatusMessageModel.StatusSeverity.Success,
Message = "Store email rules saved"
});
return RedirectToAction("StoreEmails", new {storeId});
return RedirectToAction("StoreEmails", new { storeId });
}
public class StoreEmailRuleViewModel

View File

@@ -186,7 +186,7 @@ namespace BTCPayServer.Controllers
[HttpPost("{storeId}/users/{userId}/delete")]
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.";
else
{

View File

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

View File

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

View File

@@ -11,8 +11,10 @@ using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.BIP78.Sender;
using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
using BTCPayServer.Logging;
using BTCPayServer.ModelBinders;
using BTCPayServer.Models;
using BTCPayServer.Models.WalletViewModels;
@@ -23,24 +25,22 @@ using BTCPayServer.Services.Labels;
using BTCPayServer.Services.Rates;
using BTCPayServer.Services.Stores;
using BTCPayServer.Services.Wallets;
using BTCPayServer.Services.Wallets.Export;
using Dapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using NBitcoin;
using BTCPayServer.Client.Models;
using BTCPayServer.Logging;
using BTCPayServer.Services.Wallets.Export;
using Microsoft.AspNetCore.Http;
using NBXplorer;
using NBXplorer.Client;
using NBXplorer.DerivationStrategy;
using NBXplorer.Models;
using Newtonsoft.Json;
using StoreData = BTCPayServer.Data.StoreData;
using Microsoft.AspNetCore.Routing;
using Newtonsoft.Json.Linq;
using StoreData = BTCPayServer.Data.StoreData;
namespace BTCPayServer.Controllers
{
@@ -476,7 +476,8 @@ namespace BTCPayServer.Controllers
(int)network.NBitcoinNetwork.Consensus.GetExpectedBlocksFor(time));
return new WalletSendModel.FeeRateOption()
{
Target = time, FeeRate = result.SatoshiPerByte
Target = time,
FeeRate = result.SatoshiPerByte
};
}
catch (Exception)
@@ -737,57 +738,57 @@ namespace BTCPayServer.Controllers
Value = output.Amount,
PaymentMethodId = pmi,
StoreId = walletId.StoreId,
PreApprove = true,
PreApprove = true,
}).ToArray();
var someFailed = false;
string? message = null;
string? errorMessage = null;
string? errorMessage = null;
var result = new Dictionary<ClaimRequest, ClaimRequest.ClaimResult>();
foreach (ClaimRequest claimRequest in claims)
{
var response = await _pullPaymentHostedService.Claim(claimRequest);
result.Add(claimRequest, response.Result);
if (response.Result == ClaimRequest.ClaimResult.Ok)
{
if (message is null)
{
message = "Payouts scheduled:<br/>";
}
var response = await _pullPaymentHostedService.Claim(claimRequest);
result.Add(claimRequest, response.Result);
if (response.Result == ClaimRequest.ClaimResult.Ok)
{
if (message is null)
{
message = "Payouts scheduled:<br/>";
}
message += $"{claimRequest.Value} to {claimRequest.Destination.ToString()}<br/>";
message += $"{claimRequest.Value} to {claimRequest.Destination.ToString()}<br/>";
}
else
{
someFailed = true;
if (errorMessage is null)
{
errorMessage = "Payouts failed to be scheduled:<br/>";
}
}
else
{
someFailed = true;
if (errorMessage is null)
{
errorMessage = "Payouts failed to be scheduled:<br/>";
}
switch (response.Result)
{
case ClaimRequest.ClaimResult.Duplicate:
errorMessage += $"{claimRequest.Value} to {claimRequest.Destination.ToString() } - address reuse<br/>";
break;
case ClaimRequest.ClaimResult.AmountTooLow:
errorMessage += $"{claimRequest.Value} to {claimRequest.Destination.ToString() } - amount too low<br/>";
break;
}
}
switch (response.Result)
{
case ClaimRequest.ClaimResult.Duplicate:
errorMessage += $"{claimRequest.Value} to {claimRequest.Destination.ToString() } - address reuse<br/>";
break;
case ClaimRequest.ClaimResult.AmountTooLow:
errorMessage += $"{claimRequest.Value} to {claimRequest.Destination.ToString() } - amount too low<br/>";
break;
}
}
}
if (message is not null && errorMessage is not null)
{
message += $"<br/><br/>{errorMessage}";
}
else if(message is null && errorMessage is not null)
else if (message is null && errorMessage is not null)
{
message = errorMessage;
}
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Severity =someFailed? StatusMessageModel.StatusSeverity.Warning:
Severity = someFailed ? StatusMessageModel.StatusSeverity.Warning :
StatusMessageModel.StatusSeverity.Success,
Html = message
});
@@ -846,7 +847,7 @@ namespace BTCPayServer.Controllers
private void LoadFromBIP21(WalletSendModel vm, string bip21, BTCPayNetwork network)
{
vm.Outputs ??= new ();
vm.Outputs ??= new();
try
{
var uriBuilder = new NBitcoin.Payment.BitcoinUrlBuilder(bip21, network.NBitcoinNetwork);
@@ -878,9 +879,9 @@ namespace BTCPayServer.Controllers
try
{
vm.Outputs.Add(new WalletSendModel.TransactionOutput()
{
DestinationAddress = BitcoinAddress.Create(bip21, network.NBitcoinNetwork).ToString()
}
{
DestinationAddress = BitcoinAddress.Create(bip21, network.NBitcoinNetwork).ToString()
}
);
}
catch
@@ -1215,70 +1216,70 @@ namespace BTCPayServer.Controllers
switch (command)
{
case "cpfp":
{
selectedTransactions ??= Array.Empty<string>();
if (selectedTransactions.Length == 0)
{
TempData[WellKnownTempData.ErrorMessage] = $"No transaction selected";
selectedTransactions ??= Array.Empty<string>();
if (selectedTransactions.Length == 0)
{
TempData[WellKnownTempData.ErrorMessage] = $"No transaction selected";
return RedirectToAction(nameof(WalletTransactions), new { walletId });
}
var parameters = new MultiValueDictionary<string, string>();
parameters.Add("walletId", walletId.ToString());
int i = 0;
foreach (var tx in selectedTransactions)
{
parameters.Add($"transactionHashes[{i}]", tx);
i++;
}
var backUrl = Url.Action(nameof(WalletTransactions), new { walletId })!;
parameters.Add("returnUrl", backUrl);
parameters.Add("backUrl", backUrl);
return View("PostRedirect",
new PostRedirectViewModel
{
AspController = "UIWallets",
AspAction = nameof(WalletCPFP),
RouteParameters = { { "walletId", walletId.ToString() } },
FormParameters = parameters
});
}
case "prune":
{
var result = await ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode)
.PruneAsync(derivationScheme.AccountDerivation, new PruneRequest(), cancellationToken);
if (result.TotalPruned == 0)
{
TempData[WellKnownTempData.SuccessMessage] = "The wallet is already pruned";
}
else
{
TempData[WellKnownTempData.SuccessMessage] =
$"The wallet has been successfully pruned ({result.TotalPruned} transactions have been removed from the history)";
}
return RedirectToAction(nameof(WalletTransactions), new { walletId });
}
var parameters = new MultiValueDictionary<string, string>();
parameters.Add("walletId", walletId.ToString());
int i = 0;
foreach (var tx in selectedTransactions)
{
parameters.Add($"transactionHashes[{i}]", tx);
i++;
}
var backUrl = Url.Action(nameof(WalletTransactions), new { walletId })!;
parameters.Add("returnUrl", backUrl);
parameters.Add("backUrl", backUrl);
return View("PostRedirect",
new PostRedirectViewModel
{
AspController = "UIWallets",
AspAction = nameof(WalletCPFP),
RouteParameters = { { "walletId", walletId.ToString() } },
FormParameters = parameters
});
}
case "prune":
{
var result = await ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode)
.PruneAsync(derivationScheme.AccountDerivation, new PruneRequest(), cancellationToken);
if (result.TotalPruned == 0)
{
TempData[WellKnownTempData.SuccessMessage] = "The wallet is already pruned";
}
else
{
TempData[WellKnownTempData.SuccessMessage] =
$"The wallet has been successfully pruned ({result.TotalPruned} transactions have been removed from the history)";
}
return RedirectToAction(nameof(WalletTransactions), new { walletId });
}
case "clear" when User.IsInRole(Roles.ServerAdmin):
{
if (Version.TryParse(_dashboard.Get(walletId.CryptoCode)?.Status?.Version ?? "0.0.0.0",
out var v) &&
v < new Version(2, 2, 4))
{
TempData[WellKnownTempData.ErrorMessage] =
"This version of NBXplorer doesn't support this operation, please upgrade to 2.2.4 or above";
}
else
{
await ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode)
.WipeAsync(derivationScheme.AccountDerivation, cancellationToken);
TempData[WellKnownTempData.SuccessMessage] =
"The transactions have been wiped out, to restore your balance, rescan the wallet.";
}
if (Version.TryParse(_dashboard.Get(walletId.CryptoCode)?.Status?.Version ?? "0.0.0.0",
out var v) &&
v < new Version(2, 2, 4))
{
TempData[WellKnownTempData.ErrorMessage] =
"This version of NBXplorer doesn't support this operation, please upgrade to 2.2.4 or above";
}
else
{
await ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode)
.WipeAsync(derivationScheme.AccountDerivation, cancellationToken);
TempData[WellKnownTempData.SuccessMessage] =
"The transactions have been wiped out, to restore your balance, rescan the wallet.";
}
return RedirectToAction(nameof(WalletTransactions), new { walletId });
}
return RedirectToAction(nameof(WalletTransactions), new { walletId });
}
default:
return NotFound();
}
@@ -1294,7 +1295,7 @@ namespace BTCPayServer.Controllers
return NotFound();
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 walletTransactionsInfo = await walletTransactionsInfoAsync;
var export = new TransactionsExport(wallet, walletTransactionsInfo);

View File

@@ -275,7 +275,7 @@ public class BitcoinLikePayoutHandler : IPayoutHandler
&& data.State == PayoutState.AwaitingPayment)
.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 network = _btcPayNetworkProvider.GetNetwork<BTCPayNetwork>(paymentMethodId.CryptoCode);
List<string> bip21 = new List<string>();
@@ -362,7 +362,7 @@ public class BitcoinLikePayoutHandler : IPayoutHandler
}
}
if (proof.TransactionId is not null && !proof.Candidates.Contains(proof.TransactionId))
if (proof.TransactionId is not null && !proof.Candidates.Contains(proof.TransactionId))
{
proof.TransactionId = null;
}

View File

@@ -14,7 +14,7 @@ namespace BTCPayServer.Data
[JsonIgnore] public string LinkTemplate { get; set; }
public string ProofType { get; } = Type;
public const string Type = "PayoutTransactionOnChainBlob";
public const string Type = "PayoutTransactionOnChainBlob";
[JsonIgnore]
public string Link

View File

@@ -44,7 +44,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike
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;
}

View File

@@ -4,7 +4,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike
{
public string PaymentHash { get; set; }
public static string PayoutLightningBlobProofType = "PayoutLightningBlob";
public static string PayoutLightningBlobProofType = "PayoutLightningBlob";
public string ProofType { get; } = PayoutLightningBlobProofType;
public string Link { get; } = null;
public string Id => PaymentHash;

View File

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

View File

@@ -10,7 +10,7 @@ namespace BTCPayServer.Data
public static PullPaymentBlob GetBlob(this PullPaymentData data)
{
var result = JsonConvert.DeserializeObject<PullPaymentBlob>(Encoding.UTF8.GetString(data.Blob));
var result = JsonConvert.DeserializeObject<PullPaymentBlob>(Encoding.UTF8.GetString(data.Blob));
result!.SupportedPaymentMethods = result.SupportedPaymentMethods.Where(id => id is not null).ToArray();
return result;
}

View File

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

View File

@@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Mvc
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);
return urlHelper.GetUriByAction(

View File

@@ -15,7 +15,7 @@ public class FormDataService
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()

View File

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

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