Some refactoring improving performance, and better tests for multiple currencies

This commit is contained in:
nicolas.dorier
2018-01-11 17:29:48 +09:00
parent 55d50af39d
commit 3a91965187
19 changed files with 253 additions and 153 deletions

View File

@@ -43,6 +43,8 @@ namespace BTCPayServer.Tests
{ {
get; set; get; set;
} }
public Uri LTCNBXplorerUri { get; set; }
public string CookieFile public string CookieFile
{ {
get; set; get; set;
@@ -79,7 +81,9 @@ namespace BTCPayServer.Tests
config.AppendLine($"regtest=1"); config.AppendLine($"regtest=1");
config.AppendLine($"port={Port}"); config.AppendLine($"port={Port}");
config.AppendLine($"explorer.url={NBXplorerUri.AbsoluteUri}"); config.AppendLine($"explorer.url={NBXplorerUri.AbsoluteUri}");
config.AppendLine($"ltc.explorer.url={LTCNBXplorerUri.AbsoluteUri}");
config.AppendLine($"explorer.cookiefile={CookieFile}"); config.AppendLine($"explorer.cookiefile={CookieFile}");
config.AppendLine($"ltc.explorer.cookiefile={CookieFile}");
config.AppendLine($"hdpubkey={HDPrivateKey.Neuter().ToString(Network.RegTest)}"); config.AppendLine($"hdpubkey={HDPrivateKey.Neuter().ToString(Network.RegTest)}");
if (Postgres != null) if (Postgres != null)
config.AppendLine($"postgres=" + Postgres); config.AppendLine($"postgres=" + Postgres);

View File

@@ -47,11 +47,17 @@ namespace BTCPayServer.Tests
Directory.CreateDirectory(_Directory); Directory.CreateDirectory(_Directory);
ExplorerNode = new RPCClient(RPCCredentialString.Parse(GetEnvironment("TESTS_RPCCONNECTION", "server=http://127.0.0.1:43782;ceiwHEbqWI83:DwubwWsoo3")), Network); var network = new BTCPayNetworkProvider(Network);
ExplorerNode = new RPCClient(RPCCredentialString.Parse(GetEnvironment("TESTS_RPCCONNECTION", "server=http://127.0.0.1:43782;ceiwHEbqWI83:DwubwWsoo3")), network.GetNetwork("BTC").NBitcoinNetwork);
LTCExplorerNode = new RPCClient(RPCCredentialString.Parse(GetEnvironment("TESTS_LTCRPCCONNECTION", "server=http://127.0.0.1:43783;ceiwHEbqWI83:DwubwWsoo3")), network.GetNetwork("LTC").NBitcoinNetwork);
ExplorerClient = new ExplorerClient(Network, new Uri(GetEnvironment("TESTS_NBXPLORERURL", "http://127.0.0.1:32838/"))); ExplorerClient = new ExplorerClient(Network, new Uri(GetEnvironment("TESTS_NBXPLORERURL", "http://127.0.0.1:32838/")));
LTCExplorerClient = new ExplorerClient(Network, new Uri(GetEnvironment("TESTS_LTCNBXPLORERURL", "http://127.0.0.1:32839/")));
PayTester = new BTCPayServerTester(Path.Combine(_Directory, "pay")) PayTester = new BTCPayServerTester(Path.Combine(_Directory, "pay"))
{ {
NBXplorerUri = ExplorerClient.Address, NBXplorerUri = ExplorerClient.Address,
LTCNBXplorerUri = LTCExplorerClient.Address,
Postgres = GetEnvironment("TESTS_POSTGRES", "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver") Postgres = GetEnvironment("TESTS_POSTGRES", "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver")
}; };
PayTester.Port = int.Parse(GetEnvironment("TESTS_PORT", Utils.FreeTcpPort().ToString())); PayTester.Port = int.Parse(GetEnvironment("TESTS_PORT", Utils.FreeTcpPort().ToString()));
@@ -107,10 +113,16 @@ namespace BTCPayServer.Tests
get; set; get; set;
} }
public RPCClient LTCExplorerNode
{
get; set;
}
public ExplorerClient ExplorerClient public ExplorerClient ExplorerClient
{ {
get; set; get; set;
} }
public ExplorerClient LTCExplorerClient { get; set; }
HttpClient _Http = new HttpClient(); HttpClient _Http = new HttpClient();

View File

@@ -71,6 +71,23 @@ namespace BTCPayServer.Tests
return store; return store;
} }
public void RegisterDerivationScheme(string crytoCode)
{
RegisterDerivationSchemeAsync(crytoCode).GetAwaiter().GetResult();
}
public async Task RegisterDerivationSchemeAsync(string crytoCode)
{
var store = parent.PayTester.GetController<StoresController>(UserId);
var networkProvider = parent.PayTester.GetService<BTCPayNetworkProvider>();
var derivation = new DerivationStrategyFactory(networkProvider.GetNetwork(crytoCode).NBitcoinNetwork).Parse(ExtKey.Neuter().ToString() + "-[legacy]");
await store.AddDerivationScheme(StoreId, new DerivationSchemeViewModel()
{
CryptoCurrency = crytoCode,
DerivationSchemeFormat = crytoCode,
DerivationScheme = derivation.ToString(),
}, "Save");
}
public DerivationStrategyBase DerivationScheme { get; set; } public DerivationStrategyBase DerivationScheme { get; set; }
private async Task RegisterAsync() private async Task RegisterAsync()

View File

