mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2024-11-19 09:54:30 +01:00
Merge pull request #1782 from xpayserver/btc-only
Add Bitcoin Only Build
This commit is contained in:
commit
3ce16dc9a3
@ -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
|
||||
|
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -17,7 +17,7 @@
|
||||
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
"pattern": "\\bListening on\\s+(https?://\\S+)"
|
||||
},
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
|
@ -45,6 +45,7 @@ namespace BTCPayServer
|
||||
_NBXplorerNetworkProvider = new NBXplorerNetworkProvider(networkType);
|
||||
NetworkType = networkType;
|
||||
InitBitcoin();
|
||||
#if ALTCOINS
|
||||
InitLiquid();
|
||||
InitLiquidAssets();
|
||||
InitLitecoin();
|
||||
@ -80,6 +81,7 @@ namespace BTCPayServer
|
||||
// Disabled because of https://twitter.com/Cryptopia_NZ/status/1085084168852291586
|
||||
//InitBitcoinplus();
|
||||
//InitUfo();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -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.UnfilteredNetworks.GetAll().OfType<ElementsBTCPayNetwork>()
|
||||
.Where(network => parentChains.Contains(network.NetworkCryptoCode)).Select(network => network.CryptoCode.ToUpperInvariant());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -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" />
|
||||
|
||||
|
@ -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"]
|
||||
|
@ -31,6 +31,12 @@ docker-compose down --v
|
||||
|
||||
You can run tests on `MySql` database instead of `Postgres` by setting environnement variable `TESTS_DB` equals to `MySql`.
|
||||
|
||||
# How to test altcoins
|
||||
|
||||
Follow the above instruction except the `docker-compose` command should be `docker-compose -f docker-compose.altcoins.yml`.
|
||||
|
||||
This will run monero, ltc and liquid dependencies.
|
||||
|
||||
## How to manually test payments
|
||||
|
||||
### Using the test bitcoin-cli
|
||||
|
@ -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();
|
||||
|
||||
|
@ -203,87 +203,6 @@ namespace BTCPayServer.Tests
|
||||
Assert.False(attribute.IsValid("httpdsadsa.com"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanCalculateCryptoDue2()
|
||||
{
|
||||
#pragma warning disable CS0618
|
||||
var dummy = new Key().PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.RegTest).ToString();
|
||||
var networkProvider = new BTCPayNetworkProvider(NetworkType.Regtest);
|
||||
var paymentMethodHandlerDictionary = new PaymentMethodHandlerDictionary(new IPaymentMethodHandler[]
|
||||
{
|
||||
new BitcoinLikePaymentHandler(null, networkProvider, null, null, null),
|
||||
new LightningLikePaymentHandler(null, null, networkProvider, null),
|
||||
});
|
||||
var networkBTC = networkProvider.GetNetwork("BTC");
|
||||
var networkLTC = networkProvider.GetNetwork("LTC");
|
||||
InvoiceEntity invoiceEntity = new InvoiceEntity();
|
||||
invoiceEntity.Networks = networkProvider;
|
||||
invoiceEntity.Payments = new System.Collections.Generic.List<PaymentEntity>();
|
||||
invoiceEntity.ProductInformation = new ProductInformation() { Price = 100 };
|
||||
PaymentMethodDictionary paymentMethods = new PaymentMethodDictionary();
|
||||
paymentMethods.Add(new PaymentMethod() { Network = networkBTC, CryptoCode = "BTC", Rate = 10513.44m, }
|
||||
.SetPaymentMethodDetails(
|
||||
new BTCPayServer.Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod()
|
||||
{
|
||||
NextNetworkFee = Money.Coins(0.00000100m),
|
||||
DepositAddress = dummy
|
||||
}));
|
||||
paymentMethods.Add(new PaymentMethod() { Network = networkLTC, CryptoCode = "LTC", Rate = 216.79m }
|
||||
.SetPaymentMethodDetails(
|
||||
new BTCPayServer.Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod()
|
||||
{
|
||||
NextNetworkFee = Money.Coins(0.00010000m),
|
||||
DepositAddress = dummy
|
||||
}));
|
||||
invoiceEntity.SetPaymentMethods(paymentMethods);
|
||||
|
||||
var btc = invoiceEntity.GetPaymentMethod(new PaymentMethodId("BTC", PaymentTypes.BTCLike));
|
||||
var accounting = btc.Calculate();
|
||||
|
||||
invoiceEntity.Payments.Add(
|
||||
new PaymentEntity()
|
||||
{
|
||||
Accounted = true,
|
||||
CryptoCode = "BTC",
|
||||
NetworkFee = 0.00000100m,
|
||||
Network = networkProvider.GetNetwork("BTC"),
|
||||
}
|
||||
.SetCryptoPaymentData(new BitcoinLikePaymentData()
|
||||
{
|
||||
Network = networkProvider.GetNetwork("BTC"),
|
||||
Output = new TxOut() { Value = Money.Coins(0.00151263m) }
|
||||
}));
|
||||
accounting = btc.Calculate();
|
||||
invoiceEntity.Payments.Add(
|
||||
new PaymentEntity()
|
||||
{
|
||||
Accounted = true,
|
||||
CryptoCode = "BTC",
|
||||
NetworkFee = 0.00000100m,
|
||||
Network = networkProvider.GetNetwork("BTC")
|
||||
}
|
||||
.SetCryptoPaymentData(new BitcoinLikePaymentData()
|
||||
{
|
||||
Network = networkProvider.GetNetwork("BTC"),
|
||||
Output = new TxOut() { Value = accounting.Due }
|
||||
}));
|
||||
accounting = btc.Calculate();
|
||||
Assert.Equal(Money.Zero, accounting.Due);
|
||||
Assert.Equal(Money.Zero, accounting.DueUncapped);
|
||||
|
||||
var ltc = invoiceEntity.GetPaymentMethod(new PaymentMethodId("LTC", PaymentTypes.BTCLike));
|
||||
accounting = ltc.Calculate();
|
||||
|
||||
Assert.Equal(Money.Zero, accounting.Due);
|
||||
// LTC might have over paid due to BTC paying above what it should (round 1 satoshi up)
|
||||
Assert.True(accounting.DueUncapped < Money.Zero);
|
||||
|
||||
var paymentMethod = InvoiceWatcher.GetNearestClearedPayment(paymentMethods, out var accounting2);
|
||||
Assert.Equal(btc.CryptoCode, paymentMethod.CryptoCode);
|
||||
#pragma warning restore CS0618
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanParseTorrc()
|
||||
@ -1816,76 +1735,6 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
[Trait("Altcoins", "Altcoins")]
|
||||
public async Task CanHaveLTCOnlyStore()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.ActivateLTC();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("LTC");
|
||||
|
||||
// First we try payment with a merchant having only BTC
|
||||
var invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
{
|
||||
Price = 500,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
Assert.Single(invoice.CryptoInfo);
|
||||
Assert.Equal("LTC", invoice.CryptoInfo[0].CryptoCode);
|
||||
Assert.True(invoice.PaymentCodes.ContainsKey("LTC"));
|
||||
Assert.True(invoice.SupportedTransactionCurrencies.ContainsKey("LTC"));
|
||||
Assert.True(invoice.SupportedTransactionCurrencies["LTC"].Enabled);
|
||||
Assert.True(invoice.PaymentSubtotals.ContainsKey("LTC"));
|
||||
Assert.True(invoice.PaymentTotals.ContainsKey("LTC"));
|
||||
var cashCow = tester.LTCExplorerNode;
|
||||
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network);
|
||||
var firstPayment = Money.Coins(0.1m);
|
||||
cashCow.SendToAddress(invoiceAddress, firstPayment);
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
invoice = user.BitPay.GetInvoice(invoice.Id);
|
||||
Assert.Equal(firstPayment, invoice.CryptoInfo[0].Paid);
|
||||
});
|
||||
|
||||
Assert.Single(invoice.CryptoInfo); // Only BTC should be presented
|
||||
|
||||
var controller = tester.PayTester.GetController<InvoiceController>(null);
|
||||
var checkout =
|
||||
(Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id, null)
|
||||
.GetAwaiter().GetResult()).Value;
|
||||
Assert.Single(checkout.AvailableCryptos);
|
||||
Assert.Equal("LTC", checkout.CryptoCode);
|
||||
|
||||
//////////////////////
|
||||
|
||||
// Despite it is called BitcoinAddress it should be LTC because BTC is not available
|
||||
Assert.Null(invoice.BitcoinAddress);
|
||||
Assert.NotEqual(1.0m, invoice.Rate);
|
||||
Assert.NotEqual(invoice.BtcDue, invoice.CryptoInfo[0].Due); // Should be BTC rate
|
||||
cashCow.SendToAddress(invoiceAddress, invoice.CryptoInfo[0].Due);
|
||||
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
invoice = user.BitPay.GetInvoice(invoice.Id);
|
||||
Assert.Equal("paid", invoice.Status);
|
||||
checkout = (Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id, null)
|
||||
.GetAwaiter().GetResult()).Value;
|
||||
Assert.Equal("paid", checkout.Status);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanModifyRates()
|
||||
@ -1953,145 +1802,6 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
[Trait("Altcoins", "Altcoins")]
|
||||
public async Task CanPayWithTwoCurrencies()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.ActivateLTC();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
// First we try payment with a merchant having only BTC
|
||||
var invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
{
|
||||
Price = 5000.0m,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
var cashCow = tester.ExplorerNode;
|
||||
cashCow.Generate(2); // get some money in case
|
||||
var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network);
|
||||
var firstPayment = Money.Coins(0.04m);
|
||||
cashCow.SendToAddress(invoiceAddress, firstPayment);
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
invoice = user.BitPay.GetInvoice(invoice.Id);
|
||||
Assert.True(invoice.BtcPaid == firstPayment);
|
||||
});
|
||||
|
||||
Assert.Single(invoice.CryptoInfo); // Only BTC should be presented
|
||||
|
||||
var controller = tester.PayTester.GetController<InvoiceController>(null);
|
||||
var checkout =
|
||||
(Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id, null)
|
||||
.GetAwaiter().GetResult()).Value;
|
||||
Assert.Single(checkout.AvailableCryptos);
|
||||
Assert.Equal("BTC", checkout.CryptoCode);
|
||||
|
||||
Assert.Single(invoice.PaymentCodes);
|
||||
Assert.Single(invoice.SupportedTransactionCurrencies);
|
||||
Assert.Single(invoice.SupportedTransactionCurrencies);
|
||||
Assert.Single(invoice.PaymentSubtotals);
|
||||
Assert.Single(invoice.PaymentTotals);
|
||||
Assert.True(invoice.PaymentCodes.ContainsKey("BTC"));
|
||||
Assert.True(invoice.SupportedTransactionCurrencies.ContainsKey("BTC"));
|
||||
Assert.True(invoice.SupportedTransactionCurrencies["BTC"].Enabled);
|
||||
Assert.True(invoice.PaymentSubtotals.ContainsKey("BTC"));
|
||||
Assert.True(invoice.PaymentTotals.ContainsKey("BTC"));
|
||||
//////////////////////
|
||||
|
||||
// Retry now with LTC enabled
|
||||
user.RegisterDerivationScheme("LTC");
|
||||
invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
{
|
||||
Price = 5000.0m,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
cashCow = tester.ExplorerNode;
|
||||
invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network);
|
||||
firstPayment = Money.Coins(0.04m);
|
||||
cashCow.SendToAddress(invoiceAddress, firstPayment);
|
||||
Logs.Tester.LogInformation("First payment sent to " + invoiceAddress);
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
invoice = user.BitPay.GetInvoice(invoice.Id);
|
||||
Assert.True(invoice.BtcPaid == firstPayment);
|
||||
});
|
||||
|
||||
cashCow = tester.LTCExplorerNode;
|
||||
var ltcCryptoInfo = invoice.CryptoInfo.FirstOrDefault(c => c.CryptoCode == "LTC");
|
||||
Assert.NotNull(ltcCryptoInfo);
|
||||
invoiceAddress = BitcoinAddress.Create(ltcCryptoInfo.Address, cashCow.Network);
|
||||
var secondPayment = Money.Coins(decimal.Parse(ltcCryptoInfo.Due, CultureInfo.InvariantCulture));
|
||||
cashCow.Generate(4); // LTC is not worth a lot, so just to make sure we have money...
|
||||
cashCow.SendToAddress(invoiceAddress, secondPayment);
|
||||
Logs.Tester.LogInformation("Second payment sent to " + invoiceAddress);
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
invoice = user.BitPay.GetInvoice(invoice.Id);
|
||||
Assert.Equal(Money.Zero, invoice.BtcDue);
|
||||
var ltcPaid = invoice.CryptoInfo.First(c => c.CryptoCode == "LTC");
|
||||
Assert.Equal(Money.Zero, ltcPaid.Due);
|
||||
Assert.Equal(secondPayment, ltcPaid.CryptoPaid);
|
||||
Assert.Equal("paid", invoice.Status);
|
||||
Assert.False((bool)((JValue)invoice.ExceptionStatus).Value);
|
||||
});
|
||||
|
||||
controller = tester.PayTester.GetController<InvoiceController>(null);
|
||||
checkout = (Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id, "LTC")
|
||||
.GetAwaiter().GetResult()).Value;
|
||||
Assert.Equal(2, checkout.AvailableCryptos.Count);
|
||||
Assert.Equal("LTC", checkout.CryptoCode);
|
||||
|
||||
|
||||
Assert.Equal(2, invoice.PaymentCodes.Count());
|
||||
Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count());
|
||||
Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count());
|
||||
Assert.Equal(2, invoice.PaymentSubtotals.Count());
|
||||
Assert.Equal(2, invoice.PaymentTotals.Count());
|
||||
Assert.True(invoice.PaymentCodes.ContainsKey("LTC"));
|
||||
Assert.True(invoice.SupportedTransactionCurrencies.ContainsKey("LTC"));
|
||||
Assert.True(invoice.SupportedTransactionCurrencies["LTC"].Enabled);
|
||||
Assert.True(invoice.PaymentSubtotals.ContainsKey("LTC"));
|
||||
Assert.True(invoice.PaymentTotals.ContainsKey("LTC"));
|
||||
|
||||
|
||||
// Check if we can disable LTC
|
||||
invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
{
|
||||
Price = 5000.0m,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true,
|
||||
SupportedTransactionCurrencies = new Dictionary<string, InvoiceSupportedTransactionCurrency>()
|
||||
{
|
||||
{"BTC", new InvoiceSupportedTransactionCurrency() {Enabled = true}}
|
||||
}
|
||||
}, Facade.Merchant);
|
||||
|
||||
Assert.Single(invoice.CryptoInfo.Where(c => c.CryptoCode == "BTC"));
|
||||
Assert.Empty(invoice.CryptoInfo.Where(c => c.CryptoCode == "LTC"));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void HasCurrencyDataForNetworks()
|
||||
@ -2127,305 +1837,6 @@ namespace BTCPayServer.Tests
|
||||
Assert.False(CurrencyValue.TryParse("1.501", out result));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanParseDerivationScheme()
|
||||
{
|
||||
var testnetNetworkProvider = new BTCPayNetworkProvider(NetworkType.Testnet);
|
||||
var regtestNetworkProvider = new BTCPayNetworkProvider(NetworkType.Regtest);
|
||||
var mainnetNetworkProvider = new BTCPayNetworkProvider(NetworkType.Mainnet);
|
||||
var testnetParser = new DerivationSchemeParser(testnetNetworkProvider.GetNetwork<BTCPayNetwork>("BTC"));
|
||||
var mainnetParser = new DerivationSchemeParser(mainnetNetworkProvider.GetNetwork<BTCPayNetwork>("BTC"));
|
||||
NBXplorer.DerivationStrategy.DerivationStrategyBase result;
|
||||
// Passing electrum stuff
|
||||
// Passing a native segwit from mainnet to a testnet parser, means the testnet parser will try to convert it into segwit
|
||||
result = testnetParser.Parse(
|
||||
"zpub6nL6PUGurpU3DfPDSZaRS6WshpbNc9ctCFFzrCn54cssnheM31SZJZUcFHKtjJJNhAueMbh6ptFMfy1aeiMQJr3RJ4DDt1hAPx7sMTKV48t");
|
||||
Assert.Equal(
|
||||
"tpubD93CJNkmGjLXnsBqE2zGDqfEh1Q8iJ8wueordy3SeWt1RngbbuxXCsqASuVWFywmfoCwUE1rSfNJbaH4cBNcbp8WcyZgPiiRSTazLGL8U9w",
|
||||
result.ToString());
|
||||
result = mainnetParser.Parse(
|
||||
"zpub6nL6PUGurpU3DfPDSZaRS6WshpbNc9ctCFFzrCn54cssnheM31SZJZUcFHKtjJJNhAueMbh6ptFMfy1aeiMQJr3RJ4DDt1hAPx7sMTKV48t");
|
||||
Assert.Equal(
|
||||
"xpub68fZn8w5ZTP5X4zymr1B1vKsMtJUiudtN2DZHQzJJc87gW1tXh7S4SALCsQijUzXstg2reVyuZYFuPnTDKXNiNgDZNpNiC4BrVzaaGEaRHj",
|
||||
result.ToString());
|
||||
// P2SH
|
||||
result = testnetParser.Parse(
|
||||
"upub57Wa4MvRPNyAipy1MCpERxcFpHR2ZatyikppkyeWkoRL6QJvLVMo39jYdcaJVxyvBURyRVmErBEA5oGicKBgk1j72GAXSPFH5tUDoGZ8nEu");
|
||||
Assert.Equal(
|
||||
"tpubD6NzVbkrYhZ4YWjDJUACG9E8fJx2NqNY1iynTiPKEjJrzzRKAgha3nNnwGXr2BtvCJKJHW4nmG7rRqc2AGGy2AECgt16seMyV2FZivUmaJg-[p2sh]",
|
||||
result.ToString());
|
||||
|
||||
result = mainnetParser.Parse(
|
||||
"ypub6QqdH2c5z79681jUgdxjGJzGW9zpL4ryPCuhtZE4GpvrJoZqM823XQN6iSQeVbbbp2uCRQ9UgpeMcwiyV6qjvxTWVcxDn2XEAnioMUwsrQ5");
|
||||
Assert.Equal(
|
||||
"xpub661MyMwAqRbcGiYMrHB74DtmLBrNPSsUU6PV7ALAtpYyFhkc6TrUuLhxhET4VgwgQPnPfvYvEAHojf7QmQRj8imudHFoC7hju4f9xxri8wR-[p2sh]",
|
||||
result.ToString());
|
||||
|
||||
// if prefix not recognize, assume it is segwit
|
||||
result = testnetParser.Parse(
|
||||
"xpub661MyMwAqRbcGeVGU5e5KBcau1HHEUGf9Wr7k4FyLa8yRPNQrrVa7Ndrgg8Afbe2UYXMSL6tJBFd2JewwWASsePPLjkcJFL1tTVEs3UQ23X");
|
||||
Assert.Equal(
|
||||
"tpubD6NzVbkrYhZ4YSg7vGdAX6wxE8NwDrmih9SR6cK7gUtsAg37w5LfFpJgviCxC6bGGT4G3uckqH5fiV9ZLN1gm5qgQLVuymzFUR5ed7U7ksu",
|
||||
result.ToString());
|
||||
////////////////
|
||||
|
||||
var tpub =
|
||||
"tpubD6NzVbkrYhZ4Wc65tjhmcKdWFauAo7bGLRTxvggygkNyp6SMGutJp7iociwsinU33jyNBp1J9j2hJH5yQsayfiS3LEU2ZqXodAcnaygra8o";
|
||||
|
||||
result = testnetParser.Parse(tpub);
|
||||
Assert.Equal(tpub, result.ToString());
|
||||
testnetParser.HintScriptPubKey = BitcoinAddress
|
||||
.Create("tb1q4s33amqm8l7a07zdxcunqnn3gcsjcfz3xc573l", testnetParser.Network).ScriptPubKey;
|
||||
result = testnetParser.Parse(tpub);
|
||||
Assert.Equal(tpub, result.ToString());
|
||||
|
||||
testnetParser.HintScriptPubKey = BitcoinAddress
|
||||
.Create("2N2humNio3YTApSfY6VztQ9hQwDnhDvaqFQ", testnetParser.Network).ScriptPubKey;
|
||||
result = testnetParser.Parse(tpub);
|
||||
Assert.Equal($"{tpub}-[p2sh]", result.ToString());
|
||||
|
||||
testnetParser.HintScriptPubKey = BitcoinAddress
|
||||
.Create("mwD8bHS65cdgUf6rZUUSoVhi3wNQFu1Nfi", testnetParser.Network).ScriptPubKey;
|
||||
result = testnetParser.Parse(tpub);
|
||||
Assert.Equal($"{tpub}-[legacy]", result.ToString());
|
||||
|
||||
testnetParser.HintScriptPubKey = BitcoinAddress
|
||||
.Create("2N2humNio3YTApSfY6VztQ9hQwDnhDvaqFQ", testnetParser.Network).ScriptPubKey;
|
||||
result = testnetParser.Parse($"{tpub}-[legacy]");
|
||||
Assert.Equal($"{tpub}-[p2sh]", result.ToString());
|
||||
|
||||
result = testnetParser.Parse(tpub);
|
||||
Assert.Equal($"{tpub}-[p2sh]", result.ToString());
|
||||
|
||||
var regtestParser = new DerivationSchemeParser(regtestNetworkProvider.GetNetwork<BTCPayNetwork>("BTC"));
|
||||
var parsed =
|
||||
regtestParser.Parse(
|
||||
"xpub6DG1rMYXiQtCc6CfdLFD9CtxqhzzRh7j6Sq6EdE9abgYy3cfDRrniLLv2AdwqHL1exiLnnKR5XXcaoiiexf3Y9R6J6rxkJtqJHzNzMW9QMZ-[p2sh]");
|
||||
Assert.Equal(
|
||||
"tpubDDdeNbNDRgqestPX5XEJM8ELAq6eR5cne5RPbBHHvWSSiLHNHehsrn1kGCijMnHFSsFFQMqHcdMfGzDL3pWHRasPMhcGRqZ4tFankQ3i4ok-[p2sh]",
|
||||
parsed.ToString());
|
||||
|
||||
// Let's make sure we can't generate segwit with dogecoin
|
||||
regtestParser = new DerivationSchemeParser(regtestNetworkProvider.GetNetwork<BTCPayNetwork>("DOGE"));
|
||||
parsed = regtestParser.Parse(
|
||||
"xpub6DG1rMYXiQtCc6CfdLFD9CtxqhzzRh7j6Sq6EdE9abgYy3cfDRrniLLv2AdwqHL1exiLnnKR5XXcaoiiexf3Y9R6J6rxkJtqJHzNzMW9QMZ-[p2sh]");
|
||||
Assert.Equal(
|
||||
"tpubDDdeNbNDRgqestPX5XEJM8ELAq6eR5cne5RPbBHHvWSSiLHNHehsrn1kGCijMnHFSsFFQMqHcdMfGzDL3pWHRasPMhcGRqZ4tFankQ3i4ok-[legacy]",
|
||||
parsed.ToString());
|
||||
|
||||
regtestParser = new DerivationSchemeParser(regtestNetworkProvider.GetNetwork<BTCPayNetwork>("DOGE"));
|
||||
parsed = regtestParser.Parse(
|
||||
"tpubDDdeNbNDRgqestPX5XEJM8ELAq6eR5cne5RPbBHHvWSSiLHNHehsrn1kGCijMnHFSsFFQMqHcdMfGzDL3pWHRasPMhcGRqZ4tFankQ3i4ok-[p2sh]");
|
||||
Assert.Equal(
|
||||
"tpubDDdeNbNDRgqestPX5XEJM8ELAq6eR5cne5RPbBHHvWSSiLHNHehsrn1kGCijMnHFSsFFQMqHcdMfGzDL3pWHRasPMhcGRqZ4tFankQ3i4ok-[legacy]",
|
||||
parsed.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
[Trait("Altcoins", "Altcoins")]
|
||||
[Trait("Lightning", "Lightning")]
|
||||
public async Task CanAddDerivationSchemes()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.ActivateLTC();
|
||||
tester.ActivateLightning();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
user.RegisterDerivationScheme("LTC");
|
||||
user.RegisterLightningNode("BTC", LightningConnectionType.CLightning);
|
||||
var btcNetwork = tester.PayTester.Networks.GetNetwork<BTCPayNetwork>("BTC");
|
||||
var invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
{
|
||||
Price = 1.5m,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
Assert.Equal(3, invoice.CryptoInfo.Length);
|
||||
|
||||
var controller = user.GetController<StoresController>();
|
||||
var lightningVM =
|
||||
(LightningNodeViewModel)Assert.IsType<ViewResult>(controller.AddLightningNode(user.StoreId, "BTC"))
|
||||
.Model;
|
||||
Assert.True(lightningVM.Enabled);
|
||||
lightningVM.Enabled = false;
|
||||
controller.AddLightningNode(user.StoreId, lightningVM, "save", "BTC").GetAwaiter().GetResult();
|
||||
lightningVM =
|
||||
(LightningNodeViewModel)Assert.IsType<ViewResult>(controller.AddLightningNode(user.StoreId, "BTC"))
|
||||
.Model;
|
||||
Assert.False(lightningVM.Enabled);
|
||||
|
||||
// Only Enabling/Disabling the payment method must redirect to store page
|
||||
var derivationVM = (DerivationSchemeViewModel)Assert
|
||||
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
|
||||
Assert.True(derivationVM.Enabled);
|
||||
derivationVM.Enabled = false;
|
||||
Assert.IsType<RedirectToActionResult>(controller.AddDerivationScheme(user.StoreId, derivationVM, "BTC")
|
||||
.GetAwaiter().GetResult());
|
||||
derivationVM = (DerivationSchemeViewModel)Assert
|
||||
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
|
||||
Assert.False(derivationVM.Enabled);
|
||||
|
||||
// Clicking next without changing anything should send to the confirmation screen
|
||||
derivationVM = (DerivationSchemeViewModel)Assert
|
||||
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
|
||||
derivationVM = (DerivationSchemeViewModel)Assert.IsType<ViewResult>(controller
|
||||
.AddDerivationScheme(user.StoreId, derivationVM, "BTC").GetAwaiter().GetResult()).Model;
|
||||
Assert.True(derivationVM.Confirmation);
|
||||
|
||||
invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
{
|
||||
Price = 1.5m,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
Assert.Single(invoice.CryptoInfo);
|
||||
Assert.Equal("LTC", invoice.CryptoInfo[0].CryptoCode);
|
||||
|
||||
// Removing the derivation scheme, should redirect to store page
|
||||
var oldScheme = derivationVM.DerivationScheme;
|
||||
derivationVM = (DerivationSchemeViewModel)Assert
|
||||
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
|
||||
derivationVM.DerivationScheme = null;
|
||||
Assert.IsType<RedirectToActionResult>(controller.AddDerivationScheme(user.StoreId, derivationVM, "BTC")
|
||||
.GetAwaiter().GetResult());
|
||||
|
||||
// Setting it again should redirect to the confirmation page
|
||||
derivationVM = (DerivationSchemeViewModel)Assert
|
||||
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
|
||||
derivationVM.DerivationScheme = oldScheme;
|
||||
derivationVM = (DerivationSchemeViewModel)Assert.IsType<ViewResult>(controller
|
||||
.AddDerivationScheme(user.StoreId, derivationVM, "BTC").GetAwaiter().GetResult()).Model;
|
||||
Assert.True(derivationVM.Confirmation);
|
||||
|
||||
|
||||
//cobo vault file
|
||||
var content = "{\"ExtPubKey\":\"xpub6CEqRFZ7yZxCFXuEWZBAdnC8bdvu9SRHevaoU2SsW9ZmKhrCShmbpGZWwaR15hdLURf8hg47g4TpPGaqEU8hw5LEJCE35AUhne67XNyFGBk\",\"MasterFingerprint\":\"7a7563b5\",\"DerivationPath\":\"M\\/84'\\/0'\\/0'\",\"CoboVaultFirmwareVersion\":\"1.2.0(BTC-Only)\"}";
|
||||
derivationVM = (DerivationSchemeViewModel)Assert
|
||||
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
|
||||
derivationVM.WalletFile = TestUtils.GetFormFile("wallet3.json", content);
|
||||
derivationVM.Enabled = true;
|
||||
derivationVM = (DerivationSchemeViewModel)Assert.IsType<ViewResult>(controller
|
||||
.AddDerivationScheme(user.StoreId, derivationVM, "BTC").GetAwaiter().GetResult()).Model;
|
||||
Assert.True(derivationVM.Confirmation);
|
||||
Assert.IsType<RedirectToActionResult>(controller.AddDerivationScheme(user.StoreId, derivationVM, "BTC")
|
||||
.GetAwaiter().GetResult());
|
||||
|
||||
//wasabi wallet file
|
||||
content =
|
||||
"{\r\n \"EncryptedSecret\": \"6PYWBQ1zsukowsnTNA57UUx791aBuJusm7E4egXUmF5WGw3tcdG3cmTL57\",\r\n \"ChainCode\": \"waSIVbn8HaoovoQg/0t8IS1+ZCxGsJRGFT21i06nWnc=\",\r\n \"MasterFingerprint\": \"7a7563b5\",\r\n \"ExtPubKey\": \"xpub6CEqRFZ7yZxCFXuEWZBAdnC8bdvu9SRHevaoU2SsW9ZmKhrCShmbpGZWwaR15hdLURf8hg47g4TpPGaqEU8hw5LEJCE35AUhne67XNyFGBk\",\r\n \"PasswordVerified\": false,\r\n \"MinGapLimit\": 21,\r\n \"AccountKeyPath\": \"84'/0'/0'\",\r\n \"BlockchainState\": {\r\n \"Network\": \"RegTest\",\r\n \"Height\": \"0\"\r\n },\r\n \"HdPubKeys\": []\r\n}";
|
||||
|
||||
derivationVM = (DerivationSchemeViewModel)Assert
|
||||
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
|
||||
derivationVM.WalletFile = TestUtils.GetFormFile("wallet4.json", content);
|
||||
derivationVM.Enabled = true;
|
||||
derivationVM = (DerivationSchemeViewModel)Assert.IsType<ViewResult>(controller
|
||||
.AddDerivationScheme(user.StoreId, derivationVM, "BTC").GetAwaiter().GetResult()).Model;
|
||||
Assert.True(derivationVM.Confirmation);
|
||||
Assert.IsType<RedirectToActionResult>(controller.AddDerivationScheme(user.StoreId, derivationVM, "BTC")
|
||||
.GetAwaiter().GetResult());
|
||||
|
||||
|
||||
// Can we upload coldcard settings? (Should fail, we are giving a mainnet file to a testnet network)
|
||||
derivationVM = (DerivationSchemeViewModel)Assert
|
||||
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
|
||||
content =
|
||||
"{\"keystore\": {\"ckcc_xpub\": \"xpub661MyMwAqRbcGVBsTGeNZN6QGVHmMHLdSA4FteGsRrEriu4pnVZMZWnruFFFXkMnyoBjyHndD3Qwcfz4MPzBUxjSevweNFQx7SAYZATtcDw\", \"xpub\": \"ypub6WWc2gWwHbdnAAyJDnR4SPL1phRh7REqrPBfZeizaQ1EmTshieRXJC3Z5YoU4wkcdKHEjQGkh6AYEzCQC1Kz3DNaWSwdc1pc8416hAjzqyD\", \"label\": \"Coldcard Import 0x60d1af8b\", \"ckcc_xfp\": 1624354699, \"type\": \"hardware\", \"hw_type\": \"coldcard\", \"derivation\": \"m/49'/0'/0'\"}, \"wallet_type\": \"standard\", \"use_encryption\": false, \"seed_version\": 17}";
|
||||
derivationVM.WalletFile = TestUtils.GetFormFile("wallet.json", content);
|
||||
derivationVM = (DerivationSchemeViewModel)Assert.IsType<ViewResult>(controller
|
||||
.AddDerivationScheme(user.StoreId, derivationVM, "BTC").GetAwaiter().GetResult()).Model;
|
||||
Assert.False(derivationVM
|
||||
.Confirmation); // Should fail, we are giving a mainnet file to a testnet network
|
||||
|
||||
// And with a good file? (upub)
|
||||
content =
|
||||
"{\"keystore\": {\"ckcc_xpub\": \"tpubD6NzVbkrYhZ4YHNiuTdTmHRmbcPRLfqgyneZFCL1mkzkUBjXriQShxTh9HL34FK2mhieasJVk9EzJrUfkFqRNQBjiXgx3n5BhPkxKBoFmaS\", \"xpub\": \"upub5DBYp1qGgsTrkzCptMGZc2x18pquLwGrBw6nS59T4NViZ4cni1mGowQzziy85K8vzkp1jVtWrSkLhqk9KDfvrGeB369wGNYf39kX8rQfiLn\", \"label\": \"Coldcard Import 0x60d1af8b\", \"ckcc_xfp\": 1624354699, \"type\": \"hardware\", \"hw_type\": \"coldcard\", \"derivation\": \"m/49'/0'/0'\"}, \"wallet_type\": \"standard\", \"use_encryption\": false, \"seed_version\": 17}";
|
||||
derivationVM = (DerivationSchemeViewModel)Assert
|
||||
.IsType<ViewResult>(await controller.AddDerivationScheme(user.StoreId, "BTC")).Model;
|
||||
derivationVM.WalletFile = TestUtils.GetFormFile("wallet2.json", content);
|
||||
derivationVM.Enabled = true;
|
||||
derivationVM = (DerivationSchemeViewModel)Assert.IsType<ViewResult>(controller
|
||||
.AddDerivationScheme(user.StoreId, derivationVM, "BTC").GetAwaiter().GetResult()).Model;
|
||||
Assert.True(derivationVM.Confirmation);
|
||||
Assert.IsType<RedirectToActionResult>(controller.AddDerivationScheme(user.StoreId, derivationVM, "BTC")
|
||||
.GetAwaiter().GetResult());
|
||||
|
||||
|
||||
// Now let's check that no data has been lost in the process
|
||||
var store = tester.PayTester.StoreRepository.FindStore(user.StoreId).GetAwaiter().GetResult();
|
||||
var onchainBTC = store.GetSupportedPaymentMethods(tester.PayTester.Networks)
|
||||
.OfType<DerivationSchemeSettings>().First(o => o.PaymentId.IsBTCOnChain);
|
||||
DerivationSchemeSettings.TryParseFromWalletFile(content, onchainBTC.Network, out var expected);
|
||||
Assert.Equal(expected.ToJson(), onchainBTC.ToJson());
|
||||
|
||||
// Let's check that the root hdkey and account key path are taken into account when making a PSBT
|
||||
invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
{
|
||||
Price = 1.5m,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
tester.ExplorerNode.Generate(1);
|
||||
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo.First(c => c.CryptoCode == "BTC").Address,
|
||||
tester.ExplorerNode.Network);
|
||||
tester.ExplorerNode.SendToAddress(invoiceAddress, Money.Coins(1m));
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
invoice = user.BitPay.GetInvoice(invoice.Id);
|
||||
Assert.Equal("paid", invoice.Status);
|
||||
});
|
||||
var wallet = tester.PayTester.GetController<WalletsController>();
|
||||
var psbt = wallet.CreatePSBT(btcNetwork, onchainBTC,
|
||||
new WalletSendModel()
|
||||
{
|
||||
Outputs = new List<WalletSendModel.TransactionOutput>()
|
||||
{
|
||||
new WalletSendModel.TransactionOutput()
|
||||
{
|
||||
Amount = 0.5m,
|
||||
DestinationAddress = new Key().PubKey.GetAddress(btcNetwork.NBitcoinNetwork)
|
||||
.ToString(),
|
||||
}
|
||||
},
|
||||
FeeSatoshiPerByte = 1
|
||||
}, default).GetAwaiter().GetResult();
|
||||
|
||||
Assert.NotNull(psbt);
|
||||
|
||||
var root = new Mnemonic(
|
||||
"usage fever hen zero slide mammal silent heavy donate budget pulse say brain thank sausage brand craft about save attract muffin advance illegal cabbage")
|
||||
.DeriveExtKey().AsHDKeyCache();
|
||||
var account = root.Derive(new KeyPath("m/49'/0'/0'"));
|
||||
Assert.All(psbt.PSBT.Inputs, input =>
|
||||
{
|
||||
var keyPath = input.HDKeyPaths.Single();
|
||||
Assert.False(keyPath.Value.KeyPath.IsHardened);
|
||||
Assert.Equal(account.Derive(keyPath.Value.KeyPath).GetPublicKey(), keyPath.Key);
|
||||
Assert.Equal(keyPath.Value.MasterFingerprint,
|
||||
onchainBTC.AccountKeySettings[0].AccountKey.GetPublicKey().GetHDFingerPrint());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanSetPaymentMethodLimits()
|
||||
@ -2493,228 +1904,6 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
[Trait("Altcoins", "Altcoins")]
|
||||
public async Task CanUsePoSApp()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.ActivateLTC();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
user.RegisterDerivationScheme("LTC");
|
||||
var apps = user.GetController<AppsController>();
|
||||
var vm = Assert.IsType<CreateAppViewModel>(Assert.IsType<ViewResult>(apps.CreateApp().Result).Model);
|
||||
vm.Name = "test";
|
||||
vm.SelectedAppType = AppType.PointOfSale.ToString();
|
||||
Assert.IsType<RedirectToActionResult>(apps.CreateApp(vm).Result);
|
||||
var appId = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps().Result).Model)
|
||||
.Apps[0].Id;
|
||||
var vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
|
||||
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
|
||||
vmpos.Title = "hello";
|
||||
vmpos.Currency = "CAD";
|
||||
vmpos.ButtonText = "{0} Purchase";
|
||||
vmpos.CustomButtonText = "Nicolas Sexy Hair";
|
||||
vmpos.CustomTipText = "Wanna tip?";
|
||||
vmpos.CustomTipPercentages = "15,18,20";
|
||||
vmpos.Template = @"
|
||||
apple:
|
||||
price: 5.0
|
||||
title: good apple
|
||||
orange:
|
||||
price: 10.0
|
||||
donation:
|
||||
price: 1.02
|
||||
custom: true
|
||||
";
|
||||
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result);
|
||||
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
|
||||
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
|
||||
Assert.Equal("hello", vmpos.Title);
|
||||
|
||||
var publicApps = user.GetController<AppsPublicController>();
|
||||
var vmview =
|
||||
Assert.IsType<ViewPointOfSaleViewModel>(Assert
|
||||
.IsType<ViewResult>(publicApps.ViewPointOfSale(appId, PosViewType.Cart).Result).Model);
|
||||
Assert.Equal("hello", vmview.Title);
|
||||
Assert.Equal(3, vmview.Items.Length);
|
||||
Assert.Equal("good apple", vmview.Items[0].Title);
|
||||
Assert.Equal("orange", vmview.Items[1].Title);
|
||||
Assert.Equal(10.0m, vmview.Items[1].Price.Value);
|
||||
Assert.Equal("$5.00", vmview.Items[0].Price.Formatted);
|
||||
Assert.Equal("{0} Purchase", vmview.ButtonText);
|
||||
Assert.Equal("Nicolas Sexy Hair", vmview.CustomButtonText);
|
||||
Assert.Equal("Wanna tip?", vmview.CustomTipText);
|
||||
Assert.Equal("15,18,20", string.Join(',', vmview.CustomTipPercentages));
|
||||
Assert.IsType<RedirectToActionResult>(publicApps
|
||||
.ViewPointOfSale(appId, PosViewType.Cart, 0, null, null, null, null, "orange").Result);
|
||||
|
||||
//
|
||||
var invoices = user.BitPay.GetInvoices();
|
||||
var orangeInvoice = invoices.First();
|
||||
Assert.Equal(10.00m, orangeInvoice.Price);
|
||||
Assert.Equal("CAD", orangeInvoice.Currency);
|
||||
Assert.Equal("orange", orangeInvoice.ItemDesc);
|
||||
|
||||
|
||||
Assert.IsType<RedirectToActionResult>(publicApps
|
||||
.ViewPointOfSale(appId, PosViewType.Cart, 0, null, null, null, null, "apple").Result);
|
||||
|
||||
invoices = user.BitPay.GetInvoices();
|
||||
var appleInvoice = invoices.SingleOrDefault(invoice => invoice.ItemCode.Equals("apple"));
|
||||
Assert.NotNull(appleInvoice);
|
||||
Assert.Equal("good apple", appleInvoice.ItemDesc);
|
||||
|
||||
|
||||
// testing custom amount
|
||||
var action = Assert.IsType<RedirectToActionResult>(publicApps
|
||||
.ViewPointOfSale(appId, PosViewType.Cart, 6.6m, null, null, null, null, "donation").Result);
|
||||
Assert.Equal(nameof(InvoiceController.Checkout), action.ActionName);
|
||||
invoices = user.BitPay.GetInvoices();
|
||||
var donationInvoice = invoices.Single(i => i.Price == 6.6m);
|
||||
Assert.NotNull(donationInvoice);
|
||||
Assert.Equal("CAD", donationInvoice.Currency);
|
||||
Assert.Equal("donation", donationInvoice.ItemDesc);
|
||||
|
||||
foreach (var test in new[]
|
||||
{
|
||||
(Code: "EUR", ExpectedSymbol: "€", ExpectedDecimalSeparator: ",", ExpectedDivisibility: 2,
|
||||
ExpectedThousandSeparator: "\xa0", ExpectedPrefixed: false, ExpectedSymbolSpace: true),
|
||||
(Code: "INR", ExpectedSymbol: "₹", ExpectedDecimalSeparator: ".", ExpectedDivisibility: 2,
|
||||
ExpectedThousandSeparator: ",", ExpectedPrefixed: true, ExpectedSymbolSpace: true),
|
||||
(Code: "JPY", ExpectedSymbol: "¥", ExpectedDecimalSeparator: ".", ExpectedDivisibility: 0,
|
||||
ExpectedThousandSeparator: ",", ExpectedPrefixed: true, ExpectedSymbolSpace: false),
|
||||
(Code: "BTC", ExpectedSymbol: "₿", ExpectedDecimalSeparator: ".", ExpectedDivisibility: 8,
|
||||
ExpectedThousandSeparator: ",", ExpectedPrefixed: false, ExpectedSymbolSpace: true),
|
||||
})
|
||||
{
|
||||
Logs.Tester.LogInformation($"Testing for {test.Code}");
|
||||
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
|
||||
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
|
||||
vmpos.Title = "hello";
|
||||
vmpos.Currency = test.Item1;
|
||||
vmpos.ButtonText = "{0} Purchase";
|
||||
vmpos.CustomButtonText = "Nicolas Sexy Hair";
|
||||
vmpos.CustomTipText = "Wanna tip?";
|
||||
vmpos.Template = @"
|
||||
apple:
|
||||
price: 1000.0
|
||||
title: good apple
|
||||
orange:
|
||||
price: 10.0
|
||||
donation:
|
||||
price: 1.02
|
||||
custom: true
|
||||
";
|
||||
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result);
|
||||
publicApps = user.GetController<AppsPublicController>();
|
||||
vmview = Assert.IsType<ViewPointOfSaleViewModel>(Assert
|
||||
.IsType<ViewResult>(publicApps.ViewPointOfSale(appId, PosViewType.Cart).Result).Model);
|
||||
Assert.Equal(test.Code, vmview.CurrencyCode);
|
||||
Assert.Equal(test.ExpectedSymbol,
|
||||
vmview.CurrencySymbol.Replace("¥", "¥")); // Hack so JPY test pass on linux as well);
|
||||
Assert.Equal(test.ExpectedSymbol,
|
||||
vmview.CurrencyInfo.CurrencySymbol
|
||||
.Replace("¥", "¥")); // Hack so JPY test pass on linux as well);
|
||||
Assert.Equal(test.ExpectedDecimalSeparator, vmview.CurrencyInfo.DecimalSeparator);
|
||||
Assert.Equal(test.ExpectedThousandSeparator, vmview.CurrencyInfo.ThousandSeparator);
|
||||
Assert.Equal(test.ExpectedPrefixed, vmview.CurrencyInfo.Prefixed);
|
||||
Assert.Equal(test.ExpectedDivisibility, vmview.CurrencyInfo.Divisibility);
|
||||
Assert.Equal(test.ExpectedSymbolSpace, vmview.CurrencyInfo.SymbolSpace);
|
||||
}
|
||||
|
||||
|
||||
//test inventory related features
|
||||
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
|
||||
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
|
||||
vmpos.Title = "hello";
|
||||
vmpos.Currency = "BTC";
|
||||
vmpos.Template = @"
|
||||
inventoryitem:
|
||||
price: 1.0
|
||||
title: good apple
|
||||
inventory: 1
|
||||
noninventoryitem:
|
||||
price: 10.0";
|
||||
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result);
|
||||
|
||||
//inventoryitem has 1 item available
|
||||
Assert.IsType<RedirectToActionResult>(publicApps
|
||||
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "inventoryitem").Result);
|
||||
//we already bought all available stock so this should fail
|
||||
await Task.Delay(100);
|
||||
Assert.IsType<RedirectToActionResult>(publicApps
|
||||
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "inventoryitem").Result);
|
||||
|
||||
//inventoryitem has unlimited items available
|
||||
Assert.IsType<RedirectToActionResult>(publicApps
|
||||
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "noninventoryitem").Result);
|
||||
Assert.IsType<RedirectToActionResult>(publicApps
|
||||
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "noninventoryitem").Result);
|
||||
|
||||
//verify invoices where created
|
||||
invoices = user.BitPay.GetInvoices();
|
||||
Assert.Equal(2, invoices.Count(invoice => invoice.ItemCode.Equals("noninventoryitem")));
|
||||
var inventoryItemInvoice =
|
||||
Assert.Single(invoices.Where(invoice => invoice.ItemCode.Equals("inventoryitem")));
|
||||
Assert.NotNull(inventoryItemInvoice);
|
||||
|
||||
//let's mark the inventoryitem invoice as invalid, thsi should return the item to back in stock
|
||||
var controller = tester.PayTester.GetController<InvoiceController>(user.UserId, user.StoreId);
|
||||
var appService = tester.PayTester.GetService<AppService>();
|
||||
var eventAggregator = tester.PayTester.GetService<EventAggregator>();
|
||||
Assert.IsType<JsonResult>(await controller.ChangeInvoiceState(inventoryItemInvoice.Id, "invalid"));
|
||||
//check that item is back in stock
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
|
||||
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
|
||||
Assert.Equal(1,
|
||||
appService.Parse(vmpos.Template, "BTC").Single(item => item.Id == "inventoryitem").Inventory);
|
||||
}, 10000);
|
||||
|
||||
|
||||
//test payment methods option
|
||||
|
||||
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert
|
||||
.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
|
||||
vmpos.Title = "hello";
|
||||
vmpos.Currency = "BTC";
|
||||
vmpos.Template = @"
|
||||
btconly:
|
||||
price: 1.0
|
||||
title: good apple
|
||||
payment_methods:
|
||||
- BTC
|
||||
normal:
|
||||
price: 1.0";
|
||||
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result);
|
||||
Assert.IsType<RedirectToActionResult>(publicApps
|
||||
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "btconly").Result);
|
||||
Assert.IsType<RedirectToActionResult>(publicApps
|
||||
.ViewPointOfSale(appId, PosViewType.Cart, 1, null, null, null, null, "normal").Result);
|
||||
invoices = user.BitPay.GetInvoices();
|
||||
var normalInvoice = invoices.Single(invoice => invoice.ItemCode == "normal");
|
||||
var btcOnlyInvoice = invoices.Single(invoice => invoice.ItemCode == "btconly");
|
||||
Assert.Single(btcOnlyInvoice.CryptoInfo);
|
||||
Assert.Equal("BTC",
|
||||
btcOnlyInvoice.CryptoInfo.First().CryptoCode);
|
||||
Assert.Equal(PaymentTypes.BTCLike.ToString(),
|
||||
btcOnlyInvoice.CryptoInfo.First().PaymentType);
|
||||
|
||||
Assert.Equal(2, normalInvoice.CryptoInfo.Length);
|
||||
Assert.Contains(
|
||||
normalInvoice.CryptoInfo,
|
||||
s => PaymentTypes.BTCLike.ToString() == s.PaymentType && new[] { "BTC", "LTC" }.Contains(
|
||||
s.CryptoCode));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public async Task CanScheduleBackgroundTasks()
|
||||
@ -3719,40 +2908,6 @@ normal:
|
||||
Assert.True(settings.AccountDerivation is DirectDerivationStrategy s3 && s3.Segwit);
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
[Trait("Altcoins", "Altcoins")]
|
||||
[Trait("Lightning", "Lightning")]
|
||||
public async Task CanCreateInvoiceWithSpecificPaymentMethods()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.ActivateLightning();
|
||||
tester.ActivateLTC();
|
||||
await tester.StartAsync();
|
||||
await tester.EnsureChannelsSetup();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterLightningNode("BTC", LightningConnectionType.Charge);
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
user.RegisterDerivationScheme("LTC");
|
||||
|
||||
var invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(100, "BTC"));
|
||||
Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count);
|
||||
|
||||
|
||||
invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(100, "BTC")
|
||||
{
|
||||
SupportedTransactionCurrencies = new Dictionary<string, InvoiceSupportedTransactionCurrency>()
|
||||
{
|
||||
{"BTC", new InvoiceSupportedTransactionCurrency() {Enabled = true}}
|
||||
}
|
||||
});
|
||||
|
||||
Assert.Single(invoice.SupportedTransactionCurrencies);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
|
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
|
||||
@ -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,6 +29,21 @@
|
||||
<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" />
|
||||
|
@ -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)
|
||||
{
|
||||
|
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; }
|
||||
}
|
||||
|
||||
}
|
@ -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 _:
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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>();
|
||||
@ -177,6 +181,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>();
|
||||
|
@ -1,5 +1,7 @@
|
||||
using System;
|
||||
#if ALTCOINS
|
||||
using BTCPayServer.Services.Altcoins.Monero.Payments;
|
||||
#endif
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using NBitcoin;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@ -32,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;
|
||||
|
@ -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,7 +15,7 @@
|
||||
"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",
|
||||
@ -24,7 +23,38 @@
|
||||
},
|
||||
"applicationUrl": "http://127.0.0.1:14142/"
|
||||
},
|
||||
"Docker-Regtest-https": {
|
||||
"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": "https://localhost:14142/"
|
||||
},
|
||||
"Altcoins-HTTPS": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
|
@ -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;
|
||||
@ -123,3 +124,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1,3 +1,4 @@
|
||||
#if ALTCOINS
|
||||
using System.Globalization;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
@ -54,3 +55,4 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
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;
|
||||
@ -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
|
||||
|
@ -72,6 +72,9 @@ namespace BTCPayServer.Services
|
||||
{
|
||||
StringBuilder txt = new StringBuilder();
|
||||
txt.Append($"@Copyright BTCPayServer v{Version}");
|
||||
#if ALTCOINS
|
||||
txt.Append($" (altcoins)");
|
||||
#endif
|
||||
if (!Environment.IsProduction() || !Build.Equals("Release", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
txt.Append($" Environment: {Environment.EnvironmentName} Build: {Build}");
|
||||
|
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";
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
@using BTCPayServer.Services.Altcoins.Monero.Services
|
||||
@inject BTCPayServer.HostedServices.NBXplorerDashboard dashboard
|
||||
@inject MoneroRPCProvider MoneroRpcProvider
|
||||
@if (!dashboard.IsFullySynched() || !MoneroRpcProvider.Summaries.All(pair => pair.Value.WalletAvailable))
|
||||
@using BTCPayServer.Contracts
|
||||
@inject IEnumerable<ISyncSummaryProvider> SyncSummaryProviders;
|
||||
@if(SyncSummaryProviders.Any(provider => !provider.AllAvailable()))
|
||||
{
|
||||
<!-- Modal -->
|
||||
<div id="modalDialog" class="modal-dialog animated bounceInRight"
|
||||
@ -14,71 +13,14 @@
|
||||
<h4 class="modal-title">Your nodes are synching...</h4>
|
||||
<button type="button" class="close" onclick="dismissSyncModal()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="modal-body" style="max-height: 400px; overflow-y: scroll;">
|
||||
<p>
|
||||
Your node is synching the entire blockchain and validating the consensus rules...
|
||||
</p>
|
||||
@foreach (var line in dashboard.GetAll().Where(summary => summary.Network.ShowSyncSummary))
|
||||
@foreach (var provider in SyncSummaryProviders)
|
||||
{
|
||||
<h4>@line.Network.CryptoCode</h4>
|
||||
@if (line.Status == null)
|
||||
{
|
||||
<ul>
|
||||
<li>The node is offline</li>
|
||||
@if (line.Error != null)
|
||||
{
|
||||
<li>Last error: @line.Error</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ul>
|
||||
<li>NBXplorer headers height: @line.Status.ChainHeight</li>
|
||||
@if (line.Status.BitcoinStatus == null)
|
||||
{
|
||||
if (line.State == BTCPayServer.HostedServices.NBXplorerState.Synching)
|
||||
{
|
||||
<li>The node is starting...</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li>The node is offline</li>
|
||||
@if (line.Error != null)
|
||||
{
|
||||
<li>Last error: @line.Error</li>
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (line.Status.BitcoinStatus.IsSynched)
|
||||
{
|
||||
<li>The node is synchronized (Height: @line.Status.BitcoinStatus.Headers)</li>
|
||||
@if (line.Status.BitcoinStatus.IsSynched &&
|
||||
line.Status.SyncHeight.HasValue &&
|
||||
line.Status.SyncHeight.Value < line.Status.BitcoinStatus.Headers)
|
||||
{
|
||||
<li>NBXplorer is synchronizing... (Height: @line.Status.SyncHeight.Value)</li>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<li>Node headers height: @line.Status.BitcoinStatus.Headers</li>
|
||||
<li>Validated blocks: @line.Status.BitcoinStatus.Blocks</li>
|
||||
}
|
||||
</ul>
|
||||
@if (!line.Status.IsFullySynched && line.Status.BitcoinStatus != null)
|
||||
{
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="@((int)(line.Status.BitcoinStatus.VerificationProgress * 100))"
|
||||
aria-valuemin="0" aria-valuemax="100" style="width:@((int)(line.Status.BitcoinStatus.VerificationProgress * 100))%">
|
||||
@((int)(line.Status.BitcoinStatus.VerificationProgress * 100))%
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
<partial name="@provider.Partial" />
|
||||
}
|
||||
|
||||
<partial name="Monero/MoneroSyncSummary"/>
|
||||
<p>
|
||||
<a href="https://www.youtube.com/watch?v=OrYDehC-8TU" target="_blank">Watch this video</a> to understand the importance of blockchain synchronization.
|
||||
</p>
|
||||
|
60
BTCPayServer/Views/Shared/NBXSyncSummary.cshtml
Normal file
60
BTCPayServer/Views/Shared/NBXSyncSummary.cshtml
Normal file
@ -0,0 +1,60 @@
|
||||
@inject BTCPayServer.HostedServices.NBXplorerDashboard dashboard;
|
||||
@foreach (var line in dashboard.GetAll().Where(summary => summary.Network.ShowSyncSummary))
|
||||
{
|
||||
<h4>@line.Network.CryptoCode</h4>
|
||||
@if (line.Status == null)
|
||||
{
|
||||
<ul>
|
||||
<li>The node is offline</li>
|
||||
@if (line.Error != null)
|
||||
{
|
||||
<li>Last error: @line.Error</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ul>
|
||||
<li>NBXplorer headers height: @line.Status.ChainHeight</li>
|
||||
@if (line.Status.BitcoinStatus == null)
|
||||
{
|
||||
if (line.State == BTCPayServer.HostedServices.NBXplorerState.Synching)
|
||||
{
|
||||
<li>The node is starting...</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li>The node is offline</li>
|
||||
@if (line.Error != null)
|
||||
{
|
||||
<li>Last error: @line.Error</li>
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (line.Status.BitcoinStatus.IsSynched)
|
||||
{
|
||||
<li>The node is synchronized (Height: @line.Status.BitcoinStatus.Headers)</li>
|
||||
@if (line.Status.BitcoinStatus.IsSynched &&
|
||||
line.Status.SyncHeight.HasValue &&
|
||||
line.Status.SyncHeight.Value < line.Status.BitcoinStatus.Headers)
|
||||
{
|
||||
<li>NBXplorer is synchronizing... (Height: @line.Status.SyncHeight.Value)</li>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<li>Node headers height: @line.Status.BitcoinStatus.Headers</li>
|
||||
<li>Validated blocks: @line.Status.BitcoinStatus.Blocks</li>
|
||||
}
|
||||
</ul>
|
||||
@if (!line.Status.IsFullySynched && line.Status.BitcoinStatus != null)
|
||||
{
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="@((int) (line.Status.BitcoinStatus.VerificationProgress * 100))"
|
||||
aria-valuemin="0" aria-valuemax="100" style="width:@((int) (line.Status.BitcoinStatus.VerificationProgress * 100))%">
|
||||
@((int) (line.Status.BitcoinStatus.VerificationProgress * 100))%
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
@ -5,4 +5,29 @@
|
||||
<NoWarn>NU1701,CA1816,CA1308,CA1810,CA2208,CA1303,CA2000</NoWarn>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Configurations>Debug;Release;Altcoins-Release;Altcoins-Debug</Configurations>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Default similar to Debug/Release -->
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Altcoins-Release' ">
|
||||
<Optimize Condition=" '$(Optimize)' == '' ">true</Optimize>
|
||||
<Altcoins>true</Altcoins>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Altcoins-Debug'">
|
||||
<DefineConstants>$(DefineConstants);DEBUG</DefineConstants>
|
||||
<Altcoins>true</Altcoins>
|
||||
</PropertyGroup>
|
||||
<!-- -->
|
||||
|
||||
<PropertyGroup Condition="( '$(Configuration)' == 'Debug' Or '$(Configuration)' == 'Altcoins-Debug') And '$(RazorCompileOnBuild)' != 'true'">
|
||||
<RazorCompileOnBuild>false</RazorCompileOnBuild>
|
||||
<DefineConstants>$(DefineConstants);RAZOR_RUNTIME_COMPILE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Altcoins)' == 'true'">
|
||||
<DefineConstants>$(DefineConstants);ALTCOINS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
@ -15,7 +15,8 @@ COPY BTCPayServer.Data/. BTCPayServer.Data/.
|
||||
COPY BTCPayServer.Client/. BTCPayServer.Client/.
|
||||
COPY BTCPayServer/. BTCPayServer/.
|
||||
COPY Build/Version.csproj Build/Version.csproj
|
||||
RUN cd BTCPayServer && dotnet publish --output /app/ --configuration Release
|
||||
ARG CONFIGURATION_NAME=Release
|
||||
RUN cd BTCPayServer && dotnet publish --output /app/ --configuration ${CONFIGURATION_NAME}
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.4-buster-slim
|
||||
|
||||
|
@ -19,7 +19,8 @@ COPY BTCPayServer.Data/. BTCPayServer.Data/.
|
||||
COPY BTCPayServer.Client/. BTCPayServer.Client/.
|
||||
COPY BTCPayServer/. BTCPayServer/.
|
||||
COPY Build/Version.csproj Build/Version.csproj
|
||||
RUN cd BTCPayServer && dotnet publish --output /app/ --configuration Release
|
||||
ARG CONFIGURATION_NAME=Release
|
||||
RUN cd BTCPayServer && dotnet publish --output /app/ --configuration ${CONFIGURATION_NAME}
|
||||
|
||||
# Force the builder machine to take make an arm runtime image. This is fine as long as the builder does not run any program
|
||||
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.4-buster-slim-arm32v7
|
||||
|
@ -1,6 +1,7 @@
|
||||
# This is a manifest image, will pull the image with the same arch as the builder machine
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:3.1.202 AS builder
|
||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
ENV LC_ALL en_US.UTF-8
|
||||
RUN apt-get update \
|
||||
&& apt-get install -qq --no-install-recommends qemu qemu-user-static qemu-user binfmt-support
|
||||
|
||||
@ -19,7 +20,8 @@ COPY BTCPayServer.Data/. BTCPayServer.Data/.
|
||||
COPY BTCPayServer.Client/. BTCPayServer.Client/.
|
||||
COPY BTCPayServer/. BTCPayServer/.
|
||||
COPY Build/Version.csproj Build/Version.csproj
|
||||
RUN cd BTCPayServer && dotnet publish --output /app/ --configuration Release
|
||||
ARG CONFIGURATION_NAME=Release
|
||||
RUN cd BTCPayServer && dotnet publish --output /app/ --configuration ${CONFIGURATION_NAME}
|
||||
|
||||
# Force the builder machine to take make an arm runtime image. This is fine as long as the builder does not run any program
|
||||
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.4-buster-slim-arm64v8
|
||||
|
@ -30,6 +30,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BTCPayServer.Client", "BTCP
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Altcoins-Debug|Any CPU = Altcoins-Debug|Any CPU
|
||||
Altcoins-Debug|x64 = Altcoins-Debug|x64
|
||||
Altcoins-Debug|x86 = Altcoins-Debug|x86
|
||||
Altcoins-Release|Any CPU = Altcoins-Release|Any CPU
|
||||
Altcoins-Release|x64 = Altcoins-Release|x64
|
||||
Altcoins-Release|x86 = Altcoins-Release|x86
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
@ -38,6 +44,18 @@ Global
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Altcoins-Debug|x64.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Altcoins-Debug|x64.Build.0 = Altcoins-Debug|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Altcoins-Debug|x86.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Altcoins-Debug|x86.Build.0 = Altcoins-Debug|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Altcoins-Release|x64.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Altcoins-Release|x64.Build.0 = Altcoins-Release|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Altcoins-Release|x86.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Altcoins-Release|x86.Build.0 = Altcoins-Release|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@ -50,6 +68,18 @@ Global
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Release|x64.Build.0 = Release|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{949A0870-8D8C-4DE5-8845-DDD560489177}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Altcoins-Debug|x64.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Altcoins-Debug|x64.Build.0 = Altcoins-Debug|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Altcoins-Debug|x86.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Altcoins-Debug|x86.Build.0 = Altcoins-Debug|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Altcoins-Release|x64.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Altcoins-Release|x64.Build.0 = Altcoins-Release|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Altcoins-Release|x86.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Altcoins-Release|x86.Build.0 = Altcoins-Release|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@ -62,6 +92,18 @@ Global
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B373F439-6E75-4A94-985D-10A0C7C500D0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Altcoins-Debug|x64.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Altcoins-Debug|x64.Build.0 = Altcoins-Debug|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Altcoins-Debug|x86.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Altcoins-Debug|x86.Build.0 = Altcoins-Debug|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Altcoins-Release|x64.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Altcoins-Release|x64.Build.0 = Altcoins-Release|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Altcoins-Release|x86.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Altcoins-Release|x86.Build.0 = Altcoins-Release|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@ -74,6 +116,18 @@ Global
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6DC77459-D52F-45EE-B3F3-315043D33A1B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Altcoins-Debug|x64.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Altcoins-Debug|x64.Build.0 = Altcoins-Debug|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Altcoins-Debug|x86.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Altcoins-Debug|x86.Build.0 = Altcoins-Debug|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Altcoins-Release|x64.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Altcoins-Release|x64.Build.0 = Altcoins-Release|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Altcoins-Release|x86.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Altcoins-Release|x86.Build.0 = Altcoins-Release|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@ -86,6 +140,18 @@ Global
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4BE42370-6114-4176-BFB3-37C6B6DA094D}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Altcoins-Debug|x64.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Altcoins-Debug|x64.Build.0 = Altcoins-Debug|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Altcoins-Debug|x86.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Altcoins-Debug|x86.Build.0 = Altcoins-Debug|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Altcoins-Release|x64.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Altcoins-Release|x64.Build.0 = Altcoins-Release|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Altcoins-Release|x86.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Altcoins-Release|x86.Build.0 = Altcoins-Release|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@ -98,6 +164,18 @@ Global
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4D7A865D-3945-4C70-9CC8-B09A274A697E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Altcoins-Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Altcoins-Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Altcoins-Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Altcoins-Debug|x64.Build.0 = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Altcoins-Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Altcoins-Debug|x86.Build.0 = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Altcoins-Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Altcoins-Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Altcoins-Release|x64.ActiveCfg = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Altcoins-Release|x64.Build.0 = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Altcoins-Release|x86.ActiveCfg = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Altcoins-Release|x86.Build.0 = Release|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{21A13304-7168-49A0-86C2-0A1A9453E9C7}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
|
Loading…
Reference in New Issue
Block a user