Skip to content

feat(core): FeePayer abstraction#362

Draft
Hanssen0 wants to merge 2 commits intockb-devrel:releases/nextfrom
Hanssen0:feat/fee-payer
Draft

feat(core): FeePayer abstraction#362
Hanssen0 wants to merge 2 commits intockb-devrel:releases/nextfrom
Hanssen0:feat/fee-payer

Conversation

@Hanssen0
Copy link
Member

@Hanssen0 Hanssen0 commented Mar 21, 2026

Refactors #328

@changeset-bot
Copy link

changeset-bot bot commented Mar 21, 2026

🦋 Changeset detected

Latest commit: 0d38e4c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
Name Type
@ckb-ccc/core Minor
@ckb-ccc/did-ckb Patch
@ckb-ccc/eip6963 Patch
@ckb-ccc/joy-id Patch
@ckb-ccc/lumos-patches Patch
@ckb-ccc/nip07 Patch
@ckb-ccc/okx Patch
@ckb-ccc/rei Patch
@ckb-ccc/shell Patch
@ckb-ccc/spore Patch
@ckb-ccc/ssri Patch
@ckb-ccc/type-id Patch
@ckb-ccc/udt Patch
@ckb-ccc/uni-sat Patch
@ckb-ccc/utxo-global Patch
@ckb-ccc/xverse Patch
@ckb-ccc/ccc Patch
ckb-ccc Patch
@ckb-ccc/connector Patch
@ckb-ccc/connector-react Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify
Copy link

netlify bot commented Mar 21, 2026

Deploy Preview for appccc ready!

