Skip to content

Conversation

Hanssen0
Copy link
Member

For full context see #228

Copy link

changeset-bot bot commented Aug 16, 2025

🦋 Changeset detected

Latest commit: a242ce7

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/ssri Minor
@ckb-ccc/udt Minor
@ckb-ccc/core Patch
@ckb-ccc/shell 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/spore 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/examples Patch
@ckb-ccc/ccc-playground 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

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.

Summary of Changes

Hello @Hanssen0, 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 enhances the UDT (User Defined Token) functionality by introducing comprehensive methods for querying UDT information. It provides utilities to calculate the total balance, capacity, and count of UDT cells associated with a signer, offering both detailed information and a simplified balance-only query. This change improves the usability and efficiency of interacting with UDTs, particularly for wallet displays and account analysis, while also deprecating an older, less specific balance calculation function to promote a more robust and UDT-centric approach.

Highlights

  • New UDT Querying Methods: Introduces calculateInfo and calculateBalance methods within the Udt class to provide comprehensive information (balance, capacity, count) or just the total balance of UDT cells for a given signer. These methods offer flexibility for querying UDT data from either the blockchain or a local indexer cache.
  • Improved Balance Calculation: Adds a dedicated Udt.balanceFrom method for accurately extracting UDT balances from cell output data. This new method provides a more robust and UDT-specific way to interpret balance information, leading to the deprecation of the generic udtBalanceFrom in the @ckb-ccc/core package.
  • Code Refactoring and Consistency: Existing UDT-related functions, such as those for calculating input/output information and completing transactions, have been refactored to utilize the new Udt.balanceFrom method. This ensures consistency across the codebase and leverages the improved UDT-specific balance calculation 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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

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 issue 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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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.

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 new methods for querying UDT information, such as total balance and cell count, and refactors the UDT balance calculation logic into the @ckb-ccc/udt package. The changes are well-structured and the new methods are thoroughly documented. My feedback focuses on improving the examples in the documentation to use safer methods for handling large numbers, preventing potential precision loss.

Comment on lines 517 to 699
* const balanceInTokens = Number(info.balance) / (10 ** 8); // Assuming 8 decimals
* console.log(`Balance: ${balanceInTokens} tokens in ${info.count} cells`);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Converting info.balance to Number can lead to precision loss if the balance is very large (greater than Number.MAX_SAFE_INTEGER). It's safer to use a utility function that handles BigInt arithmetic for formatting, like ccc.fixedPointToString.

Suggested change
* const balanceInTokens = Number(info.balance) / (10 ** 8); // Assuming 8 decimals
* console.log(`Balance: ${balanceInTokens} tokens in ${info.count} cells`);
* const balanceInTokens = ccc.fixedPointToString(info.balance, 8); // Assuming 8 decimals
* console.log(`Balance: ${balanceInTokens} tokens in ${info.count} cells`);

Copy link
Member Author

Choose a reason for hiding this comment

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

Augment wrote these docs before. You're smarter than her.

@Hanssen0
Copy link
Member Author

@phroi This should allow us to query info about UDT-like cells. One issue left: How should we handle the custom UDT cell while changing?

const balanceData = ccc.numLeToBytes(
ccc.udtBalanceFrom(outputData) + balance,
16,
);

and
const balanceData = ccc.numLeToBytes(balance, 16);

Copy link

netlify bot commented Aug 16, 2025

Deploy Preview for apiccc ready!

