mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 06:24:24 +01:00
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:
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
namespace BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
public interface IScopeProvider
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using NBitcoin;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,5 +5,4 @@ public class InsufficientFundsException : CustodianApiException
|
||||
public InsufficientFundsException(string message) : base(400, "insufficient-funds", message)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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}.")
|
||||
|
||||
@@ -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",...]
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using BTCPayServer.Client.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace BTCPayServer.Client;
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public class LockUserRequest
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using BTCPayServer.Client.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace BTCPayServer.Client.Models;
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class RateSource
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace BTCPayServer.Client.Models;
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class StoreRateResult
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace BTCPayServer.Data;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace BTCPayServer.Data.Data;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Net.Http;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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("")]
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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() })
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace BTCPayServer.Data
|
||||
return rules;
|
||||
}
|
||||
|
||||
public static JObject RecommendedExchanges = new ()
|
||||
public static JObject RecommendedExchanges = new()
|
||||
{
|
||||
{ "EUR", "kraken" },
|
||||
{ "USD", "kraken" },
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user