mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2026-02-12 09:44:28 +01:00
Merge branch 'master' into MonetaryUnit
This commit is contained in:
6
.circleci/can-build.sh
Executable file
6
.circleci/can-build.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "Checking if it is possible to build Bitcoin only..."
|
||||
cd ../BTCPayServer.Tests
|
||||
docker-compose -f "docker-compose.yml" build
|
||||
@@ -7,7 +7,7 @@ jobs:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
cd .circleci && ./run-tests.sh "Fast=Fast"
|
||||
cd .circleci && ./run-tests.sh "Fast=Fast" && ./can-build.sh
|
||||
selenium_tests:
|
||||
machine:
|
||||
enabled: true
|
||||
@@ -49,8 +49,10 @@ jobs:
|
||||
LATEST_TAG=${CIRCLE_TAG:1} #trim v from tag
|
||||
#
|
||||
sudo docker build --pull -t $DOCKERHUB_REPO:$LATEST_TAG-amd64 -f amd64.Dockerfile .
|
||||
sudo docker build --pull --build-arg CONFIGURATION_NAME=Altcoins-Release -t $DOCKERHUB_REPO:$LATEST_TAG-altcoins-amd64 -f amd64.Dockerfile .
|
||||
sudo docker login --username=$DOCKERHUB_USER --password=$DOCKERHUB_PASS
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-amd64
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-altcoins-amd64
|
||||
|
||||
arm32v7:
|
||||
machine:
|
||||
@@ -63,8 +65,10 @@ jobs:
|
||||
LATEST_TAG=${CIRCLE_TAG:1} #trim v from tag
|
||||
#
|
||||
sudo docker build --pull -t $DOCKERHUB_REPO:$LATEST_TAG-arm32v7 -f arm32v7.Dockerfile .
|
||||
sudo docker build --pull --build-arg CONFIGURATION_NAME=Altcoins-Release -t $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm32v7 -f arm32v7.Dockerfile .
|
||||
sudo docker login --username=$DOCKERHUB_USER --password=$DOCKERHUB_PASS
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-arm32v7
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm32v7
|
||||
|
||||
arm64v8:
|
||||
machine:
|
||||
@@ -77,8 +81,10 @@ jobs:
|
||||
LATEST_TAG=${CIRCLE_TAG:1} #trim v from tag
|
||||
#
|
||||
sudo docker build --pull -t $DOCKERHUB_REPO:$LATEST_TAG-arm64v8 -f arm64v8.Dockerfile .
|
||||
sudo docker build --build-arg CONFIGURATION_NAME=Altcoins-Release --pull -t $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm64v8 -f arm64v8.Dockerfile .
|
||||
sudo docker login --username=$DOCKERHUB_USER --password=$DOCKERHUB_PASS
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-arm64v8
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm64v8
|
||||
|
||||
multiarch:
|
||||
machine:
|
||||
@@ -99,6 +105,13 @@ jobs:
|
||||
sudo docker manifest annotate $DOCKERHUB_REPO:$LATEST_TAG $DOCKERHUB_REPO:$LATEST_TAG-arm32v7 --os linux --arch arm --variant v7
|
||||
sudo docker manifest annotate $DOCKERHUB_REPO:$LATEST_TAG $DOCKERHUB_REPO:$LATEST_TAG-arm64v8 --os linux --arch arm64 --variant v8
|
||||
sudo docker manifest push $DOCKERHUB_REPO:$LATEST_TAG -p
|
||||
|
||||
|
||||
sudo docker manifest create --amend $DOCKERHUB_REPO:$LATEST_TAG-altcoins $DOCKERHUB_REPO:$LATEST_TAG-altcoins-amd64 $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm32v7 $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm64v8
|
||||
sudo docker manifest annotate $DOCKERHUB_REPO:$LATEST_TAG-altcoins $DOCKERHUB_REPO:$LATEST_TAG-altcoins-amd64 --os linux --arch amd64
|
||||
sudo docker manifest annotate $DOCKERHUB_REPO:$LATEST_TAG-altcoins $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm32v7 --os linux --arch arm --variant v7
|
||||
sudo docker manifest annotate $DOCKERHUB_REPO:$LATEST_TAG-altcoins $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm64v8 --os linux --arch arm64 --variant v8
|
||||
sudo docker manifest push $DOCKERHUB_REPO:$LATEST_TAG-altcoins -p
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
@@ -3,7 +3,7 @@ set -e
|
||||
|
||||
cd ../BTCPayServer.Tests
|
||||
docker-compose -v
|
||||
docker-compose down --v
|
||||
docker-compose pull
|
||||
docker-compose build
|
||||
docker-compose run -e "TEST_FILTERS=$1" tests
|
||||
docker-compose -f "docker-compose.altcoins.yml" down --v
|
||||
docker-compose -f "docker-compose.altcoins.yml" pull
|
||||
docker-compose -f "docker-compose.altcoins.yml" build
|
||||
docker-compose -f "docker-compose.altcoins.yml" run -e "TEST_FILTERS=$1" tests
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -292,5 +292,9 @@ __pycache__/
|
||||
BTCPayServer/wwwroot/bundles/*
|
||||
!BTCPayServer/wwwroot/bundles/.gitignore
|
||||
|
||||
.vscode
|
||||
.vscode/*
|
||||
!.vscode/launch.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/extensions.json
|
||||
BTCPayServer/testpwd
|
||||
.DS_Store
|
||||
|
||||
3
.vscode/extensions.json
vendored
Normal file
3
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["ms-dotnettools.csharp"]
|
||||
}
|
||||
33
.vscode/launch.json
vendored
Normal file
33
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||
// Use hover for the description of the existing attributes
|
||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": ".NET Core Launch (web)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/BTCPayServer/bin/Debug/netcoreapp3.1/BTCPayServer.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/BTCPayServer",
|
||||
"stopAtEntry": false,
|
||||
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bListening on\\s+(https?://\\S+)"
|
||||
},
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/Views": "${workspaceFolder}/Views"
|
||||
},
|
||||
"logging": {
|
||||
"moduleLoad": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
42
.vscode/tasks.json
vendored
Normal file
42
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/BTCPayServer/BTCPayServer.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/BTCPayServer/BTCPayServer.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"${workspaceFolder}/BTCPayServer/BTCPayServer.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.JsonConverters
|
||||
{
|
||||
public class DecimalStringJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return (objectType == typeof(decimal) || objectType == typeof(decimal?));
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
JToken token = JToken.Load(reader);
|
||||
switch (token.Type)
|
||||
{
|
||||
case JTokenType.Float:
|
||||
case JTokenType.Integer:
|
||||
case JTokenType.String:
|
||||
return decimal.Parse(token.ToString(), CultureInfo.InvariantCulture);
|
||||
case JTokenType.Null when objectType == typeof(decimal?):
|
||||
return null;
|
||||
default:
|
||||
throw new JsonSerializationException("Unexpected token type: " +
|
||||
token.Type);
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
if (value != null)
|
||||
writer.WriteValue(((decimal)value).ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.JsonConverters
|
||||
{
|
||||
public class NumericStringJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return (objectType == typeof(decimal) ||
|
||||
objectType == typeof(decimal?) ||
|
||||
objectType == typeof(double) ||
|
||||
objectType == typeof(double?));
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
JToken token = JToken.Load(reader);
|
||||
switch (token.Type)
|
||||
{
|
||||
case JTokenType.Float:
|
||||
case JTokenType.Integer:
|
||||
case JTokenType.String:
|
||||
if (objectType == typeof(decimal) || objectType == typeof(decimal?) )
|
||||
return decimal.Parse(token.ToString(), CultureInfo.InvariantCulture);
|
||||
if (objectType == typeof(double) || objectType == typeof(double?))
|
||||
return double.Parse(token.ToString(), CultureInfo.InvariantCulture);
|
||||
|
||||
throw new JsonSerializationException("Unexpected object type: " + objectType);
|
||||
case JTokenType.Null when objectType == typeof(decimal?) || objectType == typeof(double?):
|
||||
return null;
|
||||
default:
|
||||
throw new JsonSerializationException("Unexpected token type: " +
|
||||
token.Type);
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case null:
|
||||
break;
|
||||
case decimal x:
|
||||
writer.WriteValue(x.ToString(CultureInfo.InvariantCulture));
|
||||
break;
|
||||
case double x:
|
||||
writer.WriteValue(x.ToString(CultureInfo.InvariantCulture));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace BTCPayServer.Client.Models
|
||||
public class CreatePayoutRequest
|
||||
{
|
||||
public string Destination { get; set; }
|
||||
[JsonConverter(typeof(DecimalStringJsonConverter))]
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal? Amount { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace BTCPayServer.Client.Models
|
||||
public class CreatePullPaymentRequest
|
||||
{
|
||||
public string Name { get; set; }
|
||||
[JsonProperty(ItemConverterType = typeof(DecimalStringJsonConverter))]
|
||||
[JsonProperty(ItemConverterType = typeof(NumericStringJsonConverter))]
|
||||
public decimal Amount { get; set; }
|
||||
public string Currency { get; set; }
|
||||
[JsonConverter(typeof(TimeSpanJsonConverter))]
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public class PaymentRequestBaseData
|
||||
{
|
||||
[JsonProperty(ItemConverterType = typeof(DecimalStringJsonConverter))]
|
||||
[JsonProperty(ItemConverterType = typeof(NumericStringJsonConverter))]
|
||||
public decimal Amount { get; set; }
|
||||
public string Currency { get; set; }
|
||||
public DateTime? ExpiryDate { get; set; }
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace BTCPayServer.Client.Models
|
||||
public string PullPaymentId { get; set; }
|
||||
public string Destination { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
[JsonConverter(typeof(DecimalStringJsonConverter))]
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Amount { get; set; }
|
||||
[JsonConverter(typeof(DecimalStringJsonConverter))]
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal? PaymentMethodAmount { get; set; }
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public PayoutState State { get; set; }
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace BTCPayServer.Client.Models
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Currency { get; set; }
|
||||
[JsonConverter(typeof(DecimalStringJsonConverter))]
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Amount { get; set; }
|
||||
[JsonConverter(typeof(TimeSpanJsonConverter))]
|
||||
public TimeSpan? Period { get; set; }
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using NBitcoin;
|
||||
using NBitcoin.Altcoins;
|
||||
using NBitcoin.Altcoins.Elements;
|
||||
@@ -34,3 +35,4 @@ namespace BTCPayServer
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer
|
||||
@@ -81,3 +82,4 @@ namespace BTCPayServer
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NBitcoin;
|
||||
@@ -58,3 +59,4 @@ namespace BTCPayServer
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
18
BTCPayServer.Common/Altcoins/Liquid/LiquidExtensions.cs
Normal file
18
BTCPayServer.Common/Altcoins/Liquid/LiquidExtensions.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
#if ALTCOINS
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public static class LiquidExtensions
|
||||
{
|
||||
public static IEnumerable<string> GetAllElementsSubChains(this BTCPayNetworkProvider networkProvider)
|
||||
{
|
||||
var elementsBased = networkProvider.GetAll().OfType<ElementsBTCPayNetwork>();
|
||||
var parentChains = elementsBased.Select(network => network.NetworkCryptoCode.ToUpperInvariant()).Distinct();
|
||||
return networkProvider.GetAll().OfType<ElementsBTCPayNetwork>()
|
||||
.Where(network => parentChains.Contains(network.NetworkCryptoCode)).Select(network => network.CryptoCode.ToUpperInvariant());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -20,7 +20,8 @@ namespace BTCPayServer
|
||||
"XMR_X = XMR_BTC * BTC_X",
|
||||
"XMR_BTC = kraken(XMR_BTC)"
|
||||
},
|
||||
CryptoImagePath = "/imlegacy/monero.svg"
|
||||
CryptoImagePath = "/imlegacy/monero.svg",
|
||||
UriScheme = "monero"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,6 @@ namespace BTCPayServer
|
||||
public class MoneroLikeSpecificBtcPayNetwork : BTCPayNetworkBase
|
||||
{
|
||||
public int MaxTrackedConfirmation = 10;
|
||||
public string UriScheme { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,4 +131,4 @@ namespace BTCPayServer
|
||||
return network as T;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="../Build/Version.csproj" Condition="Exists('../Build/Version.csproj')" />
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
|
||||
@@ -6,4 +6,7 @@
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="NBXplorer.Client" Version="3.0.16" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Altcoins)' != 'true'">
|
||||
<Compile Remove="Altcoins\**\*.cs"></Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="../Build/Version.csproj" Condition="Exists('../Build/Version.csproj')" />
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="../Build/Version.csproj" Condition="Exists('../Build/Version.csproj')" />
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
|
||||
|
||||
1040
BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs
Normal file
1040
BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -66,6 +66,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.NotNull(options.NetworkProvider.GetNetwork("USDT"));
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
[Trait("Altcoins", "Altcoins")]
|
||||
public async Task ElementsAssetsAreHandledCorrectly()
|
||||
@@ -1,11 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework Condition="'$(TargetFrameworkOverride)' != ''">$(TargetFrameworkOverride)</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<NoWarn>NU1701,CA1816,CA1308,CA1810,CA2208</NoWarn>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<UserSecretsId>AB0AC1DD-9D26-485B-9416-56A33F268117</UserSecretsId>
|
||||
<!--https://devblogs.microsoft.com/aspnet/testing-asp-net-core-mvc-web-apps-in-memory/-->
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
@@ -21,6 +17,9 @@
|
||||
<PropertyGroup Condition="'$(CI_TESTS)' == 'true'">
|
||||
<DefineConstants>$(DefineConstants);SHORT_TIMEOUT</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<DefineConstants>$(DefineConstants);ALTCOINS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
|
||||
@@ -33,11 +32,16 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(Altcoins)' != 'true'">
|
||||
<Compile Remove="AltcoinTests\**\*.cs"></Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update=".dockerignore">
|
||||
<DependentUpon>Dockerfile</DependentUpon>
|
||||
</None>
|
||||
<None Update="docker-compose.altcoins.yml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="docker-compose.yml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
||||
@@ -103,53 +103,6 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Altcoins", "Altcoins")]
|
||||
[Trait("Lightning", "Lightning")]
|
||||
public async Task CanUsePaymentMethodDropdown()
|
||||
{
|
||||
using (var s = SeleniumTester.Create())
|
||||
{
|
||||
s.Server.ActivateLTC();
|
||||
s.Server.ActivateLightning();
|
||||
await s.StartAsync();
|
||||
s.GoToRegister();
|
||||
s.RegisterNewUser();
|
||||
var store = s.CreateNewStore();
|
||||
s.AddDerivationScheme("BTC");
|
||||
|
||||
//check that there is no dropdown since only one payment method is set
|
||||
var invoiceId = s.CreateInvoice(store.storeName, 10, "USD", "a@g.com");
|
||||
s.GoToInvoiceCheckout(invoiceId);
|
||||
s.Driver.FindElement(By.ClassName("payment__currencies_noborder"));
|
||||
s.GoToHome();
|
||||
s.GoToStore(store.storeId);
|
||||
s.AddDerivationScheme("LTC");
|
||||
s.AddLightningNode("BTC", LightningConnectionType.CLightning);
|
||||
//there should be three now
|
||||
invoiceId = s.CreateInvoice(store.storeName, 10, "USD", "a@g.com");
|
||||
s.GoToInvoiceCheckout(invoiceId);
|
||||
var currencyDropdownButton = s.Driver.WaitForElement(By.ClassName("payment__currencies"));
|
||||
Assert.Contains("BTC", currencyDropdownButton.Text);
|
||||
currencyDropdownButton.Click();
|
||||
|
||||
var elements = s.Driver.FindElement(By.ClassName("vex-content")).FindElements(By.ClassName("vexmenuitem"));
|
||||
Assert.Equal(3, elements.Count);
|
||||
elements.Single(element => element.Text.Contains("LTC")).Click();
|
||||
currencyDropdownButton = s.Driver.WaitForElement(By.ClassName("payment__currencies"));
|
||||
Assert.Contains("LTC", currencyDropdownButton.Text);
|
||||
currencyDropdownButton.Click();
|
||||
|
||||
elements = s.Driver.FindElement(By.ClassName("vex-content")).FindElements(By.ClassName("vexmenuitem"));
|
||||
elements.Single(element => element.Text.Contains("Lightning")).Click();
|
||||
|
||||
currencyDropdownButton = s.Driver.WaitForElement(By.ClassName("payment__currencies"));
|
||||
Assert.Contains("Lightning", currencyDropdownButton.Text);
|
||||
|
||||
s.Driver.Quit();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Lightning", "Lightning")]
|
||||
public async Task CanUseLightningSatsFeature()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:3.1.101 AS builder
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:3.1.202 AS builder
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends chromium-driver \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
@@ -21,6 +21,9 @@ ENV SCREEN_HEIGHT 600 \
|
||||
SCREEN_WIDTH 1200
|
||||
|
||||
COPY . .
|
||||
RUN cd BTCPayServer.Tests && dotnet build /p:CI_TESTS=true /p:RazorCompileOnBuild=true
|
||||
|
||||
ARG CONFIGURATION_NAME=Release
|
||||
RUN cd BTCPayServer.Tests && dotnet build --configuration ${CONFIGURATION_NAME} /p:CI_TESTS=true /p:RazorCompileOnBuild=true
|
||||
WORKDIR /source/BTCPayServer.Tests
|
||||
ENV CONFIGURATION_NAME=${CONFIGURATION_NAME}
|
||||
ENTRYPOINT ["./docker-entrypoint.sh"]
|
||||
|
||||
@@ -734,17 +734,18 @@ namespace BTCPayServer.Tests
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void DecimalStringJsonConverterTests()
|
||||
public void NumericJsonConverterTests()
|
||||
{
|
||||
JsonReader Get(string val)
|
||||
{
|
||||
return new JsonTextReader(new StringReader(val));
|
||||
}
|
||||
|
||||
var jsonConverter = new DecimalStringJsonConverter();
|
||||
var jsonConverter = new NumericStringJsonConverter();
|
||||
Assert.True(jsonConverter.CanConvert(typeof(decimal)));
|
||||
Assert.True(jsonConverter.CanConvert(typeof(decimal?)));
|
||||
Assert.False(jsonConverter.CanConvert(typeof(double)));
|
||||
Assert.True(jsonConverter.CanConvert(typeof(double)));
|
||||
Assert.True(jsonConverter.CanConvert(typeof(double?)));
|
||||
Assert.False(jsonConverter.CanConvert(typeof(float)));
|
||||
Assert.False(jsonConverter.CanConvert(typeof(int)));
|
||||
Assert.False(jsonConverter.CanConvert(typeof(string)));
|
||||
@@ -755,12 +756,20 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(1m, jsonConverter.ReadJson(Get(numberJson), typeof(decimal), null, null));
|
||||
Assert.Equal(1.2m, jsonConverter.ReadJson(Get(numberDecimalJson), typeof(decimal), null, null));
|
||||
Assert.Null(jsonConverter.ReadJson(Get("null"), typeof(decimal?), null, null));
|
||||
Assert.Equal((double)1.0, jsonConverter.ReadJson(Get(numberJson), typeof(double), null, null));
|
||||
Assert.Equal((double)1.2, jsonConverter.ReadJson(Get(numberDecimalJson), typeof(double), null, null));
|
||||
Assert.Null(jsonConverter.ReadJson(Get("null"), typeof(double?), null, null));
|
||||
Assert.Throws<JsonSerializationException>(() =>
|
||||
{
|
||||
jsonConverter.ReadJson(Get("null"), typeof(decimal), null, null);
|
||||
});Assert.Throws<JsonSerializationException>(() =>
|
||||
{
|
||||
jsonConverter.ReadJson(Get("null"), typeof(double), null, null);
|
||||
});
|
||||
Assert.Equal(1.2m, jsonConverter.ReadJson(Get(stringJson), typeof(decimal), null, null));
|
||||
Assert.Equal(1.2m, jsonConverter.ReadJson(Get(stringJson), typeof(decimal?), null, null));
|
||||
Assert.Equal(1.2, jsonConverter.ReadJson(Get(stringJson), typeof(double), null, null));
|
||||
Assert.Equal(1.2, jsonConverter.ReadJson(Get(stringJson), typeof(double?), null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,74 +1,52 @@
|
||||
# How to be started for development
|
||||
# Tooling
|
||||
|
||||
BTCPay Server tests depend on having a proper environment running with Postgres, Bitcoind, NBxplorer configured.
|
||||
You can however use the `docker-compose.yml` of this folder to get it running.
|
||||
|
||||
In addition, when you run a debug session of BTCPay (Hitting F5 on Visual Studio Code or Visual Studio 2017), it will run the launch profile called `Docker-Regtest`. This launch profile depends on this `docker-compose` running.
|
||||
|
||||
This is running a bitcoind instance on regtest, a private bitcoin blockchain for testing on which you can generate blocks yourself.
|
||||
|
||||
```
|
||||
docker-compose up dev
|
||||
```
|
||||
|
||||
You can run the tests while it is running through your favorite IDE, or with
|
||||
|
||||
```
|
||||
dotnet test
|
||||
```
|
||||
|
||||
Once you want to stop
|
||||
|
||||
```
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
If you want to stop, and remove all existing data
|
||||
|
||||
```
|
||||
docker-compose down --v
|
||||
```
|
||||
|
||||
You can run tests on `MySql` database instead of `Postgres` by setting environnement variable `TESTS_DB` equals to `MySql`.
|
||||
This README describe some useful tooling that you may need during development and testing.
|
||||
To learn how to get started with your local development environment, read [our documentation](https://docs.btcpayserver.org/LocalDevelopment/).
|
||||
|
||||
## How to manually test payments
|
||||
|
||||
### Using the test bitcoin-cli
|
||||
|
||||
You can call bitcoin-cli inside the container with `docker exec`, for example, if you want to send `0.23111090` to `mohu16LH66ptoWGEL1GtP6KHTBJYXMWhEf`:
|
||||
```
|
||||
You can call bitcoin-cli inside the container with `docker exec`.
|
||||
For example, if you want to send `0.23111090` to `mohu16LH66ptoWGEL1GtP6KHTBJYXMWhEf`:
|
||||
|
||||
```sh
|
||||
./docker-bitcoin-cli.sh sendtoaddress "mohu16LH66ptoWGEL1GtP6KHTBJYXMWhEf" 0.23111090
|
||||
```
|
||||
|
||||
If you are using Powershell:
|
||||
|
||||
```powershell
|
||||
.\docker-bitcoin-cli.ps1 sendtoaddress "mohu16LH66ptoWGEL1GtP6KHTBJYXMWhEf" 0.23111090
|
||||
```
|
||||
|
||||
You can also generate blocks:
|
||||
|
||||
```powershell
|
||||
.\docker-bitcoin-generate.ps1 3
|
||||
```
|
||||
|
||||
### Using the test litecoin-cli
|
||||
|
||||
Same as bitcoin-cli, but with `.\docker-litecoin-cli.ps1` and `.\docker-litecoin-cli.sh` instead.
|
||||
Same as bitcoin-cli, but with `.\docker-litecoin-cli.ps1` and `.\docker-litecoin-cli.sh` instead.
|
||||
|
||||
### Using the test lightning-cli
|
||||
|
||||
If you are using Linux:
|
||||
```
|
||||
|
||||
```sh
|
||||
./docker-customer-lightning-cli.sh pay lnbcrt100u1pd2e6uspp5ajnadvhazjrz55twd5k6yeg9u87wpw0q2fdr7g960yl5asv5fmnqdq9d3hkccqpxmedyrk0ehw5ueqx5e0r4qrrv74cewddfcvsxaawqz7634cmjj39sqwy5tvhz0hasktkk6t9pqfdh3edmf3z09zst5y7khv3rvxh8ctqqw6mwhh
|
||||
```
|
||||
|
||||
If you are using Powershell:
|
||||
```
|
||||
|
||||
```powershell
|
||||
.\docker-customer-lightning-cli.ps1 pay lnbcrt100u1pd2e6uspp5ajnadvhazjrz55twd5k6yeg9u87wpw0q2fdr7g960yl5asv5fmnqdq9d3hkccqpxmedyrk0ehw5ueqx5e0r4qrrv74cewddfcvsxaawqz7634cmjj39sqwy5tvhz0hasktkk6t9pqfdh3edmf3z09zst5y7khv3rvxh8ctqqw6mwhh
|
||||
```
|
||||
|
||||
If you get this message:
|
||||
|
||||
```
|
||||
```json
|
||||
{ "code" : 205, "message" : "Could not find a route", "data" : { "getroute_tries" : 1, "sendpay_tries" : 0 } }
|
||||
```
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ using BTCPayServer.Views.Wallets;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NBitcoin;
|
||||
using NBitcoin.Payment;
|
||||
using NBitpayClient;
|
||||
using OpenQA.Selenium;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
@@ -686,80 +687,6 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Selenium", "Selenium")]
|
||||
[Trait("Altcoins", "Altcoins")]
|
||||
public async Task CanCreateRefunds()
|
||||
{
|
||||
using (var s = SeleniumTester.Create())
|
||||
{
|
||||
s.Server.ActivateLTC();
|
||||
await s.StartAsync();
|
||||
var user = s.Server.NewAccount();
|
||||
await user.GrantAccessAsync();
|
||||
s.GoToLogin();
|
||||
s.Login(user.RegisterDetails.Email, user.RegisterDetails.Password);
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
await s.Server.ExplorerNode.GenerateAsync(1);
|
||||
|
||||
foreach (var multiCurrency in new[] { false, true })
|
||||
{
|
||||
if (multiCurrency)
|
||||
user.RegisterDerivationScheme("LTC");
|
||||
foreach (var rateSelection in new[] { "FiatText", "CurrentRateText", "RateThenText" })
|
||||
await CanCreateRefundsCore(s, user, multiCurrency, rateSelection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task CanCreateRefundsCore(SeleniumTester s, TestAccount user, bool multiCurrency, string rateSelection)
|
||||
{
|
||||
s.GoToHome();
|
||||
s.Server.PayTester.ChangeRate("BTC_USD", new Rating.BidAsk(5000.0m, 5100.0m));
|
||||
var invoice = await user.BitPay.CreateInvoiceAsync(new NBitpayClient.Invoice()
|
||||
{
|
||||
Currency = "USD",
|
||||
Price = 5000.0m
|
||||
});
|
||||
var info = invoice.CryptoInfo.First(o => o.CryptoCode == "BTC");
|
||||
var totalDue = decimal.Parse(info.TotalDue, CultureInfo.InvariantCulture);
|
||||
var paid = totalDue + 0.1m;
|
||||
await s.Server.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(info.Address, Network.RegTest), Money.Coins(paid));
|
||||
await s.Server.ExplorerNode.GenerateAsync(1);
|
||||
await TestUtils.EventuallyAsync(async () =>
|
||||
{
|
||||
invoice = await user.BitPay.GetInvoiceAsync(invoice.Id);
|
||||
Assert.Equal("confirmed", invoice.Status);
|
||||
});
|
||||
|
||||
// BTC crash by 50%
|
||||
s.Server.PayTester.ChangeRate("BTC_USD", new Rating.BidAsk(5000.0m / 2.0m, 5100.0m / 2.0m));
|
||||
s.GoToInvoice(invoice.Id);
|
||||
s.Driver.FindElement(By.Id("refundlink")).Click();
|
||||
if (multiCurrency)
|
||||
{
|
||||
s.Driver.FindElement(By.Id("SelectedPaymentMethod")).SendKeys("BTC" + Keys.Enter);
|
||||
s.Driver.FindElement(By.Id("ok")).Click();
|
||||
}
|
||||
Assert.Contains("$5,500.00", s.Driver.PageSource); // Should propose reimburse in fiat
|
||||
Assert.Contains("1.10000000 ₿", s.Driver.PageSource); // Should propose reimburse in BTC at the rate of before
|
||||
Assert.Contains("2.20000000 ₿", s.Driver.PageSource); // Should propose reimburse in BTC at the current rate
|
||||
s.Driver.FindElement(By.Id(rateSelection)).Click();
|
||||
s.Driver.FindElement(By.Id("ok")).Click();
|
||||
Assert.Contains("pull-payments", s.Driver.Url);
|
||||
if (rateSelection == "FiatText")
|
||||
Assert.Contains("$5,500.00", s.Driver.PageSource);
|
||||
if (rateSelection == "CurrentRateText")
|
||||
Assert.Contains("2.20000000 ₿", s.Driver.PageSource);
|
||||
if (rateSelection == "RateThenText")
|
||||
Assert.Contains("1.10000000 ₿", s.Driver.PageSource);
|
||||
s.GoToHome();
|
||||
s.GoToInvoices();
|
||||
s.GoToInvoice(invoice.Id);
|
||||
s.Driver.FindElement(By.Id("refundlink")).Click();
|
||||
Assert.Contains("pull-payments", s.Driver.Url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Selenium", "Selenium")]
|
||||
public async Task CanUsePullPaymentsViaUI()
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace BTCPayServer.Tests
|
||||
PayTester.SSHConnection = GetEnvironment("TESTS_SSHCONNECTION", "root@127.0.0.1:21622");
|
||||
PayTester.SocksEndpoint = GetEnvironment("TESTS_SOCKSENDPOINT", "localhost:9050");
|
||||
}
|
||||
|
||||
#if ALTCOINS
|
||||
public void ActivateLTC()
|
||||
{
|
||||
LTCExplorerNode = new RPCClient(RPCCredentialString.Parse(GetEnvironment("TESTS_LTCRPCCONNECTION", "server=http://127.0.0.1:43783;ceiwHEbqWI83:DwubwWsoo3")), NetworkProvider.GetNetwork<BTCPayNetwork>("LTC").NBitcoinNetwork);
|
||||
@@ -78,7 +78,7 @@ namespace BTCPayServer.Tests
|
||||
PayTester.Chains.Add("LBTC");
|
||||
PayTester.LBTCNBXplorerUri = LBTCExplorerClient.Address;
|
||||
}
|
||||
|
||||
#endif
|
||||
public void ActivateLightning()
|
||||
{
|
||||
var btc = NetworkProvider.GetNetwork<BTCPayNetwork>("BTC").NBitcoinNetwork;
|
||||
@@ -170,20 +170,21 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
#if ALTCOINS
|
||||
public RPCClient LTCExplorerNode
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public RPCClient LBTCExplorerNode { get; set; }
|
||||
public ExplorerClient LTCExplorerClient { get; set; }
|
||||
public ExplorerClient LBTCExplorerClient { get; set; }
|
||||
#endif
|
||||
|
||||
public ExplorerClient ExplorerClient
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public ExplorerClient LTCExplorerClient { get; set; }
|
||||
public ExplorerClient LBTCExplorerClient { get; set; }
|
||||
|
||||
readonly HttpClient _Http = new HttpClient();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
419
BTCPayServer.Tests/docker-compose.altcoins.yml
Normal file
419
BTCPayServer.Tests/docker-compose.altcoins.yml
Normal file
@@ -0,0 +1,419 @@
|
||||
version: "3"
|
||||
|
||||
# Run `docker-compose up dev` for bootstrapping your development environment
|
||||
# Doing so will expose NBXplorer, Bitcoind RPC and postgres port to the host so that tests can Run,
|
||||
# The Visual Studio launch setting `Docker-regtest` is configured to use this environment.
|
||||
services:
|
||||
|
||||
tests:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: BTCPayServer.Tests/Dockerfile
|
||||
args:
|
||||
CONFIGURATION_NAME: Altcoins-Release
|
||||
environment:
|
||||
TESTS_BTCRPCCONNECTION: server=http://bitcoind:43782;ceiwHEbqWI83:DwubwWsoo3
|
||||
TESTS_LTCRPCCONNECTION: server=http://litecoind:43782;ceiwHEbqWI83:DwubwWsoo3
|
||||
TESTS_BTCNBXPLORERURL: http://nbxplorer:32838/
|
||||
TESTS_LTCNBXPLORERURL: http://nbxplorer:32838/
|
||||
TESTS_DB: "Postgres"
|
||||
TESTS_POSTGRES: User ID=postgres;Host=postgres;Port=5432;Database=btcpayserver
|
||||
TESTS_HOSTNAME: tests
|
||||
TESTS_RUN_EXTERNAL_INTEGRATION: ${TESTS_RUN_EXTERNAL_INTEGRATION:-false}
|
||||
TESTS_AzureBlobStorageConnectionString: ${TESTS_AzureBlobStorageConnectionString:-none}
|
||||
TEST_MERCHANTLIGHTNINGD: "type=clightning;server=unix://etc/merchant_lightningd_datadir/lightning-rpc"
|
||||
TEST_CUSTOMERLIGHTNINGD: "type=clightning;server=unix://etc/customer_lightningd_datadir/lightning-rpc"
|
||||
TEST_MERCHANTCHARGE: "type=charge;server=http://lightning-charged:9112/;api-token=foiewnccewuify"
|
||||
TEST_MERCHANTLND: "https://lnd:lnd@merchant_lnd:8080/"
|
||||
TESTS_INCONTAINER: "true"
|
||||
TESTS_SSHCONNECTION: "root@sshd:22"
|
||||
TESTS_SSHPASSWORD: ""
|
||||
TESTS_SSHKEYFILE: ""
|
||||
TESTS_SOCKSENDPOINT: "tor:9050"
|
||||
expose:
|
||||
- "80"
|
||||
links:
|
||||
- dev
|
||||
extra_hosts:
|
||||
- "tests:127.0.0.1"
|
||||
volumes:
|
||||
- "sshd_datadir:/root/.ssh"
|
||||
- "customer_lightningd_datadir:/etc/customer_lightningd_datadir"
|
||||
- "merchant_lightningd_datadir:/etc/merchant_lightningd_datadir"
|
||||
|
||||
# The dev container is not actually used, it is just handy to run `docker-compose up dev` to start all services
|
||||
dev:
|
||||
image: alpine:3.7
|
||||
command: [ "/bin/sh", "-c", "trap : TERM INT; while :; do echo Ready to code and debug like a rockstar!!!; sleep 2073600; done & wait" ]
|
||||
links:
|
||||
- nbxplorer
|
||||
- postgres
|
||||
- customer_lightningd
|
||||
- merchant_lightningd
|
||||
- lightning-charged
|
||||
- customer_lnd
|
||||
- merchant_lnd
|
||||
- sshd
|
||||
- tor
|
||||
- monero_wallet
|
||||
|
||||
sshd:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: sshd.Dockerfile
|
||||
ports:
|
||||
- "21622:22"
|
||||
expose:
|
||||
- 22
|
||||
volumes:
|
||||
- "sshd_datadir:/root/.ssh"
|
||||
|
||||
devlnd:
|
||||
image: btcpayserver/bitcoin:0.19.0.1
|
||||
environment:
|
||||
BITCOIN_NETWORK: regtest
|
||||
BITCOIN_EXTRA_ARGS: |
|
||||
deprecatedrpc=signrawtransaction
|
||||
connect=bitcoind:39388
|
||||
links:
|
||||
- nbxplorer
|
||||
- postgres
|
||||
- customer_lnd
|
||||
- merchant_lnd
|
||||
nbxplorer:
|
||||
image: nicolasdorier/nbxplorer:2.1.35
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "32838:32838"
|
||||
expose:
|
||||
- "32838"
|
||||
environment:
|
||||
NBXPLORER_NETWORK: regtest
|
||||
NBXPLORER_CHAINS: "btc,ltc,lbtc"
|
||||
NBXPLORER_BTCRPCURL: http://bitcoind:43782/
|
||||
NBXPLORER_BTCNODEENDPOINT: bitcoind:39388
|
||||
NBXPLORER_BTCRPCUSER: ceiwHEbqWI83
|
||||
NBXPLORER_BTCRPCPASSWORD: DwubwWsoo3
|
||||
NBXPLORER_LTCRPCURL: http://litecoind:43782/
|
||||
NBXPLORER_LTCNODEENDPOINT: litecoind:39388
|
||||
NBXPLORER_LTCRPCUSER: ceiwHEbqWI83
|
||||
NBXPLORER_LTCRPCPASSWORD: DwubwWsoo3
|
||||
NBXPLORER_LBTCRPCURL: "http://elementsd-liquid:19332/"
|
||||
NBXPLORER_LBTCNODEENDPOINT: "elementsd-liquid:19444"
|
||||
NBXPLORER_LBTCRPCUSER: "liquid"
|
||||
NBXPLORER_LBTCRPCPASSWORD: "liquid"
|
||||
NBXPLORER_BIND: 0.0.0.0:32838
|
||||
NBXPLORER_MINGAPSIZE: 5
|
||||
NBXPLORER_MAXGAPSIZE: 10
|
||||
NBXPLORER_VERBOSE: 1
|
||||
NBXPLORER_NOAUTH: 1
|
||||
links:
|
||||
- bitcoind
|
||||
- litecoind
|
||||
- elementsd-liquid
|
||||
|
||||
|
||||
bitcoind:
|
||||
restart: unless-stopped
|
||||
image: btcpayserver/bitcoin:0.19.0.1
|
||||
environment:
|
||||
BITCOIN_NETWORK: regtest
|
||||
BITCOIN_EXTRA_ARGS: |-
|
||||
rpcuser=ceiwHEbqWI83
|
||||
rpcpassword=DwubwWsoo3
|
||||
rpcport=43782
|
||||
rpcbind=0.0.0.0:43782
|
||||
port=39388
|
||||
whitelist=0.0.0.0/0
|
||||
zmqpubrawblock=tcp://0.0.0.0:28332
|
||||
zmqpubrawtx=tcp://0.0.0.0:28333
|
||||
deprecatedrpc=signrawtransaction
|
||||
ports:
|
||||
- "43782:43782"
|
||||
- "39388:39388"
|
||||
expose:
|
||||
- "43782" # RPC
|
||||
- "39388" # P2P
|
||||
- "28332" # ZMQ
|
||||
- "28333" # ZMQ
|
||||
volumes:
|
||||
- "bitcoin_datadir:/data"
|
||||
|
||||
customer_lightningd:
|
||||
image: btcpayserver/lightning:v0.8.2-dev
|
||||
stop_signal: SIGKILL
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
EXPOSE_TCP: "true"
|
||||
LIGHTNINGD_CHAIN: "btc"
|
||||
LIGHTNINGD_NETWORK: "regtest"
|
||||
LIGHTNINGD_OPT: |
|
||||
bitcoin-datadir=/etc/bitcoin
|
||||
bitcoin-rpcconnect=bitcoind
|
||||
announce-addr=customer_lightningd
|
||||
log-level=debug
|
||||
funding-confirms=1
|
||||
dev-fast-gossip
|
||||
dev-bitcoind-poll=1
|
||||
ports:
|
||||
- "30992:9835" # api port
|
||||
expose:
|
||||
- "9735" # server port
|
||||
- "9835" # api port
|
||||
volumes:
|
||||
- "bitcoin_datadir:/etc/bitcoin"
|
||||
- "customer_lightningd_datadir:/root/.lightning"
|
||||
links:
|
||||
- bitcoind
|
||||
|
||||
lightning-charged:
|
||||
image: shesek/lightning-charge:0.4.19-standalone
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
NETWORK: regtest
|
||||
API_TOKEN: foiewnccewuify
|
||||
BITCOIND_RPCCONNECT: bitcoind
|
||||
volumes:
|
||||
- "bitcoin_datadir:/etc/bitcoin"
|
||||
- "lightning_charge_datadir:/data"
|
||||
- "merchant_lightningd_datadir:/etc/lightning"
|
||||
expose:
|
||||
- "9112" # Charge
|
||||
- "9735" # Lightning
|
||||
ports:
|
||||
- "54938:9112" # Charge
|
||||
links:
|
||||
- bitcoind
|
||||
- merchant_lightningd
|
||||
|
||||
merchant_lightningd:
|
||||
image: btcpayserver/lightning:v0.8.2-dev
|
||||
stop_signal: SIGKILL
|
||||
environment:
|
||||
EXPOSE_TCP: "true"
|
||||
LIGHTNINGD_CHAIN: "btc"
|
||||
LIGHTNINGD_NETWORK: "regtest"
|
||||
LIGHTNINGD_OPT: |
|
||||
bitcoin-datadir=/etc/bitcoin
|
||||
bitcoin-rpcconnect=bitcoind
|
||||
announce-addr=merchant_lightningd
|
||||
funding-confirms=1
|
||||
log-level=debug
|
||||
dev-fast-gossip
|
||||
dev-bitcoind-poll=1
|
||||
ports:
|
||||
- "30993:9835" # api port
|
||||
expose:
|
||||
- "9735" # server port
|
||||
- "9835" # api port
|
||||
volumes:
|
||||
- "bitcoin_datadir:/etc/bitcoin"
|
||||
- "merchant_lightningd_datadir:/root/.lightning"
|
||||
links:
|
||||
- bitcoind
|
||||
|
||||
litecoind:
|
||||
restart: unless-stopped
|
||||
image: nicolasdorier/docker-litecoin:0.16.3
|
||||
environment:
|
||||
BITCOIN_EXTRA_ARGS: |-
|
||||
rpcuser=ceiwHEbqWI83
|
||||
rpcpassword=DwubwWsoo3
|
||||
regtest=1
|
||||
rpcport=43782
|
||||
port=39388
|
||||
whitelist=0.0.0.0/0
|
||||
ports:
|
||||
- "43783:43782"
|
||||
expose:
|
||||
- "43782" # RPC
|
||||
- "39388" # P2P
|
||||
|
||||
elementsd-liquid:
|
||||
restart: always
|
||||
container_name: btcpayserver_elementsd_liquid
|
||||
image: btcpayserver/elements:0.18.1.7
|
||||
environment:
|
||||
ELEMENTS_CHAIN: elementsregtest
|
||||
ELEMENTS_EXTRA_ARGS: |
|
||||
mainchainrpcport=43782
|
||||
mainchainrpchost=bitcoind
|
||||
mainchainrpcuser=liquid
|
||||
mainchainrpcpassword=liquid
|
||||
rpcport=19332
|
||||
rpcbind=0.0.0.0:19332
|
||||
rpcauth=liquid:c8bf1a8961d97f224cb21224aaa8235d$$402f4a8907683d057b8c58a42940b6e54d1638322a42986ae28ebb844e603ae6
|
||||
port=19444
|
||||
whitelist=0.0.0.0/0
|
||||
validatepegin=0
|
||||
initialfreecoins=210000000000000
|
||||
con_dyna_deploy_start=99999999999
|
||||
expose:
|
||||
- "19332"
|
||||
- "19444"
|
||||
ports:
|
||||
- "19332:19332"
|
||||
- "19444:19444"
|
||||
volumes:
|
||||
- "elementsd_liquid_datadir:/data"
|
||||
|
||||
postgres:
|
||||
image: postgres:9.6.5
|
||||
ports:
|
||||
- "39372:5432"
|
||||
expose:
|
||||
- "5432"
|
||||
|
||||
merchant_lnd:
|
||||
image: btcpayserver/lnd:v0.10.2-beta
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
LND_CHAIN: "btc"
|
||||
LND_ENVIRONMENT: "regtest"
|
||||
LND_EXPLORERURL: "http://nbxplorer:32838/"
|
||||
LND_EXTRA_ARGS: |
|
||||
restlisten=0.0.0.0:8080
|
||||
rpclisten=127.0.0.1:10008
|
||||
rpclisten=0.0.0.0:10009
|
||||
bitcoin.node=bitcoind
|
||||
bitcoind.rpchost=bitcoind:43782
|
||||
bitcoind.zmqpubrawblock=tcp://bitcoind:28332
|
||||
bitcoind.zmqpubrawtx=tcp://bitcoind:28333
|
||||
externalip=merchant_lnd:9735
|
||||
bitcoin.defaultchanconfs=1
|
||||
no-macaroons=1
|
||||
debuglevel=debug
|
||||
trickledelay=1000
|
||||
ports:
|
||||
- "35531:8080"
|
||||
expose:
|
||||
- "9735"
|
||||
volumes:
|
||||
- "merchant_lnd_datadir:/data"
|
||||
- "bitcoin_datadir:/deps/.bitcoin"
|
||||
links:
|
||||
- bitcoind
|
||||
|
||||
customer_lnd:
|
||||
image: btcpayserver/lnd:v0.10.2-beta
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
LND_CHAIN: "btc"
|
||||
LND_ENVIRONMENT: "regtest"
|
||||
LND_EXPLORERURL: "http://nbxplorer:32838/"
|
||||
LND_EXTRA_ARGS: |
|
||||
restlisten=0.0.0.0:8080
|
||||
rpclisten=127.0.0.1:10008
|
||||
rpclisten=0.0.0.0:10009
|
||||
bitcoin.node=bitcoind
|
||||
bitcoind.rpchost=bitcoind:43782
|
||||
bitcoind.zmqpubrawblock=tcp://bitcoind:28332
|
||||
bitcoind.zmqpubrawtx=tcp://bitcoind:28333
|
||||
externalip=customer_lnd:10009
|
||||
bitcoin.defaultchanconfs=1
|
||||
no-macaroons=1
|
||||
debuglevel=debug
|
||||
trickledelay=1000
|
||||
ports:
|
||||
- "35532:8080"
|
||||
expose:
|
||||
- "8080"
|
||||
- "10009"
|
||||
volumes:
|
||||
- "customer_lnd_datadir:/root/.lnd"
|
||||
- "bitcoin_datadir:/deps/.bitcoin"
|
||||
links:
|
||||
- bitcoind
|
||||
|
||||
tor:
|
||||
restart: unless-stopped
|
||||
image: btcpayserver/tor:0.4.1.5
|
||||
container_name: tor
|
||||
environment:
|
||||
TOR_PASSWORD: btcpayserver
|
||||
ports:
|
||||
- "9050:9050" # SOCKS
|
||||
- "9051:9051" # Tor Control
|
||||
volumes:
|
||||
- "tor_datadir:/home/tor/.tor"
|
||||
- "torrcdir:/usr/local/etc/tor"
|
||||
- "tor_servicesdir:/var/lib/tor/hidden_services"
|
||||
monerod:
|
||||
image: btcpayserver/monero:0.15.0.1-amd64
|
||||
restart: unless-stopped
|
||||
container_name: xmr_monerod
|
||||
entrypoint: sleep 999999
|
||||
# entrypoint: monerod --fixed-difficulty 200 --rpc-bind-ip=0.0.0.0 --confirm-external-bind --rpc-bind-port=18081 --block-notify="/bin/sh ./scripts/notifier.sh -k -X GET https://host.docker.internal:14142/monerolikedaemoncallback/block?cryptoCode=xmr&hash=%s" --testnet --no-igd --hide-my-port --offline
|
||||
volumes:
|
||||
- "monero_data:/home/monero/.bitmonero"
|
||||
ports:
|
||||
- "18081:18081"
|
||||
monero_wallet:
|
||||
image: btcpayserver/monero:0.15.0.1-amd64
|
||||
restart: unless-stopped
|
||||
container_name: xmr_wallet_rpc
|
||||
entrypoint: monero-wallet-rpc --testnet --rpc-bind-ip=0.0.0.0 --disable-rpc-login --confirm-external-bind --rpc-bind-port=18082 --non-interactive --trusted-daemon --daemon-address=monerod:18081 --wallet-file=/wallet/wallet.keys --password-file=/wallet/password --tx-notify="/bin/sh ./scripts/notifier.sh -k -X GET https://host.docker.internal:14142/monerolikedaemoncallback/tx?cryptoCode=xmr&hash=%s"
|
||||
ports:
|
||||
- "18082:18082"
|
||||
volumes:
|
||||
- "./monero_wallet:/wallet"
|
||||
depends_on:
|
||||
- monerod
|
||||
|
||||
litecoind:
|
||||
restart: unless-stopped
|
||||
image: nicolasdorier/docker-litecoin:0.16.3
|
||||
environment:
|
||||
BITCOIN_EXTRA_ARGS: |-
|
||||
rpcuser=ceiwHEbqWI83
|
||||
rpcpassword=DwubwWsoo3
|
||||
regtest=1
|
||||
rpcport=43782
|
||||
port=39388
|
||||
whitelist=0.0.0.0/0
|
||||
ports:
|
||||
- "43783:43782"
|
||||
expose:
|
||||
- "43782" # RPC
|
||||
- "39388" # P2P
|
||||
|
||||
elementsd-liquid:
|
||||
restart: always
|
||||
container_name: btcpayserver_elementsd_liquid
|
||||
image: btcpayserver/elements:0.18.1.7
|
||||
environment:
|
||||
ELEMENTS_CHAIN: elementsregtest
|
||||
ELEMENTS_EXTRA_ARGS: |
|
||||
mainchainrpcport=43782
|
||||
mainchainrpchost=bitcoind
|
||||
mainchainrpcuser=liquid
|
||||
mainchainrpcpassword=liquid
|
||||
rpcport=19332
|
||||
rpcbind=0.0.0.0:19332
|
||||
rpcauth=liquid:c8bf1a8961d97f224cb21224aaa8235d$$402f4a8907683d057b8c58a42940b6e54d1638322a42986ae28ebb844e603ae6
|
||||
port=19444
|
||||
whitelist=0.0.0.0/0
|
||||
validatepegin=0
|
||||
initialfreecoins=210000000000000
|
||||
con_dyna_deploy_start=99999999999
|
||||
expose:
|
||||
- "19332"
|
||||
- "19444"
|
||||
ports:
|
||||
- "19332:19332"
|
||||
- "19444:19444"
|
||||
volumes:
|
||||
- "elementsd_liquid_datadir:/data"
|
||||
volumes:
|
||||
sshd_datadir:
|
||||
bitcoin_datadir:
|
||||
elementsd_liquid_datadir:
|
||||
customer_lightningd_datadir:
|
||||
merchant_lightningd_datadir:
|
||||
lightning_charge_datadir:
|
||||
customer_lnd_datadir:
|
||||
merchant_lnd_datadir:
|
||||
tor_datadir:
|
||||
torrcdir:
|
||||
tor_servicesdir:
|
||||
monero_data:
|
||||
@@ -1,28 +0,0 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
|
||||
monerod:
|
||||
image: btcpayserver/monero:0.15.0.1-amd64
|
||||
restart: unless-stopped
|
||||
container_name: xmr_monerod
|
||||
entrypoint: sleep 999999
|
||||
# entrypoint: monerod --fixed-difficulty 200 --rpc-bind-ip=0.0.0.0 --confirm-external-bind --rpc-bind-port=18081 --block-notify="/bin/sh ./scripts/notifier.sh -k -X GET https://host.docker.internal:14142/monerolikedaemoncallback/block?cryptoCode=xmr&hash=%s" --testnet --no-igd --hide-my-port --offline
|
||||
volumes:
|
||||
- "monero_data:/home/monero/.bitmonero"
|
||||
ports:
|
||||
- "18081:18081"
|
||||
monero_wallet:
|
||||
image: btcpayserver/monero:0.15.0.1-amd64
|
||||
restart: unless-stopped
|
||||
container_name: xmr_wallet_rpc
|
||||
entrypoint: monero-wallet-rpc --testnet --rpc-bind-ip=0.0.0.0 --disable-rpc-login --confirm-external-bind --rpc-bind-port=18082 --non-interactive --trusted-daemon --daemon-address=monerod:18081 --wallet-file=/wallet/wallet.keys --password-file=/wallet/password --tx-notify="/bin/sh ./scripts/notifier.sh -k -X GET https://host.docker.internal:14142/monerolikedaemoncallback/tx?cryptoCode=xmr&hash=%s"
|
||||
ports:
|
||||
- "18082:18082"
|
||||
volumes:
|
||||
- "./monero_wallet:/wallet"
|
||||
depends_on:
|
||||
- monerod
|
||||
|
||||
volumes:
|
||||
monero_data:
|
||||
@@ -9,11 +9,11 @@ services:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: BTCPayServer.Tests/Dockerfile
|
||||
args:
|
||||
CONFIGURATION_NAME: Release
|
||||
environment:
|
||||
TESTS_BTCRPCCONNECTION: server=http://bitcoind:43782;ceiwHEbqWI83:DwubwWsoo3
|
||||
TESTS_LTCRPCCONNECTION: server=http://litecoind:43782;ceiwHEbqWI83:DwubwWsoo3
|
||||
TESTS_BTCNBXPLORERURL: http://nbxplorer:32838/
|
||||
TESTS_LTCNBXPLORERURL: http://nbxplorer:32838/
|
||||
TESTS_DB: "Postgres"
|
||||
TESTS_POSTGRES: User ID=postgres;Host=postgres;Port=5432;Database=btcpayserver
|
||||
TESTS_HOSTNAME: tests
|
||||
@@ -78,7 +78,7 @@ services:
|
||||
- customer_lnd
|
||||
- merchant_lnd
|
||||
nbxplorer:
|
||||
image: nicolasdorier/nbxplorer:2.1.35
|
||||
image: nicolasdorier/nbxplorer:2.1.37
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "32838:32838"
|
||||
@@ -86,19 +86,11 @@ services:
|
||||
- "32838"
|
||||
environment:
|
||||
NBXPLORER_NETWORK: regtest
|
||||
NBXPLORER_CHAINS: "btc,ltc,lbtc"
|
||||
NBXPLORER_CHAINS: "btc"
|
||||
NBXPLORER_BTCRPCURL: http://bitcoind:43782/
|
||||
NBXPLORER_BTCNODEENDPOINT: bitcoind:39388
|
||||
NBXPLORER_BTCRPCUSER: ceiwHEbqWI83
|
||||
NBXPLORER_BTCRPCPASSWORD: DwubwWsoo3
|
||||
NBXPLORER_LTCRPCURL: http://litecoind:43782/
|
||||
NBXPLORER_LTCNODEENDPOINT: litecoind:39388
|
||||
NBXPLORER_LTCRPCUSER: ceiwHEbqWI83
|
||||
NBXPLORER_LTCRPCPASSWORD: DwubwWsoo3
|
||||
NBXPLORER_LBTCRPCURL: "http://elementsd-liquid:19332/"
|
||||
NBXPLORER_LBTCNODEENDPOINT: "elementsd-liquid:19444"
|
||||
NBXPLORER_LBTCRPCUSER: "liquid"
|
||||
NBXPLORER_LBTCRPCPASSWORD: "liquid"
|
||||
NBXPLORER_BIND: 0.0.0.0:32838
|
||||
NBXPLORER_MINGAPSIZE: 5
|
||||
NBXPLORER_MAXGAPSIZE: 10
|
||||
@@ -106,8 +98,6 @@ services:
|
||||
NBXPLORER_NOAUTH: 1
|
||||
links:
|
||||
- bitcoind
|
||||
- litecoind
|
||||
- elementsd-liquid
|
||||
|
||||
|
||||
bitcoind:
|
||||
@@ -209,51 +199,6 @@ services:
|
||||
links:
|
||||
- bitcoind
|
||||
|
||||
litecoind:
|
||||
restart: unless-stopped
|
||||
image: nicolasdorier/docker-litecoin:0.16.3
|
||||
environment:
|
||||
BITCOIN_EXTRA_ARGS: |-
|
||||
rpcuser=ceiwHEbqWI83
|
||||
rpcpassword=DwubwWsoo3
|
||||
regtest=1
|
||||
rpcport=43782
|
||||
port=39388
|
||||
whitelist=0.0.0.0/0
|
||||
ports:
|
||||
- "43783:43782"
|
||||
expose:
|
||||
- "43782" # RPC
|
||||
- "39388" # P2P
|
||||
|
||||
elementsd-liquid:
|
||||
restart: always
|
||||
container_name: btcpayserver_elementsd_liquid
|
||||
image: btcpayserver/elements:0.18.1.7
|
||||
environment:
|
||||
ELEMENTS_CHAIN: elementsregtest
|
||||
ELEMENTS_EXTRA_ARGS: |
|
||||
mainchainrpcport=43782
|
||||
mainchainrpchost=bitcoind
|
||||
mainchainrpcuser=liquid
|
||||
mainchainrpcpassword=liquid
|
||||
rpcport=19332
|
||||
rpcbind=0.0.0.0:19332
|
||||
rpcauth=liquid:c8bf1a8961d97f224cb21224aaa8235d$$402f4a8907683d057b8c58a42940b6e54d1638322a42986ae28ebb844e603ae6
|
||||
port=19444
|
||||
whitelist=0.0.0.0/0
|
||||
validatepegin=0
|
||||
initialfreecoins=210000000000000
|
||||
con_dyna_deploy_start=99999999999
|
||||
expose:
|
||||
- "19332"
|
||||
- "19444"
|
||||
ports:
|
||||
- "19332:19332"
|
||||
- "19444:19444"
|
||||
volumes:
|
||||
- "elementsd_liquid_datadir:/data"
|
||||
|
||||
postgres:
|
||||
image: postgres:9.6.5
|
||||
ports:
|
||||
@@ -336,7 +281,6 @@ services:
|
||||
- "torrcdir:/usr/local/etc/tor"
|
||||
- "tor_servicesdir:/var/lib/tor/hidden_services"
|
||||
|
||||
|
||||
volumes:
|
||||
sshd_datadir:
|
||||
bitcoin_datadir:
|
||||
|
||||
@@ -6,4 +6,4 @@ if [ ! -z "$TEST_FILTERS" ]; then
|
||||
FILTERS="--filter $TEST_FILTERS"
|
||||
fi
|
||||
|
||||
dotnet test $FILTERS --no-build -v n < /dev/null
|
||||
dotnet test -c ${CONFIGURATION_NAME} $FILTERS --no-build -v n < /dev/null
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Import Project="../Build/Version.csproj" Condition="Exists('../Build/Version.csproj')" />
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Debug' And '$(RazorCompileOnBuild)' != 'true'">
|
||||
<RazorCompileOnBuild>false</RazorCompileOnBuild>
|
||||
<DefineConstants>$(DefineConstants);RAZOR_RUNTIME_COMPILE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
@@ -21,6 +18,10 @@
|
||||
<None Remove="Build\**" />
|
||||
<None Remove="wwwroot\bundles\jqueryvalidate\**" />
|
||||
<None Remove="wwwroot\vendor\jquery-nice-select\**" />
|
||||
<Content Update="Views\Shared\NBXSyncSummary.cshtml">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Currencies.txt" />
|
||||
@@ -28,12 +29,28 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="bundleconfig.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Altcoins)' == 'true'">
|
||||
<PackageReference Include="Nethereum.ABI" Version="3.8.0" />
|
||||
<PackageReference Include="Nethereum.HdWallet" Version="3.8.0" />
|
||||
<PackageReference Include="Nethereum.StandardTokenEIP20" Version="3.8.0" />
|
||||
<PackageReference Include="Nethereum.Web3" Version="3.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(Altcoins)' != 'true'">
|
||||
<Content Remove="Services\Altcoins\**\*" />
|
||||
<Content Remove="Views\EthereumLikeStore\**\*" />
|
||||
<Content Remove="Views\MoneroLikeStore\**\*" />
|
||||
<Content Remove="Views\Shared\Ethereum\**\*" />
|
||||
<Content Remove="Views\Shared\Monero\**\*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BTCPayServer.Hwi" Version="1.1.3" />
|
||||
<PackageReference Include="BTCPayServer.Lightning.All" Version="1.2.0" />
|
||||
<PackageReference Include="BuildBundlerMinifier" Version="3.2.435" />
|
||||
<PackageReference Include="BundlerMinifier.Core" Version="3.2.435" />
|
||||
<PackageReference Include="BundlerMinifier.TagHelpers" Version="3.2.435" />
|
||||
<PackageReference Include="CsvHelper" Version="15.0.5" />
|
||||
<PackageReference Include="HtmlSanitizer" Version="4.0.217" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Filter" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.NetCore.Analyzers" Version="2.9.8">
|
||||
|
||||
@@ -10,6 +10,7 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NBitcoin;
|
||||
using Serilog.Events;
|
||||
using TwentyTwenty.Storage;
|
||||
|
||||
namespace BTCPayServer.Configuration
|
||||
{
|
||||
@@ -90,11 +91,14 @@ namespace BTCPayServer.Configuration
|
||||
|
||||
var networkProvider = new BTCPayNetworkProvider(NetworkType);
|
||||
var filtered = networkProvider.Filter(supportedChains.ToArray());
|
||||
var elementsBased = filtered.GetAll().OfType<ElementsBTCPayNetwork>();
|
||||
var parentChains = elementsBased.Select(network => network.NetworkCryptoCode.ToUpperInvariant()).Distinct();
|
||||
var allSubChains = networkProvider.GetAll().OfType<ElementsBTCPayNetwork>()
|
||||
.Where(network => parentChains.Contains(network.NetworkCryptoCode)).Select(network => network.CryptoCode.ToUpperInvariant());
|
||||
supportedChains.AddRange(allSubChains);
|
||||
#if ALTCOINS
|
||||
supportedChains.AddRange(filtered.GetAllElementsSubChains());
|
||||
#endif
|
||||
#if !ALTCOINS
|
||||
var onlyBTC = supportedChains.Count == 1 && supportedChains.First() == "BTC";
|
||||
if (!onlyBTC)
|
||||
throw new ConfigException($"This build of BTCPay Server does not support altcoins");
|
||||
#endif
|
||||
NetworkProvider = networkProvider.Filter(supportedChains.ToArray());
|
||||
foreach (var chain in supportedChains)
|
||||
{
|
||||
@@ -172,6 +176,7 @@ namespace BTCPayServer.Configuration
|
||||
SocksEndpoint = endpoint;
|
||||
}
|
||||
|
||||
UpdateUrl = conf.GetOrDefault<Uri>("updateurl", null);
|
||||
|
||||
var sshSettings = ParseSSHConfiguration(conf);
|
||||
if ((!string.IsNullOrEmpty(sshSettings.Password) || !string.IsNullOrEmpty(sshSettings.KeyFile)) && !string.IsNullOrEmpty(sshSettings.Server))
|
||||
@@ -297,5 +302,6 @@ namespace BTCPayServer.Configuration
|
||||
set;
|
||||
}
|
||||
public string TorrcFile { get; set; }
|
||||
public Uri UpdateUrl { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace BTCPayServer.Configuration
|
||||
app.Option("--sshtrustedfingerprints", "SSH Host public key fingerprint or sha256 (default: empty, it will allow untrusted connections)", CommandOptionType.SingleValue);
|
||||
app.Option("--torrcfile", "Path to torrc file containing hidden services directories (default: empty)", CommandOptionType.SingleValue);
|
||||
app.Option("--socksendpoint", "Socks endpoint to connect to onion urls (default: empty)", CommandOptionType.SingleValue);
|
||||
app.Option("--updateurl", $"Url used for once a day new release version check. Check performed only if value is not empty (default: empty)", CommandOptionType.SingleValue);
|
||||
app.Option("--debuglog", "A rolling log file for debug messages.", CommandOptionType.SingleValue);
|
||||
app.Option("--debugloglevel", "The severity you log (default:information)", CommandOptionType.SingleValue);
|
||||
app.Option("--disable-registration", "Disables new user registrations (default:true)", CommandOptionType.SingleValue);
|
||||
|
||||
10
BTCPayServer/Contracts/ISyncSummaryProvider.cs
Normal file
10
BTCPayServer/Contracts/ISyncSummaryProvider.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace BTCPayServer.Contracts
|
||||
{
|
||||
public interface ISyncSummaryProvider
|
||||
{
|
||||
bool AllAvailable();
|
||||
|
||||
string Partial { get; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -443,13 +443,8 @@ namespace BTCPayServer.Controllers
|
||||
var settings = await _SettingsRepository.GetSettingAsync<ThemeSettings>();
|
||||
settings.FirstRun = false;
|
||||
await _SettingsRepository.UpdateSetting<ThemeSettings>(settings);
|
||||
if (_Options.DisableRegistration)
|
||||
{
|
||||
// Once the admin user has been created lock subsequent user registrations (needs to be disabled for unit tests that require multiple users).
|
||||
Logs.PayServer.LogInformation("First admin created, disabling subscription (disable-registration is set to true)");
|
||||
policies.LockSubscription = true;
|
||||
await _SettingsRepository.UpdateSetting(policies);
|
||||
}
|
||||
|
||||
await _SettingsRepository.FirstAdminRegistered(policies, _Options.UpdateUrl != null, _Options.DisableRegistration);
|
||||
RegisteredAdmin = true;
|
||||
}
|
||||
|
||||
@@ -626,7 +621,7 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
private bool CanLoginOrRegister()
|
||||
{
|
||||
return _btcPayServerEnvironment.IsDevelopping || _btcPayServerEnvironment.IsSecure;
|
||||
return _btcPayServerEnvironment.IsDeveloping || _btcPayServerEnvironment.IsSecure;
|
||||
}
|
||||
|
||||
private void SetInsecureFlags()
|
||||
|
||||
@@ -47,9 +47,42 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
public string CreatedAppId { get; set; }
|
||||
|
||||
public async Task<IActionResult> ListApps()
|
||||
public async Task<IActionResult> ListApps(
|
||||
string sortOrder = null,
|
||||
string sortOrderColumn = null
|
||||
)
|
||||
{
|
||||
var apps = await _AppService.GetAllApps(GetUserId());
|
||||
|
||||
if (sortOrder != null && sortOrderColumn != null)
|
||||
{
|
||||
apps = apps.OrderByDescending(app =>
|
||||
{
|
||||
switch (sortOrderColumn)
|
||||
{
|
||||
case nameof(app.AppName):
|
||||
return app.AppName;
|
||||
case nameof(app.StoreName):
|
||||
return app.StoreName;
|
||||
case nameof(app.AppType):
|
||||
return app.AppType;
|
||||
default:
|
||||
return app.Id;
|
||||
}
|
||||
}).ToArray();
|
||||
|
||||
switch (sortOrder)
|
||||
{
|
||||
case "desc":
|
||||
ViewData[$"{sortOrderColumn}SortOrder"] = "asc";
|
||||
break;
|
||||
case "asc":
|
||||
apps = apps.Reverse().ToArray();
|
||||
ViewData[$"{sortOrderColumn}SortOrder"] = "desc";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return View(new ListAppsViewModel()
|
||||
{
|
||||
Apps = apps
|
||||
|
||||
@@ -288,7 +288,7 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
|
||||
protected bool CanUseInternalLightning(bool doingAdminThings)
|
||||
{
|
||||
return (_btcPayServerEnvironment.IsDevelopping || User.IsInRole(Roles.ServerAdmin) ||
|
||||
return (_btcPayServerEnvironment.IsDeveloping || User.IsInRole(Roles.ServerAdmin) ||
|
||||
(_cssThemeManager.AllowLightningInternalNodeForAll && !doingAdminThings));
|
||||
}
|
||||
|
||||
|
||||
@@ -148,13 +148,7 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
await _userManager.AddToRoleAsync(user, Roles.ServerAdmin);
|
||||
if (!anyAdmin)
|
||||
{
|
||||
if (_options.DisableRegistration)
|
||||
{
|
||||
// automatically lock subscriptions now that we have our first admin
|
||||
Logs.PayServer.LogInformation("First admin created, disabling subscription (disable-registration is set to true)");
|
||||
policies.LockSubscription = true;
|
||||
await _settingsRepository.UpdateSetting(policies);
|
||||
}
|
||||
await _settingsRepository.FirstAdminRegistered(policies, _options.UpdateUrl != null, _options.DisableRegistration);
|
||||
}
|
||||
}
|
||||
_eventAggregator.Publish(new UserRegisteredEvent() { RequestUri = Request.GetAbsoluteRootUri(), User = user, Admin = request.IsAdministrator is true });
|
||||
|
||||
@@ -29,7 +29,6 @@ using Microsoft.EntityFrameworkCore;
|
||||
using NBitcoin;
|
||||
using NBitpayClient;
|
||||
using NBXplorer;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using StoreData = BTCPayServer.Data.StoreData;
|
||||
|
||||
@@ -598,55 +597,23 @@ namespace BTCPayServer.Controllers
|
||||
return Ok("{}");
|
||||
}
|
||||
|
||||
public class InvoicePreference
|
||||
{
|
||||
public int? TimezoneOffset { get; set; }
|
||||
public string SearchTerm { get; set; }
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("invoices")]
|
||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[BitpayAPIConstraint(false)]
|
||||
public async Task<IActionResult> ListInvoices(string searchTerm = null, int skip = 0, int count = 50, int? timezoneOffset = null)
|
||||
public async Task<IActionResult> ListInvoices(InvoicesModel model = null)
|
||||
{
|
||||
// If the user enter an empty searchTerm, then the variable will be null and not empty string
|
||||
// but we want searchTerm to be null only if the user is browsing the page via some link
|
||||
// NOT if the user entered some empty search
|
||||
searchTerm = searchTerm is string ? searchTerm :
|
||||
this.Request.Query.ContainsKey(nameof(searchTerm)) ? string.Empty :
|
||||
null;
|
||||
if (searchTerm is null)
|
||||
{
|
||||
if (this.Request.Cookies.TryGetValue("ListInvoicePreferences", out var str))
|
||||
{
|
||||
var preferences = JsonConvert.DeserializeObject<InvoicePreference>(str);
|
||||
searchTerm = preferences.SearchTerm;
|
||||
timezoneOffset = timezoneOffset is int v ? v : preferences.TimezoneOffset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var preferences = new InvoicePreference();
|
||||
preferences.SearchTerm = searchTerm;
|
||||
preferences.TimezoneOffset = timezoneOffset;
|
||||
this.Response.Cookies.Append("ListInvoicePreferences", JsonConvert.SerializeObject(preferences));
|
||||
}
|
||||
var fs = new SearchString(searchTerm);
|
||||
model = this.ParseListQuery(model ?? new InvoicesModel());
|
||||
|
||||
var fs = new SearchString(model.SearchTerm);
|
||||
var storeIds = fs.GetFilterArray("storeid") != null ? fs.GetFilterArray("storeid") : new List<string>().ToArray();
|
||||
|
||||
var model = new InvoicesModel
|
||||
{
|
||||
SearchTerm = searchTerm,
|
||||
Skip = skip,
|
||||
Count = count,
|
||||
StoreIds = storeIds,
|
||||
TimezoneOffset = timezoneOffset
|
||||
};
|
||||
InvoiceQuery invoiceQuery = GetInvoiceQuery(searchTerm, timezoneOffset ?? 0);
|
||||
model.StoreIds = storeIds;
|
||||
|
||||
InvoiceQuery invoiceQuery = GetInvoiceQuery(model.SearchTerm, model.TimezoneOffset ?? 0);
|
||||
var counting = _InvoiceRepository.GetInvoicesTotal(invoiceQuery);
|
||||
invoiceQuery.Count = count;
|
||||
invoiceQuery.Skip = skip;
|
||||
invoiceQuery.Count = model.Count;
|
||||
invoiceQuery.Skip = model.Skip;
|
||||
var list = await _InvoiceRepository.GetInvoices(invoiceQuery);
|
||||
|
||||
foreach (var invoice in list)
|
||||
|
||||
@@ -61,23 +61,22 @@ namespace BTCPayServer.Controllers
|
||||
[HttpGet]
|
||||
[Route("")]
|
||||
[BitpayAPIConstraint(false)]
|
||||
public async Task<IActionResult> GetPaymentRequests(int skip = 0, int count = 50, bool includeArchived = false)
|
||||
public async Task<IActionResult> GetPaymentRequests(ListPaymentRequestsViewModel model = null)
|
||||
{
|
||||
model = this.ParseListQuery(model ?? new ListPaymentRequestsViewModel());
|
||||
|
||||
var includeArchived = new SearchString(model.SearchTerm).GetFilterBool("includearchived") == true;
|
||||
var result = await _PaymentRequestRepository.FindPaymentRequests(new PaymentRequestQuery()
|
||||
{
|
||||
UserId = GetUserId(),
|
||||
Skip = skip,
|
||||
Count = count,
|
||||
Skip = model.Skip,
|
||||
Count = model.Count,
|
||||
IncludeArchived = includeArchived
|
||||
});
|
||||
return View(new ListPaymentRequestsViewModel()
|
||||
{
|
||||
IncludeArchived = includeArchived,
|
||||
Skip = skip,
|
||||
Count = count,
|
||||
Total = result.Total,
|
||||
Items = result.Items.Select(data => new ViewPaymentRequestViewModel(data)).ToList()
|
||||
});
|
||||
|
||||
model.Total = result.Total;
|
||||
model.Items = result.Items.Select(data => new ViewPaymentRequestViewModel(data)).ToList();
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
private bool CanUseInternalLightning()
|
||||
{
|
||||
return (_BTCPayEnv.IsDevelopping || User.IsInRole(Roles.ServerAdmin) || _CssThemeManager.AllowLightningInternalNodeForAll);
|
||||
return (_BTCPayEnv.IsDeveloping || User.IsInRole(Roles.ServerAdmin) || _CssThemeManager.AllowLightningInternalNodeForAll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,7 +520,9 @@ namespace BTCPayServer.Controllers
|
||||
Value = value,
|
||||
WalletId = new WalletId(store.Id, paymentMethodId.CryptoCode),
|
||||
Enabled = !excludeFilters.Match(paymentMethodId) && strategy != null,
|
||||
#if ALTCOINS
|
||||
Collapsed = network is ElementsBTCPayNetwork elementsBTCPayNetwork && elementsBTCPayNetwork.NetworkCryptoCode != elementsBTCPayNetwork.CryptoCode && string.IsNullOrEmpty(value)
|
||||
#endif
|
||||
});
|
||||
break;
|
||||
case LightningPaymentType _:
|
||||
|
||||
@@ -259,7 +259,11 @@ namespace BTCPayServer.Controllers
|
||||
[Route("{walletId}/transactions")]
|
||||
public async Task<IActionResult> WalletTransactions(
|
||||
[ModelBinder(typeof(WalletIdModelBinder))]
|
||||
WalletId walletId, string labelFilter = null)
|
||||
WalletId walletId,
|
||||
string labelFilter = null,
|
||||
int skip = 0,
|
||||
int count = 50
|
||||
)
|
||||
{
|
||||
DerivationSchemeSettings paymentMethod = GetDerivationSchemeSettings(walletId);
|
||||
if (paymentMethod == null)
|
||||
@@ -271,7 +275,12 @@ namespace BTCPayServer.Controllers
|
||||
var transactions = await wallet.FetchTransactions(paymentMethod.AccountDerivation);
|
||||
var walletBlob = await walletBlobAsync;
|
||||
var walletTransactionsInfo = await walletTransactionsInfoAsync;
|
||||
var model = new ListTransactionsViewModel();
|
||||
var model = new ListTransactionsViewModel
|
||||
{
|
||||
Skip = skip,
|
||||
Count = count,
|
||||
Total = 0
|
||||
};
|
||||
if (transactions == null)
|
||||
{
|
||||
TempData.SetStatusMessageModel(new StatusMessageModel()
|
||||
@@ -309,7 +318,8 @@ namespace BTCPayServer.Controllers
|
||||
model.Transactions.Add(vm);
|
||||
}
|
||||
|
||||
model.Transactions = model.Transactions.OrderByDescending(t => t.Timestamp).ToList();
|
||||
model.Total = model.Transactions.Count;
|
||||
model.Transactions = model.Transactions.OrderByDescending(t => t.Timestamp).Skip(skip).Take(count).ToList();
|
||||
}
|
||||
|
||||
return View(model);
|
||||
|
||||
@@ -149,9 +149,9 @@ namespace BTCPayServer.Data
|
||||
}
|
||||
public class PayoutBlob
|
||||
{
|
||||
[JsonConverter(typeof(DecimalStringJsonConverter))]
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Amount { get; set; }
|
||||
[JsonConverter(typeof(DecimalStringJsonConverter))]
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal? CryptoAmount { get; set; }
|
||||
public int MinimumConfirmation { get; set; } = 1;
|
||||
public IClaimDestination Destination { get; set; }
|
||||
@@ -190,9 +190,9 @@ namespace BTCPayServer.Data
|
||||
public string Name { get; set; }
|
||||
public string Currency { get; set; }
|
||||
public int Divisibility { get; set; }
|
||||
[JsonConverter(typeof(DecimalStringJsonConverter))]
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Limit { get; set; }
|
||||
[JsonConverter(typeof(DecimalStringJsonConverter))]
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal MinimumClaim { get; set; }
|
||||
public PullPaymentView View { get; set; } = new PullPaymentView();
|
||||
[JsonConverter(typeof(TimeSpanJsonConverter))]
|
||||
|
||||
@@ -64,7 +64,6 @@ namespace BTCPayServer.Data
|
||||
{
|
||||
if (storeData == null)
|
||||
throw new ArgumentNullException(nameof(storeData));
|
||||
networks = networks.UnfilteredNetworks;
|
||||
#pragma warning disable CS0618
|
||||
bool btcReturned = false;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.WebSockets;
|
||||
using System.Reflection;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
@@ -449,5 +450,21 @@ namespace BTCPayServer
|
||||
};
|
||||
return controller.View("PostRedirect", redirectVm);
|
||||
}
|
||||
|
||||
public static string ToSql<TEntity>(this IQueryable<TEntity> query) where TEntity : class
|
||||
{
|
||||
var enumerator = query.Provider.Execute<IEnumerable<TEntity>>(query.Expression).GetEnumerator();
|
||||
var relationalCommandCache = enumerator.Private("_relationalCommandCache");
|
||||
var selectExpression = relationalCommandCache.Private<Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression>("_selectExpression");
|
||||
var factory = relationalCommandCache.Private<Microsoft.EntityFrameworkCore.Query.IQuerySqlGeneratorFactory>("_querySqlGeneratorFactory");
|
||||
|
||||
var sqlGenerator = factory.Create();
|
||||
var command = sqlGenerator.GetCommand(selectExpression);
|
||||
|
||||
string sql = command.CommandText;
|
||||
return sql;
|
||||
}
|
||||
private static object Private(this object obj, string privateField) => obj?.GetType().GetField(privateField, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj);
|
||||
private static T Private<T>(this object obj, string privateField) => (T)obj?.GetType().GetField(privateField, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj);
|
||||
}
|
||||
}
|
||||
|
||||
39
BTCPayServer/Extensions/ActionLogicExtensions.cs
Normal file
39
BTCPayServer/Extensions/ActionLogicExtensions.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
// All logic that would otherwise be duplicated across solution goes into this utility class
|
||||
// ~If~ Once this starts growing out of control, begin extracting action logic classes out of here
|
||||
// Also some of logic in here may be result of parallel development of Greenfield API
|
||||
// It's much better that we extract those common methods then copy paste and maintain same code across codebase
|
||||
internal static class ActionLogicExtensions
|
||||
{
|
||||
internal static async Task FirstAdminRegistered(this SettingsRepository settingsRepository, PoliciesSettings policies,
|
||||
bool updateCheck, bool disableRegistrations)
|
||||
{
|
||||
if (updateCheck)
|
||||
{
|
||||
Logs.PayServer.LogInformation("First admin created, enabling checks for new versions");
|
||||
policies.CheckForNewVersions = updateCheck;
|
||||
}
|
||||
|
||||
if (disableRegistrations)
|
||||
{
|
||||
// Once the admin user has been created lock subsequent user registrations (needs to be disabled for unit tests that require multiple users).
|
||||
Logs.PayServer.LogInformation("First admin created, disabling subscription (disable-registration is set to true)");
|
||||
policies.LockSubscription = true;
|
||||
}
|
||||
|
||||
if (updateCheck || disableRegistrations)
|
||||
await settingsRepository.UpdateSetting(policies);
|
||||
}
|
||||
}
|
||||
}
|
||||
93
BTCPayServer/Extensions/ControllerBaseExtensions.cs
Normal file
93
BTCPayServer/Extensions/ControllerBaseExtensions.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Models.InvoicingModels;
|
||||
using BTCPayServer.Models.PaymentRequestViewModels;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
// Classes here remember users preferences on certain pages and store them in unified blob cookie "UserPreferCookie"
|
||||
public static class ControllerBaseExtension
|
||||
{
|
||||
public static T ParseListQuery<T>(this ControllerBase ctrl, T model) where T : BasePagingViewModel
|
||||
{
|
||||
PropertyInfo prop;
|
||||
if (model is InvoicesModel)
|
||||
prop = typeof(UserPrefsCookie).GetProperty(nameof(UserPrefsCookie.InvoicesQuery));
|
||||
else if (model is ListPaymentRequestsViewModel)
|
||||
prop = typeof(UserPrefsCookie).GetProperty(nameof(UserPrefsCookie.PaymentRequestsQuery));
|
||||
else
|
||||
throw new Exception("Unsupported BasePagingViewModel for cookie user preferences saving");
|
||||
|
||||
return ProcessParse(ctrl, model, prop);
|
||||
}
|
||||
|
||||
private static T ProcessParse<T>(ControllerBase ctrl, T model, PropertyInfo prop) where T : BasePagingViewModel
|
||||
{
|
||||
var prefCookie = parsePrefCookie(ctrl);
|
||||
|
||||
// If the user enter an empty searchTerm, then the variable will be null and not empty string
|
||||
// but we want searchTerm to be null only if the user is browsing the page via some link
|
||||
// NOT if the user entered some empty search
|
||||
var searchTerm = model.SearchTerm;
|
||||
searchTerm = searchTerm is string ? searchTerm :
|
||||
ctrl.Request.Query.ContainsKey(nameof(searchTerm)) ? string.Empty :
|
||||
null;
|
||||
if (searchTerm is null)
|
||||
{
|
||||
var section = prop.GetValue(prefCookie) as ListQueryDataHolder;
|
||||
if (section != null && !String.IsNullOrEmpty(section.SearchTerm))
|
||||
{
|
||||
model.SearchTerm = section.SearchTerm;
|
||||
model.TimezoneOffset = section.TimezoneOffset ?? 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prop.SetValue(prefCookie, new ListQueryDataHolder(model.SearchTerm, model.TimezoneOffset));
|
||||
ctrl.Response.Cookies.Append(nameof(UserPrefsCookie), JsonConvert.SerializeObject(prefCookie));
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private static UserPrefsCookie parsePrefCookie(ControllerBase ctrl)
|
||||
{
|
||||
var prefCookie = new UserPrefsCookie();
|
||||
ctrl.Request.Cookies.TryGetValue(nameof(UserPrefsCookie), out var strPrefCookie);
|
||||
if (!String.IsNullOrEmpty(strPrefCookie))
|
||||
{
|
||||
try
|
||||
{
|
||||
prefCookie = JsonConvert.DeserializeObject<UserPrefsCookie>(strPrefCookie);
|
||||
}
|
||||
catch { /* ignore cookie deserialization failures */ }
|
||||
}
|
||||
|
||||
return prefCookie;
|
||||
}
|
||||
|
||||
class UserPrefsCookie
|
||||
{
|
||||
public ListQueryDataHolder InvoicesQuery { get; set; }
|
||||
|
||||
public ListQueryDataHolder PaymentRequestsQuery { get; set; }
|
||||
}
|
||||
|
||||
class ListQueryDataHolder
|
||||
{
|
||||
public ListQueryDataHolder() { }
|
||||
|
||||
public ListQueryDataHolder(string searchTerm, int? timezoneOffset)
|
||||
{
|
||||
SearchTerm = searchTerm;
|
||||
TimezoneOffset = timezoneOffset;
|
||||
}
|
||||
|
||||
public int? TimezoneOffset { get; set; }
|
||||
public string SearchTerm { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ namespace BTCPayServer
|
||||
return money.ToDecimal(MoneyUnit.BTC);
|
||||
case MoneyBag mb:
|
||||
return mb.Select(money => money.GetValue(network)).Sum();
|
||||
#if ALTCOINS
|
||||
case AssetMoney assetMoney:
|
||||
if (network is ElementsBTCPayNetwork elementsBTCPayNetwork)
|
||||
{
|
||||
@@ -24,6 +25,7 @@ namespace BTCPayServer
|
||||
: 0;
|
||||
}
|
||||
throw new NotSupportedException("IMoney type not supported");
|
||||
#endif
|
||||
default:
|
||||
throw new NotSupportedException("IMoney type not supported");
|
||||
}
|
||||
|
||||
@@ -10,12 +10,11 @@ namespace BTCPayServer.HostedServices
|
||||
{
|
||||
public abstract class BaseAsyncService : IHostedService
|
||||
{
|
||||
private CancellationTokenSource _Cts;
|
||||
private CancellationTokenSource _Cts = new CancellationTokenSource();
|
||||
protected Task[] _Tasks;
|
||||
|
||||
public virtual Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_Cts = new CancellationTokenSource();
|
||||
_Tasks = InitializeTasks();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
121
BTCPayServer/HostedServices/NewVersionCheckerHostedService.cs
Normal file
121
BTCPayServer/HostedServices/NewVersionCheckerHostedService.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Notifications;
|
||||
using BTCPayServer.Services.Notifications.Blobs;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.HostedServices
|
||||
{
|
||||
public class NewVersionCheckerHostedService : BaseAsyncService
|
||||
{
|
||||
private readonly SettingsRepository _settingsRepository;
|
||||
private readonly BTCPayServerEnvironment _env;
|
||||
private readonly NotificationSender _notificationSender;
|
||||
private readonly IVersionFetcher _versionFetcher;
|
||||
|
||||
public NewVersionCheckerHostedService(SettingsRepository settingsRepository, BTCPayServerEnvironment env,
|
||||
NotificationSender notificationSender, IVersionFetcher versionFetcher)
|
||||
{
|
||||
_settingsRepository = settingsRepository;
|
||||
_env = env;
|
||||
_notificationSender = notificationSender;
|
||||
_versionFetcher = versionFetcher;
|
||||
}
|
||||
|
||||
internal override Task[] InitializeTasks()
|
||||
{
|
||||
return new Task[] { CreateLoopTask(LoopVersionCheck) };
|
||||
}
|
||||
|
||||
protected async Task LoopVersionCheck()
|
||||
{
|
||||
try
|
||||
{
|
||||
await ProcessVersionCheck();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logs.Events.LogError(ex, "Error while performing new version check");
|
||||
}
|
||||
await Task.Delay(TimeSpan.FromDays(1), Cancellation);
|
||||
}
|
||||
|
||||
public async Task ProcessVersionCheck()
|
||||
{
|
||||
var policies = await _settingsRepository.GetSettingAsync<PoliciesSettings>() ?? new PoliciesSettings();
|
||||
if (policies.CheckForNewVersions)
|
||||
{
|
||||
var tag = await _versionFetcher.Fetch(Cancellation);
|
||||
if (tag != null && tag != _env.Version)
|
||||
{
|
||||
var dh = await _settingsRepository.GetSettingAsync<NewVersionCheckerDataHolder>() ?? new NewVersionCheckerDataHolder();
|
||||
if (dh.LastVersion != tag)
|
||||
{
|
||||
await _notificationSender.SendNotification(new AdminScope(), new NewVersionNotification(tag));
|
||||
|
||||
dh.LastVersion = tag;
|
||||
await _settingsRepository.UpdateSetting(dh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class NewVersionCheckerDataHolder
|
||||
{
|
||||
public string LastVersion { get; set; }
|
||||
}
|
||||
|
||||
public interface IVersionFetcher
|
||||
{
|
||||
Task<string> Fetch(CancellationToken cancellation);
|
||||
}
|
||||
|
||||
public class GithubVersionFetcher : IVersionFetcher
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly Uri _updateurl;
|
||||
public GithubVersionFetcher(IHttpClientFactory httpClientFactory, BTCPayServerOptions options)
|
||||
{
|
||||
_httpClient = httpClientFactory.CreateClient(nameof(GithubVersionFetcher));
|
||||
_httpClient.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
|
||||
_httpClient.DefaultRequestHeaders.Add("User-Agent", "BTCPayServer/NewVersionChecker");
|
||||
|
||||
_updateurl = options.UpdateUrl;
|
||||
}
|
||||
|
||||
private static readonly Regex _releaseVersionTag = new Regex("^(v[1-9]+(\\.[0-9]+)*(-[0-9]+)?)$");
|
||||
public async Task<string> Fetch(CancellationToken cancellation)
|
||||
{
|
||||
if (_updateurl == null)
|
||||
return null;
|
||||
|
||||
using (var resp = await _httpClient.GetAsync(_updateurl, cancellation))
|
||||
{
|
||||
var strResp = await resp.Content.ReadAsStringAsync();
|
||||
if (resp.IsSuccessStatusCode)
|
||||
{
|
||||
var jobj = JObject.Parse(strResp);
|
||||
var tag = jobj["tag_name"].ToString();
|
||||
|
||||
var isReleaseVersionTag = _releaseVersionTag.IsMatch(tag);
|
||||
return isReleaseVersionTag ? tag : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logs.Events.LogWarning($"Unsuccessful status code returned during new version check. " +
|
||||
$"Url: {_updateurl}, HTTP Code: {resp.StatusCode}, Response Body: {strResp}");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Contracts;
|
||||
using BTCPayServer.Controllers;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.HostedServices;
|
||||
@@ -16,7 +17,6 @@ using BTCPayServer.Security;
|
||||
using BTCPayServer.Security.Bitpay;
|
||||
using BTCPayServer.Security.GreenField;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Altcoins.Monero;
|
||||
using BTCPayServer.Services.Apps;
|
||||
using BTCPayServer.Services.Fees;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
@@ -47,7 +47,9 @@ using NBXplorer.DerivationStrategy;
|
||||
using Newtonsoft.Json;
|
||||
using NicolasDorier.RateLimits;
|
||||
using Serilog;
|
||||
|
||||
#if ALTCOINS
|
||||
using BTCPayServer.Services.Altcoins.Monero;
|
||||
#endif
|
||||
namespace BTCPayServer.Hosting
|
||||
{
|
||||
public static class BTCPayServerServices
|
||||
@@ -75,7 +77,9 @@ namespace BTCPayServer.Hosting
|
||||
services.RegisterJsonConverter(n => new ClaimDestinationJsonConverter(n));
|
||||
|
||||
services.AddPayJoinServices();
|
||||
#if ALTCOINS
|
||||
services.AddMoneroLike();
|
||||
#endif
|
||||
services.TryAddSingleton<SettingsRepository>();
|
||||
services.TryAddSingleton<LabelFactory>();
|
||||
services.TryAddSingleton<TorServices>();
|
||||
@@ -168,6 +172,7 @@ namespace BTCPayServer.Hosting
|
||||
htmlSanitizer.RemovingStyle += (sender, args) => { args.Cancel = true; };
|
||||
htmlSanitizer.AllowedAttributes.Add("class");
|
||||
htmlSanitizer.AllowedTags.Add("iframe");
|
||||
htmlSanitizer.AllowedTags.Add("style");
|
||||
htmlSanitizer.AllowedTags.Remove("img");
|
||||
htmlSanitizer.AllowedAttributes.Add("webkitallowfullscreen");
|
||||
htmlSanitizer.AllowedAttributes.Add("allowfullscreen");
|
||||
@@ -177,6 +182,7 @@ namespace BTCPayServer.Hosting
|
||||
services.TryAddSingleton<LightningConfigurationProvider>();
|
||||
services.TryAddSingleton<LanguageService>();
|
||||
services.TryAddSingleton<NBXplorerDashboard>();
|
||||
services.TryAddSingleton<ISyncSummaryProvider, NBXSyncSummaryProvider>();
|
||||
services.TryAddSingleton<StoreRepository>();
|
||||
services.TryAddSingleton<PaymentRequestRepository>();
|
||||
services.TryAddSingleton<BTCPayWalletProvider>();
|
||||
@@ -233,7 +239,11 @@ namespace BTCPayServer.Hosting
|
||||
services.AddSingleton<IBackgroundJobClient, BackgroundJobClient>();
|
||||
services.AddScoped<IAuthorizationHandler, CookieAuthorizationHandler>();
|
||||
services.AddScoped<IAuthorizationHandler, BitpayAuthorizationHandler>();
|
||||
|
||||
services.AddSingleton<IVersionFetcher, GithubVersionFetcher>();
|
||||
services.AddSingleton<IHostedService, NewVersionCheckerHostedService>();
|
||||
services.AddSingleton<INotificationHandler, NewVersionNotification.Handler>();
|
||||
|
||||
services.AddSingleton<INotificationHandler, InvoiceEventNotification.Handler>();
|
||||
services.AddSingleton<INotificationHandler, PayoutNotification.Handler>();
|
||||
|
||||
@@ -278,7 +288,7 @@ namespace BTCPayServer.Hosting
|
||||
{
|
||||
var btcPayEnv = provider.GetService<BTCPayServerEnvironment>();
|
||||
var rateLimits = new RateLimitService();
|
||||
if (btcPayEnv.IsDevelopping)
|
||||
if (btcPayEnv.IsDeveloping)
|
||||
{
|
||||
rateLimits.SetZone($"zone={ZoneLimits.Login} rate=1000r/min burst=100 nodelay");
|
||||
rateLimits.SetZone($"zone={ZoneLimits.Register} rate=1000r/min burst=100 nodelay");
|
||||
|
||||
14
BTCPayServer/Models/BasePagingViewModel.cs
Normal file
14
BTCPayServer/Models/BasePagingViewModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace BTCPayServer.Models
|
||||
{
|
||||
public abstract class BasePagingViewModel
|
||||
{
|
||||
public int Skip { get; set; } = 0;
|
||||
public int Count { get; set; } = 50;
|
||||
public int Total { get; set; }
|
||||
[DisplayFormat(ConvertEmptyStringToNull = false)]
|
||||
public string SearchTerm { get; set; }
|
||||
public int? TimezoneOffset { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,8 @@ using BTCPayServer.Services.Invoices;
|
||||
|
||||
namespace BTCPayServer.Models.InvoicingModels
|
||||
{
|
||||
public class InvoicesModel
|
||||
public class InvoicesModel : BasePagingViewModel
|
||||
{
|
||||
public int Skip { get; set; }
|
||||
public int Count { get; set; }
|
||||
public int Total { get; set; }
|
||||
public string SearchTerm { get; set; }
|
||||
public int? TimezoneOffset { get; set; }
|
||||
public List<InvoiceModel> Invoices { get; set; } = new List<InvoiceModel>();
|
||||
public string[] StoreIds { get; set; }
|
||||
}
|
||||
|
||||
@@ -8,15 +8,10 @@ using PaymentRequestData = BTCPayServer.Data.PaymentRequestData;
|
||||
|
||||
namespace BTCPayServer.Models.PaymentRequestViewModels
|
||||
{
|
||||
public class ListPaymentRequestsViewModel
|
||||
public class ListPaymentRequestsViewModel : BasePagingViewModel
|
||||
{
|
||||
public int Skip { get; set; }
|
||||
public int Count { get; set; }
|
||||
|
||||
public List<ViewPaymentRequestViewModel> Items { get; set; }
|
||||
|
||||
public int Total { get; set; }
|
||||
public bool IncludeArchived { get; set; }
|
||||
}
|
||||
|
||||
public class UpdatePaymentRequestViewModel
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||
public DerivationSchemeViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
[Display(Name = "Derivation scheme")]
|
||||
public string DerivationScheme
|
||||
{
|
||||
get; set;
|
||||
@@ -31,7 +33,7 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||
|
||||
public KeyPath RootKeyPath { get; set; }
|
||||
|
||||
[Display(Name = "Electrum/Hardware Wallet File")]
|
||||
[Display(Name = "Wallet File")]
|
||||
public IFormFile WalletFile { get; set; }
|
||||
public string Config { get; set; }
|
||||
public string Source { get; set; }
|
||||
|
||||
@@ -19,5 +19,8 @@ namespace BTCPayServer.Models.WalletViewModels
|
||||
}
|
||||
public HashSet<Label> Labels { get; set; } = new HashSet<Label>();
|
||||
public List<TransactionViewModel> Transactions { get; set; } = new List<TransactionViewModel>();
|
||||
public int Skip { get; set; }
|
||||
public int Count { get; set; }
|
||||
public int Total { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using NBXplorer.Models;
|
||||
|
||||
@@ -12,11 +13,14 @@ namespace BTCPayServer.Models.WalletViewModels
|
||||
public bool Ok => IsServerAdmin && IsSupportedByCurrency && IsFullySync;
|
||||
|
||||
[Range(1000, 10_000)]
|
||||
[DisplayName("Batch size")]
|
||||
public int BatchSize { get; set; } = 3000;
|
||||
[Range(0, 10_000_000)]
|
||||
[DisplayName("Starting index")]
|
||||
public int StartingIndex { get; set; } = 0;
|
||||
|
||||
[Range(100, 100000)]
|
||||
[DisplayName("Gap limit")]
|
||||
public int GapLimit { get; set; } = 10000;
|
||||
|
||||
public int? Progress { get; set; }
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace BTCPayServer.Models.WalletViewModels
|
||||
_FileName = value;
|
||||
}
|
||||
}
|
||||
[Display(Name = "PSBT content")]
|
||||
public string PSBT { get; set; }
|
||||
public List<string> Errors { get; set; } = new List<string>();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace BTCPayServer.Models.WalletViewModels
|
||||
@@ -6,6 +7,7 @@ namespace BTCPayServer.Models.WalletViewModels
|
||||
public class WalletSettingsViewModel
|
||||
{
|
||||
public string Label { get; set; }
|
||||
[DisplayName("Derivation scheme")]
|
||||
public string DerivationScheme { get; set; }
|
||||
public string DerivationSchemeInput { get; set; }
|
||||
[Display(Name = "Is signing key")]
|
||||
@@ -20,9 +22,12 @@ namespace BTCPayServer.Models.WalletViewModels
|
||||
|
||||
public class WalletSettingsAccountKeyViewModel
|
||||
{
|
||||
[DisplayName("Account key")]
|
||||
public string AccountKey { get; set; }
|
||||
[DisplayName("Master fingerprint")]
|
||||
[Validation.HDFingerPrintValidator]
|
||||
public string MasterFingerprint { get; set; }
|
||||
[DisplayName("Account key path")]
|
||||
[Validation.KeyPathValidator]
|
||||
public string AccountKeyPath { get; set; }
|
||||
}
|
||||
|
||||
@@ -502,7 +502,7 @@ namespace BTCPayServer.Payments.PayJoin
|
||||
{
|
||||
var o = new JObject();
|
||||
o.Add(new JProperty("errorCode", PayjoinReceiverHelper.GetErrorCode(error)));
|
||||
if (string.IsNullOrEmpty(debug) || !_env.IsDevelopping)
|
||||
if (string.IsNullOrEmpty(debug) || !_env.IsDeveloping)
|
||||
{
|
||||
o.Add(new JProperty("message", PayjoinReceiverHelper.GetMessage(error)));
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Payments.Bitcoin;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using NBitcoin;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Payments
|
||||
@@ -64,6 +66,19 @@ namespace BTCPayServer.Payments
|
||||
txId = txId.Split('-').First();
|
||||
return string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, txId);
|
||||
}
|
||||
|
||||
public override string GetPaymentLink(BTCPayNetworkBase network, IPaymentMethodDetails paymentMethodDetails,
|
||||
Money cryptoInfoDue, string serverUri)
|
||||
{
|
||||
var bip21 = ((BTCPayNetwork)network).GenerateBIP21(paymentMethodDetails.GetPaymentDestination(), cryptoInfoDue);
|
||||
|
||||
if ((paymentMethodDetails as BitcoinLikeOnChainPaymentMethod)?.PayjoinEnabled is true)
|
||||
{
|
||||
bip21 += $"&{PayjoinClient.BIP21EndpointKey}={serverUri.WithTrailingSlash()}{network.CryptoCode}/{PayjoinClient.BIP21EndpointKey}";
|
||||
}
|
||||
return bip21;
|
||||
}
|
||||
|
||||
public override string InvoiceViewPaymentPartialName { get; } = "ViewBitcoinLikePaymentData";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using NBitcoin;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
@@ -8,13 +10,14 @@ namespace BTCPayServer.Payments
|
||||
public class LightningPaymentType : PaymentType
|
||||
{
|
||||
public static LightningPaymentType Instance { get; } = new LightningPaymentType();
|
||||
|
||||
private LightningPaymentType()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override string ToPrettyString() => "Off-Chain";
|
||||
public override string GetId() => "LightningLike";
|
||||
|
||||
public override CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str)
|
||||
{
|
||||
return ((BTCPayNetwork)network).ToObject<LightningLikePaymentData>(str);
|
||||
@@ -35,7 +38,8 @@ namespace BTCPayServer.Payments
|
||||
return JsonConvert.SerializeObject(details);
|
||||
}
|
||||
|
||||
public override ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network, JToken value)
|
||||
public override ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network,
|
||||
JToken value)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<LightningSupportedPaymentMethod>(value.ToString());
|
||||
}
|
||||
@@ -44,6 +48,14 @@ namespace BTCPayServer.Payments
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string GetPaymentLink(BTCPayNetworkBase network, IPaymentMethodDetails paymentMethodDetails,
|
||||
Money cryptoInfoDue, string serverUri)
|
||||
{
|
||||
return
|
||||
$"lightning:{paymentMethodDetails.GetPaymentDestination().ToUpperInvariant().Replace("LIGHTNING:", "", StringComparison.InvariantCultureIgnoreCase)}";
|
||||
}
|
||||
|
||||
public override string InvoiceViewPaymentPartialName { get; } = "ViewLightningLikePaymentData";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using System;
|
||||
#if ALTCOINS
|
||||
using BTCPayServer.Services.Altcoins.Monero.Payments;
|
||||
#endif
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using NBitcoin;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Payments
|
||||
@@ -31,9 +34,11 @@ namespace BTCPayServer.Payments
|
||||
case "offchain":
|
||||
type = PaymentTypes.LightningLike;
|
||||
break;
|
||||
#if ALTCOINS
|
||||
case "monerolike":
|
||||
type = MoneroPaymentType.Instance;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
type = null;
|
||||
return false;
|
||||
@@ -63,6 +68,8 @@ namespace BTCPayServer.Payments
|
||||
public abstract string SerializePaymentMethodDetails(BTCPayNetworkBase network, IPaymentMethodDetails details);
|
||||
public abstract ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network, JToken value);
|
||||
public abstract string GetTransactionLink(BTCPayNetworkBase network, string txId);
|
||||
public abstract string GetPaymentLink(BTCPayNetworkBase network, IPaymentMethodDetails paymentMethodDetails,
|
||||
Money cryptoInfoDue, string serverUri);
|
||||
public abstract string InvoiceViewPaymentPartialName { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Docker-Regtest": {
|
||||
"Bitcoin": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"BTCPAY_NETWORK": "regtest",
|
||||
"BTCPAY_LAUNCHSETTINGS": "true",
|
||||
"BTCPAY_BUNDLEJSCSS": "false",
|
||||
"BTCPAY_LTCEXPLORERURL": "http://127.0.0.1:32838/",
|
||||
"BTCPAY_BTCLIGHTNING": "type=clightning;server=tcp://127.0.0.1:30993",
|
||||
"BTCPAY_BTCEXTERNALLNDGRPC": "type=lnd-grpc;server=https://lnd:lnd@127.0.0.1:53280/;allowinsecure=true",
|
||||
"BTCPAY_BTCEXTERNALLNDREST": "type=lnd-rest;server=https://lnd:lnd@127.0.0.1:53280/lnd-rest/btc/;allowinsecure=true;macaroonfilepath=D:\\admin.macaroon",
|
||||
@@ -16,15 +15,47 @@
|
||||
"BTCPAY_ALLOW-ADMIN-REGISTRATION": "true",
|
||||
"BTCPAY_DISABLE-REGISTRATION": "false",
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"BTCPAY_CHAINS": "btc,ltc",
|
||||
"BTCPAY_CHAINS": "btc",
|
||||
"BTCPAY_POSTGRES": "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver",
|
||||
"BTCPAY_DEBUGLOG": "debug.log",
|
||||
"BTCPAY_TORRCFILE": "../BTCPayServer.Tests/TestData/Tor/torrc",
|
||||
"BTCPAY_SOCKSENDPOINT": "localhost:9050",
|
||||
"BTCPAY_UPDATEURL": ""
|
||||
},
|
||||
"applicationUrl": "http://127.0.0.1:14142/"
|
||||
},
|
||||
"Bitcoin-HTTPS": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"BTCPAY_NETWORK": "regtest",
|
||||
"BTCPAY_LAUNCHSETTINGS": "true",
|
||||
"BTCPAY_PORT": "14142",
|
||||
"BTCPAY_HttpsUseDefaultCertificate": "true",
|
||||
"BTCPAY_BUNDLEJSCSS": "false",
|
||||
"BTCPAY_BTCLIGHTNING": "type=clightning;server=tcp://127.0.0.1:30993",
|
||||
"BTCPAY_BTCEXTERNALLNDGRPC": "type=lnd-grpc;server=https://lnd:lnd@127.0.0.1:53280/;allowinsecure=true",
|
||||
"BTCPAY_BTCEXTERNALLNDREST": "type=lnd-rest;server=https://lnd:lnd@127.0.0.1:53280/lnd-rest/btc/;allowinsecure=true",
|
||||
"BTCPAY_BTCEXTERNALLNDSEEDBACKUP": "../BTCPayServer.Tests/TestData/LndSeedBackup/walletunlock.json",
|
||||
"BTCPAY_BTCEXTERNALSPARK": "server=/spark/btc/;cookiefile=fake",
|
||||
"BTCPAY_BTCEXTERNALCHARGE": "server=https://127.0.0.1:53280/mycharge/btc/;cookiefilepath=fake",
|
||||
"BTCPAY_EXTERNALCONFIGURATOR": "passwordfile=testpwd;server=/configurator",
|
||||
"BTCPAY_BTCEXPLORERURL": "http://127.0.0.1:32838/",
|
||||
"BTCPAY_ALLOW-ADMIN-REGISTRATION": "true",
|
||||
"BTCPAY_DISABLE-REGISTRATION": "false",
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"BTCPAY_CHAINS": "btc",
|
||||
"BTCPAY_POSTGRES": "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver",
|
||||
"BTCPAY_EXTERNALSERVICES": "totoservice:totolink;",
|
||||
"BTCPAY_SSHCONNECTION": "root@127.0.0.1:21622",
|
||||
"BTCPAY_SSHPASSWORD": "opD3i2282D",
|
||||
"BTCPAY_DEBUGLOG": "debug.log",
|
||||
"BTCPAY_TORRCFILE": "../BTCPayServer.Tests/TestData/Tor/torrc",
|
||||
"BTCPAY_SOCKSENDPOINT": "localhost:9050"
|
||||
},
|
||||
"applicationUrl": "http://127.0.0.1:14142/"
|
||||
"applicationUrl": "https://localhost:14142/"
|
||||
},
|
||||
"Docker-Regtest-https": {
|
||||
"Altcoins-HTTPS": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
|
||||
@@ -58,6 +58,16 @@ namespace BTCPayServer
|
||||
return null;
|
||||
|
||||
var val = Filters[key].First();
|
||||
|
||||
// handle special string values
|
||||
if (val == "-24h")
|
||||
return DateTimeOffset.UtcNow.AddHours(-24).AddMinutes(timezoneOffset);
|
||||
else if (val == "-3d")
|
||||
return DateTimeOffset.UtcNow.AddDays(-3).AddMinutes(timezoneOffset);
|
||||
else if (val == "-7d")
|
||||
return DateTimeOffset.UtcNow.AddDays(-7).AddMinutes(timezoneOffset);
|
||||
|
||||
// default parsing logic
|
||||
var success = DateTimeOffset.TryParse(val, null as IFormatProvider, DateTimeStyles.AssumeUniversal, out var r);
|
||||
if (success)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -16,3 +17,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.Configuration
|
||||
public string WalletDirectory { get; set; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using System;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Configuration;
|
||||
@@ -23,6 +24,7 @@ namespace BTCPayServer.Services.Altcoins.Monero
|
||||
serviceCollection.AddSingleton<MoneroLikePaymentMethodHandler>();
|
||||
serviceCollection.AddSingleton<IPaymentMethodHandler>(provider => provider.GetService<MoneroLikePaymentMethodHandler>());
|
||||
serviceCollection.AddSingleton<IStoreNavExtension, MoneroStoreNavExtension>();
|
||||
serviceCollection.AddSingleton<ISyncSummaryProvider, MoneroSyncSummaryProvider>();
|
||||
|
||||
return serviceCollection;
|
||||
}
|
||||
@@ -67,3 +69,4 @@ namespace BTCPayServer.Services.Altcoins.Monero
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using BTCPayServer.Contracts;
|
||||
|
||||
namespace BTCPayServer.Services.Altcoins.Monero
|
||||
@@ -7,3 +8,4 @@ namespace BTCPayServer.Services.Altcoins.Monero
|
||||
public string Partial { get; } = "Monero/StoreNavMoneroExtension";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using BTCPayServer.Payments;
|
||||
|
||||
namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
@@ -34,3 +35,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
public decimal NextNetworkFee { get; set; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Services.Altcoins.Monero.Utils;
|
||||
@@ -65,3 +66,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -75,20 +76,15 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
public override void PreparePaymentModel(PaymentModel model, InvoiceResponse invoiceResponse, StoreBlob storeBlob)
|
||||
{
|
||||
var paymentMethodId = new PaymentMethodId(model.CryptoCode, PaymentType);
|
||||
|
||||
var client = _moneroRpcProvider.WalletRpcClients[model.CryptoCode];
|
||||
|
||||
var cryptoInfo = invoiceResponse.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
|
||||
var network = _networkProvider.GetNetwork<MoneroLikeSpecificBtcPayNetwork>(model.CryptoCode);
|
||||
model.IsLightning = false;
|
||||
model.PaymentMethodName = GetPaymentMethodName(network);
|
||||
model.CryptoImage = GetCryptoImage(network);
|
||||
model.InvoiceBitcoinUrl = client.SendCommandAsync<MakeUriRequest, MakeUriResponse>("make_uri", new MakeUriRequest()
|
||||
model.InvoiceBitcoinUrl = MoneroPaymentType.Instance.GetPaymentLink(network, new MoneroLikeOnChainPaymentMethodDetails()
|
||||
{
|
||||
Address = cryptoInfo.Address,
|
||||
Amount = MoneroMoney.Convert(decimal.Parse(cryptoInfo.Due, CultureInfo.InvariantCulture))
|
||||
}).GetAwaiter()
|
||||
.GetResult().Uri;
|
||||
DepositAddress = cryptoInfo.Address
|
||||
}, cryptoInfo.Due, null);
|
||||
model.InvoiceBitcoinUrlQR = model.InvoiceBitcoinUrl;
|
||||
}
|
||||
public override string GetCryptoImage(PaymentMethodId paymentMethodId)
|
||||
@@ -128,3 +124,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#if ALTCOINS
|
||||
using System.Globalization;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using NBitcoin;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
@@ -44,6 +46,13 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
return string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, txId);
|
||||
}
|
||||
|
||||
public override string GetPaymentLink(BTCPayNetworkBase network, IPaymentMethodDetails paymentMethodDetails, Money cryptoInfoDue, string serverUri)
|
||||
{
|
||||
return
|
||||
$"{(network as MoneroLikeSpecificBtcPayNetwork).UriScheme}:{paymentMethodDetails.GetPaymentDestination()}?tx_amount={cryptoInfoDue.ToDecimal(MoneyUnit.BTC)}";
|
||||
}
|
||||
|
||||
public override string InvoiceViewPaymentPartialName { get; } = "Monero/ViewMoneroLikePaymentData";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using BTCPayServer.Payments;
|
||||
|
||||
namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
@@ -10,3 +11,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
public PaymentMethodId PaymentId => new PaymentMethodId(CryptoCode, MoneroPaymentType.Instance);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using BTCPayServer.Filters;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@@ -36,3 +37,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.RPC
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
namespace BTCPayServer.Services.Altcoins.Monero.RPC
|
||||
{
|
||||
public class MoneroEvent
|
||||
@@ -13,3 +14,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.RPC
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -64,3 +65,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@@ -374,3 +375,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Immutable;
|
||||
@@ -63,7 +64,7 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
||||
await daemonRpcClient.SendCommandAsync<JsonRpcClient.NoRequestModel, SyncInfoResponse>("sync_info",
|
||||
JsonRpcClient.NoRequestModel.Instance);
|
||||
summary.TargetHeight = daemonResult.TargetHeight ?? daemonResult.Height;
|
||||
summary.Synced = daemonResult.Height >= summary.TargetHeight && (summary.TargetHeight > 0 || _btcPayServerEnvironment.IsDevelopping);
|
||||
summary.Synced = daemonResult.Height >= summary.TargetHeight && (summary.TargetHeight > 0 || _btcPayServerEnvironment.IsDeveloping);
|
||||
summary.CurrentHeight = daemonResult.Height;
|
||||
summary.UpdatedAt = DateTime.Now;
|
||||
summary.DaemonAvailable = true;
|
||||
@@ -117,3 +118,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#if ALTCOINS
|
||||
using System.Linq;
|
||||
using BTCPayServer.Contracts;
|
||||
|
||||
namespace BTCPayServer.Services.Altcoins.Monero.Services
|
||||
{
|
||||
public class MoneroSyncSummaryProvider : ISyncSummaryProvider
|
||||
{
|
||||
private readonly MoneroRPCProvider _moneroRpcProvider;
|
||||
|
||||
public MoneroSyncSummaryProvider(MoneroRPCProvider moneroRpcProvider)
|
||||
{
|
||||
_moneroRpcProvider = moneroRpcProvider;
|
||||
}
|
||||
|
||||
public bool AllAvailable()
|
||||
{
|
||||
return _moneroRpcProvider.Summaries.All(pair => pair.Value.WalletAvailable);
|
||||
}
|
||||
|
||||
public string Partial { get; } = "Monero/MoneroSyncSummary";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
@@ -302,3 +303,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.UI
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using System;
|
||||
|
||||
namespace BTCPayServer.Services.Altcoins.Monero.UI
|
||||
@@ -13,3 +14,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.UI
|
||||
public string TransactionLink { get; set; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace BTCPayServer.Services
|
||||
{
|
||||
public BTCPayNetworkJsonSerializerSettings(BTCPayNetworkProvider networkProvider, IEnumerable<IJsonConverterRegistration> jsonSerializers)
|
||||
{
|
||||
foreach (var network in networkProvider.UnfilteredNetworks.GetAll().OfType<BTCPayNetwork>())
|
||||
foreach (var network in networkProvider.GetAll().OfType<BTCPayNetwork>())
|
||||
{
|
||||
var serializer = new JsonSerializerSettings();
|
||||
foreach (var jsonSerializer in jsonSerializers)
|
||||
|
||||
@@ -22,6 +22,12 @@ namespace BTCPayServer.Services
|
||||
#else
|
||||
Build = "Release";
|
||||
#endif
|
||||
#if ALTCOINS
|
||||
AltcoinsVersion = true;
|
||||
#else
|
||||
AltcoinsVersion = false;
|
||||
#endif
|
||||
|
||||
Environment = env;
|
||||
NetworkType = provider.NetworkType;
|
||||
this.torServices = torServices;
|
||||
@@ -46,8 +52,9 @@ namespace BTCPayServer.Services
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public bool AltcoinsVersion { get; set; }
|
||||
|
||||
public bool IsDevelopping
|
||||
public bool IsDeveloping
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -72,6 +79,8 @@ namespace BTCPayServer.Services
|
||||
{
|
||||
StringBuilder txt = new StringBuilder();
|
||||
txt.Append($"@Copyright BTCPayServer v{Version}");
|
||||
if (AltcoinsVersion)
|
||||
txt.Append($" (altcoins)");
|
||||
if (!Environment.IsProduction() || !Build.Equals("Release", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
txt.Append($" Environment: {Environment.EnvironmentName} Build: {Build}");
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
// Ref: https://www.codeproject.com/Articles/566656/CSV-Serializer-for-NET
|
||||
namespace BTCPayServer.Services.Invoices.Export
|
||||
{
|
||||
/// <summary>
|
||||
/// Serialize and Deserialize Lists of any object type to CSV.
|
||||
/// </summary>
|
||||
public class CsvSerializer<T> where T : class, new()
|
||||
{
|
||||
private readonly List<PropertyInfo> _properties;
|
||||
|
||||
public bool IgnoreEmptyLines { get; set; } = true;
|
||||
public bool IgnoreReferenceTypesExceptString { get; set; } = true;
|
||||
public string NewlineReplacement { get; set; } = ((char)0x254).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
public char Separator { get; set; } = ',';
|
||||
|
||||
public string RowNumberColumnTitle { get; set; } = "RowNumber";
|
||||
public bool UseLineNumbers { get; set; } = false;
|
||||
public bool UseEofLiteral { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Csv Serializer
|
||||
/// Initialize by selected properties from the type to be de/serialized
|
||||
/// </summary>
|
||||
public CsvSerializer()
|
||||
{
|
||||
var type = typeof(T);
|
||||
|
||||
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance
|
||||
| BindingFlags.GetProperty | BindingFlags.SetProperty);
|
||||
|
||||
|
||||
var q = properties.AsQueryable();
|
||||
|
||||
if (IgnoreReferenceTypesExceptString)
|
||||
{
|
||||
q = q.Where(a => a.PropertyType.IsValueType || a.PropertyType.Name == "String");
|
||||
}
|
||||
|
||||
var r = from a in q
|
||||
where a.GetCustomAttribute<CsvIgnoreAttribute>() == null
|
||||
select a;
|
||||
|
||||
_properties = r.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serialize
|
||||
/// </summary>
|
||||
/// <param name="stream">stream</param>
|
||||
/// <param name="data">data</param>
|
||||
public string Serialize(IList<T> data)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var values = new List<string>();
|
||||
|
||||
sb.AppendLine(GetHeader());
|
||||
|
||||
var row = 1;
|
||||
foreach (var item in data)
|
||||
{
|
||||
values.Clear();
|
||||
|
||||
if (UseLineNumbers)
|
||||
{
|
||||
values.Add(row++.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
foreach (var p in _properties)
|
||||
{
|
||||
var raw = p.GetValue(item);
|
||||
var value = raw == null ? "" :
|
||||
raw.ToString()
|
||||
.Replace("\"", "``", StringComparison.OrdinalIgnoreCase)
|
||||
.Replace(Environment.NewLine, NewlineReplacement, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
value = String.Format(CultureInfo.InvariantCulture, "\"{0}\"", value);
|
||||
|
||||
values.Add(value);
|
||||
}
|
||||
sb.AppendLine(String.Join(Separator.ToString(CultureInfo.InvariantCulture), values.ToArray()));
|
||||
}
|
||||
|
||||
if (UseEofLiteral)
|
||||
{
|
||||
values.Clear();
|
||||
|
||||
if (UseLineNumbers)
|
||||
{
|
||||
values.Add(row++.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
values.Add("EOF");
|
||||
|
||||
sb.AppendLine(string.Join(Separator.ToString(CultureInfo.InvariantCulture), values.ToArray()));
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Header
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private string GetHeader()
|
||||
{
|
||||
var header = _properties.Select(a => a.Name);
|
||||
|
||||
if (UseLineNumbers)
|
||||
{
|
||||
header = new string[] { RowNumberColumnTitle }.Union(header);
|
||||
}
|
||||
|
||||
return string.Join(Separator.ToString(CultureInfo.InvariantCulture), header.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public class CsvIgnoreAttribute : Attribute { }
|
||||
|
||||
public class InvalidCsvFormatException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Invalid Csv Format Exception
|
||||
/// </summary>
|
||||
/// <param name="message">message</param>
|
||||
public InvalidCsvFormatException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidCsvFormatException(string message, Exception ex)
|
||||
: base(message, ex)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using CsvHelper.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Services.Invoices.Export
|
||||
@@ -42,10 +44,15 @@ namespace BTCPayServer.Services.Invoices.Export
|
||||
|
||||
private string processCsv(List<ExportInvoiceHolder> invoices)
|
||||
{
|
||||
var serializer = new CsvSerializer<ExportInvoiceHolder>();
|
||||
var csv = serializer.Serialize(invoices);
|
||||
|
||||
return csv;
|
||||
using StringWriter writer = new StringWriter();
|
||||
using var csvWriter = new CsvHelper.CsvWriter(writer, new CsvConfiguration(CultureInfo.InvariantCulture), true);
|
||||
csvWriter.WriteHeader<ExportInvoiceHolder>();
|
||||
foreach (var invoice in invoices)
|
||||
{
|
||||
csvWriter.WriteRecord(invoice);
|
||||
}
|
||||
csvWriter.Flush();
|
||||
return writer.ToString();
|
||||
}
|
||||
|
||||
private IEnumerable<ExportInvoiceHolder> convertFromDb(InvoiceEntity invoice)
|
||||
|
||||
@@ -456,7 +456,8 @@ namespace BTCPayServer.Services.Invoices
|
||||
{
|
||||
cryptoInfo.PaymentUrls = new InvoicePaymentUrls()
|
||||
{
|
||||
BOLT11 = $"lightning:{cryptoInfo.Address}"
|
||||
BOLT11 = paymentId.PaymentType.GetPaymentLink(info.Network, details, cryptoInfo.Due,
|
||||
ServerUrl)
|
||||
};
|
||||
}
|
||||
else if (paymentId.PaymentType == PaymentTypes.BTCLike)
|
||||
@@ -466,15 +467,10 @@ namespace BTCPayServer.Services.Invoices
|
||||
minerInfo.SatoshiPerBytes = ((BitcoinLikeOnChainPaymentMethod)details).FeeRate
|
||||
.GetFee(1).Satoshi;
|
||||
dto.MinerFees.TryAdd(cryptoInfo.CryptoCode, minerInfo);
|
||||
var bip21 = ((BTCPayNetwork)info.Network).GenerateBIP21(cryptoInfo.Address, cryptoInfo.Due);
|
||||
|
||||
if ((details as BitcoinLikeOnChainPaymentMethod)?.PayjoinEnabled is true)
|
||||
cryptoInfo.PaymentUrls = new InvoicePaymentUrls()
|
||||
{
|
||||
bip21 += $"&{PayjoinClient.BIP21EndpointKey}={ServerUrl.WithTrailingSlash()}{cryptoCode}/{PayjoinClient.BIP21EndpointKey}";
|
||||
}
|
||||
cryptoInfo.PaymentUrls = new NBitpayClient.InvoicePaymentUrls()
|
||||
{
|
||||
BIP21 = bip21,
|
||||
BIP21 = paymentId.PaymentType.GetPaymentLink(info.Network, details, cryptoInfo.Due,
|
||||
ServerUrl)
|
||||
};
|
||||
|
||||
#pragma warning disable 618
|
||||
@@ -558,7 +554,12 @@ namespace BTCPayServer.Services.Invoices
|
||||
r.CryptoCode = paymentMethodId.CryptoCode;
|
||||
r.PaymentType = paymentMethodId.PaymentType.ToString();
|
||||
r.ParentEntity = this;
|
||||
r.Network = Networks?.UnfilteredNetworks.GetNetwork<BTCPayNetworkBase>(r.CryptoCode);
|
||||
if (Networks != null)
|
||||
{
|
||||
r.Network = Networks.GetNetwork<BTCPayNetworkBase>(r.CryptoCode);
|
||||
if (r.Network is null)
|
||||
continue;
|
||||
}
|
||||
paymentMethods.Add(r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ retry:
|
||||
catch when (retryCount++ < 5) { goto retry; }
|
||||
_IndexerThread = new CustomThreadPool(1, "Invoice Indexer");
|
||||
_ContextFactory = contextFactory;
|
||||
_Networks = networks.UnfilteredNetworks;
|
||||
_Networks = networks;
|
||||
}
|
||||
|
||||
public InvoiceEntity CreateNewInvoice()
|
||||
@@ -527,7 +527,9 @@ retry:
|
||||
|
||||
private IQueryable<Data.InvoiceData> GetInvoiceQuery(ApplicationDbContext context, InvoiceQuery queryObject)
|
||||
{
|
||||
IQueryable<Data.InvoiceData> query = context.Invoices;
|
||||
IQueryable<Data.InvoiceData> query = queryObject.UserId is null
|
||||
? context.Invoices
|
||||
: context.UserStore.Where(u => u.ApplicationUserId == queryObject.UserId).SelectMany(c => c.StoreData.Invoices);
|
||||
|
||||
if (!queryObject.IncludeArchived)
|
||||
{
|
||||
@@ -546,11 +548,6 @@ retry:
|
||||
query = query.Where(i => stores.Contains(i.StoreDataId));
|
||||
}
|
||||
|
||||
if (queryObject.UserId != null)
|
||||
{
|
||||
query = query.Where(i => i.StoreData.UserStores.Any(u => u.ApplicationUserId == queryObject.UserId));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(queryObject.TextSearch))
|
||||
{
|
||||
var ids = new HashSet<string>(SearchInvoice(queryObject.TextSearch)).ToArray();
|
||||
@@ -605,7 +602,6 @@ retry:
|
||||
|
||||
if (queryObject.Count != null)
|
||||
query = query.Take(queryObject.Count.Value);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@@ -628,7 +624,6 @@ retry:
|
||||
query = query.Include(o => o.HistoricalAddressInvoices).Include(o => o.AddressInvoices);
|
||||
if (queryObject.IncludeEvents)
|
||||
query = query.Include(o => o.Events);
|
||||
|
||||
var data = await query.ToArrayAsync().ConfigureAwait(false);
|
||||
return data.Select(ToEntity).ToArray();
|
||||
}
|
||||
|
||||
22
BTCPayServer/Services/NBXSyncSummaryProvider.cs
Normal file
22
BTCPayServer/Services/NBXSyncSummaryProvider.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using BTCPayServer.Contracts;
|
||||
using BTCPayServer.HostedServices;
|
||||
|
||||
namespace BTCPayServer.Services
|
||||
{
|
||||
public class NBXSyncSummaryProvider : ISyncSummaryProvider
|
||||
{
|
||||
private readonly NBXplorerDashboard _nbXplorerDashboard;
|
||||
|
||||
public NBXSyncSummaryProvider(NBXplorerDashboard nbXplorerDashboard)
|
||||
{
|
||||
_nbXplorerDashboard = nbXplorerDashboard;
|
||||
}
|
||||
|
||||
public bool AllAvailable()
|
||||
{
|
||||
return _nbXplorerDashboard.IsFullySynched();
|
||||
}
|
||||
|
||||
public string Partial { get; } = "NBXSyncSummary";
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@ namespace BTCPayServer.Services
|
||||
public bool AllowHotWalletForAll { get; set; }
|
||||
[Display(Name = "Allow non-admins to import their hot wallets to the node wallet")]
|
||||
public bool AllowHotWalletRPCImportForAll { get; set; }
|
||||
[Display(Name = "Check releases on GitHub and alert when new BTCPayServer version is available")]
|
||||
public bool CheckForNewVersions { get; set; }
|
||||
|
||||
[Display(Name = "Display app on website root")]
|
||||
public string RootAppId { get; set; }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user