fix lq errors and tests (#5371)

* fix lq errors and tests

* more fixes

* more fixes

* fix

* fix xmr
This commit is contained in:
Andrew Camilleri 2023-10-11 14:12:33 +02:00 committed by GitHub
parent 41e3828eea
commit d3dca7e808
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 146 additions and 54 deletions

View File

@ -19,7 +19,7 @@ namespace BTCPayServer
"USDT_X = USDT_BTC * BTC_X",
"USDT_BTC = bitfinex(UST_BTC)",
},
AssetId = new uint256("ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"),
AssetId = NetworkType == ChainName.Regtest? null: new uint256("ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"),
DisplayName = "Liquid Tether",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
@ -42,7 +42,7 @@ namespace BTCPayServer
"ETB_BTC = bitpay(ETB_BTC)"
},
Divisibility = 2,
AssetId = new uint256("aa775044c32a7df391902b3659f46dfe004ccb2644ce2ddc7dba31e889391caf"),
AssetId = NetworkType == ChainName.Regtest? null: new uint256("aa775044c32a7df391902b3659f46dfe004ccb2644ce2ddc7dba31e889391caf"),
DisplayName = "Ethiopian Birr",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
@ -65,7 +65,7 @@ namespace BTCPayServer
"LCAD_BTC = bylls(CAD_BTC)",
"CAD_BTC = LCAD_BTC"
},
AssetId = new uint256("0e99c1a6da379d1f4151fb9df90449d40d0608f6cb33a5bcbfc8c265f42bab0a"),
AssetId = NetworkType == ChainName.Regtest? null: new uint256("0e99c1a6da379d1f4151fb9df90449d40d0608f6cb33a5bcbfc8c265f42bab0a"),
DisplayName = "Liquid CAD",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,

View File