@@ -43,7 +43,7 @@ namespace BTCPayServer.Tests
entity.TxFee = Money.Coins(0.1m); entity.TxFee = Money.Coins(0.1m);
entity.Rate = 5000; entity.Rate = 5000;
var cryptoData = entity.GetCryptoData("BTC"); var cryptoData = entity.GetCryptoData("BTC", null);
Assert.NotNull(cryptoData); // Should use legacy data to build itself Assert.NotNull(cryptoData); // Should use legacy data to build itself
entity.Payments = new System.Collections.Generic.List<PaymentEntity>(); entity.Payments = new System.Collections.Generic.List<PaymentEntity>();
entity.ProductInformation = new ProductInformation() { Price = 5000 }; entity.ProductInformation = new ProductInformation() { Price = 5000 };
@@ -92,17 +92,17 @@ namespace BTCPayServer.Tests
}) })
})); }));
entity.Payments = new List<PaymentEntity>(); entity.Payments = new List<PaymentEntity>();
cryptoData = entity.GetCryptoData("BTC"); cryptoData = entity.GetCryptoData("BTC", null);
accounting = cryptoData.Calculate(); accounting = cryptoData.Calculate();
Assert.Equal(Money.Coins(5.1m), accounting.Due); Assert.Equal(Money.Coins(5.1m), accounting.Due);
cryptoData = entity.GetCryptoData("LTC"); cryptoData = entity.GetCryptoData("LTC", null);
accounting = cryptoData.Calculate(); accounting = cryptoData.Calculate();
Assert.Equal(Money.Coins(10.01m), accounting.TotalDue); Assert.Equal(Money.Coins(10.01m), accounting.TotalDue);
entity.Payments.Add(new PaymentEntity() { CryptoCode = "BTC", Output = new TxOut(Money.Coins(1.0m), new Key()), Accounted = true }); entity.Payments.Add(new PaymentEntity() { CryptoCode = "BTC", Output = new TxOut(Money.Coins(1.0m), new Key()), Accounted = true });
cryptoData = entity.GetCryptoData("BTC"); cryptoData = entity.GetCryptoData("BTC", null);
accounting = cryptoData.Calculate(); accounting = cryptoData.Calculate();
Assert.Equal(Money.Coins(4.2m), accounting.Due); Assert.Equal(Money.Coins(4.2m), accounting.Due);
Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid); Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid);
@@ -110,7 +110,7 @@ namespace BTCPayServer.Tests
Assert.Equal(Money.Coins(5.2m), accounting.TotalDue); Assert.Equal(Money.Coins(5.2m), accounting.TotalDue);
Assert.Equal(2, accounting.TxCount); Assert.Equal(2, accounting.TxCount);
cryptoData = entity.GetCryptoData("LTC"); cryptoData = entity.GetCryptoData("LTC", null);
accounting = cryptoData.Calculate(); accounting = cryptoData.Calculate();
Assert.Equal(Money.Coins(10.01m + 0.1m * 2 - 2.0m /* 8.21m */), accounting.Due); Assert.Equal(Money.Coins(10.01m + 0.1m * 2 - 2.0m /* 8.21m */), accounting.Due);
Assert.Equal(Money.Coins(0.0m), accounting.CryptoPaid); Assert.Equal(Money.Coins(0.0m), accounting.CryptoPaid);
@@ -120,7 +120,7 @@ namespace BTCPayServer.Tests
entity.Payments.Add(new PaymentEntity() { CryptoCode = "LTC", Output = new TxOut(Money.Coins(1.0m), new Key()), Accounted = true }); entity.Payments.Add(new PaymentEntity() { CryptoCode = "LTC", Output = new TxOut(Money.Coins(1.0m), new Key()), Accounted = true });
cryptoData = entity.GetCryptoData("BTC"); cryptoData = entity.GetCryptoData("BTC", null);
accounting = cryptoData.Calculate(); accounting = cryptoData.Calculate();
Assert.Equal(Money.Coins(4.2m - 0.5m + 0.01m / 2), accounting.Due); Assert.Equal(Money.Coins(4.2m - 0.5m + 0.01m / 2), accounting.Due);
Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid); Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid);
@@ -128,7 +128,7 @@ namespace BTCPayServer.Tests
Assert.Equal(Money.Coins(5.2m + 0.01m / 2), accounting.TotalDue); // The fee for LTC added Assert.Equal(Money.Coins(5.2m + 0.01m / 2), accounting.TotalDue); // The fee for LTC added
Assert.Equal(2, accounting.TxCount); Assert.Equal(2, accounting.TxCount);
cryptoData = entity.GetCryptoData("LTC"); cryptoData = entity.GetCryptoData("LTC", null);
accounting = cryptoData.Calculate(); accounting = cryptoData.Calculate();
Assert.Equal(Money.Coins(8.21m - 1.0m + 0.01m), accounting.Due); Assert.Equal(Money.Coins(8.21m - 1.0m + 0.01m), accounting.Due);
Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid); Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid);
@@ -139,7 +139,7 @@ namespace BTCPayServer.Tests
var remaining = Money.Coins(4.2m - 0.5m + 0.01m / 2); var remaining = Money.Coins(4.2m - 0.5m + 0.01m / 2);
entity.Payments.Add(new PaymentEntity() { CryptoCode = "BTC", Output = new TxOut(remaining, new Key()), Accounted = true }); entity.Payments.Add(new PaymentEntity() { CryptoCode = "BTC", Output = new TxOut(remaining, new Key()), Accounted = true });
cryptoData = entity.GetCryptoData("BTC"); cryptoData = entity.GetCryptoData("BTC", null);
accounting = cryptoData.Calculate(); accounting = cryptoData.Calculate();
Assert.Equal(Money.Zero, accounting.Due); Assert.Equal(Money.Zero, accounting.Due);
Assert.Equal(Money.Coins(1.0m) + remaining, accounting.CryptoPaid); Assert.Equal(Money.Coins(1.0m) + remaining, accounting.CryptoPaid);
@@ -148,7 +148,7 @@ namespace BTCPayServer.Tests
Assert.Equal(accounting.Paid, accounting.TotalDue); Assert.Equal(accounting.Paid, accounting.TotalDue);
Assert.Equal(2, accounting.TxCount); Assert.Equal(2, accounting.TxCount);
cryptoData = entity.GetCryptoData("LTC"); cryptoData = entity.GetCryptoData("LTC", null);
accounting = cryptoData.Calculate(); accounting = cryptoData.Calculate();
Assert.Equal(Money.Zero, accounting.Due); Assert.Equal(Money.Zero, accounting.Due);
Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid); Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid);
@@ -384,6 +384,93 @@ namespace BTCPayServer.Tests
} }
} }
[Fact]
public void CanPayWithTwoCurrencies()
{
using (var tester = ServerTester.Create())
{
tester.Start();
var user = tester.NewAccount();
user.GrantAccess();
// First we try payment with a merchant having only BTC
var invoice = user.BitPay.CreateInvoice(new Invoice()
{
Price = 5000.0,
Currency = "USD",
PosData = "posData",
OrderId = "orderId",
ItemDesc = "Some description",
FullNotifications = true
}, Facade.Merchant);
var cashCow = tester.ExplorerNode;
var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network);
var firstPayment = Money.Coins(0.04m);
cashCow.SendToAddress(invoiceAddress, firstPayment);
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);
//////////////////////
// Retry now with LTC enabled
user.RegisterDerivationScheme("LTC");
invoice = user.BitPay.CreateInvoice(new Invoice()
{
Price = 5000.0,
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);
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));
cashCow.Generate(2); // LTC is not worth a lot, so just to make sure we have money...
cashCow.SendToAddress(invoiceAddress, secondPayment);
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);
}
}
[Fact] [Fact]
public void InvoiceFlowThroughDifferentStatesCorrectly() public void InvoiceFlowThroughDifferentStatesCorrectly()
{ {
@@ -398,8 +485,6 @@ namespace BTCPayServer.Tests
Currency = "USD", Currency = "USD",
PosData = "posData", PosData = "posData",
OrderId = "orderId", OrderId = "orderId",
//RedirectURL = redirect + "redirect",
//NotificationURL = CallbackUri + "/notification",
ItemDesc = "Some description", ItemDesc = "Some description",
FullNotifications = true FullNotifications = true
}, Facade.Merchant); }, Facade.Merchant);

