Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Segwit Fee Calculation #127

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Fix Segwit Fee Calculation #127

wants to merge 6 commits into from

Conversation

nomo-app
Copy link
Owner

@nomo-app nomo-app commented Dec 19, 2024

Summary by CodeRabbit

  • New Features

    • Introduced a smart fee estimation option to provide more accurate fee predictions for transactions.
    • Added a method for estimating transaction fees based on the number of blocks.
    • Enhanced the ElectrumOutput class with a new method for converting to BTCOutput.
  • Refactor

    • Enhanced transaction fee calculations and weight measurements, improving support for SegWit transactions and overall fee assessment.
    • Improved logging for transaction fee calculations to enhance traceability.
    • Streamlined the handling of transaction inputs and outputs with more structured representations.
  • Tests

    • Expanded test coverage to ensure consistent smart fee functionality across multiple cryptocurrency networks.
    • Introduced a new test for the BTCRawTransaction class to validate instantiation.

Copy link

coderabbitai bot commented Dec 19, 2024

Walkthrough

This update introduces a new smart fee estimation method within the ElectrumXClient alongside enhancements to fee calculation logic and logging in UTXO transaction functions. The modifications include changes to transaction input handling with refined witness size and weight calculations, abstract getters in raw transactions, and adaptations in fee estimation methods in the UTXO analyzer to support a new smart fee option. Additionally, a utility function to compute variable-length integer sizes is added, and new tests verify smart fee estimation across multiple networks.

Changes

File(s) Change Summary
lib/src/crypto/utxo/repositories/electrum_json_rpc_client.dart Added new method estimateSmartFee to ElectrumXClient for estimating transaction fees using the ElectrumX "estimatesmartfee" call.
lib/src/crypto/utxo/utils/send.dart Enhanced logging in buildUnsignedTransaction and updated calculateFee to include a SegWit case that computes fee based on transaction weight.
lib/src/crypto/utxo/entities/raw_transaction/input.dart Modified the Input class and subclasses by introducing a new witnessSize getter, making weight an abstract getter, and updating implementations in BTCInput and EC8Input (including dynamic script size computations).
lib/src/crypto/utxo/entities/raw_transaction/raw_transaction.dart Updated the RawTransaction class: weight is now abstract, added vSize and feePerByte getters, implemented SegWit-specific weight calculations in BTCRawTransaction and adjusted EC8RawTransaction.
lib/src/crypto/utxo/utxo_analyzer.dart Modified fee estimation methods to accept a new useSmartFee flag, which conditionally selects between estimateSmartFee and estimateFee.
lib/src/utils/var_uint.dart Introduced a new utility function, getVarIntSize, to calculate the size of a variable-length integer based on its value.
test/ci/fetching/gasfees_test.dart Added new tests for smart fee estimation across multiple networks (Bitcoin, Litecoin, Bitcoincash, Zeniq) using the useSmartFee: true flag.

Sequence Diagram(s)

sequenceDiagram
    participant Analyzer as UTXO Analyzer
    participant Client as ElectrumXClient

    Analyzer->>Client: estimateFeeForPriority(blocks, ..., useSmartFee=true)
    alt Use Smart Fee
        Client->>Client: estimateSmartFee(blocks)
    else Use Legacy Fee
        Client->>Client: estimateFee(blocks)
    end
    Client-->>Analyzer: Fee estimation result
Loading

Suggested reviewers

  • ThomasFercher

Poem

In the code burrow, I happily hop,
Smart fees now dance, with each little pop.
Witness sizes and weights in a neat display,
Logging and tests light up the day.
For every bit of code, I cheer and play!
🐇💻


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
lib/src/crypto/utxo/repositories/electrum_json_rpc_client.dart (1)

218-228: Consider enhancing error handling for fee estimation.

While the implementation is correct, the error handling could be more informative. The current implementation throws a generic "Fee estimation failed" message for both null and zero fee cases.

Consider this improved implementation:

 Future<double> estimateSmartFee({required int blocks}) async {
   final response = await _client.sendRequest(
     {
       "method": "blockchain.estimatesmartfee",
       "params": [blocks]
     },
   );
   final fee = response as double?;
-  if (fee == null || fee == 0) throw Exception("Fee estimation failed");
+  if (fee == null) throw Exception("Fee estimation failed: received null response");
+  if (fee == 0) throw Exception("Fee estimation failed: received zero fee");
   return fee;
 }
lib/src/crypto/utxo/utils/send.dart (1)

Line range hint 218-228: Consider documenting fee estimation strategy.

With the addition of estimateSmartFee, the codebase now has two methods for fee estimation. Consider documenting:

  1. The differences between estimateFee and estimateSmartFee
  2. When to use each method
  3. The trade-offs between them
    This will help maintain consistency in fee estimation across the codebase.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9eb93eb and dfcac37.

📒 Files selected for processing (2)
  • lib/src/crypto/utxo/repositories/electrum_json_rpc_client.dart (1 hunks)
  • lib/src/crypto/utxo/utils/send.dart (1 hunks)
🔇 Additional comments (1)
lib/src/crypto/utxo/utils/send.dart (1)

596-599: LGTM! Efficient handling of client availability.

The addition of this condition is a good optimization that prevents unnecessary iterations when no clients are available for rebroadcasting.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (6)
test/ci/gasfees_test.dart (1)

11-19: Consider enhancing test validation and reducing duplication.

The tests follow a good pattern but could benefit from the following improvements:

  1. Add specific assertions for fee ranges to ensure reasonable values.
  2. Compare smart fee with regular fee to validate the difference.
  3. Extract common test logic to reduce duplication.