Name Link
🔨 Latest commit a242ce7
🔍 Latest deploy log https://app.netlify.com/projects/apiccc/deploys/68a22d0a0f45000008e8a76d
😎 Deploy Preview https://deploy-preview-261--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: 94 (🟢 up 12 from production)
Accessibility: 90 (no change from production)
Best Practices: 92 (no change from production)
SEO: 83 (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

netlify bot commented Aug 16, 2025

Deploy Preview for appccc ready!

Name Link
🔨 Latest commit a242ce7
🔍 Latest deploy log https://app.netlify.com/projects/appccc/deploys/68a22d0af509cb00085828c1
😎 Deploy Preview https://deploy-preview-261--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: 53 (🔴 down 16 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.

Copy link

netlify bot commented Aug 16, 2025

Deploy Preview for docsccc ready!

Name Link
🔨 Latest commit a242ce7
🔍 Latest deploy log https://app.netlify.com/projects/docsccc/deploys/68a22d0a5766880008f4b046
😎 Deploy Preview https://deploy-preview-261--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: 70 (🟢 up 6 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

netlify bot commented Aug 16, 2025

Deploy Preview for liveccc ready!

Name Link
🔨 Latest commit a242ce7
🔍 Latest deploy log https://app.netlify.com/projects/liveccc/deploys/68a22d0a83f3600008543ad1
😎 Deploy Preview https://deploy-preview-261--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: 9 (no change 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.

@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 new methods for querying UDT information, such as total balance and capacity. The changes include deprecating the old udtBalanceFrom function in favor of a new Udt.balanceFrom method, and adding calculateInfo and calculateBalance to the Udt class. The refactoring is well-structured and the documentation for the new methods is comprehensive.

I have one suggestion regarding testing for the new functionality to ensure its long-term stability.

Comment on lines 544 to 738
async calculateInfo(
signer: ccc.Signer,
options?: { source?: "chain" | "local" | null },
): Promise<{
balance: ccc.Num;
capacity: ccc.Num;
count: number;
}> {
let balance = ccc.Zero;
let capacity = ccc.Zero;
let count = 0;
const isFromLocal = (options?.source ?? "chain") === "local";

for await (const cell of isFromLocal
? signer.findCells(this.filter)
: signer.findCellsOnChain(this.filter)) {
balance += this.balanceFrom(cell.outputData, cell.cellOutput);
capacity += cell.cellOutput.capacity;
count += 1;
}

return {
balance,
capacity,
count,
};
}
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 new calculateInfo method and its wrapper calculateBalance are great additions for querying UDT information. To ensure their correctness and prevent future regressions, it would be beneficial to add unit tests for them. Consider covering scenarios such as:

  • An account with no UDT cells.
  • An account with one UDT cell.
  • An account with multiple UDT cells.
  • Verifying the behavior for both 'local' and 'chain' data sources.

Copy link
Member Author

Choose a reason for hiding this comment

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

We'll do that later

@phroi
Copy link
Contributor

phroi commented Aug 16, 2025

This is phase 2 of the UDT master plan:

  1. Try to add more querying methods, like calculating info of a Signer. Meanwhile, we should have methods for parsing a single UDT cell. On this stage, we should consider if these new methods can be overridden to accommodate some unconventional UDT cell requirements.

Back to your comment:

This should allow us to query info about UDT-like cells. One issue left: How should we handle the custom UDT cell while changing?

You meant while chaining, right?

Yeah, I have feelings about those two methods!! 🤣

I don't particularly like static balanceFrom: notice how I can call that method on any cell, irregarding of how it may be a UDT or not. It will also cause confusion if actually is called on cells that seems like UDTs but actually are not (iCKB Receipts)

Additionally, I don't particularly like the non-static balanceFrom:

  • At the very least we need to check the type of the cell against UDT.script
  • Also, for subclasses compatibility reasons, you need to pass the outpoint (if exists) and a ccc.Client parameter (headers of iCKB Receipts).
  • At that point you realize that not all protocols are chainable and that's a fact of life.

For example in the case of iCKB Receipts:

  • iCKB Receipts as output do have a zero iCKB value (cause we don't know the transaction header)
  • iCKB Receipts as inputs have a positive iCKB value (cause we know the transaction header)

Similarly goes for iCKB Deposits:

  • iCKB Deposits as output do have a zero iCKB value (cause we don't know the transaction) header.
  • iCKB Deposits as inputs have a negative iCKB value (cause we know the transaction header)

As outputs (so when depositing), the iCKB Receipt will just track the value of the free CKB of the iCKB Deposit(s). This way the protocol work around the on-chain determinism of L1, which doesn't allow to read the transaction inclusion header at validation time.

As inputs (so when withdrawing), the positive Receipt iCKB value (and iCKB UDTs) and negative Deposit iCKB value cancel each other out.

Are we able to move somewhat closer to infoFrom?

Phroi %36

@phroi
Copy link
Contributor

phroi commented Aug 16, 2025

Just one thing that makes me wonder is filter: correct if we handle only UDT, but we'll be able to extend it later?

I know that it's tightly coupled with tx.completeInputs

Maybe it's not necessary for it to be extendable, cause maybe we don't want to automatically add non-UDT cells

Maybe a second filter or something for other cells types will be needed by subclasses and that's about it

I'm unsure about the scenario here. You mean maybe we will need multiple filters? Or may we need more criteria in the filter?

If it's the first one, will having multiple Udt instances be better?
If it's the second one, the filter is defined by the CKB's PRC. It will be hard to make it extendable.

First case. I'm very much aware of CKB RPC methods and parameters.

Take for example iCKB, a user may own both UDTs and iCKB Receipt cells, which have types that are completely different from each-other, but for example both cells needs to be accounted in the same UDT value for a transaction.

Phroi %11

@Hanssen0
Copy link
Member Author

This should allow us to query info about UDT-like cells. One issue left: How should we handle the custom UDT cell while changing?

You meant while chaining, right?

Nah, I mean while giving the change cell. I thought the change could be used as a verb.
So, for example, we're dealing with an iCKB receipt. How do we construct the change cell so it's a valid cell?

I don't particularly like static balanceFrom: notice how I can call that method on any cell, irregarding of how it may be a UDT or not. It will also cause confusion if actually is called on cells that seems like UDTs but actually are not (iCKB Receipts)

It's for convenience, so devs won't need to make a Udt instance to parse the balance. What about giving it a more detailed name e.g. balanceFromUnsafe or sth?

Additionally, I don't particularly like the non-static balanceFrom:

  • At the very least we need to check the type of the cell against UDT.script

Sure. If it's not an expected UDT cell, let's return 0.

  • Also, for subclasses compatibility reasons, you need to pass the outpoint (if exists) and a ccc.Client parameter (headers of iCKB Receipts).

Of course. Do you think any more info is needed?

  • At that point you realize that not all protocols are chainable and that's a fact of life.

Absolutely. We just want to try our best to make things faster.

Are we able to move somewhat closer to infoFrom?

I'm unsure in what perspective we can make them closer.

  1. I can accept having an infoFrom similar to the current balanceFrom, but returns more detail. I'll still keep the balanceFrom but invoke the infoFrom inside it.
  2. I can accept letting the method accept multiple cells and accumulate their info (need to design the signature so it's still clear with only one cell);
  3. I can accept moving the initialInfo to the last parameter and making it optional;

Is it good enough for you?

So, for example, we're dealing with an iCKB receipt. How do we construct the change cell so it's a valid cell?

This still makes me struggle, and infoFrom doesn't seem to solve it. Looking forward to your suggestions!

@Hanssen0
Copy link
Member Author

Take for example iCKB, a user may own both UDTs and iCKB Receipt cells, which have types that are completely different from each-other, but for example both cells needs to be accounted in the same UDT value for a transaction.

I have two possible solutions:

  1. Making the filter an array. But I would like to make it private until we see cases really need to access the Udt.filters, since I'm not sure if we will still change that in the future.
  2. iCkbUdt can override the completeInputs method.

@Hanssen0
Copy link
Member Author

  • Also, for subclasses compatibility reasons, you need to pass the outpoint (if exists) and a ccc.Client parameter (headers of iCKB Receipts).

Of course. Do you think any more info is needed?

That also means balanceFrom/infoFrom needs to be async, right?

@phroi
Copy link
Contributor

phroi commented Aug 16, 2025

Nah, I mean while giving the change cell. I thought the change could be used as a verb.

You are indeed correct, it is a verb, my bad! I just didn't get the meaning, I'm so sorry!! 🤣

So, for example, we're dealing with an iCKB receipt. How do we construct the change cell so it's a valid cell?

You just add a UDT cell as usual, if for any reason the transaction has a positive burned amount of iCKB.

Change cell will be always an UDT, even in iCKB. Receipt only tracks deposits in output, so in a way is a kind of change cell in itself.

The iCKB validation at L1 script level is:

in_udt_ickb + in_receipts_ickb == out_udt_ickb + in_deposits_ickb

It's for convenience, so devs won't need to make a Udt instance to parse the balance. What about giving it a more detailed name e.g. balanceFromUnsafe or sth?

Something like that, with the appropriate warning in the TypeDoc

Also, for subclasses compatibility reasons, you need to pass the outpoint (if exists) and a ccc.Client parameter (headers of iCKB Receipts).

Of course. Do you think any more info is needed?

Another thought that comes up sometimes is that at time two or more cells cells need to be consumed togheter. That said, usually there is one cell holding the value, while the other controls the logic of accessing it, so should be fine as it is.

That also means balanceFrom/infoFrom needs to be async, right?

Yesss, think for example if these methods are implemented in SSRI.

Are we able to move somewhat closer to #250?

I'm unsure in what perspective we can make them closer.

Just async + client + outpoint should be enough

I have two possible solutions:

  1. Making the filter an array. But I would like to make it private until we see cases really need to access the Udt.filters, since I'm not sure if we will still change that in the future.

Array has an issue: different scripts may have different uses and purposes, as with iCKB Receipt. If it was a named tuple it would make sense for sub-classes, but not for base.

For example, an issue is that consuming each of these cells could be done in a different way, we cannot tell for sure how the Transaction will be modified by consuming a non-UDT cell. iCKB Receipts need header in HeaderDeps, for example.

  1. iCkbUdt can override the completeInputs method.

And all methods using directly UDT.filter, like calculateInfo.

  1. I just ovverride in iCKB UDT the minimal methods like balanceFrom. Dev/user will need to manually add these non-UDT cells, possibly they will not be counted by calculateInfo.

Phroi %38

@Hanssen0
Copy link
Member Author

So, for example, we're dealing with an iCKB receipt. How do we construct the change cell so it's a valid cell?

You just add a UDT cell as usual, if for any reason the transaction has a positive burned amount of iCKB.

Change cell will be always an UDT, even in iCKB. Receipt only tracks deposits in output, so in a way is a kind of change cell in itself.

The iCKB validation at L1 script level is:

in_udt_ickb + in_receipts_ickb == out_udt_ickb + in_deposits_ickb

Glad to hear that we don't need more detailed control currently! This should make things easier.

I have two possible solutions:

  1. Making the filter an array. But I would like to make it private until we see cases really need to access the Udt.filters, since I'm not sure if we will still change that in the future.

Array has an issue: different scripts may have different uses and purposes, as with iCKB Receipt. If it was a named tuple it would make sense for sub-classes, but not for base.

  1. iCkbUdt can override the completeInputs method.

And all methods using directly UDT.filter, like calculateInfo.

Seems like there is no easy solution for this. Perhaps we could create two Udt subclasses, UdtICkb and UdtICkbReceipt, with overridden isUdt methods. This would allow them to recognize others' balances during transaction composition. But when fetching cells on-chain, they only handle their own script.

@phroi
Copy link
Contributor

phroi commented Aug 16, 2025

Seems like there is no easy solution for this. Perhaps we could create two Udt subclasses, UdtICkb and UdtICkbReceipt, with overridden isUdt methods. This would allow them to recognize others' balances during transaction composition. But when fetching cells on-chain, they only handle their own script.

I currently have something along those lines, I need to check the feasibility of Subclassing, but I'm honestly too sleepy now...

If you want to try your hand with a commit, as soon as I wake up I'll check the feasibility!

Wish you a good sleep, night night 🤗

Phroi

@Hanssen0 Hanssen0 force-pushed the feat/udt-query branch 3 times, most recently from 295258e to 25a1301 Compare August 17, 2025 01:01
@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 significant and beneficial refactoring by adding CellAny to represent both on-chain and off-chain cells, which simplifies the core API. It also adds new methods for querying UDT information, improving the library's capabilities. The changes are generally well-implemented and documented. However, I've identified a couple of logical errors in the test files that were introduced during the refactoring. Please address these issues to ensure the tests are correct and provide reliable coverage.

@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 significant and beneficial refactoring by adding CellAny to represent both on-chain and off-chain cells, which helps in reducing code duplication and improving clarity. It also adds new, well-documented UDT info querying methods. The changes are consistent and well-tested. I've provided a few suggestions to simplify some of the new implementations for better readability and maintainability.

@Hanssen0
Copy link
Member Author

#262 should be reviewed first.

@Hanssen0
Copy link
Member Author

Do you think the new infoFrom design works well with iCKB?

Issue with iCKB is that the value of a cell varies if it's used as input or output of a transaction.

With CellAny we are not able to distinguish that, we only know if the outpoint is given or not

Which is different from if a cell is used as input or output

Seems like I had the same issue in my own code

I suggest that we can safely assume all CellAny with outPoint are inputs, and outputs if without.

@phroi
Copy link
Contributor

phroi commented Aug 17, 2025

What if someone is fetching old transaction and he keeps both inputs and outputs as ccc.Cell to re-validate what happened in that transaction?

@phroi
Copy link
Contributor

phroi commented Aug 17, 2025

Having only the oupoint as un/defined to distinguish between inputs and outputs use is finicky and fragile

@phroi
Copy link
Contributor

phroi commented Aug 17, 2025

Yesterday I was thinking, what if we remove inforFrom and to determine values of single cells we just add the single cell to an empty transaction and from there getInputInfo/getOutputInfo

@phroi
Copy link
Contributor

phroi commented Aug 17, 2025

Using getInputInfo/getOutputInfo then just boils down to expand appropriately the methods interface to include non-tx types?

@phroi
Copy link
Contributor

phroi commented Aug 17, 2025

Alternatively, we need to explicitly pass the intended use input/output to infoFrom

@Hanssen0
Copy link
Member Author

What if someone is fetching old transaction and he keeps both inputs and outputs as ccc.Cell to re-validate what happened in that transaction?

That means, the dev gives up getInpusInfo & getOutputsInfo, chooses to manually construct output Cells, and passes them into infoFrom, just to get a wrong result.
I would say that won't be our problem.

Alternatively, we need to explicitly pass the intended use input/output to infoFrom

That seems to make things more semantically correct. But we can also assume "cells with outpoints are inputs".

As I mentioned, if we also assign outPoint to outputs, things will be much more painful. If not, we can do the assumption.

@phroi
Copy link
Contributor

phroi commented Aug 17, 2025

Ok, as reviewer I had to raise the concern! Assumption is reasonable, could you also add some remarks in the TypeDoc?

I was wondering, have you considered passing acc/origin as parameter to infoFrom?

@phroi
Copy link
Contributor

phroi commented Aug 17, 2025

Do you think the new infoFrom design works well with iCKB?

At high level, yes, I just need to check deeper the use of two subclasses that you were proposing yesterday 🤔

@Hanssen0
Copy link
Member Author

Hanssen0 commented Aug 17, 2025

Ok, as reviewer I had to raise the concern! Assumption is reasonable, could you also add some remarks in the TypeDoc?

Of course.

I was wondering, have you considered passing acc/origin as parameter to infoFrom?

Yes. There are two designs:

async infoFrom(
    client: ccc.Client,
    ...cells: (ccc.CellAnyLike | ccc.CellAnyLike[])[]
  )

and

async infoFrom(
    client: ccc.Client,
    cells: ccc.CellAnyLike[],
    acc?: InfoLike | null,
  )

As you can see, the second design incurs some cost: we can no longer pass in a single cell, and that's also true for balanceFrom. I think both have pros and cons, and the first style is more unified with other methods' design, like Transaction.addCellDeps, ClientCache.mark* or SignerCkbScriptReadonly.

What do you think?

Edit: I rechecked related code, the acc seems more useful than accepting the single cell. I'll switch to the second design.

@phroi
Copy link
Contributor

phroi commented Aug 17, 2025

We can still pass a single cell by allowing it as param ccc.CellAnyLike | ccc.CellAnyLike[].

That said, I was mostly looking at optimizing calculateInfo, which can eventually be optimized by paging if necessary.

If optimizing a method that should be called as sparingly as possible makes the rest worse, then it makes no sense.

I'm not sure myself:

  • usecase of acc may be limited to calculateInfo
  • acc type may be enlarged to have more fields by Subclasses

@phroi
Copy link
Contributor

phroi commented Aug 17, 2025

Perhaps we could create two Udt subclasses, UdtICkb and UdtICkbReceipt, with overridden isUdt methods. This would allow them to recognize others' balances during transaction composition. But when fetching cells on-chain, they only handle their own script.

Nope. iCKB Receipts are no UDT: they are non transferable, just receipts that can be transformed in UDT or used to withdraw. Basically we are missing all UDT methods.

The way I implemented it was:

  1. Segregate iCKB core logic into its own manager LogicManager
  2. IckbUdtManager sublass UdtManager and requires as parameters:

And maybe I could keep a similar implementation here?

Phroi %70

@Hanssen0
Copy link
Member Author

By the way, since we are here, please take a look at iCKB/Utils and check out what makes sense to bring into CCC

@phroi Let's go back here.

I'm curious about modifications on Epoch codec.union and hexFrom. It looks like it's possible to port them to CCC's codebase.

What do you think? Or do you suggest also merging some other things?

@phroi
Copy link
Contributor

phroi commented Aug 17, 2025

Epoch would be nice, I worked quite a bit to reach that level. Only issue is that maybe it uses GCD too much. Maybe not all people are comfortable with that. If you add Epoch, then GCD should be added too.

Union with fixed size support is a great candidate too. With that implemented we can get back to the issue on molecule.

About hexFrom there was a catch: not all bigint will be encoded into hex in that form, depends on the codec, hexFrom just choose the simplest one

Maybe also something like unique to extract unique entities from an Iterable? Not sure cause once you implement on Signer the utility to get cells from both local and chain my biggest unique use-case disappears

binarySearch and asyncBinarySearch are pretty good utilities too, maybe out of place in CCC Core

Phroi %25

@Hanssen0 Hanssen0 force-pushed the feat/udt-query branch 3 times, most recently from 0eb76e4 to 6a25f02 Compare August 17, 2025 19:26
@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 new methods for querying UDT (User Defined Token) information, such as total balance, capacity, and cell count. It adds a new UdtInfo class to encapsulate this data and refactors existing methods to use it, improving code consistency and reusability. The changes are well-documented, including performance warnings for expensive operations. I've provided a few suggestions to further improve performance and readability by optimizing how data is accumulated in some of the new and refactored methods.

const isFromLocal = (options?.source ?? "chain") === "local";

return ccc.reduceAsync(
isFromLocal
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we add the method on signer to switch between local and chain?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we can do that in another PR

@Hanssen0
Copy link
Member Author

Epoch would be nice, I worked quite a bit to reach that level. Only issue is that maybe it uses GCD too much. Maybe not all people are comfortable with that. If you add Epoch, then GCD should be added too.

GCD is fine.

Union with fixed size support is a great candidate too. With that implemented we can get back to the issue on molecule.

I remember that you created a PR once in a while but closed it later. I think we can merge that part into CCC.

About hexFrom there was a catch: not all bigint will be encoded into hex in that form, depends on the codec, hexFrom just choose the simplest one

I'm thinking that we can add Num | mol.Entity to BytesLike and handle that part in the bytesFrom. I'm not sure about the early return of isHex since we also do a similar thing in bytesFrom, and that means it might not introduce a performance gain.

Maybe also something like unique to extract unique entities from an Iterable? Not sure cause once you implement on Signer the utility to get cells from both local and chain my biggest unique use-case disappears

binarySearch and asyncBinarySearch are pretty good utilities too, maybe out of place in CCC Core

Considering that they're not currently used by other parts in CCC, now doesn't seem like a good time to add them. However, if they can be designed to be more generic and have full test cases, that's still possible.

Considering you are more familiar with these codes, it would be great if you could submit PRs to CCC when you have time.

@Hanssen0
Copy link
Member Author

/canary
@phroi I'll release the canary version for us to test. Looking forward to your feedback!

Copy link
Contributor

🚀 Canary version published successfully! View workflow run

The following packages have been published to npm:

  • @ckb-ccc/ccc@0.0.0-canary-20250817202237
  • ckb-ccc@0.0.0-canary-20250817202237
  • @ckb-ccc/connector@0.0.0-canary-20250817202237
  • @ckb-ccc/connector-react@0.0.0-canary-20250817202237
  • @ckb-ccc/core@0.0.0-canary-20250817202237
  • @ckb-ccc/eip6963@0.0.0-canary-20250817202237
  • @ckb-ccc/joy-id@0.0.0-canary-20250817202237
  • @ckb-ccc/lumos-patches@0.0.0-canary-20250817202237
  • @ckb-ccc/nip07@0.0.0-canary-20250817202237
  • @ckb-ccc/okx@0.0.0-canary-20250817202237
  • @ckb-ccc/rei@0.0.0-canary-20250817202237
  • @ckb-ccc/shell@0.0.0-canary-20250817202237
  • @ckb-ccc/spore@0.0.0-canary-20250817202237
  • @ckb-ccc/ssri@0.0.0-canary-20250817202237
  • @ckb-ccc/udt@0.0.0-canary-20250817202237
  • @ckb-ccc/uni-sat@0.0.0-canary-20250817202237
  • @ckb-ccc/utxo-global@0.0.0-canary-20250817202237
  • @ckb-ccc/xverse@0.0.0-canary-20250817202237

@phroi
Copy link
Contributor

phroi commented Aug 17, 2025

The PR looks pretty good right now, nice job there 👍👍

Just to give you an heads up:

  • Today 18th August when I wake up I'll be available
  • Tomorrow 19th August I'll be busy, likely all day
  • 20th/21th I should start to be available again

Phroi %13

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