View File

@@ -11,7 +11,8 @@ services:
dockerfile: BTCPayServer.Tests/Dockerfile dockerfile: BTCPayServer.Tests/Dockerfile
environment: environment:
TESTS_RPCCONNECTION: server=http://bitcoind:43782;ceiwHEbqWI83:DwubwWsoo3 TESTS_RPCCONNECTION: server=http://bitcoind:43782;ceiwHEbqWI83:DwubwWsoo3
TESTS_BTCNBXPLORERURL: http://bitcoin-nbxplorer:32838/ TESTS_LTCRPCCONNECTION: server=http://litecoind:43782;ceiwHEbqWI83:DwubwWsoo3
TESTS_NBXPLORERURL: http://bitcoin-nbxplorer:32838/
TESTS_LTCNBXPLORERURL: http://litecoin-nbxplorer:32839/ TESTS_LTCNBXPLORERURL: http://litecoin-nbxplorer:32839/
TESTS_POSTGRES: User ID=postgres;Host=postgres;Port=5432;Database=btcpayserver TESTS_POSTGRES: User ID=postgres;Host=postgres;Port=5432;Database=btcpayserver
TESTS_PORT: 80 TESTS_PORT: 80

View File

@@ -25,5 +25,9 @@ namespace BTCPayServer
} }
public string CryptoImagePath { get; set; } public string CryptoImagePath { get; set; }
public override string ToString()
{
return CryptoCode;
}
} }
} }

View File

@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
<Version>1.0.0.64</Version> <Version>1.0.0.65</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Remove="Build\dockerfiles\**" /> <Compile Remove="Build\dockerfiles\**" />
@@ -22,7 +22,7 @@
<PackageReference Include="Hangfire.PostgreSql" Version="1.4.8.1" /> <PackageReference Include="Hangfire.PostgreSql" Version="1.4.8.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Filter" Version="1.1.2" /> <PackageReference Include="Microsoft.Extensions.Logging.Filter" Version="1.1.2" />
<PackageReference Include="NBitcoin" Version="4.0.0.51" /> <PackageReference Include="NBitcoin" Version="4.0.0.51" />
<PackageReference Include="NBitpayClient" Version="1.0.0.14" /> <PackageReference Include="NBitpayClient" Version="1.0.0.16" />
<PackageReference Include="DBreeze" Version="1.87.0" /> <PackageReference Include="DBreeze" Version="1.87.0" />
<PackageReference Include="NBXplorer.Client" Version="1.0.0.28" /> <PackageReference Include="NBXplorer.Client" Version="1.0.0.28" />
<PackageReference Include="NicolasDorier.CommandLine" Version="1.0.0.1" /> <PackageReference Include="NicolasDorier.CommandLine" Version="1.0.0.1" />

View File

