Skip to content

Conversation

@ashuralyk
Copy link
Contributor

Description

Add a new layer named FeePayer (could be changed further), to abstract our transaction complete step, like balancing process, paying with capacity margin or with DeFi swap ratio, etc.

This change can bring much clearer layer hierarchy on CCC, it makes transaction completion step programmable.

@changeset-bot
Copy link

changeset-bot bot commented Nov 3, 2025

🦋 Changeset detected

Latest commit: cca8107

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

This PR includes changesets to release 18 packages
Name Type
@ckb-ccc/core 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/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 Nov 3, 2025

Deploy Preview for liveccc ready!

Name Link
🔨 Latest commit cca8107
🔍 Latest deploy log https://app.netlify.com/projects/liveccc/deploys/69301e61f370c40008043597
😎 Deploy Preview https://deploy-preview-328--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: 23 (🟢 up 3 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 Nov 3, 2025

Deploy Preview for apiccc ready!

Name Link
🔨 Latest commit cca8107
🔍 Latest deploy log https://app.netlify.com/projects/apiccc/deploys/69301e6129a35b00084aa66e
😎 Deploy Preview https://deploy-preview-328--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: 88 (🟢 up 6 from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (no change from production)
SEO: 94 (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 Nov 3, 2025

Deploy Preview for appccc ready!

Name Link
🔨 Latest commit cca8107
🔍 Latest deploy log https://app.netlify.com/projects/appccc/deploys/69301e6182f46b000891802a
😎 Deploy Preview https://deploy-preview-328--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: 68 (🔴 down 7 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 Nov 3, 2025

Deploy Preview for docsccc ready!

Name Link
🔨 Latest commit cca8107
🔍 Latest deploy log https://app.netlify.com/projects/docsccc/deploys/69301e616f68bc00089bc82f
😎 Deploy Preview https://deploy-preview-328--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: 65 (🔴 down 2 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.

@ashuralyk ashuralyk changed the title feat: fee payer feat: new layer of FeePayer as a helper for transaction final completion step Nov 5, 2025
@ashuralyk
Copy link
Contributor Author

ashuralyk commented Nov 13, 2025

further implementation on margin fee payer for Spore module, here it is: ashuralyk#8

@Hanssen0

@ashuralyk ashuralyk marked this pull request as ready for review November 13, 2025 11:56
@ashuralyk
Copy link
Contributor 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 new FeePayer abstraction layer to handle the transaction completion step, which is a significant and positive architectural change. It successfully decouples fee payment logic from the Transaction class, making it more modular and extensible. The refactoring of the Signer class to leverage this new abstraction is clean. However, I've identified a critical issue in the new completeByFeePayer method where the return value of prepareTransaction is ignored, potentially leading to incorrect transaction preparation and fee calculation.

Comment on lines 2291 to 2301
async completeByFeePayer(
client: Client,
...feePayers: FeePayer[]
): Promise<void> {
for (const feePayer of feePayers) {
await feePayer.prepareTransaction(this);
}
for (const feePayer of feePayers) {
await feePayer.completeTxFee(this, client);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The current implementation of completeByFeePayer has a critical bug. The prepareTransaction method on a FeePayer can return a new Transaction instance, but its return value is ignored in the first loop. This means any preparations (like adding cell dependencies) are lost, and the subsequent completeTxFee calls operate on the original, unprepared transaction, which can lead to incorrect fee calculation and transaction failure.

To fix this, you should chain the results of prepareTransaction, perform fee completion on the fully prepared transaction, and then copy the state of the modified transaction back to the current instance.

  async completeByFeePayer(
    client: Client,
    ...feePayers: FeePayer[]
  ): Promise<void> {
    let tx: Transaction = this;
    for (const feePayer of feePayers) {
      tx = await feePayer.prepareTransaction(tx);
    }

    for (const feePayer of feePayers) {
      await feePayer.completeTxFee(tx, client);
    }

    this.copy(tx);
  }

...feePayers: FeePayer[]
): Promise<void> {
for (const feePayer of feePayers) {
await feePayer.prepareTransaction(this);
Copy link
Member

Choose a reason for hiding this comment

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

I agree with Gemini here: we should use the return value of prepareTransaction rather than assuming it modifies the tx in place. The previous implementation should be considered a bug.

Possible situation: A wallet (like JoyID, a web wallet) decides to handle the prepareTransaction stage itself to support more lock scripts in the future, and we serialize the tx for the API. This prevents the operation from happening in place.

To fix this problem without changing APIs, I assume we can use Transaction.copy to modify this at the end of completeBy* methods.

@ashuralyk
Copy link
Contributor 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 new FeePayer abstraction layer, significantly improving the modularity and extensibility of transaction completion logic. By moving the fee calculation and input collection responsibilities from the Transaction class to dedicated FeePayer and FeePayerFromAddress classes, the codebase becomes cleaner and more maintainable. The Signer class now correctly extends FeePayerFromAddress, inheriting these capabilities. The new test cases for margin calculation and the FeePayer layer are comprehensive and well-structured, ensuring the new functionality works as expected. This is a well-executed architectural improvement.


await tx.completeByFeePayer(client, mockFeePayer1, mockFeePayer2);

expect(mockFeePayer1.prepareTransaction).toHaveBeenCalledWith(tx);
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 completeByFeePayer method clones the transaction before passing it to prepareTransaction. Therefore, mockFeePayer1.prepareTransaction receives a clone of the original tx, not the original tx object itself. The current assertion toHaveBeenCalledWith(tx) will likely fail because tx is the original transaction instance, not the cloned one passed to the mock. Consider asserting with expect.any(ccc.Transaction) or expect.objectContaining if specific properties of the cloned transaction need to be verified.

Suggested change
expect(mockFeePayer1.prepareTransaction).toHaveBeenCalledWith(tx);
expect(mockFeePayer1.prepareTransaction).toHaveBeenCalledWith(expect.any(ccc.Transaction));

await tx.completeByFeePayer(client, mockFeePayer1, mockFeePayer2);

expect(mockFeePayer1.prepareTransaction).toHaveBeenCalledWith(tx);
expect(mockFeePayer2.prepareTransaction).toHaveBeenCalledWith(tx);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Similar to the previous comment, mockFeePayer2.prepareTransaction also receives a cloned transaction. The assertion toHaveBeenCalledWith(tx) should be updated to reflect this.

Suggested change
expect(mockFeePayer2.prepareTransaction).toHaveBeenCalledWith(tx);
expect(mockFeePayer2.prepareTransaction).toHaveBeenCalledWith(expect.any(ccc.Transaction));

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