Compare commits
198 Commits
fwoinq
...
v1.12.0-rc
Author | SHA1 | Date | |
---|---|---|---|
3f344f2c0c | |||
d050c8e3b2 | |||
b13f140b86 | |||
7066a2a577 | |||
a8ebaa6784 | |||
60ff7e86b8 | |||
44b7ed0e6e | |||
afed3a0899 | |||
28265b30d2 | |||
a97172cea6 | |||
605741182d | |||
2c94a87be4 | |||
6f98d5aa20 | |||
3d08e70101 | |||
bdf56c0a6f | |||
b9b3860e6b | |||
b0554bbf17 | |||
b31f1812d2 | |||
04292d09e1 | |||
1081eab9db | |||
4023b24209 | |||
bac9ab08d1 | |||
75bf8a5086 | |||
3ffae30b95 | |||
2fda9cf539 | |||
c8b9a425b8 | |||
62865d7d88 | |||
3afd24fcd7 | |||
fd582aad75 | |||
f9155772f5 | |||
2e4313bf18 | |||
5ad320ee4b | |||
d46543ae16 | |||
2f23bad3bc | |||
6d288271cd | |||
b4daa76aeb | |||
5bd8067328 | |||
9ccc42f556 | |||
3ee4f43eb5 | |||
d1bf47a5c0 | |||
ccf9cfa332 | |||
773f8a9aea | |||
dd62e166a1 | |||
2fb72d5aa6 | |||
46f0818765 | |||
96569ae4aa | |||
f2b1e5f93e | |||
2326894a2b | |||
c15f02ddbf | |||
7708084331 | |||
696a414e95 | |||
c16dfb2dcb | |||
c979c4774c | |||
e82281d273 | |||
27c22d5e33 | |||
6acc545b66 | |||
609ec0989f | |||
b702621a04 | |||
89041a6744 | |||
c485c109e6 | |||
29a49d5f71 | |||
a5fafc4864 | |||
a921504bcf | |||
027154a4d3 | |||
bf1a1368ff | |||
097ffbf8a3 | |||
ec076d1560 | |||
8dadfa2111 | |||
c8ee6ead0b | |||
018e4c501d | |||
99a0b70cfa | |||
314a1352ec | |||
901e6be21e | |||
d58dde950e | |||
8ac18b74df | |||
2846c38ff5 | |||
d44efce225 | |||
d3dca7e808 | |||
41e3828eea | |||
9e76b4d28e | |||
ef03497350 | |||
e5a2aeb145 | |||
229a4ea56c | |||
f20e6d3768 | |||
1d210eb6e3 | |||
d8422a979f | |||
0cf6d39f02 | |||
076c20a3b7 | |||
0cfb0ba890 | |||
44a7e9387e | |||
e71954ee34 | |||
9cd9e84be6 | |||
25af9c4227 | |||
72a99bf9a6 | |||
f1228523cb | |||
a45d368115 | |||
16433dc183 | |||
0a956fdc73 | |||
75396f491b | |||
66a064e78b | |||
c4f8c4c7b4 | |||
22bbafa659 | |||
8cdfaba20c | |||
7da82826fb | |||
9a46a64cad | |||
33198d693d | |||
eaeb7021d5 | |||
b443acd43b | |||
616883648f | |||
7873f94848 | |||
17d1832dad | |||
f034e2cd65 | |||
19de73f9da | |||
00acbccd7f | |||
77d8e202d3 | |||
44df8cf0c5 | |||
e694568674 | |||
163f805f3b | |||
492512f527 | |||
73a4ac599c | |||
4aedf76f1f | |||
2d38113c66 | |||
445e1b7bd9 | |||
019ac7ae31 | |||
2b3b025bd8 | |||
57bc90ad03 | |||
089e16020e | |||
0c4f31794d | |||
cdffe9b355 | |||
5a28cf9e87 | |||
3b05de7f30 | |||
79b2f1652b | |||
b32e0e7cce | |||
1f9fbbee22 | |||
8c9f325c9f | |||
9bf1e35bf4 | |||
32e830a1c5 | |||
561bae071f | |||
08b6942c59 | |||
4564f9a46c | |||
58a1c6d2c8 | |||
97acec340c | |||
52790a6954 | |||
af6249a741 | |||
17064ab3c8 | |||
1487bf4ff5 | |||
e8c0858558 | |||
56fa3fe8f2 | |||
583813883c | |||
c69f95bdce | |||
b3df403980 | |||
90ce75ee21 | |||
1c5fcfe094 | |||
45c1fb42ee | |||
64bd493996 | |||
ec6029409e | |||
c0fc31c69a | |||
b5d0188f21 | |||
0ccbaf4bd6 | |||
ed43fb2071 | |||
d67ebd957e | |||
19d360a543 | |||
7dc41ebcea | |||
1eb7c727f3 | |||
ede8171408 | |||
2538f3d8f6 | |||
ac64f5e395 | |||
1a7a731b54 | |||
86f4d48bcb | |||
83536bee88 | |||
abfd6ea1dc | |||
688e873f7a | |||
c88df08350 | |||
82586590a7 | |||
88c66f30f2 | |||
9132592717 | |||
c0ffab768a | |||
69190081c8 | |||
093206cf1e | |||
a0110b7570 | |||
6d65feca4c | |||
95be0242b6 | |||
79e121c3af | |||
676ac2fe46 | |||
8eabdab53a | |||
957fb09ffc | |||
4bffe117a9 | |||
05b01a13c8 | |||
08e21c1a5d | |||
4d5245605d | |||
453548d614 | |||
95a0614ae1 | |||
36ea17a6b7 | |||
dc986959fd | |||
845e2881fa | |||
2e4be9310c | |||
a2faa6fd59 | |||
0a78846e8d |
.gitignore
BTCPayServer.Abstractions
BTCPayServer.Client
BTCPayServer.Client.csprojBTCPayServerClient.OnChainWallet.csBTCPayServerClient.PullPayments.cs
Models
CreateAppRequest.csCreatePayoutThroughStoreRequest.csInvoiceExceptionStatus.csLNURLPayPaymentMethodBaseData.csLNURLPayPaymentMethodData.csPaymentRequestData.csPayoutData.csPointOfSaleAppData.csRegisterBoltcardRequest.csStoreBaseData.csStoreReportRequest.csStoreReportsResponse.csStoreWebhookData.csWebhookEvent.csWebhookEventType.csWebhookInvoiceEvent.cs
Permissions.csBTCPayServer.Common
Altcoins
BTCPayNetworkProvider.Althash.csBTCPayNetworkProvider.Argoneum.csBTCPayNetworkProvider.BGold.csBTCPayNetworkProvider.BPlus.csBTCPayNetworkProvider.Bitcore.csBTCPayNetworkProvider.Dash.csBTCPayNetworkProvider.Dogecoin.csBTCPayNetworkProvider.Feathercoin.csBTCPayNetworkProvider.Groestlcoin.csBTCPayNetworkProvider.Litecoin.csBTCPayNetworkProvider.Monacoin.csBTCPayNetworkProvider.Polis.csBTCPayNetworkProvider.Ufo.csBTCPayNetworkProvider.Viacoin.cs
BTCPayNetwork.csBTCPayNetworkProvider.Bitcoin.csBTCPayNetworkProvider.csBTCPayServer.Common.csprojLiquid
BTCPayNetworkProvider.Liquid.csBTCPayNetworkProvider.LiquidAssets.csElementsLikeBtcPayNetwork.csLiquidExtensions.cs
Monero
Zcash
Configuration
SelectedChains.csBTCPayServer.Data
BTCPayServer.PluginPacker
BTCPayServer.Rating
AvailableRateProvider.csBTCPayServer.Rating.csprojCurrencyNameTable.csCurrencyPair.cs
Providers
ArgoneumRateProvider.csCoinGeckoRateProvider.csExchangeRateHostRateProvider.csRipioExchangeProvider.cs
RateSourceInfo.csServices
BTCPayServer.Tests
AltcoinTests
BTCPayServer.Tests.csprojChargeTester.csCrowdfundTests.csDockerfileExtensions.csFastTests.csFormTests.csGreenfieldAPITests.csPOSTests.csPaymentRequestTests.csSeleniumTester.csSeleniumTests.csServerTester.csTestAccount.csTestUtils.csThirdPartyTests.csUnitTest1.csUnitTestBase.csdocker-bitcoin-multisig-setup.shdocker-compose.altcoins.ymldocker-compose.ymlBTCPayServer
APDUVaultTransport.csBTCPayServer.csprojProgram.cs_ViewImports.cshtml
Blazor
ColorPalette.csComponents
AppSales
AppTopItems
InvoiceStatus
LabelManager
MainLogo
MainNav
Notifications
Pager
QRCode
StoreLightningBalance
StoreNumbers
StoreRecentInvoices
StoreRecentTransactions
StoreSelector
StoreWalletBalance
ThemeSwitch
TruncateCenter
WalletNav
Configuration
Controllers
BitpayInvoiceController.cs
GreenField
GreenfieldAppsController.csGreenfieldInvoiceController.csGreenfieldLightningNodeApiController.Internal.csGreenfieldLightningNodeApiController.Store.csGreenfieldPaymentRequestsController.csGreenfieldPullPaymentController.csGreenfieldReportsController.csGreenfieldStoreAutomatedLightningPayoutProcessorsController.csGreenfieldStoreLNURLPayPaymentMethodsController.csGreenfieldStoreLightningNetworkPaymentMethodsController.csGreenfieldStoreOnChainWalletsController.csGreenfieldStoreWebhooksController.csGreenfieldStoresController.csGreenfieldUsersController.csLocalBTCPayServerClient.cs
LightningAddressService.csUIAccountController.csUIAppsController.csUIBoltcardController.csUICustodianAccountsController.csUIHomeController.csUIInvoiceController.Testing.csUIInvoiceController.UI.csUIInvoiceController.csUILNURLController.csUIManageController.APIKeys.csUINotificationsController.csUIPaymentRequestController.csUIPublicController.csUIPublicLightningNodeInfoController.csUIPullPaymentController.Boltcard.csUIPullPaymentController.csUIReportsController.CheatMode.csUIReportsController.csUIServerController.csUIStorePullPaymentsController.PullPayments.csUIStoresController.Email.csUIStoresController.LightningLike.csUIStoresController.csUIUserStoresController.csUIVaultController.csUIWalletsController.csData
AddressInvoiceDataExtensions.csBoltcardDataExtensions.cs
DerivationSchemeSettings.csExtensions.csPayouts
StoreBlob.csWebhookDataExtensions.csExtensions
FileTypeDetector.csFilters
Forms
FieldValueMirror.csFormDataService.csHtmlFieldsetFormProvider.csIFormComponentProvider.cs
Models
UIFormsController.csHostedServices
AppInventoryUpdaterHostedService.csGithubVersionFetcher.csPluginUpdateFetcher.csPullPaymentHostedService.csStoreEmailRuleProcessorSender.csTransactionLabelMarkerHostedService.csWebhookSender.cs
Webhooks
Hosting
BTCPayServerServices.csBlockExplorerLinkStartupTask.csMigrationStartupTask.csStartup.csToPostgresMigrationStartupTask.cs
HwiWebSocketTransport.csModels
AccountViewModels
AppViewModels
InvoicingModels
CreateInvoiceModel.csInvoiceDetailsModel.csInvoiceReceiptViewModel.csInvoicesModel.csPaymentModel.cs
PaymentRequestViewModels
SetupBoltcardViewModel.csStoreBrandingViewModel.csStoreReportsViewModels
StoreViewModels
CheckoutAppearanceViewModel.csEditWebhookViewModel.csGeneralSettingsViewModel.csListStoresViewModel.csRatesViewModel.csTestWebhookViewModel.cs
ViewPullPaymentModel.csWalletViewModels
PaymentRequest
Payments
Bitcoin
Lightning
LightningExtensions.csLightningLikePaymentHandler.csLightningListener.csLightningSupportedPaymentMethod.cs
PaymentTypes.Bitcoin.csPaymentTypes.Lightning.csPaymentTypes.csPayoutProcessors
Plugins
Altcoins
AltcoinsPlugin.BGold.csAltcoinsPlugin.Dash.csAltcoinsPlugin.Dogecoin.csAltcoinsPlugin.Groestlcoin.csAltcoinsPlugin.Litecoin.csAltcoinsPlugin.Monacoin.csAltcoinsPlugin.cs
Liquid
Monero
AltcoinsPlugin.Monero.csMoneroLikeSpecificBtcPayNetwork.cs
RPC
JsonRpcClient.cs
Models
CreateAccountRequest.csCreateAccountResponse.csCreateAddressRequest.csCreateAddressResponse.csGetAccountsRequest.csGetAccountsResponse.csGetFeeEstimateRequest.csGetFeeEstimateResponse.csGetHeightResponse.csGetTransferByTransactionIdRequest.csGetTransferByTransactionIdResponse.csGetTransfersRequest.csGetTransfersResponse.csInfo.csMakeUriRequest.csMakeUriResponse.csParseStringConverter.csPeer.csSubaddrIndex.csSubaddressAccount.csSyncInfoResponse.cs
Utils
Zcash
AltcoinsPlugin.Zcash.cs
RPC
JsonRpcClient.cs
Models
CreateAccountRequest.csCreateAccountResponse.csCreateAddressRequest.csCreateAddressResponse.csGetAccountsRequest.csGetAccountsResponse.csGetFeeEstimateRequest.csGetFeeEstimateResponse.csGetHeightResponse.csGetTransferByTransactionIdRequest.csGetTransferByTransactionIdResponse.csGetTransfersRequest.csGetTransfersResponse.csInfo.csMakeUriRequest.csMakeUriResponse.csParseStringConverter.csPeer.csSubaddrIndex.csSubaddressAccount.csSyncInfoResponse.cs
Utils
ZcashLikeSpecificBtcPayNetwork.csBitcoin
Crowdfund
LightningAddresssResolver.csNFC
PluginManager.csPluginServiceCollection.csPointOfSale
Properties
Security
Bitpay
GreenField
Services
Altcoins
Apps
Cheater.csDefaultTransactionLinkProvider.csDisplayFormatter.csFees
FallbackFeeProvider.csFeeProviderFactory.csMempoolSpaceFeeProvider.csNBxplorerFeeProvider.csStaticFeeProvider.cs
Invoices
LightningClientFactoryService.csMails
Notifications
PaymentRequests
ReportService.csReporting
FormattedAmount.csOnChainWalletReportProvider.csPaymentsReportProvider.csPayoutsReportProvider.csProductsReportProvider.csQueryContext.csReportProvider.csViewDefinition.cs
Stores
TransactionLinkProvider.csTransactionLinkProviders.csUserService.csWalletRepository.csWallets
Storage
Services/Providers/FileSystemStorage
StorageExtensions.csTagHelpers
VaultClient.csVaultHWITransport.csViews
Shared
Bitcoin
BitcoinLikeMethodCheckout-v2.cshtmlBitcoinLikeMethodCheckout.cshtmlViewBitcoinLikePaymentData.cshtml
Crowdfund
LNURL
LayoutFoot.cshtmlLayoutHead.cshtmlLayoutHeadStoreBranding.cshtmlLayoutHeadTheme.cshtmlLightning
LightningLikeMethodCheckout-v2.cshtmlLightningLikeMethodCheckout.cshtmlViewLightningLikePaymentData.cshtml
ListRoles.cshtmlMonero
NFC
PointOfSale
PosData.cshtmlPostRedirect.cshtmlShopify
ShowQR.cshtmlTemplateEditor.cshtmlVaultElements.cshtmlZcash
_BTCPaySupporters.cshtml_Footer.cshtml_Layout.cshtml_LayoutSignedOut.cshtml_LayoutWizard.cshtml_StatusMessage.cshtml_StoreFooterLogo.cshtml_StoreHeader.cshtmlUIAccount
UIApps
UICustodianAccounts
UIForms
UIInvoice
Checkout-Body.cshtmlCheckout-Cheating.cshtmlCheckout.cshtmlCheckoutV2.cshtmlCreateInvoice.cshtmlInvoice.cshtmlInvoiceReceipt.cshtmlInvoiceReceiptPrint.cshtmlListInvoices.cshtmlListInvoicesPaymentsPartial.cshtml
UILNURL
UILightningAutomatedPayoutProcessors
UIManage
UIMoneroLikeStore
UINotifications
UIOnChainAutomatedPayoutProcessors
UIPaymentRequest
UIPublicLightningNodeInfo
UIPullPayment
UIReports
UIServer
UIStorePullPayments
UIStores
CheckoutAppearance.cshtmlGeneralSettings.cshtml
ImportWallet
Index.cshtmlLightning.cshtmlLightningSettings.cshtmlListTokens.cshtmlModifyWebhook.cshtmlStoreEmailSettings.cshtml~refs/remotes/Kukks
StoreEmails.cshtmlStoreNavPages.csStoreUsers.cshtmlTestWebhook.cshtmlWalletSettings.cshtmlWebhooks.cshtml_Nav.cshtmlUIUserStores
UIWallets
wwwroot
cart
checkout-v2
checkout/js
crowdfund
img
js
copy-to-clipboard.jsdatatable.jsform-editor.jsstore-reports.jstemplate-editor.jstheme-switch.jsvaultbridge.jsvaultbridge.ui.jsvue-utils.js
light-pos
main
payment-request
pos
swagger/v1
swagger.template.apps.jsonswagger.template.custodians.jsonswagger.template.invoices.jsonswagger.template.jsonswagger.template.lightning.common.jsonswagger.template.payment-requests.jsonswagger.template.payout-processors.jsonswagger.template.pull-payments.jsonswagger.template.stores-payment-methods.lnurl.jsonswagger.template.stores-users.jsonswagger.template.stores-wallet.on-chain.jsonswagger.template.stores.jsonswagger.template.users.jsonswagger.template.webhooks.json
vendor
FileSaver
bootstrap
decimal.js
papaparse
tom-select
Build
Changelog.mdREADME.mdamd64.Dockerfilearm32v7.Dockerfilearm64v8.Dockerfilebtcpayserver.sln.DotSettings
3
.gitignore
vendored
3
.gitignore
vendored
@ -298,4 +298,5 @@ Packed Plugins
|
||||
Plugins/packed
|
||||
|
||||
BTCPayServer/wwwroot/swagger/v1/openapi.json
|
||||
BTCPayServer/appsettings.dev.json
|
||||
BTCPayServer/appsettings.dev.json
|
||||
BTCPayServer.Tests/monero_wallet
|
||||
|
@ -31,11 +31,11 @@
|
||||
<None Include="icon.png" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlSanitizer" Version="5.0.372" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.9" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.7" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1" />
|
||||
<PackageReference Include="HtmlSanitizer" Version="8.0.723" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.0-beta.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BTCPayServer.Client\BTCPayServer.Client.csproj" />
|
||||
|
@ -84,6 +84,7 @@ namespace BTCPayServer.Abstractions.Contracts
|
||||
.UseNpgsql(_options.Value.ConnectionString, o =>
|
||||
{
|
||||
o.EnableRetryOnFailure(10);
|
||||
o.SetPostgresVersion(12, 0);
|
||||
if (!string.IsNullOrEmpty(_schemaPrefix))
|
||||
{
|
||||
o.MigrationsHistoryTable(_schemaPrefix);
|
||||
|
@ -20,6 +20,15 @@ namespace BTCPayServer.Abstractions.Extensions
|
||||
Relative
|
||||
}
|
||||
|
||||
public static void SetBlazorAllowed(this ViewDataDictionary viewData, bool allowed)
|
||||
{
|
||||
viewData["BlazorAllowed"] = allowed;
|
||||
}
|
||||
public static bool IsBlazorAllowed(this ViewDataDictionary viewData)
|
||||
{
|
||||
return viewData["BlazorAllowed"] is not false;
|
||||
}
|
||||
|
||||
public static void SetActivePage<T>(this ViewDataDictionary viewData, T activePage, string title = null, string activeId = null)
|
||||
where T : IConvertible
|
||||
{
|
||||
|
@ -5,7 +5,6 @@ using System.Reflection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Npgsql.Internal.TypeHandlers.GeometricHandlers;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Form;
|
||||
|
||||
@ -105,31 +104,7 @@ public class Form
|
||||
}
|
||||
}
|
||||
|
||||
public void SetValues(JObject values)
|
||||
{
|
||||
var fields = GetAllFields().ToDictionary(k => k.FullName, k => k.Field);
|
||||
SetValues(fields, new List<string>(), values);
|
||||
}
|
||||
|
||||
private void SetValues(Dictionary<string, Field> fields, List<string> path, JObject values)
|
||||
{
|
||||
foreach (var prop in values.Properties())
|
||||
{
|
||||
List<string> propPath = new List<string>(path.Count + 1);
|
||||
propPath.AddRange(path);
|
||||
propPath.Add(prop.Name);
|
||||
if (prop.Value.Type == JTokenType.Object)
|
||||
{
|
||||
SetValues(fields, propPath, (JObject)prop.Value);
|
||||
}
|
||||
else if (prop.Value.Type == JTokenType.String)
|
||||
{
|
||||
var fullName = string.Join('_', propPath.Where(s => !string.IsNullOrEmpty(s)));
|
||||
if (fields.TryGetValue(fullName, out var f) && !f.Constant)
|
||||
f.Value = prop.Value.Value<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ganss.XSS;
|
||||
using System.Web;
|
||||
using Ganss.Xss;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
|
||||
@ -21,6 +22,11 @@ namespace BTCPayServer.Abstractions.Services
|
||||
{
|
||||
return _htmlHelper.Raw(_htmlSanitizer.Sanitize(value));
|
||||
}
|
||||
|
||||
public IHtmlContent RawEncode(string value)
|
||||
{
|
||||
return _htmlHelper.Raw(HttpUtility.HtmlEncode(_htmlSanitizer.Sanitize(value)));
|
||||
}
|
||||
|
||||
public IHtmlContent Json(object model)
|
||||
{
|
||||
|
@ -2,51 +2,93 @@ using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace BTCPayServer.Abstractions.TagHelpers;
|
||||
|
||||
[HtmlTargetElement(Attributes = "[permission]")]
|
||||
[HtmlTargetElement(Attributes = "[not-permission]" )]
|
||||
[HtmlTargetElement(Attributes = "[not-permission]")]
|
||||
public class PermissionTagHelper : TagHelper
|
||||
{
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ILogger<PermissionTagHelper> _logger;
|
||||
|
||||
public PermissionTagHelper(IAuthorizationService authorizationService, IHttpContextAccessor httpContextAccessor, ILogger<PermissionTagHelper> logger)
|
||||
public PermissionTagHelper(IAuthorizationService authorizationService, IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_authorizationService = authorizationService;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string Permission { get; set; }
|
||||
public string NotPermission { get; set; }
|
||||
public string PermissionResource { get; set; }
|
||||
|
||||
public bool AndMode { get; set; } = false;
|
||||
|
||||
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Permission) && string.IsNullOrEmpty(NotPermission))
|
||||
var permissions = Permission?.Split(',', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>();
|
||||
var notPermissions = NotPermission?.Split(',', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>();
|
||||
|
||||
if (!permissions.Any() && !notPermissions.Any())
|
||||
return;
|
||||
if (_httpContextAccessor.HttpContext is null)
|
||||
return;
|
||||
|
||||
var expectedResult = !string.IsNullOrEmpty(Permission);
|
||||
var key = $"{Permission??NotPermission}_{PermissionResource}";
|
||||
if (!_httpContextAccessor.HttpContext.Items.TryGetValue(key, out var o) ||
|
||||
o is not AuthorizationResult res)
|
||||
bool shouldRender = true; // Assume tag should be rendered unless a check fails
|
||||
|
||||
// Process 'Permission' - User must have these permissions
|
||||
if (permissions.Any())
|
||||
{
|
||||
res = await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User,
|
||||
PermissionResource,
|
||||
Permission);
|
||||
_httpContextAccessor.HttpContext.Items.Add(key, res);
|
||||
bool finalResult = AndMode;
|
||||
foreach (var perm in permissions)
|
||||
{
|
||||
var key = $"{perm}_{PermissionResource}";
|
||||
AuthorizationResult res = await GetOrAddAuthorizationResult(key, perm);
|
||||
|
||||
if (AndMode)
|
||||
finalResult &= res.Succeeded;
|
||||
else
|
||||
finalResult |= res.Succeeded;
|
||||
|
||||
if (!AndMode && finalResult) break;
|
||||
}
|
||||
|
||||
shouldRender = finalResult;
|
||||
}
|
||||
if (expectedResult != res.Succeeded)
|
||||
|
||||
// Process 'NotPermission' - User must not have these permissions
|
||||
if (shouldRender && notPermissions.Any())
|
||||
{
|
||||
foreach (var notPerm in notPermissions)
|
||||
{
|
||||
var key = $"{notPerm}_{PermissionResource}";
|
||||
AuthorizationResult res = await GetOrAddAuthorizationResult(key, notPerm);
|
||||
|
||||
if (res.Succeeded) // If the user has a 'NotPermission', they should not see the tag
|
||||
{
|
||||
shouldRender = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldRender)
|
||||
{
|
||||
output.SuppressOutput();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<AuthorizationResult> GetOrAddAuthorizationResult(string key, string permission)
|
||||
{
|
||||
if (!_httpContextAccessor.HttpContext.Items.TryGetValue(key, out var cachedResult))
|
||||
{
|
||||
var res = await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User,
|
||||
PermissionResource, permission);
|
||||
_httpContextAccessor.HttpContext.Items[key] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
return cachedResult as AuthorizationResult;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<Version Condition=" '$(Version)' == '' ">1.7.2</Version>
|
||||
<Version Condition=" '$(Version)' == '' ">1.7.3</Version>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
@ -30,9 +30,9 @@
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.3.21" />
|
||||
<PackageReference Include="NBitcoin" Version="7.0.24" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.5.1" />
|
||||
<PackageReference Include="NBitcoin" Version="7.0.31" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="icon.png" Pack="true" PackagePath="\" />
|
||||
|
@ -55,7 +55,7 @@ namespace BTCPayServer.Client
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<OnChainWalletTransactionData>> ShowOnChainWalletTransactions(
|
||||
string storeId, string cryptoCode, TransactionStatus[] statusFilter = null, string labelFilter = null,
|
||||
string storeId, string cryptoCode, TransactionStatus[] statusFilter = null, string labelFilter = null, int skip = 0,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var query = new Dictionary<string, object>();
|
||||
@ -67,6 +67,10 @@ namespace BTCPayServer.Client
|
||||
{
|
||||
query.Add(nameof(labelFilter), labelFilter);
|
||||
}
|
||||
if (skip != 0)
|
||||
{
|
||||
query.Add(nameof(skip), skip);
|
||||
}
|
||||
var response =
|
||||
await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/transactions", query), token);
|
||||
|
@ -20,6 +20,12 @@ namespace BTCPayServer.Client
|
||||
return await HandleResponse<PullPaymentData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<RegisterBoltcardResponse> RegisterBoltcard(string pullPaymentId, RegisterBoltcardRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}/boltcards", bodyPayload: request, method: HttpMethod.Post), cancellationToken);
|
||||
return await HandleResponse<RegisterBoltcardResponse>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<PullPaymentData[]> GetPullPayments(string storeId, bool includeArchived = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Dictionary<string, object> query = new Dictionary<string, object>();
|
||||
|
@ -28,6 +28,8 @@ namespace BTCPayServer.Client.Models
|
||||
public PosViewType DefaultView { get; set; }
|
||||
public bool ShowCustomAmount { get; set; } = false;
|
||||
public bool ShowDiscount { get; set; } = true;
|
||||
public bool ShowSearch { get; set; } = true;
|
||||
public bool ShowCategories { get; set; } = true;
|
||||
public bool EnableTips { get; set; } = true;
|
||||
public string CustomAmountPayButtonText { get; set; } = null;
|
||||
public string FixedAmountPayButtonText { get; set; } = null;
|
||||
@ -37,9 +39,9 @@ namespace BTCPayServer.Client.Models
|
||||
public string RedirectUrl { get; set; } = null;
|
||||
public bool? RedirectAutomatically { get; set; } = null;
|
||||
public bool? RequiresRefundEmail { get; set; } = null;
|
||||
public bool? Archived { get; set; } = null;
|
||||
public string FormId { get; set; } = null;
|
||||
public string EmbeddedCSS { get; set; } = null;
|
||||
public CheckoutType? CheckoutType { get; set; } = null;
|
||||
}
|
||||
|
||||
public enum CrowdfundResetEvery
|
||||
@ -78,6 +80,7 @@ namespace BTCPayServer.Client.Models
|
||||
public bool? DisplayPerksValue { get; set; } = null;
|
||||
public bool? DisplayPerksRanking { get; set; } = null;
|
||||
public bool? SortPerksByPopularity { get; set; } = null;
|
||||
public bool? Archived { get; set; } = null;
|
||||
public string[] Sounds { get; set; } = null;
|
||||
public string[] AnimationColors { get; set; } = null;
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
#nullable enable
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class CreatePayoutThroughStoreRequest : CreatePayoutRequest
|
||||
{
|
||||
public string? PullPaymentId { get; set; }
|
||||
public bool? Approved { get; set; }
|
||||
public JObject? Metadata { get; set; }
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
namespace BTCPayServer.Client.Models
|
||||
namespace BTCPayServer.Client.Models;
|
||||
public enum InvoiceExceptionStatus
|
||||
{
|
||||
public enum InvoiceExceptionStatus
|
||||
{
|
||||
None,
|
||||
PaidLate,
|
||||
PaidPartial,
|
||||
Marked,
|
||||
Invalid,
|
||||
PaidOver
|
||||
}
|
||||
None,
|
||||
PaidLate,
|
||||
PaidPartial,
|
||||
Marked,
|
||||
Invalid,
|
||||
PaidOver
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,8 +1,12 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public class LNURLPayPaymentMethodBaseData
|
||||
{
|
||||
public bool UseBech32Scheme { get; set; }
|
||||
|
||||
[JsonProperty("lud12Enabled")]
|
||||
public bool LUD12Enabled { get; set; }
|
||||
|
||||
public LNURLPayPaymentMethodBaseData()
|
||||
|
@ -16,11 +16,12 @@ namespace BTCPayServer.Client.Models
|
||||
{
|
||||
}
|
||||
|
||||
public LNURLPayPaymentMethodData(string cryptoCode, bool enabled, bool useBech32Scheme)
|
||||
public LNURLPayPaymentMethodData(string cryptoCode, bool enabled, bool useBech32Scheme, bool lud12Enabled)
|
||||
{
|
||||
Enabled = enabled;
|
||||
CryptoCode = cryptoCode;
|
||||
UseBech32Scheme = useBech32Scheme;
|
||||
LUD12Enabled = lud12Enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ namespace BTCPayServer.Client.Models
|
||||
public class PaymentRequestData : PaymentRequestBaseData
|
||||
{
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public PaymentRequestData.PaymentRequestStatus Status { get; set; }
|
||||
public PaymentRequestStatus Status { get; set; }
|
||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||
public DateTimeOffset CreatedTime { get; set; }
|
||||
public string Id { get; set; }
|
||||
@ -16,7 +16,8 @@ namespace BTCPayServer.Client.Models
|
||||
{
|
||||
Pending = 0,
|
||||
Completed = 1,
|
||||
Expired = 2
|
||||
Expired = 2,
|
||||
Processing = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,5 +31,6 @@ namespace BTCPayServer.Client.Models
|
||||
public PayoutState State { get; set; }
|
||||
public int Revision { get; set; }
|
||||
public JObject PaymentProof { get; set; }
|
||||
public JObject Metadata { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ namespace BTCPayServer.Client.Models
|
||||
public string AppType { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string StoreId { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool? Archived { get; set; }
|
||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||
public DateTimeOffset Created { get; set; }
|
||||
}
|
||||
@ -19,6 +21,8 @@ namespace BTCPayServer.Client.Models
|
||||
public string DefaultView { get; set; }
|
||||
public bool ShowCustomAmount { get; set; }
|
||||
public bool ShowDiscount { get; set; }
|
||||
public bool ShowSearch { get; set; }
|
||||
public bool ShowCategories { get; set; }
|
||||
public bool EnableTips { get; set; }
|
||||
public string Currency { get; set; }
|
||||
public object Items { get; set; }
|
||||
|
39
BTCPayServer.Client/Models/RegisterBoltcardRequest.cs
Normal file
39
BTCPayServer.Client/Models/RegisterBoltcardRequest.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using NBitcoin.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public enum OnExistingBehavior
|
||||
{
|
||||
KeepVersion,
|
||||
UpdateVersion
|
||||
}
|
||||
public class RegisterBoltcardRequest
|
||||
{
|
||||
[JsonConverter(typeof(HexJsonConverter))]
|
||||
[JsonProperty("UID")]
|
||||
public byte[] UID { get; set; }
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public OnExistingBehavior? OnExisting { get; set; }
|
||||
}
|
||||
public class RegisterBoltcardResponse
|
||||
{
|
||||
[JsonProperty("LNURLW")]
|
||||
public string LNURLW { get; set; }
|
||||
public int Version { get; set; }
|
||||
[JsonProperty("K0")]
|
||||
public string K0 { get; set; }
|
||||
[JsonProperty("K1")]
|
||||
public string K1 { get; set; }
|
||||
[JsonProperty("K2")]
|
||||
public string K2 { get; set; }
|
||||
[JsonProperty("K3")]
|
||||
public string K3 { get; set; }
|
||||
[JsonProperty("K4")]
|
||||
public string K4 { get; set; }
|
||||
}
|
||||
}
|
@ -37,14 +37,20 @@ namespace BTCPayServer.Client.Models
|
||||
public bool AnyoneCanCreateInvoice { get; set; }
|
||||
public string DefaultCurrency { get; set; }
|
||||
public bool RequiresRefundEmail { get; set; }
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public CheckoutType CheckoutType { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public CheckoutType? CheckoutType { get; set; }
|
||||
|
||||
public bool LightningAmountInSatoshi { get; set; }
|
||||
public bool LightningPrivateRouteHints { get; set; }
|
||||
public bool OnChainWithLnInvoiceFallback { get; set; }
|
||||
public bool LazyPaymentMethods { get; set; }
|
||||
public bool RedirectAutomatically { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool Archived { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool ShowRecommendedFee { get; set; } = true;
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
@ -70,6 +76,17 @@ namespace BTCPayServer.Client.Models
|
||||
|
||||
public bool PayJoinEnabled { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool? AutoDetectLanguage { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool? ShowPayInWalletButton { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool? ShowStoreHeader { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool? CelebratePayment { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool? PlaySoundOnPayment { get; set; }
|
||||
|
||||
public InvoiceData.ReceiptOptions Receipt { get; set; }
|
||||
|
||||
|
||||
|
62
BTCPayServer.Client/Models/StoreReportRequest.cs
Normal file
62
BTCPayServer.Client/Models/StoreReportRequest.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BTCPayServer.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class StoreReportRequest
|
||||
{
|
||||
public string ViewName { get; set; }
|
||||
public TimePeriod TimePeriod { get; set; }
|
||||
}
|
||||
public class StoreReportResponse
|
||||
{
|
||||
public class Field
|
||||
{
|
||||
public Field()
|
||||
{
|
||||
|
||||
}
|
||||
public Field(string name, string type)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
}
|
||||
public string Name { get; set; }
|
||||
public string Type { get; set; }
|
||||
}
|
||||
public IList<Field> Fields { get; set; } = new List<Field>();
|
||||
public List<JArray> Data { get; set; }
|
||||
public DateTimeOffset From { get; set; }
|
||||
public DateTimeOffset To { get; set; }
|
||||
public List<ChartDefinition> Charts { get; set; }
|
||||
|
||||
public int GetIndex(string fieldName)
|
||||
{
|
||||
return Fields.ToList().FindIndex(f => f.Name == fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
public class ChartDefinition
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<string> Groups { get; set; } = new List<string>();
|
||||
public List<string> Totals { get; set; } = new List<string>();
|
||||
public bool HasGrandTotal { get; set; }
|
||||
public List<string> Aggregates { get; set; } = new List<string>();
|
||||
public List<string> Filters { get; set; } = new List<string>();
|
||||
}
|
||||
|
||||
public class TimePeriod
|
||||
{
|
||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||
public DateTimeOffset? From { get; set; }
|
||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||
public DateTimeOffset? To { get; set; }
|
||||
}
|
16
BTCPayServer.Client/Models/StoreReportsResponse.cs
Normal file
16
BTCPayServer.Client/Models/StoreReportsResponse.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public class StoreReportsResponse
|
||||
{
|
||||
public string ViewName { get; set; }
|
||||
public StoreReportResponse.Field[] Fields
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
@ -11,8 +11,7 @@ namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public bool Everything { get; set; } = true;
|
||||
|
||||
[JsonProperty(ItemConverterType = typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public WebhookEventType[] SpecificEvents { get; set; } = Array.Empty<WebhookEventType>();
|
||||
public string[] SpecificEvents { get; set; } = Array.Empty<string>();
|
||||
}
|
||||
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
@ -9,7 +9,7 @@ namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public class WebhookEvent
|
||||
{
|
||||
public readonly static JsonSerializerSettings DefaultSerializerSettings;
|
||||
public static readonly JsonSerializerSettings DefaultSerializerSettings;
|
||||
static WebhookEvent()
|
||||
{
|
||||
DefaultSerializerSettings = new JsonSerializerSettings();
|
||||
@ -45,8 +45,7 @@ namespace BTCPayServer.Client.Models
|
||||
}
|
||||
}
|
||||
public bool IsRedelivery { get; set; }
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public WebhookEventType Type { get; set; }
|
||||
public string Type { get; set; }
|
||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
[JsonExtensionData]
|
||||
|
@ -1,13 +1,20 @@
|
||||
namespace BTCPayServer.Client.Models
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public static class WebhookEventType
|
||||
{
|
||||
public enum WebhookEventType
|
||||
{
|
||||
InvoiceCreated,
|
||||
InvoiceReceivedPayment,
|
||||
InvoiceProcessing,
|
||||
InvoiceExpired,
|
||||
InvoiceSettled,
|
||||
InvoiceInvalid,
|
||||
InvoicePaymentSettled,
|
||||
}
|
||||
public const string InvoiceCreated = nameof(InvoiceCreated);
|
||||
public const string InvoiceReceivedPayment = nameof(InvoiceReceivedPayment);
|
||||
public const string InvoiceProcessing = nameof(InvoiceProcessing);
|
||||
public const string InvoiceExpired = nameof(InvoiceExpired);
|
||||
public const string InvoiceSettled = nameof(InvoiceSettled);
|
||||
public const string InvoiceInvalid = nameof(InvoiceInvalid);
|
||||
public const string InvoicePaymentSettled = nameof(InvoicePaymentSettled);
|
||||
public const string PayoutCreated = nameof(PayoutCreated);
|
||||
public const string PayoutApproved = nameof(PayoutApproved);
|
||||
public const string PayoutUpdated = nameof(PayoutUpdated);
|
||||
public const string PaymentRequestUpdated = nameof(PaymentRequestUpdated);
|
||||
public const string PaymentRequestCreated = nameof(PaymentRequestCreated);
|
||||
public const string PaymentRequestArchived = nameof(PaymentRequestArchived);
|
||||
public const string PaymentRequestStatusChanged = nameof(PaymentRequestStatusChanged);
|
||||
|
||||
}
|
||||
|
@ -1,44 +1,74 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public class WebhookInvoiceEvent : WebhookEvent
|
||||
public class WebhookPayoutEvent : StoreWebhookEvent
|
||||
{
|
||||
public WebhookPayoutEvent(string evtType, string storeId)
|
||||
{
|
||||
if (!evtType.StartsWith("payout", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new ArgumentException("Invalid event type", nameof(evtType));
|
||||
Type = evtType;
|
||||
StoreId = storeId;
|
||||
}
|
||||
|
||||
[JsonProperty(Order = 2)] public string PayoutId { get; set; }
|
||||
[JsonProperty(Order = 3)] public string PullPaymentId { get; set; }
|
||||
[JsonProperty(Order = 4)] [JsonConverter(typeof(StringEnumConverter))]public PayoutState PayoutState { get; set; }
|
||||
}
|
||||
public class WebhookPaymentRequestEvent : StoreWebhookEvent
|
||||
{
|
||||
public WebhookPaymentRequestEvent(string evtType, string storeId)
|
||||
{
|
||||
if (!evtType.StartsWith("paymentrequest", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new ArgumentException("Invalid event type", nameof(evtType));
|
||||
Type = evtType;
|
||||
StoreId = storeId;
|
||||
}
|
||||
|
||||
[JsonProperty(Order = 2)] public string PaymentRequestId { get; set; }
|
||||
[JsonProperty(Order = 3)] [JsonConverter(typeof(StringEnumConverter))]public PaymentRequestData.PaymentRequestStatus Status { get; set; }
|
||||
}
|
||||
|
||||
public abstract class StoreWebhookEvent : WebhookEvent
|
||||
{
|
||||
[JsonProperty(Order = 1)] public string StoreId { get; set; }
|
||||
}
|
||||
|
||||
public class WebhookInvoiceEvent : StoreWebhookEvent
|
||||
{
|
||||
public WebhookInvoiceEvent()
|
||||
{
|
||||
}
|
||||
|
||||
public WebhookInvoiceEvent(WebhookEventType evtType)
|
||||
{
|
||||
this.Type = evtType;
|
||||
public WebhookInvoiceEvent(string evtType, string storeId)
|
||||
{
|
||||
if (!evtType.StartsWith("invoice", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new ArgumentException("Invalid event type", nameof(evtType));
|
||||
Type = evtType;
|
||||
StoreId = storeId;
|
||||
}
|
||||
|
||||
[JsonProperty(Order = 1)] public string StoreId { get; set; }
|
||||
[JsonProperty(Order = 2)] public string InvoiceId { get; set; }
|
||||
[JsonProperty(Order = 3)] public JObject Metadata { get; set; }
|
||||
}
|
||||
|
||||
public class WebhookInvoiceSettledEvent : WebhookInvoiceEvent
|
||||
{
|
||||
public WebhookInvoiceSettledEvent()
|
||||
{
|
||||
}
|
||||
|
||||
public WebhookInvoiceSettledEvent(WebhookEventType evtType) : base(evtType)
|
||||
public WebhookInvoiceSettledEvent(string storeId) : base(WebhookEventType.InvoiceSettled, storeId)
|
||||
{
|
||||
}
|
||||
|
||||
public bool ManuallyMarked { get; set; }
|
||||
public bool OverPaid { get; set; }
|
||||
}
|
||||
|
||||
public class WebhookInvoiceInvalidEvent : WebhookInvoiceEvent
|
||||
{
|
||||
public WebhookInvoiceInvalidEvent()
|
||||
{
|
||||
}
|
||||
|
||||
public WebhookInvoiceInvalidEvent(WebhookEventType evtType) : base(evtType)
|
||||
public WebhookInvoiceInvalidEvent(string storeId) : base(WebhookEventType.InvoiceInvalid, storeId)
|
||||
{
|
||||
}
|
||||
|
||||
@ -47,11 +77,7 @@ namespace BTCPayServer.Client.Models
|
||||
|
||||
public class WebhookInvoiceProcessingEvent : WebhookInvoiceEvent
|
||||
{
|
||||
public WebhookInvoiceProcessingEvent()
|
||||
{
|
||||
}
|
||||
|
||||
public WebhookInvoiceProcessingEvent(WebhookEventType evtType) : base(evtType)
|
||||
public WebhookInvoiceProcessingEvent(string storeId) : base(WebhookEventType.InvoiceProcessing, storeId)
|
||||
{
|
||||
}
|
||||
|
||||
@ -60,11 +86,7 @@ namespace BTCPayServer.Client.Models
|
||||
|
||||
public class WebhookInvoiceReceivedPaymentEvent : WebhookInvoiceEvent
|
||||
{
|
||||
public WebhookInvoiceReceivedPaymentEvent()
|
||||
{
|
||||
}
|
||||
|
||||
public WebhookInvoiceReceivedPaymentEvent(WebhookEventType evtType) : base(evtType)
|
||||
public WebhookInvoiceReceivedPaymentEvent(string type, string storeId) : base(type, storeId)
|
||||
{
|
||||
}
|
||||
|
||||
@ -76,22 +98,14 @@ namespace BTCPayServer.Client.Models
|
||||
|
||||
public class WebhookInvoicePaymentSettledEvent : WebhookInvoiceReceivedPaymentEvent
|
||||
{
|
||||
public WebhookInvoicePaymentSettledEvent()
|
||||
{
|
||||
}
|
||||
|
||||
public WebhookInvoicePaymentSettledEvent(WebhookEventType evtType) : base(evtType)
|
||||
public WebhookInvoicePaymentSettledEvent(string storeId) : base(WebhookEventType.InvoicePaymentSettled, storeId)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class WebhookInvoiceExpiredEvent : WebhookInvoiceEvent
|
||||
{
|
||||
public WebhookInvoiceExpiredEvent()
|
||||
{
|
||||
}
|
||||
|
||||
public WebhookInvoiceExpiredEvent(WebhookEventType evtType) : base(evtType)
|
||||
public WebhookInvoiceExpiredEvent(string storeId) : base(WebhookEventType.InvoiceExpired, storeId)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ namespace BTCPayServer.Client
|
||||
public const string CanModifyStoreWebhooks = "btcpay.store.webhooks.canmodifywebhooks";
|
||||
public const string CanModifyStoreSettingsUnscoped = "btcpay.store.canmodifystoresettings:";
|
||||
public const string CanViewStoreSettings = "btcpay.store.canviewstoresettings";
|
||||
public const string CanViewReports = "btcpay.store.canviewreports";
|
||||
public const string CanViewInvoices = "btcpay.store.canviewinvoices";
|
||||
public const string CanCreateInvoice = "btcpay.store.cancreateinvoice";
|
||||
public const string CanModifyInvoices = "btcpay.store.canmodifyinvoices";
|
||||
@ -33,7 +34,11 @@ namespace BTCPayServer.Client
|
||||
public const string CanManageUsers = "btcpay.server.canmanageusers";
|
||||
public const string CanDeleteUser = "btcpay.user.candeleteuser";
|
||||
public const string CanManagePullPayments = "btcpay.store.canmanagepullpayments";
|
||||
public const string CanArchivePullPayments = "btcpay.store.canarchivepullpayments";
|
||||
public const string CanManagePayouts = "btcpay.store.canmanagepayouts";
|
||||
public const string CanViewPayouts = "btcpay.store.canviewpayouts";
|
||||
public const string CanCreatePullPayments = "btcpay.store.cancreatepullpayments";
|
||||
public const string CanViewPullPayments = "btcpay.store.canviewpullpayments";
|
||||
public const string CanCreateNonApprovedPullPayments = "btcpay.store.cancreatenonapprovedpullpayments";
|
||||
public const string CanViewCustodianAccounts = "btcpay.store.canviewcustodianaccounts";
|
||||
public const string CanManageCustodianAccounts = "btcpay.store.canmanagecustodianaccounts";
|
||||
@ -52,6 +57,7 @@ namespace BTCPayServer.Client
|
||||
yield return CanModifyServerSettings;
|
||||
yield return CanModifyStoreSettings;
|
||||
yield return CanViewStoreSettings;
|
||||
yield return CanViewReports;
|
||||
yield return CanViewPaymentRequests;
|
||||
yield return CanModifyPaymentRequests;
|
||||
yield return CanModifyProfile;
|
||||
@ -69,7 +75,9 @@ namespace BTCPayServer.Client
|
||||
yield return CanViewLightningInvoiceInStore;
|
||||
yield return CanCreateLightningInvoiceInStore;
|
||||
yield return CanManagePullPayments;
|
||||
yield return CanArchivePullPayments;
|
||||
yield return CanCreatePullPayments;
|
||||
yield return CanViewPullPayments;
|
||||
yield return CanCreateNonApprovedPullPayments;
|
||||
yield return CanViewCustodianAccounts;
|
||||
yield return CanManageCustodianAccounts;
|
||||
@ -77,6 +85,8 @@ namespace BTCPayServer.Client
|
||||
yield return CanWithdrawFromCustodianAccounts;
|
||||
yield return CanTradeCustodianAccount;
|
||||
yield return CanManageUsers;
|
||||
yield return CanManagePayouts;
|
||||
yield return CanViewPayouts;
|
||||
}
|
||||
}
|
||||
public static bool IsValidPolicy(string policy)
|
||||
@ -250,11 +260,13 @@ namespace BTCPayServer.Client
|
||||
Policies.CanViewStoreSettings,
|
||||
Policies.CanModifyStoreWebhooks,
|
||||
Policies.CanModifyPaymentRequests,
|
||||
Policies.CanManagePayouts,
|
||||
Policies.CanUseLightningNodeInStore);
|
||||
|
||||
PolicyHasChild(policyMap,Policies.CanManageUsers, Policies.CanCreateUser);
|
||||
PolicyHasChild(policyMap,Policies.CanManagePullPayments, Policies.CanCreatePullPayments);
|
||||
PolicyHasChild(policyMap,Policies.CanManagePullPayments, Policies.CanCreatePullPayments, Policies.CanArchivePullPayments);
|
||||
PolicyHasChild(policyMap,Policies.CanCreatePullPayments, Policies.CanCreateNonApprovedPullPayments);
|
||||
PolicyHasChild(policyMap, Policies.CanCreateNonApprovedPullPayments, Policies.CanViewPullPayments);
|
||||
PolicyHasChild(policyMap,Policies.CanModifyPaymentRequests, Policies.CanViewPaymentRequests);
|
||||
PolicyHasChild(policyMap,Policies.CanModifyProfile, Policies.CanViewProfile);
|
||||
PolicyHasChild(policyMap,Policies.CanUseLightningNodeInStore, Policies.CanViewLightningInvoiceInStore, Policies.CanCreateLightningInvoiceInStore);
|
||||
@ -265,7 +277,8 @@ namespace BTCPayServer.Client
|
||||
PolicyHasChild(policyMap, Policies.CanUseInternalLightningNode, Policies.CanCreateLightningInvoiceInternalNode, Policies.CanViewLightningInvoiceInternalNode);
|
||||
PolicyHasChild(policyMap, Policies.CanManageCustodianAccounts, Policies.CanViewCustodianAccounts);
|
||||
PolicyHasChild(policyMap, Policies.CanModifyInvoices, Policies.CanViewInvoices, Policies.CanCreateInvoice, Policies.CanCreateLightningInvoiceInStore);
|
||||
PolicyHasChild(policyMap, Policies.CanViewStoreSettings, Policies.CanViewInvoices, Policies.CanViewPaymentRequests);
|
||||
PolicyHasChild(policyMap, Policies.CanViewStoreSettings, Policies.CanViewInvoices, Policies.CanViewPaymentRequests, Policies.CanViewReports, Policies.CanViewPullPayments, Policies.CanViewPayouts);
|
||||
PolicyHasChild(policyMap, Policies.CanManagePayouts, Policies.CanViewPayouts);
|
||||
|
||||
var missingPolicies = Policies.AllPolicies.ToHashSet();
|
||||
//recurse through the tree to see which policies are not included in the tree
|
||||
|
@ -1,28 +0,0 @@
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitAlthash()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("HTML");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Htmlcoin",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://explorer.htmlcoin.com/api/tx/{0}" : "https://explorer.htmlcoin.com/api/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"HTML_X = HTML_USD",
|
||||
"HTML_USD = hitbtc(HTML_USD)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/althash.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("172'") : new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitArgoneum()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("AGM");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Argoneum",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet
|
||||
? "https://chainz.cryptoid.info/agm/tx.dws?{0}"
|
||||
: "https://chainz.cryptoid.info/agm-test/tx.dws?{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"AGM_X = AGM_BTC * BTC_X",
|
||||
"AGM_BTC = argoneum(AGM_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/argoneum.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("421'")
|
||||
: new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitBGold()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("BTG");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "BGold",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://btgexplorer.com/tx/{0}" : "https://testnet.btgexplorer.com/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"BTG_X = BTG_BTC * BTC_X",
|
||||
"BTG_BTC = exmo(BTG_BTC)",
|
||||
},
|
||||
CryptoImagePath = "imlegacy/btg.svg",
|
||||
LightningImagePath = "imlegacy/btg-lightning.svg",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("156'") : new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitBPlus()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("XBC");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "BPlus",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://chainz.cryptoid.info/xbc/tx.dws?{0}" : "https://chainz.cryptoid.info/xbc/tx.dws?{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"XBC_X = XBC_BTC * BTC_X",
|
||||
"XBC_BTC = cryptopia(XBC_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/xbc.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("65'") : new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitBitcore()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("BTX");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "BitCore",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://explorer.bitcore.cc/tx/{0}" : "https://explorer.bitcore.cc/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"BTX_X = BTX_BTC * BTC_X",
|
||||
"BTX_BTC = graviex(BTX_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/bitcore.svg",
|
||||
LightningImagePath = "imlegacy/bitcore-lightning.svg",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("160'") : new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitDash()
|
||||
{
|
||||
//not needed: NBitcoin.Altcoins.Dash.Instance.EnsureRegistered();
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("DASH");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Dash",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet
|
||||
? "https://insight.dash.org/insight/tx/{0}"
|
||||
: "https://testnet-insight.dashevo.org/insight/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"DASH_X = DASH_BTC * BTC_X",
|
||||
"DASH_BTC = bitfinex(DSH_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/dash.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
//https://github.com/satoshilabs/slips/blob/master/slip-0044.md
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("5'")
|
||||
: new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitDogecoin()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("DOGE");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Dogecoin",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://dogechain.info/tx/{0}" : "https://dogechain.info/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"DOGE_X = DOGE_BTC * BTC_X",
|
||||
"DOGE_BTC = bittrex(DOGE_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/dogecoin.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("3'") : new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitFeathercoin()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("FTC");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Feathercoin",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://explorer.feathercoin.com/tx/{0}" : "https://explorer.feathercoin.com/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"FTC_X = FTC_BTC * BTC_X",
|
||||
"FTC_BTC = bittrex(FTC_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/feathercoin.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("8'") : new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitGroestlcoin()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("GRS");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Groestlcoin",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet
|
||||
? "https://chainz.cryptoid.info/grs/tx.dws?{0}.htm"
|
||||
: "https://chainz.cryptoid.info/grs-test/tx.dws?{0}.htm",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"GRS_X = GRS_BTC * BTC_X",
|
||||
"GRS_BTC = bittrex(GRS_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/groestlcoin.png",
|
||||
LightningImagePath = "imlegacy/groestlcoin-lightning.svg",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("17'") : new KeyPath("1'"),
|
||||
SupportRBF = true,
|
||||
SupportPayJoin = true,
|
||||
VaultSupported = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitLitecoin()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("LTC");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Litecoin",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet
|
||||
? "https://live.blockcypher.com/ltc/tx/{0}/"
|
||||
: "http://explorer.litecointools.com/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"LTC_X = LTC_BTC * BTC_X",
|
||||
"LTC_BTC = coingecko(LTC_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/litecoin.svg",
|
||||
LightningImagePath = "imlegacy/litecoin-lightning.svg",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("2'") : new KeyPath("1'"),
|
||||
//https://github.com/pooler/electrum-ltc/blob/0d6989a9d2fb2edbea421c116e49d1015c7c5a91/electrum_ltc/constants.py
|
||||
ElectrumMapping = NetworkType == ChainName.Mainnet
|
||||
? new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x0488b21eU, DerivationType.Legacy },
|
||||
{0x049d7cb2U, DerivationType.SegwitP2SH },
|
||||
{0x04b24746U, DerivationType.Segwit },
|
||||
}
|
||||
: new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x043587cfU, DerivationType.Legacy },
|
||||
{0x044a5262U, DerivationType.SegwitP2SH },
|
||||
{0x045f1cf6U, DerivationType.Segwit }
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitMonacoin()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("MONA");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Monacoin",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://mona.insight.monaco-ex.org/insight/tx/{0}" : "https://testnet-mona.insight.monaco-ex.org/insight/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"MONA_X = MONA_BTC * BTC_X",
|
||||
"MONA_BTC = bittrex(MONA_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/monacoin.png",
|
||||
LightningImagePath = "imlegacy/mona-lightning.svg",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("22'") : new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitPolis()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("POLIS");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Polis",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://blockbook.polispay.org/tx/{0}" : "https://blockbook.polispay.org/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"POLIS_X = POLIS_BTC * BTC_X",
|
||||
"POLIS_BTC = polispay(POLIS_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/polis.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1997'") : new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitUfo()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("UFO");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Ufo",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://chainz.cryptoid.info/ufo/tx.dws?{0}" : "https://chainz.cryptoid.info/ufo/tx.dws?{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"UFO_X = UFO_BTC * BTC_X",
|
||||
"UFO_BTC = coinexchange(UFO_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/ufo.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("202'") : new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitViacoin()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("VIA");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Viacoin",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://explorer.viacoin.org/tx/{0}" : "https://explorer.viacoin.org/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"VIA_X = VIA_BTC * BTC_X",
|
||||
"VIA_BTC = bittrex(VIA_BTC)"
|
||||
},
|
||||
CryptoImagePath = "imlegacy/viacoin.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("14'") : new KeyPath("1'")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
#if ALTCOINS
|
||||
using NBitcoin;
|
||||
using NBitcoin.Altcoins;
|
||||
using NBitcoin.Altcoins.Elements;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitLiquid()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("LBTC");
|
||||
Add(new ElementsBTCPayNetwork()
|
||||
{
|
||||
AssetId = NetworkType == ChainName.Mainnet ? ElementsParams<Liquid>.PeggedAssetId : ElementsParams<Liquid.LiquidRegtest>.PeggedAssetId,
|
||||
CryptoCode = "LBTC",
|
||||
NetworkCryptoCode = "LBTC",
|
||||
DisplayName = "Liquid Bitcoin",
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"LBTC_X = LBTC_BTC * BTC_X",
|
||||
"LBTC_BTC = 1",
|
||||
},
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
CryptoImagePath = "imlegacy/liquid.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
|
||||
SupportRBF = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
@ -1,83 +0,0 @@
|
||||
#if ALTCOINS
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitLiquidAssets()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("LBTC");
|
||||
Add(new ElementsBTCPayNetwork()
|
||||
{
|
||||
CryptoCode = "USDt",
|
||||
NetworkCryptoCode = "LBTC",
|
||||
ShowSyncSummary = false,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"USDT_UST = 1",
|
||||
"USDT_X = USDT_BTC * BTC_X",
|
||||
"USDT_BTC = bitfinex(UST_BTC)",
|
||||
},
|
||||
AssetId = new uint256("ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"),
|
||||
DisplayName = "Liquid Tether",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
CryptoImagePath = "imlegacy/liquid-tether.svg",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
|
||||
SupportRBF = true,
|
||||
SupportLightning = false
|
||||
});
|
||||
|
||||
Add(new ElementsBTCPayNetwork()
|
||||
{
|
||||
CryptoCode = "ETB",
|
||||
NetworkCryptoCode = "LBTC",
|
||||
ShowSyncSummary = false,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
|
||||
"ETB_X = ETB_BTC * BTC_X",
|
||||
"ETB_BTC = bitpay(ETB_BTC)"
|
||||
},
|
||||
Divisibility = 2,
|
||||
AssetId = new uint256("aa775044c32a7df391902b3659f46dfe004ccb2644ce2ddc7dba31e889391caf"),
|
||||
DisplayName = "Ethiopian Birr",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
CryptoImagePath = "imlegacy/etb.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
|
||||
SupportRBF = true,
|
||||
SupportLightning = false
|
||||
});
|
||||
|
||||
Add(new ElementsBTCPayNetwork()
|
||||
{
|
||||
CryptoCode = "LCAD",
|
||||
NetworkCryptoCode = "LBTC",
|
||||
ShowSyncSummary = false,
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"LCAD_CAD = 1",
|
||||
"LCAD_X = CAD_BTC * BTC_X",
|
||||
"LCAD_BTC = bylls(CAD_BTC)",
|
||||
"CAD_BTC = LCAD_BTC"
|
||||
},
|
||||
AssetId = new uint256("0e99c1a6da379d1f4151fb9df90449d40d0608f6cb33a5bcbfc8c265f42bab0a"),
|
||||
DisplayName = "Liquid CAD",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
CryptoImagePath = "imlegacy/lcad.png",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
|
||||
SupportRBF = true,
|
||||
SupportLightning = false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
@ -1,50 +0,0 @@
|
||||
#if ALTCOINS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Common;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
using NBXplorer.Models;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public class ElementsBTCPayNetwork : BTCPayNetwork
|
||||
{
|
||||
public string NetworkCryptoCode { get; set; }
|
||||
public uint256 AssetId { get; set; }
|
||||
public override bool ReadonlyWallet { get; set; } = true;
|
||||
|
||||
public override IEnumerable<(MatchedOutput matchedOutput, OutPoint outPoint)> GetValidOutputs(
|
||||
NewTransactionEvent evtOutputs)
|
||||
{
|
||||
return evtOutputs.Outputs.Where(output =>
|
||||
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId).Select(output =>
|
||||
{
|
||||
var outpoint = new OutPoint(evtOutputs.TransactionData.TransactionHash, output.Index);
|
||||
return (output, outpoint);
|
||||
});
|
||||
}
|
||||
|
||||
public override List<TransactionInformation> FilterValidTransactions(List<TransactionInformation> transactionInformationSet)
|
||||
{
|
||||
return transactionInformationSet.FindAll(information =>
|
||||
information.Outputs.Any(output =>
|
||||
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId) ||
|
||||
information.Inputs.Any(output =>
|
||||
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId));
|
||||
}
|
||||
|
||||
public override PaymentUrlBuilder GenerateBIP21(string cryptoInfoAddress, decimal? cryptoInfoDue)
|
||||
{
|
||||
//precision 0: 10 = 0.00000010
|
||||
//precision 2: 10 = 0.00001000
|
||||
//precision 8: 10 = 10
|
||||
var money = cryptoInfoDue / (decimal)Math.Pow(10, 8 - Divisibility);
|
||||
var builder = base.GenerateBIP21(cryptoInfoAddress, money);
|
||||
builder.QueryParams.Add("assetid", AssetId.ToString());
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -1,18 +0,0 @@
|
||||
#if ALTCOINS
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public static class LiquidExtensions
|
||||
{
|
||||
public static IEnumerable<string> GetAllElementsSubChains(this BTCPayNetworkProvider networkProvider, BTCPayNetworkProvider unfiltered)
|
||||
{
|
||||
var elementsBased = networkProvider.GetAll().OfType<ElementsBTCPayNetwork>();
|
||||
var parentChains = elementsBased.Select(network => network.NetworkCryptoCode.ToUpperInvariant()).Distinct();
|
||||
return unfiltered.GetAll().OfType<ElementsBTCPayNetwork>()
|
||||
.Where(network => parentChains.Contains(network.NetworkCryptoCode)).Select(network => network.CryptoCode.ToUpperInvariant());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -1,28 +0,0 @@
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitMonero()
|
||||
{
|
||||
Add(new MoneroLikeSpecificBtcPayNetwork()
|
||||
{
|
||||
CryptoCode = "XMR",
|
||||
DisplayName = "Monero",
|
||||
Divisibility = 12,
|
||||
BlockExplorerLink =
|
||||
NetworkType == ChainName.Mainnet
|
||||
? "https://www.exploremonero.com/transaction/{0}"
|
||||
: "https://testnet.xmrchain.net/tx/{0}",
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"XMR_X = XMR_BTC * BTC_X",
|
||||
"XMR_BTC = kraken(XMR_BTC)"
|
||||
},
|
||||
CryptoImagePath = "/imlegacy/monero.svg",
|
||||
UriScheme = "monero"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public class MoneroLikeSpecificBtcPayNetwork : BTCPayNetworkBase
|
||||
{
|
||||
public int MaxTrackedConfirmation = 10;
|
||||
public string UriScheme { get; set; }
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
// Change this if you want another zcash coin
|
||||
public void InitZcash()
|
||||
{
|
||||
Add(new ZcashLikeSpecificBtcPayNetwork()
|
||||
{
|
||||
CryptoCode = "ZEC",
|
||||
DisplayName = "Zcash",
|
||||
Divisibility = 8,
|
||||
BlockExplorerLink =
|
||||
NetworkType == ChainName.Mainnet
|
||||
? "https://www.exploreZcash.com/transaction/{0}"
|
||||
: "https://testnet.xmrchain.net/tx/{0}",
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"ZEC_X = ZEC_BTC * BTC_X",
|
||||
"ZEC_BTC = kraken(ZEC_BTC)"
|
||||
},
|
||||
CryptoImagePath = "/imlegacy/zcash.png",
|
||||
UriScheme = "zcash"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public class ZcashLikeSpecificBtcPayNetwork : BTCPayNetworkBase
|
||||
{
|
||||
public int MaxTrackedConfirmation = 10;
|
||||
public string UriScheme { get; set; }
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Common;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
using NBXplorer.Models;
|
||||
@ -62,6 +64,31 @@ namespace BTCPayServer
|
||||
public KeyPath CoinType { get; set; }
|
||||
|
||||
public Dictionary<uint, DerivationType> ElectrumMapping = new Dictionary<uint, DerivationType>();
|
||||
public BTCPayNetwork SetDefaultElectrumMapping(ChainName chainName)
|
||||
{
|
||||
//https://github.com/spesmilo/electrum/blob/11733d6bc271646a00b69ff07657119598874da4/electrum/constants.py
|
||||
ElectrumMapping = chainName == ChainName.Mainnet
|
||||
? new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x0488b21eU, DerivationType.Legacy }, // xpub
|
||||
{0x049d7cb2U, DerivationType.SegwitP2SH }, // ypub
|
||||
{0x04b24746U, DerivationType.Segwit }, //zpub
|
||||
}
|
||||
: new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x043587cfU, DerivationType.Legacy}, // tpub
|
||||
{0x044a5262U, DerivationType.SegwitP2SH}, // upub
|
||||
{0x045f1cf6U, DerivationType.Segwit} // vpub
|
||||
};
|
||||
if (!NBitcoinNetwork.Consensus.SupportSegwit)
|
||||
{
|
||||
ElectrumMapping =
|
||||
ElectrumMapping
|
||||
.Where(kv => kv.Value == DerivationType.Legacy)
|
||||
.ToDictionary(k => k.Key, k => k.Value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual bool WalletSupported { get; set; } = true;
|
||||
public virtual bool ReadonlyWallet { get; set; } = false;
|
||||
@ -107,25 +134,8 @@ namespace BTCPayServer
|
||||
|
||||
public abstract class BTCPayNetworkBase
|
||||
{
|
||||
private string _blockExplorerLink;
|
||||
public bool ShowSyncSummary { get; set; } = true;
|
||||
public string CryptoCode { get; set; }
|
||||
|
||||
public string BlockExplorerLink
|
||||
{
|
||||
get => _blockExplorerLink;
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(BlockExplorerLinkDefault))
|
||||
{
|
||||
BlockExplorerLinkDefault = value;
|
||||
}
|
||||
|
||||
_blockExplorerLink = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string BlockExplorerLinkDefault { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public int Divisibility { get; set; } = 8;
|
||||
public bool IsBTC
|
||||
@ -153,5 +163,8 @@ namespace BTCPayServer
|
||||
{
|
||||
return NBitcoin.JsonConverters.Serializer.ToString(obj, null);
|
||||
}
|
||||
|
||||
[Obsolete("Use TransactionLinkProviders service instead")]
|
||||
public string BlockExplorerLink { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitBitcoin()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("BTC");
|
||||
Add(new BTCPayNetwork()
|
||||
{
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Bitcoin",
|
||||
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://mempool.space/tx/{0}" :
|
||||
NetworkType == Bitcoin.Instance.Signet.ChainName ? "https://mempool.space/signet/tx/{0}"
|
||||
: "https://mempool.space/testnet/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
CryptoImagePath = "imlegacy/bitcoin.svg",
|
||||
LightningImagePath = "imlegacy/bitcoin-lightning.svg",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("0'") : new KeyPath("1'"),
|
||||
SupportRBF = true,
|
||||
SupportPayJoin = true,
|
||||
VaultSupported = true,
|
||||
//https://github.com/spesmilo/electrum/blob/11733d6bc271646a00b69ff07657119598874da4/electrum/constants.py
|
||||
ElectrumMapping = NetworkType == ChainName.Mainnet
|
||||
? new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x0488b21eU, DerivationType.Legacy }, // xpub
|
||||
{0x049d7cb2U, DerivationType.SegwitP2SH }, // ypub
|
||||
{0x04b24746U, DerivationType.Segwit }, //zpub
|
||||
}
|
||||
: new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x043587cfU, DerivationType.Legacy}, // tpub
|
||||
{0x044a5262U, DerivationType.SegwitP2SH}, // upub
|
||||
{0x045f1cf6U, DerivationType.Segwit} // vpub
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Logging;
|
||||
using Microsoft.AspNetCore.DataProtection.KeyManagement;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
using StandardConfiguration;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
@ -19,92 +26,39 @@ namespace BTCPayServer
|
||||
}
|
||||
}
|
||||
|
||||
BTCPayNetworkProvider(BTCPayNetworkProvider unfiltered, string[] cryptoCodes)
|
||||
{
|
||||
NetworkType = unfiltered.NetworkType;
|
||||
_NBXplorerNetworkProvider = new NBXplorerNetworkProvider(unfiltered.NetworkType);
|
||||
_Networks = new Dictionary<string, BTCPayNetworkBase>();
|
||||
cryptoCodes = cryptoCodes.Select(c => c.ToUpperInvariant()).ToArray();
|
||||
foreach (var network in unfiltered._Networks)
|
||||
{
|
||||
if (cryptoCodes.Contains(network.Key))
|
||||
{
|
||||
_Networks.Add(network.Key, network.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ChainName NetworkType { get; private set; }
|
||||
public BTCPayNetworkProvider(ChainName networkType)
|
||||
public BTCPayNetworkProvider(
|
||||
IEnumerable<BTCPayNetworkBase> networks,
|
||||
SelectedChains selectedChains,
|
||||
NBXplorerNetworkProvider nbxplorerNetworkProvider,
|
||||
Logs logs,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
_NBXplorerNetworkProvider = new NBXplorerNetworkProvider(networkType);
|
||||
NetworkType = networkType;
|
||||
InitBitcoin();
|
||||
#if ALTCOINS
|
||||
InitLiquid();
|
||||
InitLiquidAssets();
|
||||
InitLitecoin();
|
||||
InitBitcore();
|
||||
InitDogecoin();
|
||||
InitBGold();
|
||||
InitMonacoin();
|
||||
InitDash();
|
||||
InitFeathercoin();
|
||||
InitAlthash();
|
||||
InitGroestlcoin();
|
||||
InitViacoin();
|
||||
InitMonero();
|
||||
InitZcash();
|
||||
// InitArgoneum();//their rate source is down 9/15/20.
|
||||
// InitMonetaryUnit(); Not supported from Bittrex from 11/23/2022, dead shitcoin
|
||||
#if !ALTCOINS
|
||||
var onlyBTC = networks.Count() == 1 && networks.First().IsBTC;
|
||||
if (!onlyBTC)
|
||||
throw new ConfigException($"This build of BTCPay Server does not support altcoins");
|
||||
#endif
|
||||
|
||||
// Assume that electrum mappings are same as BTC if not specified
|
||||
foreach (var network in _Networks.Values.OfType<BTCPayNetwork>())
|
||||
_NBXplorerNetworkProvider = nbxplorerNetworkProvider;
|
||||
NetworkType = nbxplorerNetworkProvider.NetworkType;
|
||||
foreach (var network in networks)
|
||||
{
|
||||
if (network.ElectrumMapping.Count == 0)
|
||||
{
|
||||
network.ElectrumMapping = GetNetwork<BTCPayNetwork>("BTC").ElectrumMapping;
|
||||
if (!network.NBitcoinNetwork.Consensus.SupportSegwit)
|
||||
{
|
||||
network.ElectrumMapping =
|
||||
network.ElectrumMapping
|
||||
.Where(kv => kv.Value == DerivationType.Legacy)
|
||||
.ToDictionary(k => k.Key, k => k.Value);
|
||||
}
|
||||
}
|
||||
_Networks.Add(network.CryptoCode.ToUpperInvariant(), network);
|
||||
}
|
||||
|
||||
// Disabled because of https://twitter.com/Cryptopia_NZ/status/1085084168852291586
|
||||
//InitBPlus();
|
||||
//InitUfo();
|
||||
#endif
|
||||
}
|
||||
foreach (var chain in selectedChains.ExplicitlySelected)
|
||||
{
|
||||
if (GetNetwork<BTCPayNetworkBase>(chain) == null)
|
||||
throw new ConfigException($"Invalid chains \"{chain}\"");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Keep only the specified crypto
|
||||
/// </summary>
|
||||
/// <param name="cryptoCodes">Crypto to support</param>
|
||||
/// <returns></returns>
|
||||
public BTCPayNetworkProvider Filter(string[] cryptoCodes)
|
||||
{
|
||||
return new BTCPayNetworkProvider(this, cryptoCodes);
|
||||
logs.Configuration.LogInformation(
|
||||
"Supported chains: " + String.Join(',', _Networks.Select(n => n.Key).ToArray()));
|
||||
}
|
||||
|
||||
public BTCPayNetwork BTC => GetNetwork<BTCPayNetwork>("BTC");
|
||||
public BTCPayNetworkBase DefaultNetwork => BTC ?? GetAll().First();
|
||||
|
||||
public void Add(BTCPayNetwork network)
|
||||
{
|
||||
if (network.NBitcoinNetwork == null)
|
||||
return;
|
||||
Add(network as BTCPayNetworkBase);
|
||||
}
|
||||
public void Add(BTCPayNetworkBase network)
|
||||
{
|
||||
_Networks.Add(network.CryptoCode.ToUpperInvariant(), network);
|
||||
}
|
||||
|
||||
public IEnumerable<BTCPayNetworkBase> GetAll()
|
||||
{
|
||||
return _Networks.Values.ToArray();
|
||||
|
@ -4,10 +4,13 @@
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="NBXplorer.Client" Version="4.2.5" />
|
||||
<PackageReference Include="NBXplorer.Client" Version="4.2.6" />
|
||||
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="2.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Altcoins)' != 'true'">
|
||||
<Compile Remove="Altcoins\**\*.cs"></Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Altcoins\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
0
BTCPayServer/Configuration/ConfigException.cs → BTCPayServer.Common/Configuration/ConfigException.cs
0
BTCPayServer/Configuration/ConfigException.cs → BTCPayServer.Common/Configuration/ConfigException.cs
49
BTCPayServer.Common/SelectedChains.cs
Normal file
49
BTCPayServer.Common/SelectedChains.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Logging;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json.Bson;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public class SelectedChains
|
||||
{
|
||||
HashSet<string> chains = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
bool all = false;
|
||||
public SelectedChains(IConfiguration configuration, Logs logs)
|
||||
{
|
||||
foreach (var chain in (configuration["chains"] ?? "btc")
|
||||
.Split(',', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(t => t.ToUpperInvariant()))
|
||||
{
|
||||
if (new[] { "ETH", "USDT20", "FAU" }.Contains(chain, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
logs.Configuration.LogWarning($"'{chain}' is not anymore supported, please remove it from 'chains'");
|
||||
continue;
|
||||
}
|
||||
if (chain == "*")
|
||||
{
|
||||
all = true;
|
||||
continue;
|
||||
}
|
||||
chains.Add(chain);
|
||||
}
|
||||
if (chains.Count == 0)
|
||||
chains.Add("BTC");
|
||||
if (all)
|
||||
chains.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(string cryptoCode)
|
||||
{
|
||||
return all || chains.Contains(cryptoCode);
|
||||
}
|
||||
public void Add(string cryptoCode)
|
||||
{
|
||||
chains.Add(cryptoCode);
|
||||
}
|
||||
public IEnumerable<string> ExplicitlySelected => chains;
|
||||
}
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -1,13 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="../Build/Version.csproj" Condition="Exists('../Build/Version.csproj')" />
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.9">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BTCPayServer.Abstractions\BTCPayServer.Abstractions.csproj" />
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
|
@ -14,6 +14,7 @@ namespace BTCPayServer.Data
|
||||
public DateTimeOffset Created { get; set; }
|
||||
public bool TagAllInvoices { get; set; }
|
||||
public string Settings { get; set; }
|
||||
public bool Archived { get; set; }
|
||||
|
||||
internal static void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
|
@ -30,9 +30,6 @@ namespace BTCPayServer.Data
|
||||
public List<PendingInvoiceData> PendingInvoices { get; set; }
|
||||
public List<InvoiceSearchData> InvoiceSearchData { get; set; }
|
||||
public List<RefundData> Refunds { get; set; }
|
||||
public string CurrentRefundId { get; set; }
|
||||
[ForeignKey("Id,CurrentRefundId")]
|
||||
public RefundData CurrentRefund { get; set; }
|
||||
|
||||
|
||||
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
|
||||
@ -42,8 +39,6 @@ namespace BTCPayServer.Data
|
||||
.WithMany(a => a.Invoices).OnDelete(DeleteBehavior.Cascade);
|
||||
builder.Entity<InvoiceData>().HasIndex(o => o.StoreDataId);
|
||||
builder.Entity<InvoiceData>().HasIndex(o => o.OrderId);
|
||||
builder.Entity<InvoiceData>()
|
||||
.HasOne(o => o.CurrentRefund);
|
||||
builder.Entity<InvoiceData>().HasIndex(o => o.Created);
|
||||
|
||||
if (databaseFacade.IsNpgsql())
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
@ -13,7 +14,6 @@ namespace BTCPayServer.Data
|
||||
public PullPaymentData PullPaymentData { get; set; }
|
||||
public InvoiceData InvoiceData { get; set; }
|
||||
|
||||
|
||||
internal static void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
builder.Entity<RefundData>()
|
||||
|
@ -48,6 +48,7 @@ namespace BTCPayServer.Data
|
||||
public IEnumerable<StoreSettingData> Settings { get; set; }
|
||||
public IEnumerable<FormData> Forms { get; set; }
|
||||
public IEnumerable<StoreRole> StoreRoles { get; set; }
|
||||
public bool Archived { get; set; }
|
||||
|
||||
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
|
||||
{
|
||||
|
@ -1,14 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public class WalletObjectData
|
||||
public class WalletObjectData : IEqualityComparer<WalletObjectData>
|
||||
{
|
||||
public class Types
|
||||
{
|
||||
@ -88,9 +86,30 @@ namespace BTCPayServer.Data
|
||||
if (databaseFacade.IsNpgsql())
|
||||
{
|
||||
builder.Entity<WalletObjectData>()
|
||||
.Property(o => o.Data)
|
||||
.HasColumnType("JSONB");
|
||||
.Property(o => o.Data)
|
||||
.HasColumnType("JSONB");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(WalletObjectData x, WalletObjectData y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return string.Equals(x.WalletId, y.WalletId, StringComparison.InvariantCultureIgnoreCase) &&
|
||||
string.Equals(x.Type, y.Type, StringComparison.InvariantCultureIgnoreCase) &&
|
||||
string.Equals(x.Id, y.Id, StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public int GetHashCode(WalletObjectData obj)
|
||||
{
|
||||
HashCode hashCode = new HashCode();
|
||||
hashCode.Add(obj.WalletId, StringComparer.InvariantCultureIgnoreCase);
|
||||
hashCode.Add(obj.Type, StringComparer.InvariantCultureIgnoreCase);
|
||||
hashCode.Add(obj.Id, StringComparer.InvariantCultureIgnoreCase);
|
||||
return hashCode.ToHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20230906135844_AddArchivedFlagForStoresAndApps")]
|
||||
public partial class AddArchivedFlagForStoresAndApps : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "Archived",
|
||||
table: "Stores",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "Archived",
|
||||
table: "Apps",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Archived",
|
||||
table: "Stores");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Archived",
|
||||
table: "Apps");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
using System.Security.Permissions;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20231020135844_AddBoltcardsTable")]
|
||||
public partial class AddBoltcardsTable : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "boltcards",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<string>(maxLength: 32, nullable: false),
|
||||
counter = table.Column<int>(type: "INT", nullable: false, defaultValue: 0),
|
||||
ppid = table.Column<string>(maxLength: 30, nullable: true),
|
||||
version = table.Column<int>(nullable: false, defaultValue: 0)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_id", x => x.id);
|
||||
table.ForeignKey("FK_boltcards_PullPayments", x => x.ppid, "PullPayments", "Id", onDelete: ReferentialAction.SetNull);
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable("boltcards");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20231121031609_removecurrentrefund")]
|
||||
public partial class removecurrentrefund : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
if (migrationBuilder.IsNpgsql())
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Invoices_Refunds_Id_CurrentRefundId",
|
||||
table: "Invoices");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Invoices_Id_CurrentRefundId",
|
||||
table: "Invoices");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CurrentRefundId",
|
||||
table: "Invoices");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -79,6 +79,9 @@ namespace BTCPayServer.Migrations
|
||||
b.Property<string>("AppType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Archived")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset>("Created")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
@ -284,9 +287,6 @@ namespace BTCPayServer.Migrations
|
||||
b.Property<DateTimeOffset>("Created")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CurrentRefundId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CustomerEmail")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
@ -313,8 +313,6 @@ namespace BTCPayServer.Migrations
|
||||
|
||||
b.HasIndex("StoreDataId");
|
||||
|
||||
b.HasIndex("Id", "CurrentRefundId");
|
||||
|
||||
b.ToTable("Invoices");
|
||||
});
|
||||
|
||||
@ -751,6 +749,9 @@ namespace BTCPayServer.Migrations
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Archived")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DefaultCrypto")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
@ -1245,12 +1246,6 @@ namespace BTCPayServer.Migrations
|
||||
.HasForeignKey("StoreDataId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("BTCPayServer.Data.RefundData", "CurrentRefund")
|
||||
.WithMany()
|
||||
.HasForeignKey("Id", "CurrentRefundId");
|
||||
|
||||
b.Navigation("CurrentRefund");
|
||||
|
||||
b.Navigation("StoreData");
|
||||
});
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Version>1.0.0.0</Version>
|
||||
<PackAsTool>true</PackAsTool>
|
||||
<ToolCommandName>btcpay-plugin</ToolCommandName>
|
||||
|
@ -1,37 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace BTCPayServer.Rating
|
||||
{
|
||||
public enum RateSource
|
||||
{
|
||||
Coingecko,
|
||||
Direct
|
||||
}
|
||||
public class AvailableRateProvider
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Url { get; }
|
||||
public string Id { get; }
|
||||
public RateSource Source { get; }
|
||||
|
||||
public AvailableRateProvider(string id, string name, string url) : this(id, name, url, RateSource.Direct)
|
||||
{
|
||||
|
||||
}
|
||||
public AvailableRateProvider(string id, string name, string url, RateSource source)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
Url = url;
|
||||
Source = source;
|
||||
}
|
||||
|
||||
public string DisplayName =>
|
||||
Source switch
|
||||
{
|
||||
RateSource.Direct => Name,
|
||||
RateSource.Coingecko => $"{Name} (via CoinGecko)",
|
||||
_ => throw new NotSupportedException(Source.ToString())
|
||||
};
|
||||
}
|
||||
}
|
@ -4,11 +4,11 @@
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
|
||||
<PackageReference Include="NBitcoin" Version="7.0.24" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="DigitalRuby.ExchangeSharp" Version="1.0.2" />
|
||||
<PackageReference Include="NBitcoin" Version="7.0.31" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="DigitalRuby.ExchangeSharp" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
public class ArgoneumRateProvider : IRateProvider
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
public ArgoneumRateProvider(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient ?? new HttpClient();
|
||||
}
|
||||
|
||||
public RateSourceInfo RateSourceInfo => new("argoneum", "Argoneum", "https://rates.argoneum.net/rates");
|
||||
|
||||
public async Task<PairRate[]> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
// Example result: AGM to BTC rate: {"agm":5000000.000000}
|
||||
var response = await _httpClient.GetAsync("https://rates.argoneum.net/rates/btc", cancellationToken);
|
||||
var jobj = await response.Content.ReadAsAsync<JObject>(cancellationToken);
|
||||
var value = jobj["agm"].Value<decimal>();
|
||||
return new[] { new PairRate(new CurrencyPair("BTC", "AGM"), new BidAsk(value)) };
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -1,40 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Rating;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Services.Rates;
|
||||
|
||||
|
||||
public class ExchangeRateHostRateProvider : IRateProvider
|
||||
{
|
||||
public RateSourceInfo RateSourceInfo => new("exchangeratehost", "Yadio", "https://api.exchangerate.host/latest?base=BTC");
|
||||
private readonly HttpClient _httpClient;
|
||||
public ExchangeRateHostRateProvider(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient ?? new HttpClient();
|
||||
}
|
||||
|
||||
public async Task<PairRate[]> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _httpClient.GetAsync(RateSourceInfo.Url, cancellationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var jobj = await response.Content.ReadAsAsync<JObject>(cancellationToken);
|
||||
if(jobj["success"].Value<bool>() is not true || !jobj["base"].Value<string>().Equals("BTC", StringComparison.InvariantCulture))
|
||||
throw new Exception("exchangerate.host returned a non success response or the base currency was not the requested one (BTC)");
|
||||
var results = (JObject) jobj["rates"] ;
|
||||
//key value is currency code to rate value
|
||||
var list = new List<PairRate>();
|
||||
foreach (var item in results)
|
||||
{
|
||||
string name = item.Key;
|
||||
var value = item.Value.Value<decimal>();
|
||||
list.Add(new PairRate(new CurrencyPair("BTC", name), new BidAsk(value)));
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ namespace BTCPayServer.Services.Rates
|
||||
{
|
||||
public class RipioExchangeProvider : IRateProvider
|
||||
{
|
||||
public RateSourceInfo RateSourceInfo => new("ripio", "Ripio", "https://api.exchange.ripio.com/api/v1/rate/all/");
|
||||
public RateSourceInfo RateSourceInfo => new("ripio", "Ripio", "https://api.ripiotrade.co/v4/public/tickers");
|
||||
private readonly HttpClient _httpClient;
|
||||
public RipioExchangeProvider(HttpClient httpClient)
|
||||
{
|
||||
@ -21,9 +21,9 @@ namespace BTCPayServer.Services.Rates
|
||||
}
|
||||
public async Task<PairRate[]> GetRatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _httpClient.GetAsync("https://api.exchange.ripio.com/api/v1/rate/all/", cancellationToken);
|
||||
var response = await _httpClient.GetAsync("https://api.ripiotrade.co/v4/public/tickers", cancellationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var jarray = (JArray)(await response.Content.ReadAsAsync<JArray>(cancellationToken));
|
||||
var jarray = (JArray)(await response.Content.ReadAsAsync<JObject>(cancellationToken))["data"];
|
||||
return jarray
|
||||
.Children<JObject>()
|
||||
.Select(jobj => ParsePair(jobj))
|
||||
|
@ -1,21 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Rating
|
||||
#nullable enable
|
||||
namespace BTCPayServer.Rating;
|
||||
public enum RateSource
|
||||
{
|
||||
public class RateSourceInfo
|
||||
{
|
||||
public RateSourceInfo(string id, string displayName, string url)
|
||||
{
|
||||
Id = id;
|
||||
DisplayName = displayName;
|
||||
Url = url;
|
||||
}
|
||||
public string Id { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string Url { get; set; }
|
||||
}
|
||||
Coingecko,
|
||||
Direct
|
||||
}
|
||||
public record RateSourceInfo(string Id, string DisplayName, string Url, RateSource Source = RateSource.Direct);
|
||||
|
@ -85,14 +85,13 @@ namespace BTCPayServer.Services.Rates
|
||||
bgFetcher.RefreshRate = TimeSpan.FromMinutes(1.0);
|
||||
bgFetcher.ValidatyTime = TimeSpan.FromMinutes(5.0);
|
||||
Providers.Add(supportedExchange.Id, bgFetcher);
|
||||
var rsi = coingecko.RateSourceInfo;
|
||||
AvailableRateProviders.Add(new(rsi.Id, rsi.DisplayName, rsi.Url, RateSource.Coingecko));
|
||||
AvailableRateProviders.Add(coingecko.RateSourceInfo);
|
||||
}
|
||||
}
|
||||
AvailableRateProviders.Sort((a, b) => StringComparer.Ordinal.Compare(a.DisplayName, b.DisplayName));
|
||||
}
|
||||
|
||||
public List<AvailableRateProvider> AvailableRateProviders { get; } = new List<AvailableRateProvider>();
|
||||
public List<RateSourceInfo> AvailableRateProviders { get; } = new List<RateSourceInfo>();
|
||||
|
||||
public async Task<QueryRateResult> QueryRates(string exchangeName, CancellationToken cancellationToken)
|
||||
{
|
||||
|
@ -663,7 +663,7 @@ donation:
|
||||
Assert.Equal(3, vmview.Items.Length);
|
||||
Assert.Equal("good apple", vmview.Items[0].Title);
|
||||
Assert.Equal("orange", vmview.Items[1].Title);
|
||||
Assert.Equal(10.0m, vmview.Items[1].Price.Value);
|
||||
Assert.Equal(10.0m, vmview.Items[1].Price);
|
||||
Assert.Equal("{0} Purchase", vmview.ButtonText);
|
||||
Assert.Equal("Nicolas Sexy Hair", vmview.CustomButtonText);
|
||||
Assert.Equal("Wanna tip?", vmview.CustomTipText);
|
||||
@ -680,7 +680,7 @@ donation:
|
||||
Assert.IsType<RedirectToActionResult>(publicApps
|
||||
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, choiceKey: "apple").Result);
|
||||
|
||||
invoices = user.BitPay.GetInvoices();
|
||||
invoices = await user.BitPay.GetInvoicesAsync();
|
||||
var appleInvoice = invoices.SingleOrDefault(invoice => invoice.ItemCode.Equals("apple"));
|
||||
Assert.NotNull(appleInvoice);
|
||||
Assert.Equal("good apple", appleInvoice.ItemDesc);
|
||||
@ -689,7 +689,7 @@ donation:
|
||||
var action = Assert.IsType<RedirectToActionResult>(publicApps
|
||||
.ViewPointOfSale(app.Id, PosViewType.Cart, 6.6m, choiceKey: "donation").Result);
|
||||
Assert.Equal(nameof(UIInvoiceController.Checkout), action.ActionName);
|
||||
invoices = user.BitPay.GetInvoices();
|
||||
invoices = await user.BitPay.GetInvoicesAsync();
|
||||
var donationInvoice = invoices.Single(i => i.Price == 6.6m);
|
||||
Assert.NotNull(donationInvoice);
|
||||
Assert.Equal("CAD", donationInvoice.Currency);
|
||||
|
@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Controllers;
|
||||
using BTCPayServer.Models.WalletViewModels;
|
||||
using BTCPayServer.Plugins.Altcoins;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using BTCPayServer.Tests.Logging;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -52,11 +53,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 +77,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 +88,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 +101,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(() =>
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
<PropertyGroup>
|
||||
<NoWarn>$(NoWarn),xUnit1031</NoWarn>
|
||||
<IsPackable>false</IsPackable>
|
||||
<UserSecretsId>AB0AC1DD-9D26-485B-9416-56A33F268117</UserSecretsId>
|
||||
<!--https://devblogs.microsoft.com/aspnet/testing-asp-net-core-mvc-web-apps-in-memory/-->
|
||||
@ -19,13 +20,13 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
|
||||
<PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.14" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.15" />
|
||||
<PackageReference Include="Selenium.Support" Version="4.1.1" />
|
||||
<PackageReference Include="Selenium.WebDriver" Version="4.1.1" />
|
||||
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="114.0.5735.9000" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="119.0.6045.10500" />
|
||||
<PackageReference Include="xunit" Version="2.6.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
@ -12,7 +12,8 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
this._Parent = serverTester;
|
||||
var url = serverTester.GetEnvironment(environmentName, defaultValue);
|
||||
Client = (ChargeClient)LightningClientFactory.CreateClient(url, network);
|
||||
|
||||
Client = (ChargeClient)new LightningClientFactory(network).Create(url);
|
||||
P2PHost = _Parent.GetEnvironment(environmentName + "_HOST", defaultHost);
|
||||
}
|
||||
public ChargeClient Client { get; set; }
|
||||
|
@ -54,13 +54,33 @@ namespace BTCPayServer.Tests
|
||||
Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps2.ListApps(user2.StoreId).Result).Model);
|
||||
Assert.Single(appList.Apps);
|
||||
Assert.Empty(appList2.Apps);
|
||||
Assert.Equal("test", appList.Apps[0].AppName);
|
||||
Assert.Equal(apps.CreatedAppId, appList.Apps[0].Id);
|
||||
Assert.True(appList.Apps[0].Role.ToPermissionSet(appList.Apps[0].StoreId).Contains(Policies.CanModifyStoreSettings, appList.Apps[0].StoreId));
|
||||
Assert.Equal(user.StoreId, appList.Apps[0].StoreId);
|
||||
Assert.IsType<NotFoundResult>(apps2.DeleteApp(appList.Apps[0].Id));
|
||||
Assert.IsType<ViewResult>(apps.DeleteApp(appList.Apps[0].Id));
|
||||
var redirectToAction = Assert.IsType<RedirectToActionResult>(apps.DeleteAppPost(appList.Apps[0].Id).Result);
|
||||
Assert.Equal("test", app.AppName);
|
||||
Assert.Equal(apps.CreatedAppId, app.Id);
|
||||
Assert.True(app.Role.ToPermissionSet(app.StoreId).Contains(Policies.CanModifyStoreSettings, app.StoreId));
|
||||
Assert.Equal(user.StoreId, app.StoreId);
|
||||
// Archive
|
||||
redirect = Assert.IsType<RedirectResult>(apps.ToggleArchive(app.Id).Result);
|
||||
Assert.EndsWith("/settings/crowdfund", redirect.Url);
|
||||
appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
|
||||
Assert.Empty(appList.Apps);
|
||||
appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId, archived: true).Result).Model);
|
||||
app = appList.Apps[0];
|
||||
Assert.True(app.Archived);
|
||||
Assert.IsType<NotFoundResult>(await crowdfund.ViewCrowdfund(app.Id));
|
||||
// Unarchive
|
||||
redirect = Assert.IsType<RedirectResult>(apps.ToggleArchive(app.Id).Result);
|
||||
Assert.EndsWith("/settings/crowdfund", redirect.Url);
|
||||
appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
|
||||
app = appList.Apps[0];
|
||||
Assert.False(app.Archived);
|
||||
var crowdfundViewModel = await crowdfund.UpdateCrowdfund(app.Id).AssertViewModelAsync<UpdateCrowdfundViewModel>();
|
||||
crowdfundViewModel.Enabled = true;
|
||||
Assert.IsType<RedirectToActionResult>(crowdfund.UpdateCrowdfund(app.Id, crowdfundViewModel, "save").Result);
|
||||
Assert.IsType<ViewResult>(await crowdfund.ViewCrowdfund(app.Id));
|
||||
// Delete
|
||||
Assert.IsType<NotFoundResult>(apps2.DeleteApp(app.Id));
|
||||
Assert.IsType<ViewResult>(apps.DeleteApp(app.Id));
|
||||
var redirectToAction = Assert.IsType<RedirectToActionResult>(apps.DeleteAppPost(app.Id).Result);
|
||||
Assert.Equal(nameof(UIStoresController.Dashboard), redirectToAction.ActionName);
|
||||
appList = await apps.ListApps(user.StoreId).AssertViewModelAsync<ListAppsViewModel>();
|
||||
Assert.Empty(appList.Apps);
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0.401-bullseye-slim AS builder
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0.100-bookworm-slim AS builder
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends chromium-driver \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -97,7 +98,7 @@ retry:
|
||||
}
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
Assert.False(true, "Elements was found");
|
||||
Assert.Fail("Elements was found");
|
||||
}
|
||||
|
||||
public static void UntilJsIsReady(this WebDriverWait wait)
|
||||
@ -198,7 +199,9 @@ retry:
|
||||
|
||||
public static bool ElementDoesNotExist(this IWebDriver driver, By selector)
|
||||
{
|
||||
Assert.Throws<NoSuchElementException>(() =>
|
||||
Assert.Throws<NoSuchElementException>(
|
||||
[DebuggerStepThrough]
|
||||
() =>
|
||||
{
|
||||
driver.FindElement(selector);
|
||||
});
|
||||
|
@ -10,6 +10,7 @@ using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Configuration;
|
||||
@ -18,11 +19,15 @@ using BTCPayServer.Data;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Hosting;
|
||||
using BTCPayServer.JsonConverters;
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Bitcoin;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.Plugins;
|
||||
using BTCPayServer.Plugins.Bitcoin;
|
||||
using BTCPayServer.Rating;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Apps;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Labels;
|
||||
using BTCPayServer.Services.Rates;
|
||||
@ -130,7 +135,7 @@ namespace BTCPayServer.Tests
|
||||
var tags = new HashSet<String>(g.Select(o => o.Tag));
|
||||
if (tags.Count != 1)
|
||||
{
|
||||
Assert.False(true, $"All docker images '{g.Key}' in docker-compose.yml and docker-compose.altcoins.yml should have the same tags. (Found {string.Join(',', tags)})");
|
||||
Assert.Fail($"All docker images '{g.Key}' in docker-compose.yml and docker-compose.altcoins.yml should have the same tags. (Found {string.Join(',', tags)})");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -346,11 +351,70 @@ namespace BTCPayServer.Tests
|
||||
Assert.True(Torrc.TryParse(input, out torrc));
|
||||
Assert.Equal(expected, torrc.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanParseCartItems()
|
||||
{
|
||||
Assert.True(AppService.TryParsePosCartItems(new JObject()
|
||||
{
|
||||
{"cart", new JArray()
|
||||
{
|
||||
new JObject()
|
||||
{
|
||||
{ "id", "ddd"},
|
||||
{"price", 4},
|
||||
{"count", 1}
|
||||
}
|
||||
}}
|
||||
}, out var items));
|
||||
Assert.Equal("ddd", items[0].Id);
|
||||
Assert.Equal(1, items[0].Count);
|
||||
Assert.Equal(4, items[0].Price);
|
||||
|
||||
// Using legacy parsing
|
||||
Assert.True(AppService.TryParsePosCartItems(new JObject()
|
||||
{
|
||||
{"cart", new JArray()
|
||||
{
|
||||
new JObject()
|
||||
{
|
||||
{ "id", "ddd"},
|
||||
{"price", new JObject()
|
||||
{
|
||||
{ "value", 8.49m }
|
||||
}
|
||||
},
|
||||
{"count", 1}
|
||||
}
|
||||
}}
|
||||
}, out items));
|
||||
Assert.Equal("ddd", items[0].Id);
|
||||
Assert.Equal(1, items[0].Count);
|
||||
Assert.Equal(8.49m, items[0].Price);
|
||||
|
||||
Assert.False(AppService.TryParsePosCartItems(new JObject()
|
||||
{
|
||||
{"cart", new JArray()
|
||||
{
|
||||
new JObject()
|
||||
{
|
||||
{ "id", "ddd"},
|
||||
{"price", new JObject()
|
||||
{
|
||||
{ "value", "nocrahs" }
|
||||
}
|
||||
},
|
||||
{"count", 1}
|
||||
}
|
||||
}}
|
||||
}, out items));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanCalculateDust()
|
||||
{
|
||||
var entity = new InvoiceEntity() { Currency = "USD" };
|
||||
entity.Networks = new BTCPayNetworkProvider(ChainName.Regtest);
|
||||
entity.Networks = CreateNetworkProvider(ChainName.Regtest);
|
||||
#pragma warning disable CS0618
|
||||
entity.Payments = new System.Collections.Generic.List<PaymentEntity>();
|
||||
entity.SetPaymentMethod(new PaymentMethod()
|
||||
@ -396,7 +460,7 @@ namespace BTCPayServer.Tests
|
||||
[Fact]
|
||||
public void CanCalculateCryptoDue()
|
||||
{
|
||||
var networkProvider = new BTCPayNetworkProvider(ChainName.Regtest);
|
||||
var networkProvider = CreateNetworkProvider(ChainName.Regtest);
|
||||
var entity = new InvoiceEntity() { Currency = "USD" };
|
||||
entity.Networks = networkProvider;
|
||||
#pragma warning disable CS0618
|
||||
@ -584,7 +648,7 @@ namespace BTCPayServer.Tests
|
||||
[Fact]
|
||||
public void CanAcceptInvoiceWithTolerance()
|
||||
{
|
||||
var networkProvider = new BTCPayNetworkProvider(ChainName.Regtest);
|
||||
var networkProvider = CreateNetworkProvider(ChainName.Regtest);
|
||||
var paymentMethodHandlerDictionary = new PaymentMethodHandlerDictionary(new IPaymentMethodHandler[]
|
||||
{
|
||||
new BitcoinLikePaymentHandler(null, networkProvider, null, null, null, null),
|
||||
@ -659,7 +723,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanDetectImage()
|
||||
public void CanDetectFileType()
|
||||
{
|
||||
Assert.True(FileTypeDetector.IsPicture(new byte[] { 0x42, 0x4D }, "test.bmp"));
|
||||
Assert.False(FileTypeDetector.IsPicture(new byte[] { 0x42, 0x4D }, ".bmp"));
|
||||
@ -672,6 +736,15 @@ namespace BTCPayServer.Tests
|
||||
Assert.False(FileTypeDetector.IsPicture(new byte[] { 0x3C, 0x73, 0x76, 0x67 }, "test.jpg"));
|
||||
Assert.False(FileTypeDetector.IsPicture(new byte[] { 0xFF }, "e.jpg"));
|
||||
Assert.False(FileTypeDetector.IsPicture(new byte[] { }, "empty.jpg"));
|
||||
|
||||
Assert.False(FileTypeDetector.IsPicture(new byte[] { 0x49, 0x44, 0x33, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23 }, "music.mp3"));
|
||||
Assert.True(FileTypeDetector.IsAudio(new byte[] { 0x49, 0x44, 0x33, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23 }, "music.mp3"));
|
||||
Assert.True(FileTypeDetector.IsAudio(new byte[] { 0x52, 0x49, 0x46, 0x46, 0x24, 0x9A, 0x08, 0x00, 0x57, 0x41 }, "music.wav"));
|
||||
Assert.True(FileTypeDetector.IsAudio(new byte[] { 0xFF, 0xF1, 0x50, 0x80, 0x1C, 0x3F, 0xFC, 0xDA, 0x00, 0x4C }, "music.aac"));
|
||||
Assert.True(FileTypeDetector.IsAudio(new byte[] { 0x66, 0x4C, 0x61, 0x43, 0x00, 0x00, 0x00, 0x22, 0x04, 0x80 }, "music.flac"));
|
||||
Assert.True(FileTypeDetector.IsAudio(new byte[] { 0x4F, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 }, "music.ogg"));
|
||||
Assert.True(FileTypeDetector.IsAudio(new byte[] { 0x1A, 0x45, 0xDF, 0xA3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, "music.weba"));
|
||||
Assert.True(FileTypeDetector.IsAudio(new byte[] { 0xFF, 0xF3, 0xE4, 0x64, 0x00, 0x20, 0xAD, 0xBD, 0x04, 0x00 }, "music.mp3"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -695,7 +768,7 @@ namespace BTCPayServer.Tests
|
||||
[Fact]
|
||||
public async Task CanEnumerateTorServices()
|
||||
{
|
||||
var tor = new TorServices(new BTCPayNetworkProvider(ChainName.Regtest),
|
||||
var tor = new TorServices(CreateNetworkProvider(ChainName.Regtest),
|
||||
new OptionsWrapper<BTCPayServerOptions>(new BTCPayServerOptions()
|
||||
{
|
||||
TorrcFile = TestUtils.GetTestDataFullPath("Tor/torrc")
|
||||
@ -707,7 +780,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Single(tor.Services.Where(t => t.ServiceType == TorServiceType.RPC));
|
||||
Assert.True(tor.Services.Count(t => t.ServiceType == TorServiceType.Other) > 1);
|
||||
|
||||
tor = new TorServices(new BTCPayNetworkProvider(ChainName.Regtest),
|
||||
tor = new TorServices(CreateNetworkProvider(ChainName.Regtest),
|
||||
new OptionsWrapper<BTCPayServerOptions>(new BTCPayServerOptions()
|
||||
{
|
||||
TorrcFile = null,
|
||||
@ -744,7 +817,7 @@ namespace BTCPayServer.Tests
|
||||
[Fact]
|
||||
public void CanParseDerivationSchemes()
|
||||
{
|
||||
var networkProvider = new BTCPayNetworkProvider(ChainName.Regtest);
|
||||
var networkProvider = CreateNetworkProvider(ChainName.Regtest);
|
||||
var parser = new DerivationSchemeParser(networkProvider.BTC);
|
||||
|
||||
// xpub
|
||||
@ -770,7 +843,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(expected, inner.ToString());
|
||||
|
||||
// Output Descriptor
|
||||
networkProvider = new BTCPayNetworkProvider(ChainName.Mainnet);
|
||||
networkProvider = CreateNetworkProvider(ChainName.Mainnet);
|
||||
parser = new DerivationSchemeParser(networkProvider.BTC);
|
||||
var od = "wpkh([8bafd160/49h/0h/0h]xpub661MyMwAqRbcGVBsTGeNZN6QGVHmMHLdSA4FteGsRrEriu4pnVZMZWnruFFFXkMnyoBjyHndD3Qwcfz4MPzBUxjSevweNFQx7SAYZATtcDw/0/*)#9x4vkw48";
|
||||
(strategyBase, rootedKeyPath) = parser.ParseOutputDescriptor(od);
|
||||
@ -812,8 +885,8 @@ namespace BTCPayServer.Tests
|
||||
[Fact]
|
||||
public void ParseDerivationSchemeSettings()
|
||||
{
|
||||
var testnet = new BTCPayNetworkProvider(ChainName.Testnet).GetNetwork<BTCPayNetwork>("BTC");
|
||||
var mainnet = new BTCPayNetworkProvider(ChainName.Mainnet).GetNetwork<BTCPayNetwork>("BTC");
|
||||
var testnet = CreateNetworkProvider(ChainName.Testnet).GetNetwork<BTCPayNetwork>("BTC");
|
||||
var mainnet = CreateNetworkProvider(ChainName.Mainnet).GetNetwork<BTCPayNetwork>("BTC");
|
||||
var root = new Mnemonic(
|
||||
"usage fever hen zero slide mammal silent heavy donate budget pulse say brain thank sausage brand craft about save attract muffin advance illegal cabbage")
|
||||
.DeriveExtKey();
|
||||
@ -885,6 +958,40 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal("49'/0'/0'", specter.AccountKeySettings[0].AccountKeyPath.ToString());
|
||||
Assert.Equal("Specter", specter.Label);
|
||||
Assert.Null(error);
|
||||
|
||||
//BSMS BIP129, Nunchuk
|
||||
|
||||
var bsms = @"BSMS 1.0
|
||||
wsh(sortedmulti(1,[5c9e228d/48'/0'/0'/2']xpub6EgGHjcvovyN3nK921zAGPfuB41cJXkYRdt3tLGmiMyvbgHpss4X1eRZwShbEBb1znz2e2bCkCED87QZpin3sSYKbmCzQ9Sc7LaV98ngdeX/**,[2b0e251e/48'/0'/0'/2']xpub6DrimHB8KUSkPvmJ8Pk8RE769EdDm2VEoZ8MBz76w9QupP8Py4wexs4Pa3aRB1LUEhc9GyY6ypDWEFFRCgqeDQePcyWQfjtmintrehq3JCL/**))
|
||||
/0/*,/1/*
|
||||
bc1qfzu57kgu5jthl934f9xrdzzx8mmemx7gn07tf0grnvz504j6kzusu2v0ku
|
||||
";
|
||||
|
||||
Assert.True(DerivationSchemeSettings.TryParseFromWalletFile(bsms,
|
||||
mainnet, out var nunchuk, out error));
|
||||
|
||||
Assert.Equal(2, nunchuk.AccountKeySettings.Length);
|
||||
//check that the account key settings match those in bsms string
|
||||
Assert.Equal("5c9e228d", nunchuk.AccountKeySettings[0].RootFingerprint.ToString());
|
||||
Assert.Equal("48'/0'/0'/2'", nunchuk.AccountKeySettings[0].AccountKeyPath.ToString());
|
||||
Assert.Equal("2b0e251e", nunchuk.AccountKeySettings[1].RootFingerprint.ToString());
|
||||
Assert.Equal("48'/0'/0'/2'", nunchuk.AccountKeySettings[1].AccountKeyPath.ToString());
|
||||
|
||||
var multsig = Assert.IsType < MultisigDerivationStrategy >
|
||||
(Assert.IsType<P2WSHDerivationStrategy>(nunchuk.AccountDerivation).Inner);
|
||||
|
||||
Assert.True(multsig.LexicographicOrder);
|
||||
Assert.Equal(1, multsig.RequiredSignatures);
|
||||
|
||||
var deposit = new NBXplorer.KeyPathTemplates(null).GetKeyPathTemplate(DerivationFeature.Deposit);
|
||||
var line =nunchuk.AccountDerivation.GetLineFor(deposit).Derive(0);
|
||||
|
||||
Assert.Equal(BitcoinAddress.Create("bc1qfzu57kgu5jthl934f9xrdzzx8mmemx7gn07tf0grnvz504j6kzusu2v0ku", Network.Main).ScriptPubKey,
|
||||
line.ScriptPubKey);
|
||||
|
||||
Assert.Equal("BSMS", nunchuk.Source);
|
||||
Assert.Null(error);
|
||||
|
||||
|
||||
// Failure case
|
||||
Assert.False(DerivationSchemeSettings.TryParseFromWalletFile(
|
||||
@ -895,7 +1002,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckRatesProvider()
|
||||
public async Task CheckRatesProvider()
|
||||
{
|
||||
var spy = new SpyRateProvider();
|
||||
RateRules.TryParse("X_X = bittrex(X_X);", out var rateRules);
|
||||
@ -907,23 +1014,22 @@ namespace BTCPayServer.Tests
|
||||
var fetch = new BackgroundFetcherRateProvider(spy);
|
||||
fetch.DoNotAutoFetchIfExpired = true;
|
||||
factory.Providers.Add("bittrex", fetch);
|
||||
var fetchedRate = fetcher.FetchRate(CurrencyPair.Parse("BTC_USD"), rateRules, default).GetAwaiter()
|
||||
.GetResult();
|
||||
var fetchedRate = await fetcher.FetchRate(CurrencyPair.Parse("BTC_USD"), rateRules, default);
|
||||
spy.AssertHit();
|
||||
fetchedRate = fetcher.FetchRate(CurrencyPair.Parse("BTC_USD"), rateRules, default).GetAwaiter().GetResult();
|
||||
fetchedRate = await fetcher.FetchRate(CurrencyPair.Parse("BTC_USD"), rateRules, default);
|
||||
spy.AssertNotHit();
|
||||
fetch.UpdateIfNecessary(default).GetAwaiter().GetResult();
|
||||
await fetch.UpdateIfNecessary(default);
|
||||
spy.AssertNotHit();
|
||||
fetch.RefreshRate = TimeSpan.FromSeconds(1.0);
|
||||
Thread.Sleep(1020);
|
||||
fetchedRate = fetcher.FetchRate(CurrencyPair.Parse("BTC_USD"), rateRules, default).GetAwaiter().GetResult();
|
||||
fetchedRate = await fetcher.FetchRate(CurrencyPair.Parse("BTC_USD"), rateRules, default);
|
||||
spy.AssertNotHit();
|
||||
fetch.ValidatyTime = TimeSpan.FromSeconds(1.0);
|
||||
fetch.UpdateIfNecessary(default).GetAwaiter().GetResult();
|
||||
await fetch.UpdateIfNecessary(default);
|
||||
spy.AssertHit();
|
||||
fetch.GetRatesAsync(default).GetAwaiter().GetResult();
|
||||
await fetch.GetRatesAsync(default);
|
||||
Thread.Sleep(1000);
|
||||
Assert.Throws<InvalidOperationException>(() => fetch.GetRatesAsync(default).GetAwaiter().GetResult());
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => fetch.GetRatesAsync(default));
|
||||
}
|
||||
|
||||
public static RateProviderFactory CreateBTCPayRateFactory()
|
||||
@ -1177,7 +1283,7 @@ namespace BTCPayServer.Tests
|
||||
[Fact]
|
||||
public void HasCurrencyDataForNetworks()
|
||||
{
|
||||
var btcPayNetworkProvider = new BTCPayNetworkProvider(ChainName.Regtest);
|
||||
var btcPayNetworkProvider = CreateNetworkProvider(ChainName.Regtest);
|
||||
foreach (var network in btcPayNetworkProvider.GetAll())
|
||||
{
|
||||
var cd = CurrencyNameTable.Instance.GetCurrencyData(network.CryptoCode, false);
|
||||
@ -1756,8 +1862,7 @@ namespace BTCPayServer.Tests
|
||||
new KeyValuePair<string, string>("chains", "usdt")}
|
||||
})
|
||||
});
|
||||
|
||||
var networkProvider = config.ConfigureNetworkProvider(BTCPayLogs);
|
||||
var networkProvider = CreateNetworkProvider(config);
|
||||
Assert.NotNull(networkProvider.GetNetwork("LBTC"));
|
||||
Assert.NotNull(networkProvider.GetNetwork("USDT"));
|
||||
}
|
||||
@ -1765,9 +1870,9 @@ namespace BTCPayServer.Tests
|
||||
[Trait("Altcoins", "Altcoins")]
|
||||
public void CanParseDerivationScheme()
|
||||
{
|
||||
var testnetNetworkProvider = new BTCPayNetworkProvider(ChainName.Testnet);
|
||||
var regtestNetworkProvider = new BTCPayNetworkProvider(ChainName.Regtest);
|
||||
var mainnetNetworkProvider = new BTCPayNetworkProvider(ChainName.Mainnet);
|
||||
var testnetNetworkProvider = CreateNetworkProvider(ChainName.Testnet);
|
||||
var regtestNetworkProvider = CreateNetworkProvider(ChainName.Regtest);
|
||||
var mainnetNetworkProvider = CreateNetworkProvider(ChainName.Mainnet);
|
||||
var testnetParser = new DerivationSchemeParser(testnetNetworkProvider.GetNetwork<BTCPayNetwork>("BTC"));
|
||||
var mainnetParser = new DerivationSchemeParser(mainnetNetworkProvider.GetNetwork<BTCPayNetwork>("BTC"));
|
||||
NBXplorer.DerivationStrategy.DerivationStrategyBase result;
|
||||
@ -1933,7 +2038,7 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
#pragma warning disable CS0618
|
||||
var dummy = new Key().PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.RegTest).ToString();
|
||||
var networkProvider = new BTCPayNetworkProvider(ChainName.Regtest);
|
||||
var networkProvider = CreateNetworkProvider(ChainName.Regtest);
|
||||
var networkBTC = networkProvider.GetNetwork("BTC");
|
||||
var networkLTC = networkProvider.GetNetwork("LTC");
|
||||
InvoiceEntity invoiceEntity = new InvoiceEntity();
|
||||
@ -2050,7 +2155,7 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
["derivationStrategy"] = "tpubDDLQZ1WMdy5YJAJWmRNoTJ3uQkavEPXCXnmD4eAuo9BKbzFUBbJmVHys5M3ku4Qw1C165wGpVWH55gZpHjdsCyntwNzhmCAzGejSL6rzbyf"
|
||||
};
|
||||
var scheme = DerivationSchemeSettings.Parse("tpubDDLQZ1WMdy5YJAJWmRNoTJ3uQkavEPXCXnmD4eAuo9BKbzFUBbJmVHys5M3ku4Qw1C165wGpVWH55gZpHjdsCyntwNzhmCAzGejSL6rzbyf", new BTCPayNetworkProvider(ChainName.Regtest).BTC);
|
||||
var scheme = DerivationSchemeSettings.Parse("tpubDDLQZ1WMdy5YJAJWmRNoTJ3uQkavEPXCXnmD4eAuo9BKbzFUBbJmVHys5M3ku4Qw1C165wGpVWH55gZpHjdsCyntwNzhmCAzGejSL6rzbyf", CreateNetworkProvider(ChainName.Regtest).BTC);
|
||||
|
||||
scheme.Source = "ManualDerivationScheme";
|
||||
scheme.AccountOriginal = "tpubDDLQZ1WMdy5YJAJWmRNoTJ3uQkavEPXCXnmD4eAuo9BKbzFUBbJmVHys5M3ku4Qw1C165wGpVWH55gZpHjdsCyntwNzhmCAzGejSL6rzbyf";
|
||||
@ -2070,7 +2175,7 @@ namespace BTCPayServer.Tests
|
||||
.Select(o =>
|
||||
{
|
||||
var entity = JsonConvert.DeserializeObject<InvoiceEntity>(o.ToString());
|
||||
entity.Networks = new BTCPayNetworkProvider(ChainName.Regtest);
|
||||
entity.Networks = CreateNetworkProvider(ChainName.Regtest);
|
||||
return entity.DerivationStrategies.ToString();
|
||||
})
|
||||
.ToHashSet();
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Form;
|
||||
using BTCPayServer.Forms;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@ -10,16 +11,25 @@ using Xunit.Abstractions;
|
||||
|
||||
namespace BTCPayServer.Tests;
|
||||
|
||||
[Trait("Fast", "Fast")]
|
||||
[Collection(nameof(NonParallelizableCollectionDefinition))]
|
||||
[Trait("Integration", "Integration")]
|
||||
public class FormTests : UnitTestBase
|
||||
{
|
||||
public FormTests(ITestOutputHelper helper) : base(helper)
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanParseForm()
|
||||
|
||||
[Fact(Timeout = TestUtils.TestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanParseForm()
|
||||
{
|
||||
using var tester = CreateServerTester();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
var service = tester.PayTester.GetService<FormDataService>();
|
||||
|
||||
var form = new Form()
|
||||
{
|
||||
Fields = new List<Field>
|
||||
@ -40,8 +50,6 @@ public class FormTests : UnitTestBase
|
||||
}
|
||||
}
|
||||
};
|
||||
var providers = new FormComponentProviders(new List<IFormComponentProvider>());
|
||||
var service = new FormDataService(null, providers);
|
||||
Assert.False(service.IsFormSchemaValid(form.ToString(), out _, out _));
|
||||
form = new Form
|
||||
{
|
||||
@ -164,7 +172,7 @@ public class FormTests : UnitTestBase
|
||||
Assert.Equal("original", obj["invoice"]["test"].Value<string>());
|
||||
Assert.Equal("updated", obj["invoice_item3"].Value<string>());
|
||||
Clear(form);
|
||||
form.SetValues(obj);
|
||||
service.SetValues(form, obj);
|
||||
obj = service.GetValues(form);
|
||||
Assert.Equal("original", obj["invoice"]["test"].Value<string>());
|
||||
Assert.Equal("updated", obj["invoice_item3"].Value<string>());
|
||||
@ -182,12 +190,73 @@ public class FormTests : UnitTestBase
|
||||
}
|
||||
}
|
||||
};
|
||||
form.SetValues(obj);
|
||||
|
||||
service.SetValues(form, obj);
|
||||
obj = service.GetValues(form);
|
||||
Assert.Null(obj["test"].Value<string>());
|
||||
form.SetValues(new JObject { ["test"] = "hello" });
|
||||
|
||||
service.SetValues(form, new JObject { ["test"] = "hello" });
|
||||
obj = service.GetValues(form);
|
||||
Assert.Equal("hello", obj["test"].Value<string>());
|
||||
|
||||
var req = service.GenerateInvoiceParametersFromForm(form);
|
||||
Assert.Null(req.Amount);
|
||||
Assert.Null(req.Currency);
|
||||
|
||||
form.Fields.Add(new Field
|
||||
{
|
||||
Name = $"{FormDataService.InvoiceParameterPrefix}amount",
|
||||
Type = "number",
|
||||
Value = "1"
|
||||
});
|
||||
req = service.GenerateInvoiceParametersFromForm(form);
|
||||
Assert.Equal(1, req.Amount);
|
||||
|
||||
form.Fields.Add(new Field
|
||||
{
|
||||
Name = $"{FormDataService.InvoiceParameterPrefix}amount_adjustment",
|
||||
Type = "number",
|
||||
Value = "1"
|
||||
});
|
||||
req = service.GenerateInvoiceParametersFromForm(form);
|
||||
Assert.Equal(2, req.Amount);
|
||||
form.Fields.Add(new Field
|
||||
{
|
||||
Name = $"{FormDataService.InvoiceParameterPrefix}amount_adjustment2",
|
||||
Type = "number",
|
||||
Value = "2"
|
||||
});
|
||||
form.Fields.Add(new Field
|
||||
{
|
||||
Name = $"{FormDataService.InvoiceParameterPrefix}currency",
|
||||
Type = "text",
|
||||
Value = "eur"
|
||||
});
|
||||
req = service.GenerateInvoiceParametersFromForm(form);
|
||||
Assert.Equal("eur", req.Currency);
|
||||
Assert.Equal(4, req.Amount);
|
||||
|
||||
|
||||
form.Fields.Add(new Field
|
||||
{
|
||||
Name = $"{FormDataService.InvoiceParameterPrefix}amount_multiply_adjustment",
|
||||
Type = "number",
|
||||
Value = "2"
|
||||
});
|
||||
|
||||
req = service.GenerateInvoiceParametersFromForm(form);
|
||||
Assert.Equal(8, req.Amount);
|
||||
|
||||
|
||||
form.Fields.Add(new Field
|
||||
{
|
||||
Name = $"{FormDataService.InvoiceParameterPrefix}amount_multiply_adjustment1",
|
||||
Type = "number",
|
||||
Value = "2"
|
||||
});
|
||||
|
||||
req = service.GenerateInvoiceParametersFromForm(form);
|
||||
Assert.Equal(16, req.Amount);
|
||||
}
|
||||
|
||||
private void Clear(Form form)
|
||||
|
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
@ -16,8 +16,6 @@ using BTCPayServer.Models.InvoicingModels;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.PayoutProcessors;
|
||||
using BTCPayServer.PayoutProcessors.OnChain;
|
||||
using BTCPayServer.Plugins;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Custodian.Client.MockCustodian;
|
||||
using BTCPayServer.Services.Notifications;
|
||||
@ -25,7 +23,6 @@ using BTCPayServer.Services.Notifications.Blobs;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using NBitcoin;
|
||||
using NBitpayClient;
|
||||
using Newtonsoft.Json;
|
||||
@ -301,6 +298,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(user.StoreId, app.StoreId);
|
||||
Assert.Equal("PointOfSale", app.AppType);
|
||||
Assert.Equal("test app title", app.Title);
|
||||
Assert.False(app.Archived);
|
||||
|
||||
// Make sure we return a 404 if we try to get an app that doesn't exist
|
||||
await AssertHttpError(404, async () =>
|
||||
@ -324,17 +322,20 @@ namespace BTCPayServer.Tests
|
||||
new CreatePointOfSaleAppRequest()
|
||||
{
|
||||
AppName = "new app name",
|
||||
Title = "new app title"
|
||||
Title = "new app title",
|
||||
Archived = true
|
||||
}
|
||||
);
|
||||
// Test generic GET app endpoint first
|
||||
retrievedApp = await client.GetApp(app.Id);
|
||||
Assert.Equal("new app name", retrievedApp.Name);
|
||||
Assert.True(retrievedApp.Archived);
|
||||
|
||||
// Test the POS-specific endpoint also
|
||||
var retrievedPosApp = await client.GetPosApp(app.Id);
|
||||
Assert.Equal("new app name", retrievedPosApp.Name);
|
||||
Assert.Equal("new app title", retrievedPosApp.Title);
|
||||
Assert.True(retrievedPosApp.Archived);
|
||||
|
||||
// Make sure we return a 404 if we try to delete an app that doesn't exist
|
||||
await AssertHttpError(404, async () =>
|
||||
@ -466,6 +467,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal("test app from API", app.Name);
|
||||
Assert.Equal(user.StoreId, app.StoreId);
|
||||
Assert.Equal("Crowdfund", app.AppType);
|
||||
Assert.False(app.Archived);
|
||||
|
||||
// Make sure we return a 404 if we try to get an app that doesn't exist
|
||||
await AssertHttpError(404, async () =>
|
||||
@ -482,11 +484,13 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(app.Name, retrievedApp.Name);
|
||||
Assert.Equal(app.StoreId, retrievedApp.StoreId);
|
||||
Assert.Equal(app.AppType, retrievedApp.AppType);
|
||||
Assert.False(retrievedApp.Archived);
|
||||
|
||||
// Test the crowdfund-specific endpoint also
|
||||
var retrievedPosApp = await client.GetCrowdfundApp(app.Id);
|
||||
Assert.Equal(app.Name, retrievedPosApp.Name);
|
||||
Assert.Equal(app.Title, retrievedPosApp.Title);
|
||||
var retrievedCfApp = await client.GetCrowdfundApp(app.Id);
|
||||
Assert.Equal(app.Name, retrievedCfApp.Name);
|
||||
Assert.Equal(app.Title, retrievedCfApp.Title);
|
||||
Assert.False(retrievedCfApp.Archived);
|
||||
|
||||
// Make sure we return a 404 if we try to delete an app that doesn't exist
|
||||
await AssertHttpError(404, async () =>
|
||||
@ -536,10 +540,12 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(posApp.Name, apps[0].Name);
|
||||
Assert.Equal(posApp.StoreId, apps[0].StoreId);
|
||||
Assert.Equal(posApp.AppType, apps[0].AppType);
|
||||
Assert.False(apps[0].Archived);
|
||||
|
||||
Assert.Equal(crowdfundApp.Name, apps[1].Name);
|
||||
Assert.Equal(crowdfundApp.StoreId, apps[1].StoreId);
|
||||
Assert.Equal(crowdfundApp.AppType, apps[1].AppType);
|
||||
Assert.False(apps[1].Archived);
|
||||
|
||||
// Get all apps for all store now
|
||||
apps = await client.GetAllApps();
|
||||
@ -549,15 +555,17 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(posApp.Name, apps[0].Name);
|
||||
Assert.Equal(posApp.StoreId, apps[0].StoreId);
|
||||
Assert.Equal(posApp.AppType, apps[0].AppType);
|
||||
Assert.False(apps[0].Archived);
|
||||
|
||||
Assert.Equal(crowdfundApp.Name, apps[1].Name);
|
||||
Assert.Equal(crowdfundApp.StoreId, apps[1].StoreId);
|
||||
Assert.Equal(crowdfundApp.AppType, apps[1].AppType);
|
||||
Assert.False(apps[1].Archived);
|
||||
|
||||
Assert.Equal(newApp.Name, apps[2].Name);
|
||||
Assert.Equal(newApp.StoreId, apps[2].StoreId);
|
||||
Assert.Equal(newApp.AppType, apps[2].AppType);
|
||||
|
||||
Assert.False(apps[2].Archived);
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
@ -878,7 +886,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
TestLogs.LogInformation("Can't archive without knowing the walletId");
|
||||
var ex = await AssertAPIError("missing-permission", async () => await client.ArchivePullPayment("lol", result.Id));
|
||||
Assert.Equal("btcpay.store.canmanagepullpayments", ((GreenfieldPermissionAPIError)ex.APIError).MissingPermission);
|
||||
Assert.Equal("btcpay.store.canarchivepullpayments", ((GreenfieldPermissionAPIError)ex.APIError).MissingPermission);
|
||||
TestLogs.LogInformation("Can't archive without permission");
|
||||
await AssertAPIError("unauthenticated", async () => await unauthenticated.ArchivePullPayment(storeId, result.Id));
|
||||
await client.ArchivePullPayment(storeId, result.Id);
|
||||
@ -1077,7 +1085,39 @@ namespace BTCPayServer.Tests
|
||||
Assert.IsType<string>(lnrURLs.LNURLUri);
|
||||
Assert.Equal(12.303228134m, test4.Amount);
|
||||
Assert.Equal("BTC", test4.Currency);
|
||||
|
||||
|
||||
// Check we can register Boltcard
|
||||
var uid = new byte[7];
|
||||
RandomNumberGenerator.Fill(uid);
|
||||
var card = await client.RegisterBoltcard(test4.Id, new RegisterBoltcardRequest()
|
||||
{
|
||||
UID = uid
|
||||
});
|
||||
Assert.Equal(0, card.Version);
|
||||
var card1keys = new[] { card.K0, card.K1, card.K2, card.K3, card.K4 };
|
||||
Assert.DoesNotContain(null, card1keys);
|
||||
var card2 = await client.RegisterBoltcard(test4.Id, new RegisterBoltcardRequest()
|
||||
{
|
||||
UID = uid
|
||||
});
|
||||
Assert.Equal(1, card2.Version);
|
||||
Assert.StartsWith("lnurlw://", card2.LNURLW);
|
||||
Assert.EndsWith("/boltcard", card2.LNURLW);
|
||||
var card2keys = new[] { card2.K0, card2.K1, card2.K2, card2.K3, card2.K4 };
|
||||
Assert.DoesNotContain(null, card2keys);
|
||||
for (int i = 0; i < card1keys.Length; i++)
|
||||
{
|
||||
if (i == 1)
|
||||
Assert.Contains(card1keys[i], card2keys);
|
||||
else
|
||||
Assert.DoesNotContain(card1keys[i], card2keys);
|
||||
}
|
||||
var card3 = await client.RegisterBoltcard(test4.Id, new RegisterBoltcardRequest()
|
||||
{
|
||||
UID = uid,
|
||||
OnExisting = OnExistingBehavior.KeepVersion
|
||||
});
|
||||
Assert.Equal(card2.Version, card3.Version);
|
||||
// Test with SATS denomination values
|
||||
var testSats = await client.CreatePullPayment(storeId, new Client.Models.CreatePullPaymentRequest()
|
||||
{
|
||||
@ -1152,7 +1192,8 @@ namespace BTCPayServer.Tests
|
||||
Approved = false,
|
||||
PaymentMethod = "BTC",
|
||||
Amount = 0.0001m,
|
||||
Destination = address.ToString()
|
||||
Destination = address.ToString(),
|
||||
|
||||
});
|
||||
await AssertAPIError("invalid-state", async () =>
|
||||
{
|
||||
@ -1271,20 +1312,23 @@ namespace BTCPayServer.Tests
|
||||
using var tester = CreateServerTester();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
await user.GrantAccessAsync();
|
||||
await user.MakeAdmin();
|
||||
var client = await user.CreateClient(Policies.Unrestricted);
|
||||
|
||||
//create store
|
||||
var newStore = await client.CreateStore(new CreateStoreRequest() { Name = "A" });
|
||||
var newStore = await client.CreateStore(new CreateStoreRequest { Name = "A" });
|
||||
Assert.Equal("A", newStore.Name);
|
||||
Assert.Equal(CheckoutType.V2, newStore.CheckoutType);
|
||||
|
||||
//update store
|
||||
Assert.Empty(newStore.PaymentMethodCriteria);
|
||||
await client.GenerateOnChainWallet(newStore.Id, "BTC", new GenerateOnChainWalletRequest());
|
||||
var updatedStore = await client.UpdateStore(newStore.Id, new UpdateStoreRequest()
|
||||
var updatedStore = await client.UpdateStore(newStore.Id, new UpdateStoreRequest
|
||||
{
|
||||
Name = "B",
|
||||
PaymentMethodCriteria = new List<PaymentMethodCriteriaData>()
|
||||
CheckoutType = CheckoutType.V1,
|
||||
PaymentMethodCriteria = new List<PaymentMethodCriteriaData>
|
||||
{
|
||||
new()
|
||||
{
|
||||
@ -1296,6 +1340,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
});
|
||||
Assert.Equal("B", updatedStore.Name);
|
||||
Assert.Equal(CheckoutType.V1, updatedStore.CheckoutType);
|
||||
var s = (await client.GetStore(newStore.Id));
|
||||
Assert.Equal("B", s.Name);
|
||||
var pmc = Assert.Single(s.PaymentMethodCriteria);
|
||||
@ -1350,6 +1395,13 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
tester.DeleteStore = false;
|
||||
Assert.Empty(await client.GetStores());
|
||||
|
||||
// Archive
|
||||
var archivableStore = await client.CreateStore(new CreateStoreRequest { Name = "Archivable" });
|
||||
Assert.False(archivableStore.Archived);
|
||||
archivableStore = await client.UpdateStore(archivableStore.Id, new UpdateStoreRequest { Name = "Archived", Archived = true });
|
||||
Assert.Equal("Archived", archivableStore.Name);
|
||||
Assert.True(archivableStore.Archived);
|
||||
}
|
||||
|
||||
private async Task<GreenfieldValidationException> AssertValidationError(string[] fields, Func<Task> act)
|
||||
@ -1442,7 +1494,7 @@ namespace BTCPayServer.Tests
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanUseWebhooks()
|
||||
{
|
||||
void AssertHook(FakeServer fakeServer, Client.Models.StoreWebhookData hook)
|
||||
void AssertHook(FakeServer fakeServer, StoreWebhookData hook)
|
||||
{
|
||||
Assert.True(hook.Enabled);
|
||||
Assert.True(hook.AuthorizedEvents.Everything);
|
||||
@ -1591,7 +1643,7 @@ namespace BTCPayServer.Tests
|
||||
using var tester = CreateServerTester();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
await user.GrantAccessAsync();
|
||||
await user.MakeAdmin();
|
||||
var client = await user.CreateClient(Policies.Unrestricted);
|
||||
var viewOnly = await user.CreateClient(Policies.CanViewPaymentRequests);
|
||||
@ -1673,11 +1725,18 @@ namespace BTCPayServer.Tests
|
||||
BitcoinAddress.Create(invoice.BitcoinAddress, tester.ExplorerNode.Network), invoice.BtcDue);
|
||||
});
|
||||
await TestUtils.EventuallyAsync(async () =>
|
||||
{
|
||||
Assert.Equal(Invoice.STATUS_PAID, user.BitPay.GetInvoice(invoiceId).Status);
|
||||
if (!partialPayment)
|
||||
Assert.Equal(PaymentRequestData.PaymentRequestStatus.Completed, (await client.GetPaymentRequest(user.StoreId, paymentTestPaymentRequest.Id)).Status);
|
||||
});
|
||||
{
|
||||
Assert.Equal(Invoice.STATUS_PAID, (await user.BitPay.GetInvoiceAsync(invoiceId)).Status);
|
||||
if (!partialPayment)
|
||||
Assert.Equal(PaymentRequestData.PaymentRequestStatus.Processing, (await client.GetPaymentRequest(user.StoreId, paymentTestPaymentRequest.Id)).Status);
|
||||
});
|
||||
await tester.ExplorerNode.GenerateAsync(1);
|
||||
await TestUtils.EventuallyAsync(async () =>
|
||||
{
|
||||
Assert.Equal(Invoice.STATUS_CONFIRMED, (await user.BitPay.GetInvoiceAsync(invoiceId)).Status);
|
||||
if (!partialPayment)
|
||||
Assert.Equal(PaymentRequestData.PaymentRequestStatus.Completed, (await client.GetPaymentRequest(user.StoreId, paymentTestPaymentRequest.Id)).Status);
|
||||
});
|
||||
}
|
||||
await Pay(invoiceId);
|
||||
|
||||
@ -2073,18 +2132,18 @@ namespace BTCPayServer.Tests
|
||||
//validation errors
|
||||
await AssertValidationError(new[] { nameof(CreateInvoiceRequest.Amount), $"{nameof(CreateInvoiceRequest.Checkout)}.{nameof(CreateInvoiceRequest.Checkout.PaymentTolerance)}", $"{nameof(CreateInvoiceRequest.Checkout)}.{nameof(CreateInvoiceRequest.Checkout.PaymentMethods)}[0]" }, async () =>
|
||||
{
|
||||
await client.CreateInvoice(user.StoreId, new CreateInvoiceRequest() { Amount = -1, Checkout = new CreateInvoiceRequest.CheckoutOptions() { PaymentTolerance = -2, PaymentMethods = new[] { "jasaas_sdsad" } } });
|
||||
await client.CreateInvoice(user.StoreId, new CreateInvoiceRequest { Amount = -1, Checkout = new CreateInvoiceRequest.CheckoutOptions { PaymentTolerance = -2, PaymentMethods = new[] { "jasaas_sdsad" } } });
|
||||
});
|
||||
|
||||
await AssertHttpError(403, async () =>
|
||||
{
|
||||
await viewOnly.CreateInvoice(user.StoreId,
|
||||
new CreateInvoiceRequest() { Currency = "helloinvalid", Amount = 1 });
|
||||
new CreateInvoiceRequest { Currency = "helloinvalid", Amount = 1 });
|
||||
});
|
||||
await user.RegisterDerivationSchemeAsync("BTC");
|
||||
string origOrderId = "testOrder";
|
||||
var newInvoice = await client.CreateInvoice(user.StoreId,
|
||||
new CreateInvoiceRequest()
|
||||
new CreateInvoiceRequest
|
||||
{
|
||||
Currency = "USD",
|
||||
Amount = 1,
|
||||
@ -2171,7 +2230,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
//list NonExisting Status
|
||||
var invoicesNonExistingStatus = await viewOnly.GetInvoices(user.StoreId,
|
||||
status: new[] { BTCPayServer.Client.Models.InvoiceStatus.Invalid });
|
||||
status: new[] { InvoiceStatus.Invalid });
|
||||
Assert.NotNull(invoicesNonExistingStatus);
|
||||
Assert.Empty(invoicesNonExistingStatus);
|
||||
|
||||
@ -2189,7 +2248,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
//update
|
||||
newInvoice = await client.CreateInvoice(user.StoreId,
|
||||
new CreateInvoiceRequest() { Currency = "USD", Amount = 1 });
|
||||
new CreateInvoiceRequest { Currency = "USD", Amount = 1 });
|
||||
Assert.Contains(InvoiceStatus.Settled, newInvoice.AvailableStatusesForManualMarking);
|
||||
Assert.Contains(InvoiceStatus.Invalid, newInvoice.AvailableStatusesForManualMarking);
|
||||
await client.MarkInvoiceStatus(user.StoreId, newInvoice.Id, new MarkInvoiceStatusRequest()
|
||||
@ -2201,7 +2260,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.DoesNotContain(InvoiceStatus.Settled, newInvoice.AvailableStatusesForManualMarking);
|
||||
Assert.Contains(InvoiceStatus.Invalid, newInvoice.AvailableStatusesForManualMarking);
|
||||
newInvoice = await client.CreateInvoice(user.StoreId,
|
||||
new CreateInvoiceRequest() { Currency = "USD", Amount = 1 });
|
||||
new CreateInvoiceRequest { Currency = "USD", Amount = 1 });
|
||||
await client.MarkInvoiceStatus(user.StoreId, newInvoice.Id, new MarkInvoiceStatusRequest()
|
||||
{
|
||||
Status = InvoiceStatus.Invalid
|
||||
@ -2216,13 +2275,13 @@ namespace BTCPayServer.Tests
|
||||
await AssertHttpError(403, async () =>
|
||||
{
|
||||
await viewOnly.UpdateInvoice(user.StoreId, invoice.Id,
|
||||
new UpdateInvoiceRequest()
|
||||
new UpdateInvoiceRequest
|
||||
{
|
||||
Metadata = metadataForUpdate
|
||||
});
|
||||
});
|
||||
invoice = await client.UpdateInvoice(user.StoreId, invoice.Id,
|
||||
new UpdateInvoiceRequest()
|
||||
new UpdateInvoiceRequest
|
||||
{
|
||||
Metadata = metadataForUpdate
|
||||
});
|
||||
@ -2262,13 +2321,12 @@ namespace BTCPayServer.Tests
|
||||
await client.UnarchiveInvoice(user.StoreId, invoice.Id);
|
||||
Assert.NotNull(await client.GetInvoice(user.StoreId, invoice.Id));
|
||||
|
||||
|
||||
foreach (var marked in new[] { InvoiceStatus.Settled, InvoiceStatus.Invalid })
|
||||
{
|
||||
var inv = await client.CreateInvoice(user.StoreId,
|
||||
new CreateInvoiceRequest() { Currency = "USD", Amount = 100 });
|
||||
new CreateInvoiceRequest { Currency = "USD", Amount = 100 });
|
||||
await user.PayInvoice(inv.Id);
|
||||
await client.MarkInvoiceStatus(user.StoreId, inv.Id, new MarkInvoiceStatusRequest()
|
||||
await client.MarkInvoiceStatus(user.StoreId, inv.Id, new MarkInvoiceStatusRequest
|
||||
{
|
||||
Status = marked
|
||||
});
|
||||
@ -2296,13 +2354,12 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
newInvoice = await client.CreateInvoice(user.StoreId,
|
||||
new CreateInvoiceRequest()
|
||||
new CreateInvoiceRequest
|
||||
{
|
||||
Currency = "USD",
|
||||
Amount = 1,
|
||||
Checkout = new CreateInvoiceRequest.CheckoutOptions()
|
||||
Checkout = new CreateInvoiceRequest.CheckoutOptions
|
||||
{
|
||||
DefaultLanguage = "it-it ",
|
||||
RedirectURL = "http://toto.com/lol"
|
||||
@ -3211,6 +3268,9 @@ namespace BTCPayServer.Tests
|
||||
});
|
||||
var transaction = await client.GetOnChainWalletTransaction(walletId.StoreId, walletId.CryptoCode, txdata.TransactionHash.ToString());
|
||||
|
||||
// Check skip doesn't crash
|
||||
await client.ShowOnChainWalletTransactions(walletId.StoreId, walletId.CryptoCode, skip: 1);
|
||||
|
||||
Assert.Equal(transaction.TransactionHash, txdata.TransactionHash);
|
||||
Assert.Equal(String.Empty, transaction.Comment);
|
||||
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
@ -3545,6 +3605,7 @@ namespace BTCPayServer.Tests
|
||||
PaymentMethod = "BTC_LightningNetwork",
|
||||
Destination = customerInvoice.BOLT11
|
||||
});
|
||||
Assert.Equal(payout.Metadata.ToString(), new JObject().ToString()); //empty
|
||||
Assert.Empty(await adminClient.GetStoreLightningAutomatedPayoutProcessors(admin.StoreId, "BTC_LightningNetwork"));
|
||||
await adminClient.UpdateStoreLightningAutomatedPayoutProcessors(admin.StoreId, "BTC_LightningNetwork",
|
||||
new LightningAutomatedPayoutSettings() { IntervalSeconds = TimeSpan.FromSeconds(600) });
|
||||
@ -3555,6 +3616,46 @@ namespace BTCPayServer.Tests
|
||||
(await adminClient.GetStorePayouts(admin.StoreId, false)).Single(data => data.Id == payout.Id);
|
||||
Assert.Equal(PayoutState.Completed, payoutC.State);
|
||||
});
|
||||
|
||||
payout = await adminClient.CreatePayout(admin.StoreId,
|
||||
new CreatePayoutThroughStoreRequest()
|
||||
{
|
||||
Approved = true,
|
||||
PaymentMethod = "BTC",
|
||||
Destination = (await tester.ExplorerNode.GetNewAddressAsync()).ToString(),
|
||||
Amount = 0.0001m,
|
||||
Metadata = JObject.FromObject(new
|
||||
{
|
||||
source ="apitest",
|
||||
sourceLink = "https://chocolate.com"
|
||||
})
|
||||
});
|
||||
Assert.Equal(payout.Metadata.ToString(), JObject.FromObject(new
|
||||
{
|
||||
source = "apitest",
|
||||
sourceLink = "https://chocolate.com"
|
||||
}).ToString());
|
||||
|
||||
payout =
|
||||
(await adminClient.GetStorePayouts(admin.StoreId, false)).Single(data => data.Id == payout.Id);
|
||||
|
||||
Assert.Equal(payout.Metadata.ToString(), JObject.FromObject(new
|
||||
{
|
||||
source = "apitest",
|
||||
sourceLink = "https://chocolate.com"
|
||||
}).ToString());
|
||||
|
||||
customerInvoice = await tester.CustomerLightningD.CreateInvoice(LightMoney.FromUnit(10, LightMoneyUnit.Satoshi),
|
||||
Guid.NewGuid().ToString(), TimeSpan.FromDays(40));
|
||||
var payout2 = await adminClient.CreatePayout(admin.StoreId,
|
||||
new CreatePayoutThroughStoreRequest()
|
||||
{
|
||||
Approved = true,
|
||||
Amount = new Money(100, MoneyUnit.Satoshi).ToDecimal(MoneyUnit.BTC),
|
||||
PaymentMethod = "BTC_LightningNetwork",
|
||||
Destination = customerInvoice.BOLT11
|
||||
});
|
||||
Assert.Equal(payout2.Amount, new Money(100, MoneyUnit.Satoshi).ToDecimal(MoneyUnit.BTC));
|
||||
}
|
||||
|
||||
[Fact(Timeout = 60 * 2 * 1000)]
|
||||
@ -4405,7 +4506,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
|
||||
await AssertHttpError(404, async () => await withdrawalClient.SimulateCustodianAccountWithdrawal(storeId, "WRONG-ACCOUNT-ID", simulateWithdrawalRequest));
|
||||
|
||||
// Test: SimulateWithdrawal, wrong store ID
|
||||
// TODO it is wierd that 403 is considered normal, but it is like this for all calls where the store is wrong... I'd have preferred a 404 error, because the store cannot be found.
|
||||
// TODO it is weird that 403 is considered normal, but it is like this for all calls where the store is wrong... I'd have preferred a 404 error, because the store cannot be found.
|
||||
await AssertHttpError(403, async () => await withdrawalClient.SimulateCustodianAccountWithdrawal("WRONG-STORE-ID", accountId, simulateWithdrawalRequest));
|
||||
|
||||
// Test: SimulateWithdrawal, correct payment method, wrong amount
|
||||
@ -4436,7 +4537,7 @@ clientBasic.PreviewUpdateStoreRateConfiguration(user.StoreId, new StoreRateConfi
|
||||
await AssertHttpError(404, async () => await withdrawalClient.CreateCustodianAccountWithdrawal(storeId, "WRONG-ACCOUNT-ID", createWithdrawalRequest));
|
||||
|
||||
// Test: CreateWithdrawal, wrong store ID
|
||||
// TODO it is wierd that 403 is considered normal, but it is like this for all calls where the store is wrong... I'd have preferred a 404 error, because the store cannot be found.
|
||||
// TODO it is weird that 403 is considered normal, but it is like this for all calls where the store is wrong... I'd have preferred a 404 error, because the store cannot be found.
|
||||
await AssertHttpError(403, async () => await withdrawalClient.CreateCustodianAccountWithdrawal("WRONG-STORE-ID", accountId, createWithdrawalRequest));
|
||||
|
||||
// Test: CreateWithdrawal, correct payment method, wrong amount
|
||||
|
@ -1,8 +1,10 @@
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Controllers;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Hosting;
|
||||
using BTCPayServer.Models.AppViewModels;
|
||||
using BTCPayServer.Plugins.Crowdfund.Models;
|
||||
using BTCPayServer.Plugins.PointOfSale;
|
||||
using BTCPayServer.Plugins.PointOfSale.Controllers;
|
||||
using BTCPayServer.Plugins.PointOfSale.Models;
|
||||
@ -123,12 +125,14 @@ donation:
|
||||
price: 1.02
|
||||
custom: true
|
||||
";
|
||||
vmpos.Currency = "EUR";
|
||||
vmpos.Template = AppService.SerializeTemplate(MigrationStartupTask.ParsePOSYML(vmpos.Template));
|
||||
Assert.IsType<RedirectToActionResult>(pos.UpdatePointOfSale(app.Id, vmpos).Result);
|
||||
await pos.UpdatePointOfSale(app.Id).AssertViewModelAsync<UpdatePointOfSaleViewModel>();
|
||||
var publicApps = user.GetController<UIPointOfSaleController>();
|
||||
var vmview = await publicApps.ViewPointOfSale(app.Id, PosViewType.Cart).AssertViewModelAsync<ViewPointOfSaleViewModel>();
|
||||
|
||||
Assert.Equal("EUR", vmview.CurrencyCode);
|
||||
// apple shouldn't be available since we it's set to "disabled: true" above
|
||||
Assert.Equal(2, vmview.Items.Length);
|
||||
Assert.Equal("orange", vmview.Items[0].Title);
|
||||
@ -139,6 +143,41 @@ donation:
|
||||
// apple is not found
|
||||
Assert.IsType<NotFoundResult>(publicApps
|
||||
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, choiceKey: "apple").Result);
|
||||
|
||||
// List
|
||||
appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
|
||||
app = appList.Apps[0];
|
||||
apps = user.GetController<UIAppsController>();
|
||||
appData = new AppData { Id = app.Id, StoreDataId = app.StoreId, Name = app.AppName, AppType = appType, Settings = "{\"currency\":\"EUR\"}" };
|
||||
apps.HttpContext.SetAppData(appData);
|
||||
pos.HttpContext.SetAppData(appData);
|
||||
Assert.Single(appList.Apps);
|
||||
Assert.Equal("test", app.AppName);
|
||||
Assert.True(app.Role.ToPermissionSet(appList.Apps[0].StoreId).Contains(Policies.CanModifyStoreSettings, app.StoreId));
|
||||
Assert.Equal(user.StoreId, app.StoreId);
|
||||
Assert.False(app.Archived);
|
||||
// Archive
|
||||
redirect = Assert.IsType<RedirectResult>(apps.ToggleArchive(app.Id).Result);
|
||||
Assert.EndsWith("/settings/pos", redirect.Url);
|
||||
appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
|
||||
Assert.Empty(appList.Apps);
|
||||
appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId, archived: true).Result).Model);
|
||||
app = appList.Apps[0];
|
||||
Assert.True(app.Archived);
|
||||
Assert.IsType<NotFoundResult>(await publicApps.ViewPointOfSale(app.Id, PosViewType.Static));
|
||||
// Unarchive
|
||||
redirect = Assert.IsType<RedirectResult>(apps.ToggleArchive(app.Id).Result);
|
||||
Assert.EndsWith("/settings/pos", redirect.Url);
|
||||
appList = Assert.IsType<ListAppsViewModel>(Assert.IsType<ViewResult>(apps.ListApps(user.StoreId).Result).Model);
|
||||
app = appList.Apps[0];
|
||||
Assert.False(app.Archived);
|
||||
Assert.IsType<ViewResult>(await publicApps.ViewPointOfSale(app.Id, PosViewType.Static));
|
||||
// Delete
|
||||
Assert.IsType<ViewResult>(apps.DeleteApp(app.Id));
|
||||
var redirectToAction = Assert.IsType<RedirectToActionResult>(apps.DeleteAppPost(app.Id).Result);
|
||||
Assert.Equal(nameof(UIStoresController.Dashboard), redirectToAction.ActionName);
|
||||
appList = await apps.ListApps(user.StoreId).AssertViewModelAsync<ListAppsViewModel>();
|
||||
Assert.Empty(appList.Apps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ namespace BTCPayServer.Tests
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
|
||||
var user2 = tester.NewAccount();
|
||||
|
||||
await user2.GrantAccessAsync();
|
||||
|
||||
var paymentRequestController = user.GetController<UIPaymentRequestController>();
|
||||
@ -162,7 +161,7 @@ namespace BTCPayServer.Tests
|
||||
using var tester = CreateServerTester();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
await user.GrantAccessAsync();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
|
||||
var paymentRequestController = user.GetController<UIPaymentRequestController>();
|
||||
@ -170,7 +169,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.IsType<NotFoundResult>(await
|
||||
paymentRequestController.CancelUnpaidPendingInvoice(Guid.NewGuid().ToString(), false));
|
||||
|
||||
var request = new UpdatePaymentRequestViewModel()
|
||||
var request = new UpdatePaymentRequestViewModel
|
||||
{
|
||||
Title = "original juice",
|
||||
Currency = "BTC",
|
||||
|
@ -295,17 +295,12 @@ namespace BTCPayServer.Tests
|
||||
|
||||
public void AddLightningNode()
|
||||
{
|
||||
AddLightningNode(null, null, true);
|
||||
AddLightningNode(null, true);
|
||||
}
|
||||
|
||||
public void AddLightningNode(LightningConnectionType? connectionType = null, bool test = true)
|
||||
public void AddLightningNode(string connectionType = null, bool test = true)
|
||||
{
|
||||
AddLightningNode(null, connectionType, test);
|
||||
}
|
||||
|
||||
public void AddLightningNode(string cryptoCode = null, LightningConnectionType? connectionType = null, bool test = true)
|
||||
{
|
||||
cryptoCode ??= "BTC";
|
||||
var cryptoCode = "BTC";
|
||||
if (!Driver.PageSource.Contains("Connect to a Lightning node"))
|
||||
{
|
||||
GoToLightningSettings();
|
||||
@ -565,7 +560,7 @@ namespace BTCPayServer.Tests
|
||||
walletId ??= WalletId;
|
||||
GoToWallet(walletId, WalletsNavPages.Receive);
|
||||
Driver.FindElement(By.Id("generateButton")).Click();
|
||||
var addressStr = Driver.FindElement(By.Id("Address")).GetAttribute("value");
|
||||
var addressStr = Driver.FindElement(By.Id("Address")).GetAttribute("data-text");
|
||||
var address = BitcoinAddress.Create(addressStr, ((BTCPayNetwork)Server.NetworkProvider.GetNetwork(walletId.CryptoCode)).NBitcoinNetwork);
|
||||
for (var i = 0; i < coins; i++)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,11 +5,14 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Hosting;
|
||||
using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Lightning.CLightning;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.Tests.Lnd;
|
||||
using BTCPayServer.Tests.Logging;
|
||||
using Microsoft.Extensions.Configuration.Memory;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NBitcoin;
|
||||
using NBitcoin.RPC;
|
||||
@ -26,7 +29,7 @@ namespace BTCPayServer.Tests
|
||||
public ILoggerProvider LoggerProvider { get; }
|
||||
|
||||
internal ILog TestLogs;
|
||||
public ServerTester(string scope, bool newDb, ILog testLogs, ILoggerProvider loggerProvider)
|
||||
public ServerTester(string scope, bool newDb, ILog testLogs, ILoggerProvider loggerProvider, BTCPayNetworkProvider networkProvider)
|
||||
{
|
||||
LoggerProvider = loggerProvider;
|
||||
this.TestLogs = testLogs;
|
||||
@ -36,7 +39,7 @@ namespace BTCPayServer.Tests
|
||||
if (!Directory.Exists(_Directory))
|
||||
Directory.CreateDirectory(_Directory);
|
||||
|
||||
NetworkProvider = new BTCPayNetworkProvider(ChainName.Regtest);
|
||||
NetworkProvider = networkProvider;
|
||||
ExplorerNode = new RPCClient(RPCCredentialString.Parse(GetEnvironment("TESTS_BTCRPCCONNECTION", "server=http://127.0.0.1:43782;ceiwHEbqWI83:DwubwWsoo3")), NetworkProvider.GetNetwork<BTCPayNetwork>("BTC").NBitcoinNetwork);
|
||||
ExplorerNode.ScanRPCCapabilities();
|
||||
|
||||
@ -94,17 +97,18 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
ActivateLightning(LightningConnectionType.CLightning);
|
||||
}
|
||||
public void ActivateLightning(LightningConnectionType internalNode)
|
||||
public void ActivateLightning(string internalNode)
|
||||
{
|
||||
var btc = NetworkProvider.GetNetwork<BTCPayNetwork>("BTC").NBitcoinNetwork;
|
||||
CustomerLightningD = LightningClientFactory.CreateClient(GetEnvironment("TEST_CUSTOMERLIGHTNINGD", "type=clightning;server=tcp://127.0.0.1:30992/"), btc);
|
||||
MerchantLightningD = LightningClientFactory.CreateClient(GetEnvironment("TEST_MERCHANTLIGHTNINGD", "type=clightning;server=tcp://127.0.0.1:30993/"), btc);
|
||||
var factory = new LightningClientFactory(btc);
|
||||
CustomerLightningD = factory.Create(GetEnvironment("TEST_CUSTOMERLIGHTNINGD", "type=clightning;server=tcp://127.0.0.1:30992/"));
|
||||
MerchantLightningD = factory.Create(GetEnvironment("TEST_MERCHANTLIGHTNINGD", "type=clightning;server=tcp://127.0.0.1:30993/"));
|
||||
MerchantCharge = new ChargeTester(this, "TEST_MERCHANTCHARGE", "type=charge;server=http://127.0.0.1:54938/;api-token=foiewnccewuify;allowinsecure=true", "merchant_lightningd", btc);
|
||||
MerchantLnd = new LndMockTester(this, "TEST_MERCHANTLND", "http://lnd:lnd@127.0.0.1:35531/", "merchant_lnd", btc);
|
||||
PayTester.UseLightning = true;
|
||||
PayTester.IntegratedLightning = GetLightningConnectionString(internalNode, true);
|
||||
}
|
||||
public string GetLightningConnectionString(LightningConnectionType? connectionType, bool isMerchant)
|
||||
public string GetLightningConnectionString(string connectionType, bool isMerchant)
|
||||
{
|
||||
string connectionString = null;
|
||||
if (connectionType is null)
|
||||
|
@ -40,6 +40,7 @@ namespace BTCPayServer.Tests
|
||||
public class TestAccount
|
||||
{
|
||||
readonly ServerTester parent;
|
||||
public string LNAddress;
|
||||
|
||||
public TestAccount(ServerTester parent)
|
||||
{
|
||||
@ -242,7 +243,7 @@ namespace BTCPayServer.Tests
|
||||
policies.LockSubscription = false;
|
||||
await account.Register(RegisterDetails);
|
||||
}
|
||||
|
||||
TestLogs.LogInformation($"UserId: {account.RegisteredUserId} Password: {Password}");
|
||||
UserId = account.RegisteredUserId;
|
||||
Email = RegisterDetails.Email;
|
||||
IsAdmin = account.RegisteredAdmin;
|
||||
@ -277,7 +278,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
public bool IsAdmin { get; internal set; }
|
||||
|
||||
public void RegisterLightningNode(string cryptoCode, LightningConnectionType? connectionType = null, bool isMerchant = true)
|
||||
public void RegisterLightningNode(string cryptoCode, string connectionType = null, bool isMerchant = true)
|
||||
{
|
||||
RegisterLightningNodeAsync(cryptoCode, connectionType, isMerchant).GetAwaiter().GetResult();
|
||||
}
|
||||
@ -285,7 +286,7 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
return RegisterLightningNodeAsync(cryptoCode, null, isMerchant, storeId);
|
||||
}
|
||||
public async Task RegisterLightningNodeAsync(string cryptoCode, LightningConnectionType? connectionType, bool isMerchant = true, string storeId = null)
|
||||
public async Task RegisterLightningNodeAsync(string cryptoCode, string connectionType, bool isMerchant = true, string storeId = null)
|
||||
{
|
||||
var storeController = GetController<UIStoresController>();
|
||||
|
||||
@ -296,7 +297,7 @@ namespace BTCPayServer.Tests
|
||||
await storeController.SetupLightningNode(storeId ?? StoreId,
|
||||
vm, "save", cryptoCode);
|
||||
if (storeController.ModelState.ErrorCount != 0)
|
||||
Assert.False(true, storeController.ModelState.FirstOrDefault().Value.Errors[0].ErrorMessage);
|
||||
Assert.Fail(storeController.ModelState.FirstOrDefault().Value.Errors[0].ErrorMessage);
|
||||
}
|
||||
|
||||
public async Task RegisterInternalLightningNodeAsync(string cryptoCode, string storeId = null)
|
||||
@ -306,11 +307,12 @@ namespace BTCPayServer.Tests
|
||||
await storeController.SetupLightningNode(storeId ?? StoreId,
|
||||
vm, "save", cryptoCode);
|
||||
if (storeController.ModelState.ErrorCount != 0)
|
||||
Assert.False(true, storeController.ModelState.FirstOrDefault().Value.Errors[0].ErrorMessage);
|
||||
Assert.Fail(storeController.ModelState.FirstOrDefault().Value.Errors[0].ErrorMessage);
|
||||
}
|
||||
|
||||
public async Task<Coin> ReceiveUTXO(Money value, BTCPayNetwork network)
|
||||
public async Task<Coin> ReceiveUTXO(Money value, BTCPayNetwork network = null)
|
||||
{
|
||||
network ??= SupportedNetwork;
|
||||
var cashCow = parent.ExplorerNode;
|
||||
var btcPayWallet = parent.PayTester.GetService<BTCPayWalletProvider>().GetWallet(network);
|
||||
var address = (await btcPayWallet.ReserveAddressAsync(this.DerivationScheme)).Address;
|
||||
@ -430,8 +432,7 @@ namespace BTCPayServer.Tests
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var error = JObject.Parse(await response.Content.ReadAsStringAsync());
|
||||
Assert.True(false,
|
||||
$"Error: {error["errorCode"].Value<string>()}: {error["message"].Value<string>()}");
|
||||
Assert.Fail($"Error: {error["errorCode"].Value<string>()}: {error["message"].Value<string>()}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -486,7 +487,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
public List<WebhookInvoiceEvent> WebhookEvents { get; set; } = new List<WebhookInvoiceEvent>();
|
||||
public TEvent AssertHasWebhookEvent<TEvent>(WebhookEventType eventType, Action<TEvent> assert) where TEvent : class
|
||||
public TEvent AssertHasWebhookEvent<TEvent>(string eventType, Action<TEvent> assert) where TEvent : class
|
||||
{
|
||||
int retry = 0;
|
||||
retry:
|
||||
@ -514,12 +515,12 @@ retry:
|
||||
retry++;
|
||||
goto retry;
|
||||
}
|
||||
Assert.True(false, "No webhook event match the assertion");
|
||||
Assert.Fail("No webhook event match the assertion");
|
||||
return null;
|
||||
}
|
||||
public async Task SetupWebhook()
|
||||
{
|
||||
FakeServer server = new FakeServer();
|
||||
var server = new FakeServer();
|
||||
await server.Start();
|
||||
var client = await CreateClient(Policies.CanModifyStoreWebhooks);
|
||||
var wh = await client.CreateWebhook(StoreId, new CreateStoreWebhookRequest()
|
||||
@ -535,7 +536,7 @@ retry:
|
||||
{
|
||||
var inv = await BitPay.GetInvoiceAsync(invoiceId);
|
||||
var net = parent.ExplorerNode.Network;
|
||||
this.parent.ExplorerNode.SendToAddress(BitcoinAddress.Create(inv.BitcoinAddress, net), inv.BtcDue);
|
||||
await parent.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(inv.BitcoinAddress, net), inv.BtcDue);
|
||||
await TestUtils.EventuallyAsync(async () =>
|
||||
{
|
||||
var localInvoice = await BitPay.GetInvoiceAsync(invoiceId, Facade.Merchant);
|
||||
@ -553,5 +554,94 @@ retry:
|
||||
var repo = this.parent.PayTester.GetService<StoreRepository>();
|
||||
await repo.AddStoreUser(StoreId, userId, StoreRoleId.Owner);
|
||||
}
|
||||
|
||||
public async Task<uint256> PayOnChain(string invoiceId)
|
||||
{
|
||||
var cryptoCode = "BTC";
|
||||
var client = await CreateClient();
|
||||
var methods = await client.GetInvoicePaymentMethods(StoreId, invoiceId);
|
||||
var method = methods.First(m => m.PaymentMethod == cryptoCode);
|
||||
var address = method.Destination;
|
||||
var tx = await client.CreateOnChainTransaction(StoreId, cryptoCode, new CreateOnChainTransactionRequest()
|
||||
{
|
||||
Destinations = new List<CreateOnChainTransactionRequest.CreateOnChainTransactionRequestDestination>()
|
||||
{
|
||||
new ()
|
||||
{
|
||||
Destination = address,
|
||||
Amount = method.Due
|
||||
}
|
||||
},
|
||||
FeeRate = new FeeRate(1.0m)
|
||||
});
|
||||
await WaitInvoicePaid(invoiceId);
|
||||
return tx.TransactionHash;
|
||||
}
|
||||
|
||||
public async Task PayOnBOLT11(string invoiceId)
|
||||
{
|
||||
var cryptoCode = "BTC";
|
||||
var client = await CreateClient();
|
||||
var methods = await client.GetInvoicePaymentMethods(StoreId, invoiceId);
|
||||
var method = methods.First(m => m.PaymentMethod == $"{cryptoCode}-LightningNetwork");
|
||||
var bolt11 = method.Destination;
|
||||
TestLogs.LogInformation("PAYING");
|
||||
await parent.CustomerLightningD.Pay(bolt11);
|
||||
TestLogs.LogInformation("PAID");
|
||||
await WaitInvoicePaid(invoiceId);
|
||||
}
|
||||
|
||||
public async Task PayOnLNUrl(string invoiceId)
|
||||
{
|
||||
var cryptoCode = "BTC";
|
||||
var network = SupportedNetwork.NBitcoinNetwork;
|
||||
var client = await CreateClient();
|
||||
var methods = await client.GetInvoicePaymentMethods(StoreId, invoiceId);
|
||||
var method = methods.First(m => m.PaymentMethod == $"{cryptoCode}-LNURLPAY");
|
||||
var lnurL = LNURL.LNURL.Parse(method.PaymentLink, out var tag);
|
||||
var http = new HttpClient();
|
||||
var payreq = (LNURL.LNURLPayRequest)await LNURL.LNURL.FetchInformation(lnurL, tag, http);
|
||||
var resp = await payreq.SendRequest(payreq.MinSendable, network, http);
|
||||
var bolt11 = resp.Pr;
|
||||
await parent.CustomerLightningD.Pay(bolt11);
|
||||
await WaitInvoicePaid(invoiceId);
|
||||
}
|
||||
|
||||
public Task WaitInvoicePaid(string invoiceId)
|
||||
{
|
||||
return TestUtils.EventuallyAsync(async () =>
|
||||
{
|
||||
var client = await CreateClient();
|
||||
var invoice = await client.GetInvoice(StoreId, invoiceId);
|
||||
if (invoice.Status == InvoiceStatus.Settled)
|
||||
return;
|
||||
Assert.Equal(InvoiceStatus.Processing, invoice.Status);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task PayOnLNAddress(string lnAddrUser = null)
|
||||
{
|
||||
lnAddrUser ??= LNAddress;
|
||||
var network = SupportedNetwork.NBitcoinNetwork;
|
||||
var payReqStr = await (await parent.PayTester.HttpClient.GetAsync($".well-known/lnurlp/{lnAddrUser}")).Content.ReadAsStringAsync();
|
||||
var payreq = JsonConvert.DeserializeObject<LNURL.LNURLPayRequest>(payReqStr);
|
||||
var resp = await payreq.SendRequest(payreq.MinSendable, network, parent.PayTester.HttpClient);
|
||||
var bolt11 = resp.Pr;
|
||||
await parent.CustomerLightningD.Pay(bolt11);
|
||||
}
|
||||
|
||||
public async Task<string> CreateLNAddress()
|
||||
{
|
||||
var lnAddrUser = Guid.NewGuid().ToString();
|
||||
var ctx = parent.PayTester.GetService<ApplicationDbContextFactory>().CreateContext();
|
||||
ctx.LightningAddresses.Add(new()
|
||||
{
|
||||
StoreDataId = StoreId,
|
||||
Username = lnAddrUser
|
||||
});
|
||||
await ctx.SaveChangesAsync();
|
||||
LNAddress = lnAddrUser;
|
||||
return lnAddrUser;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NBitcoin;
|
||||
using OpenQA.Selenium;
|
||||
using Xunit;
|
||||
using Xunit.Sdk;
|
||||
|
@ -11,17 +11,22 @@ using BTCPayServer.Controllers;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Models.StoreViewModels;
|
||||
using BTCPayServer.Rating;
|
||||
using BTCPayServer.Services.Fees;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using BTCPayServer.Storage.Models;
|
||||
using BTCPayServer.Storage.Services.Providers.AzureBlobStorage.Configuration;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.FileSystemGlobbing;
|
||||
using NBitcoin;
|
||||
using NBitpayClient;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
using static BTCPayServer.HostedServices.PullPaymentHostedService.PayoutApproval;
|
||||
|
||||
namespace BTCPayServer.Tests
|
||||
{
|
||||
@ -71,6 +76,25 @@ namespace BTCPayServer.Tests
|
||||
await UnitTest1.CanUploadRemoveFiles(controller);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanQueryMempoolFeeProvider()
|
||||
{
|
||||
IServiceCollection collection = new ServiceCollection();
|
||||
collection.AddMemoryCache();
|
||||
collection.AddHttpClient();
|
||||
var prov = collection.BuildServiceProvider();
|
||||
foreach (var isTestnet in new[] { true, false })
|
||||
{
|
||||
var mempoolSpaceFeeProvider = new MempoolSpaceFeeProvider(
|
||||
prov.GetService<IMemoryCache>(),
|
||||
"test" + isTestnet,
|
||||
prov.GetService<IHttpClientFactory>(),
|
||||
isTestnet);
|
||||
var rates = await mempoolSpaceFeeProvider.GetFeeRatesAsync();
|
||||
Assert.NotEmpty(rates);
|
||||
await mempoolSpaceFeeProvider.GetFeeRateAsync(20);
|
||||
}
|
||||
}
|
||||
[Fact]
|
||||
public async Task CanQueryDirectProviders()
|
||||
{
|
||||
@ -177,7 +201,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Contains(rates, e => e.CurrencyPair == new CurrencyPair("XMR", "BTC") && e.BidAsk.Bid < 1.0m);
|
||||
|
||||
// Check we didn't skip too many exchanges
|
||||
Assert.InRange(skipped, 0, 3);
|
||||
Assert.InRange(skipped, 0, 5);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -266,7 +290,7 @@ retry:
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var details = ex is EqualException ? (ex as EqualException).Actual : ex.Message;
|
||||
var details = ex.Message;
|
||||
TestLogs.LogInformation($"FAILED: {url} ({file}) {details}");
|
||||
|
||||
throw;
|
||||
@ -276,7 +300,7 @@ retry:
|
||||
[Fact()]
|
||||
public void CanSolveTheDogesRatesOnKraken()
|
||||
{
|
||||
var provider = new BTCPayNetworkProvider(ChainName.Mainnet);
|
||||
var provider = CreateNetworkProvider(ChainName.Mainnet);
|
||||
var factory = FastTests.CreateBTCPayRateFactory();
|
||||
var fetcher = new RateFetcher(factory);
|
||||
|
||||
@ -289,11 +313,45 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanGetRateFromRecommendedExchanges()
|
||||
{
|
||||
var factory = FastTests.CreateBTCPayRateFactory();
|
||||
var fetcher = new RateFetcher(factory);
|
||||
var provider = CreateNetworkProvider(ChainName.Mainnet);
|
||||
var b = new StoreBlob();
|
||||
string[] temporarilyBroken = { "COP", "UGX" };
|
||||
foreach (var k in StoreBlob.RecommendedExchanges)
|
||||
{
|
||||
b.DefaultCurrency = k.Key;
|
||||
var rules = b.GetDefaultRateRules(provider);
|
||||
var pairs = new[] { CurrencyPair.Parse($"BTC_{k.Key}") }.ToHashSet();
|
||||
var result = fetcher.FetchRates(pairs, rules, default);
|
||||
foreach ((CurrencyPair key, Task<RateResult> value) in result)
|
||||
{
|
||||
TestLogs.LogInformation($"Testing {key} when default currency is {k.Key}");
|
||||
var rateResult = await value;
|
||||
var hasRate = rateResult.BidAsk != null;
|
||||
|
||||
if (temporarilyBroken.Contains(k.Key))
|
||||
{
|
||||
if (!hasRate)
|
||||
{
|
||||
TestLogs.LogInformation($"Skipping {key} because it is marked as temporarily broken");
|
||||
continue;
|
||||
}
|
||||
TestLogs.LogInformation($"Note: {key} is marked as temporarily broken, but the rate is available");
|
||||
}
|
||||
Assert.True(hasRate, $"Impossible to get the rate {rateResult.EvaluatedRule}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanGetRateCryptoCurrenciesByDefault()
|
||||
{
|
||||
string[] brokenShitcoins = { };
|
||||
var provider = new BTCPayNetworkProvider(ChainName.Mainnet);
|
||||
using var cts = new CancellationTokenSource(60_000);
|
||||
var provider = CreateNetworkProvider(ChainName.Mainnet);
|
||||
var factory = FastTests.CreateBTCPayRateFactory();
|
||||
var fetcher = new RateFetcher(factory);
|
||||
var pairs =
|
||||
@ -301,37 +359,25 @@ retry:
|
||||
.Select(c => new CurrencyPair(c.CryptoCode, "USD"))
|
||||
.ToHashSet();
|
||||
|
||||
string[] brokenShitcoins = { "BTG", "BTX" };
|
||||
bool IsBrokenShitcoin(CurrencyPair p) => brokenShitcoins.Contains(p.Left) || brokenShitcoins.Contains(p.Right);
|
||||
foreach (var _ in brokenShitcoins)
|
||||
{
|
||||
foreach (var p in pairs.Where(IsBrokenShitcoin).ToArray())
|
||||
{
|
||||
TestLogs.LogInformation($"Skipping {p} because it is marked as broken");
|
||||
pairs.Remove(p);
|
||||
}
|
||||
}
|
||||
|
||||
var rules = new StoreBlob().GetDefaultRateRules(provider);
|
||||
var result = fetcher.FetchRates(pairs, rules, default);
|
||||
var result = fetcher.FetchRates(pairs, rules, cts.Token);
|
||||
foreach ((CurrencyPair key, Task<RateResult> value) in result)
|
||||
{
|
||||
var rateResult = await value;
|
||||
TestLogs.LogInformation($"Testing {key}");
|
||||
if (brokenShitcoins.Contains(key.ToString()))
|
||||
continue;
|
||||
Assert.True(rateResult.BidAsk != null, $"Impossible to get the rate {rateResult.EvaluatedRule}");
|
||||
}
|
||||
|
||||
var b = new StoreBlob();
|
||||
foreach (var k in StoreBlob.RecommendedExchanges)
|
||||
{
|
||||
b.DefaultCurrency = k.Key;
|
||||
rules = b.GetDefaultRateRules(provider);
|
||||
pairs =
|
||||
provider.GetAll()
|
||||
.Select(c => new CurrencyPair(c.CryptoCode, k.Key))
|
||||
.ToHashSet();
|
||||
result = fetcher.FetchRates(pairs, rules, default);
|
||||
foreach ((CurrencyPair key, Task<RateResult> value) in result)
|
||||
{
|
||||
var rateResult = await value;
|
||||
TestLogs.LogInformation($"Testing {key} when default currency is {k.Key}");
|
||||
if (brokenShitcoins.Contains(key.ToString()))
|
||||
continue;
|
||||
Assert.True(rateResult.BidAsk != null, $"Impossible to get the rate {rateResult.EvaluatedRule}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -373,7 +419,8 @@ retry:
|
||||
EqualJsContent(expected, actual);
|
||||
|
||||
actual = GetFileContent("BTCPayServer", "wwwroot", "vendor", "tom-select", "tom-select.complete.min.js").Trim();
|
||||
expected = (await (await client.GetAsync($"https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/js/tom-select.complete.min.js")).Content.ReadAsStringAsync()).Trim();
|
||||
version = Regex.Match(actual, "Tom Select v([0-9]+.[0-9]+.[0-9]+)").Groups[1].Value;
|
||||
expected = (await (await client.GetAsync($"https://cdn.jsdelivr.net/npm/tom-select@{version}/dist/js/tom-select.complete.min.js")).Content.ReadAsStringAsync()).Trim();
|
||||
EqualJsContent(expected, actual);
|
||||
|
||||
actual = GetFileContent("BTCPayServer", "wwwroot", "vendor", "dom-confetti", "dom-confetti.min.js").Trim();
|
||||
@ -391,10 +438,23 @@ retry:
|
||||
expected = (await (await client.GetAsync($"https://cdnjs.cloudflare.com/ajax/libs/bootstrap-vue/{version}/bootstrap-vue.min.js")).Content.ReadAsStringAsync()).Trim();
|
||||
EqualJsContent(expected, actual);
|
||||
|
||||
actual = GetFileContent("BTCPayServer", "wwwroot", "vendor", "FileSaver", "FileSaver.min.js").Trim();
|
||||
expected = (await (await client.GetAsync($"https://raw.githubusercontent.com/eligrey/FileSaver.js/43bbd2f0ae6794f8d452cd360e9d33aef6071234/dist/FileSaver.min.js")).Content.ReadAsStringAsync()).Trim();
|
||||
EqualJsContent(expected, actual);
|
||||
|
||||
actual = GetFileContent("BTCPayServer", "wwwroot", "vendor", "papaparse", "papaparse.min.js").Trim();
|
||||
expected = (await (await client.GetAsync($"https://raw.githubusercontent.com/mholt/PapaParse/5.4.1/papaparse.min.js")).Content.ReadAsStringAsync()).Trim();
|
||||
EqualJsContent(expected, actual);
|
||||
|
||||
actual = GetFileContent("BTCPayServer", "wwwroot", "vendor", "vue-sanitize-directive", "vue-sanitize-directive.umd.min.js").Trim();
|
||||
version = Regex.Match(actual, "Original file: /npm/vue-sanitize-directive@([0-9]+.[0-9]+.[0-9]+)").Groups[1].Value;
|
||||
expected = (await (await client.GetAsync($"https://cdn.jsdelivr.net/npm/vue-sanitize-directive@{version}/dist/vue-sanitize-directive.umd.min.js")).Content.ReadAsStringAsync()).Trim();
|
||||
EqualJsContent(expected, actual);
|
||||
|
||||
actual = GetFileContent("BTCPayServer", "wwwroot", "vendor", "decimal.js", "decimal.min.js").Trim();
|
||||
version = Regex.Match(actual, "Original file: /npm/decimal\\.js@([0-9]+.[0-9]+.[0-9]+)/decimal\\.js").Groups[1].Value;
|
||||
expected = (await (await client.GetAsync($"https://cdn.jsdelivr.net/npm/decimal.js@{version}/decimal.min.js")).Content.ReadAsStringAsync()).Trim();
|
||||
EqualJsContent(expected, actual);
|
||||
}
|
||||
|
||||
private void EqualJsContent(string expected, string actual)
|
||||
|
@ -15,6 +15,7 @@ using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Controllers;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Events;
|
||||
@ -23,6 +24,7 @@ using BTCPayServer.Fido2.Models;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Hosting;
|
||||
using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Lightning.Charge;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Models.AccountViewModels;
|
||||
using BTCPayServer.Models.AppViewModels;
|
||||
@ -45,6 +47,7 @@ using BTCPayServer.Services.Apps;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Labels;
|
||||
using BTCPayServer.Services.Mails;
|
||||
using BTCPayServer.Services.Notifications;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using BTCPayServer.Storage.Models;
|
||||
using BTCPayServer.Storage.Services.Providers.FileSystemStorage.Configuration;
|
||||
@ -56,6 +59,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
using NBitcoin.Payment;
|
||||
@ -68,6 +72,7 @@ using Newtonsoft.Json.Schema;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
using CreateInvoiceRequest = BTCPayServer.Client.Models.CreateInvoiceRequest;
|
||||
using RatesViewModel = BTCPayServer.Models.StoreViewModels.RatesViewModel;
|
||||
|
||||
namespace BTCPayServer.Tests
|
||||
@ -175,7 +180,7 @@ namespace BTCPayServer.Tests
|
||||
// If this test fail, run `UpdateSwagger` once.
|
||||
if (description != json["components"]["securitySchemes"]["API_Key"]["description"].Value<string>())
|
||||
{
|
||||
Assert.False(true, "Please run manually the test `UpdateSwagger` once");
|
||||
Assert.Fail("Please run manually the test `UpdateSwagger` once");
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,7 +274,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var details = ex is EqualException ? (ex as EqualException).Actual : ex.Message;
|
||||
var details = ex.Message;
|
||||
TestLogs.LogInformation($"FAILED: {url} ({file}) {details}");
|
||||
|
||||
throw;
|
||||
@ -386,11 +391,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);
|
||||
@ -475,7 +480,7 @@ namespace BTCPayServer.Tests
|
||||
await ProcessLightningPayment(LightningConnectionType.LndREST);
|
||||
}
|
||||
|
||||
async Task ProcessLightningPayment(LightningConnectionType type)
|
||||
async Task ProcessLightningPayment(string type)
|
||||
{
|
||||
// For easier debugging and testing
|
||||
// LightningLikePaymentHandler.LIGHTNING_TIMEOUT = int.MaxValue;
|
||||
@ -539,7 +544,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
var pairingCode = (string)token.RouteValues["pairingCode"];
|
||||
|
||||
acc.BitPay.AuthorizeClient(new PairingCode(pairingCode)).GetAwaiter().GetResult();
|
||||
await acc.BitPay.AuthorizeClient(new PairingCode(pairingCode));
|
||||
Assert.True(acc.BitPay.TestAccess(Facade.Merchant));
|
||||
}
|
||||
|
||||
@ -603,7 +608,7 @@ namespace BTCPayServer.Tests
|
||||
completed = true;
|
||||
break;
|
||||
default:
|
||||
Assert.False(true, $"{evtName} was not expected");
|
||||
Assert.Fail($"{evtName} was not expected");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1294,7 +1299,7 @@ namespace BTCPayServer.Tests
|
||||
using var tester = CreateServerTester();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
await user.GrantAccessAsync();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
|
||||
var rng = new Random();
|
||||
@ -1328,8 +1333,6 @@ namespace BTCPayServer.Tests
|
||||
var btcmethod = (await client.GetInvoicePaymentMethods(user.StoreId, invoice.Id))[0];
|
||||
var paid = btcSent;
|
||||
var invoiceAddress = BitcoinAddress.Create(btcmethod.Destination, cashCow.Network);
|
||||
|
||||
|
||||
var btc = new PaymentMethodId("BTC", PaymentTypes.BTCLike);
|
||||
var networkFee = (await tester.PayTester.InvoiceRepository.GetInvoice(invoice.Id))
|
||||
.GetPaymentMethods()[btc]
|
||||
@ -1341,9 +1344,7 @@ namespace BTCPayServer.Tests
|
||||
networkFee = 0.0m;
|
||||
}
|
||||
|
||||
cashCow.SendToAddress(invoiceAddress, paid);
|
||||
|
||||
|
||||
await cashCow.SendToAddressAsync(invoiceAddress, paid);
|
||||
await TestUtils.EventuallyAsync(async () =>
|
||||
{
|
||||
try
|
||||
@ -1363,7 +1364,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
catch (JsonSerializationException)
|
||||
{
|
||||
Assert.False(true, "The bitpay's amount is not set");
|
||||
Assert.Fail("The bitpay's amount is not set");
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1700,109 +1701,6 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Timeout = LongRunningTestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanExportInvoicesJson()
|
||||
{
|
||||
decimal GetFieldValue(string input, string fieldName)
|
||||
{
|
||||
var match = Regex.Match(input, $"\"{fieldName}\":([^,]*)");
|
||||
Assert.True(match.Success);
|
||||
return decimal.Parse(match.Groups[1].Value.Trim(), CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
async Task<object[]> GetExport(TestAccount account, string storeId = null)
|
||||
{
|
||||
var content = await account.GetController<UIInvoiceController>(false)
|
||||
.Export("json", storeId);
|
||||
var result = Assert.IsType<ContentResult>(content);
|
||||
Assert.Equal("application/json", result.ContentType);
|
||||
return JsonConvert.DeserializeObject<object[]>(result.Content ?? "[]");
|
||||
}
|
||||
|
||||
using var tester = CreateServerTester();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
await user.GrantAccessAsync();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
await user.SetNetworkFeeMode(NetworkFeeMode.Always);
|
||||
var invoice = await user.BitPay.CreateInvoiceAsync(
|
||||
new Invoice
|
||||
{
|
||||
Price = 10,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some \", description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
var networkFee = new FeeRate(invoice.MinerFees["BTC"].SatoshiPerBytes).GetFee(100);
|
||||
var result = await GetExport(user);
|
||||
Assert.Single(result);
|
||||
|
||||
var cashCow = tester.ExplorerNode;
|
||||
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network);
|
||||
var firstPayment = invoice.CryptoInfo[0].TotalDue - 3 * networkFee;
|
||||
cashCow.SendToAddress(invoiceAddress, firstPayment);
|
||||
Thread.Sleep(1000); // prevent race conditions, ordering payments
|
||||
// look if you can reduce thread sleep, this was min value for me
|
||||
|
||||
// should reduce invoice due by 0 USD because payment = network fee
|
||||
cashCow.SendToAddress(invoiceAddress, networkFee);
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// pay remaining amount
|
||||
cashCow.SendToAddress(invoiceAddress, 4 * networkFee);
|
||||
Thread.Sleep(1000);
|
||||
|
||||
await TestUtils.EventuallyAsync(async () =>
|
||||
{
|
||||
var parsedJson = await GetExport(user);
|
||||
Assert.Equal(3, parsedJson.Length);
|
||||
|
||||
var invoiceDueAfterFirstPayment = 3 * networkFee.ToDecimal(MoneyUnit.BTC) * invoice.Rate;
|
||||
var pay1str = parsedJson[0].ToString();
|
||||
Assert.Contains("\"InvoiceItemDesc\": \"Some \\\", description\"", pay1str);
|
||||
Assert.Equal(invoiceDueAfterFirstPayment, GetFieldValue(pay1str, "InvoiceDue"));
|
||||
Assert.Contains("\"InvoicePrice\": 10.0", pay1str);
|
||||
Assert.Contains("\"ConversionRate\": 5000.0", pay1str);
|
||||
Assert.Contains($"\"InvoiceId\": \"{invoice.Id}\",", pay1str);
|
||||
|
||||
var pay2str = parsedJson[1].ToString();
|
||||
Assert.Equal(invoiceDueAfterFirstPayment, GetFieldValue(pay2str, "InvoiceDue"));
|
||||
|
||||
var pay3str = parsedJson[2].ToString();
|
||||
Assert.Contains("\"InvoiceDue\": 0", pay3str);
|
||||
});
|
||||
|
||||
// create an invoice for a new store and check responses with and without store id
|
||||
var otherUser = tester.NewAccount();
|
||||
await otherUser.GrantAccessAsync();
|
||||
otherUser.RegisterDerivationScheme("BTC");
|
||||
await otherUser.SetNetworkFeeMode(NetworkFeeMode.Always);
|
||||
var newInvoice = await otherUser.BitPay.CreateInvoiceAsync(
|
||||
new Invoice
|
||||
{
|
||||
Price = 21,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some \", description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
await otherUser.PayInvoice(newInvoice.Id);
|
||||
Assert.Single(await GetExport(otherUser));
|
||||
Assert.Single(await GetExport(otherUser, otherUser.StoreId));
|
||||
Assert.Equal(3, (await GetExport(user, user.StoreId)).Length);
|
||||
Assert.Equal(3, (await GetExport(user)).Length);
|
||||
|
||||
await otherUser.AddOwner(user.UserId);
|
||||
Assert.Equal(4, (await GetExport(user)).Length);
|
||||
Assert.Single(await GetExport(user, otherUser.StoreId));
|
||||
}
|
||||
|
||||
[Fact(Timeout = LongRunningTestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanChangeNetworkFeeMode()
|
||||
@ -1892,45 +1790,6 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Timeout = LongRunningTestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanExportInvoicesCsv()
|
||||
{
|
||||
using var tester = CreateServerTester();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
await user.GrantAccessAsync();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
await user.SetNetworkFeeMode(NetworkFeeMode.Always);
|
||||
var invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice
|
||||
{
|
||||
Price = 500,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some \", description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
var cashCow = tester.ExplorerNode;
|
||||
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network);
|
||||
var firstPayment = invoice.CryptoInfo[0].TotalDue - Money.Coins(0.001m);
|
||||
cashCow.SendToAddress(invoiceAddress, firstPayment);
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
var exportResultPaid =
|
||||
user.GetController<UIInvoiceController>().Export("csv").GetAwaiter().GetResult();
|
||||
var paidresult = Assert.IsType<ContentResult>(exportResultPaid);
|
||||
Assert.Equal("application/csv", paidresult.ContentType);
|
||||
Assert.Contains($",orderId,{invoice.Id},", paidresult.Content);
|
||||
Assert.Contains($",On-Chain,BTC,0.0991,0.0001,5000.0", paidresult.Content);
|
||||
Assert.Contains($",USD,5.00", paidresult.Content); // Seems hacky but some plateform does not render this decimal the same
|
||||
Assert.Contains("0,,\"Some \"\", description\",New (paidPartial),new,paidPartial",
|
||||
paidresult.Content);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact(Timeout = LongRunningTestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanCreateAndDeleteApps()
|
||||
@ -2089,11 +1948,11 @@ namespace BTCPayServer.Tests
|
||||
using var tester = CreateServerTester();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
await user.GrantAccessAsync();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
await user.SetupWebhook();
|
||||
var invoice = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
var invoice = await user.BitPay.CreateInvoiceAsync(
|
||||
new Invoice
|
||||
{
|
||||
Price = 5000.0m,
|
||||
TaxIncluded = 1000.0m,
|
||||
@ -2125,7 +1984,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Single(textSearchResult);
|
||||
});
|
||||
|
||||
invoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
invoice = await user.BitPay.GetInvoiceAsync(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal(1000.0m, invoice.TaxIncluded);
|
||||
Assert.Equal(5000.0m, invoice.Price);
|
||||
Assert.Equal(Money.Coins(0), invoice.BtcPaid);
|
||||
@ -2140,11 +1999,8 @@ namespace BTCPayServer.Tests
|
||||
Assert.Empty(user.BitPay.GetInvoices(invoice.InvoiceTime.UtcDateTime - TimeSpan.FromDays(5),
|
||||
invoice.InvoiceTime.DateTime - TimeSpan.FromDays(1)));
|
||||
|
||||
|
||||
var firstPayment = Money.Coins(0.04m);
|
||||
|
||||
var txFee = Money.Zero;
|
||||
|
||||
var cashCow = tester.ExplorerNode;
|
||||
|
||||
var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network);
|
||||
@ -2172,7 +2028,7 @@ namespace BTCPayServer.Tests
|
||||
secondPayment = localInvoice.BtcDue;
|
||||
});
|
||||
|
||||
cashCow.SendToAddress(invoiceAddress, secondPayment);
|
||||
await cashCow.SendToAddressAsync(invoiceAddress, secondPayment);
|
||||
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
@ -2186,7 +2042,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.False((bool)((JValue)localInvoice.ExceptionStatus).Value);
|
||||
});
|
||||
|
||||
cashCow.Generate(1); //The user has medium speed settings, so 1 conf is enough to be confirmed
|
||||
await cashCow.GenerateAsync(1); //The user has medium speed settings, so 1 conf is enough to be confirmed
|
||||
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
@ -2194,7 +2050,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal("confirmed", localInvoice.Status);
|
||||
});
|
||||
|
||||
cashCow.Generate(5); //Now should be complete
|
||||
await cashCow.GenerateAsync(5); //Now should be complete
|
||||
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
@ -2203,7 +2059,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.NotEqual(0.0m, localInvoice.Rate);
|
||||
});
|
||||
|
||||
invoice = user.BitPay.CreateInvoice(new Invoice()
|
||||
invoice = await user.BitPay.CreateInvoiceAsync(new Invoice
|
||||
{
|
||||
Price = 5000.0m,
|
||||
Currency = "USD",
|
||||
@ -2216,7 +2072,7 @@ namespace BTCPayServer.Tests
|
||||
}, Facade.Merchant);
|
||||
invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network);
|
||||
|
||||
var txId = cashCow.SendToAddress(invoiceAddress, invoice.BtcDue + Money.Coins(1));
|
||||
var txId = await cashCow.SendToAddressAsync(invoiceAddress, invoice.BtcDue + Money.Coins(1));
|
||||
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
@ -2233,7 +2089,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Single(textSearchResult);
|
||||
});
|
||||
|
||||
cashCow.Generate(1);
|
||||
await cashCow.GenerateAsync(2);
|
||||
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
@ -2248,6 +2104,7 @@ namespace BTCPayServer.Tests
|
||||
c =>
|
||||
{
|
||||
Assert.False(c.ManuallyMarked);
|
||||
Assert.True(c.OverPaid);
|
||||
});
|
||||
user.AssertHasWebhookEvent<WebhookInvoiceProcessingEvent>(WebhookEventType.InvoiceProcessing,
|
||||
c =>
|
||||
@ -2398,13 +2255,17 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
|
||||
class MockVersionFetcher : IVersionFetcher
|
||||
class MockVersionFetcher : GithubVersionFetcher
|
||||
{
|
||||
public const string MOCK_NEW_VERSION = "9.9.9.9";
|
||||
public Task<string> Fetch(CancellationToken cancellation)
|
||||
public override Task<string> Fetch(CancellationToken cancellation)
|
||||
{
|
||||
return Task.FromResult(MOCK_NEW_VERSION);
|
||||
}
|
||||
|
||||
public MockVersionFetcher(IHttpClientFactory httpClientFactory, BTCPayServerOptions options, ILogger<GithubVersionFetcher> logger, SettingsRepository settingsRepository, BTCPayServerEnvironment environment, NotificationSender notificationSender) : base(httpClientFactory, options, logger, settingsRepository, environment, notificationSender)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Timeout = LongRunningTestTimeout)]
|
||||
@ -2423,8 +2284,13 @@ namespace BTCPayServer.Tests
|
||||
var mockEnv = tester.PayTester.GetService<BTCPayServerEnvironment>();
|
||||
var mockSender = tester.PayTester.GetService<Services.Notifications.NotificationSender>();
|
||||
|
||||
var svc = new NewVersionCheckerHostedService(settings, mockEnv, mockSender, new MockVersionFetcher(), BTCPayLogs);
|
||||
await svc.ProcessVersionCheck();
|
||||
var svc = new MockVersionFetcher(tester.PayTester.GetService<IHttpClientFactory>(),
|
||||
tester.PayTester.GetService<BTCPayServerOptions>(),
|
||||
tester.PayTester.GetService<ILogger<GithubVersionFetcher>>(),
|
||||
settings,
|
||||
mockEnv,
|
||||
mockSender);
|
||||
await svc.Do(CancellationToken.None);
|
||||
|
||||
// since last version present in database was null, it should've been updated with version mock returned
|
||||
var lastVersion = await settings.GetSettingAsync<NewVersionCheckerDataHolder>();
|
||||
@ -2532,9 +2398,14 @@ namespace BTCPayServer.Tests
|
||||
Assert.NotNull(lnMethod.GetExternalLightningUrl());
|
||||
|
||||
var url = lnMethod.GetExternalLightningUrl();
|
||||
Assert.Equal(LightningConnectionType.Charge, url.ConnectionType);
|
||||
Assert.Equal("pass", url.Password);
|
||||
Assert.Equal("usr", url.Username);
|
||||
var kv = LightningConnectionStringHelper.ExtractValues(url, out var connType);
|
||||
Assert.Equal(LightningConnectionType.Charge,connType);
|
||||
var client = Assert.IsType<ChargeClient>(tester.PayTester.GetService<LightningClientFactoryService>()
|
||||
.Create(url, tester.NetworkProvider.GetNetwork<BTCPayNetwork>("BTC")));
|
||||
var auth = Assert.IsType<ChargeAuthentication.UserPasswordAuthentication>(client.ChargeAuthentication);
|
||||
|
||||
Assert.Equal("pass", auth.NetworkCredential.Password);
|
||||
Assert.Equal("usr", auth.NetworkCredential.UserName);
|
||||
|
||||
// Test if lightning connection strings get migrated to internal
|
||||
store.DerivationStrategies = new JObject()
|
||||
@ -2859,7 +2730,7 @@ namespace BTCPayServer.Tests
|
||||
using var tester = CreateServerTester();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
await user.GrantAccessAsync();
|
||||
var controller = tester.PayTester.GetController<UIServerController>(user.UserId, user.StoreId);
|
||||
|
||||
var fileSystemStorageConfiguration = Assert.IsType<FileSystemStorageConfiguration>(Assert
|
||||
@ -2874,7 +2745,6 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(StorageProvider.FileSystem,
|
||||
shouldBeRedirectingToLocalStorageConfigPage.RouteValues["provider"]);
|
||||
|
||||
|
||||
await CanUploadRemoveFiles(controller);
|
||||
}
|
||||
|
||||
@ -2906,7 +2776,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
//create a temporary link to file
|
||||
var tmpLinkGenerate = Assert.IsType<RedirectToActionResult>(await controller.CreateTemporaryFileUrl(fileId,
|
||||
new UIServerController.CreateTemporaryFileUrlViewModel()
|
||||
new UIServerController.CreateTemporaryFileUrlViewModel
|
||||
{
|
||||
IsDownload = true,
|
||||
TimeAmount = 1,
|
||||
@ -2936,5 +2806,124 @@ namespace BTCPayServer.Tests
|
||||
Assert.IsType<ViewFilesViewModel>(Assert.IsType<ViewResult>(await controller.Files(new string[] { fileId })).Model);
|
||||
Assert.Null(viewFilesViewModel.DirectUrlByFiles);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Selenium", "Selenium")]
|
||||
public async Task CanCreateReports()
|
||||
{
|
||||
using var tester = CreateServerTester();
|
||||
tester.ActivateLightning();
|
||||
tester.DeleteStore = false;
|
||||
await tester.StartAsync();
|
||||
await tester.EnsureChannelsSetup();
|
||||
var acc = tester.NewAccount();
|
||||
await acc.GrantAccessAsync();
|
||||
await acc.MakeAdmin();
|
||||
acc.RegisterDerivationScheme("BTC", importKeysToNBX: true);
|
||||
acc.RegisterLightningNode("BTC");
|
||||
await acc.ReceiveUTXO(Money.Coins(1.0m));
|
||||
|
||||
var client = await acc.CreateClient();
|
||||
var posController = acc.GetController<UIPointOfSaleController>();
|
||||
|
||||
var app = await client.CreatePointOfSaleApp(acc.StoreId, new CreatePointOfSaleAppRequest()
|
||||
{
|
||||
AppName = "Static",
|
||||
DefaultView = Client.Models.PosViewType.Static,
|
||||
Template = new PointOfSaleSettings().Template
|
||||
});
|
||||
var resp = await posController.ViewPointOfSale(app.Id, choiceKey: "green-tea");
|
||||
var invoiceId = GetInvoiceId(resp);
|
||||
await acc.PayOnChain(invoiceId);
|
||||
|
||||
app = await client.CreatePointOfSaleApp(acc.StoreId, new CreatePointOfSaleAppRequest()
|
||||
{
|
||||
AppName = "Cart",
|
||||
DefaultView = Client.Models.PosViewType.Cart,
|
||||
Template = new PointOfSaleSettings().Template
|
||||
});
|
||||
resp = await posController.ViewPointOfSale(app.Id, posData: new JObject()
|
||||
{
|
||||
["cart"] = new JArray()
|
||||
{
|
||||
new JObject()
|
||||
{
|
||||
["id"] = "green-tea",
|
||||
["count"] = 2
|
||||
},
|
||||
new JObject()
|
||||
{
|
||||
["id"] = "black-tea",
|
||||
["count"] = 1
|
||||
},
|
||||
}
|
||||
}.ToString());
|
||||
invoiceId = GetInvoiceId(resp);
|
||||
await acc.PayOnBOLT11(invoiceId);
|
||||
|
||||
resp = await posController.ViewPointOfSale(app.Id, posData: new JObject()
|
||||
{
|
||||
["cart"] = new JArray()
|
||||
{
|
||||
new JObject()
|
||||
{
|
||||
["id"] = "green-tea",
|
||||
["count"] = 5
|
||||
}
|
||||
}
|
||||
}.ToString());
|
||||
invoiceId = GetInvoiceId(resp);
|
||||
await acc.PayOnLNUrl(invoiceId);
|
||||
|
||||
await acc.CreateLNAddress();
|
||||
await acc.PayOnLNAddress();
|
||||
|
||||
var report = await GetReport(acc, new() { ViewName = "Payments" });
|
||||
// 1 payment on LN Address
|
||||
// 1 payment on LNURL
|
||||
// 1 payment on BOLT11
|
||||
// 1 payment on chain
|
||||
Assert.Equal(4, report.Data.Count);
|
||||
var lnAddressIndex = report.GetIndex("LightningAddress");
|
||||
var paymentTypeIndex = report.GetIndex("PaymentType");
|
||||
Assert.Contains(report.Data, d => d[lnAddressIndex]?.Value<string>()?.Contains(acc.LNAddress) is true);
|
||||
var paymentTypes = report.Data
|
||||
.GroupBy(d => d[paymentTypeIndex].Value<string>())
|
||||
.ToDictionary(d => d.Key);
|
||||
Assert.Equal(3, paymentTypes["Lightning"].Count());
|
||||
Assert.Single(paymentTypes["On-Chain"]);
|
||||
|
||||
// 2 on-chain transactions: It received from the cashcow, then paid its own invoice
|
||||
report = await GetReport(acc, new() { ViewName = "Wallets" });
|
||||
var txIdIndex = report.GetIndex("TransactionId");
|
||||
var balanceIndex = report.GetIndex("BalanceChange");
|
||||
Assert.Equal(2, report.Data.Count);
|
||||
Assert.Equal(64, report.Data[0][txIdIndex].Value<string>().Length);
|
||||
Assert.Contains(report.Data, d => d[balanceIndex]["v"].Value<decimal>() == 1.0m);
|
||||
|
||||
// Items sold
|
||||
report = await GetReport(acc, new() { ViewName = "Sales" });
|
||||
var itemIndex = report.GetIndex("Product");
|
||||
var countIndex = report.GetIndex("Quantity");
|
||||
var itemsCount = report.Data.GroupBy(d => d[itemIndex].Value<string>())
|
||||
.ToDictionary(d => d.Key, r => r.Sum(d => d[countIndex].Value<int>()));
|
||||
Assert.Equal(8, itemsCount["green-tea"]);
|
||||
Assert.Equal(1, itemsCount["black-tea"]);
|
||||
}
|
||||
|
||||
private async Task<StoreReportResponse> GetReport(TestAccount acc, StoreReportRequest req)
|
||||
{
|
||||
var controller = acc.GetController<UIReportsController>();
|
||||
return (await controller.StoreReportsJson(acc.StoreId, req)).AssertType<JsonResult>()
|
||||
.Value
|
||||
.AssertType<StoreReportResponse>();
|
||||
}
|
||||
|
||||
private static string GetInvoiceId(IActionResult resp)
|
||||
{
|
||||
var redirect = resp.AssertType<RedirectToActionResult>();
|
||||
Assert.Equal("Checkout", redirect.ActionName);
|
||||
return (string)redirect.RouteValues["invoiceId"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,18 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Hosting;
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.Plugins.Bitcoin;
|
||||
using BTCPayServer.Plugins;
|
||||
using BTCPayServer.Tests.Logging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NBXplorer;
|
||||
using Xunit.Abstractions;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Configuration.Memory;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Tests
|
||||
{
|
||||
@ -15,7 +25,53 @@ namespace BTCPayServer.Tests
|
||||
TestLogs = new XUnitLog(helper) { Name = "Tests" };
|
||||
TestLogProvider = new XUnitLogProvider(helper);
|
||||
BTCPayLogs = new BTCPayServer.Logging.Logs();
|
||||
BTCPayLogs.Configure(new BTCPayServer.Logging.FuncLoggerFactory((n) => new XUnitLog(helper) { Name = n }));
|
||||
LoggerFactory = new BTCPayServer.Logging.FuncLoggerFactory((n) => new XUnitLog(helper) { Name = n });
|
||||
BTCPayLogs.Configure(LoggerFactory);
|
||||
}
|
||||
|
||||
public BTCPayNetworkProvider CreateNetworkProvider(ChainName chainName)
|
||||
{
|
||||
var conf = new ConfigurationRoot(new List<IConfigurationProvider>()
|
||||
{
|
||||
new MemoryConfigurationProvider(new MemoryConfigurationSource()
|
||||
{
|
||||
InitialData = new[] {
|
||||
new KeyValuePair<string, string>("chains", "*"),
|
||||
new KeyValuePair<string, string>("network", chainName.ToString())
|
||||
}
|
||||
})
|
||||
});
|
||||
return CreateNetworkProvider(conf);
|
||||
}
|
||||
public BTCPayNetworkProvider CreateNetworkProvider(IConfiguration conf = null)
|
||||
{
|
||||
conf ??= new ConfigurationRoot(new List<IConfigurationProvider>()
|
||||
{
|
||||
new MemoryConfigurationProvider(new MemoryConfigurationSource()
|
||||
{
|
||||
InitialData = new[] {
|
||||
new KeyValuePair<string, string>("chains", "*"),
|
||||
new KeyValuePair<string, string>("network", "regtest")
|
||||
}
|
||||
})
|
||||
});
|
||||
var bootstrap = Startup.CreateBootstrap(conf);
|
||||
var services = new PluginServiceCollection(new ServiceCollection(), bootstrap);
|
||||
var plugins = new List<BaseBTCPayServerPlugin>() { new BitcoinPlugin() };
|
||||
#if ALTCOINS
|
||||
plugins.Add(new BTCPayServer.Plugins.Altcoins.AltcoinsPlugin());
|
||||
#endif
|
||||
foreach (var p in plugins)
|
||||
{
|
||||
p.Execute(services);
|
||||
}
|
||||
services.AddSingleton(services.BootstrapServices.GetRequiredService<SelectedChains>());
|
||||
services.AddSingleton(services.BootstrapServices.GetRequiredService<NBXplorerNetworkProvider>());
|
||||
services.AddSingleton(services.BootstrapServices.GetRequiredService<Logs>());
|
||||
services.AddSingleton(services.BootstrapServices.GetRequiredService<IConfiguration>());
|
||||
services.AddSingleton<BTCPayNetworkProvider>();
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
return serviceProvider.GetService<BTCPayNetworkProvider>();
|
||||
}
|
||||
public ILog TestLogs
|
||||
{
|
||||
@ -26,14 +82,15 @@ namespace BTCPayServer.Tests
|
||||
get;
|
||||
}
|
||||
public BTCPayServer.Logging.Logs BTCPayLogs { get; }
|
||||
public FuncLoggerFactory LoggerFactory { get; }
|
||||
|
||||
public ServerTester CreateServerTester([CallerMemberNameAttribute] string scope = null, bool newDb = false)
|
||||
{
|
||||
return new ServerTester(scope, newDb, TestLogs, TestLogProvider);
|
||||
return new ServerTester(scope, newDb, TestLogs, TestLogProvider, CreateNetworkProvider());
|
||||
}
|
||||
public SeleniumTester CreateSeleniumTester([CallerMemberNameAttribute] string scope = null, bool newDb = false)
|
||||
{
|
||||
return new SeleniumTester() { Server = new ServerTester(scope, newDb, TestLogs, TestLogProvider) };
|
||||
return new SeleniumTester() { Server = new ServerTester(scope, newDb, TestLogs, TestLogProvider, CreateNetworkProvider()) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ declare -A xpubs
|
||||
|
||||
printf "\n👛 Create descriptor wallets\n\n"
|
||||
for ((n=1;n<=3;n++)); do
|
||||
# Create descriptor wallets, surpress error output in case wallet already exists
|
||||
# Create descriptor wallets, suppress error output in case wallet already exists
|
||||
./docker-bitcoin-cli.sh -named createwallet wallet_name="${prefix}_part_${n}" descriptors=true > /dev/null 2>&1
|
||||
|
||||
# Collect xpubs
|
||||
@ -38,7 +38,7 @@ multisig_int_desc="{\"desc\": $internal_desc_sum, \"active\": true, \"internal\"
|
||||
|
||||
multisig_desc="[$multisig_ext_desc, $multisig_int_desc]"
|
||||
|
||||
# Create multisig wallet, surpress error output in case wallet already exists
|
||||
# Create multisig wallet, suppress error output in case wallet already exists
|
||||
|
||||
printf "\n🔐 Create multisig wallet\n"
|
||||
printf "\nExternal descriptor: $external_desc\n"
|
||||
|
@ -24,7 +24,7 @@ services:
|
||||
TESTS_AzureBlobStorageConnectionString: ${TESTS_AzureBlobStorageConnectionString:-none}
|
||||
TEST_MERCHANTLIGHTNINGD: "type=clightning;server=unix://etc/merchant_lightningd_datadir/lightning-rpc"
|
||||
TEST_CUSTOMERLIGHTNINGD: "type=clightning;server=unix://etc/customer_lightningd_datadir/lightning-rpc"
|
||||
TEST_MERCHANTLND: "http://lnd:lnd@merchant_lnd:8080/"
|
||||
TEST_MERCHANTLND: "http://merchant_lnd:8080/"
|
||||
TESTS_INCONTAINER: "true"
|
||||
TESTS_SSHCONNECTION: "root@sshd:22"
|
||||
TESTS_SSHPASSWORD: ""
|
||||
@ -73,7 +73,7 @@ services:
|
||||
- "sshd_datadir:/root/.ssh"
|
||||
|
||||
devlnd:
|
||||
image: btcpayserver/bitcoin:25.0
|
||||
image: btcpayserver/bitcoin:25.1
|
||||
environment:
|
||||
BITCOIN_NETWORK: regtest
|
||||
BITCOIN_WALLETDIR: "/data/wallets"
|
||||
@ -99,7 +99,7 @@ services:
|
||||
custom:
|
||||
|
||||
nbxplorer:
|
||||
image: nicolasdorier/nbxplorer:2.3.63
|
||||
image: nicolasdorier/nbxplorer:2.4.0
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "32838:32838"
|
||||
@ -135,7 +135,7 @@ services:
|
||||
|
||||
bitcoind:
|
||||
restart: unless-stopped
|
||||
image: btcpayserver/bitcoin:25.0
|
||||
image: btcpayserver/bitcoin:25.1
|
||||
environment:
|
||||
BITCOIN_NETWORK: regtest
|
||||
BITCOIN_WALLETDIR: "/data/wallets"
|
||||
@ -163,7 +163,7 @@ services:
|
||||
- "bitcoin_datadir:/data"
|
||||
|
||||
customer_lightningd:
|
||||
image: btcpayserver/lightning:v23.05-dev
|
||||
image: btcpayserver/lightning:v23.08-dev
|
||||
stop_signal: SIGKILL
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
@ -190,7 +190,7 @@ services:
|
||||
- bitcoind
|
||||
|
||||
merchant_lightningd:
|
||||
image: btcpayserver/lightning:v23.05-dev
|
||||
image: btcpayserver/lightning:v23.08-dev
|
||||
stop_signal: SIGKILL
|
||||
environment:
|
||||
EXPOSE_TCP: "true"
|
||||
@ -224,7 +224,7 @@ services:
|
||||
- "5432"
|
||||
|
||||
merchant_lnd:
|
||||
image: btcpayserver/lnd:v0.16.4-beta
|
||||
image: btcpayserver/lnd:v0.17.2-beta
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
LND_CHAIN: "btc"
|
||||
@ -259,7 +259,7 @@ services:
|
||||
- bitcoind
|
||||
|
||||
customer_lnd:
|
||||
image: btcpayserver/lnd:v0.16.4-beta
|
||||
image: btcpayserver/lnd:v0.17.2-beta
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
LND_CHAIN: "btc"
|
||||
@ -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"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user