Consider refactoring to a shared test function:

Future<void> testNetworkFees(UTXONetworkType network, String networkName) async {
  final gasEntity = await getNetworkFees(network: network);
  expect(gasEntity, isNotNull);
  expect(gasEntity.nextBlock.value > BigInt.zero, true, reason: '$networkName next block fee should be positive');
  print('$networkName standard fees: $gasEntity');

  final smartGasEntity = await getNetworkFees(
    network: network,
    useSmartFee: true,
  );
  expect(smartGasEntity, isNotNull);
  expect(smartGasEntity.nextBlock.value > BigInt.zero, true, reason: '$networkName smart fee should be positive');
  print('$networkName smart fees: $smartGasEntity');
}

void main() {
  test('Estimate Fees BTC', () => testNetworkFees(BitcoinNetwork, 'BTC'));
  test('Estimate Fees LTC', () => testNetworkFees(LitecoinNetwork, 'LTC'));
  test('Estimate Fees BCH', () => testNetworkFees(BitcoincashNetwork, 'BCH'));
  test('Estimate Fees Zeniq', () => testNetworkFees(ZeniqNetwork, 'ZENIQ'));
}

Also applies to: 28-36, 45-53, 62-70

lib/src/crypto/utxo/utxo_analyzer.dart (3)

493-498: Document the smart fee parameter and improve error handling.

The smart fee implementation looks good, but consider these improvements:

  1. Add documentation explaining the difference between smart fee and regular fee estimation.
  2. Consider handling specific error cases from the ElectrumX server.

