mirror of
https://github.com/aljazceru/BTCPayServerPlugins.git
synced 2025-12-17 07:34:24 +01:00
wip
This commit is contained in:
@@ -83,8 +83,8 @@ Global
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AD9635BB-C70E-4676-BB04-900D51B01666}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AD9635BB-C70E-4676-BB04-900D51B01666}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AD9635BB-C70E-4676-BB04-900D51B01666}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -99,48 +99,48 @@ Global
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6295533A-F941-40CA-B889-FE6C0432ED53}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{58863D86-3C78-4BEC-ACB6-2F82CC141210}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{58863D86-3C78-4BEC-ACB6-2F82CC141210}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{58863D86-3C78-4BEC-ACB6-2F82CC141210}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -155,8 +155,8 @@ Global
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5E1BAA06-7828-47BC-89D6-19C2A78EA427}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5E1BAA06-7828-47BC-89D6-19C2A78EA427}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5E1BAA06-7828-47BC-89D6-19C2A78EA427}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=0D438B7D_002DF996_002D4BF3_002D8F54_002D02CB9DF120D8_002Ff_003ABTCPayCoinjoinCoinSelector_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=0D438B7D_002DF996_002D4BF3_002D8F54_002D02CB9DF120D8_002Ff_003ABTCPayWallet_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABreezEvent_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F19b2ba64aa6844efb3312f86dbfe1b9652000_003F63_003F83f9cdbb_003FBreezEvent_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABreezSdkLiquidMethods_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4dbc7b5c57d04ec8a063235af9eb203a3fc00_003F7e_003F6a527844_003FBreezSdkLiquidMethods_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABreez_002ESdk_002ELiquid_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fmetadata_003F4dbc7b5c57d04ec8a063235af9eb203a3fc00_003F58_003F0584d9dc_003FBreez_002ESdk_002ELiquid_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACallSiteFactory_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Ff7e838f3c047ee76488fa4c2b9b1bffb2b33b04a2780de4664de937e024e97_003FCallSiteFactory_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADbSet_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F4b21fc3f8a3abb5d25f06c622276fbec0fd3932f169cc6af520bf5abc6a46b4_003FDbSet_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FLocal_003FSymbols_003Fsrc_003Fdotnet_003Fruntime_003F08338fcaa5c9b9a8190abb99222fed12aaba956c_003Fsrc_003Flibraries_003FSystem_002EPrivate_002ECoreLib_003Fsrc_003FSystem_003FRuntime_003FExceptionServices_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fbd1d5c50194fea68ff3559c160230b0ab50f5acf4ce3061bffd6d62958e2182_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANostrClientPool_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F758d2546736f41ac5ee3998f9abad1f58b82254824f2532c89ddf667ed74_003FNostrClientPool_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANostrEventTag_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Ff2e2e45db36b5d75d466cd5c6134e5ce566eface233da2ec472ac018f2eb16_003FNostrEventTag_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANullable_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2a3105e7355248488912e34f9ff5cbebca718_003F8b_003Fd6fc9706_003FNullable_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANullReferenceException_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fc092928882a17a51a62a367685d90a0a613eb91fb453b9f50147e19c1f3ff40_003FNullReferenceException_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APaymentDetails_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4dbc7b5c57d04ec8a063235af9eb203a3fc00_003Fc6_003Fb76207e1_003FPaymentDetails_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APayment_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4dbc7b5c57d04ec8a063235af9eb203a3fc00_003F5b_003F56fb0a4a_003FPayment_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AToCollection_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fbd47ee1ab214a7674f381fb716d273cc4bb64441375b47417e9dcd5ec96f89_003FToCollection_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWhere_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fevilk_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F767db1e17d404f86c3c73c54c6b20b5ff9ec43b79ef47681ae34b40a6852cf9_003FWhere_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=D1D1116C_002D38F9_002D4EA3_002DAC65_002DA75FEA82E5C8_002Fd_003ABlockchain_002Fd_003ATransactionOutputs_002Ff_003ACoinsView_002Ecs/@EntryIndexedValue">ExplicitlyExcluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=D1D1116C_002D38F9_002D4EA3_002DAC65_002DA75FEA82E5C8_002Fd_003ABlockchain_002Fd_003ATransactionOutputs_002Ff_003ASmartCoin_002Ecs/@EntryIndexedValue">ExplicitlyExcluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=D1D1116C_002D38F9_002D4EA3_002DAC65_002DA75FEA82E5C8_002Fd_003AWabiSabi_002Fd_003AClient_002Ff_003ACoinJoinClient_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
@@ -50,6 +64,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nostr/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -10,7 +10,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Bitcoin Whitepaper</Product>
|
||||
<Description>This makes the Bitcoin whitepaper available on your BTCPay Server.</Description>
|
||||
<Version>1.0.4</Version>
|
||||
<Version>1.0.5</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace BTCPayServer.Plugins.BitcoinWhitepaper
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=1.12.0" }
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=2.0.0" }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Blink</Product>
|
||||
<Description>Blink Lightning support</Description>
|
||||
<Version>1.0.8</Version>
|
||||
<Version>1.0.9</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<RootNamespace>BTCPayServer.Plugins.Blink</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace BTCPayServer.Plugins.Blink
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=1.12.0"}
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=2.0.0" }
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Breez / Greenlight</Product>
|
||||
<Description>Lightweight lightning baby!</Description>
|
||||
<Version>1.0.8</Version>
|
||||
<Version>1.0.9</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
@@ -34,7 +34,7 @@
|
||||
<ProjectReference Include="..\..\submodules\btcpayserver\BTCPayServer\BTCPayServer.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Breez.Sdk" Version="0.5.2" />
|
||||
<PackageReference Include="Breez.Sdk" Version="0.6.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Breez.Sdk;
|
||||
using BTCPayServer.Abstractions.Constants;
|
||||
@@ -12,13 +11,13 @@ using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
|
||||
namespace BTCPayServer.Plugins.Breez;
|
||||
|
||||
@@ -26,15 +25,19 @@ namespace BTCPayServer.Plugins.Breez;
|
||||
[Route("plugins/{storeId}/Breez")]
|
||||
public class BreezController : Controller
|
||||
{
|
||||
private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary;
|
||||
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
|
||||
private readonly BreezService _breezService;
|
||||
private readonly BTCPayWalletProvider _btcWalletProvider;
|
||||
private readonly StoreRepository _storeRepository;
|
||||
|
||||
public BreezController(BTCPayNetworkProvider btcPayNetworkProvider,
|
||||
public BreezController(
|
||||
PaymentMethodHandlerDictionary paymentMethodHandlerDictionary,
|
||||
BTCPayNetworkProvider btcPayNetworkProvider,
|
||||
BreezService breezService,
|
||||
BTCPayWalletProvider btcWalletProvider, StoreRepository storeRepository)
|
||||
{
|
||||
_paymentMethodHandlerDictionary = paymentMethodHandlerDictionary;
|
||||
_btcPayNetworkProvider = btcPayNetworkProvider;
|
||||
_breezService = breezService;
|
||||
_btcWalletProvider = btcWalletProvider;
|
||||
@@ -113,7 +116,7 @@ public class BreezController : Controller
|
||||
if (address.Equals("store", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
var store = ControllerContext.HttpContext.GetStoreData()
|
||||
.GetDerivationSchemeSettings(_btcPayNetworkProvider, "BTC");
|
||||
.GetDerivationSchemeSettings(_paymentMethodHandlerDictionary, "BTC");
|
||||
var res = await _btcWalletProvider.GetWallet(storeId)
|
||||
.ReserveAddressAsync(storeId, store.AccountDerivation, "Breez");
|
||||
address = res.Address.ToString();
|
||||
@@ -264,7 +267,7 @@ public class BreezController : Controller
|
||||
if (address.Equals("store", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
var store = ControllerContext.HttpContext.GetStoreData()
|
||||
.GetDerivationSchemeSettings(_btcPayNetworkProvider, "BTC");
|
||||
.GetDerivationSchemeSettings(_paymentMethodHandlerDictionary, "BTC");
|
||||
var res = await _btcWalletProvider.GetWallet(storeId)
|
||||
.ReserveAddressAsync(storeId, store.AccountDerivation, "Breez");
|
||||
address = res.Address.ToString();
|
||||
@@ -342,10 +345,8 @@ public class BreezController : Controller
|
||||
public async Task<IActionResult> Configure(string storeId, string command, BreezSettings settings)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
var existing = store.GetSupportedPaymentMethods(_btcPayNetworkProvider).OfType<LightningSupportedPaymentMethod>()
|
||||
.FirstOrDefault(method =>
|
||||
method.PaymentId.PaymentType == LightningPaymentType.Instance &&
|
||||
method.PaymentId.CryptoCode == "BTC");
|
||||
var pmi = PaymentTypes.LN.GetPaymentMethodId("BTC");
|
||||
var existing = store.GetPaymentMethodConfig<LightningPaymentMethodConfig>(pmi, _paymentMethodHandlerDictionary);
|
||||
|
||||
if (command == "clear")
|
||||
{
|
||||
@@ -355,7 +356,7 @@ public class BreezController : Controller
|
||||
var isStoreSetToThisMicro = existing?.GetExternalLightningUrl() == client?.ToString();
|
||||
if (client is not null && isStoreSetToThisMicro)
|
||||
{
|
||||
store.SetSupportedPaymentMethod(existing.PaymentId, null);
|
||||
store.SetPaymentMethodConfig(_paymentMethodHandlerDictionary[pmi], null);
|
||||
await _storeRepository.UpdateStore(store);
|
||||
}
|
||||
return RedirectToAction(nameof(Configure), new {storeId});
|
||||
@@ -422,18 +423,13 @@ public class BreezController : Controller
|
||||
|
||||
if(existing is null)
|
||||
{
|
||||
existing = new LightningSupportedPaymentMethod()
|
||||
{
|
||||
CryptoCode = "BTC"
|
||||
};
|
||||
|
||||
existing = new LightningPaymentMethodConfig();
|
||||
var client = _breezService.GetClient(storeId);
|
||||
existing.SetLightningUrl(client);
|
||||
store.SetSupportedPaymentMethod(existing);
|
||||
var lnurl = new LNURLPaySupportedPaymentMethod()
|
||||
{
|
||||
CryptoCode = "BTC",
|
||||
};
|
||||
store.SetSupportedPaymentMethod(lnurl);
|
||||
store.SetPaymentMethodConfig(_paymentMethodHandlerDictionary[pmi], existing);
|
||||
var lnurlPMI = PaymentTypes.LNURL.GetPaymentMethodId("BTC");
|
||||
store.SetPaymentMethodConfig(_paymentMethodHandlerDictionary[lnurlPMI], new LNURLPaymentMethodConfig());
|
||||
await _storeRepository.UpdateStore(store);
|
||||
}
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ public class BreezLightningClient : ILightningClient, IDisposable, EventListener
|
||||
OffchainBalance = new OffchainBalance()
|
||||
{
|
||||
Local = LightMoney.MilliSatoshis(ni.channelsBalanceMsat),
|
||||
Remote = LightMoney.MilliSatoshis(ni.inboundLiquidityMsats),
|
||||
Remote = LightMoney.MilliSatoshis(ni.totalInboundLiquidityMsats),
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -275,7 +275,7 @@ public class BreezLightningClient : ILightningClient, IDisposable, EventListener
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Sdk.SendPayment(new SendPaymentRequest(bolt11, (ulong?) payParams.Amount?.MilliSatoshi));
|
||||
result = Sdk.SendPayment(new SendPaymentRequest(bolt11,false, (ulong?) payParams.Amount?.MilliSatoshi));
|
||||
}
|
||||
|
||||
var details = result.payment.details as PaymentDetails.Ln;
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace BTCPayServer.Plugins.Breez
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=1.13.2" }
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=2.0.0" }
|
||||
};
|
||||
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
|
||||
@@ -11,7 +11,9 @@ using BTCPayServer.Events;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using NBitcoin;
|
||||
@@ -22,7 +24,8 @@ public class BreezService:EventHostedServiceBase
|
||||
{
|
||||
private readonly StoreRepository _storeRepository;
|
||||
private readonly IOptions<DataDirectories> _dataDirectories;
|
||||
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary => _serviceProvider.GetRequiredService<PaymentMethodHandlerDictionary>();
|
||||
private readonly ILogger _logger;
|
||||
private Dictionary<string, BreezSettings> _settings;
|
||||
private Dictionary<string, BreezLightningClient> _clients = new();
|
||||
@@ -31,12 +34,12 @@ public class BreezService:EventHostedServiceBase
|
||||
EventAggregator eventAggregator,
|
||||
StoreRepository storeRepository,
|
||||
IOptions<DataDirectories> dataDirectories,
|
||||
BTCPayNetworkProvider btcPayNetworkProvider,
|
||||
IServiceProvider serviceProvider,
|
||||
ILogger<BreezService> logger) : base(eventAggregator, logger)
|
||||
{
|
||||
_storeRepository = storeRepository;
|
||||
_dataDirectories = dataDirectories;
|
||||
_btcPayNetworkProvider = btcPayNetworkProvider;
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -133,13 +136,13 @@ public class BreezService:EventHostedServiceBase
|
||||
{
|
||||
_settings.Remove(storeId, out var oldSettings );
|
||||
var data = await _storeRepository.FindStore(storeId);
|
||||
var existing = data?.GetSupportedPaymentMethods(_btcPayNetworkProvider)
|
||||
.OfType<LightningSupportedPaymentMethod>().FirstOrDefault(method =>
|
||||
method.CryptoCode == "BTC" && method.PaymentId.PaymentType == LightningPaymentType.Instance);
|
||||
var pmi = PaymentTypes.LN.GetPaymentMethodId("BTC");
|
||||
var existing =
|
||||
data?.GetPaymentMethodConfig<LightningPaymentMethodConfig>(pmi, _paymentMethodHandlerDictionary);
|
||||
var isBreez = existing?.GetExternalLightningUrl() == $"type=breez;key={oldSettings.PaymentKey}";
|
||||
if (isBreez)
|
||||
{
|
||||
data.SetSupportedPaymentMethod(new PaymentMethodId("BTC", LightningPaymentType.Instance), null );
|
||||
data.SetPaymentMethodConfig(_paymentMethodHandlerDictionary[pmi], null );
|
||||
await _storeRepository.UpdateStore(data);
|
||||
}
|
||||
Directory.Delete(GetWorkDir(storeId), true);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
@using Breez.Sdk
|
||||
@using BTCPayServer
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Abstractions.Contracts
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Components.QRCode
|
||||
@using BTCPayServer.Components.TruncateCenter
|
||||
@@ -10,13 +8,15 @@
|
||||
@using BTCPayServer.Plugins.Breez
|
||||
@using BTCPayServer.Security
|
||||
@using BTCPayServer.Services
|
||||
@using BTCPayServer.Services.Invoices
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using NBitcoin
|
||||
@inject BreezService BreezService
|
||||
@inject BTCPayNetworkProvider BtcPayNetworkProvider
|
||||
@inject TransactionLinkProviders TransactionLinkProviders
|
||||
@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary
|
||||
@{
|
||||
ViewData.SetActivePage("Breez", "Swap In", "SwapIn");
|
||||
var pmi = PaymentTypes.CHAIN.GetPaymentMethodId("BTC");
|
||||
string storeId = Model switch
|
||||
{
|
||||
string s => s,
|
||||
@@ -38,10 +38,9 @@
|
||||
}
|
||||
|
||||
var refundables = sdk.ListRefundables();
|
||||
var deriv = Context.GetStoreData().GetDerivationSchemeSettings(BtcPayNetworkProvider, "BTC");
|
||||
var deriv = Context.GetStoreData().GetDerivationSchemeSettings(PaymentMethodHandlerDictionary, "BTC");
|
||||
var ni = sdk.NodeInfo();
|
||||
var f = sdk.RecommendedFees();
|
||||
var pmi = new PaymentMethodId("BTC", PaymentTypes.BTCLike);
|
||||
}
|
||||
|
||||
<datalist id="fees">
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
@using BTCPayServer
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Plugins.Breez
|
||||
@using BTCPayServer.Security
|
||||
@using BTCPayServer.Services.Invoices
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using Microsoft.AspNetCore.Routing
|
||||
@model string
|
||||
@inject BreezService BreezService
|
||||
@inject BTCPayNetworkProvider BtcPayNetworkProvider
|
||||
@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary
|
||||
@{
|
||||
var storeId = Context.GetImplicitStoreId();
|
||||
var address = Context.GetRouteValue("address").ToString();
|
||||
ViewData.SetActivePage("Breez", "Create Swapin Refund", "SwapIn");
|
||||
|
||||
var deriv = Context.GetStoreData().GetDerivationSchemeSettings(BtcPayNetworkProvider, "BTC");
|
||||
var deriv = Context.GetStoreData().GetDerivationSchemeSettings(PaymentMethodHandlerDictionary, "BTC");
|
||||
var sdk = BreezService.GetClient(storeId)?.Sdk;
|
||||
var f = sdk.RecommendedFees();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
@using Breez.Sdk
|
||||
@using BTCPayServer
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Models.StoreViewModels
|
||||
@using BTCPayServer.Plugins.Breez
|
||||
@using BTCPayServer.Security
|
||||
@using BTCPayServer.Services.Invoices
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@inject BreezService BreezService
|
||||
@inject BTCPayNetworkProvider BtcPayNetworkProvider
|
||||
@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary
|
||||
|
||||
|
||||
@{
|
||||
@@ -29,7 +30,7 @@
|
||||
if (sdk is null)
|
||||
return;
|
||||
var inProgressSwaps = sdk.InProgressReverseSwaps();
|
||||
var deriv = Context.GetStoreData().GetDerivationSchemeSettings(BtcPayNetworkProvider, "BTC");
|
||||
var deriv = Context.GetStoreData().GetDerivationSchemeSettings(PaymentMethodHandlerDictionary, "BTC");
|
||||
var f = sdk.RecommendedFees();
|
||||
var swapOutRec = sdk.FetchReverseSwapFees(new ReverseSwapFeesRequest());
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
@using BTCPayServer.Models.StoreViewModels
|
||||
@using BTCPayServer.Plugins.Breez
|
||||
@using BTCPayServer.Security
|
||||
@using BTCPayServer.Services.Invoices
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@inject BreezService BreezService
|
||||
@inject BTCPayNetworkProvider BtcPayNetworkProvider
|
||||
@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
ViewData.SetActivePage("Breez", "Sweep", "Sweep");
|
||||
@@ -24,7 +25,7 @@
|
||||
var sdk = BreezService.GetClient(storeId)?.Sdk;
|
||||
if (sdk is null)
|
||||
return;
|
||||
var deriv = Context.GetStoreData().GetDerivationSchemeSettings(BtcPayNetworkProvider, "BTC");
|
||||
var deriv = Context.GetStoreData().GetDerivationSchemeSettings(PaymentMethodHandlerDictionary, "BTC");
|
||||
var f = sdk.RecommendedFees();
|
||||
}
|
||||
<datalist id="fees">
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
ViewData["NavPartialName"] = "_Nav";
|
||||
}
|
||||
<style>
|
||||
#mainContent > section {
|
||||
padding: 3rem !important;
|
||||
}
|
||||
</style>
|
||||
@RenderBody()
|
||||
@@ -1,41 +0,0 @@
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Models.StoreViewModels
|
||||
@using BTCPayServer.Plugins.Breez
|
||||
@using BTCPayServer.Security
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
||||
@inject BreezService BreezService
|
||||
@{
|
||||
var storeId = Model switch
|
||||
{
|
||||
string s => s,
|
||||
StoreDashboardViewModel dashboardModel => dashboardModel.StoreId,
|
||||
_ => Context.GetImplicitStoreId()
|
||||
};
|
||||
var client = BreezService.GetClient(storeId);
|
||||
var sdk = client?.Sdk;
|
||||
}
|
||||
|
||||
<div class="sticky-header-setup"></div>
|
||||
<div class="sticky-header mb-l">
|
||||
<h2 class="mt-1 mb-2 mb-lg-4">Breez / Greenlight</h2>
|
||||
@if (sdk is not null)
|
||||
{
|
||||
<nav id="SectionNav">
|
||||
<div class="nav">
|
||||
|
||||
<a permission="@Policies.CanViewStoreSettings" asp-action="Info" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "Info")">Info</a>
|
||||
<a permission="@Policies.CanViewStoreSettings" asp-action="Payments" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "Payments")">Payments</a>
|
||||
<a permission="@Policies.CanCreateInvoice" asp-action="SwapIn" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "SwapIn")">Swap In</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" asp-action="SwapOut" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "SwapOut")">Swap Out</a>
|
||||
|
||||
<a permission="@Policies.CanModifyStoreSettings" asp-action="Configure" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "Configure")">Configuration</a>
|
||||
@if (client.Events.Any())
|
||||
{
|
||||
<a permission="@Policies.CanViewStoreSettings" asp-action="Logs" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "Logs")">Logs</a>
|
||||
}
|
||||
</div>
|
||||
</nav>
|
||||
}
|
||||
</div>
|
||||
@@ -1,27 +1,67 @@
|
||||
@using Breez.Sdk
|
||||
@using BTCPayServer.Abstractions.Contracts
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Models.StoreViewModels
|
||||
@using BTCPayServer.Plugins.Breez
|
||||
@using BTCPayServer.Security
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@inject IScopeProvider ScopeProvider
|
||||
@inject BreezService BreezService
|
||||
@{
|
||||
var storeId = ScopeProvider.GetCurrentStoreId();
|
||||
var storeId = Model switch
|
||||
{
|
||||
string s => s,
|
||||
StoreDashboardViewModel dashboardModel => dashboardModel.StoreId,
|
||||
_ => Context.GetImplicitStoreId()
|
||||
};
|
||||
var active = @ViewData.IsActivePage("Breez");
|
||||
var client = string.IsNullOrEmpty(active) ? null : BreezService.GetClient(storeId);
|
||||
var sdk = client?.Sdk;
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(storeId))
|
||||
{
|
||||
<li class="nav-item">
|
||||
<a permission="@Policies.CanViewStoreSettings" asp-controller="Breez" asp-action="Index" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez")" id="Nav-Breez">
|
||||
<a permission="@Policies.CanViewStoreSettings" asp-controller="Breez" asp-action="Index" asp-route-storeId="@storeId" class="nav-link @active" id="Nav-Breez">
|
||||
|
||||
<svg style="width: 15px; margin-left: 3px; margin-right: 7px;" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="favicon-64-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Group" transform="translate(3.000000, 2.000000)" fill-rule="nonzero">
|
||||
<path d="M35.4723926,39.8214286 C35.4723926,37.9541367 33.9340883,36.4285714 32.0236136,36.4285714 L10.3260796,36.4285714 C8.42801059,36.4285714 6.87730061,37.9419322 6.87730061,39.8214286 C6.87730061,41.6887205 8.41560491,43.2142857 10.3260796,43.2142857 L32.0236136,43.2142857 C33.9216827,43.2020812 35.4723926,41.6887205 35.4723926,39.8214286 Z" id="Shape" fill="currentColor"></path>
|
||||
<path d="M49.7395693,25.9068425 C51.3370507,23.7180544 52.2855553,21.0346249 52.2855553,18.1162407 C52.2855553,10.7460841 46.257559,4.77328937 38.819286,4.77328937 L36.9721981,4.77328937 L36.9721981,3.32646331 C36.9721981,1.48392415 35.462079,0 33.614991,0 C31.7554228,0 30.257784,1.49629019 30.257784,3.32646331 L30.257784,4.77328937 L26.8381753,4.77328937 L26.8381753,4.7856554 L24.6790793,4.7856554 C22.8819126,4.7856554 21.4341951,6.23248145 21.4341951,8.0008244 C21.4341951,9.78153339 22.894393,11.2159934 24.6790793,11.2159934 L26.8381753,11.2159934 L26.8381753,11.2283594 L38.7693647,11.2283594 C42.5009815,11.2283594 45.5212199,14.2209398 45.5212199,17.9183842 L45.5212199,17.9307502 C45.5212199,21.5292663 42.6507454,24.5342127 39.0439319,24.6084089 C38.3824747,24.6207749 36.3856229,24.6084089 36.3856229,24.6084089 C36.3731426,24.6084089 36.3481819,24.6084089 36.3357016,24.6084089 L36.310741,24.6084089 C34.3263695,24.657873 32.7413684,26.3520198 32.9535339,28.3800495 C33.1407387,30.1483924 34.7382202,31.4468261 36.5353868,31.4468261 L43.3496435,31.4468261 C44.0485417,31.4468261 44.7599201,31.4962902 45.4338576,31.6694147 C49.0905925,32.6215993 51.7988227,35.9109646 51.7988227,39.8433636 C51.7988227,44.5053586 47.9798437,48.2893652 43.2747616,48.2893652 L22.7071881,48.2893652 L18.8382878,48.2893652 C17.0161605,48.2893652 15.3937184,49.6125309 15.2189939,51.4056059 C15.0193087,53.4583677 16.6542311,55.1896125 18.6885239,55.1896125 L30.257784,55.1896125 L30.257784,56.6735367 C30.257784,58.5160758 31.7679031,60 33.614991,60 C35.4745593,60 36.9721981,58.5037098 36.9721981,56.6735367 L36.9721981,55.1896125 L39.8925939,55.1896125 C39.8925939,55.1896125 39.8925939,55.1896125 39.9050742,55.1896125 L43.5742894,55.1896125 C52.0983505,55.1896125 58.9999695,48.3388293 58.9999695,39.9051937 C59.0124498,33.6479802 55.1934708,28.2563891 49.7395693,25.9068425 Z" id="Shape" fill="currentColor"></path>
|
||||
<path d="M22.4417178,28.0357143 C22.4417178,26.1684224 20.8948734,24.6428571 18.9737925,24.6428571 L3.46792526,24.6428571 C1.55931891,24.6428571 0,26.1562179 0,28.0357143 C0,29.9030062 1.54684436,31.4285714 3.46792526,31.4285714 L18.9737925,31.4285714 C20.8948734,31.4285714 22.4417178,29.9030062 22.4417178,28.0357143 Z" id="Shape" fill="currentColor"></path>
|
||||
<path d="M15.7746737,21.4285714 L31.280541,21.4285714 C33.1891473,21.4285714 34.7484663,19.9152107 34.7484663,18.0357143 C34.7484663,16.1684224 33.2016219,14.6428571 31.280541,14.6428571 L15.7746737,14.6428571 C13.8660674,14.6428571 12.3067485,16.1562179 12.3067485,18.0357143 C12.3067485,19.9030062 13.8535928,21.4285714 15.7746737,21.4285714 Z" id="Shape" fill="currentColor"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<svg style="width: 15px; margin-left: 3px; margin-right: 7px;" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="favicon-64-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Group" transform="translate(3.000000, 2.000000)" fill-rule="nonzero">
|
||||
<path d="M35.4723926,39.8214286 C35.4723926,37.9541367 33.9340883,36.4285714 32.0236136,36.4285714 L10.3260796,36.4285714 C8.42801059,36.4285714 6.87730061,37.9419322 6.87730061,39.8214286 C6.87730061,41.6887205 8.41560491,43.2142857 10.3260796,43.2142857 L32.0236136,43.2142857 C33.9216827,43.2020812 35.4723926,41.6887205 35.4723926,39.8214286 Z" id="Shape" fill="currentColor"></path>
|
||||
<path d="M49.7395693,25.9068425 C51.3370507,23.7180544 52.2855553,21.0346249 52.2855553,18.1162407 C52.2855553,10.7460841 46.257559,4.77328937 38.819286,4.77328937 L36.9721981,4.77328937 L36.9721981,3.32646331 C36.9721981,1.48392415 35.462079,0 33.614991,0 C31.7554228,0 30.257784,1.49629019 30.257784,3.32646331 L30.257784,4.77328937 L26.8381753,4.77328937 L26.8381753,4.7856554 L24.6790793,4.7856554 C22.8819126,4.7856554 21.4341951,6.23248145 21.4341951,8.0008244 C21.4341951,9.78153339 22.894393,11.2159934 24.6790793,11.2159934 L26.8381753,11.2159934 L26.8381753,11.2283594 L38.7693647,11.2283594 C42.5009815,11.2283594 45.5212199,14.2209398 45.5212199,17.9183842 L45.5212199,17.9307502 C45.5212199,21.5292663 42.6507454,24.5342127 39.0439319,24.6084089 C38.3824747,24.6207749 36.3856229,24.6084089 36.3856229,24.6084089 C36.3731426,24.6084089 36.3481819,24.6084089 36.3357016,24.6084089 L36.310741,24.6084089 C34.3263695,24.657873 32.7413684,26.3520198 32.9535339,28.3800495 C33.1407387,30.1483924 34.7382202,31.4468261 36.5353868,31.4468261 L43.3496435,31.4468261 C44.0485417,31.4468261 44.7599201,31.4962902 45.4338576,31.6694147 C49.0905925,32.6215993 51.7988227,35.9109646 51.7988227,39.8433636 C51.7988227,44.5053586 47.9798437,48.2893652 43.2747616,48.2893652 L22.7071881,48.2893652 L18.8382878,48.2893652 C17.0161605,48.2893652 15.3937184,49.6125309 15.2189939,51.4056059 C15.0193087,53.4583677 16.6542311,55.1896125 18.6885239,55.1896125 L30.257784,55.1896125 L30.257784,56.6735367 C30.257784,58.5160758 31.7679031,60 33.614991,60 C35.4745593,60 36.9721981,58.5037098 36.9721981,56.6735367 L36.9721981,55.1896125 L39.8925939,55.1896125 C39.8925939,55.1896125 39.8925939,55.1896125 39.9050742,55.1896125 L43.5742894,55.1896125 C52.0983505,55.1896125 58.9999695,48.3388293 58.9999695,39.9051937 C59.0124498,33.6479802 55.1934708,28.2563891 49.7395693,25.9068425 Z" id="Shape" fill="currentColor"></path>
|
||||
<path d="M22.4417178,28.0357143 C22.4417178,26.1684224 20.8948734,24.6428571 18.9737925,24.6428571 L3.46792526,24.6428571 C1.55931891,24.6428571 0,26.1562179 0,28.0357143 C0,29.9030062 1.54684436,31.4285714 3.46792526,31.4285714 L18.9737925,31.4285714 C20.8948734,31.4285714 22.4417178,29.9030062 22.4417178,28.0357143 Z" id="Shape" fill="currentColor"></path>
|
||||
<path d="M15.7746737,21.4285714 L31.280541,21.4285714 C33.1891473,21.4285714 34.7484663,19.9152107 34.7484663,18.0357143 C34.7484663,16.1684224 33.2016219,14.6428571 31.280541,14.6428571 L15.7746737,14.6428571 C13.8660674,14.6428571 12.3067485,16.1562179 12.3067485,18.0357143 C12.3067485,19.9030062 13.8535928,21.4285714 15.7746737,21.4285714 Z" id="Shape" fill="currentColor"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<span>Breez</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@if (sdk is not null)
|
||||
{
|
||||
<li class="nav-item nav-item-sub">
|
||||
|
||||
<a permission="@Policies.CanViewStoreSettings" asp-action="Info" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "Info")">Info</a>
|
||||
</li>
|
||||
<li class="nav-item nav-item-sub">
|
||||
<a permission="@Policies.CanViewStoreSettings" asp-action="Payments" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "Payments")">Payments</a>
|
||||
</li>
|
||||
<li class="nav-item nav-item-sub">
|
||||
<a permission="@Policies.CanCreateInvoice" asp-action="SwapIn" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "SwapIn")">Swap In</a>
|
||||
</li>
|
||||
<li class="nav-item nav-item-sub">
|
||||
<a permission="@Policies.CanModifyStoreSettings" asp-action="SwapOut" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "SwapOut")">Swap Out</a>
|
||||
</li>
|
||||
<li class="nav-item nav-item-sub">
|
||||
|
||||
<a permission="@Policies.CanModifyStoreSettings" asp-action="Configure" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "Configure")">Configuration</a>
|
||||
</li>
|
||||
@if (client.Events.Any())
|
||||
{
|
||||
<li class="nav-item nav-item-sub">
|
||||
<a permission="@Policies.CanViewStoreSettings" asp-action="Logs" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("Breez", null, "Logs")">Logs</a>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,7 @@
|
||||
<span class="text-secondary fw-semibold currency">BTC receivable</span>
|
||||
</div>
|
||||
<div class="balance d-flex align-items-baseline gap-1">
|
||||
<h3 class="d-inline-block me-1" data-balance="@LightMoney.MilliSatoshis(nodeState.inboundLiquidityMsats).ToUnit(LightMoneyUnit.BTC)" data-sensitive>@LightMoney.MilliSatoshis(nodeState.inboundLiquidityMsats).ToUnit(LightMoneyUnit.BTC)</h3>
|
||||
<h3 class="d-inline-block me-1" data-balance="@LightMoney.MilliSatoshis(nodeState.totalInboundLiquidityMsats).ToUnit(LightMoneyUnit.BTC)" data-sensitive>@LightMoney.MilliSatoshis(nodeState.totalInboundLiquidityMsats).ToUnit(LightMoneyUnit.BTC)</h3>
|
||||
<span class="text-secondary fw-semibold currency">BTC inbound liquidity</span>
|
||||
</div>
|
||||
<div class="balance d-flex align-items-baseline gap-1">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Bringin</Product>
|
||||
<Description>Euro Offramp</Description>
|
||||
<Version>1.0.1</Version>
|
||||
<Version>1.0.2</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
@@ -41,6 +41,6 @@
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AsyncKeyedLock" Version="6.3.4" />
|
||||
<PackageReference Include="AsyncKeyedLock" Version="7.0.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -11,7 +11,10 @@ public class BringinPlugin : BaseBTCPayServerPlugin
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=1.12.0"}
|
||||
new()
|
||||
{
|
||||
Identifier = nameof(BTCPayServer), Condition = ">=2.0.0"
|
||||
}
|
||||
};
|
||||
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
|
||||
@@ -17,6 +17,7 @@ using BTCPayServer.Events;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payouts;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -139,13 +140,15 @@ public class BringinService : EventHostedServiceBase
|
||||
invoiceEvent when bringinStoreSettings.Enabled:
|
||||
|
||||
var pmPayments = invoiceEvent.Invoice.GetPayments("BTC", true)
|
||||
.GroupBy(payment => payment.GetPaymentMethodId());
|
||||
.GroupBy(payment => payment.PaymentMethodId);
|
||||
var update = false;
|
||||
foreach (var pmPayment in pmPayments)
|
||||
{
|
||||
var methodId = pmPayment.Key;
|
||||
if (methodId.PaymentType == PaymentTypes.LNURLPay)
|
||||
methodId = new PaymentMethodId(methodId.CryptoCode, PaymentTypes.LightningLike);
|
||||
if (methodId == PaymentTypes.LNURL.GetPaymentMethodId("BTC"))
|
||||
{
|
||||
methodId = PaymentTypes.LN.GetPaymentMethodId("BTC");
|
||||
}
|
||||
if (!bringinStoreSettings.MethodSettings.TryGetValue(methodId.ToString(),
|
||||
out var methodSettings))
|
||||
{
|
||||
@@ -153,7 +156,7 @@ public class BringinService : EventHostedServiceBase
|
||||
}
|
||||
|
||||
methodSettings.CurrentBalance +=
|
||||
pmPayment.Sum(payment => payment.GetCryptoPaymentData().GetValue());
|
||||
pmPayment.Sum(payment => payment.Value);
|
||||
update = true;
|
||||
}
|
||||
|
||||
@@ -190,14 +193,14 @@ public class BringinService : EventHostedServiceBase
|
||||
|
||||
foreach (var methodSetting in bringinStoreSetting.MethodSettings)
|
||||
{
|
||||
var pmi = PaymentMethodId.TryParse(methodSetting.Key);
|
||||
var pmi = PayoutMethodId.TryParse(methodSetting.Key);
|
||||
if (pmi is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var isOnChain = PayoutTypes.CHAIN.GetPayoutMethodId("BTC") == pmi;
|
||||
// if there is a pending payout, try and cancel it if this is onchain as we want to save needless tx fees
|
||||
if (methodSetting.Value.PendingPayouts.Count > 0 && pmi.PaymentType == BitcoinPaymentType.Instance)
|
||||
if (methodSetting.Value.PendingPayouts.Count > 0 && isOnChain)
|
||||
{
|
||||
var cancelResult = await _pullPaymentHostedService.Cancel(
|
||||
new PullPaymentHostedService.CancelRequest(methodSetting.Value.PendingPayouts.ToArray(),
|
||||
@@ -252,16 +255,16 @@ public class BringinService : EventHostedServiceBase
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<string?> CreateOrder(string storeId, PaymentMethodId paymentMethodId, Money amountBtc, bool payout)
|
||||
public async Task<string?> CreateOrder(string storeId, PayoutMethodId paymentMethodId, Money amountBtc, bool payout)
|
||||
{
|
||||
if (SupportedMethods.All(supportedMethod => supportedMethod.PaymentMethod != paymentMethodId))
|
||||
if (SupportedMethods.All(supportedMethod => supportedMethod.PayoutMethod != paymentMethodId))
|
||||
{
|
||||
throw new NotSupportedException($"{paymentMethodId.ToPrettyString()} Payment method not supported");
|
||||
throw new NotSupportedException($"{paymentMethodId} Payment method not supported");
|
||||
|
||||
}
|
||||
var settings = _settings[storeId];
|
||||
|
||||
var bringinClient = settings.CreateClient(_httpClientFactory, _btcPayNetworkProvider.GetNetwork<BTCPayNetwork>(paymentMethodId.CryptoCode).NBitcoinNetwork);
|
||||
var bringinClient = settings.CreateClient(_httpClientFactory, _btcPayNetworkProvider.GetNetwork<BTCPayNetwork>("BTC").NBitcoinNetwork);
|
||||
|
||||
|
||||
var host = await Dns.GetHostEntryAsync(Dns.GetHostName(), CancellationToken.None);
|
||||
@@ -270,7 +273,7 @@ public class BringinService : EventHostedServiceBase
|
||||
|
||||
|
||||
|
||||
var supportedMethod = SupportedMethods.First(supportedMethod => supportedMethod.PaymentMethod == paymentMethodId);
|
||||
var supportedMethod = SupportedMethods.First(supportedMethod => supportedMethod.PayoutMethod == paymentMethodId);
|
||||
//check if amount is enough
|
||||
if (supportedMethod.FiatMinimumAmount > 0)
|
||||
{
|
||||
@@ -297,13 +300,13 @@ public class BringinService : EventHostedServiceBase
|
||||
{
|
||||
return order.Invoice?? order.DepositAddress;
|
||||
}
|
||||
var network = _btcPayNetworkProvider.GetNetwork<BTCPayNetwork>(paymentMethodId.CryptoCode);
|
||||
var network = _btcPayNetworkProvider.GetNetwork<BTCPayNetwork>("BTC");
|
||||
|
||||
var destination = !string.IsNullOrEmpty(order.Invoice)? (IClaimDestination) new BoltInvoiceClaimDestination(order.Invoice, BOLT11PaymentRequest.Parse(order.Invoice, network.NBitcoinNetwork)):
|
||||
new AddressClaimDestination(BitcoinAddress.Create(order.DepositAddress, network.NBitcoinNetwork));
|
||||
var claim = await _pullPaymentHostedService.Claim(new ClaimRequest()
|
||||
{
|
||||
PaymentMethodId = paymentMethodId,
|
||||
PayoutMethodId = paymentMethodId,
|
||||
StoreId = storeId,
|
||||
Destination = destination,
|
||||
Value = orderMoney.ToUnit(MoneyUnit.BTC),
|
||||
@@ -363,17 +366,17 @@ public class BringinService : EventHostedServiceBase
|
||||
{
|
||||
case PayoutState.Completed:
|
||||
// remove from pending payouts list in a setting
|
||||
return _settings[payout.StoreDataId].MethodSettings[payout.GetPaymentMethodId().ToString()]
|
||||
return _settings[payout.StoreDataId].MethodSettings[payout.GetPayoutMethodId().ToString()]
|
||||
.PendingPayouts.Remove(payout.Id);
|
||||
case PayoutState.Cancelled:
|
||||
// remove from pending payouts list in a setting and add to a balance
|
||||
var result = _settings[payout.StoreDataId].MethodSettings[payout.GetPaymentMethodId().ToString()]
|
||||
var result = _settings[payout.StoreDataId].MethodSettings[payout.GetPayoutMethodId().ToString()]
|
||||
.PendingPayouts.Remove(payout.Id);
|
||||
var pmi = payout.GetPaymentMethodId();
|
||||
var pmi = payout.GetPayoutMethodId();
|
||||
if (_settings[payout.StoreDataId].MethodSettings
|
||||
.TryGetValue(pmi.ToString(), out var methodSettings))
|
||||
{
|
||||
methodSettings.CurrentBalance += payout.GetBlob(_btcPayNetworkJsonSerializerSettings).Amount;
|
||||
methodSettings.CurrentBalance += payout.Amount ?? payout.OriginalAmount;
|
||||
result = true;
|
||||
}
|
||||
|
||||
@@ -389,12 +392,12 @@ public class BringinService : EventHostedServiceBase
|
||||
return _settings.TryGetValue(storeId, out var bringinStoreSettings) ? bringinStoreSettings : null;
|
||||
}
|
||||
|
||||
public record SupportedMethodOptions(PaymentMethodId PaymentMethod, bool FiatMinimum, decimal FiatMinimumAmount, string bringinMethod);
|
||||
public record SupportedMethodOptions(PayoutMethodId PayoutMethod, bool FiatMinimum, decimal FiatMinimumAmount, string bringinMethod);
|
||||
|
||||
public static readonly SupportedMethodOptions[] SupportedMethods = new[]
|
||||
{
|
||||
new SupportedMethodOptions(new PaymentMethodId("BTC", LightningPaymentType.Instance), true, 22, "LIGHTNING"),
|
||||
new SupportedMethodOptions(new PaymentMethodId("BTC", BitcoinPaymentType.Instance), true, 22, "ON_CHAIN"),
|
||||
new SupportedMethodOptions(PayoutTypes.LN.GetPayoutMethodId("BTC"), true, 22, "LIGHTNING"),
|
||||
new SupportedMethodOptions(PayoutTypes.CHAIN.GetPayoutMethodId("BTC"), true, 22, "ON_CHAIN"),
|
||||
};
|
||||
|
||||
private ConcurrentDictionary<string, (IDisposable, BringinStoreSettings, DateTimeOffset Expiry)> _editModes = new();
|
||||
@@ -412,9 +415,9 @@ public class BringinService : EventHostedServiceBase
|
||||
// add or remove any missing methods in result
|
||||
foreach (var supportedMethod in SupportedMethods)
|
||||
{
|
||||
if (!result.MethodSettings.ContainsKey(supportedMethod.PaymentMethod.ToString()))
|
||||
if (!result.MethodSettings.ContainsKey(supportedMethod.PayoutMethod.ToString()))
|
||||
{
|
||||
result.MethodSettings.Add(supportedMethod.PaymentMethod.ToString(),
|
||||
result.MethodSettings.Add(supportedMethod.PayoutMethod.ToString(),
|
||||
new BringinStoreSettings.PaymentMethodSettings()
|
||||
{
|
||||
FiatThreshold = supportedMethod.FiatMinimum,
|
||||
@@ -424,7 +427,7 @@ public class BringinService : EventHostedServiceBase
|
||||
}
|
||||
|
||||
result.MethodSettings = result.MethodSettings.Where(pair =>
|
||||
SupportedMethods.Any(supportedMethod => supportedMethod.PaymentMethod.ToString() == pair.Key))
|
||||
SupportedMethods.Any(supportedMethod => supportedMethod.PayoutMethod.ToString() == pair.Key))
|
||||
.ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
isNew = true;
|
||||
return (storeLock, result, DateTimeOffset.Now.AddMinutes(5));
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
@using BTCPayServer.Data
|
||||
@using BTCPayServer.Payments
|
||||
@using BTCPayServer.PayoutProcessors
|
||||
@using BTCPayServer.Payouts
|
||||
@using BTCPayServer.Services
|
||||
@using BTCPayServer.Services.Invoices
|
||||
@using BTCPayServer.Services.Stores
|
||||
@using Microsoft.AspNetCore.Http
|
||||
@using Microsoft.AspNetCore.Routing
|
||||
@@ -25,6 +27,7 @@
|
||||
[Inject] private IHttpClientFactory HttpClientFactory { get; set; }
|
||||
[Inject] private PayoutProcessorService PayoutProcessorService { get; set; }
|
||||
[Inject] private IAuthorizationService AuthorizationService { get; set; }
|
||||
[Inject] private PayoutMethodHandlerDictionary PayoutMethodHandlerDictionary { get; set; }
|
||||
[Parameter] public string StoreId { get; set; }
|
||||
private decimal? LastFiatBalance { get; set; }
|
||||
private DateTimeOffset? LastDataFetch { get; set; }
|
||||
@@ -79,12 +82,13 @@
|
||||
PmiLink = $"A payout processor has not been configured for this payment method. Payouts generated by Bringin will not be automatically handled. <a href=\"{LinkGenerator.GetUriByAction(HttpContextAccessor.HttpContext, "ConfigureStorePayoutProcessors", "UIPayoutProcessors", new {StoreId})}\">Configure now</a>";
|
||||
_callbackLink = LinkGenerator.GetUriByAction(HttpContextAccessor.HttpContext, "Callback", "Bringin", new {StoreId});
|
||||
_settings = BringinService.IsInEditMode(StoreId) ? await BringinService.Update(StoreId) : await BringinService.Get(StoreId);
|
||||
_pms = (await StoreRepository.FindStore(StoreId)).GetSupportedPaymentMethods(BTCPayNetworkProvider).Select(method => method.PaymentId).Where(id => id.CryptoCode == "BTC").ToArray();
|
||||
var store = await StoreRepository.FindStore(StoreId);
|
||||
_pms = PayoutMethodHandlerDictionary.GetSupportedPayoutMethods(store);
|
||||
_pps = (await PayoutProcessorService.GetProcessors(new PayoutProcessorService.PayoutProcessorQuery()
|
||||
{
|
||||
Stores = new[] {StoreId},
|
||||
PaymentMethods = _pms.Select(p => p.ToString()).ToArray()
|
||||
})).Select(data => PaymentMethodId.TryParse(data.PaymentMethod)).Where(id => id is not null).ToArray();
|
||||
PayoutMethods = _pms.Select(p => p).ToArray()
|
||||
})).Select(data => PayoutMethodId.TryParse(data.PayoutMethodId)).Where(id => id is not null).ToArray();
|
||||
EditMode = BringinService.IsInEditMode(StoreId);
|
||||
IsLoaded = true;
|
||||
_ = FetchBalanceAndRate();
|
||||
@@ -148,8 +152,8 @@
|
||||
}
|
||||
|
||||
private bool _saving;
|
||||
private PaymentMethodId[] _pms;
|
||||
private PaymentMethodId[] _pps;
|
||||
private HashSet<PayoutMethodId> _pms;
|
||||
private PayoutMethodId[] _pps;
|
||||
private bool _apiKeyError;
|
||||
|
||||
private async Task Save()
|
||||
@@ -269,7 +273,7 @@
|
||||
_saving = true;
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
var pm = PaymentMethodId.TryParse(ManualOrderPaymentMethod);
|
||||
var pm = PayoutMethodId.TryParse(ManualOrderPaymentMethod);
|
||||
if (pm is null)
|
||||
{
|
||||
SaveError = "Invalid payment method";
|
||||
@@ -391,8 +395,8 @@
|
||||
}
|
||||
else if (_manualOrder)
|
||||
{
|
||||
var items = new List<PaymentMethodId>();
|
||||
items.AddRange(BringinService.SupportedMethods.Where(s => _pms.Contains(s.PaymentMethod)).Select(s => s.PaymentMethod));
|
||||
var items = new List<PayoutMethodId>();
|
||||
items.AddRange(BringinService.SupportedMethods.Where(s => _pms.Contains(s.PayoutMethod)).Select(s => s.PayoutMethod));
|
||||
|
||||
|
||||
<div class="row">
|
||||
@@ -422,7 +426,7 @@
|
||||
<option value="">Select a payment method</option>
|
||||
@foreach (var opt in items)
|
||||
{
|
||||
<option value="@opt.ToString()">@opt.ToPrettyString()</option>
|
||||
<option value="@opt.ToString()">@opt</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
@@ -472,7 +476,7 @@
|
||||
|
||||
@foreach (var method in _settings.MethodSettings)
|
||||
{
|
||||
var pmi = PaymentMethodId.TryParse(method.Key);
|
||||
var pmi = PayoutMethodId.TryParse(method.Key);
|
||||
if (pmi is null)
|
||||
continue;
|
||||
if (!_pms.Contains(pmi))
|
||||
@@ -480,7 +484,7 @@
|
||||
<hr class=""/>
|
||||
<div class="store-number">
|
||||
<header>
|
||||
<h6>@pmi.ToPrettyString()</h6>
|
||||
<h6>@pmi</h6>
|
||||
</header>
|
||||
|
||||
@if (LastFiatRate is null || !method.Value.FiatThreshold)
|
||||
@@ -504,7 +508,7 @@
|
||||
<span class="text-secondary"> (@DisplayFormatter.Currency(balanceInFiat.Value, "EUR", DisplayFormatter.CurrencyFormat.Code)) pending to forward once @DisplayFormatter.Currency(thresholdinBtc.Value, "BTC", DisplayFormatter.CurrencyFormat.Code) (@DisplayFormatter.Currency(method.Value.Threshold, "EUR")) is reached.</span>
|
||||
@if (method.Value.CurrentBalance > 0)
|
||||
{
|
||||
<button class="btn btn-link" @onclick="() => ResetBalance(pmi)" disabled="@_saving">Reset balance</button>
|
||||
<button class="btn btn-link" @onclick="() => ResetBalance(PaymentMethodId.Parse(pmi.ToString()))" disabled="@_saving">Reset balance</button>
|
||||
//Clear balance
|
||||
}
|
||||
</div>
|
||||
@@ -579,9 +583,9 @@
|
||||
var pmId = PaymentMethodId.TryParse(method.Key);
|
||||
if (pmId is null)
|
||||
continue;
|
||||
var supportedMethod = BringinService.SupportedMethods.FirstOrDefault(s => s.PaymentMethod.ToString() == method.Key);
|
||||
var supportedMethod = BringinService.SupportedMethods.FirstOrDefault(s => s.PayoutMethod.ToString() == method.Key);
|
||||
<div class="col-xxl-constrain col-12 @(_settings.MethodSettings.Count > 1 ? $"col-xl-6 {(i == 0 ? "border-end" : "")}" : "")">
|
||||
<h5 class=" border-bottom-0 text-muted mb-4">@pmId.ToPrettyString()</h5>
|
||||
<h5 class=" border-bottom-0 text-muted mb-4">@pmId</h5>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Percentage</label>
|
||||
@@ -644,15 +648,16 @@
|
||||
<tr>
|
||||
<td>@tx.CreatedAt.ToTimeAgo()</td>
|
||||
<td>@tx.SubType.ToHumanReadable()</td>
|
||||
<td>
|
||||
@tx.Status.ToHumanReadable()
|
||||
</td>
|
||||
<td>@tx.Status.ToHumanReadable()</td>
|
||||
<td class="amount-col">
|
||||
<span data-sensitive>@(tx.SourceCurrency == "BTC" ? Money.Satoshis(tx.SourceAmount).ToDecimal(MoneyUnit.BTC): tx.SourceAmount)@tx.SourceCurrency -> @tx.DestinationAmount @tx.DestinationCurrency </span>
|
||||
<span data-sensitive>
|
||||
@(tx.SourceCurrency == "BTC" ? Money.Satoshis(tx.SourceAmount).ToDecimal(MoneyUnit.BTC) : tx.SourceAmount) @tx.SourceCurrency
|
||||
-> @tx.DestinationAmount @tx.DestinationCurrency
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</tbody>s
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Data Erasure</Product>
|
||||
<Description>Allows you to erase user data from invoices after a period of time.</Description>
|
||||
<Version>1.0.2</Version>
|
||||
<Version>1.0.3</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace BTCPayServer.Plugins.DataErasure
|
||||
public class DataErasureController : Controller
|
||||
{
|
||||
private readonly DataErasureService _dataErasureService;
|
||||
|
||||
public DataErasureController(DataErasureService dataErasureService)
|
||||
{
|
||||
_dataErasureService = dataErasureService;
|
||||
@@ -31,7 +32,8 @@ namespace BTCPayServer.Plugins.DataErasure
|
||||
{
|
||||
if (_dataErasureService.IsRunning)
|
||||
{
|
||||
TempData["ErrorMessage"] = "Data erasure is currently running and cannot be changed. Please try again later.";
|
||||
TempData["ErrorMessage"] =
|
||||
"Data erasure is currently running and cannot be changed. Please try again later.";
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +48,11 @@ namespace BTCPayServer.Plugins.DataErasure
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case "cleardate":
|
||||
await _dataErasureService.Set(storeId, vm, true);
|
||||
|
||||
TempData["SuccessMessage"] = "Data erasure settings modified and date cleared";
|
||||
return RedirectToAction(nameof(Update), new {storeId});
|
||||
case "save":
|
||||
await _dataErasureService.Set(storeId, vm);
|
||||
TempData["SuccessMessage"] = "Data erasure settings modified";
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace BTCPayServer.Plugins.DataErasure
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=1.12.0" }
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=2.0.0" }
|
||||
};
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -14,13 +15,15 @@ namespace BTCPayServer.Plugins.DataErasure
|
||||
private readonly IStoreRepository _storeRepository;
|
||||
private readonly ILogger<DataErasureService> _logger;
|
||||
private readonly InvoiceRepository _invoiceRepository;
|
||||
private readonly ApplicationDbContextFactory _dbContextFactory;
|
||||
|
||||
public DataErasureService(IStoreRepository storeRepository, ILogger<DataErasureService> logger,
|
||||
InvoiceRepository invoiceRepository)
|
||||
InvoiceRepository invoiceRepository, ApplicationDbContextFactory dbContextFactory)
|
||||
{
|
||||
_storeRepository = storeRepository;
|
||||
_logger = logger;
|
||||
_invoiceRepository = invoiceRepository;
|
||||
_dbContextFactory = dbContextFactory;
|
||||
}
|
||||
|
||||
public async Task<DataErasureSettings> Get(string storeId)
|
||||
@@ -29,13 +32,16 @@ namespace BTCPayServer.Plugins.DataErasure
|
||||
nameof(DataErasureSettings));
|
||||
}
|
||||
|
||||
public async Task Set(string storeId, DataErasureSettings settings)
|
||||
public async Task Set(string storeId, DataErasureSettings settings, bool clearDate = false)
|
||||
{
|
||||
_cts?.Cancel();
|
||||
await _runningLock.WaitAsync();
|
||||
var existing = await Get(storeId);
|
||||
settings.LastRunCutoff = existing?.LastRunCutoff;
|
||||
settings.LastRunCutoff = clearDate? null: existing?.LastRunCutoff;
|
||||
await SetCore(storeId, settings);
|
||||
_runningLock.Release();
|
||||
_cts = new CancellationTokenSource();
|
||||
_ = Run();
|
||||
}
|
||||
|
||||
private async Task SetCore(string storeId, DataErasureSettings settings)
|
||||
@@ -46,11 +52,11 @@ namespace BTCPayServer.Plugins.DataErasure
|
||||
public bool IsRunning { get; private set; }
|
||||
private readonly SemaphoreSlim _runningLock = new(1, 1);
|
||||
|
||||
private async Task Run(CancellationToken cancellationToken)
|
||||
private async Task Run()
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
while (!_cts.IsCancellationRequested)
|
||||
{
|
||||
await _runningLock.WaitAsync(cancellationToken);
|
||||
await _runningLock.WaitAsync(_cts.Token);
|
||||
IsRunning = true;
|
||||
|
||||
|
||||
@@ -58,53 +64,69 @@ namespace BTCPayServer.Plugins.DataErasure
|
||||
await _storeRepository.GetSettingsAsync<DataErasureSettings>(nameof(DataErasureSettings));
|
||||
foreach (var setting in settings.Where(setting => setting.Value.Enabled))
|
||||
{
|
||||
var skip = 0;
|
||||
var count = 0;
|
||||
var cutoffDate = DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(setting.Value.DaysToKeep));
|
||||
while (true)
|
||||
if (setting.Value.EntirelyEraseInvoice)
|
||||
{
|
||||
var invoices = await _invoiceRepository.GetInvoices(new InvoiceQuery()
|
||||
{
|
||||
StartDate = setting.Value.LastRunCutoff,
|
||||
EndDate = cutoffDate,
|
||||
StoreId = new[] {setting.Key},
|
||||
Skip = skip,
|
||||
Take = 100
|
||||
});
|
||||
foreach (var invoice in invoices)
|
||||
{
|
||||
//replace all buyer info with "erased"
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerAddress1))
|
||||
invoice.Metadata.BuyerAddress1 = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerAddress2))
|
||||
invoice.Metadata.BuyerAddress2 = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerCity))
|
||||
invoice.Metadata.BuyerCity = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerCountry))
|
||||
invoice.Metadata.BuyerCountry = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerEmail))
|
||||
invoice.Metadata.BuyerEmail = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerName))
|
||||
invoice.Metadata.BuyerName = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerPhone))
|
||||
invoice.Metadata.BuyerPhone = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerState))
|
||||
invoice.Metadata.BuyerState = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerZip))
|
||||
invoice.Metadata.BuyerZip = "erased";
|
||||
await _invoiceRepository.UpdateInvoiceMetadata(invoice.Id, invoice.StoreId,
|
||||
invoice.Metadata.ToJObject());
|
||||
count++;
|
||||
}
|
||||
|
||||
if (invoices.Length < 100)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
skip += 100;
|
||||
await using var db = _dbContextFactory.CreateContext();
|
||||
db.Invoices.RemoveRange(db.Invoices.Where(i => i.StoreDataId == setting.Key && i.Created < cutoffDate && (setting.Value.LastRunCutoff == null || i.Created > setting.Value.LastRunCutoff)));
|
||||
count = await db.SaveChangesAsync(_cts.Token);
|
||||
}
|
||||
if(count > 0)
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
|
||||
var skip = 0;
|
||||
while (true)
|
||||
{
|
||||
var invoices = await _invoiceRepository.GetInvoices(new InvoiceQuery()
|
||||
{
|
||||
StartDate = setting.Value.LastRunCutoff,
|
||||
EndDate = cutoffDate,
|
||||
StoreId = new[] {setting.Key},
|
||||
Skip = skip,
|
||||
Take = 100
|
||||
}, _cts.Token);
|
||||
|
||||
|
||||
|
||||
foreach (var invoice in invoices)
|
||||
{
|
||||
//replace all buyer info with "erased"
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerAddress1))
|
||||
invoice.Metadata.BuyerAddress1 = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerAddress2))
|
||||
invoice.Metadata.BuyerAddress2 = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerCity))
|
||||
invoice.Metadata.BuyerCity = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerCountry))
|
||||
invoice.Metadata.BuyerCountry = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerEmail))
|
||||
invoice.Metadata.BuyerEmail = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerName))
|
||||
invoice.Metadata.BuyerName = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerPhone))
|
||||
invoice.Metadata.BuyerPhone = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerState))
|
||||
invoice.Metadata.BuyerState = "erased";
|
||||
if (!string.IsNullOrEmpty(invoice.Metadata.BuyerZip))
|
||||
invoice.Metadata.BuyerZip = "erased";
|
||||
await _invoiceRepository.UpdateInvoiceMetadata(invoice.Id, invoice.StoreId,
|
||||
invoice.Metadata.ToJObject());
|
||||
count++;
|
||||
}
|
||||
|
||||
if (invoices.Length < 100)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
skip += 100;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
_logger.LogInformation($"Erased {count} invoice data for store {setting.Key}");
|
||||
setting.Value.LastRunCutoff = cutoffDate;
|
||||
await SetCore(setting.Key, setting.Value);
|
||||
@@ -114,18 +136,30 @@ namespace BTCPayServer.Plugins.DataErasure
|
||||
|
||||
|
||||
_runningLock.Release();
|
||||
await Task.Delay(TimeSpan.FromDays(1), cancellationToken);
|
||||
await Task.Delay(TimeSpan.FromHours(1), _cts.Token);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_runningLock.Release();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private CancellationTokenSource _cts;
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_ = Run(cancellationToken);
|
||||
_cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
_ = Run();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_cts?.Cancel();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,5 +7,7 @@ namespace BTCPayServer.Plugins.DataErasure
|
||||
public bool Enabled { get; set; }
|
||||
public int DaysToKeep { get; set; }
|
||||
public DateTimeOffset? LastRunCutoff { get; set; }
|
||||
|
||||
public bool EntirelyEraseInvoice { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,9 +36,24 @@
|
||||
<input asp-for="DaysToKeep" type="number" class="form-control"/>
|
||||
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="d-flex align-items-center">
|
||||
<input asp-for="EntirelyEraseInvoice" type="checkbox" class="btcpay-toggle me-2"/>
|
||||
<label asp-for="EntirelyEraseInvoice" class="form-label mb-0 me-1">Remove entire invoice from records (instead of just buyer data)</label>
|
||||
|
||||
</div>
|
||||
<div class="alert alert-warning">
|
||||
<p>
|
||||
Deleting entire invoices may cause issues with integrations and accounting. Only use this option if you are sure you want to remove the invoice entirely.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@if (Model.LastRunCutoff != null)
|
||||
{
|
||||
<div>Cleared data up to @Model.LastRunCutoff.Value.ToString("g")</div>
|
||||
<div class="form-group">
|
||||
<button name="command" type="submit" value="cleardate" class="btn btn-danger">Start over</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Dynamic Rate Limit</Product>
|
||||
<Description>Allows you to override the default rate limiting.</Description>
|
||||
<Version>1.0.1</Version>
|
||||
<Version>1.0.2</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
|
||||
@@ -10,7 +10,7 @@ public class DynamicRateLimitsPlugin : BaseBTCPayServerPlugin
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=1.12.0" }
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=2.0.0" }
|
||||
};
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
{
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
@using BTCPayServer.Plugins.DynamicRateLimits
|
||||
@model DynamicRateLimitSettings
|
||||
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
ViewData["NavPartialName"] = "../UIServer/_Nav";
|
||||
}
|
||||
|
||||
<h2 class="mb-4">Rate limit configuration</h2>
|
||||
|
||||
<form method="post">
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Plugins.DynamicRateLimits
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@{
|
||||
var isActive = ViewContext.RouteData.Values.TryGetValue("Controller", out var controller) && controller is not null &&
|
||||
var isActive = ViewContext.RouteData.Values.TryGetValue("Controller", out var controller) && controller is not null &&
|
||||
nameof(DynamicRatesLimiterController).StartsWith(controller?.ToString(), StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
<a class="nav-link @(isActive ? "active" : string.Empty)" asp-action="Update" asp-controller="DynamicRatesLimiter">Rate Limits</a>
|
||||
|
||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
|
||||
|
||||
<a class="nav-link @(isActive ? "active" : string.Empty)" asp-action="Update" asp-controller="DynamicRatesLimiter">Rate Limits</a>
|
||||
</li>
|
||||
@@ -9,7 +9,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Dynamic Reports</Product>
|
||||
<Description>Allows you to create custom reports using SQL.</Description>
|
||||
<Version>1.0.1</Version>
|
||||
<Version>1.0.2</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
|
||||
@@ -10,7 +10,7 @@ public class DynamicReportsPlugin : BaseBTCPayServerPlugin
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=1.13.0" }
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=2.0.0" }
|
||||
};
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
{
|
||||
|
||||
@@ -21,19 +21,15 @@ public class PostgresReportProvider : ReportProvider
|
||||
public DynamicReportsSettings.DynamicReportSetting Setting { get; set; }
|
||||
|
||||
private readonly ApplicationDbContextFactory _dbContextFactory;
|
||||
private readonly IOptions<DatabaseOptions> _options;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
public PostgresReportProvider( ApplicationDbContextFactory dbContextFactory,
|
||||
IOptions<DatabaseOptions> options, IHttpContextAccessor httpContextAccessor)
|
||||
public PostgresReportProvider( ApplicationDbContextFactory dbContextFactory, IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_dbContextFactory = dbContextFactory;
|
||||
_options = options;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
public override bool IsAvailable()
|
||||
{
|
||||
return _options.Value.DatabaseType == DatabaseType.Postgres &&
|
||||
Setting.AllowForNonAdmins || _httpContextAccessor.HttpContext?.User.IsInRole(Roles.ServerAdmin) is true;
|
||||
return Setting.AllowForNonAdmins || _httpContextAccessor.HttpContext?.User.IsInRole(Roles.ServerAdmin) is true;
|
||||
}
|
||||
public override async Task Query(QueryContext queryContext, CancellationToken cancellation)
|
||||
{
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
@inject DynamicReportService DynamicReportService
|
||||
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
ViewData["NavPartialName"] = "../UIServer/_Nav";
|
||||
var storeId = ScopeProvider.GetCurrentStoreId();
|
||||
var reportName = Context.Request.Query["reportName"].ToString();
|
||||
reportName = string.IsNullOrEmpty(reportName) ? null : reportName;
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Plugins.DynamicReports
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
||||
@{
|
||||
var isActive = ViewContext.RouteData.Values.TryGetValue("Controller", out var controller) && controller is not null &&
|
||||
nameof(DynamicReportsController).StartsWith(controller?.ToString(), StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
<a class="nav-link @(isActive ? "active" : string.Empty)" asp-action="Update" asp-controller="DynamicReports">Dynamic Reports</a>
|
||||
|
||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
|
||||
|
||||
<a class="nav-link @(isActive ? "active" : string.Empty)" asp-action="Update" asp-controller="DynamicReports">Dynamic Reports</a>
|
||||
</li>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>File Seller</Product>
|
||||
<Description>Allows you to sell files through the point of sale/crowdfund apps.</Description>
|
||||
<Version>1.0.4</Version>
|
||||
<Version>1.0.5</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
|
||||
@@ -9,8 +9,9 @@ public class FileSellerPlugin : BaseBTCPayServerPlugin
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=1.12.0" }
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=2.0.0"}
|
||||
};
|
||||
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
{
|
||||
applicationBuilder.AddHostedService<FileSellerService>();
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
@inject UserService UserService
|
||||
@{
|
||||
var userId = UserManager.GetUserId(User);
|
||||
var user = await UserManager.GetUserAsync(User);
|
||||
var files = (await StoredFileRepository.GetFiles(new StoredFileRepository.FilesQuery()
|
||||
{
|
||||
UserIds = await UserService.IsAdminUser(userId) ? Array.Empty<string>() : new[] {userId},
|
||||
UserIds = await UserService.IsAdminUser(user) ? Array.Empty<string>() : new[] {user.Id},
|
||||
})).Select(file => new SelectListItem(file.FileName, file.Id)).Prepend(new SelectListItem("No file", ""));
|
||||
}
|
||||
<template v-if="editingItem">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Downloadable file</label>
|
||||
<select :value="editingItem['file'] || ''" asp-items="files" class="form-select w-auto" v-on:change=" if(event.target.value) editingItem['file']= event.target.value; else delete editingItem['file'];"></select>
|
||||
<select :value="editingItem['file'] || ''" asp-items="files" class="form-select w-auto" v-on:change="if(event.target.value) Vue.set(editingItem, 'file', event.target.value); else Vue.delete(editingItem, 'file');"></select>
|
||||
<span class="form-text">If a file is selected, when a user buys this item, a download link is generated in the payment receipt once the invoice is settled. <a target="_blank" asp-action="Files" asp-controller="UIServer">Upload files here</a></span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -9,7 +9,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>FixedFloat</Product>
|
||||
<Description>Allows you to embed a FixedFloat conversion screen to allow customers to pay with altcoins.</Description>
|
||||
<Version>1.1.7</Version>
|
||||
<Version>1.1.8</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
|
||||
@@ -9,29 +9,16 @@ namespace BTCPayServer.Plugins.FixedFloat
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=1.12.0" }
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=2.0.0" }
|
||||
|
||||
};
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
{
|
||||
applicationBuilder.AddSingleton<FixedFloatService>();
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/FixedFloatNav",
|
||||
"store-integrations-nav"));
|
||||
// Checkout v2
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutPaymentMethodExtension",
|
||||
"checkout-payment-method"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutPaymentExtension",
|
||||
"checkout-payment"));
|
||||
// Checkout Classic
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutContentExtension",
|
||||
"checkout-bitcoin-post-content"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutContentExtension",
|
||||
"checkout-lightning-post-content"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutTabExtension",
|
||||
"checkout-bitcoin-post-tabs"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutTabExtension",
|
||||
"checkout-lightning-post-tabs"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutEnd",
|
||||
"checkout-end"));
|
||||
applicationBuilder.AddUIExtension("store-integrations-nav", "FixedFloat/FixedFloatNav");
|
||||
applicationBuilder.AddUIExtension("checkout-payment-method", "FixedFloat/CheckoutPaymentMethodExtension");
|
||||
applicationBuilder.AddUIExtension("checkout-payment", "FixedFloat/CheckoutPaymentExtension");
|
||||
|
||||
base.Execute(applicationBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,47 +20,61 @@ namespace BTCPayServer.Plugins.FixedFloat
|
||||
{
|
||||
{"AAVEETH", "Aave (ERC20)"},
|
||||
{"ADA", "Cardano"},
|
||||
{"ADABSC", "Cardano (BEP20)"},
|
||||
{"APT", "Aptos"},
|
||||
{"ATOM", "Cosmos"},
|
||||
{"AVAX", "Avalanche (C-Chain)"},
|
||||
{"BAT", "Basic Attention (ERC20)"},
|
||||
{"BCH", "Bitcoin Cash"},
|
||||
{"BNB", "BNB Beacon Chain (BEP2)"},
|
||||
{"BSC", "BNB Smart Chain (BEP20)"},
|
||||
{"WBNBBSC", "Wrapped BNB (BEP20)"},
|
||||
{"BTC", "Bitcoin"},
|
||||
{"BTCBSC", "Bitcoin (BEP20)"},
|
||||
{"BTCLN", "Bitcoin (Lightning)"},
|
||||
{"BTT", "BitTorrent"},
|
||||
{"BUSD", "Binance USD (BEP2)"},
|
||||
{"BUSDBSC", "Binance USD (BEP20)"},
|
||||
{"BUSDETH", "Binance USD (ERC20)"},
|
||||
{"CAKE", "PancakeSwap (BEP20)"},
|
||||
{"DAIBSC", "DAI (BEP20)"},
|
||||
{"DAIETH", "DAI (ERC20)"},
|
||||
{"DAIMATIC", "DAI (Polygon)"},
|
||||
{"DASH", "Dash"},
|
||||
{"DOGE", "Dogecoin"},
|
||||
{"DOT", "Polkadot"},
|
||||
{"EOS", "EOS"},
|
||||
{"ETC", "Ethereum Classic"},
|
||||
{"ETH", "Ethereum"},
|
||||
{"ETHARBITRUM", "Ethereum (Arbitrum)"},
|
||||
{"ETHBASE", "Ethereum (Base)"},
|
||||
{"ETHZKSYNC", "Ethereum (ZkSync)"},
|
||||
{"WETHARBITRUM", "Wrapped ETH (Arbitrum)"},
|
||||
{"WETHETH", "Wrapped ETH (ERC20)"},
|
||||
{"FTM", "Fantom"},
|
||||
{"KCS", "KuCoin Token"},
|
||||
{"LINK", "Chainlink (ERC20)"},
|
||||
{"LTC", "Litecoin"},
|
||||
{"MANAETH", "Decentraland (ERC20)"},
|
||||
{"MATIC", "Polygon"},
|
||||
{"MATICETH", "Polygon (ERC20)"},
|
||||
{"MKR", "Maker (ERC20)"},
|
||||
{"PAXGETH", "PAX Gold (ERC20)"},
|
||||
{"POL", "Polygon"},
|
||||
{"POLETH", "Polygon (ERC20)"},
|
||||
{"SHIB", "SHIBA INU (ERC20)"},
|
||||
{"SHIBBSC", "SHIBA INU (BEP20)"},
|
||||
{"SOL", "Solana"},
|
||||
{"WSOL", "Wrapped SOL (Solana)"},
|
||||
{"TON", "Toncoin"},
|
||||
{"TRX", "Tron"},
|
||||
{"TUSD", "TrueUSD (ERC20)"},
|
||||
{"TWT", "Trust Wallet Token (BEP2)"},
|
||||
{"TWTBSC", "Trust Wallet Token (BEP20)"},
|
||||
{"USDCARBITRUM", "USD Coin (Arbitrum)"},
|
||||
{"USDCBSC", "USD Coin (BEP20)"},
|
||||
{"USDCETH", "USD Coin (ERC20)"},
|
||||
{"USDCMATIC", "USD Coin (Polygon)"},
|
||||
{"USDCSOL", "USD Coin (Solana)"},
|
||||
{"USDCTRC", "USD Coin (TRC20)"},
|
||||
{"USDP", "Pax Dollar (ERC20)"},
|
||||
{"USDT", "Tether (ERC20)"},
|
||||
{"USDTBSC", "Tether (BEP20)"},
|
||||
{"USDTMATIC", "Tether (Polygon)"},
|
||||
{"USDTSOL", "Tether (Solana)"},
|
||||
{"USDTTRC", "Tether (TRC20)"},
|
||||
{"VET", "VeChain"},
|
||||
{"XLM", "Stellar Lumens"},
|
||||
{"XMR", "Monero"},
|
||||
{"XRP", "Ripple"},
|
||||
{"XTZ", "Tezos"},
|
||||
@@ -68,8 +82,8 @@ namespace BTCPayServer.Plugins.FixedFloat
|
||||
{"ZRX", "0x (ERC20)"}
|
||||
};
|
||||
|
||||
public static List<SelectListItem> AllowedSendingOptionsList => AllowedSendingOptions.Select(o => new SelectListItem(o.Value, o.Key)).ToList();
|
||||
|
||||
|
||||
public static List<SelectListItem> AllowedSendingOptionsList =>
|
||||
AllowedSendingOptions.Select(o => new SelectListItem(o.Value, o.Key)).ToList();
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,17 @@
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Data
|
||||
@using BTCPayServer.Plugins.FixedFloat
|
||||
@using BTCPayServer.Services.Invoices
|
||||
@using BTCPayServer.Services.Stores
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@model BTCPayServer.Plugins.FixedFloat.FixedFloatSettings
|
||||
@inject BTCPayNetworkProvider BTCPayNetworkProvider
|
||||
@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary
|
||||
@{
|
||||
ViewData.SetActivePage("FixedFloat", "FixedFloat", "FixedFloat");
|
||||
var store = Context.GetStoreData();
|
||||
var allowedPaymentMethods = store.GetEnabledPaymentIds(BTCPayNetworkProvider)
|
||||
.Select(pmi => new SelectListItem(pmi.ToPrettyString(), pmi.ToString()))
|
||||
var allowedPaymentMethods = store.GetEnabledPaymentIds()
|
||||
.Select(pmi => new SelectListItem(pmi.ToString(), pmi.ToString()))
|
||||
.Prepend(new SelectListItem("Any", ""));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
@using BTCPayServer.Plugins.FixedFloat
|
||||
@model BTCPayServer.Models.InvoicingModels.PaymentModel
|
||||
@inject FixedFloatService FixedFloatService
|
||||
@{
|
||||
var storeId = Model.StoreId;
|
||||
var settings = await FixedFloatService.GetFixedFloatForStore(storeId);
|
||||
|
||||
if (settings?.Enabled is true)
|
||||
{
|
||||
<div id="FixedFloat" class="bp-view payment manual-flow" style="padding:0" :class="{ active: currentTab == 'undefined' || currentTab == 'FixedFloat' }">
|
||||
<fixed-float inline-template
|
||||
:to-currency="srvModel.paymentMethodId"
|
||||
:to-currency-due="srvModel.btcDue * (1 + (@settings.AmountMarkupPercentage / 100)) "
|
||||
:to-currency-address="srvModel.btcAddress">
|
||||
<iframe :src="url" style="min-height:600px;width:100%;border:none" allowtransparency="true"></iframe>
|
||||
</fixed-float>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
@using BTCPayServer.Plugins.FixedFloat
|
||||
@using Newtonsoft.Json
|
||||
@using Newtonsoft.Json.Linq
|
||||
@inject FixedFloatService FixedFloatService
|
||||
@{
|
||||
var storeId = ((JObject)JObject.Parse(JsonConvert.SerializeObject(Model)))["StoreId"].Value<string>();
|
||||
var settings = await FixedFloatService.GetFixedFloatForStore(storeId);
|
||||
if (settings?.Enabled is true)
|
||||
{
|
||||
<script src="~/Resources/js/fixedFloatComponent.js"></script>
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
@using BTCPayServer.Abstractions.TagHelpers
|
||||
@using BTCPayServer.Payments
|
||||
@using BTCPayServer.Plugins.FixedFloat
|
||||
@inject FixedFloatService FixedFloatService
|
||||
@model BTCPayServer.Models.InvoicingModels.PaymentModel
|
||||
@model BTCPayServer.Models.InvoicingModels.CheckoutModel
|
||||
@{
|
||||
var storeId = Model.StoreId;
|
||||
var settings = await FixedFloatService.GetFixedFloatForStore(storeId);
|
||||
var preferredTargetPaymentMethodId = string.IsNullOrEmpty(settings?.PreferredTargetPaymentMethodId) ? null : Model.AvailableCryptos.Any(crypto => crypto.PaymentMethodId == settings.PreferredTargetPaymentMethodId) ? settings.PreferredTargetPaymentMethodId : null;
|
||||
var preferredTargetPaymentMethodId =
|
||||
string.IsNullOrEmpty(settings?.PreferredTargetPaymentMethodId) ? null :
|
||||
Model.AvailablePaymentMethods.Any(crypto => crypto.PaymentMethodId.ToString() == PaymentMethodId.TryParse(settings.PreferredTargetPaymentMethodId)?.ToString()) ?
|
||||
settings.PreferredTargetPaymentMethodId : null;
|
||||
}
|
||||
@if (settings?.Enabled is true)
|
||||
{
|
||||
@@ -41,7 +46,7 @@
|
||||
const result = this.$parent.paymentMethodId === "FixedFloat";
|
||||
|
||||
if(this.preferredToCurrency && this.model.paymentMethodId !== this.preferredToCurrency){
|
||||
if (this.model.onChainWithLnInvoiceFallback && this.model.paymentMethodId === "BTC"){
|
||||
if (this.model.onChainWithLnInvoiceFallback && this.model.paymentMethodId === "BTC-CHAIN"){
|
||||
return result;
|
||||
}
|
||||
this.$parent.paymentMethodId = this.preferredToCurrency;
|
||||
@@ -53,7 +58,7 @@
|
||||
return result;
|
||||
},
|
||||
lightning () {
|
||||
if (!this.model.onChainWithLnInvoiceFallback || this.model.paymentMethodId !== "BTC"){
|
||||
if (!this.model.onChainWithLnInvoiceFallback || this.model.paymentMethodId !== "BTC-CHAIN"){
|
||||
return null;
|
||||
}
|
||||
const index = this.model.invoiceBitcoinUrl.indexOf("lightning=");
|
||||
@@ -63,9 +68,9 @@
|
||||
return this.model.invoiceBitcoinUrl.slice(index + "lightning=".length);
|
||||
},
|
||||
url () {
|
||||
|
||||
const address= this.lightning || this.model.btcAddress;
|
||||
return "https://widget.fixedfloat.com/?" +
|
||||
debugger;
|
||||
const address= this.lightning || this.model.address;
|
||||
return "https://widget.ff.io/?" +
|
||||
`to=${this.settleMethodId}` +
|
||||
"&lockReceive=true&ref=fkbyt39c" +
|
||||
`&address=${address}` +
|
||||
@@ -76,9 +81,9 @@
|
||||
return this.model.paymentMethodId;
|
||||
},
|
||||
settleMethodId () {
|
||||
return this.currency.endsWith('LightningLike') || this.currency.endsWith('LNURLPay') || this.lightning
|
||||
return this.currency.endsWith('LN') || this.currency.endsWith('LNURL') || this.lightning
|
||||
? 'BTCLN'
|
||||
: this.currency.replace('_BTCLike', '').replace('_MoneroLike', '').replace('_ZcashLike', '').toUpperCase();
|
||||
: this.currency.replace('-CHAIN', '').replace('_CHAIN', '').toUpperCase();
|
||||
},
|
||||
explicitQuery (){
|
||||
const isExplicit = !!this.explicitId;
|
||||
@@ -91,7 +96,7 @@
|
||||
: `&lockType=true&hideType=true&lockAmount=true&toAmount=${this.amountDue}`;
|
||||
},
|
||||
amountDue () {
|
||||
return this.model.btcDue * (1 + (markupPercentage / 100));
|
||||
return this.model.due * (1 + (markupPercentage / 100));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@using BTCPayServer.Plugins.FixedFloat
|
||||
@model BTCPayServer.Models.InvoicingModels.PaymentModel
|
||||
@model BTCPayServer.Models.InvoicingModels.CheckoutModel
|
||||
@inject FixedFloatService FixedFloatService
|
||||
@{
|
||||
const string id = "FixedFloat";
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
@using BTCPayServer.Plugins.FixedFloat
|
||||
@model BTCPayServer.Models.InvoicingModels.PaymentModel
|
||||
@inject FixedFloatService FixedFloatService
|
||||
@{
|
||||
var storeId = Model.StoreId;
|
||||
var settings = await FixedFloatService.GetFixedFloatForStore(storeId);
|
||||
if (settings?.Enabled is true)
|
||||
{
|
||||
<div class="payment-tabs__tab py-0" id="FixedFloat-tab" v-on:click="switchTab('FixedFloat')" v-bind:class="{ 'active': currentTab == 'FixedFloat'}">
|
||||
<span>{{$t("Altcoins (FixedFloat)")}}</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>10</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Plugin specific properties -->
|
||||
<PropertyGroup>
|
||||
<Product>LDK</Product>
|
||||
<Description>The way lightning's meant to be</Description>
|
||||
<Version>1.0.0</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
<PropertyGroup>
|
||||
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
|
||||
<PreserveCompilationContext>false</PreserveCompilationContext>
|
||||
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- This will make sure that referencing BTCPayServer doesn't put any artifact in the published directory -->
|
||||
<ItemDefinitionGroup>
|
||||
<ProjectReference>
|
||||
<Properties>StaticWebAssetsEnabled=false</Properties>
|
||||
<Private>false</Private>
|
||||
<ExcludeAssets>runtime;native;build;buildTransitive;contentFiles</ExcludeAssets>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\**" />
|
||||
<ProjectReference Include="..\..\submodules\btcpayserver\BTCPayServer\BTCPayServer.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="org.ldk" Version="0.0.118-alpha1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,232 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Amazon.Runtime.Internal.Util;
|
||||
using BTCPayServer;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Services;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
using org.ldk.enums;
|
||||
using org.ldk.structs;
|
||||
using enums_Network = org.ldk.enums.Network;
|
||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
using Logger = org.ldk.structs.Logger;
|
||||
using Network = NBitcoin.Network;
|
||||
using OutPoint = org.ldk.structs.OutPoint;
|
||||
using Path = System.IO.Path;
|
||||
|
||||
public class LDKService : IHostedService, PersistInterface, BroadcasterInterfaceInterface, FeeEstimatorInterface, EventHandlerInterface, LoggerInterface, FilterInterface
|
||||
{
|
||||
private readonly ILogger<LDKService> _logger;
|
||||
private readonly IFeeProviderFactory _feeProviderFactory;
|
||||
private readonly IOptions<DataDirectories> _dataDirectories;
|
||||
private readonly BTCPayNetwork _network;
|
||||
private readonly ExplorerClient _explorerClient;
|
||||
private readonly string _workDir;
|
||||
private readonly enums_Network _ldkNetwork;
|
||||
private readonly Logger _ldklogger;
|
||||
private readonly FeeEstimator _ldkfeeEstimator;
|
||||
private readonly BroadcasterInterface _ldkbroadcaster;
|
||||
private readonly Persist _ldkpersist;
|
||||
private readonly Filter _ldkfilter;
|
||||
private readonly NetworkGraph _ldkNetworkGraph;
|
||||
private readonly ChainMonitor _ldkChainMonitor;
|
||||
|
||||
public LDKService(BTCPayNetworkProvider btcPayNetworkProvider,
|
||||
ExplorerClientProvider explorerClientProvider,
|
||||
ILogger<LDKService> logger,
|
||||
IFeeProviderFactory feeProviderFactory,
|
||||
IOptions<DataDirectories> dataDirectories)
|
||||
{
|
||||
_logger = logger;
|
||||
_feeProviderFactory = feeProviderFactory;
|
||||
_dataDirectories = dataDirectories;
|
||||
|
||||
_network = btcPayNetworkProvider.GetNetwork<BTCPayNetwork>("BTC");
|
||||
_explorerClient = explorerClientProvider.GetExplorerClient(_network);
|
||||
_workDir = GetWorkDir();
|
||||
Directory.CreateDirectory(_workDir);
|
||||
|
||||
_ldkNetwork = GetLdkNetwork(_network.NBitcoinNetwork);
|
||||
_ldklogger = Logger.new_impl(this);
|
||||
_ldkfeeEstimator = FeeEstimator.new_impl(this);
|
||||
_ldkbroadcaster = BroadcasterInterface.new_impl(this);
|
||||
_ldkpersist = Persist.new_impl(this);
|
||||
_ldkfilter = Filter.new_impl(this);
|
||||
|
||||
_ldkNetworkGraph = NetworkGraph.of(_ldkNetwork, _ldklogger);
|
||||
_ldkChainMonitor = ChainMonitor.of( Option_FilterZ.Option_FilterZ_Some.some(_ldkfilter), _ldkbroadcaster, _ldklogger, _ldkfeeEstimator, _ldkpersist);
|
||||
}
|
||||
|
||||
|
||||
private static enums_Network GetLdkNetwork(Network network)
|
||||
{
|
||||
enums_Network? ldkNetwork = null;
|
||||
if (network.ChainName == ChainName.Mainnet)
|
||||
ldkNetwork = org.ldk.enums.Network.LDKNetwork_Bitcoin;
|
||||
else if (network.ChainName == ChainName.Testnet)
|
||||
ldkNetwork = org.ldk.enums.Network.LDKNetwork_Testnet;
|
||||
else if (network.ChainName == ChainName.Regtest)
|
||||
ldkNetwork = org.ldk.enums.Network.LDKNetwork_Regtest;
|
||||
|
||||
return ldkNetwork ?? throw new NotSupportedException();
|
||||
}
|
||||
|
||||
|
||||
private string GetWorkDir()
|
||||
{
|
||||
var dir = _dataDirectories.Value.DataDir;
|
||||
return Path.Combine(dir, "Plugins", "LDK");
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int get_est_sat_per_1000_weight(ConfirmationTarget confirmation_target)
|
||||
{
|
||||
var feeProvider = _feeProviderFactory.CreateFeeProvider(_network);
|
||||
var targetBlocks = confirmation_target switch
|
||||
{
|
||||
ConfirmationTarget.LDKConfirmationTarget_OnChainSweep => 30, // High priority (10-50 blocks)
|
||||
ConfirmationTarget
|
||||
.LDKConfirmationTarget_MaxAllowedNonAnchorChannelRemoteFee =>
|
||||
20, // Moderate to high priority (small multiple of high-priority estimate)
|
||||
ConfirmationTarget
|
||||
.LDKConfirmationTarget_MinAllowedAnchorChannelRemoteFee =>
|
||||
12, // Moderate priority (long-term mempool minimum or medium-priority)
|
||||
ConfirmationTarget
|
||||
.LDKConfirmationTarget_MinAllowedNonAnchorChannelRemoteFee =>
|
||||
12, // Moderate priority (medium-priority feerate)
|
||||
ConfirmationTarget.LDKConfirmationTarget_AnchorChannelFee => 6, // Lower priority (can be bumped later)
|
||||
ConfirmationTarget
|
||||
.LDKConfirmationTarget_NonAnchorChannelFee => 20, // Moderate to high priority (high-priority feerate)
|
||||
ConfirmationTarget.LDKConfirmationTarget_ChannelCloseMinimum => 144, // Within a day or so (144-250 blocks)
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(confirmation_target), confirmation_target, null)
|
||||
};
|
||||
return (int) Math.Max(253, feeProvider.GetFeeRateAsync(targetBlocks).GetAwaiter().GetResult().FeePerK.Satoshi);
|
||||
}
|
||||
|
||||
public void log(Record record)
|
||||
{
|
||||
var level = record.get_level() switch
|
||||
{
|
||||
Level.LDKLevel_Trace => LogLevel.Trace,
|
||||
Level.LDKLevel_Debug => LogLevel.Debug,
|
||||
Level.LDKLevel_Info => LogLevel.Information,
|
||||
Level.LDKLevel_Warn => LogLevel.Warning,
|
||||
Level.LDKLevel_Error => LogLevel.Error,
|
||||
Level.LDKLevel_Gossip => LogLevel.Trace,
|
||||
};
|
||||
_logger.Log(level, $"[{record.get_module_path()}] {record.get_args()}");
|
||||
}
|
||||
|
||||
public void broadcast_transactions(byte[][] txs)
|
||||
{
|
||||
foreach (var tx in txs)
|
||||
{
|
||||
var loadedTx = Transaction.Load(tx, _explorerClient.Network.NBitcoinNetwork);
|
||||
|
||||
_explorerClient.Broadcast(loadedTx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ChannelMonitorUpdateStatus persist_new_channel(OutPoint channel_id, ChannelMonitor data,
|
||||
MonitorUpdateId update_id)
|
||||
{
|
||||
var name = Convert.ToHexString(channel_id.write());
|
||||
File.WriteAllBytes(Path.Combine(_workDir, name), data.write());
|
||||
return ChannelMonitorUpdateStatus.LDKChannelMonitorUpdateStatus_Completed;
|
||||
}
|
||||
|
||||
public ChannelMonitorUpdateStatus update_persisted_channel(OutPoint channel_id, ChannelMonitorUpdate update,
|
||||
ChannelMonitor data, MonitorUpdateId update_id)
|
||||
{
|
||||
var name = Convert.ToHexString(channel_id.write());
|
||||
File.WriteAllBytes(Path.Combine(_workDir, name), data.write());
|
||||
return ChannelMonitorUpdateStatus.LDKChannelMonitorUpdateStatus_Completed;
|
||||
}
|
||||
|
||||
public void handle_event(Event _event)
|
||||
{
|
||||
switch (_event)
|
||||
{
|
||||
case Event.Event_BumpTransaction eventBumpTransaction:
|
||||
switch (eventBumpTransaction.bump_transaction)
|
||||
{
|
||||
case BumpTransactionEvent.BumpTransactionEvent_ChannelClose bumpTransactionEventChannelClose:
|
||||
break;
|
||||
case BumpTransactionEvent.BumpTransactionEvent_HTLCResolution bumpTransactionEventHtlcResolution:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
break;
|
||||
case Event.Event_ChannelClosed eventChannelClosed:
|
||||
break;
|
||||
case Event.Event_ChannelPending eventChannelPending:
|
||||
break;
|
||||
case Event.Event_ChannelReady eventChannelReady:
|
||||
break;
|
||||
case Event.Event_DiscardFunding eventDiscardFunding:
|
||||
break;
|
||||
case Event.Event_FundingGenerationReady eventFundingGenerationReady:
|
||||
break;
|
||||
case Event.Event_HTLCHandlingFailed eventHtlcHandlingFailed:
|
||||
break;
|
||||
case Event.Event_HTLCIntercepted eventHtlcIntercepted:
|
||||
break;
|
||||
case Event.Event_InvoiceRequestFailed eventInvoiceRequestFailed:
|
||||
break;
|
||||
case Event.Event_OpenChannelRequest eventOpenChannelRequest:
|
||||
break;
|
||||
case Event.Event_PaymentClaimable eventPaymentClaimable:
|
||||
break;
|
||||
case Event.Event_PaymentClaimed eventPaymentClaimed:
|
||||
break;
|
||||
case Event.Event_PaymentFailed eventPaymentFailed:
|
||||
break;
|
||||
case Event.Event_PaymentForwarded eventPaymentForwarded:
|
||||
break;
|
||||
case Event.Event_PaymentPathFailed eventPaymentPathFailed:
|
||||
break;
|
||||
case Event.Event_PaymentPathSuccessful eventPaymentPathSuccessful:
|
||||
break;
|
||||
case Event.Event_PaymentSent eventPaymentSent:
|
||||
break;
|
||||
case Event.Event_PendingHTLCsForwardable eventPendingHtlCsForwardable:
|
||||
break;
|
||||
case Event.Event_ProbeFailed eventProbeFailed:
|
||||
break;
|
||||
case Event.Event_ProbeSuccessful eventProbeSuccessful:
|
||||
break;
|
||||
case Event.Event_SpendableOutputs eventSpendableOutputs:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(_event));
|
||||
}
|
||||
}
|
||||
|
||||
public void register_tx(byte[] txid, byte[] script_pubkey)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void register_output(WatchedOutput output)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Liquid+</Product>
|
||||
<Description>Enhanced support for the liquid network.</Description>
|
||||
<Version>1.1.4</Version>
|
||||
<Version>1.1.5</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -10,7 +10,10 @@ using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Common;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Plugins.Altcoins;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
@@ -25,20 +28,24 @@ namespace BTCPayServer.Plugins.LiquidPlus.Controllers
|
||||
[AutoValidateAntiforgeryToken]
|
||||
public class StoreLiquidController : Controller
|
||||
{
|
||||
private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary;
|
||||
private readonly StoreRepository _storeRepository;
|
||||
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
|
||||
private readonly BTCPayServerClient _client;
|
||||
private readonly IExplorerClientProvider _explorerClientProvider;
|
||||
|
||||
public StoreLiquidController(BTCPayNetworkProvider btcPayNetworkProvider,
|
||||
BTCPayServerClient client, IExplorerClientProvider explorerClientProvider)
|
||||
public StoreLiquidController(PaymentMethodHandlerDictionary paymentMethodHandlerDictionary,
|
||||
StoreRepository storeRepository, BTCPayNetworkProvider btcPayNetworkProvider,
|
||||
IExplorerClientProvider explorerClientProvider)
|
||||
{
|
||||
_paymentMethodHandlerDictionary = paymentMethodHandlerDictionary;
|
||||
_storeRepository = storeRepository;
|
||||
_btcPayNetworkProvider = btcPayNetworkProvider;
|
||||
_client = client;
|
||||
_explorerClientProvider = explorerClientProvider;
|
||||
}
|
||||
|
||||
[HttpGet("stores/{storeId}/liquid")]
|
||||
public async Task<IActionResult> GenerateLiquidScript(string storeId, Dictionary<string, BitcoinExtKey> bitcoinExtKeys = null)
|
||||
public async Task<IActionResult> GenerateLiquidScript(string storeId,
|
||||
Dictionary<string, BitcoinExtKey> bitcoinExtKeys = null)
|
||||
{
|
||||
Dictionary<string, string> generated = new Dictionary<string, string>();
|
||||
var allNetworks = _btcPayNetworkProvider.GetAll().OfType<ElementsBTCPayNetwork>()
|
||||
@@ -49,12 +56,19 @@ namespace BTCPayServer.Plugins.LiquidPlus.Controllers
|
||||
.Distinct();
|
||||
Dictionary<string, BitcoinExtKey> privKeys = bitcoinExtKeys ?? new Dictionary<string, BitcoinExtKey>();
|
||||
|
||||
var store = await _storeRepository.FindStore(storeId);
|
||||
var pms = store
|
||||
.GetPaymentMethodConfigs<DerivationSchemeSettings>(_paymentMethodHandlerDictionary)
|
||||
.Select(pair => (PaymentMethodId: pair.Key, DerivationSchemeSettings: pair.Value,
|
||||
CryptoCode: pair.Key.ToString().Split("-")[0])).ToArray();
|
||||
|
||||
var paymentMethods = (await _client.GetStoreOnChainPaymentMethods(storeId))
|
||||
.Where(settings => allNetworkCodes.Contains(settings.CryptoCode))
|
||||
.GroupBy(data => _btcPayNetworkProvider.GetNetwork<ElementsBTCPayNetwork>(data.CryptoCode).NetworkCryptoCode);
|
||||
var paymentMethodsGroupedByNetworkCode =
|
||||
pms
|
||||
.Where(settings => allNetworkCodes.Contains(settings.CryptoCode))
|
||||
.GroupBy(data =>
|
||||
_btcPayNetworkProvider.GetNetwork<ElementsBTCPayNetwork>(data.CryptoCode).NetworkCryptoCode);
|
||||
|
||||
if (paymentMethods.Any() is false)
|
||||
if (paymentMethodsGroupedByNetworkCode.Any() is false)
|
||||
{
|
||||
TempData.SetStatusMessageModel(new StatusMessageModel()
|
||||
{
|
||||
@@ -64,7 +78,7 @@ namespace BTCPayServer.Plugins.LiquidPlus.Controllers
|
||||
return View(new GenerateLiquidImportScripts());
|
||||
}
|
||||
|
||||
foreach (var der in paymentMethods)
|
||||
foreach (var der in paymentMethodsGroupedByNetworkCode)
|
||||
{
|
||||
var network = _btcPayNetworkProvider.GetNetwork<ElementsBTCPayNetwork>(der.Key);
|
||||
var nbxnet = network.NBXplorerNetwork;
|
||||
@@ -79,12 +93,12 @@ namespace BTCPayServer.Plugins.LiquidPlus.Controllers
|
||||
generated.Add(der.Key, sb.ToString());
|
||||
continue;
|
||||
}
|
||||
var derivationSchemesForNetwork = der.GroupBy(data => data.DerivationScheme);
|
||||
|
||||
var derivationSchemesForNetwork = der.GroupBy(data => data.DerivationSchemeSettings);
|
||||
|
||||
foreach (var paymentMethodDerivationScheme in derivationSchemesForNetwork)
|
||||
{
|
||||
var derivatonScheme =
|
||||
nbxnet.DerivationStrategyFactory.Parse(paymentMethodDerivationScheme.Key);
|
||||
var derivatonScheme = paymentMethodDerivationScheme.Key.AccountDerivation;
|
||||
var sameWalletCryptoCodes = paymentMethodDerivationScheme.Select(data => data.CryptoCode).ToArray();
|
||||
var matchedExistingKey = privKeys.Where(pair => sameWalletCryptoCodes.Contains(pair.Key));
|
||||
BitcoinExtKey key = null;
|
||||
@@ -94,18 +108,16 @@ namespace BTCPayServer.Plugins.LiquidPlus.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
key = await explorerClient.GetMetadataAsync<BitcoinExtKey>(derivatonScheme,
|
||||
WellknownMetadataKeys.AccountHDKey);
|
||||
}
|
||||
|
||||
if (key != null)
|
||||
{
|
||||
|
||||
foreach (var paymentMethodData in paymentMethodDerivationScheme)
|
||||
{
|
||||
privKeys.TryAdd(paymentMethodData.CryptoCode, key);
|
||||
}
|
||||
{
|
||||
privKeys.TryAdd(paymentMethodData.CryptoCode, key);
|
||||
}
|
||||
}
|
||||
|
||||
var utxos = await explorerClient.GetUTXOsAsync(derivatonScheme, CancellationToken.None);
|
||||
@@ -139,21 +151,21 @@ namespace BTCPayServer.Plugins.LiquidPlus.Controllers
|
||||
{
|
||||
sb.AppendLine("elements-cli stop");
|
||||
sb.AppendLine("elementsd -rescan");
|
||||
|
||||
}
|
||||
|
||||
generated.Add(der.Key, sb.ToString());
|
||||
}
|
||||
|
||||
return View(new GenerateLiquidImportScripts()
|
||||
{
|
||||
Wallets = paymentMethods.SelectMany(settings =>
|
||||
Wallets = paymentMethodsGroupedByNetworkCode.SelectMany(settings =>
|
||||
settings.Select(data =>
|
||||
new GenerateLiquidImportScripts.GenerateLiquidImportScriptWalletKeyVm()
|
||||
{
|
||||
CryptoCode = data.CryptoCode,
|
||||
KeyPresent = privKeys.ContainsKey(data.CryptoCode),
|
||||
ManualKey = null
|
||||
}).ToArray()).ToArray(),
|
||||
new GenerateLiquidImportScripts.GenerateLiquidImportScriptWalletKeyVm()
|
||||
{
|
||||
CryptoCode = data.CryptoCode,
|
||||
KeyPresent = privKeys.ContainsKey(data.CryptoCode),
|
||||
ManualKey = null
|
||||
}).ToArray()).ToArray(),
|
||||
Scripts = generated
|
||||
});
|
||||
}
|
||||
@@ -199,10 +211,9 @@ namespace BTCPayServer.Plugins.LiquidPlus.Controllers
|
||||
continue;
|
||||
}
|
||||
|
||||
var der = HttpContext.GetStoreData()
|
||||
.GetDerivationSchemeSettings(_paymentMethodHandlerDictionary, wallet.CryptoCode).AccountDerivation;
|
||||
|
||||
|
||||
var der = n.NBXplorerNetwork.DerivationStrategyFactory.Parse(
|
||||
(await _client.GetStoreOnChainPaymentMethod(storeId, wallet.CryptoCode)).DerivationScheme);
|
||||
if (der.GetExtPubKeys().Count() > 1)
|
||||
{
|
||||
vm.AddModelError(scripts => scripts.Wallets[index].ManualKey, "cannot handle multsig", this);
|
||||
@@ -250,7 +261,8 @@ namespace BTCPayServer.Plugins.LiquidPlus.Controllers
|
||||
|
||||
return await GenerateLiquidScript(storeId, privKeys);
|
||||
}
|
||||
public class GenerateLiquidImportScripts
|
||||
|
||||
public class GenerateLiquidImportScripts
|
||||
{
|
||||
public class GenerateLiquidImportScriptWalletKeyVm
|
||||
{
|
||||
@@ -266,6 +278,7 @@ public class GenerateLiquidImportScripts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace XX
|
||||
{
|
||||
public static class ModelStateExtensions
|
||||
@@ -275,7 +288,9 @@ namespace XX
|
||||
string message,
|
||||
ControllerBase controller)
|
||||
{
|
||||
var provider = (ModelExpressionProvider)controller.HttpContext.RequestServices.GetService(typeof(ModelExpressionProvider));
|
||||
var provider =
|
||||
(ModelExpressionProvider) controller.HttpContext.RequestServices.GetService(
|
||||
typeof(ModelExpressionProvider));
|
||||
var key = provider.GetExpressionText(ex);
|
||||
controller.ModelState.AddModelError(key, message);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace BTCPayServer.Plugins.LiquidPlus
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=1.12.0"}
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=2.0.0"}
|
||||
};
|
||||
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
@@ -31,11 +31,11 @@ namespace BTCPayServer.Plugins.LiquidPlus
|
||||
if (services.BootstrapServices.GetRequiredService<NBXplorerNetworkProvider>()
|
||||
.GetFromCryptoCode("LBTC") is null || !services.BootstrapServices.GetRequiredService<SelectedChains>().Contains("LBTC"))
|
||||
return;
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("LiquidNav", "store-integrations-nav"));
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("OnChainWalletSetupLiquidExtension",
|
||||
"onchain-wallet-setup-post-body"));
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("CustomLiquidAssetsNavExtension", "server-nav"));
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("StoreNavLiquidExtension", "store-nav"));
|
||||
services.AddUIExtension("store-integrations-nav", "LiquidNav");
|
||||
services.AddUIExtension("onchain-wallet-setup-post-body", "OnChainWalletSetupLiquidExtension");
|
||||
services.AddUIExtension("server-nav", "CustomLiquidAssetsNavExtension");
|
||||
services.AddUIExtension("store-nav", "StoreNavLiquidExtension");
|
||||
|
||||
services.AddSingleton<CustomLiquidAssetsRepository>();
|
||||
|
||||
|
||||
@@ -53,12 +53,11 @@ namespace BTCPayServer.Plugins.LiquidPlus
|
||||
CryptoCode: "LBTC"
|
||||
})
|
||||
.ImplementationInstance;
|
||||
|
||||
var pmi = PaymentTypes.CHAIN.GetPaymentMethodId("LBTC");
|
||||
var tlProvider = (TransactionLinkProviders.Entry) services.Single(descriptor =>
|
||||
descriptor.ServiceType == typeof(TransactionLinkProviders.Entry) &&
|
||||
descriptor.ImplementationInstance is TransactionLinkProviders.Entry
|
||||
{
|
||||
PaymentMethodId: {CryptoCode: "LBTC"}
|
||||
})
|
||||
descriptor.ImplementationInstance is TransactionLinkProviders.Entry entry && entry.PaymentMethodId == pmi)
|
||||
.ImplementationInstance;
|
||||
settings.Items.ForEach(configuration =>
|
||||
|
||||
@@ -80,7 +79,6 @@ namespace BTCPayServer.Plugins.LiquidPlus
|
||||
NetworkCryptoCode = template.NetworkCryptoCode,
|
||||
DefaultSettings = template.DefaultSettings,
|
||||
ElectrumMapping = template.ElectrumMapping,
|
||||
BlockExplorerLink = template.BlockExplorerLink,
|
||||
ReadonlyWallet = template.ReadonlyWallet,
|
||||
SupportLightning = false,
|
||||
SupportPayJoin = false,
|
||||
@@ -92,7 +90,7 @@ namespace BTCPayServer.Plugins.LiquidPlus
|
||||
VaultSupported = template.VaultSupported,
|
||||
MaxTrackedConfirmation = template.MaxTrackedConfirmation,
|
||||
SupportRBF = template.SupportRBF
|
||||
}).AddTransactionLinkProvider(new PaymentMethodId(code, PaymentTypes.BTCLike), tlProvider.Provider);
|
||||
}).AddTransactionLinkProvider(code, tlProvider.Provider);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\**" />
|
||||
<ProjectReference Include="..\..\submodules\btcpayserver\BTCPayServer\BTCPayServer.csproj" />
|
||||
<PackageReference Include="AsyncKeyedLock" Version="6.4.2" />
|
||||
<PackageReference Include="AsyncKeyedLock" Version="7.0.1" />
|
||||
<PackageReference Include="FlexLabs.EntityFrameworkCore.Upsert" Version="8.0.0" />
|
||||
<PackageReference Include="Laraue.EfCoreTriggers.PostgreSql" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.10.0" />
|
||||
|
||||
@@ -1,23 +1,29 @@
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using System;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using Laraue.EfCoreTriggers.PostgreSql.Extensions;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure;
|
||||
|
||||
namespace BTCPayServer.Plugins.MicroNode;
|
||||
|
||||
public class MicroNodeContextFactory : BaseDbContextFactory<MicroNodeContext>
|
||||
{
|
||||
public MicroNodeContextFactory(IOptions<DatabaseOptions> options) : base(options, "BTCPayServer.Plugins.MicroNode")
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
|
||||
public MicroNodeContextFactory(IOptions<DatabaseOptions> options, ILoggerFactory loggerFactory) : base(options, "BTCPayServer.Plugins.MicroNode")
|
||||
{
|
||||
_loggerFactory = loggerFactory;
|
||||
}
|
||||
|
||||
public override MicroNodeContext CreateContext()
|
||||
public override MicroNodeContext CreateContext(Action<NpgsqlDbContextOptionsBuilder> npgsqlOptionsAction = null)
|
||||
{
|
||||
var builder = new DbContextOptionsBuilder<MicroNodeContext>();
|
||||
ConfigureBuilder(builder);
|
||||
builder.UsePostgreSqlTriggers();
|
||||
|
||||
builder.UseLoggerFactory(_loggerFactory);
|
||||
builder.AddInterceptors(MigrationInterceptor.Instance);
|
||||
ConfigureBuilder(builder, npgsqlOptionsAction);
|
||||
return new MicroNodeContext(builder.Options);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using BTCPayServer.Client;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -17,14 +18,17 @@ namespace BTCPayServer.Plugins.MicroNode;
|
||||
[Route("plugins/micronode")]
|
||||
public class MicroNodeController : Controller
|
||||
{
|
||||
private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary;
|
||||
private readonly MicroNodeService _microNodeService;
|
||||
private readonly StoreRepository _storeRepository;
|
||||
private readonly BTCPayNetworkProvider _networkProvider;
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
|
||||
public MicroNodeController(MicroNodeService microNodeService, StoreRepository storeRepository,
|
||||
public MicroNodeController(
|
||||
PaymentMethodHandlerDictionary paymentMethodHandlerDictionary,MicroNodeService microNodeService, StoreRepository storeRepository,
|
||||
BTCPayNetworkProvider networkProvider, IAuthorizationService authorizationService)
|
||||
{
|
||||
_paymentMethodHandlerDictionary = paymentMethodHandlerDictionary;
|
||||
_microNodeService = microNodeService;
|
||||
_storeRepository = storeRepository;
|
||||
_networkProvider = networkProvider;
|
||||
@@ -66,11 +70,8 @@ public class MicroNodeController : Controller
|
||||
ModelState.AddModelError("masterStoreId", "Master cannot be the same as this store");
|
||||
return View(settings);
|
||||
}
|
||||
|
||||
var existing = store.GetSupportedPaymentMethods(_networkProvider).OfType<LightningSupportedPaymentMethod>()
|
||||
.FirstOrDefault(method =>
|
||||
method.PaymentId.PaymentType == LightningPaymentType.Instance &&
|
||||
method.PaymentId.CryptoCode == network.CryptoCode);
|
||||
var pmi = PaymentTypes.LN.GetPaymentMethodId(network.CryptoCode);
|
||||
var existing = store.GetPaymentMethodConfig<LightningPaymentMethodConfig>(pmi, _paymentMethodHandlerDictionary);
|
||||
var isSet = settings?.Key is not null;
|
||||
settings ??= new MicroNodeStoreSettings();
|
||||
settings.Key ??= Guid.NewGuid().ToString();
|
||||
@@ -118,12 +119,10 @@ public class MicroNodeController : Controller
|
||||
}
|
||||
|
||||
|
||||
existing ??= new LightningSupportedPaymentMethod()
|
||||
{
|
||||
CryptoCode = "BTC"
|
||||
};
|
||||
existing ??= new();
|
||||
existing.SetLightningUrl(mlc);
|
||||
store.SetSupportedPaymentMethod(existing);
|
||||
|
||||
store.SetPaymentMethodConfig(_paymentMethodHandlerDictionary[pmi], existing);
|
||||
|
||||
|
||||
await _microNodeService.Set(storeId, settings, masterStoreId);
|
||||
@@ -145,7 +144,7 @@ public class MicroNodeController : Controller
|
||||
|
||||
if (isStoreSetToThisMicro)
|
||||
{
|
||||
store.SetSupportedPaymentMethod(existing.PaymentId, null);
|
||||
store.SetPaymentMethodConfig(_paymentMethodHandlerDictionary[pmi], null);
|
||||
await _storeRepository.UpdateStore(store);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ public class MicroNodePlugin:BaseBTCPayServerPlugin
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new () { Identifier = nameof(BTCPayServer), Condition = ">=1.12.0" }
|
||||
new () { Identifier = nameof(BTCPayServer), Condition = ">=2.0.0" }
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@ using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.Payouts;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -34,6 +36,7 @@ public class MicroNodeService : EventHostedServiceBase
|
||||
private readonly ILogger<MicroNodeService> _logger;
|
||||
private readonly PullPaymentHostedService _pullPaymentHostedService;
|
||||
private readonly IOptions<LightningNetworkOptions> _lightningNetworkOptions;
|
||||
private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary;
|
||||
private static readonly ConcurrentDictionary<string, long> ExpectedCounter = new();
|
||||
private readonly TaskCompletionSource _init = new();
|
||||
private Dictionary<string, MicroNodeSettings> _ownerSettings;
|
||||
@@ -53,6 +56,7 @@ public class MicroNodeService : EventHostedServiceBase
|
||||
EventAggregator eventAggregator,
|
||||
PullPaymentHostedService pullPaymentHostedService,
|
||||
IOptions<LightningNetworkOptions> lightningNetworkOptions,
|
||||
PaymentMethodHandlerDictionary paymentMethodHandlerDictionary,
|
||||
IServiceProvider serviceProvider) : base(eventAggregator, logger)
|
||||
{
|
||||
_network = btcPayNetworkProvider.BTC;
|
||||
@@ -63,6 +67,7 @@ public class MicroNodeService : EventHostedServiceBase
|
||||
_logger = logger;
|
||||
_pullPaymentHostedService = pullPaymentHostedService;
|
||||
_lightningNetworkOptions = lightningNetworkOptions;
|
||||
_paymentMethodHandlerDictionary = paymentMethodHandlerDictionary;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
@@ -124,17 +129,20 @@ public class MicroNodeService : EventHostedServiceBase
|
||||
{
|
||||
var b = payout.GetBlob(_btcPayNetworkJsonSerializerSettings);
|
||||
|
||||
List<MicroTransaction> res = new();
|
||||
res.Add(new MicroTransaction()
|
||||
{
|
||||
Id = payout.Id,
|
||||
AccountId = key,
|
||||
Amount = -LightMoney.Coins(b.CryptoAmount.Value).MilliSatoshi,
|
||||
Accounted = payout.State != PayoutState.Cancelled,
|
||||
Active = payout.State is PayoutState.AwaitingApproval or PayoutState.AwaitingPayment
|
||||
or PayoutState.InProgress,
|
||||
Type = "Payout"
|
||||
});
|
||||
List<MicroTransaction> res =
|
||||
[
|
||||
new()
|
||||
{
|
||||
Id = payout.Id,
|
||||
AccountId = key,
|
||||
Amount = -LightMoney.Coins(payout.Amount!.Value).MilliSatoshi,
|
||||
Accounted = payout.State != PayoutState.Cancelled,
|
||||
Active = payout.State is PayoutState.AwaitingApproval or PayoutState.AwaitingPayment
|
||||
or PayoutState.InProgress,
|
||||
Type = "Payout"
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
if (b.Metadata?.TryGetValue("Fee", out var microNode) is true && microNode.Value<decimal>() is { } payoutFee)
|
||||
{
|
||||
@@ -230,7 +238,7 @@ public class MicroNodeService : EventHostedServiceBase
|
||||
await using var ctx = _microNodeContextFactory.CreateContext();
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var account = await ctx.MicroAccounts.FindAsync(key);
|
||||
var account = await ctx.MicroAccounts.FindAsync(key, cancellation);
|
||||
if (account is null)
|
||||
{
|
||||
return null;
|
||||
@@ -336,9 +344,9 @@ public class MicroNodeService : EventHostedServiceBase
|
||||
return null;
|
||||
}
|
||||
|
||||
var lightningConnectionString = store.GetSupportedPaymentMethods(_btcPayNetworkProvider)
|
||||
.OfType<LightningSupportedPaymentMethod>()
|
||||
.FirstOrDefault(method => method.CryptoCode == _network.CryptoCode)?.CreateLightningClient(_network,
|
||||
var pmi = PaymentTypes.LN.GetPaymentMethodId(_network.CryptoCode);
|
||||
var lightningConnectionString = store.GetPaymentMethodConfig<LightningPaymentMethodConfig>(pmi, _paymentMethodHandlerDictionary)
|
||||
?.CreateLightningClient(_network,
|
||||
_lightningNetworkOptions.Value, _serviceProvider.GetService<LightningClientFactoryService>());
|
||||
return lightningConnectionString;
|
||||
}
|
||||
@@ -616,7 +624,7 @@ public class MicroNodeService : EventHostedServiceBase
|
||||
StoreId = masterClients.Key,
|
||||
Destination = new LNURLPayClaimDestinaton(destination),
|
||||
PreApprove = true,
|
||||
PaymentMethodId = new PaymentMethodId("BTC", LightningPaymentType.Instance),
|
||||
PayoutMethodId = PayoutTypes.LN.GetPayoutMethodId("BTC"),
|
||||
Metadata = JObject.FromObject(new
|
||||
{
|
||||
Source = $"MicroNode on store {storeId.Key}"
|
||||
@@ -667,7 +675,7 @@ public class MicroNodeService : EventHostedServiceBase
|
||||
await base.StopAsync(cancellationToken);
|
||||
}
|
||||
|
||||
private ConcurrentDictionary<string, string> _keyToMasterStoreId = new();
|
||||
private readonly ConcurrentDictionary<string, string> _keyToMasterStoreId = new();
|
||||
|
||||
public async Task Set(string storeId, MicroNodeStoreSettings? settings, string? masterStoreId = null)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Nostr</Product>
|
||||
<Description>NIP5 addresses, Zap support, Nostr Wallet Connect Lightning support</Description>
|
||||
<Version>1.1.13</Version>
|
||||
<Version>1.1.14</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace BTCPayServer.Plugins.NIP05
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=1.13.0"}
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=2.0.0"}
|
||||
};
|
||||
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<div class="col-xl-8 col-xxl-constrain">
|
||||
<div class="form-group">
|
||||
<div class="form-group pt-2">
|
||||
<label asp-for="Name (does not need to be same as for a lightning address)" class="form-label"></label>
|
||||
<label asp-for="Name" class="form-label">Name (does not need to be same as for a lightning address)</label>
|
||||
<div class="input-group">
|
||||
<input asp-for="Name" class="form-control"/>
|
||||
<span class="input-group-text">@@@Context.Request.Host.ToUriComponent()@Context.Request.PathBase</span>
|
||||
|
||||
@@ -5,11 +5,9 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Events;
|
||||
using BTCPayServer.Models.InvoicingModels;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -24,6 +22,7 @@ public class Zapper : IHostedService
|
||||
{
|
||||
record PendingZapEvent(string[] relays, NostrEvent nostrEvent);
|
||||
|
||||
private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary;
|
||||
private readonly EventAggregator _eventAggregator;
|
||||
private readonly Nip5Controller _nip5Controller;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
@@ -51,7 +50,9 @@ public class Zapper : IHostedService
|
||||
}
|
||||
|
||||
|
||||
public Zapper(EventAggregator eventAggregator,
|
||||
public Zapper(
|
||||
PaymentMethodHandlerDictionary paymentMethodHandlerDictionary,
|
||||
EventAggregator eventAggregator,
|
||||
Nip5Controller nip5Controller,
|
||||
IMemoryCache memoryCache,
|
||||
ILogger<Zapper> logger,
|
||||
@@ -59,6 +60,7 @@ public class Zapper : IHostedService
|
||||
InvoiceRepository invoiceRepository,
|
||||
NostrClientPool nostrClientPool)
|
||||
{
|
||||
_paymentMethodHandlerDictionary = paymentMethodHandlerDictionary;
|
||||
_eventAggregator = eventAggregator;
|
||||
_nip5Controller = nip5Controller;
|
||||
_memoryCache = memoryCache;
|
||||
@@ -150,7 +152,8 @@ public class Zapper : IHostedService
|
||||
{
|
||||
if (arg.EventCode != InvoiceEventCode.Completed && arg.EventCode != InvoiceEventCode.MarkedCompleted)
|
||||
return;
|
||||
var pm = arg.Invoice.GetPaymentMethod(new PaymentMethodId("BTC", LNURLPayPaymentType.Instance));
|
||||
var pmi = PaymentTypes.LNURL.GetPaymentMethodId("BTC");
|
||||
var pm = arg.Invoice.GetPaymentPrompt(pmi);
|
||||
if (pm is null)
|
||||
{
|
||||
return;
|
||||
@@ -160,7 +163,6 @@ public class Zapper : IHostedService
|
||||
return;
|
||||
}
|
||||
|
||||
var pmd = (LNURLPayPaymentMethodDetails) pm.GetPaymentMethodDetails();
|
||||
var settings = await GetSettings();
|
||||
|
||||
var zapRequestEvent = JsonSerializer.Deserialize<NostrEvent>(zapRequest);
|
||||
@@ -174,7 +176,7 @@ public class Zapper : IHostedService
|
||||
new NostrEventTag
|
||||
{
|
||||
TagIdentifier = "bolt11",
|
||||
Data = new() {pmd.BOLT11}
|
||||
Data = new() {pm.Destination}
|
||||
},
|
||||
|
||||
new NostrEventTag()
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Prism</Product>
|
||||
<Description>Automated value splits for Bitcoin.</Description>
|
||||
<Version>1.2.8</Version>
|
||||
<Version>1.2.9</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
@using BTCPayServer.HostedServices
|
||||
@using BTCPayServer.Payments
|
||||
@using BTCPayServer.PayoutProcessors
|
||||
@using BTCPayServer.Payouts
|
||||
@using Microsoft.AspNetCore.Http
|
||||
@using Microsoft.AspNetCore.Routing
|
||||
@using Microsoft.Extensions.Logging
|
||||
@@ -28,7 +29,7 @@ else
|
||||
{
|
||||
<datalist id="users">
|
||||
<option value="*">Catch-all lightning payments made against invoices in your store (excluding when other prisms are configured that capture those payments.)</option>
|
||||
<option value="*@BitcoinPaymentType.Instance.ToStringNormalized()">Catch-all on-chain payments made against invoices in your store</option>
|
||||
<option value="*@PaymentTypes.CHAIN.ToString()">Catch-all on-chain payments made against invoices in your store</option>
|
||||
<option value="*All">Catch-all any payments made against invoices in your store</option>
|
||||
|
||||
@foreach (var user in Users)
|
||||
@@ -201,8 +202,8 @@ else
|
||||
|
||||
public bool Loading { get; set; } = true;
|
||||
public List<LightningAddressData> Users { get; set; } = new();
|
||||
public PaymentMethodId pmi { get; set; } = new("BTC", LightningPaymentType.Instance);
|
||||
public PaymentMethodId pmichain { get; set; } = new("BTC", PaymentTypes.BTCLike);
|
||||
public PayoutMethodId pmi { get; set; } = PayoutTypes.LN.GetPayoutMethodId("BTC");
|
||||
public PayoutMethodId pmichain { get; set; } = PayoutTypes.CHAIN.GetPayoutMethodId("BTC");
|
||||
public bool NoPayoutProcessors { get; set; }
|
||||
|
||||
private string PrismEditButtonsFilter { get; set; }
|
||||
@@ -224,7 +225,7 @@ else
|
||||
var fetchProcessors = PayoutProcessorService.GetProcessors(new PayoutProcessorService.PayoutProcessorQuery()
|
||||
{
|
||||
Stores = new[] {StoreId},
|
||||
PaymentMethods = new[] {pmi.ToString(), pmichain.ToString()}
|
||||
PayoutMethods = new[] {pmi, pmichain}
|
||||
});
|
||||
|
||||
var tasks = new Task[]
|
||||
@@ -243,8 +244,8 @@ else
|
||||
EditContext.OnFieldChanged += FieldChanged;
|
||||
SatBreaker.PrismUpdated += SatBreakerOnPrismUpdated;
|
||||
//set NoPayoutProcessors to true if there are no configured payout processores for pmi and pmichain
|
||||
NoPayoutProcessors = PayoutProcessorFactories.Any(factory => factory.GetSupportedPaymentMethods().Contains(pmi)) && (await fetchProcessors).All(data =>
|
||||
!new[] {pmi, pmichain}.Contains(data.GetPaymentMethodId()));
|
||||
NoPayoutProcessors = PayoutProcessorFactories.Any(factory => factory.GetSupportedPayoutMethods().Contains(pmi)) && (await fetchProcessors).All(data =>
|
||||
!new[] {pmi, pmichain}.Contains(data.GetPayoutMethodId()));
|
||||
|
||||
Loading = false;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payouts;
|
||||
|
||||
namespace BTCPayServer.Plugins.Prism;
|
||||
|
||||
@@ -19,7 +20,7 @@ public class LNURLPrismDestinationValidator : IPluginHookFilter
|
||||
return Task.FromResult<object>(new PrismDestinationValidationResult()
|
||||
{
|
||||
Success = true,
|
||||
PaymentMethod = new PaymentMethodId("BTC", PaymentTypes.LNURLPay)
|
||||
PayoutMethodId = PayoutTypes.LN.GetPayoutMethodId("BTC")
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -30,7 +31,7 @@ public class LNURLPrismDestinationValidator : IPluginHookFilter
|
||||
return Task.FromResult<object>(new PrismDestinationValidationResult()
|
||||
{
|
||||
Success = true,
|
||||
PaymentMethod = new PaymentMethodId("BTC", PaymentTypes.LNURLPay)
|
||||
PayoutMethodId =PayoutTypes.LN.GetPayoutMethodId("BTC")
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -45,5 +46,5 @@ public class LNURLPrismDestinationValidator : IPluginHookFilter
|
||||
public class PrismDestinationValidationResult
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public PaymentMethodId PaymentMethod { get; set; }
|
||||
public PayoutMethodId PayoutMethodId { get; set; }
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payouts;
|
||||
using NBitcoin;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
|
||||
@@ -35,7 +34,7 @@ public class OnChainPrismClaimCreate : IPluginHookFilter
|
||||
{
|
||||
claimRequest.Destination =
|
||||
new AddressClaimDestination(BitcoinAddress.Create(destStr, network.NBitcoinNetwork));
|
||||
claimRequest.PaymentMethodId = new PaymentMethodId("BTC", BitcoinPaymentType.Instance);
|
||||
claimRequest.PayoutMethodId = PayoutTypes.CHAIN.GetPayoutMethodId("BTC");
|
||||
return args;
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -48,7 +47,7 @@ public class OnChainPrismClaimCreate : IPluginHookFilter
|
||||
|
||||
claimRequest.Destination =
|
||||
new AddressClaimDestination(add.Address);
|
||||
claimRequest.PaymentMethodId = new PaymentMethodId("BTC", BitcoinPaymentType.Instance);
|
||||
claimRequest.PayoutMethodId = PayoutTypes.CHAIN.GetPayoutMethodId("BTC");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payouts;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
@@ -34,7 +35,7 @@ public class OnChainPrismDestinationValidator : IPluginHookFilter
|
||||
return Task.FromResult<object>(new PrismDestinationValidationResult()
|
||||
{
|
||||
Success = true,
|
||||
PaymentMethod = new PaymentMethodId("BTC", PaymentTypes.BTCLike)
|
||||
PayoutMethodId = PayoutTypes.CHAIN.GetPayoutMethodId("BTC")
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -46,7 +47,7 @@ public class OnChainPrismDestinationValidator : IPluginHookFilter
|
||||
return Task.FromResult<object>(new PrismDestinationValidationResult()
|
||||
{
|
||||
Success = true,
|
||||
PaymentMethod = new PaymentMethodId("BTC", PaymentTypes.BTCLike)
|
||||
PayoutMethodId =PayoutTypes.CHAIN.GetPayoutMethodId("BTC")
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payouts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
@@ -30,7 +31,7 @@ public class OpenSatsDestinationValidator : IPluginHookFilter
|
||||
|
||||
var parts = args1.ToLowerInvariant().Split(":", StringSplitOptions.RemoveEmptyEntries);
|
||||
var project = "general_fund";
|
||||
var paymentMethod = new PaymentMethodId("BTC", PaymentTypes.LightningLike);
|
||||
var paymentMethod = PayoutTypes.LN.GetPayoutMethodId("BTC");
|
||||
if (parts.Length > 1)
|
||||
{
|
||||
project = parts[1];
|
||||
@@ -38,12 +39,11 @@ public class OpenSatsDestinationValidator : IPluginHookFilter
|
||||
|
||||
if (parts.Length > 2)
|
||||
{
|
||||
paymentMethod = PaymentMethodId.Parse(parts[2]);
|
||||
paymentMethod = PayoutMethodId.Parse(parts[2]);
|
||||
}
|
||||
|
||||
|
||||
var handler = _serviceProvider.GetServices<IPayoutHandler>().FindPayoutHandler(paymentMethod);
|
||||
if (handler is null)
|
||||
if (_serviceProvider.GetService<PayoutMethodHandlerDictionary>().TryGetValue(paymentMethod, out var handler))
|
||||
{
|
||||
result.Success = false;
|
||||
}
|
||||
@@ -63,7 +63,7 @@ public class OpenSatsDestinationValidator : IPluginHookFilter
|
||||
var invoiceBtcpayModel = JObject.Parse(await httpClient.GetStringAsync(invoiceUrl).ConfigureAwait(false));
|
||||
var destination = invoiceBtcpayModel.Value<string>("btcAddress");
|
||||
|
||||
var claimDestination = await handler.ParseClaimDestination(paymentMethod,destination, CancellationToken.None);
|
||||
var claimDestination = await handler.ParseClaimDestination(destination, CancellationToken.None);
|
||||
if (claimDestination.destination is null)
|
||||
{
|
||||
|
||||
@@ -72,7 +72,7 @@ public class OpenSatsDestinationValidator : IPluginHookFilter
|
||||
|
||||
|
||||
result.Success = true;
|
||||
result.PaymentMethod = paymentMethod;
|
||||
result.PayoutMethodId = paymentMethod;
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Abstractions.Custodians;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Payments;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using BTCPayServer.Payouts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NBitcoin;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Plugins.Prism;
|
||||
@@ -41,7 +35,7 @@ public class OpenSatsPrismClaimCreate : IPluginHookFilter
|
||||
|
||||
var parts = args1.Split(":", StringSplitOptions.RemoveEmptyEntries);
|
||||
var project = "opensats";
|
||||
var paymentMethod = new PaymentMethodId("BTC", PaymentTypes.LightningLike);
|
||||
var paymentMethod = PayoutTypes.LN.GetPayoutMethodId("BTC");
|
||||
if (parts.Length > 1)
|
||||
{
|
||||
project = parts[1];
|
||||
@@ -49,11 +43,11 @@ public class OpenSatsPrismClaimCreate : IPluginHookFilter
|
||||
|
||||
if (parts.Length > 2)
|
||||
{
|
||||
paymentMethod = PaymentMethodId.Parse(parts[2]);
|
||||
paymentMethod = PayoutMethodId.Parse(parts[2]);
|
||||
}
|
||||
|
||||
|
||||
var handler = _serviceProvider.GetServices<IPayoutHandler>().FindPayoutHandler(paymentMethod);
|
||||
_serviceProvider.GetService<PayoutMethodHandlerDictionary>().TryGetValue(paymentMethod, out var handler);
|
||||
if (handler is null)
|
||||
{
|
||||
return null;
|
||||
@@ -75,7 +69,7 @@ public class OpenSatsPrismClaimCreate : IPluginHookFilter
|
||||
var destination = invoiceBtcpayModel.Value<string>("btcAddress");
|
||||
var receiptLink = invoiceBtcpayModel.Value<string>("receiptLink");
|
||||
|
||||
var claimDestination = await handler.ParseClaimDestination(paymentMethod,destination, CancellationToken.None);
|
||||
var claimDestination = await handler.ParseClaimDestination(destination, CancellationToken.None);
|
||||
if (claimDestination.destination is null)
|
||||
{
|
||||
|
||||
@@ -88,7 +82,7 @@ public class OpenSatsPrismClaimCreate : IPluginHookFilter
|
||||
});
|
||||
|
||||
claimRequest.Destination = claimDestination.destination;
|
||||
claimRequest.PaymentMethodId = paymentMethod;
|
||||
claimRequest.PayoutMethodId = paymentMethod;
|
||||
|
||||
return claimRequest;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ public class PrismPlugin : BaseBTCPayServerPlugin
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=1.13.0"}
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=2.0.0"}
|
||||
};
|
||||
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
|
||||
@@ -20,5 +20,5 @@ public class PrismDestination
|
||||
public string Destination { get; set; }
|
||||
public decimal? Reserve { get; set; }
|
||||
public long? SatThreshold { get; set; }
|
||||
public string? PaymentMethodId { get; set; }
|
||||
public string? PayoutMethodId { get; set; }
|
||||
}
|
||||
@@ -13,6 +13,7 @@ using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.Payouts;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Stores;
|
||||
@@ -47,13 +48,13 @@ namespace BTCPayServer.Plugins.Prism
|
||||
{
|
||||
private readonly StoreRepository _storeRepository;
|
||||
private readonly ILogger<SatBreaker> _logger;
|
||||
private readonly LightningAddressService _lightningAddressService;
|
||||
private readonly PullPaymentHostedService _pullPaymentHostedService;
|
||||
private readonly LightningLikePayoutHandler _lightningLikePayoutHandler;
|
||||
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
|
||||
private readonly LightningClientFactoryService _lightningClientFactoryService;
|
||||
private readonly IOptions<LightningNetworkOptions> _lightningNetworkOptions;
|
||||
private readonly BTCPayNetworkJsonSerializerSettings _btcPayNetworkJsonSerializerSettings;
|
||||
private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary;
|
||||
private readonly PayoutMethodHandlerDictionary _payoutMethodHandlerDictionary;
|
||||
private readonly IPluginHookService _pluginHookService;
|
||||
private Dictionary<string, PrismSettings> _prismSettings;
|
||||
|
||||
@@ -62,24 +63,24 @@ namespace BTCPayServer.Plugins.Prism
|
||||
public SatBreaker(StoreRepository storeRepository,
|
||||
EventAggregator eventAggregator,
|
||||
ILogger<SatBreaker> logger,
|
||||
LightningAddressService lightningAddressService,
|
||||
PullPaymentHostedService pullPaymentHostedService,
|
||||
LightningLikePayoutHandler lightningLikePayoutHandler,
|
||||
BTCPayNetworkProvider btcPayNetworkProvider,
|
||||
LightningClientFactoryService lightningClientFactoryService,
|
||||
IOptions<LightningNetworkOptions> lightningNetworkOptions,
|
||||
BTCPayNetworkJsonSerializerSettings btcPayNetworkJsonSerializerSettings,
|
||||
PaymentMethodHandlerDictionary paymentMethodHandlerDictionary,
|
||||
PayoutMethodHandlerDictionary payoutMethodHandlerDictionary,
|
||||
IPluginHookService pluginHookService) : base(eventAggregator, logger)
|
||||
{
|
||||
_storeRepository = storeRepository;
|
||||
_logger = logger;
|
||||
_lightningAddressService = lightningAddressService;
|
||||
_pullPaymentHostedService = pullPaymentHostedService;
|
||||
_lightningLikePayoutHandler = lightningLikePayoutHandler;
|
||||
_btcPayNetworkProvider = btcPayNetworkProvider;
|
||||
_lightningClientFactoryService = lightningClientFactoryService;
|
||||
_lightningNetworkOptions = lightningNetworkOptions;
|
||||
_btcPayNetworkJsonSerializerSettings = btcPayNetworkJsonSerializerSettings;
|
||||
_paymentMethodHandlerDictionary = paymentMethodHandlerDictionary;
|
||||
_payoutMethodHandlerDictionary = payoutMethodHandlerDictionary;
|
||||
_pluginHookService = pluginHookService;
|
||||
}
|
||||
|
||||
@@ -148,17 +149,25 @@ namespace BTCPayServer.Plugins.Prism
|
||||
|
||||
foreach (var payout in storePayouts)
|
||||
{
|
||||
|
||||
if (!pendingPayouts.TryGetValue(payout.Id, out var pendingPayout))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(payout.GetPayoutMethodId() is not { } payoutMethodId)
|
||||
continue;
|
||||
|
||||
if (!_payoutMethodHandlerDictionary.TryGetValue(payoutMethodId, out var handler))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
long toCredit = 0;
|
||||
switch (payout.State)
|
||||
{
|
||||
case PayoutState.Completed:
|
||||
|
||||
var proof = _lightningLikePayoutHandler.ParseProof(payout) as PayoutLightningBlob;
|
||||
var proof = handler.ParseProof(payout) as PayoutLightningBlob;
|
||||
|
||||
long? feePaid = null;
|
||||
if (!string.IsNullOrEmpty(proof?.PaymentHash))
|
||||
@@ -168,10 +177,10 @@ namespace BTCPayServer.Plugins.Prism
|
||||
var store = await _storeRepository.FindStore(payout.StoreDataId);
|
||||
|
||||
var network = _btcPayNetworkProvider.GetNetwork<BTCPayNetwork>("BTC");
|
||||
var id = new PaymentMethodId("BTC", LightningPaymentType.Instance);
|
||||
var existing = store.GetSupportedPaymentMethods(_btcPayNetworkProvider)
|
||||
.OfType<LightningSupportedPaymentMethod>()
|
||||
.FirstOrDefault(d => d.PaymentId == id);
|
||||
var id = PaymentTypes.LN.GetPaymentMethodId("BTC");
|
||||
var existing =
|
||||
store.GetPaymentMethodConfig<LightningPaymentMethodConfig>(id,
|
||||
_paymentMethodHandlerDictionary);
|
||||
if (existing?.GetExternalLightningUrl() is { } connectionString)
|
||||
{
|
||||
lnClient = _lightningClientFactoryService.Create(connectionString,
|
||||
@@ -313,28 +322,33 @@ namespace BTCPayServer.Plugins.Prism
|
||||
private (Split, LightMoney)[] DetermineMatches(PrismSettings prismSettings, InvoiceEntity entity)
|
||||
{
|
||||
//first check the primary thing - ln address
|
||||
var explicitPMI = new PaymentMethodId("BTC", LNURLPayPaymentType.Instance);
|
||||
var pm = entity.GetPaymentMethod(explicitPMI);
|
||||
var pmd = pm?.GetPaymentMethodDetails() as LNURLPayPaymentMethodDetails;
|
||||
var explicitPMI = PaymentTypes.LNURL.GetPaymentMethodId("BTC");
|
||||
var pm = entity.GetPaymentPrompt(explicitPMI);
|
||||
|
||||
var payments = entity.GetPayments(true).GroupBy(paymentEntity => paymentEntity.PaymentMethodId).ToArray();
|
||||
List<(Split, LightMoney)> result = new();
|
||||
|
||||
var payments = entity.GetPayments(true).GroupBy(paymentEntity => paymentEntity.GetPaymentMethodId()).ToArray();
|
||||
if (pmd?.ConsumedLightningAddress is not null)
|
||||
if(_paymentMethodHandlerDictionary.TryGetValue(explicitPMI, out var handler) && pm is not null)
|
||||
{
|
||||
var address = pmd.ConsumedLightningAddress.Split("@")[0];
|
||||
var matchedExplicit = prismSettings.Splits.FirstOrDefault(s =>
|
||||
s.Source.Equals(address, StringComparison.InvariantCultureIgnoreCase));
|
||||
var pmd = handler.ParsePaymentPromptDetails(pm.Details) as LNURLPayPaymentMethodDetails;
|
||||
|
||||
if (matchedExplicit is not null)
|
||||
|
||||
if (pmd?.ConsumedLightningAddress is not null)
|
||||
{
|
||||
var explicitPayments = payments.FirstOrDefault(grouping =>
|
||||
grouping.Key == explicitPMI)?.Sum(paymentEntity => paymentEntity.PaidAmount.Net);
|
||||
payments = payments.Where(grouping => grouping.Key != explicitPMI).ToArray();
|
||||
var address = pmd.ConsumedLightningAddress.Split("@")[0];
|
||||
var matchedExplicit = prismSettings.Splits.FirstOrDefault(s =>
|
||||
s.Source.Equals(address, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
if (explicitPayments > 0)
|
||||
{
|
||||
result.Add((matchedExplicit, LightMoney.FromUnit(explicitPayments.Value, LightMoneyUnit.BTC)));
|
||||
}
|
||||
if (matchedExplicit is not null)
|
||||
{
|
||||
var explicitPayments = payments.FirstOrDefault(grouping =>
|
||||
grouping.Key == explicitPMI)?.Sum(paymentEntity => paymentEntity.PaidAmount.Net);
|
||||
payments = payments.Where(grouping => grouping.Key != explicitPMI).ToArray();
|
||||
|
||||
if (explicitPayments > 0)
|
||||
{
|
||||
result.Add((matchedExplicit, LightMoney.FromUnit(explicitPayments.Value, LightMoneyUnit.BTC)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,20 +360,25 @@ namespace BTCPayServer.Plugins.Prism
|
||||
switch (split.Source)
|
||||
{
|
||||
case "*":
|
||||
pmi = new PaymentMethodId("BTC", PaymentTypes.LightningLike);
|
||||
pmi = PaymentTypes.LN.GetPaymentMethodId("BTC");
|
||||
break;
|
||||
case "*All":
|
||||
break;
|
||||
case var s when PaymentTypes.TryParse(s.Substring(1), out var pType):
|
||||
|
||||
pmi = new PaymentMethodId("BTC", pType);
|
||||
case var s when s.StartsWith("*") && s.Substring(1) ==PaymentTypes.CHAIN.ToString():
|
||||
pmi = PaymentTypes.CHAIN.GetPaymentMethodId("BTC");
|
||||
break;
|
||||
case var s2 when s2.StartsWith("*") && s2.Substring(1) ==PaymentTypes.LN.ToString():
|
||||
pmi = PaymentTypes.LN.GetPaymentMethodId("BTC");
|
||||
break;
|
||||
case var s3 when s3.StartsWith("*") && s3.Substring(1) ==PaymentTypes.LNURL.ToString():
|
||||
pmi = PaymentTypes.LNURL.GetPaymentMethodId("BTC");
|
||||
break;
|
||||
case var s when !PaymentMethodId.TryParse(s.Substring(1), out pmi):
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pmi is not null && pmi.CryptoCode != "BTC")
|
||||
if (pmi is not null && !pmi.ToString().StartsWith("BTC-"))
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
@@ -367,6 +386,7 @@ namespace BTCPayServer.Plugins.Prism
|
||||
return (pmi, valid, split);
|
||||
}).Where(tuple => tuple.valid).ToDictionary(split => split.pmi, split => split.split);
|
||||
|
||||
|
||||
while(payments.Any() || catchAlls.Any())
|
||||
{
|
||||
decimal paymentSum;
|
||||
@@ -511,9 +531,9 @@ namespace BTCPayServer.Plugins.Prism
|
||||
continue;
|
||||
}
|
||||
|
||||
var pmi = string.IsNullOrEmpty(destinationSettings?.PaymentMethodId) ||
|
||||
!PaymentMethodId.TryParse(destinationSettings?.PaymentMethodId, out var pmi2)
|
||||
? new PaymentMethodId("BTC", LightningPaymentType.Instance)
|
||||
var pmi = string.IsNullOrEmpty(destinationSettings?.PayoutMethodId) ||
|
||||
!PayoutMethodId.TryParse(destinationSettings?.PayoutMethodId, out var pmi2)
|
||||
? PayoutTypes.LN.GetPayoutMethodId("BTC")
|
||||
: pmi2;
|
||||
|
||||
var source = "Prism";
|
||||
@@ -526,7 +546,7 @@ namespace BTCPayServer.Plugins.Prism
|
||||
Destination = new PrismPlaceholderClaimDestination(destinationSettings?.Destination ?? destination),
|
||||
PreApprove = true,
|
||||
StoreId = storeId,
|
||||
PaymentMethodId = pmi,
|
||||
PayoutMethodId = pmi,
|
||||
Value = Money.Satoshis(payoutAmount).ToDecimal(MoneyUnit.BTC),
|
||||
Metadata = JObject.FromObject(new
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>SideShift</Product>
|
||||
<Description>Allows you to embed a SideShift conversion screen to allow customers to pay with altcoins.</Description>
|
||||
<Version>1.1.13</Version>
|
||||
<Version>1.1.14</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Data.Payouts.LightningLike;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Lightning;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Plugins.SideShift;
|
||||
|
||||
public class PrismClaimCreate : IPluginHookFilter
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly BTCPayNetworkProvider _networkProvider;
|
||||
public string Hook => "prism-claim-create";
|
||||
|
||||
public PrismClaimCreate(IHttpClientFactory httpClientFactory, BTCPayNetworkProvider networkProvider)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_networkProvider = networkProvider;
|
||||
}
|
||||
public async Task<object> Execute(object args)
|
||||
{
|
||||
var network = _networkProvider.GetNetwork<BTCPayNetwork>("BTC");
|
||||
if (args is not ClaimRequest claimRequest || network is null)
|
||||
{
|
||||
return args;
|
||||
}
|
||||
|
||||
if (claimRequest.Destination?.ToString() is not { } args1 || !args1.StartsWith("sideshift:")) return args;
|
||||
var request = JObject.Parse(args1.Substring("sideshift:".Length)).ToObject<PrismSideshiftDestination>();
|
||||
if (!request.Valid())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var client = _httpClientFactory.CreateClient("sideshift");
|
||||
|
||||
|
||||
var shiftResponse = await client.PostAsJsonAsync("https://sideshift.ai/api/v2/shifts/variable", new
|
||||
{
|
||||
settleAddress = request.ShiftDestination,
|
||||
affiliateId = "qg0OrfHJV",
|
||||
settleMemo = request.ShiftMemo,
|
||||
depositCoin = "BTC",
|
||||
depositNetwork = request.SourceNetwork?? "lightning",
|
||||
settleCoin = request.ShiftCoin,
|
||||
settleNetwork = request.ShiftNetwork,
|
||||
}
|
||||
);
|
||||
if (!shiftResponse.IsSuccessStatusCode)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var shift = await shiftResponse.Content.ReadAsAsync<SideShiftController.ShiftResponse>();
|
||||
try
|
||||
{
|
||||
LNURL.LNURL.Parse(shift.depositAddress, out _);
|
||||
claimRequest.Destination = new LNURLPayClaimDestinaton(shift.depositAddress);
|
||||
claimRequest.Metadata = JObject.FromObject(new
|
||||
{
|
||||
Source = $"Prism->Sideshift",
|
||||
SourceLink = $"https://sideshift.ai/orders/{shift.id}?openSupport=true",
|
||||
});
|
||||
return claimRequest;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (BOLT11PaymentRequest.TryParse(shift.depositAddress, out var bolt11, network.NBitcoinNetwork))
|
||||
{
|
||||
claimRequest.Destination = new BoltInvoiceClaimDestination(shift.depositAddress, bolt11);
|
||||
claimRequest.Metadata = JObject.FromObject(new
|
||||
{
|
||||
Source = $"Prism->Sideshift",
|
||||
SourceLink = $"https://sideshift.ai/orders/{shift.id}?openSupport=true",
|
||||
});
|
||||
return claimRequest;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Plugins.SideShift;
|
||||
|
||||
public class PrismDestinationValidate : IPluginHookFilter
|
||||
{
|
||||
public string Hook => "prism-destination-validate";
|
||||
public async Task<object> Execute(object args)
|
||||
{
|
||||
if (args is not string args1 || !args1.StartsWith("sideshift:")) return args;
|
||||
var json = JObject.Parse(args1.Substring("sideshift:".Length)).ToObject<PrismSideshiftDestination>();
|
||||
return json.Valid();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
namespace BTCPayServer.Plugins.SideShift;
|
||||
|
||||
public class PrismEditFilter : IPluginHookFilter
|
||||
{
|
||||
public string Hook => "prism-edit-buttons";
|
||||
|
||||
public Task<object> Execute(object args)
|
||||
{
|
||||
return Task.FromResult<object>(( args??"") + "<button type='button' class=\"btn btn-primary\" data-bs-toggle=\"modal\" data-bs-target=\"#sideshiftModal\">Generate SideShift destination</button>");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace BTCPayServer.Plugins.SideShift;
|
||||
|
||||
public class PrismSideshiftDestination
|
||||
{
|
||||
public string ShiftCoin { get; set; }
|
||||
public string ShiftNetwork { get; set; }
|
||||
public string ShiftDestination { get; set; }
|
||||
public string ShiftMemo { get; set; }
|
||||
public string SourceNetwork { get; set; }
|
||||
|
||||
public bool Valid()
|
||||
{
|
||||
return !string.IsNullOrEmpty(ShiftCoin) && !string.IsNullOrEmpty(ShiftNetwork) &&
|
||||
!string.IsNullOrEmpty(ShiftDestination);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payouts;
|
||||
using BTCPayServer.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -26,7 +27,7 @@ namespace BTCPayServer.Plugins.SideShift
|
||||
{
|
||||
private readonly SideShiftService _sideShiftService;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IEnumerable<IPayoutHandler> _payoutHandlers;
|
||||
private readonly PayoutMethodHandlerDictionary _payoutMethodHandlerDictionary;
|
||||
private readonly PullPaymentHostedService _pullPaymentHostedService;
|
||||
private readonly BTCPayNetworkJsonSerializerSettings _serializerSettings;
|
||||
private readonly ApplicationDbContextFactory _dbContextFactory;
|
||||
@@ -34,13 +35,13 @@ namespace BTCPayServer.Plugins.SideShift
|
||||
public SideShiftController(
|
||||
SideShiftService sideShiftService,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IEnumerable<IPayoutHandler> payoutHandlers,
|
||||
PayoutMethodHandlerDictionary payoutMethodHandlerDictionary,
|
||||
PullPaymentHostedService pullPaymentHostedService,
|
||||
BTCPayNetworkJsonSerializerSettings serializerSettings, ApplicationDbContextFactory dbContextFactory)
|
||||
{
|
||||
_sideShiftService = sideShiftService;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_payoutHandlers = payoutHandlers;
|
||||
_payoutMethodHandlerDictionary = payoutMethodHandlerDictionary;
|
||||
_pullPaymentHostedService = pullPaymentHostedService;
|
||||
_serializerSettings = serializerSettings;
|
||||
_dbContextFactory = dbContextFactory;
|
||||
@@ -111,19 +112,23 @@ namespace BTCPayServer.Plugins.SideShift
|
||||
ModelState.AddModelError(nameof(request.Amount), "Amount must be specified");
|
||||
}
|
||||
|
||||
if (!PaymentMethodId.TryParse(request.PaymentMethod, out var pmi))
|
||||
if (!PayoutMethodId.TryParse(request.PayoutMethodId, out var pmi))
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.PaymentMethod), "Invalid payment method");
|
||||
ModelState.AddModelError(nameof(request.PayoutMethodId), "Invalid payout method");
|
||||
}
|
||||
else
|
||||
{
|
||||
handler = _payoutHandlers.FindPayoutHandler(pmi);
|
||||
if (handler == null)
|
||||
if (!_payoutMethodHandlerDictionary.TryGetValue(pmi, out handler))
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.PaymentMethod), "Invalid payment method");
|
||||
ModelState.AddModelError(nameof(request.PayoutMethodId), "Invalid payment method");
|
||||
}
|
||||
}
|
||||
var isLN = pmi.ToString().EndsWith("-" +PayoutTypes.LN.Id);
|
||||
if (isLN)
|
||||
{
|
||||
|
||||
ModelState.AddModelError(nameof(request.PayoutMethodId), "SideShift does not support Lightning payouts");
|
||||
}
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return this.CreateValidationError(ModelState);
|
||||
@@ -166,13 +171,13 @@ namespace BTCPayServer.Plugins.SideShift
|
||||
// shiftResponse.EnsureSuccessStatusCode();
|
||||
// var shift = await shiftResponse.Content.ReadAsAsync<ShiftResponse>();
|
||||
|
||||
var cryptoCode = pmi.ToString().Split('-')[0];
|
||||
var shiftResponse = await client.PostAsJsonAsync("https://sideshift.ai/api/v2/shifts/variable", new
|
||||
{
|
||||
settleAddress = request.Destination,
|
||||
affiliateId = "qg0OrfHJV",
|
||||
settleMemo = request.Memo,
|
||||
depositCoin = pmi.CryptoCode,
|
||||
depositNetwork = pmi.PaymentType == LightningPaymentType.Instance ? "lightning" : null,
|
||||
depositCoin = cryptoCode,
|
||||
settleCoin = request.ShiftCurrency,
|
||||
settleNetwork = request.ShiftNetwork,
|
||||
}
|
||||
@@ -188,20 +193,20 @@ namespace BTCPayServer.Plugins.SideShift
|
||||
|
||||
|
||||
var destination =
|
||||
await handler.ParseAndValidateClaimDestination(pmi, shift.depositAddress, ppBlob,
|
||||
await handler.ParseAndValidateClaimDestination(shift.depositAddress, ppBlob,
|
||||
CancellationToken.None);
|
||||
|
||||
var claim = await _pullPaymentHostedService.Claim(new ClaimRequest()
|
||||
{
|
||||
PullPaymentId = pullPaymentId,
|
||||
Destination = destination.destination,
|
||||
PaymentMethodId = pmi,
|
||||
PayoutMethodId = pmi,
|
||||
Value = request.Amount
|
||||
});
|
||||
if (claim.Result == ClaimRequest.ClaimResult.Ok)
|
||||
{
|
||||
await using var ctx = _dbContextFactory.CreateContext();
|
||||
ppBlob.Description += $"<br/>The payout of {claim.PayoutData.Destination} will be forwarded to SideShift.ai for further conversion. Please go to <a href=\"https://sideshift.ai/orders/{shift.id}?openSupport=true\">the order page</a> for support.";
|
||||
ppBlob.Description += $"<br/>The payout of {destination.destination} will be forwarded to SideShift.ai for further conversion. Please go to <a href=\"https://sideshift.ai/orders/{shift.id}?openSupport=true\">the order page</a> for support.";
|
||||
pp.SetBlob(ppBlob);
|
||||
ctx.Attach(pp).State = EntityState.Modified;
|
||||
await ctx.SaveChangesAsync();
|
||||
@@ -242,19 +247,21 @@ namespace BTCPayServer.Plugins.SideShift
|
||||
private Client.Models.PayoutData ToModel(Data.PayoutData p)
|
||||
{
|
||||
var blob = p.GetBlob(_serializerSettings);
|
||||
var model = new Client.Models.PayoutData
|
||||
var model = new Client.Models.PayoutData()
|
||||
{
|
||||
Id = p.Id,
|
||||
PullPaymentId = p.PullPaymentDataId,
|
||||
Date = p.Date,
|
||||
Amount = blob.Amount,
|
||||
PaymentMethodAmount = blob.CryptoAmount,
|
||||
OriginalCurrency = p.OriginalCurrency,
|
||||
OriginalAmount = p.OriginalAmount,
|
||||
PayoutCurrency = p.Currency,
|
||||
PayoutAmount = p.Amount,
|
||||
Revision = blob.Revision,
|
||||
State = p.State,
|
||||
PayoutMethodId = p.PayoutMethodId,
|
||||
PaymentProof = p.GetProofBlobJson(),
|
||||
Destination = blob.Destination,
|
||||
PaymentMethod = p.PaymentMethodId,
|
||||
CryptoCode = p.GetPaymentMethodId().CryptoCode,
|
||||
PaymentProof = p.GetProofBlobJson()
|
||||
Metadata = blob.Metadata?? new JObject(),
|
||||
};
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Abstractions.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace BTCPayServer.Plugins.SideShift
|
||||
@@ -8,41 +7,22 @@ namespace BTCPayServer.Plugins.SideShift
|
||||
public class SideShiftPlugin : BaseBTCPayServerPlugin
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=1.12.0"}
|
||||
{ new() { Identifier = nameof(BTCPayServer), Condition = ">=2.0.0" }
|
||||
|
||||
};
|
||||
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
{
|
||||
applicationBuilder.AddSingleton<SideShiftService>();
|
||||
applicationBuilder.AddHostedService(provider => provider.GetService<SideShiftService>());
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("SideShift/SideShiftNav",
|
||||
"store-integrations-nav"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("SideShift/PullPaymentViewInsert",
|
||||
"pullpayment-foot"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("SideShift/StoreIntegrationSideShiftOption",
|
||||
"store-integrations-list"));
|
||||
|
||||
applicationBuilder.AddUIExtension("store-integrations-nav","SideShift/SideShiftNav");
|
||||
applicationBuilder.AddUIExtension("pullpayment-foot","SideShift/PullPaymentViewInsert");
|
||||
applicationBuilder.AddUIExtension("store-integrations-list", "SideShift/StoreIntegrationSideShiftOption");
|
||||
// Checkout v2
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("SideShift/CheckoutPaymentMethodExtension",
|
||||
"checkout-payment-method"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("SideShift/CheckoutPaymentExtension",
|
||||
"checkout-payment"));
|
||||
// Checkout Classic
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("SideShift/CheckoutContentExtension",
|
||||
"checkout-bitcoin-post-content"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("SideShift/CheckoutContentExtension",
|
||||
"checkout-lightning-post-content"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("SideShift/CheckoutTabExtension",
|
||||
"checkout-bitcoin-post-tabs"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("SideShift/CheckoutTabExtension",
|
||||
"checkout-lightning-post-tabs"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("SideShift/CheckoutEnd",
|
||||
"checkout-end"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("SideShift/PrismEnhance",
|
||||
"prism-edit"));
|
||||
applicationBuilder.AddSingleton<IPluginHookFilter, PrismDestinationValidate>();
|
||||
applicationBuilder.AddSingleton<IPluginHookFilter, PrismClaimCreate>();
|
||||
applicationBuilder.AddSingleton<IPluginHookFilter, PrismEditFilter>();
|
||||
applicationBuilder.AddUIExtension("checkout-payment-method", "SideShift/CheckoutPaymentMethodExtension");
|
||||
applicationBuilder.AddUIExtension("checkout-payment","SideShift/CheckoutPaymentExtension");
|
||||
|
||||
base.Execute(applicationBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
@using BTCPayServer.Plugins.SideShift
|
||||
@inject SideShiftService SideShiftService
|
||||
@model BTCPayServer.Models.InvoicingModels.PaymentModel
|
||||
|
||||
@{
|
||||
var settings = await SideShiftService.GetSideShiftForInvoice(Model.InvoiceId, Model.StoreId);
|
||||
|
||||
if (settings?.Enabled is true)
|
||||
{
|
||||
<div id="sideshift" class="bp-view payment manual-flow" :class="{ active: currentTab == 'undefined' || currentTab == 'sideshift' }">
|
||||
<div class="manual__step-two__instructions">
|
||||
<span>
|
||||
{{$t("ConversionTab_BodyTop", srvModel)}}
|
||||
<br/><br/>
|
||||
{{$t("ConversionTab_BodyDesc", srvModel)}}
|
||||
</span>
|
||||
</div>
|
||||
<side-shift inline-template
|
||||
:to-currency="srvModel.paymentMethodId"
|
||||
:to-currency-due="srvModel.btcDue * (1 + (@settings.AmountMarkupPercentage / 100)) "
|
||||
:to-currency-address="srvModel.btcAddress">
|
||||
<a v-on:click="openDialog($event)" href="#" class="action-button btn btn-secondary rounded-pill w-100 mt-4">{{$t("Pay with SideShift")}}</a>
|
||||
</side-shift>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
@using BTCPayServer.Plugins.SideShift
|
||||
@inject BTCPayServer.Security.ContentSecurityPolicies csp
|
||||
@inject SideShiftService SideShiftService
|
||||
@model BTCPayServer.Models.InvoicingModels.PaymentModel
|
||||
@{
|
||||
var settings = await SideShiftService.GetSideShiftForInvoice(Model.InvoiceId, Model.StoreId);
|
||||
if (settings?.Enabled is true)
|
||||
{
|
||||
csp.Add("script-src", "https://sideshift.ai");
|
||||
csp.Add("script-src", "*.sideshift.ai");
|
||||
<script src="~/Resources/js/sideShiftComponent.js"></script>
|
||||
<script src="https://sideshift.ai/static/js/main.js" defer></script>
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,18 @@
|
||||
@using BTCPayServer.Payments
|
||||
@inject BTCPayServer.Security.ContentSecurityPolicies csp
|
||||
@inject SideShiftService SideShiftService
|
||||
@model BTCPayServer.Models.InvoicingModels.PaymentModel
|
||||
@model BTCPayServer.Models.InvoicingModels.CheckoutModel
|
||||
@{
|
||||
var settings = await SideShiftService.GetSideShiftForInvoice(Model.InvoiceId, Model.StoreId);
|
||||
var preferredTargetPaymentMethodId = "";
|
||||
PaymentMethodId preferredTargetPaymentMethodId = null;
|
||||
if(!PaymentMethodId.TryParse(settings?.PreferredTargetPaymentMethodId, out var preferredPMI))
|
||||
{
|
||||
preferredTargetPaymentMethodId = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
preferredTargetPaymentMethodId = Model.AvailableCryptos.FirstOrDefault(crypto =>
|
||||
crypto.PaymentMethodId == settings.PreferredTargetPaymentMethodId ||
|
||||
(crypto.CryptoCode == preferredPMI.CryptoCode && crypto.PaymentMethodId.EndsWith(LNURLPayPaymentType.Instance.GetId()) || crypto.PaymentMethodId.EndsWith(LightningPaymentType.Instance.GetId())))?.PaymentMethodId;
|
||||
preferredTargetPaymentMethodId = Model.AvailablePaymentMethods.FirstOrDefault(crypto =>
|
||||
crypto.PaymentMethodId == preferredPMI )?.PaymentMethodId;
|
||||
}
|
||||
}
|
||||
@if (settings?.Enabled is true)
|
||||
@@ -25,7 +24,8 @@
|
||||
<template id="side-shift-checkout-template">
|
||||
<div class="payment-box">
|
||||
<p v-html="content"></p>
|
||||
<button type="button" v-on:click="openDialog" class="btn btn-primary rounded-pill w-100">{{$t("Pay with SideShift")}}</button>
|
||||
<p v-if="!settleMethodId" class="text-danger">Lightning is not supported via Sideshift. Select another payment method first, then come back.</p>
|
||||
<button v-if="settleMethodId" type="button" v-on:click="openDialog" class="btn btn-primary rounded-pill w-100">{{$t("Pay with SideShift", {crryptoCode: settleMethodId})}}</button>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -48,7 +48,7 @@
|
||||
},200)
|
||||
|
||||
if(this.preferredToCurrency && this.model.paymentMethodId !== this.preferredToCurrency){
|
||||
if (this.model.onChainWithLnInvoiceFallback && this.model.paymentMethodId === "BTC"){
|
||||
if (this.model.onChainWithLnInvoiceFallback && this.model.paymentMethodId === "BTC-CHAIN"){
|
||||
return;
|
||||
}
|
||||
this.$parent.paymentMethodId = this.preferredToCurrency;
|
||||
@@ -58,16 +58,7 @@
|
||||
|
||||
},
|
||||
computed: {
|
||||
lightning () {
|
||||
if (!this.model.onChainWithLnInvoiceFallback || this.model.paymentMethodId !== "BTC"){
|
||||
return null;
|
||||
}
|
||||
const index = this.model.invoiceBitcoinUrl.indexOf("lightning=");
|
||||
if (index === -1){
|
||||
return null;
|
||||
}
|
||||
return this.model.invoiceBitcoinUrl.slice(index + "lightning=".length);
|
||||
},
|
||||
|
||||
content () {
|
||||
return this.$i18n.i18next.t("conversion_body", this.model).replace(/\n/ig, '<br>');
|
||||
},
|
||||
@@ -76,16 +67,16 @@
|
||||
},
|
||||
settleMethodId () {
|
||||
|
||||
const toCurrency = this.currency.toLowerCase();
|
||||
const toCurrency = this.currency.toUpperCase();
|
||||
|
||||
if (toCurrency === "lbtc") {
|
||||
return 'liquid';
|
||||
} else if (toCurrency === "usdt") {
|
||||
return "usdtla";
|
||||
} else if (toCurrency.endsWith('lightninglike') || toCurrency.endsWith('lnurlpay') || this.lightning) {
|
||||
return "ln";
|
||||
} else if (toCurrency.endsWith('LN') || toCurrency.endsWith('LNURL')) {
|
||||
return null;
|
||||
} else {
|
||||
return toCurrency.replace('_btclike', '').replace('_monerolike', '').replace('_zcashlike', '').toLowerCase();
|
||||
return toCurrency.replace('-CHAIN', '').replace('_CHAIN', '').toLowerCase();
|
||||
}
|
||||
},
|
||||
type () {
|
||||
@@ -96,16 +87,19 @@
|
||||
amountDue () {
|
||||
return this.model.isUnsetTopUp
|
||||
? undefined
|
||||
: this.model.btcDue * (1 + (@settings.AmountMarkupPercentage / 100));
|
||||
: this.model.due * (1 + (@settings.AmountMarkupPercentage / 100));
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openDialog () {
|
||||
if (!this.settleMethodId){
|
||||
return;
|
||||
}
|
||||
window.__SIDESHIFT__ = {
|
||||
parentAffiliateId: "qg0OrfHJV",
|
||||
defaultDepositMethodId: this.explicitId || undefined,
|
||||
defaultSettleMethodId: this.settleMethodId,
|
||||
settleAddress: this.lightning || this.model.btcAddress,
|
||||
settleAddress: this.model.address,
|
||||
settleAmount: this.amountDue,
|
||||
type: this.type
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@using BTCPayServer.Plugins.SideShift
|
||||
@inject SideShiftService SideShiftService
|
||||
@model BTCPayServer.Models.InvoicingModels.PaymentModel
|
||||
@model BTCPayServer.Models.InvoicingModels.CheckoutModel
|
||||
@{
|
||||
const string id = "SideShift";
|
||||
var settings = await SideShiftService.GetSideShiftForInvoice(Model.InvoiceId, Model.StoreId);
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
@using BTCPayServer.Plugins.SideShift
|
||||
@inject SideShiftService SideShiftService
|
||||
@model BTCPayServer.Models.InvoicingModels.PaymentModel
|
||||
@{
|
||||
var settings = await SideShiftService.GetSideShiftForInvoice(Model.InvoiceId, Model.StoreId);
|
||||
if (settings?.Enabled is true)
|
||||
{
|
||||
<div class="payment-tabs__tab py-0" id="sideshift-tab" v-on:click="switchTab('sideshift')" v-bind:class="{ 'active': currentTab == 'sideshift'}" v-if="!srvModel.paymentMethodId.endsWith('LNURLPAY')">
|
||||
<span>{{$t("Altcoins (SideShift)")}}</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
@using BTCPayServer.Abstractions.TagHelpers
|
||||
@using BTCPayServer.Plugins.SideShift
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@inject SideShiftService SideShiftService
|
||||
@{
|
||||
|
||||
var coins = await SideShiftService.GetSettleCoins();
|
||||
coins = coins.Where(tuple => new[] {SideShiftService.CoinType.VariableOnly, SideShiftService.CoinType.Both}.Contains(tuple.Type)).ToList();
|
||||
if(coins.Any() is not true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
<script>
|
||||
|
||||
const ssAvailableCoins = @Json.Serialize(coins.ToDictionary(tuple=> $"{tuple.CryptoCode}_{tuple.Network}",tuple =>
|
||||
new {
|
||||
coin = tuple.DisplayName,
|
||||
code = tuple.CryptoCode,
|
||||
memo = tuple.HasMemo,
|
||||
network = tuple.Network
|
||||
}));
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
if (new URLSearchParams(window.location.search).has("hidejunk")) {
|
||||
localStorage.setItem('hidejunk', 'true');
|
||||
}
|
||||
if(localStorage.getItem("hidejunk")) {
|
||||
|
||||
[...document.querySelectorAll("#sscoin option")].forEach(option => {
|
||||
const text = option.innerText.toLowerCase();
|
||||
|
||||
// Check if the option matches the criteria
|
||||
const isMatch = (text.includes("bitcoin") || text.includes("tether") || text.includes("usd")) &&
|
||||
!text.includes("bitcoincash");
|
||||
|
||||
// If it matches, show it; otherwise, hide it
|
||||
//remove it
|
||||
if (!isMatch)
|
||||
option.remove();
|
||||
});
|
||||
}
|
||||
// const sideshiftDestinationButton = document.createElement("button");
|
||||
// sideshiftDestinationButton.type= "button";
|
||||
// sideshiftDestinationButton.className = "btn btn-primary btn-sm";
|
||||
// sideshiftDestinationButton.innerText = "Generate SideShift destination";
|
||||
// document.getElementById("add-prism").insertAdjacentElement("afterend", sideshiftDestinationButton);
|
||||
|
||||
// const modal = new bootstrap.Modal('#sideshiftModal');
|
||||
// sideshiftDestinationButton.addEventListener("click", ev => modal.show());
|
||||
const selectedSideShiftCoin = document.getElementById("sscoin");
|
||||
const specifiedSideShiftDestination = document.getElementById("ssdest");
|
||||
const specifiedSideShiftDepositNetwork = document.getElementById("ssdepositNetwork");
|
||||
const specifiedSideShiftMemo= document.getElementById("ssmemo");
|
||||
const shiftButton = document.getElementById("ssshift");
|
||||
let selectedCoin = null;
|
||||
const destinationContainer = document.getElementById("ss-dest-info");
|
||||
specifiedSideShiftDestination.addEventListener("input", ev1 => {
|
||||
|
||||
document.getElementById("ss-result").style.display = "none";
|
||||
if (isValid()){
|
||||
shiftButton.removeAttribute("disabled");
|
||||
}
|
||||
});
|
||||
specifiedSideShiftMemo.addEventListener("input", ev1 => {
|
||||
if (isValid()){
|
||||
shiftButton.removeAttribute("disabled");
|
||||
}else{
|
||||
shiftButton.setAttribute("disabled", "disabled");
|
||||
}
|
||||
});
|
||||
isValid = ()=>{
|
||||
return selectedCoin && specifiedSideShiftDestination.value &&
|
||||
(!selectedCoin.memo || specifiedSideShiftMemo.value);
|
||||
};
|
||||
handleSelectChanges = ()=>{
|
||||
if (selectedSideShiftCoin.value){
|
||||
selectedCoin = ssAvailableCoins[selectedSideShiftCoin.value];
|
||||
destinationContainer.style.display = "block";
|
||||
if (selectedCoin){
|
||||
specifiedSideShiftMemo.parentElement.style.display = selectedCoin.memo ? "block" : "none";
|
||||
specifiedSideShiftMemo.value = selectedCoin.memo ? specifiedSideShiftMemo.value : "";
|
||||
}
|
||||
}else{
|
||||
destinationContainer.style.display = "none";
|
||||
}
|
||||
};
|
||||
selectedSideShiftCoin.addEventListener("change", ev1 => {
|
||||
handleSelectChanges();
|
||||
});
|
||||
shiftButton.addEventListener("click", ev1 => {
|
||||
|
||||
document.getElementById("ss-server-errors").innerHTML = "";
|
||||
document.getElementById("ss-result-txt").value = "";
|
||||
document.getElementById("ss-result-additional-info").value = "";
|
||||
if (isValid()){
|
||||
shiftButton.setAttribute("disabled", "disabled");
|
||||
const type = "permanent";
|
||||
|
||||
if (type ==="permanent"){
|
||||
fetch("https://sideshift.ai/api/v2/shifts/variable",{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
settleAddress: specifiedSideShiftDestination.value,
|
||||
settleMemo: specifiedSideShiftMemo.value,
|
||||
affiliateId: "qg0OrfHJV",
|
||||
depositCoin : "BTC",
|
||||
depositNetwork : specifiedSideShiftDepositNetwork.value,
|
||||
settleCoin: selectedCoin.code,
|
||||
settleNetwork: selectedCoin.network,
|
||||
permanent: true
|
||||
})})
|
||||
.then(async response => {
|
||||
if (!response.ok){
|
||||
try {
|
||||
document.getElementById("ss-server-errors").innerHTML = (await response.json())["error"]["message"];
|
||||
}catch{
|
||||
document.getElementById("ss-server-errors").innerHTML = JSON.stringify((await response.json()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
const shift = await response.json();
|
||||
document.getElementById("ss-result").style.display = "block";
|
||||
document.getElementById("ss-result-txt").value = shift.depositAddress;
|
||||
const link = `https://sideshift.ai/orders/${shift.id}`;
|
||||
document.getElementById("ss-result-additional-info").innerHTML = "<b>IMPORTANT:</b> You must keep this link to be able to recover your funds in case of a problem. <a href='"+link+"' target='_blank'>"+link+"</a> ";
|
||||
|
||||
})
|
||||
.catch(error => document.getElementById("ss-server-errors").innerHTML = error)
|
||||
.finally(() => shiftButton.removeAttribute("disabled"));
|
||||
}else{
|
||||
document.getElementById("ss-result").style.display = "block";
|
||||
document.getElementById("ss-result-txt").value = "sideshift:"+JSON.stringify({
|
||||
shiftCoin:selectedCoin.code,
|
||||
shiftNetwork: selectedCoin.network,
|
||||
shiftDestination: specifiedSideShiftDestination.value,
|
||||
shiftMemo: specifiedSideShiftMemo.value,
|
||||
shiftDepositNetwork: specifiedSideShiftDepositNetwork.value
|
||||
});
|
||||
shiftButton.removeAttribute("disabled");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
handleSelectChanges();
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="modal" tabindex="-1" id="sideshiftModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Generate SideShift destination</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div id="ss-server-errors" class="text-danger"></div>
|
||||
<p>This will generate a piece of code based on Sideshift configuration that can work as a valid destination in prism. Prism will then generate a "shift" on Sideshift and send the funds through LN to it, and Sideshift will send you the conversion. </p>
|
||||
<div class="form-group">
|
||||
<label class="form-label">How do you want to send BTC to SideShift?</label>
|
||||
<select id="ssdepositNetwork" class="form-select">
|
||||
<option value="lightning">Lightning</option>
|
||||
<option value="bitcoin">On-Chain</option>
|
||||
</select>
|
||||
</div><div class="form-group">
|
||||
<label class="form-label">Which coin should Sideshift send you</label>
|
||||
<select id="sscoin" class="form-select">
|
||||
@foreach (var opt in coins)
|
||||
{
|
||||
<option value="@($"{opt.CryptoCode}_{opt.Network}")">@opt.ToString()</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div id="ss-dest-info" style="display: none">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Destination</label>
|
||||
<input type="text" id="ssdest" class="form-control"/>
|
||||
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Memo</label>
|
||||
<input type="text" id="ssmemo" class="form-control"/>
|
||||
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-primary" id="ssshift" disabled="disabled">Generate code</button>
|
||||
|
||||
<div id="ss-result" class="form-group mt-4" style="display: none;">
|
||||
<label class="form-label">Generated code</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="ss-result-txt" class="form-control" readonly="readonly"/>
|
||||
<button type="button" class="btn btn-secondary" data-clipboard-target="#ss-result-txt">
|
||||
<vc:icon symbol="copy"/>
|
||||
</button>
|
||||
</div>
|
||||
<p id="ss-result-additional-info"></p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,4 +1,5 @@
|
||||
@using BTCPayServer.Plugins.SideShift
|
||||
@using BTCPayServer.Payouts
|
||||
@using BTCPayServer.Plugins.SideShift
|
||||
@model BTCPayServer.Models.ViewPullPaymentModel
|
||||
@inject SideShiftService SideShiftService
|
||||
@{
|
||||
@@ -14,7 +15,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
var potentialPaymentMethods = Model.PaymentMethods;//.Where(id => id.CryptoCode.Equals(Model.Currency, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var potentialPaymentMethods = Model.PayoutMethodIds.ToList();//.Where(id => id.CryptoCode.Equals(Model.Currency, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
potentialPaymentMethods.Remove(PayoutTypes.LN.GetPayoutMethodId("BTC"));
|
||||
if (Model.IsPending && potentialPaymentMethods.Any())
|
||||
{
|
||||
<script>
|
||||
@@ -26,7 +28,7 @@
|
||||
memo = tuple.HasMemo,
|
||||
network = tuple.Network
|
||||
}));
|
||||
const ssPaymentMethods = @Json.Serialize(potentialPaymentMethods.Select(id => new { id = id.ToString(), name= id.ToPrettyString()}));
|
||||
const ssPaymentMethods = @Json.Serialize(potentialPaymentMethods.Select(id => new { id = id.ToString(), name= id.ToString()}));
|
||||
document.addEventListener("DOMContentLoaded", ev => {
|
||||
const ssButton = document.createElement("button");
|
||||
ssButton.type= "button";
|
||||
@@ -142,7 +144,7 @@
|
||||
<select id="sspmi" class="form-select">
|
||||
@foreach (var opt in potentialPaymentMethods)
|
||||
{
|
||||
<option value="@opt.ToString()">@opt.ToPrettyString()</option>
|
||||
<option value="@opt.ToString()">@opt.ToString()</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
@using BTCPayServer.Plugins.SideShift
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@model BTCPayServer.Plugins.SideShift.SideShiftSettings
|
||||
@inject BTCPayNetworkProvider BTCPayNetworkProvider
|
||||
@inject SideShiftService SideShiftService
|
||||
@{
|
||||
ViewData.SetActivePage("SideShift", "SideShift", "SideShift");
|
||||
var store = Context.GetStoreData();
|
||||
var allowedPaymentMethods = store.GetEnabledPaymentIds(BTCPayNetworkProvider)
|
||||
.Select(pmi => new SelectListItem(pmi.ToPrettyString(), pmi.ToString()))
|
||||
var allowedPaymentMethods = store.GetEnabledPaymentIds()
|
||||
.Where(id => !id.ToString().EndsWith("LN") && !id.ToString().EndsWith("LNURL"))
|
||||
.Select(pmi => new SelectListItem(pmi.ToString(), pmi.ToString()))
|
||||
|
||||
.Prepend(new SelectListItem("Any", ""));
|
||||
var coins = await SideShiftService.GetDepositOptions();
|
||||
var allowedCoins = coins.OrderBy(coin => coin.ToString()).Select(c => new SelectListItem(c.ToString(), $"{c.CryptoCode}_{c.Network}"));
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Subscriptions</Product>
|
||||
<Description>Offer and manage subscriptions through BTCPay Server</Description>
|
||||
<Version>1.0.1</Version>
|
||||
<Version>1.0.2</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer;
|
||||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Plugins.Subscriptions;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Apps;
|
||||
using BTCPayServer.Services.PaymentRequests;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@@ -23,13 +22,16 @@ namespace BTCPayServer.Plugins.Subscriptions;
|
||||
public class SubscriptionController : Controller
|
||||
{
|
||||
private readonly AppService _appService;
|
||||
private readonly UriResolver _uriResolver;
|
||||
private readonly PaymentRequestRepository _paymentRequestRepository;
|
||||
private readonly SubscriptionService _subscriptionService;
|
||||
|
||||
public SubscriptionController(AppService appService,
|
||||
UriResolver uriResolver,
|
||||
PaymentRequestRepository paymentRequestRepository, SubscriptionService subscriptionService)
|
||||
{
|
||||
_appService = appService;
|
||||
_uriResolver = uriResolver;
|
||||
_paymentRequestRepository = paymentRequestRepository;
|
||||
_subscriptionService = subscriptionService;
|
||||
}
|
||||
@@ -44,7 +46,7 @@ public class SubscriptionController : Controller
|
||||
return NotFound();
|
||||
var ss = app.GetSettings<SubscriptionAppSettings>();
|
||||
ss.SubscriptionName = app.Name;
|
||||
ViewData["StoreBranding"] = new StoreBrandingViewModel(app.StoreData.GetStoreBlob());
|
||||
ViewData["StoreBranding"] =await StoreBrandingViewModel.CreateAsync(Request, _uriResolver, app.StoreData.GetStoreBlob());
|
||||
return View(ss);
|
||||
}
|
||||
|
||||
@@ -62,8 +64,7 @@ public class SubscriptionController : Controller
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
ViewData["StoreBranding"] = new StoreBrandingViewModel(app.StoreData.GetStoreBlob());
|
||||
ViewData["StoreBranding"] =await StoreBrandingViewModel.CreateAsync(Request, _uriResolver, app.StoreData.GetStoreBlob());
|
||||
|
||||
return View(ss);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Abstractions.Services;
|
||||
using BTCPayServer.HostedServices.Webhooks;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Apps;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -18,12 +16,11 @@ namespace BTCPayServer.Plugins.Subscriptions
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
[
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=1.13.0"}
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=2.0.0"}
|
||||
];
|
||||
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
{
|
||||
|
||||
applicationBuilder.AddSingleton<ISwaggerProvider, SubscriptionsSwaggerProvider>();
|
||||
applicationBuilder.AddSingleton<SubscriptionService>();
|
||||
applicationBuilder.AddSingleton<IWebhookProvider>(o => o.GetRequiredService<SubscriptionService>());
|
||||
@@ -35,19 +32,17 @@ namespace BTCPayServer.Plugins.Subscriptions
|
||||
}
|
||||
}
|
||||
|
||||
public class SubscriptionsSwaggerProvider: ISwaggerProvider
|
||||
public class SubscriptionsSwaggerProvider : ISwaggerProvider
|
||||
{
|
||||
private readonly IFileProvider _fileProvider;
|
||||
|
||||
public SubscriptionsSwaggerProvider(IWebHostEnvironment webHostEnvironment)
|
||||
{
|
||||
|
||||
_fileProvider = webHostEnvironment.WebRootFileProvider;
|
||||
}
|
||||
|
||||
public async Task<JObject> Fetch()
|
||||
{
|
||||
|
||||
var file = _fileProvider.GetFileInfo("Resources/swagger.subscriptions.json");
|
||||
using var reader = new StreamReader(file.CreateReadStream());
|
||||
return JObject.Parse(await reader.ReadToEndAsync());
|
||||
|
||||
@@ -48,10 +48,10 @@ public class AppMigrate : IStartupTask
|
||||
await using var ctx = _contextFactory.CreateContext();
|
||||
var invoices = await ctx.Invoices
|
||||
.Include(data => data.InvoiceSearchData)
|
||||
.Where(data => data.StoreDataId == setting.Key && data.OrderId == "tickettailor").ToListAsync(cancellationToken: cancellationToken);
|
||||
.Where(data => data.StoreDataId == setting.Key && data.InvoiceSearchData.Any(searchData => searchData.Value == "tickettailor")).ToListAsync(cancellationToken: cancellationToken);
|
||||
foreach (var invoice in invoices)
|
||||
{
|
||||
var entity = invoice.GetBlob(_btcPayNetworkProvider);
|
||||
var entity = invoice.GetBlob();
|
||||
entity.Metadata.SetAdditionalData("appId", app.Id);
|
||||
entity.InternalTags.Add(AppService.GetAppInternalTag(app.Id));
|
||||
InvoiceRepository.AddToTextSearch(ctx, invoice, AppService.GetAppSearchTerm(app) );
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>TicketTailor</Product>
|
||||
<Description>Allows you to integrate with TicketTailor.com to sell tickets for Bitcoin</Description>
|
||||
<Version>2.0.3</Version>
|
||||
<Version>2.0.4</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<!-- Plugin development properties -->
|
||||
|
||||
@@ -12,6 +12,7 @@ using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Controllers;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Apps;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@@ -28,6 +29,7 @@ namespace BTCPayServer.Plugins.TicketTailor
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly TicketTailorService _ticketTailorService;
|
||||
private readonly UriResolver _uriResolver;
|
||||
private readonly AppService _appService;
|
||||
private readonly ApplicationDbContextFactory _contextFactory;
|
||||
private readonly InvoiceRepository _invoiceRepository;
|
||||
@@ -35,6 +37,7 @@ namespace BTCPayServer.Plugins.TicketTailor
|
||||
|
||||
public TicketTailorController(IHttpClientFactory httpClientFactory,
|
||||
TicketTailorService ticketTailorService,
|
||||
UriResolver uriResolver,
|
||||
AppService appService,
|
||||
ApplicationDbContextFactory contextFactory,
|
||||
InvoiceRepository invoiceRepository,
|
||||
@@ -42,6 +45,7 @@ namespace BTCPayServer.Plugins.TicketTailor
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_ticketTailorService = ticketTailorService;
|
||||
_uriResolver = uriResolver;
|
||||
_appService = appService;
|
||||
_contextFactory = contextFactory;
|
||||
_invoiceRepository = invoiceRepository;
|
||||
@@ -87,7 +91,7 @@ namespace BTCPayServer.Plugins.TicketTailor
|
||||
return View(new TicketTailorViewModel()
|
||||
{
|
||||
Event = evt, Settings = config,
|
||||
StoreBranding = new StoreBrandingViewModel(app.StoreData.GetStoreBlob())
|
||||
StoreBranding = await StoreBrandingViewModel.CreateAsync(Request, _uriResolver, app.StoreData.GetStoreBlob())
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -270,7 +274,6 @@ namespace BTCPayServer.Plugins.TicketTailor
|
||||
AdditionalSearchTerms = new[] {"tickettailor", hold.Value.Item1.Id, evt.Id, AppService.GetAppSearchTerm(app)},
|
||||
Checkout =
|
||||
{
|
||||
RequiresRefundEmail = true,
|
||||
RedirectAutomatically = price > 0,
|
||||
RedirectURL = redirectUrl,
|
||||
},
|
||||
@@ -292,13 +295,13 @@ namespace BTCPayServer.Plugins.TicketTailor
|
||||
|
||||
}, app.StoreData, HttpContext.Request.GetAbsoluteRoot(),new List<string> { AppService.GetAppInternalTag(appId) }, CancellationToken.None);
|
||||
|
||||
while (inv.Price == 0 && inv.Status == InvoiceStatusLegacy.New)
|
||||
while (inv.Price == 0 && inv.Status == InvoiceStatus.New)
|
||||
{
|
||||
if (inv.Status == InvoiceStatusLegacy.New)
|
||||
if (inv.Status == InvoiceStatus.New)
|
||||
inv = await _invoiceRepository.GetInvoice(inv.Id);
|
||||
}
|
||||
|
||||
return inv.Status.ToModernStatus() == InvoiceStatus.Settled
|
||||
return inv.Status == InvoiceStatus.Settled
|
||||
? RedirectToAction("Receipt", new {invoiceId = inv.Id})
|
||||
: RedirectToAction("Checkout", "UIInvoice", new {invoiceId = inv.Id});
|
||||
}
|
||||
@@ -342,13 +345,13 @@ namespace BTCPayServer.Plugins.TicketTailor
|
||||
var appId = AppService.GetAppInternalTags(inv).First();
|
||||
|
||||
var result = new TicketReceiptPage() {InvoiceId = invoiceId};
|
||||
result.Status = inv.Status.ToModernStatus();
|
||||
result.Status = inv.Status;
|
||||
if (result.Status == InvoiceStatus.Settled &&
|
||||
inv.Metadata.AdditionalData.TryGetValue("ticketIds", out var ticketIds))
|
||||
{
|
||||
await SetTicketTailorTicketResult(appId, result, ticketIds.Values<string>());
|
||||
}
|
||||
else if (inv.Status.ToModernStatus() == InvoiceStatus.Settled)
|
||||
else if (inv.Status == InvoiceStatus.Settled)
|
||||
{
|
||||
await _ticketTailorService.CheckAndIssueTicket(inv.Id);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace BTCPayServer.Plugins.TicketTailor
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=1.12.0"}
|
||||
new() {Identifier = nameof(BTCPayServer), Condition = ">=2.0.0"}
|
||||
};
|
||||
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
|
||||
@@ -101,8 +101,7 @@ public class TicketTailorService : EventHostedServiceBase, IWebhookProvider
|
||||
!new[]
|
||||
{
|
||||
InvoiceStatus.Settled, InvoiceStatus.Expired, InvoiceStatus.Invalid
|
||||
}.Contains(invoiceEvent.Invoice.GetInvoiceState().Status
|
||||
.ToModernStatus()):
|
||||
}.Contains(invoiceEvent.Invoice.GetInvoiceState().Status):
|
||||
return;
|
||||
case InvoiceEvent invoiceEvent:
|
||||
|
||||
@@ -157,7 +156,7 @@ public class TicketTailorService : EventHostedServiceBase, IWebhookProvider
|
||||
return;
|
||||
}
|
||||
|
||||
if (new[] {InvoiceStatus.Invalid, InvoiceStatus.Expired}.Contains(invoice.Status.ToModernStatus()))
|
||||
if (new[] {InvoiceStatus.Invalid, InvoiceStatus.Expired}.Contains(invoice.Status))
|
||||
{
|
||||
|
||||
if (invoice.Metadata.AdditionalData.TryGetValue("holdId", out var jHoldIdx) &&
|
||||
@@ -178,7 +177,7 @@ public class TicketTailorService : EventHostedServiceBase, IWebhookProvider
|
||||
return;
|
||||
}
|
||||
|
||||
if (invoice.Status.ToModernStatus() != InvoiceStatus.Settled)
|
||||
if (invoice.Status != InvoiceStatus.Settled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Coinjoin</Product>
|
||||
<Description>Allows you to integrate your btcpayserver store with coinjoins.</Description>
|
||||
<Version>1.0.100</Version>
|
||||
<Version>1.0.101</Version>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ using BTCPayServer.Data;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.PayJoin;
|
||||
using BTCPayServer.Payouts;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using LinqKit;
|
||||
@@ -37,12 +39,14 @@ using WalletWasabi.WabiSabi.Backend.Rounds;
|
||||
using WalletWasabi.WabiSabi.Client;
|
||||
using WalletWasabi.Wallets;
|
||||
using LogLevel = WalletWasabi.Logging.LogLevel;
|
||||
using SecureRandom = WalletWasabi.Crypto.Randomness.SecureRandom;
|
||||
|
||||
namespace BTCPayServer.Plugins.Wabisabi;
|
||||
|
||||
|
||||
public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
{
|
||||
private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary;
|
||||
private readonly WalletRepository _walletRepository;
|
||||
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
|
||||
private readonly BitcoinLikePayoutHandler _bitcoinLikePayoutHandler;
|
||||
@@ -56,6 +60,7 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
public static readonly BlockchainAnalyzer BlockchainAnalyzer = new();
|
||||
|
||||
public BTCPayWallet(
|
||||
PaymentMethodHandlerDictionary paymentMethodHandlerDictionary,
|
||||
WalletRepository walletRepository,
|
||||
BTCPayNetworkProvider btcPayNetworkProvider,
|
||||
BitcoinLikePayoutHandler bitcoinLikePayoutHandler,
|
||||
@@ -75,6 +80,7 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
WalletId = new WalletWasabi.Wallets.WalletId(new Guid(SHA256.HashData(Encoding.UTF8.GetBytes(storeId)).Take(16)
|
||||
.ToArray()));
|
||||
KeyChain = keyChain;
|
||||
_paymentMethodHandlerDictionary = paymentMethodHandlerDictionary;
|
||||
_walletRepository = walletRepository;
|
||||
_btcPayNetworkProvider = btcPayNetworkProvider;
|
||||
_bitcoinLikePayoutHandler = bitcoinLikePayoutHandler;
|
||||
@@ -495,7 +501,7 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
if (storeIdForutxo != StoreId)
|
||||
{
|
||||
var s = await _storeRepository.FindStore(storeIdForutxo);
|
||||
var scheme = s.GetDerivationSchemeSettings(_btcPayNetworkProvider, "BTC");
|
||||
var scheme = s.GetDerivationSchemeSettings(_paymentMethodHandlerDictionary, "BTC");
|
||||
utxoDerivationScheme = scheme.AccountDerivation;
|
||||
}
|
||||
|
||||
@@ -689,7 +695,7 @@ public async Task<IEnumerable<IDestination>> GetNextDestinationsAsync(int count,
|
||||
try
|
||||
{
|
||||
var mixStore = await _storeRepository.FindStore(WabisabiStoreSettings.MixToOtherWallet);
|
||||
var pm = mixStore.GetDerivationSchemeSettings(_btcPayNetworkProvider, "BTC");
|
||||
var pm = mixStore.GetDerivationSchemeSettings(_paymentMethodHandlerDictionary, "BTC");
|
||||
|
||||
|
||||
if (pm?.AccountDerivation?.ScriptPubKeyType() == DerivationScheme.ScriptPubKeyType())
|
||||
@@ -718,20 +724,19 @@ public async Task<IEnumerable<IDestination>> GetNextDestinationsAsync(int count,
|
||||
{
|
||||
States = new [] {PayoutState.AwaitingPayment},
|
||||
Stores = new []{StoreId},
|
||||
PaymentMethods = new []{"BTC"}
|
||||
PayoutMethods = new []{ PayoutTypes.CHAIN.GetPayoutMethodId("BTC").ToString()}
|
||||
})).Select(async data =>
|
||||
{
|
||||
|
||||
var claim = await _bitcoinLikePayoutHandler.ParseClaimDestination(new PaymentMethodId("BTC", BitcoinPaymentType.Instance),
|
||||
data.Destination, CancellationToken.None);
|
||||
var payoutBlob = data.GetBlob(_btcPayNetworkJsonSerializerSettings);
|
||||
var claim = await _bitcoinLikePayoutHandler.ParseClaimDestination(payoutBlob.Destination, CancellationToken.None);
|
||||
|
||||
if (!string.IsNullOrEmpty(claim.error) || claim.destination is not IBitcoinLikeClaimDestination bitcoinLikeClaimDestination )
|
||||
if (!string.IsNullOrEmpty(claim.error) || claim.destination is not IBitcoinLikeClaimDestination bitcoinLikeClaimDestination || data.Amount is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var payoutBlob = data.GetBlob(_btcPayNetworkJsonSerializerSettings);
|
||||
var value = new Money(payoutBlob.CryptoAmount.Value, MoneyUnit.BTC);
|
||||
var value = new Money(data.Amount.Value, MoneyUnit.BTC);
|
||||
return new PendingPayment()
|
||||
{
|
||||
Identifier = data.Id,
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using NBitcoin;
|
||||
@@ -17,16 +18,19 @@ public class WabisabiScriptResolver: WabiSabiConfig.CoordinatorScriptResolver
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly StoreRepository _storeRepository;
|
||||
private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary;
|
||||
private readonly BTCPayNetworkProvider _networkProvider;
|
||||
private readonly BTCPayWalletProvider _walletProvider;
|
||||
|
||||
public WabisabiScriptResolver(IHttpClientFactory httpClientFactory,
|
||||
StoreRepository storeRepository,
|
||||
PaymentMethodHandlerDictionary paymentMethodHandlerDictionary,
|
||||
BTCPayNetworkProvider networkProvider,
|
||||
BTCPayWalletProvider walletProvider)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_storeRepository = storeRepository;
|
||||
_paymentMethodHandlerDictionary = paymentMethodHandlerDictionary;
|
||||
_networkProvider = networkProvider;
|
||||
_walletProvider = walletProvider;
|
||||
}
|
||||
@@ -61,7 +65,7 @@ public class WabisabiScriptResolver: WabiSabiConfig.CoordinatorScriptResolver
|
||||
var store = await _storeRepository.FindStore(value);
|
||||
var cryptoCode = _networkProvider.GetAll().OfType<BTCPayNetwork>()
|
||||
.First(payNetwork => payNetwork.NBitcoinNetwork == network);
|
||||
var dss = store.GetDerivationSchemeSettings(_networkProvider, cryptoCode.CryptoCode);
|
||||
var dss = store.GetDerivationSchemeSettings(_paymentMethodHandlerDictionary, cryptoCode.CryptoCode);
|
||||
var w = _walletProvider.GetWallet(cryptoCode.CryptoCode);
|
||||
var kpi = await w.ReserveAddressAsync(store.Id, dss.AccountDerivation, "wabisabi coordinator");
|
||||
return kpi.ScriptPubKey;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user