@@ -46,7 +46,7 @@ namespace BTCPayServer.Configuration
Logs.Configuration.LogInformation("Network: " + Network); Logs.Configuration.LogInformation("Network: " + Network);
bool btcHandled = false;
foreach (var net in new BTCPayNetworkProvider(Network).GetAll()) foreach (var net in new BTCPayNetworkProvider(Network).GetAll())
{ {
var nbxplorer = NBXplorer.Configuration.NetworkInformation.GetNetworkByName(net.NBitcoinNetwork.Name); var nbxplorer = NBXplorer.Configuration.NetworkInformation.GetNetworkByName(net.NBitcoinNetwork.Name);
@@ -54,12 +54,16 @@ namespace BTCPayServer.Configuration
var cookieFile = conf.GetOrDefault<string>($"{net.CryptoCode}.explorer.cookiefile", nbxplorer.GetDefaultCookieFile()); var cookieFile = conf.GetOrDefault<string>($"{net.CryptoCode}.explorer.cookiefile", nbxplorer.GetDefaultCookieFile());
if (explorer != null) if (explorer != null)
{ {
#pragma warning disable CS0618
if (net.IsBTC)
btcHandled = true;
#pragma warning restore CS0618
ExplorerFactories.Add(net.CryptoCode, (n) => CreateExplorerClient(n, explorer, cookieFile)); ExplorerFactories.Add(net.CryptoCode, (n) => CreateExplorerClient(n, explorer, cookieFile));
} }
} }
// Handle legacy explorer.url and explorer.cookiefile // Handle legacy explorer.url and explorer.cookiefile
if (ExplorerFactories.Count == 0) if (!btcHandled)
{ {
var nbxplorer = NBXplorer.Configuration.NetworkInformation.GetNetworkByName(Network.Name); // Will get BTC info var nbxplorer = NBXplorer.Configuration.NetworkInformation.GetNetworkByName(Network.Name); // Will get BTC info
var explorer = conf.GetOrDefault<Uri>($"explorer.url", new Uri(nbxplorer.GetDefaultExplorerUrl(), UriKind.Absolute)); var explorer = conf.GetOrDefault<Uri>($"explorer.url", new Uri(nbxplorer.GetDefaultExplorerUrl(), UriKind.Absolute));

View File

@@ -59,7 +59,7 @@ namespace BTCPayServer.Controllers
StatusException = invoice.ExceptionStatus StatusException = invoice.ExceptionStatus
}; };
foreach (var data in invoice.GetCryptoData()) foreach (var data in invoice.GetCryptoData(null))
{ {
var cryptoInfo = dto.CryptoInfo.First(o => o.CryptoCode.Equals(data.Key, StringComparison.OrdinalIgnoreCase)); var cryptoInfo = dto.CryptoInfo.First(o => o.CryptoCode.Equals(data.Key, StringComparison.OrdinalIgnoreCase));
var accounting = data.Value.Calculate(); var accounting = data.Value.Calculate();
@@ -128,7 +128,7 @@ namespace BTCPayServer.Controllers
var network = _NetworkProvider.GetNetwork(cryptoCode); var network = _NetworkProvider.GetNetwork(cryptoCode);
if (invoice == null || network == null || !invoice.Support(network)) if (invoice == null || network == null || !invoice.Support(network))
return null; return null;
var cryptoData = invoice.GetCryptoData(network); var cryptoData = invoice.GetCryptoData(network, _NetworkProvider);
var dto = invoice.EntityToDTO(_NetworkProvider); var dto = invoice.EntityToDTO(_NetworkProvider);
var cryptoInfo = dto.CryptoInfo.First(o => o.CryptoCode == network.CryptoCode); var cryptoInfo = dto.CryptoInfo.First(o => o.CryptoCode == network.CryptoCode);
@@ -157,12 +157,15 @@ namespace BTCPayServer.Controllers
Status = invoice.Status, Status = invoice.Status,
CryptoImage = "/" + Url.Content(network.CryptoImagePath), CryptoImage = "/" + Url.Content(network.CryptoImagePath),
NetworkFeeDescription = $"{accounting.TxCount} transaction{(accounting.TxCount > 1 ? "s" : "")} x {cryptoData.TxFee} {network.CryptoCode}", NetworkFeeDescription = $"{accounting.TxCount} transaction{(accounting.TxCount > 1 ? "s" : "")} x {cryptoData.TxFee} {network.CryptoCode}",
AvailableCryptos = invoice.GetCryptoData().Select(kv=> new PaymentModel.AvailableCrypto() AvailableCryptos = invoice.GetCryptoData(_NetworkProvider)
.Where(i => i.Value.Network != null)
.Select(kv=> new PaymentModel.AvailableCrypto()
{ {
CryptoCode = kv.Key, CryptoCode = kv.Key,
CryptoImage = "/" + _NetworkProvider.GetNetwork(kv.Key).CryptoImagePath, CryptoImage = "/" + kv.Value.Network.CryptoImagePath,
Link = Url.Action(nameof(Checkout), new { invoiceId = invoiceId, cryptoCode = kv.Key }) Link = Url.Action(nameof(Checkout), new { invoiceId = invoiceId, cryptoCode = kv.Key })
}).ToList() }).Where(c => c.CryptoImage != "/")
.ToList()
}; };
var isMultiCurrency = invoice.GetPayments().Select(p=>p.GetCryptoCode()).Concat(new[] { network.CryptoCode }).Distinct().Count() > 1; var isMultiCurrency = invoice.GetPayments().Select(p=>p.GetCryptoCode()).Concat(new[] { network.CryptoCode }).Distinct().Count() > 1;

View File

@@ -121,7 +121,9 @@ namespace BTCPayServer.Controllers
Network: derivationStrategy.Network, Network: derivationStrategy.Network,
RateProvider: _RateProviders.GetRateProvider(derivationStrategy.Network), RateProvider: _RateProviders.GetRateProvider(derivationStrategy.Network),
FeeRateProvider: _FeeProviderFactory.CreateFeeProvider(derivationStrategy.Network))) FeeRateProvider: _FeeProviderFactory.CreateFeeProvider(derivationStrategy.Network)))
.Where(_ => _.Wallet != null && _.FeeRateProvider != null && _.RateProvider != null) .Where(_ => _.Wallet != null &&
_.FeeRateProvider != null &&
_.RateProvider != null)
.Select(_ => .Select(_ =>
{ {
return new return new

View File

@@ -14,7 +14,7 @@ namespace BTCPayServer.Events
public override string ToString() public override string ToString()
{ {
String address = ScriptPubKey.GetDestinationAddress(Network.NBitcoinNetwork)?.ToString() ?? ScriptPubKey.ToString(); String address = ScriptPubKey.GetDestinationAddress(Network.NBitcoinNetwork)?.ToString() ?? ScriptPubKey.ToString();
return $"{address} received a transaction"; return $"{address} received a transaction ({Network.CryptoCode})";
} }
} }
} }

View File