Add documentation and improve error handling:

 Future<Amount> estimateFeeForPriority({
   required int blocks,
   required UTXONetworkType network,
   required ElectrumXClient? initalClient,
-  bool useSmartFee = false,
+  /// When true, uses the ElectrumX estimatesmartfee method which provides more accurate
+  /// fee estimation based on recent block history and mempool state.
+  /// When false, uses the basic fee estimation method.
+  bool useSmartFee = false,
 }) async {
   final (fee, _, error) = await fetchFromRandomElectrumXNode(
     (client) => useSmartFee
         ? client.estimateSmartFee(blocks: blocks)
         : client.estimateFee(blocks: blocks),
     client: initalClient,
     endpoints: network.endpoints,
     token: network.coin,
   );

-  if (fee == null) throw Exception("Fee estimation failed");
+  if (fee == null) {
+    throw Exception("Fee estimation failed: ${error ?? 'Unknown error'}");
+  }

508-508: Consider adding bounds checking for fee calculation.

The fee calculation could benefit from minimum/maximum bounds to prevent unreasonable values.

-  final feePerB = feePerKb.multiplyAndCeil(0.001);
+  final feePerB = feePerKb.multiplyAndCeil(0.001);
+  // Ensure fee is within reasonable bounds (e.g., 1-1000 sat/byte)
+  if (feePerB.value < BigInt.from(1) || feePerB.value > BigInt.from(1000)) {
+    Logger.logWarning("Fee outside reasonable bounds: ${feePerB.value} sat/byte");
+  }

516-516: Document the multiplier parameter's purpose and constraints.

The multiplier parameter needs documentation to explain its purpose and valid range.

 Future<UtxoNetworkFees> getNetworkFees({
   required UTXONetworkType network,
-  double multiplier = 1.0,
+  /// Fee multiplier to adjust the estimated fees.
+  /// Must be greater than 0. Values > 1 increase fees, values < 1 decrease fees.
+  /// @throws ArgumentError if multiplier <= 0
+  double multiplier = 1.0,
   bool useSmartFee = false,
 }) async {
+  if (multiplier <= 0) {
+    throw ArgumentError.value(multiplier, 'multiplier', 'Must be greater than 0');
+  }
lib/src/crypto/utxo/entities/raw_transaction/raw_transaction.dart (2)

40-41: Fee per byte division by zero check
Since size can theoretically be zero for certain edge cases, consider either bounding or verifying that size is non-zero before dividing. Otherwise, a potential runtime exception may occur.

-double get feePerByte => fee.toInt() / size;
+double get feePerByte {
+  if (size == 0) return 0; 
+  return fee.toInt() / size;
+}

509-520: Summation-based weight in EC8
EC8RawTransaction weight simply accumulates input + output weights. Confirm that additional overhead fields (version, validFrom, validUntil, etc.) don’t also need weighting. To avoid confusion, add a small comment or a helper function to incorporate overhead if applicable.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dfcac37 and 30719b8.

📒 Files selected for processing (6)
  • lib/src/crypto/utxo/entities/raw_transaction/input.dart (4 hunks)
  • lib/src/crypto/utxo/entities/raw_transaction/raw_transaction.dart (4 hunks)
  • lib/src/crypto/utxo/utils/send.dart (3 hunks)
  • lib/src/crypto/utxo/utxo_analyzer.dart (2 hunks)
  • lib/src/utils/var_uint.dart (1 hunks)
  • test/ci/gasfees_test.dart (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/src/crypto/utxo/utils/send.dart
🔇 Additional comments (7)
lib/src/crypto/utxo/entities/raw_transaction/input.dart (2)

46-46: Abstract getter is well-structured
Declaring "BigInt get weight;" in the base class ensures that each subclass correctly implements its own weight logic. Nicely done.


239-239: Dynamic size calculation for scriptSig
Using getVarIntSize(scriptSig.length) is a good approach to handle variable-length integers. The usage here appears correct and more future-proof than a fixed-size approach.

lib/src/crypto/utxo/entities/raw_transaction/raw_transaction.dart (4)

24-26: Abstract getter design
Defining "BigInt get weight;" as an abstract in RawTransaction cleanly enforces the specialized logic in each subclass. Good job providing a strong contract for transaction classes.


27-29: vSize calculation
Dividing weight by 4 matches standard meal-of-bytes for vSize. This logic is correct for standard Bitcoin usage.


213-215: isSegwit logic
Checking return inputs.any((input) => input.isSegwit); is concise. If partial Segwit usage is expected, you may want to confirm that all inputs must be segwit to treat the transaction as segwit.


194-211: Verify the combined weight calculation
You're adding a base overhead (line 197) if isSegwit is true, then summing input/output weights. Ensure that the overhead properly accounts for all fields (including marker & flag) and that you don’t double-count them in the individual inputs.

✅ Verification successful

Let me gather more information about the weight calculation by checking the input and output weight implementations.


Let me check one more thing about the script weight calculation.


Let me check the script weight calculation implementation.


Based on the comprehensive review of the weight calculation implementation, I can now provide the final response:

Weight calculation implementation is correct
The transaction weight calculation properly accounts for all components:

  • Base transaction overhead (version + locktime) * 4
  • Segwit marker and flag overhead (2 bytes * 4) when applicable
  • Input weights are calculated separately and include their script weights
  • Output weights are calculated separately with their script weights
  • Script weight calculation properly handles different opcodes with appropriate weights

The implementation follows the BIP-141 weight calculation rules, and there is no double-counting of segwit fields as the marker and flag are only added once at the transaction level, while individual input weights are calculated independently.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Cross-check references to isSegwit and the segwit overhead calculation
rg -A 5 "isSegwit"

Length of output: 6078


Script:

#!/bin/bash
# Check input weight calculation
ast-grep --pattern 'get weight {
  $$$
}'

# Check for any weight-related constants
rg "weight" -B 2 -A 2

Length of output: 17028


Script:

#!/bin/bash
# Check for script weight calculation
ast-grep --pattern 'getScriptWeight'
rg "getScriptWeight"

Length of output: 473


Script:

#!/bin/bash
# Check script weight calculation implementation
cat lib/src/crypto/utxo/entities/script.dart

Length of output: 3931

lib/src/utils/var_uint.dart (1)

124-136: New function getVarIntSize
This function aligns with variable integer encoding logic (BIP141 style). Consider adding validation for negative values to avoid potential edge cases. Otherwise, it looks correct.

Comment on lines 32 to 43
BigInt get witnessSize {
if (_wittnessScript == null || _wittnessScript!.isEmpty) return 0.toBI;

BigInt size = getVarIntSize(_wittnessScript!.length)
.toBI; // Count of witness elements

for (final element in witness!) {
size += getVarIntSize(element.length).toBI; // Size of this element
size += element.length.toBI; // The element itself
}

return size;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential missing 'witness' property reference and spelling concern
It looks like line 38 refers to "for (final element in witness!)", but this property or getter named "witness" is not defined within the class. This might be an unintentional reference, a leftover from a refactor, or a missing getter. Also note that the internal field is spelled "_wittnessScript" instead of "_witnessScript." Consider renaming and ensuring code references match.

Comment on lines 291 to 296
@override
BigInt get weight {
if (_scriptSig == null || _prevScriptPubKey == null) return -1.toBI;
return calculateWeight(_prevScriptPubKey!, _scriptSig!);
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid returning negative weight
Returning -1.toBI from the weight getter might lead to unexpected behavior if the rest of the codebase assumes weight is non-negative. A better approach might be to return 0.toBI or throw an exception if the data is insufficient to compute the weight.

- if (_scriptSig == null || _prevScriptPubKey == null) return -1.toBI;
+ if (_scriptSig == null || _prevScriptPubKey == null) {
+   // Consider returning 0 or throwing an informative exception
+   return 0.toBI;
+ }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 258 to 275

@override
BigInt get weight {
BigInt weight = (txid.length + output_index_length + sequence_length).toBI *
4.toBI; // (32 + 4 + 4) * 4

weight +=
(scriptSig.length + getVarIntSize(scriptSig.length)).toBI * 4.toBI;

if (_wittnessScript != null) {
weight +=
(_wittnessScript!.length + getVarIntSize(_wittnessScript!.length))
.toBI *
4.toBI;
}

return weight;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Weight calculation for witness data needs correction

Based on the code review and search results, the current implementation incorrectly applies a weight multiplier of 4 to witness data (_wittnessScript). According to the Segwit specification (BIP141):

  • Non-witness data (txid, output_index, sequence, scriptSig) should have a weight of 4 units per byte
  • Witness data (_wittnessScript) should have a weight of 1 unit per byte

The code needs to be modified to multiply _wittnessScript length by 1 instead of 4.

Locations needing attention:

  • lib/src/crypto/utxo/entities/raw_transaction/input.dart: Change the witness data weight calculation from 4.toBI to 1.toBI
🔗 Analysis chain

Verify correctness of Segwit weighting
Current logic multiplies all scriptSig and witness data lengths by 4. Typically, non-witness data is counted as 4 weight units/byte, while witness data is 1 weight unit/byte. Mixing them at 4 might incorrectly inflate the transaction weight. Confirm or correct the weighting to accurately reflect Segwit’s weighting rules.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Searching for weight calculations that multiply witness data by 4
rg -A 3 "weight.*=.*(_wittnessScript|witnessSize).*4"

Length of output: 55


Script:

#!/bin/bash
# Let's search for all weight-related calculations in the codebase
rg -A 5 "weight.*=.*\*.*4" lib/

Length of output: 868


Script:

#!/bin/bash
# Let's also check for any BIP documentation or comments about Segwit weight calculation
rg -i "segwit.*weight|weight.*segwit" lib/

Length of output: 285


Script:

#!/bin/bash
# Let's look at the entire input class implementation to understand the context better
ast-grep --pattern 'class Input {
  $$$
}'

Length of output: 44


Script:

#!/bin/bash
# Let's also check if there are any test files validating the weight calculation
fd -e dart test_weight -x cat {}
fd -e dart weight_test -x cat {}

Length of output: 73


Script:

#!/bin/bash
# Let's try a different pattern to find the Input class implementation
ast-grep --pattern 'class Input {
  BigInt get weight {
    $$$
  }
}'

Length of output: 72


Script:

#!/bin/bash
# Let's also check for any test files related to transaction weight or segwit
rg -l "test.*weight|test.*segwit" --type dart

Length of output: 47


Script:

#!/bin/bash
# Let's look for any documentation about weight calculation in comments
rg -B 2 -A 2 "weight.*=|weight.*{" --type dart

Length of output: 150

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
test/ci/fetching/gasfees_test.dart (3)

5-71: Consider refactoring tests to reduce duplication.

The test structure is identical across all networks, which presents an opportunity to improve maintainability through parameterized testing.

Consider refactoring using a helper function and test parameters:

void main() {
  final networks = [
    BitcoinNetwork,
    LitecoinNetwork,
    BitcoincashNetwork,
    ZeniqNetwork,
  ];

  Future<void> testNetworkFees(Network network) async {
    test('Estimate Fees ${network.runtimeType}', () async {
      final gasEntity = await getNetworkFees(network: network);
      expect(gasEntity, isNotNull);
      print(gasEntity);

      final smartGasEntity = await getNetworkFees(
        network: network,
        useSmartFee: true,
      );
      expect(smartGasEntity, isNotNull);
      print(smartGasEntity);
    });
  }

  for (final network in networks) {
    testNetworkFees(network);
  }
}

8-8: Enhance test assertions for better coverage.

The current assertions only verify that the returned entities are not null. Consider adding more specific assertions to validate:

  • The structure of the returned entities
  • The relationship between standard and smart fee values
  • The range of acceptable fee values

Example of enhanced assertions:

expect(gasEntity.fee, isPositive);
expect(gasEntity.fee, lessThan(maxExpectedFee));
expect(smartGasEntity.fee, isPositive);
expect(smartGasEntity.fee, lessThan(maxExpectedFee));
// Optionally, verify smart fee is within a reasonable range of standard fee
expect((smartGasEntity.fee - gasEntity.fee).abs(), lessThan(maxFeeDifference));

Also applies to: 17-17, 25-25, 34-34, 42-42, 51-51, 59-59, 68-68


10-10: Consider enhancing test documentation and error handling.

The tests would benefit from:

  1. Using a proper logging framework instead of print statements
  2. Adding documentation about expected behavior
  3. Including error case scenarios

Example improvements:

// Add test documentation
/// Tests fee estimation for different networks.
/// Expected behavior:
/// - Standard fees should reflect current network conditions
/// - Smart fees should provide more accurate estimates for different priorities
/// - Both methods should handle network errors gracefully

// Add error case tests
test('Handle network errors gracefully', () async {
  // Test with invalid network
  expect(
    () => getNetworkFees(network: invalidNetwork),
    throwsA(isA<NetworkException>()),
  );

  // Test with network timeout
  expect(
    () => getNetworkFees(network: network, timeout: Duration.zero),
    throwsA(isA<TimeoutException>()),
  );
});

// Use proper logging
import 'package:logging/logging.dart';
final _logger = Logger('GasFeesTest');
// ...
_logger.info('Standard fee result: $gasEntity');

Also applies to: 19-19, 27-27, 36-36, 44-44, 53-53, 61-61, 70-70

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30719b8 and 93ff42c.

📒 Files selected for processing (5)
  • lib/src/crypto/utxo/repositories/electrum_json_rpc_client.dart (1 hunks)
  • lib/src/crypto/utxo/utils/send.dart (3 hunks)
  • lib/src/crypto/utxo/utxo_analyzer.dart (2 hunks)
  • lib/src/utils/var_uint.dart (1 hunks)
  • test/ci/fetching/gasfees_test.dart (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • lib/src/crypto/utxo/repositories/electrum_json_rpc_client.dart
  • lib/src/utils/var_uint.dart
  • lib/src/crypto/utxo/utils/send.dart
  • lib/src/crypto/utxo/utxo_analyzer.dart

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (12)
lib/src/crypto/utxo/utils/pubkey_to_address.dart (1)

130-133: Function name typo and missing documentation

The newly added function has a name typo - it should be "ripemd160Hash" instead of "ripmed160Hash" to match the standard naming convention for this hash algorithm. Also, unlike other hash functions in this file, this one lacks a documentation comment.

-Uint8List ripmed160Hash(Uint8List buffer) {
+/// 
+/// Ripmed160 Hash
+/// 
+Uint8List ripemd160Hash(Uint8List buffer) {
   final ripmed160 = RIPEMD160Digest();
   return ripmed160.process(buffer);
 }

Note: Since this function is likely being added to support segwit fee calculation, ensure any references to this function name are updated if you decide to fix the typo.

lib/src/crypto/utxo/entities/op_codes.dart (1)

153-155: Useful utility method, but needs documentation.

The new fromHex static method provides a helpful way to look up an opcode by its hex value, which is valuable for the Segwit fee calculation improvements. However, it would benefit from documentation explaining its purpose and behavior.

+  /// Returns the OPCODE enum value corresponding to the given hex value,
+  /// or null if no matching opcode is found.
   static OPCODE? fromHex(int hex) {
     return OPCODE.values.singleWhereOrNull((element) => element.hex == hex);
   }
test/ci/raw_transaction/btc_raw_transaction_test.dart (1)

1-14: Fix unused import and variable warnings

There are two pipeline warnings in this test file:

  1. The import on line 2 for input.dart is unused
  2. The tx variable created on line 9 is not used anywhere

Apply these changes to fix the warnings:

-import 'package:walletkit_dart/src/crypto/utxo/entities/raw_transaction/input.dart';

And either add assertions to use the tx variable or remove it:

-      final tx = BTCRawTransaction(
+      // Create a BTC transaction (just verifying it constructs properly)
+      BTCRawTransaction(
🧰 Tools
🪛 GitHub Actions: TestSuite

[warning] 2-2: Unused import: 'package:walletkit_dart/src/crypto/utxo/entities/raw_transaction/input.dart'. Try removing the import directive.


[warning] 9-9: The value of the local variable 'tx' isn't used. Try removing the variable or using it.

lib/src/crypto/utxo/utils/proof_of_payment.dart (2)

5-7: Remove unused import

There's an unused import of op_codes.dart that can be removed according to the pipeline warning.

-import 'package:walletkit_dart/src/crypto/utxo/entities/op_codes.dart';
🧰 Tools
🪛 GitHub Actions: TestSuite

[warning] 5-5: Unused import: 'package:walletkit_dart/src/crypto/utxo/entities/op_codes.dart'. Try removing the import directive.


94-104: Improved script creation for OP_RETURN

The code now correctly uses the OPReturnScript class instead of manually constructing a script with OP_RETURN. This approach is more structured and aligns with the refactoring done in the codebase for script handling.

Consider adding a comment explaining why the size is calculated as 2 + 32 + nonceBytes.length + 1 for better maintainability:

-  final pop_output_script_data = Uint8List(2 + 32 + nonceBytes.length + 1);
+  // Size: 2 bytes (version) + 32 bytes (txid) + variable length nonce + 1 byte (VarInt for nonce)
+  final pop_output_script_data = Uint8List(2 + 32 + nonceBytes.length + 1);
lib/src/crypto/utxo/entities/transactions/utxo_transaction.dart (1)

541-549: Check whether additional fields should be preserved.
This extension only maps value and scriptPubKey.lockingScript into a BTCOutput, ignoring other ElectrumOutput fields like belongsToUs, spent, or node. If those fields are relevant downstream, consider including them or documenting why they’re omitted.

lib/src/crypto/utxo/entities/raw_transaction/input.dart (1)

32-47: Consider removing or finalizing commented-out witness code.
Leaving large blocks of commented code can create confusion. If no longer needed, remove them. If still relevant, reintroduce them or add clearer TODO comments.

lib/src/crypto/utxo/entities/raw_transaction/raw_transaction.dart (3)

40-41: Potential precision concern in feePerByte.
Casting fee to int could overflow with very large fees, and using a double may lose precision.


299-300: Minor naming inconsistency.
Consider renaming wittnessScriptswitnessScripts for clarity.

-List<(BTCUnlockingScript, BTCInput)> wittnessScripts = [];
+List<(BTCUnlockingScript, BTCInput)> witnessScripts = [];

413-416: Support for only SIG_HASH_ALL is documented.
If you plan to add other types (e.g., SIGHASH_SINGLE), ensure the code handles them gracefully.

lib/src/crypto/utxo/entities/raw_transaction/tx_structure.dart (2)

434-446: OPReturnScript
Limits data to 80 bytes. Suitable for typical OP_RETURN usage, but double-check any protocol requiring smaller OP_RETURN.


504-526: SegwitFormat
Unimplemented buildBuffer again. Mark or track TODO so it’s not forgotten.

Do you want a helper function or a follow-up commit to implement it fully?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a86a6f and 50e9371.

📒 Files selected for processing (15)
  • lib/src/crypto/utxo/entities/op_codes.dart (2 hunks)
  • lib/src/crypto/utxo/entities/payments/p2h.dart (0 hunks)
  • lib/src/crypto/utxo/entities/payments/pk_script_converter.dart (0 hunks)
  • lib/src/crypto/utxo/entities/raw_transaction/input.dart (10 hunks)
  • lib/src/crypto/utxo/entities/raw_transaction/output.dart (7 hunks)
  • lib/src/crypto/utxo/entities/raw_transaction/raw_transaction.dart (14 hunks)
  • lib/src/crypto/utxo/entities/raw_transaction/tx_structure.dart (1 hunks)
  • lib/src/crypto/utxo/entities/transactions/utxo_transaction.dart (2 hunks)
  • lib/src/crypto/utxo/utils/proof_of_payment.dart (2 hunks)
  • lib/src/crypto/utxo/utils/pubkey_to_address.dart (1 hunks)
  • lib/src/crypto/utxo/utils/send.dart (13 hunks)
  • lib/src/domain/entities/generic_transaction.dart (1 hunks)
  • test/ci/proof_of_payment/pop_test.dart (12 hunks)
  • test/ci/raw_transaction/btc_raw_transaction_test.dart (1 hunks)
  • test/no_ci/input_simulation_test.dart (1 hunks)
💤 Files with no reviewable changes (2)
  • lib/src/crypto/utxo/entities/payments/p2h.dart
  • lib/src/crypto/utxo/entities/payments/pk_script_converter.dart
✅ Files skipped from review due to trivial changes (1)
  • lib/src/domain/entities/generic_transaction.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/src/crypto/utxo/utils/send.dart
🧰 Additional context used
🪛 GitHub Actions: TestSuite
test/ci/raw_transaction/btc_raw_transaction_test.dart

[warning] 2-2: Unused import: 'package:walletkit_dart/src/crypto/utxo/entities/raw_transaction/input.dart'. Try removing the import directive.


[warning] 9-9: The value of the local variable 'tx' isn't used. Try removing the variable or using it.

lib/src/crypto/utxo/utils/proof_of_payment.dart

[warning] 5-5: Unused import: 'package:walletkit_dart/src/crypto/utxo/entities/op_codes.dart'. Try removing the import directive.

lib/src/crypto/utxo/entities/raw_transaction/input.dart

[warning] 6-6: Unused import: 'package:walletkit_dart/src/crypto/utxo/entities/script.dart'. Try removing the import directive.


[warning] 7-7: Unused import: 'package:walletkit_dart/src/crypto/utxo/entities/op_codes.dart'. Try removing the import directive.


[warning] 10-10: Unused import: 'package:walletkit_dart/walletkit_dart.dart'. Try removing the import directive.


[warning] 80-80: The value of the local variable 'redeemScript' isn't used. Try removing the variable or using it.

lib/src/crypto/utxo/entities/raw_transaction/output.dart

[warning] 6-6: Unused import: 'package:walletkit_dart/src/crypto/utxo/entities/script.dart'. Try removing the import directive.

🔇 Additional comments (72)
lib/src/crypto/utxo/entities/op_codes.dart (3)

5-5: Good import addition for required functionality.

The collection package provides the necessary singleWhereOrNull extension method used in the new fromHex method.


153-155: Consider handling duplicate hex values consistently.

There are cases in the enum where multiple opcodes share the same hex value (e.g., OP_0/OP_FALSE, OP_NOP2/OP_CHECKLOCKTIMEVERIFY). The current implementation will return the first matching opcode, which may not always be the expected one.

Consider whether this behavior is acceptable for your use case. If not, you might need to implement a more sophisticated lookup strategy or document this limitation.


3-3: Existing TODO should be addressed in a future PR.

There's an existing TODO to refactor this class for better readability. While not related to the current changes, this technical debt should be tracked and addressed in a future PR.

test/no_ci/input_simulation_test.dart (2)

308-309: Property name change from scriptPubKey to script looks good

Correctly updated BTCOutput to use the new script property name instead of scriptPubKey.


312-313: Property name change from scriptPubKey to script looks good

Correctly updated EC8Output to use the new script property name instead of scriptPubKey.

test/ci/proof_of_payment/pop_test.dart (12)

52-53: Property access pattern updated correctly

The code has been correctly updated to access script data via the new structure.


74-75: Property access pattern updated correctly

Input script access has been correctly updated to use the new structure.


133-134: Property access pattern updated correctly

Script data access has been correctly updated to use the new structure.


155-156: Property access pattern updated correctly

Input script access has been correctly updated to use the new structure.


197-198: Property access pattern updated correctly

Script data access has been correctly updated to use the new structure.


219-220: Property access pattern updated correctly

Input script access has been correctly updated to use the new structure.


265-266: Property access pattern updated correctly

Script data access has been correctly updated to use the new structure.


287-288: Property access pattern updated correctly

Input script access has been correctly updated to use the new structure.


348-349: Property access pattern updated correctly

Script data access has been correctly updated to use the new structure.


370-371: Property access pattern updated correctly

Input script access has been correctly updated to use the new structure.


426-427: Property access pattern updated correctly

Script data access has been correctly updated to use the new structure.


448-449: Property access pattern updated correctly

Input script access has been correctly updated to use the new structure.

lib/src/crypto/utxo/entities/transactions/utxo_transaction.dart (1)

509-510: Consider handling invalid hex strings.
If hexString is malformed or empty, hex.decode(hexString) will throw. It may be prudent to add an assertion or error-handling mechanism to prevent runtime exceptions.

lib/src/crypto/utxo/entities/raw_transaction/output.dart (12)

14-14: Typed script property looks good.
Replacing a raw Uint8List with a BTCLockingScript clarifies responsibility for script parsing and is consistent with the new design.


18-18: Simplified scriptHex getter is clear.
This change helps unify script representation with the rest of the codebase.


26-27: Validate the feasibility of script-based weight.
Ensure that script.weight correctly accounts for witness vs non-witness data if the script can be Segwit. Otherwise, this approach might over/under-calculate transaction weight.


30-30: Constructor update is consistent.
Requiring script explicitly is a good move toward more robust, non-nullable design.


48-49: Validate reading the script from the buffer.
Double-check offset correctness in fromBuffer(). Any mismatch can corrupt subsequent reads.


53-53: Constructing BTCLockingScript from buffer is a great improvement.
Typing the script data as BTCLockingScript clarifies its usage and prevents confusion with raw byte slices.


58-58: Allocate buffer capacity carefully.
value_length + script.size + 1 works, but ensure that script size plus the VarInt prefix reliably fits. If script becomes large, you might need additional length checks to avoid RangeError.


66-66: VarInt usage is correct here.
Writing the script length with writeVarSlice() is a standard approach. No issues spotted.


80-82: Confirm weight logic for EC8Output.
Allocating value_length + weight_length + script.size + 1 might be correct for your protocol, but be sure you’re not ignoring SegWit specifics if intended.


108-109: Edge case: zero weight
Here, the code sets weight to 0. If a script is actually standard or non-segwit, the weight might differ. Confirm this approach is correct for your scenario, or handle potential future expansions.


111-112: Check for sufficient space.
Writing the script to the buffer requires the allocated length to accommodate both the VarInt prefix and the script bytes. Any mismatch can cause an out-of-bounds error.


133-134: Ensure consistent usage of BTCLockingScript.fromBuffer().
This matches the design pattern used in BTCOutput.fromBuffer(). Good consistency across your outputs.

lib/src/crypto/utxo/entities/raw_transaction/input.dart (6)

19-23: New fields strongly typed.
Introducing prevOutput and script clarifies the relation between an input and its previous output. This is a solid improvement toward structured data handling.


55-55: Weight as an abstract getter is fine, but be careful with unimplemented states.
Any subclass must implement this carefully to avoid negative or inaccurate weight, especially with SegWit rules.


74-75: hasWitness logic.
script is ScriptWitness is a simplified check. Ensure no edge cases exist if the script’s type changes or if other script kinds might also hold witness data.


77-82: Ensure publicKeyFromSig covers all script variants.
Currently, the switch throws for RedeemScript and unknown scripts. Confirm this is intentional or if more integration with multi-sig or advanced scripts is required.

🧰 Tools
🪛 GitHub Actions: TestSuite

[warning] 80-80: The value of the local variable 'redeemScript' isn't used. Try removing the variable or using it.


85-85: addScript(...) signature is clear.
This pattern of returning a new instance with updated script fosters immutability.


132-134: Nullable prevOutput in factory constructor.
Currently, prevOutput is null upon creation. Confirm a follow-up mechanism is in place to set the actual reference if needed, or clarify if a separate path is used for non-lookup scenarios.

lib/src/crypto/utxo/entities/raw_transaction/raw_transaction.dart (11)

4-4: No issues with the new import.
It references needed classes from tx_structure.dart.


24-25: Good introduction of abstract weight.
Making weight abstract ensures each subclass implements its own specialized calculation.


27-29: vSize calculation is standard for Bitcoin-like transactions.
Integer division by 4 matches typical SegWit vSize = weight / 4.


194-215: Verify weight components include varint overhead.
Although adding base fields and segwit markers is correct, ensure input/output counts’ varints are accounted for in input.weight/output.weight. Otherwise, weight may be slightly underestimated.


217-219: isSegwit property is straightforward.
Treating the transaction as SegWit if one input is SegWit aligns with typical Bitcoin node logic.


308-319: Check boundary conditions when reading witness data.
If the buffer is malformed or an input is not found in inputs, code may throw or incorrectly parse.


424-426: Enforced assertion for SIGHASH_ALL.
This is a helpful runtime check, but consider returning a descriptive exception.


430-430: Forcibly creating a P2PKH script from prevScript.data.
Validate or guard if prevScript is not truly P2PKH to avoid unexpected behavior.


464-464: Writing script bytes for outputs.
This looks consistent with typical varint + script buffer format.


470-471: Index bounds check recommended.
Ensure index < inputs.length before referencing inputs[index].


481-481: Appending p2pkh script is correct for standard signatures.
No immediate issues.

lib/src/crypto/utxo/entities/raw_transaction/tx_structure.dart (25)

1-13: Imports look appropriate.
All imported packages appear valid for address encoding/decoding and script handling.


14-22: InputType enum covers major script types.
It’s a clear, organized approach for classification.


23-34: Base BTCScript class uses getScriptWeight externally.
Ensure getScriptWeight is defined and tested. The added +1 might slightly overcount weight.


35-163: BTCLockingScript handles multiple address formats.
Implementation covers P2PK, P2PKH, P2SH, P2WPKH, etc. Ensure more exotic cases or edge addresses throw early. Watch out for the BCH block where bitcoincash: is transformed into a statement akin to P2WPKH—verify correctness if truly intended.


165-178: BTCUnlockingScript base.
Factory approach for script types is neat; watch for unknown or unhandled leading bytes.


179-203: RedeemScript structure is consistent.
Parses signature and script correctly for P2SH. No critical issues identified.


204-223: ScriptSignature design is fine for typical P2PKH unlocking.
Double-check large public keys or non-standard scriptSig lengths.


225-245: ScriptWitness design.
Implementation appears aligned with SegWit witness data. Confirm no mismatch in lengths if there are multiple pushes.


247-271: TimeLockedScript for CSV/CLTV logic.
Check for corner cases around large lockTime or negative indexes. Currently it’s a single byte for lockTime.


273-287: PayToPublicKeyScript
Straightforward. Just confirm the last op is indeed OP_CHECKSIG.


289-306: PayToPublicKeyHashScript
Implementation matches standard OP_DUP / OP_HASH160 structure. Looks correct.


308-323: PayToScriptHashScript
Good usage of OP_HASH160. The sublist constraints are correct.


325-339: PayToWitnessPublicKeyHashScript
Standard P2WPKH structure recognized. Ensure length checks for unusual data.


341-355: PayToWitnessScriptHashScript
Similarly standard for P2WSH. Confirm the 32-byte script hash is always present.


357-363: NestedSegwitScript
Holds a nested script hash. If used in place of real P2SH-wrapped segwit, ensure it’s tested.


364-379: PayToWitnessPublicKeyHashNestedScript
Implements nested P2WPKH. Check the ripmed160Hash usage for correctness.


380-395: PayToWitnessScriptHashNestedScript
Creates a nested P2WSH using sha256Hash. Check that the script is always 32 bytes.


397-409: PayToTaprootScript
Implementation is minimal. OP_1 indicates v1 witness. Confirm a 32-byte key is enforced.


448-450: AnyoneCanSpendScript
Just sets OP_TRUE. This is a typical dev/test convenience script.


452-454: EmptyScript
Represents a zero-length script. No issues identified.


456-458: EmptyUnlockingScript
Same idea—script length zero for unlocking. Looks correct for placeholders.


460-462: EmptyLockingScript
Again, zero-length script for placeholders.


464-484: BTCTransactionStructure
A sealed base class for transaction formats. The create factory is unimplemented, so ensure usage is appropriate.


486-502: LegacyFormat
Empty buildBuffer suggests incomplete or placeholder logic. Ensure final usage is implemented.


528-541: TaprootFormat
Extends SegwitFormat with a new version and extra input type. The buildBuffer is also unimplemented.

Comment on lines +6 to +16
test(
"Legacy BTC Raw Transaction Test",
() async {
final tx = BTCRawTransaction(
version: BitcoinNetwork.txVersion,
lockTime: 0,
inputs: [],
outputs: [],
);
},
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Test is incomplete - missing assertions

This test creates a BTCRawTransaction but doesn't verify any of its properties or behavior. This makes the test ineffective for detecting regressions.

Add assertions to verify the transaction properties, especially those related to Segwit fee calculation which is the focus of this PR:

      final tx = BTCRawTransaction(
        version: BitcoinNetwork.txVersion,
        lockTime: 0,
        inputs: [],
        outputs: [],
      );
+      
+      // Verify basic properties
+      expect(tx.version, equals(BitcoinNetwork.txVersion));
+      expect(tx.lockTime, equals(0));
+      expect(tx.inputs, isEmpty);
+      expect(tx.outputs, isEmpty);
+      
+      // Verify Segwit-related properties
+      expect(tx.isSegwit, isFalse);
+      expect(tx.hasWitness, isFalse);
+      expect(tx.weight, equals(tx.size * 4));  // Non-Segwit tx weight = size * 4
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test(
"Legacy BTC Raw Transaction Test",
() async {
final tx = BTCRawTransaction(
version: BitcoinNetwork.txVersion,
lockTime: 0,
inputs: [],
outputs: [],
);
},
);
test(
"Legacy BTC Raw Transaction Test",
() async {
final tx = BTCRawTransaction(
version: BitcoinNetwork.txVersion,
lockTime: 0,
inputs: [],
outputs: [],
);
// Verify basic properties
expect(tx.version, equals(BitcoinNetwork.txVersion));
expect(tx.lockTime, equals(0));
expect(tx.inputs, isEmpty);
expect(tx.outputs, isEmpty);
// Verify Segwit-related properties
expect(tx.isSegwit, isFalse);
expect(tx.hasWitness, isFalse);
expect(tx.weight, equals(tx.size * 4)); // Non-Segwit tx weight = size * 4
},
);
🧰 Tools
🪛 GitHub Actions: TestSuite

[warning] 9-9: The value of the local variable 'tx' isn't used. Try removing the variable or using it.

@@ -2,6 +2,7 @@ import 'dart:typed_data';

import 'package:convert/convert.dart';
import 'package:walletkit_dart/src/crypto/utxo/entities/raw_transaction/input.dart';
import 'package:walletkit_dart/src/crypto/utxo/entities/raw_transaction/tx_structure.dart';
import 'package:walletkit_dart/src/crypto/utxo/entities/script.dart';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove the unused import.
The pipeline flagged import 'package:walletkit_dart/src/crypto/utxo/entities/script.dart'; as unused. Please remove it to satisfy lint rules and keep the codebase clean.

-import 'package:walletkit_dart/src/crypto/utxo/entities/script.dart';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import 'package:walletkit_dart/src/crypto/utxo/entities/script.dart';
🧰 Tools
🪛 GitHub Actions: TestSuite

[warning] 6-6: Unused import: 'package:walletkit_dart/src/crypto/utxo/entities/script.dart'. Try removing the import directive.

Comment on lines 6 to 7
import 'package:walletkit_dart/src/crypto/utxo/entities/script.dart';
import 'package:walletkit_dart/src/crypto/utxo/entities/op_codes.dart';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove or comment out the unused imports.
The pipeline flagged these imports as unused:

  • package:walletkit_dart/src/crypto/utxo/entities/script.dart
  • package:walletkit_dart/src/crypto/utxo/entities/op_codes.dart
  • package:walletkit_dart/walletkit_dart.dart

Please remove them or use them to satisfy lint rules.

-import 'package:walletkit_dart/src/crypto/utxo/entities/script.dart';
-import 'package:walletkit_dart/src/crypto/utxo/entities/op_codes.dart';
-import 'package:walletkit_dart/walletkit_dart.dart';

Also applies to: 10-10

🧰 Tools
🪛 GitHub Actions: TestSuite

[warning] 6-6: Unused import: 'package:walletkit_dart/src/crypto/utxo/entities/script.dart'. Try removing the import directive.


[warning] 7-7: Unused import: 'package:walletkit_dart/src/crypto/utxo/entities/op_codes.dart'. Try removing the import directive.

return switch (script) {
ScriptSignature scripSig => scripSig.publicKey,
ScriptWitness scriptWitness => scriptWitness.publicKey,
RedeemScript redeemScript => throw Exception("Redeem Script"),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove the unused 'redeemScript' variable if it still exists.
The pipeline indicates a local redeemScript is declared but unused around line 80. Consider removing or using it to avoid warnings.

🧰 Tools
🪛 GitHub Actions: TestSuite

[warning] 80-80: The value of the local variable 'redeemScript' isn't used. Try removing the variable or using it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants