diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b5f39e6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,364 @@ +root = true + +# All files +[*] +indent_style = space + +# Xml files +[*.xml] +indent_size = 2 + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Coding Conventions #### +[*.{cs,vb}] + +# Organize usings +dotnet_separate_import_directive_groups = true +dotnet_sort_system_directives_first = true +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_property = false:silent + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent + +# Expression-level preferences +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion + +# Field preferences +dotnet_style_readonly_field = true:warning + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:suggestion + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +#### C# Coding Conventions #### +[*.cs] + +# var preferences +csharp_style_var_elsewhere = false:silent +csharp_style_var_for_built_in_types = false:silent +csharp_style_var_when_type_is_apparent = false:silent + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:suggestion +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_pattern_matching = true:silent +csharp_style_prefer_switch_expression = true:suggestion + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:suggestion + +# Modifier preferences +csharp_prefer_static_local_function = true:warning +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent + +# Code-block preferences +csharp_prefer_braces = true:silent +csharp_prefer_simple_using_statement = true:suggestion + +# Expression-level preferences +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:silent + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### +[*.{cs,vb}] + +# Naming rules + +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols = types_and_namespaces +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.interfaces_should_be_ipascalcase.severity = suggestion +dotnet_naming_rule.interfaces_should_be_ipascalcase.symbols = interfaces +dotnet_naming_rule.interfaces_should_be_ipascalcase.style = ipascalcase + +dotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = suggestion +dotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols = type_parameters +dotnet_naming_rule.type_parameters_should_be_tpascalcase.style = tpascalcase + +dotnet_naming_rule.methods_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.methods_should_be_pascalcase.symbols = methods +dotnet_naming_rule.methods_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.properties_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.properties_should_be_pascalcase.symbols = properties +dotnet_naming_rule.properties_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.events_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.events_should_be_pascalcase.symbols = events +dotnet_naming_rule.events_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.local_variables_should_be_camelcase.severity = suggestion +dotnet_naming_rule.local_variables_should_be_camelcase.symbols = local_variables +dotnet_naming_rule.local_variables_should_be_camelcase.style = camelcase + +dotnet_naming_rule.local_constants_should_be_camelcase.severity = suggestion +dotnet_naming_rule.local_constants_should_be_camelcase.symbols = local_constants +dotnet_naming_rule.local_constants_should_be_camelcase.style = camelcase + +dotnet_naming_rule.parameters_should_be_camelcase.severity = suggestion +dotnet_naming_rule.parameters_should_be_camelcase.symbols = parameters +dotnet_naming_rule.parameters_should_be_camelcase.style = camelcase + +dotnet_naming_rule.public_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_fields_should_be_pascalcase.symbols = public_fields +dotnet_naming_rule.public_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_fields_should_be__camelcase.severity = suggestion +dotnet_naming_rule.private_fields_should_be__camelcase.symbols = private_fields +dotnet_naming_rule.private_fields_should_be__camelcase.style = _camelcase + +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.severity = suggestion +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.symbols = private_static_fields +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.style = s_camelcase + +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.symbols = public_constant_fields +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.symbols = private_constant_fields +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.symbols = public_static_readonly_fields +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.symbols = private_static_readonly_fields +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.enums_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.enums_should_be_pascalcase.symbols = enums +dotnet_naming_rule.enums_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.local_functions_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.local_functions_should_be_pascalcase.symbols = local_functions +dotnet_naming_rule.local_functions_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.non_field_members_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascalcase.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascalcase.style = pascalcase + +# Symbol specifications + +dotnet_naming_symbols.interfaces.applicable_kinds = interface +dotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interfaces.required_modifiers = + +dotnet_naming_symbols.enums.applicable_kinds = enum +dotnet_naming_symbols.enums.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.enums.required_modifiers = + +dotnet_naming_symbols.events.applicable_kinds = event +dotnet_naming_symbols.events.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.events.required_modifiers = + +dotnet_naming_symbols.methods.applicable_kinds = method +dotnet_naming_symbols.methods.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.methods.required_modifiers = + +dotnet_naming_symbols.properties.applicable_kinds = property +dotnet_naming_symbols.properties.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.properties.required_modifiers = + +dotnet_naming_symbols.public_fields.applicable_kinds = field +dotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_fields.required_modifiers = + +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_fields.required_modifiers = + +dotnet_naming_symbols.private_static_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_static_fields.required_modifiers = static + +dotnet_naming_symbols.types_and_namespaces.applicable_kinds = namespace, class, struct, interface, enum +dotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types_and_namespaces.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +dotnet_naming_symbols.type_parameters.applicable_kinds = namespace +dotnet_naming_symbols.type_parameters.applicable_accessibilities = * +dotnet_naming_symbols.type_parameters.required_modifiers = + +dotnet_naming_symbols.private_constant_fields.applicable_kinds = field +dotnet_naming_symbols.private_constant_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_constant_fields.required_modifiers = const + +dotnet_naming_symbols.local_variables.applicable_kinds = local +dotnet_naming_symbols.local_variables.applicable_accessibilities = local +dotnet_naming_symbols.local_variables.required_modifiers = + +dotnet_naming_symbols.local_constants.applicable_kinds = local +dotnet_naming_symbols.local_constants.applicable_accessibilities = local +dotnet_naming_symbols.local_constants.required_modifiers = const + +dotnet_naming_symbols.parameters.applicable_kinds = parameter +dotnet_naming_symbols.parameters.applicable_accessibilities = * +dotnet_naming_symbols.parameters.required_modifiers = + +dotnet_naming_symbols.public_constant_fields.applicable_kinds = field +dotnet_naming_symbols.public_constant_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_constant_fields.required_modifiers = const + +dotnet_naming_symbols.public_static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.public_static_readonly_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_static_readonly_fields.required_modifiers = readonly, static + +dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = readonly, static + +dotnet_naming_symbols.local_functions.applicable_kinds = local_function +dotnet_naming_symbols.local_functions.applicable_accessibilities = * +dotnet_naming_symbols.local_functions.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascalcase.required_prefix = +dotnet_naming_style.pascalcase.required_suffix = +dotnet_naming_style.pascalcase.word_separator = +dotnet_naming_style.pascalcase.capitalization = pascal_case + +dotnet_naming_style.ipascalcase.required_prefix = I +dotnet_naming_style.ipascalcase.required_suffix = +dotnet_naming_style.ipascalcase.word_separator = +dotnet_naming_style.ipascalcase.capitalization = pascal_case + +dotnet_naming_style.tpascalcase.required_prefix = T +dotnet_naming_style.tpascalcase.required_suffix = +dotnet_naming_style.tpascalcase.word_separator = +dotnet_naming_style.tpascalcase.capitalization = pascal_case + +dotnet_naming_style._camelcase.required_prefix = _ +dotnet_naming_style._camelcase.required_suffix = +dotnet_naming_style._camelcase.word_separator = +dotnet_naming_style._camelcase.capitalization = camel_case + +dotnet_naming_style.camelcase.required_prefix = +dotnet_naming_style.camelcase.required_suffix = +dotnet_naming_style.camelcase.word_separator = +dotnet_naming_style.camelcase.capitalization = camel_case + +dotnet_naming_style.s_camelcase.required_prefix = s_ +dotnet_naming_style.s_camelcase.required_suffix = +dotnet_naming_style.s_camelcase.word_separator = +dotnet_naming_style.s_camelcase.capitalization = camel_case + diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b0b16bf --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# Windows CRLF endings expected on server +* text eol=crlf + +# Explicitly set Unix LF endings for .sh files +*.sh text eol=lf \ No newline at end of file diff --git a/.github/workflows/dotnet-format.yml b/.github/workflows/dotnet-format.yml new file mode 100644 index 0000000..5334c6c --- /dev/null +++ b/.github/workflows/dotnet-format.yml @@ -0,0 +1,32 @@ +name: Code format check + +on: + push: + branches: + - "master" + pull_request: + branches: + - "master" + workflow_dispatch: + +jobs: + lint: + runs-on: windows-latest + steps: + + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Restore dependencies + run: dotnet restore + + - name: Code format check + run: | + dotnet tool install -g dotnet-format + dotnet format btcpay-monero-plugin.sln --no-restore --verify-no-changes --exclude submodules/* --verbosity diagnostic \ No newline at end of file diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 86dac7c..8bdcb18 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -8,7 +8,7 @@ on: branches: - "master" workflow_dispatch: - + jobs: build: runs-on: ubuntu-latest @@ -29,16 +29,16 @@ jobs: - name: Clean project run: dotnet clean - + - name: Build projects run: dotnet build -c Release --no-restore - + - name: Deterministic build check run: | dotnet tool install --global dotnet-validate --version 0.0.1-preview.537 dotnet pack Plugins/Monero/BTCPayServer.Plugins.Monero.csproj -c Release /p:PackageVersion=1 --no-build -o nuget-packages dotnet validate package local nuget-packages/BTCPayServer.Plugins.Monero.1.0.0.nupkg - + - name: Run unit tests run: | dotnet tool install --global JetBrains.dotCover.CommandLineTools diff --git a/.gitignore b/.gitignore index b09e66e..a98a4d9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ Plugins/packed .vs/ coverage -nuget-packages \ No newline at end of file +nuget-packages +**/.AssemblyAttributes \ No newline at end of file diff --git a/BTCPayServer.Plugins.IntegrationTests/Monero/MoneroIntegrationTestBase.cs b/BTCPayServer.Plugins.IntegrationTests/Monero/MoneroIntegrationTestBase.cs index ccfb678..05e452e 100644 --- a/BTCPayServer.Plugins.IntegrationTests/Monero/MoneroIntegrationTestBase.cs +++ b/BTCPayServer.Plugins.IntegrationTests/Monero/MoneroIntegrationTestBase.cs @@ -1,6 +1,7 @@ -using Xunit.Abstractions; using BTCPayServer.Tests; +using Xunit.Abstractions; + namespace BTCPayServer.Plugins.IntegrationTests.Monero { public class MoneroAndBitcoinIntegrationTestBase : UnitTestBase diff --git a/BTCPayServer.Plugins.IntegrationTests/Monero/MoneroPluginUITest.cs b/BTCPayServer.Plugins.IntegrationTests/Monero/MoneroPluginUITest.cs index 7728371..3bae8ef 100644 --- a/BTCPayServer.Plugins.IntegrationTests/Monero/MoneroPluginUITest.cs +++ b/BTCPayServer.Plugins.IntegrationTests/Monero/MoneroPluginUITest.cs @@ -1,4 +1,5 @@ using BTCPayServer.Tests; + using Xunit; using Xunit.Abstractions; diff --git a/BTCPayServer.Plugins.UnitTests/Monero/Configuration/MoneroLikeConfigurationTests.cs b/BTCPayServer.Plugins.UnitTests/Monero/Configuration/MoneroLikeConfigurationTests.cs index 6b67793..d5a4e46 100644 --- a/BTCPayServer.Plugins.UnitTests/Monero/Configuration/MoneroLikeConfigurationTests.cs +++ b/BTCPayServer.Plugins.UnitTests/Monero/Configuration/MoneroLikeConfigurationTests.cs @@ -1,4 +1,5 @@ using BTCPayServer.Plugins.Monero.Configuration; + using Xunit; namespace BTCPayServer.Plugins.UnitTests.Monero.Configuration diff --git a/BTCPayServer.Plugins.UnitTests/Monero/Payments/MoneroLikePaymentDataTests.cs b/BTCPayServer.Plugins.UnitTests/Monero/Payments/MoneroLikePaymentDataTests.cs index 62102e3..98b00a8 100644 --- a/BTCPayServer.Plugins.UnitTests/Monero/Payments/MoneroLikePaymentDataTests.cs +++ b/BTCPayServer.Plugins.UnitTests/Monero/Payments/MoneroLikePaymentDataTests.cs @@ -1,4 +1,5 @@ using BTCPayServer.Plugins.Monero.Payments; + using Xunit; namespace BTCPayServer.Plugins.UnitTests.Monero.Payments diff --git a/BTCPayServer.Plugins.UnitTests/Monero/RPC/Models/ParseStringConverterTest.cs b/BTCPayServer.Plugins.UnitTests/Monero/RPC/Models/ParseStringConverterTest.cs index 15b79ab..3e2225b 100644 --- a/BTCPayServer.Plugins.UnitTests/Monero/RPC/Models/ParseStringConverterTest.cs +++ b/BTCPayServer.Plugins.UnitTests/Monero/RPC/Models/ParseStringConverterTest.cs @@ -1,5 +1,7 @@ using BTCPayServer.Plugins.Monero.RPC.Models; + using Newtonsoft.Json; + using Xunit; namespace BTCPayServer.Plugins.UnitTests.Monero.RPC.Models diff --git a/BTCPayServer.Plugins.UnitTests/Monero/RPC/MoneroEventTests.cs b/BTCPayServer.Plugins.UnitTests/Monero/RPC/MoneroEventTests.cs index 49e37d1..8715993 100644 --- a/BTCPayServer.Plugins.UnitTests/Monero/RPC/MoneroEventTests.cs +++ b/BTCPayServer.Plugins.UnitTests/Monero/RPC/MoneroEventTests.cs @@ -1,4 +1,5 @@ using BTCPayServer.Plugins.Monero.RPC; + using Xunit; namespace BTCPayServer.Plugins.UnitTests.Monero.RPC @@ -46,6 +47,6 @@ namespace BTCPayServer.Plugins.UnitTests.Monero.RPC Assert.Equal(expected, result); } - + } } \ No newline at end of file diff --git a/BTCPayServer.Plugins.UnitTests/Monero/Utils/MoneroMoneyTests.cs b/BTCPayServer.Plugins.UnitTests/Monero/Utils/MoneroMoneyTests.cs index f606c83..9e10b3c 100644 --- a/BTCPayServer.Plugins.UnitTests/Monero/Utils/MoneroMoneyTests.cs +++ b/BTCPayServer.Plugins.UnitTests/Monero/Utils/MoneroMoneyTests.cs @@ -1,7 +1,9 @@ using System.Globalization; -using Xunit; + using BTCPayServer.Plugins.Monero.Utils; +using Xunit; + namespace BTCPayServer.Plugins.UnitTests.Monero.Utils { public class MoneroMoneyTests @@ -29,7 +31,7 @@ namespace BTCPayServer.Plugins.UnitTests.Monero.Utils long result = MoneroMoney.Convert(monero); Assert.Equal(expectedPiconero, result); } - + [Trait("Category", "Unit")] [Theory] [InlineData(1)] diff --git a/BTCPayServer.Plugins.UnitTests/Monero/ViewModels/MoneroPaymentViewModelTests.cs b/BTCPayServer.Plugins.UnitTests/Monero/ViewModels/MoneroPaymentViewModelTests.cs index fe1e476..0000731 100644 --- a/BTCPayServer.Plugins.UnitTests/Monero/ViewModels/MoneroPaymentViewModelTests.cs +++ b/BTCPayServer.Plugins.UnitTests/Monero/ViewModels/MoneroPaymentViewModelTests.cs @@ -1,5 +1,6 @@ using BTCPayServer.Payments; using BTCPayServer.Plugins.Monero.ViewModels; + using Xunit; namespace BTCPayServer.Plugins.UnitTests.Monero.ViewModels @@ -21,7 +22,7 @@ namespace BTCPayServer.Plugins.UnitTests.Monero.ViewModels var receivedTime = DateTimeOffset.UtcNow; var transactionLink = "https://explorer.monero.com/tx/tx123"; var currency = "XMR"; - + viewModel.PaymentMethodId = paymentMethodId; viewModel.Confirmations = confirmations; viewModel.DepositAddress = depositAddress; @@ -30,7 +31,7 @@ namespace BTCPayServer.Plugins.UnitTests.Monero.ViewModels viewModel.ReceivedTime = receivedTime; viewModel.TransactionLink = transactionLink; viewModel.Currency = currency; - + Assert.Equal(paymentMethodId, viewModel.PaymentMethodId); Assert.Equal(confirmations, viewModel.Confirmations); Assert.Equal(depositAddress, viewModel.DepositAddress); diff --git a/Plugins/Monero/Configuration/MoneroLikeConfiguration.cs b/Plugins/Monero/Configuration/MoneroLikeConfiguration.cs index e19890c..95893f3 100644 --- a/Plugins/Monero/Configuration/MoneroLikeConfiguration.cs +++ b/Plugins/Monero/Configuration/MoneroLikeConfiguration.cs @@ -18,4 +18,4 @@ namespace BTCPayServer.Plugins.Monero.Configuration public string Password { get; set; } public Uri CashCowWalletRpcUri { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/Controllers/MoneroDaemonCallbackController.cs b/Plugins/Monero/Controllers/MoneroDaemonCallbackController.cs index 667e0bb..41390f1 100644 --- a/Plugins/Monero/Controllers/MoneroDaemonCallbackController.cs +++ b/Plugins/Monero/Controllers/MoneroDaemonCallbackController.cs @@ -1,5 +1,6 @@ using BTCPayServer.Filters; using BTCPayServer.Plugins.Monero.RPC; + using Microsoft.AspNetCore.Mvc; namespace BTCPayServer.Plugins.Monero.Controllers @@ -35,4 +36,4 @@ namespace BTCPayServer.Plugins.Monero.Controllers } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/Controllers/MoneroLikeStoreController.cs b/Plugins/Monero/Controllers/MoneroLikeStoreController.cs index 4f676b3..9207e0c 100644 --- a/Plugins/Monero/Controllers/MoneroLikeStoreController.cs +++ b/Plugins/Monero/Controllers/MoneroLikeStoreController.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; + using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Models; @@ -19,6 +20,7 @@ using BTCPayServer.Plugins.Monero.RPC.Models; using BTCPayServer.Plugins.Monero.Services; using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Stores; + using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -58,7 +60,7 @@ namespace BTCPayServer.Plugins.Monero.Controllers { return View("/Views/Monero/GetStoreMoneroLikePaymentMethods.cshtml", await GetVM(StoreData)); } -[NonAction] + [NonAction] public async Task GetVM(StoreData storeData) { var excludeFilters = storeData.GetStoreBlob().GetExcludedPaymentMethods(); @@ -269,7 +271,7 @@ namespace BTCPayServer.Plugins.Monero.Controllers ModelState.AddModelError(nameof(viewModel.AccountIndex), StringLocalizer["Could not open the wallet: {0}", ex.Message]); return View("/Views/Monero/GetStoreMoneroLikePaymentMethod.cshtml", viewModel); } - + TempData.SetStatusMessageModel(new StatusMessageModel { Severity = StatusMessageModel.StatusSeverity.Info, @@ -393,4 +395,4 @@ namespace BTCPayServer.Plugins.Monero.Controllers Custom } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/MoneroLikeSpecificBtcPayNetwork.cs b/Plugins/Monero/MoneroLikeSpecificBtcPayNetwork.cs index aa4968d..d486785 100644 --- a/Plugins/Monero/MoneroLikeSpecificBtcPayNetwork.cs +++ b/Plugins/Monero/MoneroLikeSpecificBtcPayNetwork.cs @@ -4,4 +4,4 @@ public class MoneroLikeSpecificBtcPayNetwork : BTCPayNetworkBase { public int MaxTrackedConfirmation = 10; public string UriScheme { get; set; } -} +} \ No newline at end of file diff --git a/Plugins/Monero/MoneroPlugin.cs b/Plugins/Monero/MoneroPlugin.cs index dd237f6..33fbaac 100644 --- a/Plugins/Monero/MoneroPlugin.cs +++ b/Plugins/Monero/MoneroPlugin.cs @@ -1,24 +1,27 @@ -using BTCPayServer.Abstractions.Contracts; -using System.Net.Http; -using System.Net; -using BTCPayServer.Hosting; -using BTCPayServer.Payments; -using Microsoft.Extensions.DependencyInjection; -using NBitcoin; -using BTCPayServer.Configuration; -using System.Linq; using System; using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http; + +using BTCPayServer.Abstractions.Contracts; using BTCPayServer.Abstractions.Models; -using BTCPayServer.Plugins.Altcoins; +using BTCPayServer.Configuration; +using BTCPayServer.Hosting; +using BTCPayServer.Payments; using BTCPayServer.Plugins.Monero.Configuration; using BTCPayServer.Plugins.Monero.Payments; using BTCPayServer.Plugins.Monero.Services; using BTCPayServer.Services; + using Microsoft.Extensions.Configuration; -using NBXplorer; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using NBitcoin; + +using NBXplorer; + namespace BTCPayServer.Plugins.Monero; public class MoneroPlugin : BaseBTCPayServerPlugin @@ -81,7 +84,7 @@ public class MoneroPlugin : BaseBTCPayServerPlugin (IPaymentLinkExtension)ActivatorUtilities.CreateInstance(provider, typeof(MoneroPaymentLinkExtension), new object[] { network, pmi })); services.AddSingleton(provider => (ICheckoutModelExtension)ActivatorUtilities.CreateInstance(provider, typeof(MoneroCheckoutModelExtension), new object[] { network, pmi })); - + services.AddSingleton(provider => (ICheckoutCheatModeExtension)ActivatorUtilities.CreateInstance(provider, typeof(MoneroCheckoutCheatModeExtension), new object[] { network, pmi })); @@ -99,11 +102,13 @@ public class MoneroPlugin : BaseBTCPayServerPlugin public override string GetTransactionLink(string paymentId) { if (string.IsNullOrEmpty(BlockExplorerLink)) + { return null; + } return string.Format(CultureInfo.InvariantCulture, BlockExplorerLink, paymentId); } } - + private static MoneroLikeConfiguration ConfigureMoneroLikeConfiguration(IServiceProvider serviceProvider) { var configuration = serviceProvider.GetService(); @@ -139,14 +144,14 @@ public class MoneroPlugin : BaseBTCPayServerPlugin var cryptoCode = moneroLikeSpecificBtcPayNetwork.CryptoCode.ToUpperInvariant(); if (daemonUri is null) { - logger.LogWarning($"BTCPAY_{cryptoCode}_DAEMON_URI is not configured"); - } + logger.LogWarning($"BTCPAY_{cryptoCode}_DAEMON_URI is not configured"); + } if (walletDaemonUri is null) { logger.LogWarning($"BTCPAY_{cryptoCode}_WALLET_DAEMON_URI is not configured"); } - logger.LogWarning($"{cryptoCode} got disabled as it is not fully configured."); - } + logger.LogWarning($"{cryptoCode} got disabled as it is not fully configured."); + } else { result.MoneroLikeConfigurationItems.Add(moneroLikeSpecificBtcPayNetwork.CryptoCode, new MoneroLikeConfigurationItem() @@ -162,4 +167,4 @@ public class MoneroPlugin : BaseBTCPayServerPlugin } return result; } -} +} \ No newline at end of file diff --git a/Plugins/Monero/Payments/MoneroCheckoutModelExtension.cs b/Plugins/Monero/Payments/MoneroCheckoutModelExtension.cs index 0ab35d2..dd718a3 100644 --- a/Plugins/Monero/Payments/MoneroCheckoutModelExtension.cs +++ b/Plugins/Monero/Payments/MoneroCheckoutModelExtension.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Linq; + using BTCPayServer.Payments; using BTCPayServer.Payments.Bitcoin; -using BTCPayServer.Payments.Lightning; using BTCPayServer.Plugins.Monero.Services; using BTCPayServer.Services.Invoices; @@ -33,7 +33,9 @@ namespace BTCPayServer.Plugins.Monero.Payments public void ModifyCheckoutModel(CheckoutModelContext context) { if (context is not { Handler: MoneroLikePaymentMethodHandler handler }) + { return; + } context.Model.CheckoutBodyComponentName = BitcoinCheckoutModelExtension.CheckoutBodyComponentName; var details = context.InvoiceEntity.GetPayments(true) .Select(p => p.GetDetails(handler)) @@ -49,4 +51,4 @@ namespace BTCPayServer.Plugins.Monero.Payments context.Model.InvoiceBitcoinUrlQR = context.Model.InvoiceBitcoinUrl; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/Payments/MoneroLikeOnChainPaymentMethodDetails.cs b/Plugins/Monero/Payments/MoneroLikeOnChainPaymentMethodDetails.cs index 69f53f0..4dbc8e2 100644 --- a/Plugins/Monero/Payments/MoneroLikeOnChainPaymentMethodDetails.cs +++ b/Plugins/Monero/Payments/MoneroLikeOnChainPaymentMethodDetails.cs @@ -8,4 +8,4 @@ namespace BTCPayServer.Plugins.Monero.Payments public long AddressIndex { get; set; } public long? InvoiceSettledConfirmationThreshold { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/Payments/MoneroLikePaymentData.cs b/Plugins/Monero/Payments/MoneroLikePaymentData.cs index 5838552..44f1d6e 100644 --- a/Plugins/Monero/Payments/MoneroLikePaymentData.cs +++ b/Plugins/Monero/Payments/MoneroLikePaymentData.cs @@ -17,4 +17,4 @@ namespace BTCPayServer.Plugins.Monero.Payments public long LockTime { get; set; } = 0; } -} +} \ No newline at end of file diff --git a/Plugins/Monero/Payments/MoneroLikePaymentMethodHandler.cs b/Plugins/Monero/Payments/MoneroLikePaymentMethodHandler.cs index b771a5b..681b935 100644 --- a/Plugins/Monero/Payments/MoneroLikePaymentMethodHandler.cs +++ b/Plugins/Monero/Payments/MoneroLikePaymentMethodHandler.cs @@ -1,24 +1,12 @@ using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; using System.Threading.Tasks; -using AngleSharp.Dom; -using BTCPayServer.Abstractions.Extensions; -using BTCPayServer.BIP78.Sender; + using BTCPayServer.Data; -using BTCPayServer.Logging; -using BTCPayServer.Models; -using BTCPayServer.Models.InvoicingModels; using BTCPayServer.Payments; -using BTCPayServer.Plugins.Altcoins; -using BTCPayServer.Rating; +using BTCPayServer.Plugins.Monero.RPC.Models; using BTCPayServer.Plugins.Monero.Services; using BTCPayServer.Plugins.Monero.Utils; -using BTCPayServer.Plugins.Monero.RPC.Models; -using BTCPayServer.Services.Invoices; -using BTCPayServer.Services.Rates; -using NBitcoin; + using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -42,7 +30,7 @@ namespace BTCPayServer.Plugins.Monero.Payments } bool IsReady() => _moneroRpcProvider.IsConfigured(_network.CryptoCode) && _moneroRpcProvider.IsAvailable(_network.CryptoCode); - public Task BeforeFetchingRates(PaymentMethodContext context) + public Task BeforeFetchingRates(PaymentMethodContext context) { context.Prompt.Currency = _network.CryptoCode; context.Prompt.Divisibility = _network.Divisibility; @@ -61,17 +49,19 @@ namespace BTCPayServer.Plugins.Monero.Payments }; } catch (Exception ex) - { + { context.Logs.Write($"Error in BeforeFetchingRates: {ex.Message}", InvoiceEventData.EventSeverity.Error); - } - } + } + } return Task.CompletedTask; } - public async Task ConfigurePrompt(PaymentMethodContext context) + public async Task ConfigurePrompt(PaymentMethodContext context) { if (!_moneroRpcProvider.IsConfigured(_network.CryptoCode)) - throw new PaymentMethodUnavailableException($"BTCPAY_XMR_WALLET_DAEMON_URI or BTCPAY_XMR_DAEMON_URI isn't configured"); + { + throw new PaymentMethodUnavailableException($"BTCPAY_XMR_WALLET_DAEMON_URI or BTCPAY_XMR_DAEMON_URI isn't configured"); + } if (!_moneroRpcProvider.IsAvailable(_network.CryptoCode) || context.State is not Prepare moneroPrepare) throw new PaymentMethodUnavailableException($"Node or wallet not available"); var invoice = context.InvoiceEntity; @@ -107,11 +97,11 @@ namespace BTCPayServer.Plugins.Monero.Payments public long AccountIndex { get; internal set; } } - public MoneroLikeOnChainPaymentMethodDetails ParsePaymentPromptDetails(Newtonsoft.Json.Linq.JToken details) + public MoneroLikeOnChainPaymentMethodDetails ParsePaymentPromptDetails(JToken details) { return details.ToObject(Serializer); } - object IPaymentMethodHandler.ParsePaymentPromptDetails(Newtonsoft.Json.Linq.JToken details) + object IPaymentMethodHandler.ParsePaymentPromptDetails(JToken details) { return ParsePaymentPromptDetails(details); } @@ -125,4 +115,4 @@ namespace BTCPayServer.Plugins.Monero.Payments return ParsePaymentDetails(details); } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/Payments/MoneroPaymentLinkExtension.cs b/Plugins/Monero/Payments/MoneroPaymentLinkExtension.cs index 13b50a7..efd719e 100644 --- a/Plugins/Monero/Payments/MoneroPaymentLinkExtension.cs +++ b/Plugins/Monero/Payments/MoneroPaymentLinkExtension.cs @@ -1,8 +1,10 @@ #nullable enable using System.Globalization; + using BTCPayServer.Payments; using BTCPayServer.Plugins.Altcoins; using BTCPayServer.Services.Invoices; + using Microsoft.AspNetCore.Mvc; namespace BTCPayServer.Plugins.Monero.Payments @@ -24,4 +26,4 @@ namespace BTCPayServer.Plugins.Monero.Payments return $"{_network.UriScheme}:{prompt.Destination}?tx_amount={due.ToString(CultureInfo.InvariantCulture)}"; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/Payments/MoneroPaymentPromptDetails.cs b/Plugins/Monero/Payments/MoneroPaymentPromptDetails.cs index 18d125b..021918f 100644 --- a/Plugins/Monero/Payments/MoneroPaymentPromptDetails.cs +++ b/Plugins/Monero/Payments/MoneroPaymentPromptDetails.cs @@ -1,4 +1,5 @@ using BTCPayServer.Payments; + using Newtonsoft.Json; namespace BTCPayServer.Plugins.Monero.Payments @@ -8,4 +9,4 @@ namespace BTCPayServer.Plugins.Monero.Payments public long AccountIndex { get; set; } public long? InvoiceSettledConfirmationThreshold { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/JsonRpcClient.cs b/Plugins/Monero/RPC/JsonRpcClient.cs index 53807c8..ce22a6a 100644 --- a/Plugins/Monero/RPC/JsonRpcClient.cs +++ b/Plugins/Monero/RPC/JsonRpcClient.cs @@ -4,6 +4,7 @@ using System.Net.Http.Headers; using System.Text; using System.Threading; using System.Threading.Tasks; + using Newtonsoft.Json; using Newtonsoft.Json.Serialization; @@ -48,7 +49,7 @@ namespace BTCPayServer.Plugins.Monero.RPC HttpResponseMessage rawResult = await _httpClient.SendAsync(httpRequest, cts); rawResult.EnsureSuccessStatusCode(); var rawJson = await rawResult.Content.ReadAsStringAsync(); - + JsonRpcResult response; try { @@ -74,10 +75,10 @@ namespace BTCPayServer.Plugins.Monero.RPC public class NoRequestModel { - public static NoRequestModel Instance = new NoRequestModel(); + public static readonly NoRequestModel Instance = new NoRequestModel(); } - internal class JsonRpcApiException : Exception + public class JsonRpcApiException : Exception { public JsonRpcResultError Error { get; set; } @@ -118,4 +119,4 @@ namespace BTCPayServer.Plugins.Monero.RPC } } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/CreateAccountRequest.cs b/Plugins/Monero/RPC/Models/CreateAccountRequest.cs index a5cdb91..708ceb9 100644 --- a/Plugins/Monero/RPC/Models/CreateAccountRequest.cs +++ b/Plugins/Monero/RPC/Models/CreateAccountRequest.cs @@ -6,4 +6,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models { [JsonProperty("label")] public string Label { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/CreateAccountResponse.cs b/Plugins/Monero/RPC/Models/CreateAccountResponse.cs index 382d7a7..1577932 100644 --- a/Plugins/Monero/RPC/Models/CreateAccountResponse.cs +++ b/Plugins/Monero/RPC/Models/CreateAccountResponse.cs @@ -7,4 +7,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("account_index")] public long AccountIndex { get; set; } [JsonProperty("address")] public string Address { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/CreateAddressRequest.cs b/Plugins/Monero/RPC/Models/CreateAddressRequest.cs index f0b64a7..30bb630 100644 --- a/Plugins/Monero/RPC/Models/CreateAddressRequest.cs +++ b/Plugins/Monero/RPC/Models/CreateAddressRequest.cs @@ -7,4 +7,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("account_index")] public long AccountIndex { get; set; } [JsonProperty("label")] public string Label { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/CreateAddressResponse.cs b/Plugins/Monero/RPC/Models/CreateAddressResponse.cs index b37ca14..9da302d 100644 --- a/Plugins/Monero/RPC/Models/CreateAddressResponse.cs +++ b/Plugins/Monero/RPC/Models/CreateAddressResponse.cs @@ -7,4 +7,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("address")] public string Address { get; set; } [JsonProperty("address_index")] public long AddressIndex { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/CreateWalletRequest.cs b/Plugins/Monero/RPC/Models/CreateWalletRequest.cs index 9d91c3c..a7da15e 100644 --- a/Plugins/Monero/RPC/Models/CreateWalletRequest.cs +++ b/Plugins/Monero/RPC/Models/CreateWalletRequest.cs @@ -2,10 +2,10 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models { - public partial class CreateWalletRequest - { - [JsonProperty("filename")] public string Filename { get; set; } - [JsonProperty("password")] public string Password { get; set; } - [JsonProperty("language")] public string Language { get; set; } - } -} + public partial class CreateWalletRequest + { + [JsonProperty("filename")] public string Filename { get; set; } + [JsonProperty("password")] public string Password { get; set; } + [JsonProperty("language")] public string Language { get; set; } + } +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/GenerateBlocks.cs b/Plugins/Monero/RPC/Models/GenerateBlocks.cs index bd0a8b7..7f4efe6 100644 --- a/Plugins/Monero/RPC/Models/GenerateBlocks.cs +++ b/Plugins/Monero/RPC/Models/GenerateBlocks.cs @@ -4,6 +4,6 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models; public class GenerateBlocks { - [JsonProperty("wallet_address")]public string WalletAddress { get; set; } + [JsonProperty("wallet_address")] public string WalletAddress { get; set; } [JsonProperty("amount_of_blocks")] public int AmountOfBlocks { get; set; } } \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/GetAccountsRequest.cs b/Plugins/Monero/RPC/Models/GetAccountsRequest.cs index 09c0470..8c02d0c 100644 --- a/Plugins/Monero/RPC/Models/GetAccountsRequest.cs +++ b/Plugins/Monero/RPC/Models/GetAccountsRequest.cs @@ -6,4 +6,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models { [JsonProperty("tag")] public string Tag { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/GetAccountsResponse.cs b/Plugins/Monero/RPC/Models/GetAccountsResponse.cs index 5292d7c..acccf5e 100644 --- a/Plugins/Monero/RPC/Models/GetAccountsResponse.cs +++ b/Plugins/Monero/RPC/Models/GetAccountsResponse.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; + using Newtonsoft.Json; namespace BTCPayServer.Plugins.Monero.RPC.Models @@ -11,4 +12,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("total_unlocked_balance")] public decimal TotalUnlockedBalance { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/GetFeeEstimateRequest.cs b/Plugins/Monero/RPC/Models/GetFeeEstimateRequest.cs index 1fe05ff..c40ce13 100644 --- a/Plugins/Monero/RPC/Models/GetFeeEstimateRequest.cs +++ b/Plugins/Monero/RPC/Models/GetFeeEstimateRequest.cs @@ -6,4 +6,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models { [JsonProperty("grace_blocks")] public int? GraceBlocks { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/GetFeeEstimateResponse.cs b/Plugins/Monero/RPC/Models/GetFeeEstimateResponse.cs index d4d5e48..42b47c8 100644 --- a/Plugins/Monero/RPC/Models/GetFeeEstimateResponse.cs +++ b/Plugins/Monero/RPC/Models/GetFeeEstimateResponse.cs @@ -8,4 +8,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("status")] public string Status { get; set; } [JsonProperty("untrusted")] public bool Untrusted { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/GetHeightResponse.cs b/Plugins/Monero/RPC/Models/GetHeightResponse.cs index 42f0f12..10b61f8 100644 --- a/Plugins/Monero/RPC/Models/GetHeightResponse.cs +++ b/Plugins/Monero/RPC/Models/GetHeightResponse.cs @@ -6,4 +6,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models { [JsonProperty("height")] public long Height { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/GetInfoResponse.cs b/Plugins/Monero/RPC/Models/GetInfoResponse.cs index ce38ab3..6db434d 100644 --- a/Plugins/Monero/RPC/Models/GetInfoResponse.cs +++ b/Plugins/Monero/RPC/Models/GetInfoResponse.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; + using Newtonsoft.Json; namespace BTCPayServer.Plugins.Monero.RPC.Models @@ -10,4 +11,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("status")] public string Status { get; set; } [JsonProperty("target_height")] public long? TargetHeight { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/GetTransferByTransactionIdRequest.cs b/Plugins/Monero/RPC/Models/GetTransferByTransactionIdRequest.cs index d2419be..f527ac4 100644 --- a/Plugins/Monero/RPC/Models/GetTransferByTransactionIdRequest.cs +++ b/Plugins/Monero/RPC/Models/GetTransferByTransactionIdRequest.cs @@ -8,4 +8,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("account_index", DefaultValueHandling = DefaultValueHandling.Ignore)] public long? AccountIndex { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/GetTransferByTransactionIdResponse.cs b/Plugins/Monero/RPC/Models/GetTransferByTransactionIdResponse.cs index 7af8627..4873df3 100644 --- a/Plugins/Monero/RPC/Models/GetTransferByTransactionIdResponse.cs +++ b/Plugins/Monero/RPC/Models/GetTransferByTransactionIdResponse.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; + using Newtonsoft.Json; namespace BTCPayServer.Plugins.Monero.RPC.Models @@ -35,4 +36,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("unlock_time")] public long UnlockTime { get; set; } } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/GetTransfersRequest.cs b/Plugins/Monero/RPC/Models/GetTransfersRequest.cs index 5fdd123..fd0103c 100644 --- a/Plugins/Monero/RPC/Models/GetTransfersRequest.cs +++ b/Plugins/Monero/RPC/Models/GetTransfersRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; + using Newtonsoft.Json; namespace BTCPayServer.Plugins.Monero.RPC.Models @@ -16,4 +17,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("account_index")] public long AccountIndex { get; set; } [JsonProperty("subaddr_indices")] public List SubaddrIndices { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/GetTransfersResponse.cs b/Plugins/Monero/RPC/Models/GetTransfersResponse.cs index 3d88ac2..3e084ed 100644 --- a/Plugins/Monero/RPC/Models/GetTransfersResponse.cs +++ b/Plugins/Monero/RPC/Models/GetTransfersResponse.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; + using Newtonsoft.Json; namespace BTCPayServer.Plugins.Monero.RPC.Models @@ -32,4 +33,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("unlock_time")] public long UnlockTime { get; set; } } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/Info.cs b/Plugins/Monero/RPC/Models/Info.cs index a47b8ad..7701622 100644 --- a/Plugins/Monero/RPC/Models/Info.cs +++ b/Plugins/Monero/RPC/Models/Info.cs @@ -30,4 +30,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("state")] public string State { get; set; } [JsonProperty("support_flags")] public long SupportFlags { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/MakeUriRequest.cs b/Plugins/Monero/RPC/Models/MakeUriRequest.cs index 65dc19c..037d8ae 100644 --- a/Plugins/Monero/RPC/Models/MakeUriRequest.cs +++ b/Plugins/Monero/RPC/Models/MakeUriRequest.cs @@ -10,4 +10,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("tx_description")] public string TxDescription { get; set; } [JsonProperty("recipient_name")] public string RecipientName { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/MakeUriResponse.cs b/Plugins/Monero/RPC/Models/MakeUriResponse.cs index 6f17130..fd7904f 100644 --- a/Plugins/Monero/RPC/Models/MakeUriResponse.cs +++ b/Plugins/Monero/RPC/Models/MakeUriResponse.cs @@ -6,4 +6,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models { [JsonProperty("uri")] public string Uri { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/OpenWallerErrorResponse.cs b/Plugins/Monero/RPC/Models/OpenWallerErrorResponse.cs index 1f04c3f..0fbfb42 100644 --- a/Plugins/Monero/RPC/Models/OpenWallerErrorResponse.cs +++ b/Plugins/Monero/RPC/Models/OpenWallerErrorResponse.cs @@ -7,4 +7,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("code")] public int Code { get; set; } [JsonProperty("message")] public string Message { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/OpenWalletRequest.cs b/Plugins/Monero/RPC/Models/OpenWalletRequest.cs index be8a8e3..4d1ae17 100644 --- a/Plugins/Monero/RPC/Models/OpenWalletRequest.cs +++ b/Plugins/Monero/RPC/Models/OpenWalletRequest.cs @@ -7,4 +7,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("filename")] public string Filename { get; set; } [JsonProperty("password")] public string Password { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/OpenWalletResponse.cs b/Plugins/Monero/RPC/Models/OpenWalletResponse.cs index 9ecde7e..f64579f 100644 --- a/Plugins/Monero/RPC/Models/OpenWalletResponse.cs +++ b/Plugins/Monero/RPC/Models/OpenWalletResponse.cs @@ -9,4 +9,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("result")] public object Result { get; set; } [JsonProperty("error")] public OpenWalletErrorResponse Error { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/ParseStringConverter.cs b/Plugins/Monero/RPC/Models/ParseStringConverter.cs index 18b0984..4bf3b89 100644 --- a/Plugins/Monero/RPC/Models/ParseStringConverter.cs +++ b/Plugins/Monero/RPC/Models/ParseStringConverter.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; + using Newtonsoft.Json; namespace BTCPayServer.Plugins.Monero.RPC.Models @@ -11,7 +12,9 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) + { return null; + } var value = serializer.Deserialize(reader); long l; if (Int64.TryParse(value, out l)) @@ -37,4 +40,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models public static readonly ParseStringConverter Singleton = new ParseStringConverter(); } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/Peer.cs b/Plugins/Monero/RPC/Models/Peer.cs index e72716b..ba96602 100644 --- a/Plugins/Monero/RPC/Models/Peer.cs +++ b/Plugins/Monero/RPC/Models/Peer.cs @@ -6,4 +6,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models { [JsonProperty("info")] public Info Info { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/SubaddrIndex.cs b/Plugins/Monero/RPC/Models/SubaddrIndex.cs index 210dd0f..5d9205d 100644 --- a/Plugins/Monero/RPC/Models/SubaddrIndex.cs +++ b/Plugins/Monero/RPC/Models/SubaddrIndex.cs @@ -7,4 +7,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("major")] public long Major { get; set; } [JsonProperty("minor")] public long Minor { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/Models/SubaddressAccount.cs b/Plugins/Monero/RPC/Models/SubaddressAccount.cs index 17dd5d4..37a0395 100644 --- a/Plugins/Monero/RPC/Models/SubaddressAccount.cs +++ b/Plugins/Monero/RPC/Models/SubaddressAccount.cs @@ -11,4 +11,4 @@ namespace BTCPayServer.Plugins.Monero.RPC.Models [JsonProperty("tag")] public string Tag { get; set; } [JsonProperty("unlocked_balance")] public decimal UnlockedBalance { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/RPC/MoneroEvent.cs b/Plugins/Monero/RPC/MoneroEvent.cs index 0e34af7..993c7a9 100644 --- a/Plugins/Monero/RPC/MoneroEvent.cs +++ b/Plugins/Monero/RPC/MoneroEvent.cs @@ -17,4 +17,4 @@ namespace BTCPayServer.Plugins.Monero.RPC return $"{CryptoCode}: {eventDescription} ({TransactionHash ?? string.Empty}{BlockHash ?? string.Empty})"; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/Services/MoneroCheckoutCheatModeExtension.cs b/Plugins/Monero/Services/MoneroCheckoutCheatModeExtension.cs index 72590ed..1dd9a70 100644 --- a/Plugins/Monero/Services/MoneroCheckoutCheatModeExtension.cs +++ b/Plugins/Monero/Services/MoneroCheckoutCheatModeExtension.cs @@ -1,9 +1,11 @@ using System; using System.Threading.Tasks; + using BTCPayServer.Payments; using BTCPayServer.Plugins.Altcoins; using BTCPayServer.Plugins.Monero.RPC; using BTCPayServer.Plugins.Monero.RPC.Models; + using NBitcoin; namespace BTCPayServer.Plugins.Monero.Services; @@ -43,7 +45,8 @@ public class MoneroCheckoutCheatModeExtension : ICheckoutCheatModeExtension Amount = (long)amount, Address = payInvoiceContext.PaymentPrompt.Destination } - }}); + } + }); return new ICheckoutCheatModeExtension.PayInvoiceResult(result.TransactionHash); } diff --git a/Plugins/Monero/Services/MoneroLikeSummaryUpdaterHostedService.cs b/Plugins/Monero/Services/MoneroLikeSummaryUpdaterHostedService.cs index d0bfff5..c7e0a39 100644 --- a/Plugins/Monero/Services/MoneroLikeSummaryUpdaterHostedService.cs +++ b/Plugins/Monero/Services/MoneroLikeSummaryUpdaterHostedService.cs @@ -1,8 +1,10 @@ using System; using System.Threading; using System.Threading.Tasks; + using BTCPayServer.Logging; using BTCPayServer.Plugins.Monero.Configuration; + using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -64,7 +66,8 @@ namespace BTCPayServer.Plugins.Monero.Services public Task StopAsync(CancellationToken cancellationToken) { _Cts?.Cancel(); + _Cts?.Dispose(); return Task.CompletedTask; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/Services/MoneroListener.cs b/Plugins/Monero/Services/MoneroListener.cs index 6553b0e..a986c91 100644 --- a/Plugins/Monero/Services/MoneroListener.cs +++ b/Plugins/Monero/Services/MoneroListener.cs @@ -1,27 +1,26 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; -using System.Threading.Channels; using System.Threading.Tasks; + using BTCPayServer.Client.Models; using BTCPayServer.Data; using BTCPayServer.Events; using BTCPayServer.HostedServices; using BTCPayServer.Payments; -using BTCPayServer.Plugins.Altcoins; using BTCPayServer.Plugins.Monero.Configuration; using BTCPayServer.Plugins.Monero.Payments; +using BTCPayServer.Plugins.Monero.RPC; using BTCPayServer.Plugins.Monero.RPC.Models; using BTCPayServer.Plugins.Monero.Utils; using BTCPayServer.Services; -using BTCPayServer.Plugins.Monero.RPC; using BTCPayServer.Services.Invoices; -using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; + using NBitcoin; -using NBXplorer; + using Newtonsoft.Json.Linq; namespace BTCPayServer.Plugins.Monero.Services @@ -83,7 +82,9 @@ namespace BTCPayServer.Plugins.Monero.Services else if (evt is MoneroEvent moneroEvent) { if (!_moneroRpcProvider.IsAvailable(moneroEvent.CryptoCode)) + { return; + } if (!string.IsNullOrEmpty(moneroEvent.BlockHash)) { @@ -223,7 +224,7 @@ namespace BTCPayServer.Plugins.Monero.Services { if (valueTuples.Any()) { - _eventAggregator.Publish(new Events.InvoiceNeedUpdateEvent(valueTuples.Key.Id)); + _eventAggregator.Publish(new InvoiceNeedUpdateEvent(valueTuples.Key.Id)); } } } @@ -232,7 +233,7 @@ namespace BTCPayServer.Plugins.Monero.Services { await UpdateAnyPendingMoneroLikePayment(cryptoCode); _eventAggregator.Publish(new NewBlockEvent() - { PaymentMethodId = PaymentTypes.CHAIN.GetPaymentMethodId(cryptoCode) }); + { PaymentMethodId = PaymentTypes.CHAIN.GetPaymentMethodId(cryptoCode) }); } private async Task OnTransactionUpdated(string cryptoCode, string transactionHash) @@ -240,7 +241,9 @@ namespace BTCPayServer.Plugins.Monero.Services var paymentMethodId = PaymentTypes.CHAIN.GetPaymentMethodId(cryptoCode); var transfer = await GetTransferByTxId(cryptoCode, transactionHash, this.CancellationToken); if (transfer is null) + { return; + } var paymentsToUpdate = new List<(PaymentEntity Payment, InvoiceEntity invoice)>(); //group all destinations of the tx together and loop through the sets @@ -249,7 +252,9 @@ namespace BTCPayServer.Plugins.Monero.Services //find the invoice corresponding to this address, else skip var invoice = await _invoiceRepository.GetInvoiceFromAddress(paymentMethodId, destination.Key); if (invoice == null) + { continue; + } var index = destination.First().SubaddrIndex; @@ -271,7 +276,7 @@ namespace BTCPayServer.Plugins.Monero.Services { if (valueTuples.Any()) { - _eventAggregator.Publish(new Events.InvoiceNeedUpdateEvent(valueTuples.Key.Id)); + _eventAggregator.Publish(new InvoiceNeedUpdateEvent(valueTuples.Key.Id)); } } } @@ -286,7 +291,9 @@ namespace BTCPayServer.Plugins.Monero.Services .Select(a => new long?(a.AccountIndex)) .ToList(); if (accountIndexes.Count is 0) + { accountIndexes.Add(null); + } var req = accountIndexes .Select(i => GetTransferByTxId(cryptoCode, transactionHash, i)) .ToArray(); @@ -294,7 +301,9 @@ namespace BTCPayServer.Plugins.Monero.Services { var result = await task; if (result != null) + { return result; + } } return null; @@ -340,7 +349,7 @@ namespace BTCPayServer.Plugins.Monero.Services InvoiceSettledConfirmationThreshold = promptDetails.InvoiceSettledConfirmationThreshold }; var status = GetStatus(details, invoice.SpeedPolicy) ? PaymentStatus.Settled : PaymentStatus.Processing; - var paymentData = new Data.PaymentData() + var paymentData = new PaymentData() { Status = status, Amount = MoneroMoney.Convert(totalAmount), @@ -360,7 +369,9 @@ namespace BTCPayServer.Plugins.Monero.Services { var payment = await _paymentService.AddPayment(paymentData, [txId]); if (payment != null) + { await ReceivedPayment(invoice, payment); + } } else { @@ -393,7 +404,9 @@ namespace BTCPayServer.Plugins.Monero.Services var paymentMethodId = PaymentTypes.CHAIN.GetPaymentMethodId(cryptoCode); var invoices = await _invoiceRepository.GetMonitoredInvoices(paymentMethodId); if (!invoices.Any()) + { return; + } invoices = invoices.Where(entity => entity.GetPaymentPrompt(paymentMethodId)?.Activated is true).ToArray(); await UpdatePaymentStates(cryptoCode, invoices); } diff --git a/Plugins/Monero/Services/MoneroRPCProvider.cs b/Plugins/Monero/Services/MoneroRPCProvider.cs index 147d3e5..86dfc8c 100644 --- a/Plugins/Monero/Services/MoneroRPCProvider.cs +++ b/Plugins/Monero/Services/MoneroRPCProvider.cs @@ -4,12 +4,14 @@ using System.Collections.Immutable; using System.Linq; using System.Net.Http; using System.Threading.Tasks; -using Amazon.Runtime; + using BTCPayServer.Plugins.Monero.Configuration; using BTCPayServer.Plugins.Monero.RPC; using BTCPayServer.Plugins.Monero.RPC.Models; using BTCPayServer.Services; + using Microsoft.Extensions.Logging; + using NBitcoin; namespace BTCPayServer.Plugins.Monero.Services @@ -57,8 +59,8 @@ namespace BTCPayServer.Plugins.Monero.Services public ImmutableDictionary CashCowWalletRpcClients { get; set; } - public bool IsConfigured(string cryptoCode) => WalletRpcClients.ContainsKey(cryptoCode) && DaemonRpcClients.ContainsKey(cryptoCode); - public bool IsAvailable(string cryptoCode) + public bool IsConfigured(string cryptoCode) => WalletRpcClients.ContainsKey(cryptoCode) && DaemonRpcClients.ContainsKey(cryptoCode); + public bool IsAvailable(string cryptoCode) { cryptoCode = cryptoCode.ToUpperInvariant(); return _summaries.ContainsKey(cryptoCode) && IsAvailable(_summaries[cryptoCode]); @@ -97,7 +99,7 @@ namespace BTCPayServer.Plugins.Monero.Services } bool walletCreated = false; - retry: + retry: try { var walletResult = @@ -152,7 +154,9 @@ namespace BTCPayServer.Plugins.Monero.Services (await cashcow.SendCommandAsync("get_balance", JsonRpcClient.NoRequestModel.Instance)); if (balance.UnlockedBalance != 0) + { return; + } _logger.LogInformation("Mining blocks for the cashcow..."); var address = (await cashcow.SendCommandAsync("get_address", new() { @@ -165,7 +169,7 @@ namespace BTCPayServer.Plugins.Monero.Services }); _logger.LogInformation("Mining succeed!"); } - + private static async Task CreateTestWallet(JsonRpcClient walletRpcClient) { try diff --git a/Plugins/Monero/Services/MoneroSyncSummaryProvider.cs b/Plugins/Monero/Services/MoneroSyncSummaryProvider.cs index 2508f84..1bbcf1d 100644 --- a/Plugins/Monero/Services/MoneroSyncSummaryProvider.cs +++ b/Plugins/Monero/Services/MoneroSyncSummaryProvider.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; + using BTCPayServer.Abstractions.Contracts; using BTCPayServer.Client.Models; using BTCPayServer.Payments; @@ -25,12 +26,13 @@ namespace BTCPayServer.Plugins.Monero.Services { return _moneroRpcProvider.Summaries.Select(pair => new MoneroSyncStatus() { - Summary = pair.Value, PaymentMethodId = PaymentMethodId.Parse(pair.Key).ToString() + Summary = pair.Value, + PaymentMethodId = PaymentMethodId.Parse(pair.Key).ToString() }); } } - public class MoneroSyncStatus: SyncStatus, ISyncStatus + public class MoneroSyncStatus : SyncStatus, ISyncStatus { public override bool Available { @@ -42,4 +44,4 @@ namespace BTCPayServer.Plugins.Monero.Services public MoneroRPCProvider.MoneroLikeSummary Summary { get; set; } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/Utils/MoneroMoney.cs b/Plugins/Monero/Utils/MoneroMoney.cs index 8f4737c..20f2db9 100644 --- a/Plugins/Monero/Utils/MoneroMoney.cs +++ b/Plugins/Monero/Utils/MoneroMoney.cs @@ -17,4 +17,4 @@ namespace BTCPayServer.Plugins.Monero.Utils return System.Convert.ToInt64(monero * 1000000000000); } } -} +} \ No newline at end of file diff --git a/Plugins/Monero/ViewModels/MoneroPaymentViewModel.cs b/Plugins/Monero/ViewModels/MoneroPaymentViewModel.cs index d975f3d..6836fdb 100644 --- a/Plugins/Monero/ViewModels/MoneroPaymentViewModel.cs +++ b/Plugins/Monero/ViewModels/MoneroPaymentViewModel.cs @@ -1,4 +1,5 @@ using System; + using BTCPayServer.Payments; namespace BTCPayServer.Plugins.Monero.ViewModels @@ -14,4 +15,4 @@ namespace BTCPayServer.Plugins.Monero.ViewModels public string TransactionLink { get; set; } public string Currency { get; set; } } -} +} \ No newline at end of file diff --git a/README.md b/README.md index 3dbc5c4..f30810e 100644 --- a/README.md +++ b/README.md @@ -35,16 +35,16 @@ BTCPay Server's Docker deployment simplifies the setup by automatically configur ## Building and testing -## 🧑‍💻 Local Development Setup +## Local Development Setup If you're contributing to this plugin or running a local development instance of BTCPay Server with the Monero plugin, follow these steps. -## 1) Requirements +## 1. Requirements - .NET 8.0 SDK or later - JetBrains Rider (recommended) or Visual Studio Code with C# support - Git - Docker and Docker Compose -## 2) Clone the Repositories +## 2. Clone the Repositories Create a working directory and clone both the BTCPay Server and Monero plugin repositories side by side: If you are a developer maintaining this plugin, in order to maintain this plugin, you need to clone this repository with `--recurse-submodules`: @@ -63,7 +63,7 @@ To build and run unit tests, run the following commands: ```bash dotnet build btcpay-monero-plugin.sln -dotnet test BTCPayServer.Plugins.Monero.UnitTests --verbosity normal +dotnet test BTCPayServer.Plugins.UnitTests --verbosity normal ``` To run unit tests with coverage, install JetBrains dotCover CLI: @@ -83,7 +83,13 @@ dotnet build btcpay-monero-plugin.sln docker compose -f BTCPayServer.Plugins.IntegrationTests/docker-compose.yml run tests ``` -**BTCPAY_XMR_CASHCOW_WALLET_DAEMON_URI** | **Optional**. The URI of the [monero-wallet-rpc](https://getmonero.dev/interacting/monero-wallet-rpc.html) interface for the cashcow wallet. This is used to create a second wallet for testing purposes in regtest mode. | http:// +**BTCPAY_XMR_CASHCOW_WALLET_DAEMON_URI** | **Optional**. The URI of the [monero-wallet-rpc](https://getmonero.dev/interacting/monero-wallet-rpc.html) interface for the cashcow wallet. This is used to create a second wallet for testing purposes in regtest mode. + +## Code formatting + +We use the **unmodified** standardized `.editorconfig` from .NET SDK. Run `dotnet new editorconfig --force` to apply the latest version. + +To enforce formatting for the whole project, run `dotnet format btcpay-monero-plugin.sln --exclude submodules/* --verbosity diagnostic` ## 4. Configure BTCPay Server to Load the Plugin diff --git a/submodules/btcpayserver b/submodules/btcpayserver index 276bb1b..46aafe7 160000 --- a/submodules/btcpayserver +++ b/submodules/btcpayserver @@ -1 +1 @@ -Subproject commit 276bb1b165279f39d2f2f7efb614949ae4c3b5b3 +Subproject commit 46aafe7b8d31afb37350e10589af71a706097c90