@@ -37,11 +37,11 @@ namespace BTCPayServer
return activeProvider != "Microsoft.EntityFrameworkCore.Sqlite"; return activeProvider != "Microsoft.EntityFrameworkCore.Sqlite";
} }
public static async Task<Dictionary<uint256, TransactionResult>> GetTransactions(this BTCPayWallet client, BTCPayNetwork network, uint256[] hashes, CancellationToken cts = default(CancellationToken)) public static async Task<Dictionary<uint256, TransactionResult>> GetTransactions(this BTCPayWallet client, uint256[] hashes, CancellationToken cts = default(CancellationToken))
{ {
hashes = hashes.Distinct().ToArray(); hashes = hashes.Distinct().ToArray();
var transactions = hashes var transactions = hashes
.Select(async o => await client.GetTransactionAsync(network, o, cts)) .Select(async o => await client.GetTransactionAsync(o, cts))
.ToArray(); .ToArray();
await Task.WhenAll(transactions).ConfigureAwait(false); await Task.WhenAll(transactions).ConfigureAwait(false);
return transactions.Select(t => t.Result).Where(t => t != null).ToDictionary(o => o.Transaction.GetHash()); return transactions.Select(t => t.Result).Where(t => t != null).ToDictionary(o => o.Transaction.GetHash());

View File

@@ -150,7 +150,7 @@ namespace BTCPayServer.HostedServices
} }
var derivationStrategies = invoice.GetDerivationStrategies(_NetworkProvider).ToArray(); var derivationStrategies = invoice.GetDerivationStrategies(_NetworkProvider).ToArray();
var payments = await GetPaymentsWithTransaction(derivationStrategies, invoice); var payments = await GetPaymentsWithTransaction(null, derivationStrategies, invoice);
foreach (Task<NetworkCoins> coinsAsync in GetCoinsPerNetwork(context, invoice, derivationStrategies)) foreach (Task<NetworkCoins> coinsAsync in GetCoinsPerNetwork(context, invoice, derivationStrategies))
{ {
var coins = await coinsAsync; var coins = await coinsAsync;
@@ -173,11 +173,11 @@ namespace BTCPayServer.HostedServices
} }
if (dirtyAddress) if (dirtyAddress)
{ {
payments = await GetPaymentsWithTransaction(derivationStrategies, invoice); payments = await GetPaymentsWithTransaction(payments, derivationStrategies, invoice);
} }
var network = coins.Wallet.Network; var network = coins.Wallet.Network;
var cryptoData = invoice.GetCryptoData(network); var cryptoData = invoice.GetCryptoData(network, _NetworkProvider);
var cryptoDataAll = invoice.GetCryptoData(); var cryptoDataAll = invoice.GetCryptoData(_NetworkProvider);
var accounting = cryptoData.Calculate(); var accounting = cryptoData.Calculate();
if (invoice.Status == "new" || invoice.Status == "expired") if (invoice.Status == "new" || invoice.Status == "expired")
@@ -222,7 +222,7 @@ namespace BTCPayServer.HostedServices
if (invoice.Status == "paid") if (invoice.Status == "paid")
{ {
var transactions = payments; IEnumerable<AccountedPaymentEntity> transactions = payments;
if (invoice.SpeedPolicy == SpeedPolicy.HighSpeed) if (invoice.SpeedPolicy == SpeedPolicy.HighSpeed)
{ {
transactions = transactions.Where(t => t.Confirmations >= 1 || !t.Transaction.RBF); transactions = transactions.Where(t => t.Confirmations >= 1 || !t.Transaction.RBF);
@@ -260,7 +260,7 @@ namespace BTCPayServer.HostedServices
if (invoice.Status == "confirmed") if (invoice.Status == "confirmed")
{ {
var transactions = payments; IEnumerable<AccountedPaymentEntity> transactions = payments;
transactions = transactions.Where(t => t.Confirmations >= 6); transactions = transactions.Where(t => t.Confirmations >= 6);
var totalConfirmed = transactions.Select(t => t.Payment.GetValue(cryptoDataAll, cryptoData.CryptoCode)).Sum(); var totalConfirmed = transactions.Select(t => t.Payment.GetValue(cryptoDataAll, cryptoData.CryptoCode)).Sum();
if (totalConfirmed >= accounting.TotalDue) if (totalConfirmed >= accounting.TotalDue)
@@ -292,21 +292,59 @@ namespace BTCPayServer.HostedServices
.ToArray(); .ToArray();
} }
private async Task<IEnumerable<AccountedPaymentEntity>> GetPaymentsWithTransaction(DerivationStrategy[] derivations, InvoiceEntity invoice)
class AccountedPaymentEntities : List<AccountedPaymentEntity>
{
public AccountedPaymentEntities(AccountedPaymentEntities existing)
{
if (existing != null)
_Transactions = existing._Transactions;
}
Dictionary<uint256, TransactionResult> _Transactions = new Dictionary<uint256, TransactionResult>();
public void AddToCache(IEnumerable<TransactionResult> transactions)
{
foreach (var tx in transactions)
_Transactions.TryAdd(tx.Transaction.GetHash(), tx);
}
public TransactionResult GetTransaction(uint256 txId)
{
_Transactions.TryGetValue(txId, out TransactionResult result);
return result;
}
internal IEnumerable<TransactionResult> GetTransactions()
{
return _Transactions.Values;
}
}
private async Task<AccountedPaymentEntities> GetPaymentsWithTransaction(AccountedPaymentEntities previous, DerivationStrategy[] derivations, InvoiceEntity invoice)
{ {
List<PaymentEntity> updatedPaymentEntities = new List<PaymentEntity>(); List<PaymentEntity> updatedPaymentEntities = new List<PaymentEntity>();
List<AccountedPaymentEntity> accountedPayments = new List<AccountedPaymentEntity>(); AccountedPaymentEntities accountedPayments = new AccountedPaymentEntities(previous);
foreach (var network in derivations.Select(d => d.Network)) foreach (var network in derivations.Select(d => d.Network))
{ {
var wallet = _WalletProvider.GetWallet(network); var wallet = _WalletProvider.GetWallet(network);
if (wallet == null) if (wallet == null)
continue; continue;
var transactions = await wallet.GetTransactions(network, invoice.GetPayments(network).Select(t => t.Outpoint.Hash).ToArray());
var conflicts = GetConflicts(transactions.Select(t => t.Value)); var hashesToFetch = new HashSet<uint256>(invoice
.GetPayments(network)
.Select(t => t.Outpoint.Hash)
.Where(h => accountedPayments?.GetTransaction(h) == null)
.ToList());
if (hashesToFetch.Count > 0)
{
accountedPayments.AddToCache((await wallet.GetTransactions(hashesToFetch.ToArray())).Select(t => t.Value));
}
var conflicts = GetConflicts(accountedPayments.GetTransactions());
foreach (var payment in invoice.GetPayments(network)) foreach (var payment in invoice.GetPayments(network))
{ {
TransactionResult tx; TransactionResult tx = accountedPayments.GetTransaction(payment.Outpoint.Hash);
if (!transactions.TryGetValue(payment.Outpoint.Hash, out tx)) if (tx == null)
continue; continue;
AccountedPaymentEntity accountedPayment = new AccountedPaymentEntity() AccountedPaymentEntity accountedPayment = new AccountedPaymentEntity()

View File

@@ -37,81 +37,6 @@ namespace BTCPayServer.Models
} }
} }
public class InvoiceCryptoInfo
{
[JsonProperty("cryptoCode")]
public string CryptoCode { get; set; }
[JsonProperty("rate")]
public decimal Rate { get; set; }
//"exRates":{"USD":4320.02}
[JsonProperty("exRates")]
public Dictionary<string, double> ExRates
{
get; set;
}
//"btcPaid":"0.000000"
[JsonProperty("paid")]
public string Paid
{
get; set;
}
//"btcPrice":"0.001157"
[JsonProperty("price")]
public string Price
{
get; set;
}
//"btcDue":"0.001160"
/// <summary>
/// Amount of crypto remaining to pay this invoice
/// </summary>
[JsonProperty("due")]
public string Due
{
get; set;
}
[JsonProperty("paymentUrls")]
public NBitpayClient.InvoicePaymentUrls PaymentUrls
{
get; set;
}
[JsonProperty("address")]
public string Address { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
/// <summary>
/// Total amount of this invoice
/// </summary>
[JsonProperty("totalDue")]
public string TotalDue { get; set; }
/// <summary>
/// Total amount of network fee to pay to the invoice
/// </summary>
[JsonProperty("networkFee")]
public string NetworkFee { get; set; }
/// <summary>
/// Number of transactions required to pay
/// </summary>
[JsonProperty("txCount")]
public int TxCount { get; set; }
/// <summary>
/// Total amount of the invoice paid in this crypto
/// </summary>
[JsonProperty("cryptoPaid")]
public Money CryptoPaid { get; set; }
}
//{"facade":"pos/invoice","data":{,}} //{"facade":"pos/invoice","data":{,}}
public class InvoiceResponse public class InvoiceResponse
{ {
@@ -151,7 +76,7 @@ namespace BTCPayServer.Models
} }
[JsonProperty("cryptoInfo")] [JsonProperty("cryptoInfo")]
public List<InvoiceCryptoInfo> CryptoInfo { get; set; } public List<NBitpayClient.InvoiceCryptoInfo> CryptoInfo { get; set; }
//"price":5 //"price":5
[JsonProperty("price")] [JsonProperty("price")]

View File

@@ -5,7 +5,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using BTCPayServer.Models; using BTCPayServer.Models;
using NBitpayClient;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NBitcoin.DataEncoders; using NBitcoin.DataEncoders;
using BTCPayServer.Data; using BTCPayServer.Data;
@@ -234,7 +233,7 @@ namespace BTCPayServer.Services.Invoices
} }
public List<PaymentEntity> GetPayments(string cryptoCode) public List<PaymentEntity> GetPayments(string cryptoCode)
{ {
return Payments.Where(p=>p.CryptoCode == cryptoCode).ToList(); return Payments.Where(p => p.CryptoCode == cryptoCode).ToList();
} }
public List<PaymentEntity> GetPayments(BTCPayNetwork network) public List<PaymentEntity> GetPayments(BTCPayNetwork network)
{ {
@@ -323,11 +322,11 @@ namespace BTCPayServer.Services.Invoices
Flags = new Flags() { Refundable = Refundable } Flags = new Flags() { Refundable = Refundable }
}; };
dto.CryptoInfo = new List<InvoiceCryptoInfo>(); dto.CryptoInfo = new List<NBitpayClient.InvoiceCryptoInfo>();
foreach (var info in this.GetCryptoData().Values) foreach (var info in this.GetCryptoData(networkProvider).Values)
{ {
var accounting = info.Calculate(); var accounting = info.Calculate();
var cryptoInfo = new InvoiceCryptoInfo(); var cryptoInfo = new NBitpayClient.InvoiceCryptoInfo();
cryptoInfo.CryptoCode = info.CryptoCode; cryptoInfo.CryptoCode = info.CryptoCode;
cryptoInfo.Rate = info.Rate; cryptoInfo.Rate = info.Rate;
cryptoInfo.Price = Money.Coins(ProductInformation.Price / cryptoInfo.Rate).ToString(); cryptoInfo.Price = Money.Coins(ProductInformation.Price / cryptoInfo.Rate).ToString();
@@ -337,7 +336,7 @@ namespace BTCPayServer.Services.Invoices
cryptoInfo.TotalDue = accounting.TotalDue.ToString(); cryptoInfo.TotalDue = accounting.TotalDue.ToString();
cryptoInfo.NetworkFee = accounting.NetworkFee.ToString(); cryptoInfo.NetworkFee = accounting.NetworkFee.ToString();
cryptoInfo.TxCount = accounting.TxCount; cryptoInfo.TxCount = accounting.TxCount;
cryptoInfo.CryptoPaid = accounting.CryptoPaid; cryptoInfo.CryptoPaid = accounting.CryptoPaid.ToString();
cryptoInfo.Address = info.DepositAddress; cryptoInfo.Address = info.DepositAddress;
cryptoInfo.ExRates = new Dictionary<string, double> cryptoInfo.ExRates = new Dictionary<string, double>
@@ -345,12 +344,12 @@ namespace BTCPayServer.Services.Invoices
{ ProductInformation.Currency, (double)cryptoInfo.Rate } { ProductInformation.Currency, (double)cryptoInfo.Rate }
}; };
var scheme = networkProvider.GetNetwork(info.CryptoCode)?.UriScheme ?? "BTC"; var scheme = info.Network.UriScheme;
var cryptoSuffix = cryptoInfo.CryptoCode == "BTC" ? "" : "/" + cryptoInfo.CryptoCode; var cryptoSuffix = cryptoInfo.CryptoCode == "BTC" ? "" : "/" + cryptoInfo.CryptoCode;
cryptoInfo.Url = ServerUrl.WithTrailingSlash() + $"invoice{cryptoSuffix}?id=" + Id; cryptoInfo.Url = ServerUrl.WithTrailingSlash() + $"invoice{cryptoSuffix}?id=" + Id;
cryptoInfo.PaymentUrls = new InvoicePaymentUrls() cryptoInfo.PaymentUrls = new NBitpayClient.InvoicePaymentUrls()
{ {
BIP72 = $"{scheme}:{cryptoInfo.Address}?amount={cryptoInfo.Due}&r={ServerUrl.WithTrailingSlash() + ($"i/{Id}{cryptoSuffix}")}", BIP72 = $"{scheme}:{cryptoInfo.Address}?amount={cryptoInfo.Due}&r={ServerUrl.WithTrailingSlash() + ($"i/{Id}{cryptoSuffix}")}",
BIP72b = $"{scheme}:?r={ServerUrl.WithTrailingSlash() + ($"i/{Id}{cryptoSuffix}")}", BIP72b = $"{scheme}:?r={ServerUrl.WithTrailingSlash() + ($"i/{Id}{cryptoSuffix}")}",
@@ -392,23 +391,23 @@ namespace BTCPayServer.Services.Invoices
internal bool Support(BTCPayNetwork network) internal bool Support(BTCPayNetwork network)
{ {
var rates = GetCryptoData(); var rates = GetCryptoData(null);
return rates.TryGetValue(network.CryptoCode, out var data); return rates.TryGetValue(network.CryptoCode, out var data);
} }
public CryptoData GetCryptoData(string cryptoCode) public CryptoData GetCryptoData(string cryptoCode, BTCPayNetworkProvider networkProvider)
{ {
GetCryptoData().TryGetValue(cryptoCode, out var data); GetCryptoData(networkProvider).TryGetValue(cryptoCode, out var data);
return data; return data;
} }
public CryptoData GetCryptoData(BTCPayNetwork network) public CryptoData GetCryptoData(BTCPayNetwork network, BTCPayNetworkProvider networkProvider)
{ {
GetCryptoData().TryGetValue(network.CryptoCode, out var data); GetCryptoData(networkProvider).TryGetValue(network.CryptoCode, out var data);
return data; return data;
} }
public Dictionary<string, CryptoData> GetCryptoData() public Dictionary<string, CryptoData> GetCryptoData(BTCPayNetworkProvider networkProvider)
{ {
Dictionary<string, CryptoData> rates = new Dictionary<string, CryptoData>(); Dictionary<string, CryptoData> rates = new Dictionary<string, CryptoData>();
var serializer = new Serializer(Dummy); var serializer = new Serializer(Dummy);
@@ -416,7 +415,8 @@ namespace BTCPayServer.Services.Invoices
// Legacy // Legacy
if (Rate != 0.0m) if (Rate != 0.0m)
{ {
rates.TryAdd("BTC", new CryptoData() { ParentEntity = this, Rate = Rate, CryptoCode = "BTC", TxFee = TxFee, FeeRate = new FeeRate(TxFee, 100), DepositAddress = DepositAddress }); var btcNetwork = networkProvider?.GetNetwork("BTC");
rates.TryAdd("BTC", new CryptoData() { ParentEntity = this, Rate = Rate, CryptoCode = "BTC", TxFee = TxFee, FeeRate = new FeeRate(TxFee, 100), DepositAddress = DepositAddress, Network = btcNetwork });
} }
if (CryptoData != null) if (CryptoData != null)
{ {
@@ -425,6 +425,7 @@ namespace BTCPayServer.Services.Invoices
var r = serializer.ToObject<CryptoData>(prop.Value.ToString()); var r = serializer.ToObject<CryptoData>(prop.Value.ToString());
r.CryptoCode = prop.Name; r.CryptoCode = prop.Name;
r.ParentEntity = this; r.ParentEntity = this;
r.Network = networkProvider?.GetNetwork(r.CryptoCode);
rates.TryAdd(r.CryptoCode, r); rates.TryAdd(r.CryptoCode, r);
} }
} }
@@ -433,6 +434,14 @@ namespace BTCPayServer.Services.Invoices
} }
Network Dummy = Network.Main; Network Dummy = Network.Main;
public void SetCryptoData(CryptoData cryptoData)
{
var dict = GetCryptoData(null);
dict.AddOrReplace(cryptoData.CryptoCode, cryptoData);
SetCryptoData(dict);
}
public void SetCryptoData(Dictionary<string, CryptoData> cryptoData) public void SetCryptoData(Dictionary<string, CryptoData> cryptoData)
{ {
var obj = new JObject(); var obj = new JObject();
@@ -485,6 +494,8 @@ namespace BTCPayServer.Services.Invoices
{ {
[JsonIgnore] [JsonIgnore]
public InvoiceEntity ParentEntity { get; set; } public InvoiceEntity ParentEntity { get; set; }
[JsonIgnore]
public BTCPayNetwork Network { get; set; }
[JsonProperty(PropertyName = "cryptoCode", DefaultValueHandling = DefaultValueHandling.Ignore)] [JsonProperty(PropertyName = "cryptoCode", DefaultValueHandling = DefaultValueHandling.Ignore)]
public string CryptoCode { get; set; } public string CryptoCode { get; set; }
[JsonProperty(PropertyName = "rate")] [JsonProperty(PropertyName = "rate")]
@@ -498,7 +509,7 @@ namespace BTCPayServer.Services.Invoices
public CryptoDataAccounting Calculate() public CryptoDataAccounting Calculate()
{ {
var cryptoData = ParentEntity.GetCryptoData(); var cryptoData = ParentEntity.GetCryptoData(null);
var totalDue = Money.Coins(ParentEntity.ProductInformation.Price / Rate); var totalDue = Money.Coins(ParentEntity.ProductInformation.Price / Rate);
var paid = Money.Zero; var paid = Money.Zero;
var cryptoPaid = Money.Zero; var cryptoPaid = Money.Zero;

View File

@@ -125,16 +125,15 @@ namespace BTCPayServer.Services.Invoices
CustomerEmail = invoice.RefundMail CustomerEmail = invoice.RefundMail
}); });
foreach (var cryptoData in invoice.GetCryptoData().Values) foreach (var cryptoData in invoice.GetCryptoData(networkProvider).Values)
{ {
var network = networkProvider.GetNetwork(cryptoData.CryptoCode); if (cryptoData.Network == null)
if (network == null)
throw new InvalidOperationException("CryptoCode unsupported"); throw new InvalidOperationException("CryptoCode unsupported");
context.AddressInvoices.Add(new AddressInvoiceData() context.AddressInvoices.Add(new AddressInvoiceData()
{ {
InvoiceDataId = invoice.Id, InvoiceDataId = invoice.Id,
CreatedTime = DateTimeOffset.UtcNow, CreatedTime = DateTimeOffset.UtcNow,
}.SetHash(BitcoinAddress.Create(cryptoData.DepositAddress, network.NBitcoinNetwork).ScriptPubKey.Hash, network.CryptoCode)); }.SetHash(BitcoinAddress.Create(cryptoData.DepositAddress, cryptoData.Network.NBitcoinNetwork).ScriptPubKey.Hash, cryptoData.CryptoCode));
context.HistoricalAddressInvoices.Add(new HistoricalAddressInvoiceData() context.HistoricalAddressInvoices.Add(new HistoricalAddressInvoiceData()
{ {
InvoiceDataId = invoice.Id, InvoiceDataId = invoice.Id,
@@ -169,8 +168,7 @@ namespace BTCPayServer.Services.Invoices
return false; return false;
var invoiceEntity = ToObject<InvoiceEntity>(invoice.Blob); var invoiceEntity = ToObject<InvoiceEntity>(invoice.Blob);
var cryptoData = invoiceEntity.GetCryptoData(); var currencyData = invoiceEntity.GetCryptoData(network, null);
var currencyData = cryptoData.Where(c => c.Value.CryptoCode == network.CryptoCode).Select(f => f.Value).FirstOrDefault();
if (currencyData == null) if (currencyData == null)
return false; return false;
@@ -187,7 +185,7 @@ namespace BTCPayServer.Services.Invoices
invoiceEntity.DepositAddress = currencyData.DepositAddress; invoiceEntity.DepositAddress = currencyData.DepositAddress;
} }
#pragma warning restore CS0618 #pragma warning restore CS0618
invoiceEntity.SetCryptoData(cryptoData); invoiceEntity.SetCryptoData(currencyData);
invoice.Blob = ToBytes(invoiceEntity); invoice.Blob = ToBytes(invoiceEntity);
context.AddressInvoices.Add(new AddressInvoiceData() { context.AddressInvoices.Add(new AddressInvoiceData() {
@@ -207,7 +205,7 @@ namespace BTCPayServer.Services.Invoices
private static void MarkUnassigned(string invoiceId, InvoiceEntity entity, ApplicationDbContext context, string cryptoCode) private static void MarkUnassigned(string invoiceId, InvoiceEntity entity, ApplicationDbContext context, string cryptoCode)
{ {
foreach (var address in entity.GetCryptoData()) foreach (var address in entity.GetCryptoData(null))
{ {
if (cryptoCode != null && cryptoCode != address.Value.CryptoCode) if (cryptoCode != null && cryptoCode != address.Value.CryptoCode)
continue; continue;

View File

@@ -38,12 +38,6 @@ namespace BTCPayServer.Services.Rates
}); });
} }
private bool TryGetFromCache(string key, out object obj)
{
obj = _MemoryCache.Get(key);
return obj != null;
}
public Task<ICollection<Rate>> GetRatesAsync() public Task<ICollection<Rate>> GetRatesAsync()
{ {
return _MemoryCache.GetOrCreateAsync("GLOBAL_RATES", (ICacheEntry entry) => return _MemoryCache.GetOrCreateAsync("GLOBAL_RATES", (ICacheEntry entry) =>

View File

@@ -9,6 +9,7 @@ using System.Threading.Tasks;
using BTCPayServer.Data; using BTCPayServer.Data;
using System.Threading; using System.Threading;
using NBXplorer.Models; using NBXplorer.Models;
using Microsoft.Extensions.Caching.Memory;
namespace BTCPayServer.Services.Wallets namespace BTCPayServer.Services.Wallets
{ {
@@ -51,6 +52,8 @@ namespace BTCPayServer.Services.Wallets
} }
} }
public TimeSpan CacheSpan { get; private set; } = TimeSpan.FromMinutes(60);
public async Task<BitcoinAddress> ReserveAddressAsync(DerivationStrategyBase derivationStrategy) public async Task<BitcoinAddress> ReserveAddressAsync(DerivationStrategyBase derivationStrategy)
{ {
var pathInfo = await _Client.GetUnusedAsync(derivationStrategy, DerivationFeature.Deposit, 0, true).ConfigureAwait(false); var pathInfo = await _Client.GetUnusedAsync(derivationStrategy, DerivationFeature.Deposit, 0, true).ConfigureAwait(false);
@@ -62,10 +65,8 @@ namespace BTCPayServer.Services.Wallets
await _Client.TrackAsync(derivationStrategy); await _Client.TrackAsync(derivationStrategy);
} }
public Task<TransactionResult> GetTransactionAsync(BTCPayNetwork network, uint256 txId, CancellationToken cancellation = default(CancellationToken)) public Task<TransactionResult> GetTransactionAsync(uint256 txId, CancellationToken cancellation = default(CancellationToken))
{ {
if (network == null)
throw new ArgumentNullException(nameof(network));
if (txId == null) if (txId == null)
throw new ArgumentNullException(nameof(txId)); throw new ArgumentNullException(nameof(txId));
return _Client.GetTransactionAsync(txId, cancellation); return _Client.GetTransactionAsync(txId, cancellation);

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
namespace BTCPayServer.Services.Wallets namespace BTCPayServer.Services.Wallets
{ {
@@ -29,7 +30,7 @@ namespace BTCPayServer.Services.Wallets
throw new ArgumentNullException(nameof(cryptoCode)); throw new ArgumentNullException(nameof(cryptoCode));
var network = _NetworkProvider.GetNetwork(cryptoCode); var network = _NetworkProvider.GetNetwork(cryptoCode);
var client = _Client.GetExplorerClient(cryptoCode); var client = _Client.GetExplorerClient(cryptoCode);
if (network == null && client == null) if (network == null || client == null)
return null; return null;
return new BTCPayWallet(client, network); return new BTCPayWallet(client, network);
} }