Name Link
🔨 Latest commit 0d38e4c
🔍 Latest deploy log https://app.netlify.com/projects/appccc/deploys/69c06395390b2f0008d6a78e
😎 Deploy Preview https://deploy-preview-362--appccc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 74 (🔴 down 12 from production)
Accessibility: 89 (🟢 up 1 from production)
Best Practices: 92 (🔴 down 8 from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Mar 21, 2026

Deploy Preview for liveccc ready!

Name Link
🔨 Latest commit 0d38e4c
🔍 Latest deploy log https://app.netlify.com/projects/liveccc/deploys/69c063956090e50008182d44
😎 Deploy Preview https://deploy-preview-362--liveccc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 32 (🔴 down 5 from production)
Accessibility: 88 (no change from production)
Best Practices: 92 (🔴 down 8 from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Mar 21, 2026

Deploy Preview for apiccc ready!

Name Link
🔨 Latest commit 0d38e4c
🔍 Latest deploy log https://app.netlify.com/projects/apiccc/deploys/69c063954b99310008e86e62
😎 Deploy Preview https://deploy-preview-362--apiccc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 86 (🟢 up 4 from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (no change from production)
SEO: 95 (🟢 up 1 from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the transaction completion and fee payment mechanisms by introducing a dedicated FeePayer abstraction. This change decouples the complex logic of managing transaction inputs and calculating fees from the Signer interface, leading to a cleaner separation of concerns. The Signer now leverages this new abstraction, allowing for more flexible and extensible handling of transaction fees and input collection across different signer implementations.

Highlights

  • FeePayer Abstraction: Introduced a new FeePayer abstraction to separate the concerns of fee payment and input collection from the Signer interface, promoting a more modular and flexible architecture.
  • Transaction Method Updates: Updated Transaction methods such as completeInputs, completeFee, completeInputsByCapacity, completeInputsAll, completeInputsAddOne, completeInputsAtLeastOne, completeFeeChangeToLock, completeFeeChangeToOutput, and completeFeeBy to accept a FeePayer instance instead of a Signer, delegating the core logic to the new abstraction.
  • Signer Integration: Refactored the Signer class to extend FeePayerFromAddress, inheriting its capabilities for address-based cell collection and fee completion, thereby streamlining the signer implementation.
  • New FeePayer Classes and Types: Added new abstract FeePayer and FeePayerFromAddress classes, a FeePayerGroup for combining multiple fee payers, and associated types and error classes (ErrorFeePayerInsufficientCapacity) to support the new abstraction.
  • Test Suite Refactoring: Moved and adapted existing Transaction.completeFee test cases into a new FeePayer test suite, ensuring comprehensive coverage for the new fee payment logic.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@netlify
Copy link

netlify bot commented Mar 21, 2026

Deploy Preview for docsccc ready!

Name Link
🔨 Latest commit 0d38e4c
🔍 Latest deploy log https://app.netlify.com/projects/docsccc/deploys/69c06395b982210008cf383f
😎 Deploy Preview https://deploy-preview-362--docsccc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 68 (🟢 up 1 from production)
Accessibility: 88 (no change from production)
Best Practices: 92 (no change from production)
SEO: 92 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a FeePayer abstraction, which is a significant and well-executed refactoring. Moving the transaction completion and fee payment logic out of the Transaction class into a dedicated FeePayer hierarchy greatly improves separation of concerns and makes the Transaction class cleaner. The new FeePayer, FeePayerFromAddress, and FeePayerGroup classes provide a flexible and extensible way to handle fee payments. Making Signer a subclass of FeePayerFromAddress is also a logical design choice. The changes are well-tested. I have one critical comment regarding the use of an incorrect error type, which has been updated in the code suggestion.

@@ -0,0 +1,243 @@
import { Address } from "../address/index.js";
import { Cell, Transaction, TransactionLike } from "../ckb/transaction.js";
import { ErrorTransactionInsufficientCapacity } from "../ckb/transactionErrors.js";
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

You're importing ErrorTransactionInsufficientCapacity, which appears to be an old error type that was replaced as part of this refactoring. The new FeePayer module introduces its own ErrorFeePayerInsufficientCapacity in errors.ts.

To maintain consistency and correctness within the new abstraction, please use ErrorFeePayerInsufficientCapacity throughout this file. This includes updating the instanceof checks and throw statements.

Suggested change
import { ErrorTransactionInsufficientCapacity } from "../ckb/transactionErrors.js";
import { ErrorFeePayerInsufficientCapacity } from "./errors.js";

@Hanssen0 Hanssen0 force-pushed the feat/fee-payer branch 4 times, most recently from 131e0eb to 310b86d Compare March 22, 2026 19:23
@Hanssen0 Hanssen0 force-pushed the feat/fee-payer branch 2 times, most recently from f91857a to 48d2d73 Compare March 22, 2026 21:41
@Hanssen0
Copy link
Member Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a FeePayer abstraction, a significant refactoring that separates transaction fee completion logic from the Transaction class. The change is well-structured, moving logic to the new FeePayer and FeePayerFromAddress classes and making Signer a subclass of FeePayerFromAddress. Deprecating old methods on Transaction while maintaining backward compatibility is a good strategy. My review includes suggestions to improve documentation for error handling in the new FeePayer class, address a minor type safety issue, and fix an incomplete mock object in a test file to improve test robustness. All original comments were kept as they did not contradict any provided rules.

Comment on lines +113 to +120
/**
* Completes the transaction fee by applying a custom change function.
*
* @param txLike - The transaction to complete the fee for.
* @param change - A function that modifies the transaction to handle the change.
* @param optionsLike - Optional configuration for completing the fee.
* @returns A promise that resolves to the transaction with the fee paid, whether it was modified, and the operation context.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The JSDoc for completeFeeChangeTo is missing documentation for potential exceptions that can be thrown. This can make it harder for developers to use this method correctly and handle errors gracefully. Please add @throws tags to document the exceptions that can be thrown, such as ErrorFeePayerInsufficientCapacity and when the change function is misused.

For example:

   * @throws {ErrorFeePayerInsufficientCapacity} If there is not enough capacity to cover the fee and change.
   * @throws {Error} If the change function does not use all available capacity or removes existing transaction data.


let leastFee = Zero;
let leastExtraCapacity = Zero;
let collectCapacityContext = undefined as CollectCapacityContext; // It's fine because it's assigned below
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The type cast undefined as CollectCapacityContext is used here to initialize collectCapacityContext. While this works due to the while(true) loop ensuring assignment before use, it's a code smell as it bypasses type safety. This can be risky if the logic is changed in the future. A safer approach would be to avoid the cast, for instance by declaring the variable with a union type CollectCapacityContext | undefined and using a non-null assertion ! where it's guaranteed to be defined.

index: 0,
},
});
return { tx, addedCount: 1 };
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The mock implementation for completeInputsAtLeastOne returns an object that is missing the collectedCapacity property, which is required by the FeePayerCompleteInputsResult type. While the current test may pass because the return value is not fully utilized, this can lead to brittle tests that fail unexpectedly if the code under test changes to use this property. It's best practice for mocks to conform to the types they are mocking.

Suggested change
return { tx, addedCount: 1 };
return { tx, addedCount: 1, collectedCapacity: ccc.Zero };

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.

1 participant