Compare commits
23 Commits
v1.0.2.114
...
v1.0.3.2
Author | SHA1 | Date | |
---|---|---|---|
dafd958f69 | |||
f51af6c61c | |||
254db22063 | |||
8be4256278 | |||
8e8669d63f | |||
4625ff92f1 | |||
6aa84326af | |||
9a384d81fe | |||
0cbe36c048 | |||
7f16aa8c7e | |||
872f8a6229 | |||
9b261daa6d | |||
c46c15c258 | |||
a8ba1ed1ed | |||
ff4056d4f3 | |||
ae152c3ffa | |||
e2ff33d7db | |||
ce94c05fd3 | |||
9cde4dc7e2 | |||
ca571cd756 | |||
e5eb0c79c0 | |||
43bd6587d3 | |||
3bb059ab74 |
29
.circleci/config.yml
Normal file
29
.circleci/config.yml
Normal file
@ -0,0 +1,29 @@
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
machine:
|
||||
docker_layer_caching: true
|
||||
steps:
|
||||
- checkout
|
||||
test:
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
lsb_release -a
|
||||
wget -q https://packages.microsoft.com/config/ubuntu/14.04/packages-microsoft-prod.deb
|
||||
sudo dpkg -i packages-microsoft-prod.deb
|
||||
sudo apt-get install apt-transport-https
|
||||
sudo apt-get update
|
||||
sudo apt-get install dotnet-sdk-2.1
|
||||
dotnet build /p:TreatWarningsAsErrors=true
|
||||
cd BTCPayServer.Tests
|
||||
dotnet test --filter Fast=Fast
|
||||
docker-compose up -d dev
|
||||
dotnet test --filter Integration=Integration
|
||||
workflows:
|
||||
version: 2
|
||||
build_and_test:
|
||||
jobs:
|
||||
- test
|
@ -24,6 +24,9 @@
|
||||
<None Update="docker-compose.yml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="xunit.runner.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,4 +1,5 @@
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Hosting;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
@ -35,6 +36,12 @@ using Xunit;
|
||||
|
||||
namespace BTCPayServer.Tests
|
||||
{
|
||||
public enum TestDatabases
|
||||
{
|
||||
Postgres,
|
||||
MySQL,
|
||||
}
|
||||
|
||||
public class BTCPayServerTester : IDisposable
|
||||
{
|
||||
private string _Directory;
|
||||
@ -57,6 +64,11 @@ namespace BTCPayServer.Tests
|
||||
set;
|
||||
}
|
||||
|
||||
public string MySQL
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string Postgres
|
||||
{
|
||||
get; set;
|
||||
@ -68,6 +80,10 @@ namespace BTCPayServer.Tests
|
||||
get; set;
|
||||
}
|
||||
|
||||
public TestDatabases TestDatabase
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public bool MockRates { get; set; } = true;
|
||||
|
||||
@ -94,7 +110,9 @@ namespace BTCPayServer.Tests
|
||||
|
||||
config.AppendLine($"btc.lightning={IntegratedLightning.AbsoluteUri}");
|
||||
|
||||
if (Postgres != null)
|
||||
if (TestDatabase == TestDatabases.MySQL && !String.IsNullOrEmpty(MySQL))
|
||||
config.AppendLine($"mysql=" + MySQL);
|
||||
else if (!String.IsNullOrEmpty(Postgres))
|
||||
config.AppendLine($"postgres=" + Postgres);
|
||||
var confPath = Path.Combine(chainDirectory, "settings.config");
|
||||
File.WriteAllText(confPath, config.ToString());
|
||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Controllers;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Models.StoreViewModels;
|
||||
using BTCPayServer.Payments.Changelly;
|
||||
@ -27,6 +28,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async void CanSetChangellyPaymentMethod()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -67,6 +69,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async void CanToggleChangellyPaymentMethod()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -82,6 +85,7 @@ namespace BTCPayServer.Tests
|
||||
ApiKey = "key",
|
||||
ApiUrl = "http://gozo.com",
|
||||
ChangellyMerchantId = "aaa",
|
||||
Enabled = true
|
||||
};
|
||||
Assert.Equal("UpdateStore", Assert.IsType<RedirectToActionResult>(
|
||||
await controller.UpdateChangellySettings(user.StoreId, updateModel, "save")).ActionName);
|
||||
@ -103,6 +107,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async void CannotUseChangellyApiWithoutChangellyPaymentMethodSet()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -112,16 +117,14 @@ namespace BTCPayServer.Tests
|
||||
user.GrantAccess();
|
||||
var changellyController =
|
||||
tester.PayTester.GetController<ChangellyController>(user.UserId, user.StoreId);
|
||||
changellyController.IsTest = true;
|
||||
|
||||
//test non existing payment method
|
||||
Assert.IsType<BitpayErrorModel>(Assert
|
||||
.IsType<BadRequestObjectResult>(await changellyController.GetCurrencyList(user.StoreId))
|
||||
.Value);
|
||||
|
||||
var updateModel = new UpdateChangellySettingsViewModel
|
||||
{
|
||||
Enabled = false
|
||||
};
|
||||
var updateModel = CreateDefaultChangellyParams(false);
|
||||
var storesController = tester.PayTester.GetController<StoresController>(user.UserId, user.StoreId);
|
||||
//set payment method but disabled
|
||||
|
||||
@ -140,7 +143,6 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal("UpdateStore", Assert.IsType<RedirectToActionResult>(
|
||||
await storesController.UpdateChangellySettings(user.StoreId, updateModel, "save")).ActionName);
|
||||
|
||||
|
||||
|
||||
Assert.IsNotType<BitpayErrorModel>(Assert
|
||||
.IsType<OkObjectResult>(await changellyController.GetCurrencyList(user.StoreId))
|
||||
@ -148,8 +150,19 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
UpdateChangellySettingsViewModel CreateDefaultChangellyParams(bool enabled)
|
||||
{
|
||||
return new UpdateChangellySettingsViewModel()
|
||||
{
|
||||
ApiKey = "6ed02cdf1b614d89a8c0ceb170eebb61",
|
||||
ApiSecret = "8fbd66a2af5fd15a6b5f8ed0159c5842e32a18538521ffa145bd6c9e124d3483",
|
||||
ChangellyMerchantId = "804298eb5753",
|
||||
Enabled = enabled
|
||||
};
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async void CanGetCurrencyListFromChangelly()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -159,50 +172,30 @@ namespace BTCPayServer.Tests
|
||||
user.GrantAccess();
|
||||
|
||||
//save changelly settings
|
||||
var updateModel = new UpdateChangellySettingsViewModel()
|
||||
{
|
||||
ApiSecret = "secret",
|
||||
ApiKey = "key",
|
||||
ApiUrl = "http://gozo.com",
|
||||
ChangellyMerchantId = "aaa"
|
||||
};
|
||||
var updateModel = CreateDefaultChangellyParams(true);
|
||||
var storesController = tester.PayTester.GetController<StoresController>(user.UserId, user.StoreId);
|
||||
|
||||
//confirm saved
|
||||
Assert.Equal("UpdateStore", Assert.IsType<RedirectToActionResult>(
|
||||
await storesController.UpdateChangellySettings(user.StoreId, updateModel, "save")).ActionName);
|
||||
|
||||
|
||||
var mockChangelly = new MockChangelly(new MockHttpClientFactory(), updateModel.ApiKey, updateModel.ApiSecret, updateModel.ApiUrl);
|
||||
var mock = new MockChangellyClientProvider(mockChangelly, tester.PayTester.StoreRepository);
|
||||
|
||||
var factory = UnitTest1.CreateBTCPayRateFactory();
|
||||
var fetcher = new RateFetcher(factory);
|
||||
|
||||
var changellyController = new ChangellyController(mock, tester.NetworkProvider, fetcher);
|
||||
|
||||
|
||||
mockChangelly.GetCurrenciesFullResult = new List<CurrencyFull>()
|
||||
{
|
||||
new CurrencyFull()
|
||||
{
|
||||
Name = "a",
|
||||
Enable = true,
|
||||
PayInConfirmations = 10,
|
||||
FullName = "aa",
|
||||
ImageLink = ""
|
||||
}
|
||||
};
|
||||
var httpClientFactory = new MockHttpClientFactory();
|
||||
var changellyController = new ChangellyController(
|
||||
new ChangellyClientProvider(tester.PayTester.StoreRepository, httpClientFactory),
|
||||
tester.NetworkProvider, fetcher);
|
||||
changellyController.IsTest = true;
|
||||
var result = Assert
|
||||
.IsType<OkObjectResult>(await changellyController.GetCurrencyList(user.StoreId))
|
||||
.Value as IEnumerable<CurrencyFull>;
|
||||
Assert.Equal(1, mockChangelly.GetCurrenciesFullCallCount);
|
||||
|
||||
Assert.True(result.Any());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async void CanCalculateToAmountForChangelly()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -211,108 +204,50 @@ namespace BTCPayServer.Tests
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
|
||||
var updateModel = new UpdateChangellySettingsViewModel()
|
||||
{
|
||||
ApiSecret = "secret",
|
||||
ApiKey = "key",
|
||||
ApiUrl = "http://gozo.com",
|
||||
ChangellyMerchantId = "aaa"
|
||||
};
|
||||
var updateModel = CreateDefaultChangellyParams(true);
|
||||
var storesController = tester.PayTester.GetController<StoresController>(user.UserId, user.StoreId);
|
||||
|
||||
Assert.Equal("UpdateStore", Assert.IsType<RedirectToActionResult>(
|
||||
await storesController.UpdateChangellySettings(user.StoreId, updateModel, "save")).ActionName);
|
||||
|
||||
var mockChangelly = new MockChangelly(new MockHttpClientFactory(), updateModel.ApiKey, updateModel.ApiSecret, updateModel.ApiUrl);
|
||||
var mock = new MockChangellyClientProvider(mockChangelly, tester.PayTester.StoreRepository);
|
||||
|
||||
var factory = UnitTest1.CreateBTCPayRateFactory();
|
||||
var fetcher = new RateFetcher(factory);
|
||||
|
||||
var changellyController = new ChangellyController(mock,tester.NetworkProvider,fetcher);
|
||||
|
||||
mockChangelly.GetExchangeAmountResult = (from, to, amount) =>
|
||||
{
|
||||
Assert.Equal("A", from);
|
||||
Assert.Equal("B", to);
|
||||
|
||||
switch (mockChangelly.GetExchangeAmountCallCount)
|
||||
{
|
||||
case 1:
|
||||
return 0.5m;
|
||||
default:
|
||||
return 1.01m;
|
||||
}
|
||||
};
|
||||
|
||||
var httpClientFactory = new MockHttpClientFactory();
|
||||
var changellyController = new ChangellyController(
|
||||
new ChangellyClientProvider(tester.PayTester.StoreRepository, httpClientFactory),
|
||||
tester.NetworkProvider, fetcher);
|
||||
changellyController.IsTest = true;
|
||||
Assert.IsType<decimal>(Assert
|
||||
.IsType<OkObjectResult>(await changellyController.CalculateAmount(user.StoreId, "A", "B", 1.0m)).Value);
|
||||
Assert.True(mockChangelly.GetExchangeAmountCallCount > 1);
|
||||
.IsType<OkObjectResult>(await changellyController.CalculateAmount(user.StoreId, "ltc", "btc", 1.0m))
|
||||
.Value);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanComputeBaseAmount()
|
||||
{
|
||||
Assert.Equal(1, ChangellyCalculationHelper.ComputeBaseAmount(1, 1));
|
||||
Assert.Equal(0.5m, ChangellyCalculationHelper.ComputeBaseAmount(1, 0.5m));
|
||||
Assert.Equal(2, ChangellyCalculationHelper.ComputeBaseAmount(0.5m, 1));
|
||||
Assert.Equal(4m, ChangellyCalculationHelper.ComputeBaseAmount(1, 4));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanComputeCorrectAmount()
|
||||
{
|
||||
Assert.Equal(1, ChangellyCalculationHelper.ComputeCorrectAmount(0.5m, 1, 2));
|
||||
Assert.Equal(0.25m, ChangellyCalculationHelper.ComputeCorrectAmount(0.5m, 1, 0.5m));
|
||||
Assert.Equal(20, ChangellyCalculationHelper.ComputeCorrectAmount(10, 1, 2));
|
||||
}
|
||||
}
|
||||
|
||||
public class MockHttpClientFactory : IHttpClientFactory
|
||||
{
|
||||
public HttpClient CreateClient(string name)
|
||||
{
|
||||
return new HttpClient();
|
||||
}
|
||||
}
|
||||
|
||||
public class MockChangelly : Changelly
|
||||
{
|
||||
public IEnumerable<CurrencyFull> GetCurrenciesFullResult { get; set; }
|
||||
|
||||
public delegate decimal ParamsFunc<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
|
||||
|
||||
public ParamsFunc<string, string, decimal, (decimal amount, bool Success, string Error)> GetExchangeAmountResult
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public int GetCurrenciesFullCallCount { get; set; } = 0;
|
||||
public int GetExchangeAmountCallCount { get; set; } = 0;
|
||||
|
||||
public MockChangelly(IHttpClientFactory httpClientFactory, string apiKey, string apiSecret, string apiUrl) : base(httpClientFactory, apiKey, apiSecret, apiUrl)
|
||||
{
|
||||
}
|
||||
|
||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
public override async Task<IEnumerable<CurrencyFull>> GetCurrenciesFull()
|
||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
{
|
||||
GetCurrenciesFullCallCount++;
|
||||
return GetCurrenciesFullResult;
|
||||
}
|
||||
|
||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
public override async Task<decimal> GetExchangeAmount(string fromCurrency,
|
||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
string toCurrency, decimal amount)
|
||||
{
|
||||
GetExchangeAmountCallCount++;
|
||||
return GetExchangeAmountResult.Invoke(fromCurrency, toCurrency, amount);
|
||||
}
|
||||
}
|
||||
|
||||
public class MockChangellyClientProvider : ChangellyClientProvider
|
||||
{
|
||||
public MockChangelly MockChangelly;
|
||||
|
||||
public MockChangellyClientProvider(
|
||||
MockChangelly mockChangelly,
|
||||
StoreRepository storeRepository) : base(storeRepository, new MockHttpClientFactory())
|
||||
{
|
||||
MockChangelly = mockChangelly;
|
||||
}
|
||||
|
||||
public override bool TryGetChangellyClient(string storeId, out string error, out Changelly changelly)
|
||||
{
|
||||
error = null;
|
||||
changelly = MockChangelly;
|
||||
return true;
|
||||
return new HttpClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ You can run the tests inside a container by running
|
||||
docker-compose run --rm tests
|
||||
```
|
||||
|
||||
You can run tests on `MySql` database instead of `Postgres` by setting environnement variable `TESTS_DB` equals to `MySql`.
|
||||
|
||||
## How to manually test payments
|
||||
|
||||
### Using the test bitcoin-cli
|
||||
|
@ -11,6 +11,7 @@ namespace BTCPayServer.Tests
|
||||
public class RateRulesTest
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void SecondDuplicatedRuleIsIgnored()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
@ -24,6 +25,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanParseRateRules()
|
||||
{
|
||||
// Check happy path
|
||||
|
@ -60,7 +60,9 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
NBXplorerUri = ExplorerClient.Address,
|
||||
LTCNBXplorerUri = LTCExplorerClient.Address,
|
||||
TestDatabase = Enum.Parse<TestDatabases>(GetEnvironment("TESTS_DB", TestDatabases.Postgres.ToString()), true),
|
||||
Postgres = GetEnvironment("TESTS_POSTGRES", "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver"),
|
||||
MySQL = GetEnvironment("TESTS_MYSQL", "User ID=root;Host=127.0.0.1;Port=33036;Database=btcpayserver"),
|
||||
IntegratedLightning = MerchantCharge.Client.Uri
|
||||
};
|
||||
PayTester.Port = int.Parse(GetEnvironment("TESTS_PORT", Utils.FreeTcpPort().ToString(CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture);
|
||||
@ -82,7 +84,7 @@ namespace BTCPayServer.Tests
|
||||
/// Connect a customer LN node to the merchant LN node
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task EnsureConnectedToDestinations()
|
||||
public Task EnsureChannelsSetup()
|
||||
{
|
||||
return BTCPayServer.Lightning.Tests.ConnectChannels.ConnectAll(ExplorerNode, GetLightningSenderClients(), GetLightningDestClients());
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanHandleUriValidation()
|
||||
{
|
||||
var attribute = new UriAttribute();
|
||||
@ -77,6 +78,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanCalculateCryptoDue2()
|
||||
{
|
||||
var dummy = new Key().PubKey.GetAddress(Network.RegTest).ToString();
|
||||
@ -134,6 +136,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanCalculateCryptoDue()
|
||||
{
|
||||
var entity = new InvoiceEntity();
|
||||
@ -258,6 +261,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanAcceptInvoiceWithTolerance()
|
||||
{
|
||||
var entity = new InvoiceEntity();
|
||||
@ -285,6 +289,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanAcceptInvoiceWithTolerance2()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -325,6 +330,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void RoundupCurrenciesCorrectly()
|
||||
{
|
||||
foreach (var test in new[]
|
||||
@ -341,6 +347,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanPayUsingBIP70()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -391,11 +398,13 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanSetLightningServer()
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanSetLightningServer()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
await tester.EnsureChannelsSetup();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
var storeController = user.GetController<StoresController>();
|
||||
@ -427,18 +436,21 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanSendLightningPaymentCLightning()
|
||||
{
|
||||
await ProcessLightningPayment(LightningConnectionType.CLightning);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanSendLightningPaymentCharge()
|
||||
{
|
||||
await ProcessLightningPayment(LightningConnectionType.Charge);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanSendLightningPaymentLnd()
|
||||
{
|
||||
await ProcessLightningPayment(LightningConnectionType.LndREST);
|
||||
@ -452,13 +464,12 @@ namespace BTCPayServer.Tests
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
await tester.EnsureChannelsSetup();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterLightningNode("BTC", type);
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
|
||||
await tester.EnsureConnectedToDestinations();
|
||||
|
||||
await CanSendLightningPaymentCore(tester, user);
|
||||
|
||||
await Task.WhenAll(Enumerable.Range(0, 5)
|
||||
@ -491,6 +502,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanUseServerInitiatedPairingCode()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -516,6 +528,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanSendIPN()
|
||||
{
|
||||
using (var callbackServer = new CustomServer())
|
||||
@ -552,6 +565,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CantPairTwiceWithSamePubkey()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -573,6 +587,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanRescanWallet()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -639,6 +654,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanListInvoices()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -680,6 +696,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanGetRates()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -727,6 +744,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanRBFPayment()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -783,6 +801,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanParseFilter()
|
||||
{
|
||||
var filter = "storeid:abc status:abed blabhbalh ";
|
||||
@ -804,6 +823,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanParseFingerprint()
|
||||
{
|
||||
Assert.True(SSH.SSHFingerprint.TryParse("4e343c6fc6cfbf9339c02d06a151e1dd", out var unused));
|
||||
@ -820,6 +840,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void TestAccessBitpayAPI()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -886,6 +907,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanUseExchangeSpecificRate()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -928,6 +950,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanTweakRate()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -972,6 +995,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanHaveLTCOnlyStore()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1036,6 +1060,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanModifyRates()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1096,6 +1121,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanPayWithTwoCurrencies()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1207,6 +1233,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanParseCurrencyValue()
|
||||
{
|
||||
Assert.True(CurrencyValue.TryParse("1.50USD", out var result));
|
||||
@ -1227,6 +1254,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanParseDerivationScheme()
|
||||
{
|
||||
var parser = new DerivationSchemeParser(Network.TestNet);
|
||||
@ -1267,6 +1295,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanDisablePaymentMethods()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1325,11 +1354,13 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanSetPaymentMethodLimits()
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanSetPaymentMethodLimits()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
await tester.EnsureChannelsSetup();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
@ -1368,6 +1399,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanUsePoSApp()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1412,6 +1444,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanCreateAndDeleteApps()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1448,6 +1481,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void InvoiceFlowThroughDifferentStatesCorrectly()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1604,6 +1638,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CheckQuadrigacxRateProvider()
|
||||
{
|
||||
var quadri = new QuadrigacxRateProvider();
|
||||
@ -1617,6 +1652,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanQueryDirectProviders()
|
||||
{
|
||||
var factory = CreateBTCPayRateFactory();
|
||||
@ -1647,6 +1683,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanGetRateCryptoCurrenciesByDefault()
|
||||
{
|
||||
var provider = new BTCPayNetworkProvider(NetworkType.Mainnet);
|
||||
@ -1700,6 +1737,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CheckRatesProvider()
|
||||
{
|
||||
var spy = new SpyRateProvider();
|
||||
|
@ -14,7 +14,9 @@ services:
|
||||
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_MYSQL: User ID=root;Host=mysql;Port=3306;Database=btcpayserver
|
||||
TESTS_PORT: 80
|
||||
TESTS_HOSTNAME: tests
|
||||
TEST_MERCHANTLIGHTNINGD: "type=clightning;server=/etc/merchant_lightningd_datadir/lightning-rpc"
|
||||
@ -43,6 +45,7 @@ services:
|
||||
links:
|
||||
- nbxplorer
|
||||
- postgres
|
||||
- mysql
|
||||
- customer_lightningd
|
||||
- merchant_lightningd
|
||||
- lightning-charged
|
||||
@ -59,13 +62,15 @@ services:
|
||||
links:
|
||||
- nbxplorer
|
||||
- postgres
|
||||
- mysql
|
||||
- customer_lnd
|
||||
- merchant_lnd
|
||||
|
||||
|
||||
|
||||
nbxplorer:
|
||||
image: nicolasdorier/nbxplorer:1.1.0.3
|
||||
image: nicolasdorier/nbxplorer:1.1.0.4
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "32838:32838"
|
||||
expose:
|
||||
@ -114,6 +119,7 @@ services:
|
||||
|
||||
customer_lightningd:
|
||||
image: nicolasdorier/clightning:v0.6.1-1-dev
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
EXPOSE_TCP: "true"
|
||||
LIGHTNINGD_OPT: |
|
||||
@ -138,6 +144,7 @@ services:
|
||||
|
||||
lightning-charged:
|
||||
image: shesek/lightning-charge:0.4.3
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
NETWORK: regtest
|
||||
API_TOKEN: foiewnccewuify
|
||||
@ -201,9 +208,19 @@ services:
|
||||
- "39372:5432"
|
||||
expose:
|
||||
- "5432"
|
||||
|
||||
mysql:
|
||||
image: mysql:8.0.12
|
||||
expose:
|
||||
- "3306"
|
||||
ports:
|
||||
- "33036:3306"
|
||||
environment:
|
||||
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
|
||||
|
||||
merchant_lnd:
|
||||
image: btcpayserver/lnd:0.5-beta
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
LND_CHAIN: "btc"
|
||||
LND_ENVIRONMENT: "regtest"
|
||||
@ -230,6 +247,7 @@ services:
|
||||
|
||||
customer_lnd:
|
||||
image: btcpayserver/lnd:0.5-beta
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
LND_CHAIN: "btc"
|
||||
LND_ENVIRONMENT: "regtest"
|
||||
|
3
BTCPayServer.Tests/xunit.runner.json
Normal file
3
BTCPayServer.Tests/xunit.runner.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"parallelizeTestCollections": false
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<Version>1.0.2.114</Version>
|
||||
<Version>1.0.3.2</Version>
|
||||
<NoWarn>NU1701,CA1816,CA1308,CA1810,CA2208</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
@ -53,6 +53,7 @@
|
||||
<PackageReference Include="NicolasDorier.RateLimits" Version="1.0.0.3" />
|
||||
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="1.0.0.18" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.1.0" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.1.2" />
|
||||
<PackageReference Include="Serilog" Version="2.7.1" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
|
||||
@ -127,6 +128,9 @@
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
<Pack>$(IncludeRazorContentInPack)</Pack>
|
||||
</Content>
|
||||
<Content Update="Views\Server\LndRestServices.cshtml">
|
||||
<Pack>$(IncludeRazorContentInPack)</Pack>
|
||||
</Content>
|
||||
<Content Update="Views\Server\SSHService.cshtml">
|
||||
<Pack>$(IncludeRazorContentInPack)</Pack>
|
||||
</Content>
|
||||
@ -139,7 +143,7 @@
|
||||
<Content Update="Views\Public\PayButtonHandle.cshtml">
|
||||
<Pack>$(IncludeRazorContentInPack)</Pack>
|
||||
</Content>
|
||||
<Content Update="Views\Server\LNDGRPCServices.cshtml">
|
||||
<Content Update="Views\Server\LndGrpcServices.cshtml">
|
||||
<Pack>$(IncludeRazorContentInPack)</Pack>
|
||||
</Content>
|
||||
<Content Update="Views\Server\Maintenance.cshtml">
|
||||
|
@ -15,6 +15,7 @@ using Renci.SshNet;
|
||||
using NBitcoin.DataEncoders;
|
||||
using BTCPayServer.SSH;
|
||||
using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Configuration.External;
|
||||
|
||||
namespace BTCPayServer.Configuration
|
||||
{
|
||||
@ -78,6 +79,7 @@ namespace BTCPayServer.Configuration
|
||||
setting.ExplorerUri = conf.GetOrDefault<Uri>($"{net.CryptoCode}.explorer.url", net.NBXplorerNetwork.DefaultSettings.DefaultUrl);
|
||||
setting.CookieFile = conf.GetOrDefault<string>($"{net.CryptoCode}.explorer.cookiefile", net.NBXplorerNetwork.DefaultSettings.DefaultCookieFile);
|
||||
NBXplorerConnectionSettings.Add(setting);
|
||||
|
||||
{
|
||||
var lightning = conf.GetOrDefault<string>($"{net.CryptoCode}.lightning", string.Empty);
|
||||
if (lightning.Length != 0)
|
||||
@ -99,25 +101,31 @@ namespace BTCPayServer.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
void externalLnd<T>(string code, string lndType)
|
||||
{
|
||||
var lightning = conf.GetOrDefault<string>($"{net.CryptoCode}.external.lnd.grpc", string.Empty);
|
||||
var lightning = conf.GetOrDefault<string>(code, string.Empty);
|
||||
if (lightning.Length != 0)
|
||||
{
|
||||
if (!LightningConnectionString.TryParse(lightning, false, out var connectionString, out var error))
|
||||
{
|
||||
throw new ConfigException($"Invalid setting {net.CryptoCode}.external.lnd.grpc, " + Environment.NewLine +
|
||||
$"lnd server: 'type=lnd-grpc;server=https://lnd.example.com;macaroon=abf239...;certthumbprint=2abdf302...'" + Environment.NewLine +
|
||||
$"lnd server: 'type=lnd-grpc;server=https://lnd.example.com;macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" + Environment.NewLine +
|
||||
throw new ConfigException($"Invalid setting {code}, " + Environment.NewLine +
|
||||
$"lnd server: 'type={lndType};server=https://lnd.example.com;macaroon=abf239...;certthumbprint=2abdf302...'" + Environment.NewLine +
|
||||
$"lnd server: 'type={lndType};server=https://lnd.example.com;macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" + Environment.NewLine +
|
||||
error);
|
||||
}
|
||||
ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalLNDGRPC(connectionString));
|
||||
var instanceType = typeof(T);
|
||||
ExternalServicesByCryptoCode.Add(net.CryptoCode, (ExternalService)Activator.CreateInstance(instanceType, connectionString));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
externalLnd<ExternalLndGrpc>($"{net.CryptoCode}.external.lnd.grpc", "lnd-grpc");
|
||||
externalLnd<ExternalLndRest>($"{net.CryptoCode}.external.lnd.rest", "lnd-rest");
|
||||
}
|
||||
|
||||
Logs.Configuration.LogInformation("Supported chains: " + String.Join(',', supportedChains.ToArray()));
|
||||
|
||||
PostgresConnectionString = conf.GetOrDefault<string>("postgres", null);
|
||||
MySQLConnectionString = conf.GetOrDefault<string>("mysql", null);
|
||||
BundleJsCss = conf.GetOrDefault<bool>("bundlejscss", true);
|
||||
ExternalUrl = conf.GetOrDefault<Uri>("externalurl", null);
|
||||
|
||||
@ -127,12 +135,12 @@ namespace BTCPayServer.Configuration
|
||||
int waitTime = 0;
|
||||
while (!string.IsNullOrEmpty(sshSettings.KeyFile) && !File.Exists(sshSettings.KeyFile))
|
||||
{
|
||||
if(waitTime++ < 5)
|
||||
if (waitTime++ < 5)
|
||||
System.Threading.Thread.Sleep(1000);
|
||||
else
|
||||
throw new ConfigException($"sshkeyfile does not exist");
|
||||
}
|
||||
|
||||
|
||||
if (sshSettings.Port > ushort.MaxValue ||
|
||||
sshSettings.Port < ushort.MinValue)
|
||||
throw new ConfigException($"ssh port is invalid");
|
||||
@ -224,6 +232,11 @@ namespace BTCPayServer.Configuration
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string MySQLConnectionString
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Uri ExternalUrl
|
||||
{
|
||||
get;
|
||||
@ -250,29 +263,4 @@ namespace BTCPayServer.Configuration
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class ExternalServices : MultiValueDictionary<string, ExternalService>
|
||||
{
|
||||
public IEnumerable<T> GetServices<T>(string cryptoCode) where T : ExternalService
|
||||
{
|
||||
if (!this.TryGetValue(cryptoCode.ToUpperInvariant(), out var services))
|
||||
return Array.Empty<T>();
|
||||
return services.OfType<T>();
|
||||
}
|
||||
}
|
||||
|
||||
public class ExternalService
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class ExternalLNDGRPC : ExternalService
|
||||
{
|
||||
public ExternalLNDGRPC(LightningConnectionString connectionString)
|
||||
{
|
||||
ConnectionString = connectionString;
|
||||
}
|
||||
|
||||
public LightningConnectionString ConnectionString { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ namespace BTCPayServer.Configuration
|
||||
app.Option("--regtest | -regtest", $"Use regtest (deprecated, use --network instead)", CommandOptionType.BoolValue);
|
||||
app.Option("--chains | -c", $"Chains to support as a comma separated (default: btc; available: {chains})", CommandOptionType.SingleValue);
|
||||
app.Option("--postgres", $"Connection string to a PostgreSQL database (default: SQLite)", CommandOptionType.SingleValue);
|
||||
app.Option("--mysql", $"Connection string to a MySQL database (default: SQLite)", CommandOptionType.SingleValue);
|
||||
app.Option("--externalurl", $"The expected external URL of this service, to use if BTCPay is behind a reverse proxy (default: empty, use the incoming HTTP request to figure out)", CommandOptionType.SingleValue);
|
||||
app.Option("--bundlejscss", $"Bundle JavaScript and CSS files for better performance (default: true)", CommandOptionType.SingleValue);
|
||||
app.Option("--rootpath", "The root path in the URL to access BTCPay (default: /)", CommandOptionType.SingleValue);
|
||||
@ -108,6 +109,7 @@ namespace BTCPayServer.Configuration
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("### Database ###");
|
||||
builder.AppendLine("#postgres=User ID=root;Password=myPassword;Host=localhost;Port=5432;Database=myDataBase;");
|
||||
builder.AppendLine("#mysql=User ID=root;Password=myPassword;Host=localhost;Port=3306;Database=myDataBase;");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("### NBXplorer settings ###");
|
||||
foreach (var n in new BTCPayNetworkProvider(networkType).GetAll())
|
||||
|
35
BTCPayServer/Configuration/External/ExternalLnd.cs
vendored
Normal file
35
BTCPayServer/Configuration/External/ExternalLnd.cs
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Lightning;
|
||||
|
||||
namespace BTCPayServer.Configuration.External
|
||||
{
|
||||
public abstract class ExternalLnd : ExternalService
|
||||
{
|
||||
public ExternalLnd(LightningConnectionString connectionString, LndTypes type)
|
||||
{
|
||||
ConnectionString = connectionString;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public LndTypes Type { get; set; }
|
||||
public LightningConnectionString ConnectionString { get; set; }
|
||||
}
|
||||
|
||||
public enum LndTypes
|
||||
{
|
||||
gRPC, Rest
|
||||
}
|
||||
|
||||
public class ExternalLndGrpc : ExternalLnd
|
||||
{
|
||||
public ExternalLndGrpc(LightningConnectionString connectionString) : base(connectionString, LndTypes.gRPC) { }
|
||||
}
|
||||
|
||||
public class ExternalLndRest : ExternalLnd
|
||||
{
|
||||
public ExternalLndRest(LightningConnectionString connectionString) : base(connectionString, LndTypes.Rest) { }
|
||||
}
|
||||
}
|
22
BTCPayServer/Configuration/External/ExternalService.cs
vendored
Normal file
22
BTCPayServer/Configuration/External/ExternalService.cs
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Lightning;
|
||||
|
||||
namespace BTCPayServer.Configuration.External
|
||||
{
|
||||
public class ExternalServices : MultiValueDictionary<string, ExternalService>
|
||||
{
|
||||
public IEnumerable<T> GetServices<T>(string cryptoCode) where T : ExternalService
|
||||
{
|
||||
if (!this.TryGetValue(cryptoCode.ToUpperInvariant(), out var services))
|
||||
return Array.Empty<T>();
|
||||
return services.OfType<T>();
|
||||
}
|
||||
}
|
||||
|
||||
public class ExternalService
|
||||
{
|
||||
}
|
||||
}
|
@ -29,13 +29,11 @@ namespace BTCPayServer.Controllers
|
||||
[Route("currencies")]
|
||||
public async Task<IActionResult> GetCurrencyList(string storeId)
|
||||
{
|
||||
if (!TryGetChangellyClient(storeId, out var actionResult, out var client))
|
||||
{
|
||||
return actionResult;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
var client = await TryGetChangellyClient(storeId);
|
||||
|
||||
return Ok(await client.GetCurrenciesFull());
|
||||
}
|
||||
catch (Exception e)
|
||||
@ -52,29 +50,19 @@ namespace BTCPayServer.Controllers
|
||||
public async Task<IActionResult> CalculateAmount(string storeId, string fromCurrency, string toCurrency,
|
||||
decimal toCurrencyAmount)
|
||||
{
|
||||
if (!TryGetChangellyClient(storeId, out var actionResult, out var client))
|
||||
{
|
||||
return actionResult;
|
||||
}
|
||||
|
||||
|
||||
if (fromCurrency.Equals("usd", StringComparison.InvariantCultureIgnoreCase)
|
||||
|| fromCurrency.Equals("eur", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
var rules = store.GetStoreBlob().GetRateRules(_btcPayNetworkProvider);
|
||||
var rate = await _RateProviderFactory.FetchRate(new CurrencyPair(toCurrency, fromCurrency), rules);
|
||||
if (rate.BidAsk == null) return BadRequest();
|
||||
var flatRate = rate.BidAsk.Center;
|
||||
return Ok(flatRate * toCurrencyAmount);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
var client = await TryGetChangellyClient(storeId);
|
||||
|
||||
if (fromCurrency.Equals("usd", StringComparison.InvariantCultureIgnoreCase)
|
||||
|| fromCurrency.Equals("eur", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return await HandleCalculateFiatAmount(fromCurrency, toCurrency, toCurrencyAmount);
|
||||
}
|
||||
|
||||
var callCounter = 0;
|
||||
var response1 = await client.GetExchangeAmount(fromCurrency, toCurrency, 1);
|
||||
var currentAmount = response1;
|
||||
var baseRate = await client.GetExchangeAmount(fromCurrency, toCurrency, 1);
|
||||
var currentAmount = ChangellyCalculationHelper.ComputeBaseAmount(baseRate, toCurrencyAmount);
|
||||
while (true)
|
||||
{
|
||||
if (callCounter > 10)
|
||||
@ -82,13 +70,13 @@ namespace BTCPayServer.Controllers
|
||||
BadRequest();
|
||||
}
|
||||
|
||||
var response2 = await client.GetExchangeAmount(fromCurrency, toCurrency, currentAmount);
|
||||
var computedAmount = await client.GetExchangeAmount(fromCurrency, toCurrency, currentAmount);
|
||||
callCounter++;
|
||||
if (response2 < toCurrencyAmount)
|
||||
if (computedAmount < toCurrencyAmount)
|
||||
{
|
||||
var newCurrentAmount = ((toCurrencyAmount / response2) * 1m) * currentAmount;
|
||||
|
||||
currentAmount = newCurrentAmount;
|
||||
currentAmount =
|
||||
ChangellyCalculationHelper.ComputeCorrectAmount(currentAmount, computedAmount,
|
||||
toCurrencyAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -105,21 +93,27 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetChangellyClient(string storeId, out IActionResult actionResult,
|
||||
out Changelly changelly)
|
||||
private async Task<Changelly> TryGetChangellyClient(string storeId)
|
||||
{
|
||||
changelly = null;
|
||||
actionResult = null;
|
||||
storeId = storeId ?? HttpContext.GetStoreData()?.Id;
|
||||
|
||||
if (_changellyClientProvider.TryGetChangellyClient(storeId, out var error, out changelly))
|
||||
return true;
|
||||
actionResult = BadRequest(new BitpayErrorModel()
|
||||
{
|
||||
Error = error
|
||||
});
|
||||
return false;
|
||||
var store = IsTest? null: HttpContext.GetStoreData();
|
||||
storeId = storeId ?? store?.Id;
|
||||
|
||||
return await _changellyClientProvider.TryGetChangellyClient(storeId, store);
|
||||
}
|
||||
|
||||
private async Task<IActionResult> HandleCalculateFiatAmount(string fromCurrency, string toCurrency,
|
||||
decimal toCurrencyAmount)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
var rules = store.GetStoreBlob().GetRateRules(_btcPayNetworkProvider);
|
||||
var rate = await _RateProviderFactory.FetchRate(new CurrencyPair(toCurrency, fromCurrency), rules);
|
||||
if (rate.BidAsk == null) return BadRequest();
|
||||
var flatRate = rate.BidAsk.Center;
|
||||
return Ok(flatRate * toCurrencyAmount);
|
||||
}
|
||||
|
||||
public bool IsTest { get; set; } = false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ using System.Threading.Tasks;
|
||||
using Renci.SshNet;
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Configuration.External;
|
||||
|
||||
namespace BTCPayServer.Controllers
|
||||
{
|
||||
@ -277,7 +278,7 @@ namespace BTCPayServer.Controllers
|
||||
else
|
||||
{
|
||||
e.CanTrust = _Options.IsTrustedFingerprint(e.FingerPrint, e.HostKey);
|
||||
if(!e.CanTrust)
|
||||
if (!e.CanTrust)
|
||||
Logs.Configuration.LogError($"SSH host fingerprint for {e.HostKeyName} is untrusted, start BTCPay with -sshtrustedfingerprints \"{Encoders.Hex.EncodeData(e.FingerPrint)}\"");
|
||||
}
|
||||
};
|
||||
@ -421,17 +422,15 @@ namespace BTCPayServer.Controllers
|
||||
var result = new ServicesViewModel();
|
||||
foreach (var cryptoCode in _Options.ExternalServicesByCryptoCode.Keys)
|
||||
{
|
||||
int i = 0;
|
||||
foreach (var grpcService in _Options.ExternalServicesByCryptoCode.GetServices<ExternalLnd>(cryptoCode))
|
||||
{
|
||||
int i = 0;
|
||||
foreach (var grpcService in _Options.ExternalServicesByCryptoCode.GetServices<ExternalLNDGRPC>(cryptoCode))
|
||||
result.LNDServices.Add(new ServicesViewModel.LNDServiceViewModel()
|
||||
{
|
||||
result.LNDServices.Add(new ServicesViewModel.LNDServiceViewModel()
|
||||
{
|
||||
Crypto = cryptoCode,
|
||||
Type = "gRPC",
|
||||
Index = i++,
|
||||
});
|
||||
}
|
||||
Crypto = cryptoCode,
|
||||
Type = grpcService.Type,
|
||||
Index = i++,
|
||||
});
|
||||
}
|
||||
}
|
||||
result.HasSSH = _Options.SSHSettings != null;
|
||||
@ -439,17 +438,17 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
|
||||
[Route("server/services/lnd-grpc/{cryptoCode}/{index}")]
|
||||
public IActionResult LNDGRPCServices(string cryptoCode, int index, uint? nonce)
|
||||
public IActionResult LndGrpcServices(string cryptoCode, int index, uint? nonce)
|
||||
{
|
||||
if (!_dashBoard.IsFullySynched(cryptoCode, out var unusud))
|
||||
{
|
||||
StatusMessage = $"Error: {cryptoCode} is not fully synched";
|
||||
return RedirectToAction(nameof(Services));
|
||||
}
|
||||
var external = GetExternalLNDConnectionString(cryptoCode, index);
|
||||
var external = GetExternalLndConnectionString(cryptoCode, index);
|
||||
if (external == null)
|
||||
return NotFound();
|
||||
var model = new LNDGRPCServicesViewModel();
|
||||
var model = new LndGrpcServicesViewModel();
|
||||
|
||||
model.Host = $"{external.BaseUri.DnsSafeHost}:{external.BaseUri.Port}";
|
||||
model.SSL = external.BaseUri.Scheme == "https";
|
||||
@ -493,9 +492,9 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
[Route("server/services/lnd-grpc/{cryptoCode}/{index}")]
|
||||
[HttpPost]
|
||||
public IActionResult LNDGRPCServicesPOST(string cryptoCode, int index)
|
||||
public IActionResult LndGrpcServicesPost(string cryptoCode, int index)
|
||||
{
|
||||
var external = GetExternalLNDConnectionString(cryptoCode, index);
|
||||
var external = GetExternalLndConnectionString(cryptoCode, index);
|
||||
if (external == null)
|
||||
return NotFound();
|
||||
LightningConfigurations confs = new LightningConfigurations();
|
||||
@ -513,12 +512,12 @@ namespace BTCPayServer.Controllers
|
||||
var nonce = RandomUtils.GetUInt32();
|
||||
var configKey = GetConfigKey("lnd-grpc", cryptoCode, index, nonce);
|
||||
_LnConfigProvider.KeepConfig(configKey, confs);
|
||||
return RedirectToAction(nameof(LNDGRPCServices), new { cryptoCode = cryptoCode, nonce = nonce });
|
||||
return RedirectToAction(nameof(LndGrpcServices), new { cryptoCode = cryptoCode, nonce = nonce });
|
||||
}
|
||||
|
||||
private LightningConnectionString GetExternalLNDConnectionString(string cryptoCode, int index)
|
||||
private LightningConnectionString GetExternalLndConnectionString(string cryptoCode, int index)
|
||||
{
|
||||
var connectionString = _Options.ExternalServicesByCryptoCode.GetServices<ExternalLNDGRPC>(cryptoCode).Skip(index).Select(c => c.ConnectionString).FirstOrDefault();
|
||||
var connectionString = _Options.ExternalServicesByCryptoCode.GetServices<ExternalLnd>(cryptoCode).Skip(index).Select(c => c.ConnectionString).FirstOrDefault();
|
||||
if (connectionString == null)
|
||||
return null;
|
||||
connectionString = connectionString.Clone();
|
||||
@ -531,13 +530,35 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logging.Logs.Configuration.LogWarning($"{cryptoCode}: The macaroon file path of the external LND grpc config was not found ({connectionString.MacaroonFilePath})");
|
||||
Logs.Configuration.LogWarning($"{cryptoCode}: The macaroon file path of the external LND grpc config was not found ({connectionString.MacaroonFilePath})");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
[Route("server/services/lnd-rest/{cryptoCode}/{index}")]
|
||||
public IActionResult LndRestServices(string cryptoCode, int index, uint? nonce)
|
||||
{
|
||||
if (!_dashBoard.IsFullySynched(cryptoCode, out var unusud))
|
||||
{
|
||||
StatusMessage = $"Error: {cryptoCode} is not fully synched";
|
||||
return RedirectToAction(nameof(Services));
|
||||
}
|
||||
var external = GetExternalLndConnectionString(cryptoCode, index);
|
||||
if (external == null)
|
||||
return NotFound();
|
||||
var model = new LndRestServicesViewModel();
|
||||
|
||||
model.BaseApiUrl = external.BaseUri.ToString();
|
||||
if (external.CertificateThumbprint != null)
|
||||
model.CertificateThumbprint = Encoders.Hex.EncodeData(external.CertificateThumbprint);
|
||||
if (external.Macaroon != null)
|
||||
model.Macaroon = Encoders.Hex.EncodeData(external.Macaroon);
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[Route("server/services/ssh")]
|
||||
public IActionResult SSHService(bool downloadKeyFile = false)
|
||||
{
|
||||
|
@ -114,7 +114,7 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
if(!System.IO.File.Exists(connectionString.MacaroonFilePath))
|
||||
{
|
||||
ModelState.AddModelError(nameof(vm.ConnectionString), "The macaroonfilepath file does exist");
|
||||
ModelState.AddModelError(nameof(vm.ConnectionString), "The macaroonfilepath file does not exist");
|
||||
return View(vm);
|
||||
}
|
||||
if(!System.IO.Path.IsPathRooted(connectionString.MacaroonFilePath))
|
||||
|
@ -230,6 +230,7 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
[HttpPost]
|
||||
[Route("{walletId}/rescan")]
|
||||
[Authorize(Policy = Policies.CanModifyServerSettings.Key)]
|
||||
public async Task<IActionResult> WalletRescan(
|
||||
[ModelBinder(typeof(WalletIdModelBinder))]
|
||||
WalletId walletId, RescanWalletModel vm)
|
||||
|
@ -17,7 +17,8 @@ namespace BTCPayServer.Data
|
||||
public enum DatabaseType
|
||||
{
|
||||
Sqlite,
|
||||
Postgres
|
||||
Postgres,
|
||||
MySQL,
|
||||
}
|
||||
public class ApplicationDbContextFactory
|
||||
{
|
||||
@ -95,6 +96,8 @@ namespace BTCPayServer.Data
|
||||
builder
|
||||
.UseNpgsql(_ConnectionString)
|
||||
.ReplaceService<IMigrationsSqlGenerator, CustomNpgsqlMigrationsSqlGenerator>();
|
||||
else if (_Type == DatabaseType.MySQL)
|
||||
builder.UseMySql(_ConnectionString);
|
||||
}
|
||||
|
||||
public void ConfigureHangfireBuilder(IGlobalConfiguration builder)
|
||||
|
@ -43,6 +43,7 @@ using BTCPayServer.Security;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
using NicolasDorier.RateLimits;
|
||||
using Npgsql;
|
||||
|
||||
namespace BTCPayServer.Hosting
|
||||
{
|
||||
@ -76,17 +77,23 @@ namespace BTCPayServer.Hosting
|
||||
{
|
||||
var opts = o.GetRequiredService<BTCPayServerOptions>();
|
||||
ApplicationDbContextFactory dbContext = null;
|
||||
if (opts.PostgresConnectionString == null)
|
||||
if (!String.IsNullOrEmpty(opts.PostgresConnectionString))
|
||||
{
|
||||
Logs.Configuration.LogInformation($"Postgres DB used ({opts.PostgresConnectionString})");
|
||||
dbContext = new ApplicationDbContextFactory(DatabaseType.Postgres, opts.PostgresConnectionString);
|
||||
}
|
||||
else if(!String.IsNullOrEmpty(opts.MySQLConnectionString))
|
||||
{
|
||||
Logs.Configuration.LogInformation($"MySQL DB used ({opts.MySQLConnectionString})");
|
||||
dbContext = new ApplicationDbContextFactory(DatabaseType.MySQL, opts.MySQLConnectionString);
|
||||
}
|
||||
else
|
||||
{
|
||||
var connStr = "Data Source=" + Path.Combine(opts.DataDir, "sqllite.db");
|
||||
Logs.Configuration.LogInformation($"SQLite DB used ({connStr})");
|
||||
dbContext = new ApplicationDbContextFactory(DatabaseType.Sqlite, connStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logs.Configuration.LogInformation($"Postgres DB used ({opts.PostgresConnectionString})");
|
||||
dbContext = new ApplicationDbContextFactory(DatabaseType.Postgres, opts.PostgresConnectionString);
|
||||
}
|
||||
|
||||
return dbContext;
|
||||
});
|
||||
|
||||
@ -194,7 +201,7 @@ namespace BTCPayServer.Hosting
|
||||
|
||||
static void Retry(Action act)
|
||||
{
|
||||
CancellationTokenSource cts = new CancellationTokenSource(10000);
|
||||
CancellationTokenSource cts = new CancellationTokenSource(1000);
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
@ -202,7 +209,9 @@ namespace BTCPayServer.Hosting
|
||||
act();
|
||||
return;
|
||||
}
|
||||
catch when(!cts.IsCancellationRequested)
|
||||
// Starting up
|
||||
catch (PostgresException ex) when (ex.SqlState == "57P03") { Thread.Sleep(1000); }
|
||||
catch when (!cts.IsCancellationRequested)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Models.ServerViewModels
|
||||
{
|
||||
public class LNDGRPCServicesViewModel
|
||||
public class LndGrpcServicesViewModel
|
||||
{
|
||||
public string Host { get; set; }
|
||||
public bool SSL { get; set; }
|
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Models.ServerViewModels
|
||||
{
|
||||
public class LndRestServicesViewModel
|
||||
{
|
||||
public string BaseApiUrl { get; set; }
|
||||
public string Macaroon { get; set; }
|
||||
public string CertificateThumbprint { get; set; }
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Configuration.External;
|
||||
|
||||
namespace BTCPayServer.Models.ServerViewModels
|
||||
{
|
||||
@ -10,7 +11,7 @@ namespace BTCPayServer.Models.ServerViewModels
|
||||
public class LNDServiceViewModel
|
||||
{
|
||||
public string Crypto { get; set; }
|
||||
public string Type { get; set; }
|
||||
public LndTypes Type { get; set; }
|
||||
public int Index { get; set; }
|
||||
}
|
||||
public List<LNDServiceViewModel> LNDServices { get; set; } = new List<LNDServiceViewModel>();
|
||||
|
@ -8,14 +8,14 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||
{
|
||||
public class UpdateChangellySettingsViewModel
|
||||
{
|
||||
[Required] public string ApiKey { get; set; } = "6ed02cdf1b614d89a8c0ceb170eebb61";
|
||||
[Required] public string ApiKey { get; set; }
|
||||
|
||||
[Required] public string ApiSecret { get; set; } = "8fbd66a2af5fd15a6b5f8ed0159c5842e32a18538521ffa145bd6c9e124d3483";
|
||||
[Required] public string ApiSecret { get; set; }
|
||||
|
||||
[Required] public string ApiUrl { get; set; } = "https://api.changelly.com";
|
||||
|
||||
[Display(Name = "Optional, Changelly Merchant Id")]
|
||||
public string ChangellyMerchantId { get; set; } = "804298eb5753";
|
||||
public string ChangellyMerchantId { get; set; }
|
||||
|
||||
[Display(Name = "Show Fiat Currencies as option in conversion")]
|
||||
public bool ShowFiat { get; set; } = true;
|
||||
@ -26,7 +26,7 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||
"Percentage to multiply amount requested at Changelly to avoid underpaid situations due to Changelly not guaranteeing rates. ")]
|
||||
public decimal AmountMarkupPercentage { get; set; } = new decimal(2);
|
||||
|
||||
public bool Enabled { get; set; } = true;
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public string StatusMessage { get; set; }
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
namespace BTCPayServer.Payments.Changelly
|
||||
{
|
||||
public static class ChangellyCalculationHelper
|
||||
{
|
||||
public static decimal ComputeBaseAmount(decimal baseRate, decimal toAmount)
|
||||
{
|
||||
return (1m / baseRate) * toAmount;
|
||||
}
|
||||
|
||||
public static decimal ComputeCorrectAmount(decimal currentFromAmount, decimal currentAmount,
|
||||
decimal expectedAmount)
|
||||
{
|
||||
return (currentFromAmount / currentAmount) * expectedAmount;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using NBitcoin;
|
||||
|
||||
@ -29,47 +31,40 @@ namespace BTCPayServer.Payments.Changelly
|
||||
}
|
||||
|
||||
|
||||
public virtual bool TryGetChangellyClient(string storeId, out string error,
|
||||
out Changelly changelly)
|
||||
public virtual async Task<Changelly> TryGetChangellyClient(string storeId, StoreData storeData = null)
|
||||
{
|
||||
if (_clientCache.ContainsKey(storeId))
|
||||
{
|
||||
changelly = _clientCache[storeId];
|
||||
error = null;
|
||||
return true;
|
||||
return _clientCache[storeId];
|
||||
}
|
||||
|
||||
changelly = null;
|
||||
|
||||
|
||||
var store = _storeRepository.FindStore(storeId).Result;
|
||||
if (store == null)
|
||||
if (storeData == null)
|
||||
{
|
||||
error = "Store not found";
|
||||
return false;
|
||||
storeData = await _storeRepository.FindStore(storeId);
|
||||
if (storeData == null)
|
||||
{
|
||||
throw new ChangellyException("Store not found");
|
||||
}
|
||||
}
|
||||
|
||||
var blob = store.GetStoreBlob();
|
||||
var blob = storeData.GetStoreBlob();
|
||||
var changellySettings = blob.ChangellySettings;
|
||||
|
||||
|
||||
if (changellySettings == null || !changellySettings.IsConfigured())
|
||||
{
|
||||
error = "Changelly not configured for this store";
|
||||
return false;
|
||||
throw new ChangellyException("Changelly not configured for this store");
|
||||
}
|
||||
|
||||
if (!changellySettings.Enabled)
|
||||
{
|
||||
error = "Changelly not enabled for this store";
|
||||
return false;
|
||||
throw new ChangellyException("Changelly not enabled for this store");
|
||||
}
|
||||
|
||||
changelly = new Changelly(_httpClientFactory, changellySettings.ApiKey, changellySettings.ApiSecret,
|
||||
var changelly = new Changelly(_httpClientFactory, changellySettings.ApiKey, changellySettings.ApiSecret,
|
||||
changellySettings.ApiUrl, changellySettings.ShowFiat);
|
||||
_clientCache.AddOrReplace(storeId, changelly);
|
||||
error = null;
|
||||
return true;
|
||||
return changelly;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,10 +90,10 @@ namespace BTCPayServer.Payments.Lightning
|
||||
throw new PaymentMethodUnavailableException($"No lightning node public address has been configured");
|
||||
}
|
||||
|
||||
var blocksGap = Math.Abs(info.BlockHeight - summary.Status.ChainHeight);
|
||||
var blocksGap = summary.Status.ChainHeight - info.BlockHeight;
|
||||
if (blocksGap > 10)
|
||||
{
|
||||
throw new PaymentMethodUnavailableException($"The lightning is not synched ({blocksGap} blocks)");
|
||||
throw new PaymentMethodUnavailableException($"The lightning node is not synched ({blocksGap} blocks left)");
|
||||
}
|
||||
|
||||
return info.NodeInfo;
|
||||
|
@ -4,17 +4,18 @@
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "--debuglog debug.log",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"BTCPAY_NETWORK": "regtest",
|
||||
"BTCPAY_BUNDLEJSCSS": "true",
|
||||
"BTCPAY_LTCEXPLORERURL": "http://127.0.0.1:32838/",
|
||||
"BTCPAY_BTCLIGHTNING": "type=charge;server=http://127.0.0.1:54938/;api-token=foiewnccewuify",
|
||||
"BTCPAY_BTCEXTERNALLNDGRPC": "type=lnd-grpc;server=https://lnd:lnd@127.0.0.1:53280/;allowinsecure=true",
|
||||
"BTCPAY_BTCEXPLORERURL": "http://127.0.0.1:32838/",
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"BTCPAY_CHAINS": "btc,ltc",
|
||||
"BTCPAY_POSTGRES": "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver"
|
||||
},
|
||||
"environmentVariables": {
|
||||
"BTCPAY_NETWORK": "regtest",
|
||||
"BTCPAY_BUNDLEJSCSS": "true",
|
||||
"BTCPAY_LTCEXPLORERURL": "http://127.0.0.1:32838/",
|
||||
"BTCPAY_BTCLIGHTNING": "type=charge;server=http://127.0.0.1:54938/;api-token=foiewnccewuify",
|
||||
"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",
|
||||
"BTCPAY_BTCEXPLORERURL": "http://127.0.0.1:32838/",
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"BTCPAY_CHAINS": "btc,ltc",
|
||||
"BTCPAY_POSTGRES": "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver"
|
||||
},
|
||||
"applicationUrl": "http://127.0.0.1:14142/"
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
@model BTCPayServer.Models.ServerViewModels.LNDGRPCServicesViewModel
|
||||
@model LndGrpcServicesViewModel
|
||||
@{
|
||||
ViewData.SetActivePageAndTitle(ServerNavPages.Services);
|
||||
}
|
||||
|
||||
|
||||
<h4>GRPC settings</h4>
|
||||
<h4>LND GRPC</h4>
|
||||
<partial name="_StatusMessage" for="@TempData["StatusMessage"]" />
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
41
BTCPayServer/Views/Server/LndRestServices.cshtml
Normal file
41
BTCPayServer/Views/Server/LndRestServices.cshtml
Normal file
@ -0,0 +1,41 @@
|
||||
@model LndRestServicesViewModel
|
||||
@{
|
||||
ViewData.SetActivePageAndTitle(ServerNavPages.Services);
|
||||
}
|
||||
|
||||
|
||||
<h4>LND REST</h4>
|
||||
<partial name="_StatusMessage" for="@TempData["StatusMessage"]" />
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-8">
|
||||
<div class="form-group">
|
||||
<p>BTCPay exposes LND Rest services for outside consumption. See connection information below</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="BaseApiUrl">Base API Url</label>
|
||||
<input asp-for="BaseApiUrl" readonly class="form-control" />
|
||||
</div>
|
||||
@if (Model.Macaroon != null)
|
||||
{
|
||||
<div class="form-group">
|
||||
<label asp-for="Macaroon"></label>
|
||||
<input asp-for="Macaroon" readonly class="form-control" />
|
||||
</div>
|
||||
}
|
||||
@if (Model.CertificateThumbprint != null)
|
||||
{
|
||||
<div class="form-group">
|
||||
<label asp-for="CertificateThumbprint"></label>
|
||||
<input asp-for="CertificateThumbprint" readonly class="form-control" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
@ -16,7 +16,7 @@
|
||||
|
||||
<div class="col-md-8">
|
||||
<div class="form-group">
|
||||
<span>You can get access here to LND-gRPC or SSH services exposed by your server</span>
|
||||
<span>You can get access here to LND (gRPC, Rest) or SSH services exposed by your server</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@ -29,17 +29,24 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach(var lnd in Model.LNDServices)
|
||||
@foreach (var lnd in Model.LNDServices)
|
||||
{
|
||||
<tr>
|
||||
<td>@lnd.Crypto</td>
|
||||
<td>@lnd.Type</td>
|
||||
<td>LND @lnd.Type.ToString()</td>
|
||||
<td style="text-align:right">
|
||||
<a asp-action="LNDGRPCServices" asp-route-cryptoCode="@lnd.Crypto" asp-route-index="@lnd.Index">See information</a>
|
||||
@if (lnd.Type == BTCPayServer.Configuration.External.LndTypes.gRPC)
|
||||
{
|
||||
<a asp-action="LNDGRPCServices" asp-route-cryptoCode="@lnd.Crypto" asp-route-index="@lnd.Index">See information</a>
|
||||
}
|
||||
else if (lnd.Type == BTCPayServer.Configuration.External.LndTypes.Rest)
|
||||
{
|
||||
<a asp-action="LndRestServices" asp-route-cryptoCode="@lnd.Crypto" asp-route-index="@lnd.Index">See information</a>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@if(Model.HasSSH)
|
||||
@if (Model.HasSSH)
|
||||
{
|
||||
<tr>
|
||||
<td>None</td>
|
||||
|
@ -11,6 +11,12 @@
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<form method="post">
|
||||
<p>
|
||||
You can obtain API keys at
|
||||
<a href="https://changelly.com/?ref_id=804298eb5753" target="_blank">
|
||||
Changelly.com
|
||||
</a>
|
||||
</p>
|
||||
<div class="form-group">
|
||||
<label asp-for="ApiUrl"></label>
|
||||
<input asp-for="ApiUrl" class="form-control"/>
|
||||
@ -25,17 +31,17 @@
|
||||
<label asp-for="ApiSecret"></label>
|
||||
<input asp-for="ApiSecret" class="form-control"/>
|
||||
<span asp-validation-for="ApiSecret" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="ChangellyMerchantId"></label>
|
||||
<input asp-for="ChangellyMerchantId" class="form-control"/>
|
||||
<span asp-validation-for="ChangellyMerchantId" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="AmountMarkupPercentage"></label>
|
||||
<input asp-for="AmountMarkupPercentage" class="form-control"/>
|
||||
<span asp-validation-for="AmountMarkupPercentage" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="ShowFiat"></label>
|
||||
<input asp-for="ShowFiat" class="form-check"/>
|
||||
|
@ -169,7 +169,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@*<div class="form-group">
|
||||
<div class="form-group">
|
||||
<div class="form-group">
|
||||
<h5>Third party Payment methods</h5>
|
||||
</div>
|
||||
@ -203,7 +203,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>*@
|
||||
</div>
|
||||
|
||||
@if(Model.CanDelete)
|
||||
{
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
[](https://hub.docker.com/r/nicolasdorier/btcpayserver/)
|
||||
[](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fbtcpayserver%2Fbtcpayserver-azure%2Fmaster%2Fazuredeploy.json)
|
||||
[](https://circleci.com/gh/btcpayserver/btcpayserver)
|
||||
|
||||
# BTCPay Server
|
||||
|
||||
|
Reference in New Issue
Block a user