@ -19,7 +19,8 @@ namespace BTCPayServer
NewTransactionEvent evtOutputs)
{
return evtOutputs.Outputs.Where(output =>
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId).Select(output =>
(output.Value is not AssetMoney && NetworkCryptoCode.Equals(evtOutputs.CryptoCode, StringComparison.InvariantCultureIgnoreCase)) ||
(output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId)).Select(output =>
{
var outpoint = new OutPoint(evtOutputs.TransactionData.TransactionHash, output.Index);
return (output, outpoint);

View File

@ -20,13 +20,13 @@ namespace BTCPayServer.Services.Rates
}
public class CurrencyNameTable
{
public static CurrencyNameTable Instance = new CurrencyNameTable();
public static CurrencyNameTable Instance = new();
public CurrencyNameTable()
{
_Currencies = LoadCurrency().ToDictionary(k => k.Code);
_Currencies = LoadCurrency().ToDictionary(k => k.Code, StringComparer.InvariantCultureIgnoreCase);
}
static readonly Dictionary<string, IFormatProvider> _CurrencyProviders = new Dictionary<string, IFormatProvider>();
static readonly Dictionary<string, IFormatProvider> _CurrencyProviders = new();
public NumberFormatInfo GetNumberFormatInfo(string currency, bool useFallback)
{

View File

@ -19,7 +19,7 @@ namespace BTCPayServer.Rating
public static CurrencyPair Parse(string str)
{
if (!TryParse(str, out var result))
throw new FormatException("Invalid currency pair");
throw new FormatException($"Invalid currency pair ({str})");
return result;
}
public static bool TryParse(string str, out CurrencyPair value)

View File

@ -52,11 +52,12 @@ namespace BTCPayServer.Tests
{
tester.ActivateLBTC();
await tester.StartAsync();
//https://github.com/ElementsProject/elements/issues/956
await tester.LBTCExplorerNode.SendCommandAsync("rescanblockchain");
var user = tester.NewAccount();
user.GrantAccess();
user.RegisterDerivationScheme("LBTC");
user.RegisterDerivationScheme("USDT");
user.RegisterDerivationScheme("ETB");
await user.GrantAccessAsync();
await tester.LBTCExplorerNode.GenerateAsync(4);
//no tether on our regtest, lets create it and set it
var tether = tester.NetworkProvider.GetNetwork<ElementsBTCPayNetwork>("USDT");
@ -75,6 +76,10 @@ namespace BTCPayServer.Tests
.AssetId = etb.AssetId;
user.RegisterDerivationScheme("LBTC");
user.RegisterDerivationScheme("USDT");
user.RegisterDerivationScheme("ETB");
//test: register 2 assets on the same elements network and make sure paying an invoice on one does not affect the other in any way
var invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(0.1m, "BTC"));
Assert.Equal(3, invoice.SupportedTransactionCurrencies.Count);
@ -82,7 +87,7 @@ namespace BTCPayServer.Tests
//1 lbtc = 1 btc
Assert.Equal(1, ci.Rate);
var star = await tester.LBTCExplorerNode.SendCommandAsync("sendtoaddress", ci.Address, ci.Due, "", "", false, true,
1, "UNSET", lbtc.AssetId);
1, "UNSET",false, lbtc.AssetId.ToString());
TestUtils.Eventually(() =>
{
@ -95,8 +100,7 @@ namespace BTCPayServer.Tests
ci = invoice.CryptoInfo.Single(info => info.CryptoCode.Equals("USDT"));
Assert.Equal(3, invoice.SupportedTransactionCurrencies.Count);
star = await tester.LBTCExplorerNode.SendCommandAsync("sendtoaddress", ci.Address, ci.Due, "", "", false, true,
1, "UNSET", tether.AssetId);
star = tester.LBTCExplorerNode.SendCommand("sendtoaddress", ci.Address, decimal.Parse(ci.Due), "x", "z", false, true, 1, "unset", false, tether.AssetId.ToString());
TestUtils.Eventually(() =>
{

View File

@ -386,11 +386,11 @@ namespace BTCPayServer.Tests
var newBolt11 = newInvoice.CryptoInfo.First(o => o.PaymentUrls.BOLT11 != null).PaymentUrls.BOLT11;
var oldBolt11 = invoice.CryptoInfo.First(o => o.PaymentUrls.BOLT11 != null).PaymentUrls.BOLT11;
Assert.NotEqual(newBolt11, oldBolt11);
Assert.Equal(newInvoice.BtcDue.GetValue(),
Assert.Equal(newInvoice.BtcDue.ToDecimal(MoneyUnit.BTC),
BOLT11PaymentRequest.Parse(newBolt11, Network.RegTest).MinimumAmount.ToDecimal(LightMoneyUnit.BTC));
}, 40000);
TestLogs.LogInformation($"Paying invoice {newInvoice.Id} remaining due amount {newInvoice.BtcDue.GetValue()} via lightning");
TestLogs.LogInformation($"Paying invoice {newInvoice.Id} remaining due amount {newInvoice.BtcDue.GetValue((BTCPayNetwork) tester.DefaultNetwork)} via lightning");
var evt = await tester.WaitForEvent<InvoiceDataChangedEvent>(async () =>
{
await tester.SendLightningPaymentAsync(newInvoice);

View File

@ -99,7 +99,7 @@ services:
custom:
nbxplorer:
image: nicolasdorier/nbxplorer:2.3.63
image: nicolasdorier/nbxplorer:2.3.66
restart: unless-stopped
ports:
- "32838:32838"
@ -307,7 +307,7 @@ services:
- "torrcdir:/usr/local/etc/tor"
- "tor_servicesdir:/var/lib/tor/hidden_services"
monerod:
image: btcpayserver/monero:0.17.0.0-amd64
image: btcpayserver/monero:0.18.2.2-5
restart: unless-stopped
container_name: xmr_monerod
entrypoint: sleep 999999
@ -317,7 +317,7 @@ services:
ports:
- "18081:18081"
monero_wallet:
image: btcpayserver/monero:0.17.0.0-amd64
image: btcpayserver/monero:0.18.2.2-5
restart: unless-stopped
container_name: xmr_wallet_rpc
entrypoint: monero-wallet-rpc --testnet --rpc-bind-ip=0.0.0.0 --disable-rpc-login --confirm-external-bind --rpc-bind-port=18082 --non-interactive --trusted-daemon --daemon-address=monerod:18081 --wallet-file=/wallet/wallet.keys --password-file=/wallet/password --tx-notify="/bin/sh ./scripts/notifier.sh -k -X GET https://host.docker.internal:14142/monerolikedaemoncallback/tx?cryptoCode=xmr&hash=%s"
@ -349,7 +349,7 @@ services:
elementsd-liquid:
restart: always
container_name: btcpayserver_elementsd_liquid
image: btcpayserver/elements:0.21.0.1
image: btcpayserver/elements:0.21.0.2-4
environment:
ELEMENTS_CHAIN: elementsregtest
ELEMENTS_EXTRA_ARGS: |
@ -364,11 +364,9 @@ services:
whitelist=0.0.0.0/0
rpcallowip=0.0.0.0/0
validatepegin=0
initialfreecoins=210000000000000
initialfreecoins=2100000000000000
con_dyna_deploy_signal=1
con_dyna_deploy_start=0
con_nminerconfirmationwindow=1
con_nrulechangeactivationthreshold=1
con_dyna_deploy_start=10
expose:
- "19332"
- "19444"

View File

@ -96,7 +96,7 @@ services:
custom:
nbxplorer:
image: nicolasdorier/nbxplorer:2.3.63
image: nicolasdorier/nbxplorer:2.3.66
restart: unless-stopped
ports:
- "32838:32838"

View File

@ -1,6 +1,7 @@
@using BTCPayServer.Services.Wallets
@using BTCPayServer.Payments
@model BTCPayServer.Components.StoreWalletBalance.StoreWalletBalanceViewModel
@inject BTCPayNetworkProvider NetworkProvider
<div id="StoreWalletBalance-@Model.Store.Id" class="widget store-wallet-balance">
<div class="d-flex gap-3 align-items-center justify-content-between mb-2">
<h6>Wallet Balance</h6>
@ -38,6 +39,12 @@
{
<div class="ct-chart"></div>
}
else if (!Model.Store.GetSupportedPaymentMethods(NetworkProvider).Any(method => method.PaymentId.PaymentType == BitcoinPaymentType.Instance && method.PaymentId.CryptoCode == Model.CryptoCode))
{
<p>
We would like to show you a chart of your balance but you have not yet <a href="@Url.Action("SetupWallet", "UIStores", new {storeId = Model.Store.Id, cryptoCode = Model.CryptoCode})">configured a wallet</a>.
</p>
}
else
{
<p>

View File

@ -75,7 +75,7 @@ public class StoreWalletBalance : ViewComponent
if (derivation is not null)
{
var balance = await wallet.GetBalance(derivation.AccountDerivation, cts.Token);
vm.Balance = balance.Available.GetValue();
vm.Balance = balance.Available.GetValue(derivation.Network);
}
}

View File

@ -74,7 +74,7 @@ namespace BTCPayServer.Components.WalletNav
if (bid is decimal b)
{
var currencyData = _currencies.GetCurrencyData(defaultCurrency, true);
vm.BalanceDefaultCurrency = (balance.GetValue() * b).ShowMoney(currencyData.Divisibility);
vm.BalanceDefaultCurrency = (balance.GetValue(network) * b).ShowMoney(currencyData.Divisibility);
}
}

View File

@ -383,10 +383,18 @@ namespace BTCPayServer.Controllers
private async Task SendFreeMoney(Cheater cheater, WalletId walletId, DerivationSchemeSettings paymentMethod)
{
var c = this.ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode);
var cashCow = cheater.GetCashCow(walletId.CryptoCode);
#if ALTCOINS
if (walletId.CryptoCode == "LBTC")
{
await cashCow.SendCommandAsync("rescanblockchain");
}
#endif
var addresses = Enumerable.Range(0, 200).Select(_ => c.GetUnusedAsync(paymentMethod.AccountDerivation, DerivationFeature.Deposit, reserve: true)).ToArray();
await Task.WhenAll(addresses);
await cheater.CashCow.GenerateAsync(addresses.Length / 8);
var b = cheater.CashCow.PrepareBatch();
await cashCow.GenerateAsync(addresses.Length / 8);
var b = cashCow.PrepareBatch();
Random r = new Random();
List<Task<uint256>> sending = new List<Task<uint256>>();
foreach (var a in addresses)
@ -394,7 +402,7 @@ namespace BTCPayServer.Controllers
sending.Add(b.SendToAddressAsync((await a).Address, Money.Coins(0.1m) + Money.Satoshis(r.Next(0, 90_000_000))));
}
await b.SendBatchAsync();
await cheater.CashCow.GenerateAsync(1);
await cashCow.GenerateAsync(1);
var factory = ServiceProvider.GetRequiredService<NBXplorerConnectionFactory>();

View File

@ -8,7 +8,7 @@ namespace BTCPayServer
{
public static class MoneyExtensions
{
public static decimal GetValue(this IMoney m, BTCPayNetwork network = null)
public static decimal GetValue(this IMoney m, BTCPayNetwork network)
{
switch (m)
{

View File

@ -55,21 +55,26 @@ namespace BTCPayServer.Services.Altcoins.Monero.UI
[HttpGet()]
public async Task<IActionResult> GetStoreMoneroLikePaymentMethods()
{
var monero = StoreData.GetSupportedPaymentMethods(_BtcPayNetworkProvider)
return View(await GetVM(StoreData));
}
[NonAction]
public async Task<MoneroLikePaymentMethodListViewModel> GetVM(StoreData storeData)
{
var monero = storeData.GetSupportedPaymentMethods(_BtcPayNetworkProvider)
.OfType<MoneroSupportedPaymentMethod>();
var excludeFilters = StoreData.GetStoreBlob().GetExcludedPaymentMethods();
var excludeFilters = storeData.GetStoreBlob().GetExcludedPaymentMethods();
var accountsList = _MoneroLikeConfiguration.MoneroLikeConfigurationItems.ToDictionary(pair => pair.Key,
pair => GetAccounts(pair.Key));
await Task.WhenAll(accountsList.Values);
return View(new MoneroLikePaymentMethodListViewModel()
return new MoneroLikePaymentMethodListViewModel()
{
Items = _MoneroLikeConfiguration.MoneroLikeConfigurationItems.Select(pair =>
GetMoneroLikePaymentMethodViewModel(monero, pair.Key, excludeFilters,
accountsList[pair.Key].Result))
});
};
}
private Task<GetAccountsResponse> GetAccounts(string cryptoCode)

View File

@ -1,14 +1,17 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Services.Invoices;
using Microsoft.Extensions.Hosting;
using NBitcoin;
using NBitcoin.RPC;
namespace BTCPayServer.Services
{
public class Cheater : IHostedService
{
private readonly ExplorerClientProvider _prov;
private readonly InvoiceRepository _invoiceRepository;
public RPCClient CashCow { get; set; }
@ -17,18 +20,47 @@ namespace BTCPayServer.Services
InvoiceRepository invoiceRepository)
{
CashCow = prov.GetExplorerClient("BTC")?.RPCClient;
_prov = prov;
_invoiceRepository = invoiceRepository;
}
public RPCClient GetCashCow(string cryptoCode)
{
return _prov.GetExplorerClient(cryptoCode)?.RPCClient;
}
public async Task UpdateInvoiceExpiry(string invoiceId, TimeSpan seconds)
{
await _invoiceRepository.UpdateInvoiceExpiry(invoiceId, seconds);
}
Task IHostedService.StartAsync(CancellationToken cancellationToken)
async Task IHostedService.StartAsync(CancellationToken cancellationToken)
{
_ = CashCow?.ScanRPCCapabilitiesAsync(cancellationToken);
return Task.CompletedTask;
#if ALTCOINS
var liquid = _prov.GetNetwork("LBTC");
if (liquid is not null)
{
var lbtcrpc = GetCashCow(liquid.CryptoCode);
await lbtcrpc.SendCommandAsync("rescanblockchain");
var elements = _prov.NetworkProviders.GetAll().OfType<ElementsBTCPayNetwork>();
foreach (ElementsBTCPayNetwork element in elements)
{
try
{
if (element.AssetId is null)
{
var issueAssetResult = await lbtcrpc.SendCommandAsync("issueasset", 100000, 0);
element.AssetId = uint256.Parse(issueAssetResult.Result["asset"].ToString());
}
}
catch (Exception e)
{
}
}
}
#endif
}
Task IHostedService.StopAsync(CancellationToken cancellationToken)

View File

@ -81,7 +81,7 @@ public class OnChainWalletReportProvider : ReportProvider
var walletId = new WalletId(store.Id, settings.Network.CryptoCode);
var command = new CommandDefinition(
commandText:
"SELECT r.tx_id, r.seen_at, t.blk_id, t.blk_height, r.balance_change " +
"SELECT r.tx_id, r.seen_at, t.blk_id, t.blk_height, r.balance_change, r.asset_id " +
"FROM get_wallets_recent(@wallet_id, @code, @interval, NULL, NULL) r " +
"JOIN txs t USING (code, tx_id) " +
"ORDER BY r.seen_at",
@ -99,6 +99,24 @@ public class OnChainWalletReportProvider : ReportProvider
var date = (DateTimeOffset)r.seen_at;
if (date > queryContext.To)
continue;
#if ALTCOINS
if (settings.Network is ElementsBTCPayNetwork elementsBTCPayNetwork)
{
var assetId = (string?)r.asset_id;
// if this is an asset scheme, check if the asset id is the same as the network asset id
if (elementsBTCPayNetwork.CryptoCode != elementsBTCPayNetwork.NetworkCryptoCode &&
assetId is not null && assetId != elementsBTCPayNetwork.AssetId?.ToString())
{
continue;
}
else if (elementsBTCPayNetwork.CryptoCode == elementsBTCPayNetwork.NetworkCryptoCode &&
!(assetId is null || assetId == elementsBTCPayNetwork.AssetId?.ToString()))
{
continue;
}
}
#endif
var values = queryContext.AddData();
var balanceChange = Money.Satoshis((long)r.balance_change).ToDecimal(MoneyUnit.BTC);
values.Add(date);

View File

@ -158,6 +158,13 @@ public class PaymentsReportProvider : ReportProvider
{
cryptoAmount = LightMoney.MilliSatoshis(v).ToDecimal(LightMoneyUnit.BTC);
}
#if ALTCOINS
//assetmoney is an object
else if (data.SelectToken("$.value") is JObject valueObject && valueObject.SelectToken("$.value")?.Value<long>() is long amountObj)
{
cryptoAmount = Money.Satoshis(amountObj).ToDecimal(MoneyUnit.BTC);
}
#endif
else if (data.SelectToken("$.value")?.Value<long>() is long amount)
{
cryptoAmount = Money.Satoshis(amount).ToDecimal(MoneyUnit.BTC);

View File

@ -1,22 +1,34 @@
@using BTCPayServer.Services.Altcoins.Monero.Configuration
@using BTCPayServer.Services.Altcoins.Monero.UI
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using BTCPayServer.Client
@using BTCPayServer.Abstractions.TagHelpers
@using BTCPayServer.Abstractions.Contracts
@inject SignInManager<ApplicationUser> SignInManager;
@inject MoneroLikeConfiguration MoneroLikeConfiguration;
@inject IScopeProvider ScopeProvider
@inject UIMoneroLikeStoreController UIMoneroLikeStore;
@{
var storeId = ScopeProvider.GetCurrentStoreId();
var isActive = !string.IsNullOrEmpty(storeId) && ViewContext.RouteData.Values.TryGetValue("Controller", out var controller) && controller is not null &&
nameof(UIMoneroLikeStoreController).StartsWith(controller.ToString() ?? string.Empty, StringComparison.InvariantCultureIgnoreCase);
}
@if (MoneroLikeConfiguration.MoneroLikeConfigurationItems.Any())
@if (SignInManager.IsSignedIn(User) && User.IsInRole(Roles.ServerAdmin) && MoneroLikeConfiguration.MoneroLikeConfigurationItems.Any())
{
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
<a asp-action="GetStoreMoneroLikePaymentMethods" asp-controller="UIMoneroLikeStore" asp-route-storeId="@storeId" class="nav-link @(isActive ? "active" : string.Empty)" id="StoreNav-Monero">
<span class="me-2 btcpay-status"></span>
<span>Monero</span>
</a>
</li>
var store = Context.GetStoreData();
var result = await UIMoneroLikeStore.GetVM(store);
foreach (var item in result.Items)
{
var isActive = !string.IsNullOrEmpty(storeId) && ViewContext.RouteData.Values.TryGetValue("Controller", out var controller) && controller is not null &&
nameof(UIMoneroLikeStoreController).StartsWith(controller.ToString() ?? string.Empty, StringComparison.InvariantCultureIgnoreCase) &&
ViewContext.RouteData.Values.TryGetValue("cryptoCode", out var cryptoCode) && cryptoCode is not null && cryptoCode.ToString() == item.CryptoCode;
<li class="nav-item">
<a class="nav-link @(isActive? "active" : "")"
asp-route-cryptoCode="@item.CryptoCode"
asp-route-storeId="@storeId"
asp-action="GetStoreMoneroLikePaymentMethod"
asp-controller="UIMoneroLikeStore">
<span class="me-2 btcpay-status btcpay-status--@(item.Enabled ? "enabled" : "pending")"></span>
<span>@item.CryptoCode Wallet</span>
</a>
</li>
}
}

View File

@ -5,7 +5,7 @@
@{
Layout = "../Shared/_NavLayout.cshtml";
ViewData["NavPartialName"] = "../UIStores/_Nav";
ViewData.SetActivePage(StoreNavPages.OnchainSettings, $"{Model.CryptoCode} Settings");
ViewData.SetActivePage(Model.CryptoCode, $"{Model.CryptoCode} Settings", Model.CryptoCode);
}
<div class="row">

View File

@ -4,7 +4,7 @@
@{
Layout = "../Shared/_NavLayout.cshtml";
ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Monero Settings");
ViewData.SetActivePage("Monero Settings", "Monero Settings", "Monero Settings");
ViewData["NavPartialName"] = "../UIStores/_Nav";
}