Skip to content

feat(coin): new coin package#415

Open
Hanssen0 wants to merge 2 commits into
ckb-devrel:next-majorfrom
Hanssen0:feat/coin
Open

feat(coin): new coin package#415
Hanssen0 wants to merge 2 commits into
ckb-devrel:next-majorfrom
Hanssen0:feat/coin

Conversation

@Hanssen0

Copy link
Copy Markdown
Member

@changeset-bot

changeset-bot Bot commented Jun 30, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3edf75a

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

This PR includes changesets to release 6 packages
Name Type
@ckb-ccc/shell Minor
@ckb-ccc/coin Minor
@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

netlify Bot commented Jun 30, 2026

Copy link
Copy Markdown

Deploy Preview for apiccc ready!

Name Link
🔨 Latest commit 3edf75a
🔍 Latest deploy log https://app.netlify.com/projects/apiccc/deploys/6a653fb6019538000810682e
😎 Deploy Preview https://deploy-preview-415--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: 85 (🔴 down 9 from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (no change from production)
SEO: 95 (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

netlify Bot commented Jun 30, 2026

Copy link
Copy Markdown

Deploy Preview for appccc ready!

Name Link
🔨 Latest commit 3edf75a
🔍 Latest deploy log https://app.netlify.com/projects/appccc/deploys/6a653fb6cfca670008093338
😎 Deploy Preview https://deploy-preview-415--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: 63 (🔴 down 21 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

netlify Bot commented Jun 30, 2026

Copy link
Copy Markdown

Deploy Preview for liveccc ready!

Name Link
🔨 Latest commit 3edf75a
🔍 Latest deploy log https://app.netlify.com/projects/liveccc/deploys/6a653fb6feb9b40008cfe800
😎 Deploy Preview https://deploy-preview-415--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: 22 (🔴 down 19 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

netlify Bot commented Jun 30, 2026

Copy link
Copy Markdown

Deploy Preview for docsccc ready!

Name Link
🔨 Latest commit 3edf75a
🔍 Latest deploy log https://app.netlify.com/projects/docsccc/deploys/6a653fb6f492580008ea9e9b
😎 Deploy Preview https://deploy-preview-415--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: 66 (🔴 down 22 from production)
Accessibility: 95 (no change from production)
Best Practices: 92 (🔴 down 8 from production)
SEO: 75 (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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new @ckb-ccc/coin workspace package that provides a generic fungible-token (Coin) helper built on @ckb-ccc/core, and wires it into the monorepo’s testing/docs tooling and the @ckb-ccc/shell re-export surface.

Changes:

  • Added new packages/coin package (Coin implementation, tests, build/lint/test/tooling config, docs).
  • Updated root Vitest + TypeDoc configs to include packages/coin.
  • Updated @ckb-ccc/shell to depend on and re-export @ckb-ccc/coin; updated lockfile accordingly.

Reviewed changes

Copilot reviewed 21 out of 23 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
vitest.config.mts Adds packages/coin to the monorepo Vitest projects list.
typedoc.config.mjs Adds packages/coin to TypeDoc workspace entry points.
pnpm-lock.yaml Adds the packages/coin importer and updates resolved dependency snapshots.
packages/shell/src/barrel.ts Re-exports the coin namespace from @ckb-ccc/coin.
packages/shell/package.json Adds @ckb-ccc/coin as a workspace dependency.
packages/coin/vitest.config.ts Adds package-local Vitest configuration for tests and coverage.
packages/coin/typedoc.json Adds package-local TypeDoc configuration for API generation.
packages/coin/tsdown.config.mts Adds tsdown build configuration for ESM+CJS outputs and copy-basedirs.
packages/coin/tsconfig.json Adds TypeScript build configuration for the coin package.
packages/coin/src/index.ts Exposes barrel exports and a coin namespace export.
packages/coin/src/coin/index.ts Implements the Coin class (balance/info helpers and transaction completion helpers).
packages/coin/src/coin/index.test.ts Adds Vitest coverage for Coin behaviors (inputs completion, change handling, balance/info helpers).
packages/coin/src/coin/error.ts Adds ErrorCoinInsufficient error type for insufficient Coin balance conditions.
packages/coin/src/coin/coinInfo.ts Adds CoinInfo aggregation helper used by the Coin implementation.
packages/coin/src/barrel.ts Re-exports the coin module surface from src/coin.
packages/coin/README.md Adds package documentation and usage examples.
packages/coin/prettier.config.cjs Adds package-local Prettier configuration.
packages/coin/package.json Defines the new @ckb-ccc/coin package metadata, exports, and scripts.
packages/coin/misc/basedirs/dist/package.json Ensures emitted ESM dist is treated as "type": "module".
packages/coin/misc/basedirs/dist.commonjs/package.json Ensures emitted CJS dist is treated as "type": "commonjs".
packages/coin/eslint.config.mjs Adds package-local ESLint + typescript-eslint configuration.
packages/coin/.prettierignore Adds package-local Prettier ignore rules.
packages/coin/.npmignore Adds package-local npm publish ignore rules.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/coin/src/coin/index.ts Outdated
Comment thread packages/coin/typedoc.json
@Hanssen0
Hanssen0 force-pushed the feat/coin branch 5 times, most recently from 9481017 to 982850a Compare June 30, 2026 08:04
@Hanssen0
Hanssen0 requested a review from Copilot June 30, 2026 08:05

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 23 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

Comment thread packages/coin/src/coin/index.ts Outdated
Comment thread packages/coin/src/coin/index.ts Outdated
Comment thread packages/coin/src/coin/index.ts Outdated
@Hanssen0
Hanssen0 force-pushed the feat/coin branch 6 times, most recently from 0c73462 to 497132a Compare July 4, 2026 07:55
@Hanssen0
Hanssen0 changed the base branch from dev to next-major July 4, 2026 07:55
@Hanssen0
Hanssen0 requested a review from Copilot July 4, 2026 09:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 24 out of 26 changed files in this pull request and generated 6 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

Comment thread packages/coin/README.md Outdated
Comment thread packages/coin/README.md
Comment thread packages/coin/README.md
Comment thread packages/coin/src/coin/coin.ts
Comment thread packages/coin/src/coin/coin.ts
Comment thread packages/coin/src/coin/coin.ts
@Hanssen0
Hanssen0 force-pushed the feat/coin branch 3 times, most recently from b32dcb5 to 7c07413 Compare July 4, 2026 09:46
@Hanssen0
Hanssen0 force-pushed the feat/coin branch 2 times, most recently from ce82cc8 to 1b32769 Compare July 14, 2026 06:55
@Hanssen0

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Hanssen0, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 24 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e82f99d3-2be1-4ff9-bcc7-ecd3b46af5ed

📥 Commits

Reviewing files that changed from the base of the PR and between c4617af and 3edf75a.

⛔ Files ignored due to path filters (2)
  • packages/coin/misc/basedirs/dist/package.json is excluded by !**/dist/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (28)
  • .changeset/early-oranges-lick.md
  • packages/coin/.npmignore
  • packages/coin/.prettierignore
  • packages/coin/README.md
  • packages/coin/eslint.config.mjs
  • packages/coin/misc/basedirs/dist.commonjs/package.json
  • packages/coin/package.json
  • packages/coin/prettier.config.cjs
  • packages/coin/src/barrel.ts
  • packages/coin/src/coBuild.ts
  • packages/coin/src/coin/coin.test.ts
  • packages/coin/src/coin/coin.ts
  • packages/coin/src/coin/coinInfo.ts
  • packages/coin/src/coin/error.ts
  • packages/coin/src/coin/index.ts
  • packages/coin/src/index.ts
  • packages/coin/src/xUdt/args.ts
  • packages/coin/src/xUdt/coinXUdt.ts
  • packages/coin/src/xUdt/index.ts
  • packages/coin/src/xUdt/xUdt.test.ts
  • packages/coin/tsconfig.json
  • packages/coin/tsdown.config.mts
  • packages/coin/typedoc.json
  • packages/coin/vitest.config.ts
  • packages/shell/package.json
  • packages/shell/src/barrel.ts
  • typedoc.config.mjs
  • vitest.config.mts
📝 Walkthrough

Walkthrough

This change introduces the @ckb-ccc/coin package with Coin transaction utilities, CoBuild actions, xUDT support, tests, build tooling, documentation, and public exports through @ckb-ccc/shell.

Changes

Coin package

Layer / File(s) Summary
Package foundation
packages/coin/*, typedoc.config.mjs, vitest.config.mts, packages/shell/*
Adds package metadata, ESM/CommonJS builds, TypeScript, linting, formatting, testing, publishing configuration, and workspace wiring.
Coin contracts and public exports
packages/coin/src/coBuild.ts, packages/coin/src/coin/*, packages/coin/src/index.ts, packages/coin/src/barrel.ts
Defines Coin action entities, CoinInfo, insufficient-coin errors, and public barrel exports.
Coin discovery and transaction completion
packages/coin/src/coin/coin.ts, packages/coin/src/coin/coin.test.ts
Implements Coin balance inspection, input selection, change completion, transfers, minting, burning, capacity handling, and CoBuild integration with tests.
xUDT arguments and CoinXUdt
packages/coin/src/xUdt/*
Adds extension-aware owner-mode argument codecs, normalized xUDT construction, known-script resolution, and xUDT tests.
Documentation and release exposure
packages/coin/README.md, .changeset/early-oranges-lick.md
Documents Coin and CoinXUdt usage and records minor package releases.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant Coin
  participant Client
  participant Transaction
  participant CoBuild
  Caller->>Coin: create transfer or complete transaction
  Coin->>Client: query matching cells
  Client-->>Coin: return Coin cells and cell dependencies
  Coin->>Transaction: add inputs and change output
  Coin->>CoBuild: record transfer, mint, or burn action
  CoBuild-->>Coin: return action witness index
  Coin-->>Caller: return completed transaction
Loading

Suggested labels: javascript

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly describes the main change: adding a new coin package.
Description check ✅ Passed The description matches the template and confirms the required Contributing Guidelines checkbox.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/coin/README.md`:
- Around line 123-128: Update the “Change to a specific address” README example
so it is self-contained by defining tx, or explicitly label the snippet as
continuing from the preceding Send example and add that clarification in the
code block. Preserve the existing signer.getRecommendedAddressObj and
coin.completeChangeToLock calls.

In `@packages/coin/src/coin/coin.test.ts`:
- Around line 1538-1555: Update the test around completeInputsByAmount so it
passes the negative amountTweak value of -100 when invoking the method. Preserve
the existing transaction setup and addedCount expectation, ensuring the test
specifically verifies that the negative tweak cancels the output requirement.

In `@packages/coin/src/coin/coinInfo.ts`:
- Around line 49-52: Update CoinInfo.from so that when infoLike is already a
CoinInfo, it returns infoLike.clone() rather than the original reference.
Preserve the existing conversion behavior for other CoinInfoLike inputs and
maintain the documented guarantee that from always returns a new instance.

In `@packages/coin/src/xUdt/args.ts`:
- Around line 42-60: Update CoinXUdtArgsCodec and CoinXUdtArgs so xUDT extension
payloads are preserved during decode and re-encode, modeling extensionData
explicitly if supported; otherwise validate flags and encoded lengths and reject
unsupported extension data instead of silently emitting only the owner hash and
four flag bytes.

In `@packages/coin/src/xUdt/coinXUdt.ts`:
- Around line 99-115: Update the CoinXUdt constructor’s argument handling around
CoinXUdtArgs.fromBytes so extended bytes from options.script.args are preserved
when rebuilding the script, rather than always replacing them with
args.toBytes(). Keep canonical serialization for options.xUdtArgs while
retaining the original script argument bytes for the script-derived path, and
add a regression test using the extended arguments covered in xUdt.test.ts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b179b27b-6b93-41c2-8a16-7fa1df39ce82

📥 Commits

Reviewing files that changed from the base of the PR and between 8076f62 and 1b32769.

⛔ Files ignored due to path filters (2)
  • packages/coin/misc/basedirs/dist/package.json is excluded by !**/dist/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (28)
  • .changeset/early-oranges-lick.md
  • packages/coin/.npmignore
  • packages/coin/.prettierignore
  • packages/coin/README.md
  • packages/coin/eslint.config.mjs
  • packages/coin/misc/basedirs/dist.commonjs/package.json
  • packages/coin/package.json
  • packages/coin/prettier.config.cjs
  • packages/coin/src/barrel.ts
  • packages/coin/src/coBuild.ts
  • packages/coin/src/coin/coin.test.ts
  • packages/coin/src/coin/coin.ts
  • packages/coin/src/coin/coinInfo.ts
  • packages/coin/src/coin/error.ts
  • packages/coin/src/coin/index.ts
  • packages/coin/src/index.ts
  • packages/coin/src/xUdt/args.ts
  • packages/coin/src/xUdt/coinXUdt.ts
  • packages/coin/src/xUdt/index.ts
  • packages/coin/src/xUdt/xUdt.test.ts
  • packages/coin/tsconfig.json
  • packages/coin/tsdown.config.mts
  • packages/coin/typedoc.json
  • packages/coin/vitest.config.ts
  • packages/shell/package.json
  • packages/shell/src/barrel.ts
  • typedoc.config.mjs
  • vitest.config.mts

Comment thread packages/coin/README.md
Comment thread packages/coin/src/coin/coin.test.ts
Comment thread packages/coin/src/coin/coinInfo.ts
Comment thread packages/coin/src/xUdt/args.ts Outdated
Comment thread packages/coin/src/xUdt/coinXUdt.ts Outdated
@Hanssen0
Hanssen0 force-pushed the feat/coin branch 4 times, most recently from ebd5a39 to 627b291 Compare July 24, 2026 19:47
@Hanssen0
Hanssen0 requested a review from Copilot July 24, 2026 19:53

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (3)
packages/coin/src/coin/coin.ts (2)

791-893: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

transfer and mint are byte-for-byte identical except the action type.

Extract the shared output-building + action-append flow into a private helper parameterized by "Transfer" | "Mint" to keep the two paths from drifting.

♻️ Sketch
+  private async addCoinOutputs(
+    type: "Transfer" | "Mint",
+    items: { to: ccc.ScriptLike; amount: ccc.NumLike }[],
+    txLike?: ccc.TransactionLike | null,
+  ): Promise<{
+    tx: ccc.Transaction;
+    outputIndexes: number[];
+    witnessIndex: number;
+  }> {
+    const tx = ccc.Transaction.from(txLike ?? {});
+    const outputIndexes: number[] = [];
+
+    for (const { to, amount } of items) {
+      outputIndexes.push(
+        tx.addOutput(
+          await this.setAmount(
+            { cellOutput: { lock: to, type: await this.script } },
+            amount,
+          ),
+        ) - 1,
+      );
+    }
+
+    return {
+      ...(await (
+        await this.coBuild
+      ).appendActions(
+        tx,
+        items.map((value) => CoinAction.from({ type, value })),
+      )),
+      outputIndexes,
+    };
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.ts` around lines 791 - 893, Extract the
duplicated transaction output-building and CoBuild action-appending logic from
transfer and mint into a private helper parameterized by the action type
"Transfer" | "Mint". Have transfer and mint delegate to this helper while
preserving their existing inputs, outputIndexes, transaction handling, and
CoinAction behavior.

377-395: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Silently swallowing every decode error hides malformed actions.

A CoBuild action that fails to decode is treated as "no mint/burn intent", so completion accounting silently diverges from what the script will enforce on-chain. Consider narrowing the swallow to decode failures and surfacing them (log/warn), so callers can diagnose a tx that later fails verification.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.ts` around lines 377 - 395, Update
getIntendedAmountBurned so CoinAction decoding failures are not silently
ignored: catch only the expected decode error type, surface it through the
established logging or warning mechanism, and let unexpected errors propagate.
Preserve the existing zero contribution for successfully decoded non-mint/burn
actions.
packages/coin/src/coin/coin.test.ts (1)

1012-1017: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

mockImplementationOnce is fragile here — completion sources inputs in two phases.

completeChangeToOutput invokes completeInputsByAmount twice and resolves each input cell via client.getCell, so the second and later calls silently fall back to the describe-level mocks, which don't know highCapCoin. Prefer a persistent mockImplementation that resolves highCapCoin by out point.

♻️ Proposed change
-      vi.spyOn(signer, "findCells").mockImplementationOnce(async function* () {
-        yield highCapCoin;
-      });
-      vi.spyOn(client, "getCell").mockImplementationOnce(
-        async () => highCapCoin,
-      );
+      vi.spyOn(signer, "findCells").mockImplementation(async function* () {
+        yield highCapCoin;
+      });
+      vi.spyOn(client, "getCell").mockImplementation(async (outPoint) =>
+        ccc.OutPoint.from(outPoint).eq(highCapCoin.outPoint)
+          ? highCapCoin
+          : undefined,
+      );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.test.ts` around lines 1012 - 1017, Update the
test mocks around completeChangeToOutput to use persistent mockImplementation
calls instead of mockImplementationOnce for signer.findCells and client.getCell.
Ensure client.getCell resolves highCapCoin by its out point on every invocation,
so both completeInputsByAmount phases use the intended fixture rather than
falling back to describe-level mocks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/coin/src/coin/coin.test.ts`:
- Around line 1700-1707: Update the test setup in “should add outputs correctly”
so recipientLock1 and recipientLock2 are distinct scripts, using a separate
signer or address source for the second recipient. Keep the existing transfer
and recipient-pairing assertions unchanged so they can detect swapped or
incorrect output destinations.
- Around line 720-727: Clone completedTx.outputs[1] before passing it to
CellOutput.from when computing minCapacity, ensuring the capacity baseline is
independent of the output being validated. Apply the same
clone-before-comparison pattern to the other two related assertions in
coin.test.ts.

In `@packages/coin/src/coin/coin.ts`:
- Around line 145-184: Update the constructor promise fan-out around resolved,
script, cellDeps, filter, and coBuild so a single initialization failure is
shared through one guarded promise rather than producing independently unhandled
branch rejections. Ensure callers can still await each exposed promise while
handling getKnownScript or getCellDeps failures does not terminate the process
through unobserved sibling promises.

---

Nitpick comments:
In `@packages/coin/src/coin/coin.test.ts`:
- Around line 1012-1017: Update the test mocks around completeChangeToOutput to
use persistent mockImplementation calls instead of mockImplementationOnce for
signer.findCells and client.getCell. Ensure client.getCell resolves highCapCoin
by its out point on every invocation, so both completeInputsByAmount phases use
the intended fixture rather than falling back to describe-level mocks.

In `@packages/coin/src/coin/coin.ts`:
- Around line 791-893: Extract the duplicated transaction output-building and
CoBuild action-appending logic from transfer and mint into a private helper
parameterized by the action type "Transfer" | "Mint". Have transfer and mint
delegate to this helper while preserving their existing inputs, outputIndexes,
transaction handling, and CoinAction behavior.
- Around line 377-395: Update getIntendedAmountBurned so CoinAction decoding
failures are not silently ignored: catch only the expected decode error type,
surface it through the established logging or warning mechanism, and let
unexpected errors propagate. Preserve the existing zero contribution for
successfully decoded non-mint/burn actions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 243b1e87-efc2-487f-9007-58ca5a786248

📥 Commits

Reviewing files that changed from the base of the PR and between ebd5a39 and 627b291.

⛔ Files ignored due to path filters (2)
  • packages/coin/misc/basedirs/dist/package.json is excluded by !**/dist/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (28)
  • .changeset/early-oranges-lick.md
  • packages/coin/.npmignore
  • packages/coin/.prettierignore
  • packages/coin/README.md
  • packages/coin/eslint.config.mjs
  • packages/coin/misc/basedirs/dist.commonjs/package.json
  • packages/coin/package.json
  • packages/coin/prettier.config.cjs
  • packages/coin/src/barrel.ts
  • packages/coin/src/coBuild.ts
  • packages/coin/src/coin/coin.test.ts
  • packages/coin/src/coin/coin.ts
  • packages/coin/src/coin/coinInfo.ts
  • packages/coin/src/coin/error.ts
  • packages/coin/src/coin/index.ts
  • packages/coin/src/index.ts
  • packages/coin/src/xUdt/args.ts
  • packages/coin/src/xUdt/coinXUdt.ts
  • packages/coin/src/xUdt/index.ts
  • packages/coin/src/xUdt/xUdt.test.ts
  • packages/coin/tsconfig.json
  • packages/coin/tsdown.config.mts
  • packages/coin/typedoc.json
  • packages/coin/vitest.config.ts
  • packages/shell/package.json
  • packages/shell/src/barrel.ts
  • typedoc.config.mjs
  • vitest.config.mts
🚧 Files skipped from review as they are similar to previous changes (22)
  • packages/coin/misc/basedirs/dist.commonjs/package.json
  • packages/coin/typedoc.json
  • vitest.config.mts
  • packages/shell/src/barrel.ts
  • packages/coin/.prettierignore
  • packages/coin/src/xUdt/index.ts
  • packages/coin/src/coin/error.ts
  • packages/coin/src/coin/index.ts
  • packages/coin/README.md
  • packages/coin/prettier.config.cjs
  • typedoc.config.mjs
  • .changeset/early-oranges-lick.md
  • packages/coin/src/barrel.ts
  • packages/coin/src/index.ts
  • packages/coin/tsdown.config.mts
  • packages/coin/tsconfig.json
  • packages/coin/vitest.config.ts
  • packages/shell/package.json
  • packages/coin/eslint.config.mjs
  • packages/coin/src/coBuild.ts
  • packages/coin/package.json
  • packages/coin/src/coin/coinInfo.ts

Comment thread packages/coin/src/coin/coin.test.ts
Comment thread packages/coin/src/coin/coin.test.ts
Comment thread packages/coin/src/coin/coin.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 28 out of 30 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

Comment thread packages/coin/src/coin/coin.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (3)
packages/coin/src/coin/coin.test.ts (2)

1748-1749: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Both recipients are the same lock, so the pairing assertions can't fail.

Use a distinct script for recipientLock2 so a swapped to would be detected at Lines 1758-1761 and 1779-1781.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.test.ts` around lines 1748 - 1749, Update
recipientLock2 in the test setup around recipientLock1 to use a distinct
recipient signer or address script, while keeping recipientLock1 unchanged.
Ensure the pairing assertions at the referenced assertion blocks compare
different locks so swapped to values are detected.

753-759: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

minCapacity baseline is derived from the same output being asserted.

ccc.CellOutput.from(completedTx.outputs[1], ...) reuses the passed instance, so the comparison can become self-referential. Clone the output before computing minCapacity; the same pattern appears at Lines 1092-1098 and 1143-1150.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.test.ts` around lines 753 - 759, Update the
minCapacity calculations in the test blocks around the current assertion and the
matching blocks near lines 1092 and 1143 to pass a cloned completedTx.outputs[1]
into ccc.CellOutput.from instead of the original output. Keep the existing
capacity assertions unchanged while ensuring each baseline is computed from an
independent output instance.
packages/coin/src/coin/coin.ts (1)

152-169: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Promise fan-out from resolved can still surface unhandled rejections.

script, cellDeps, filter, and coBuild are four independent chains. If getKnownScript/getCellDeps rejects, any branch the caller does not await stays unobserved.

🛡️ Proposed guard
     this.coBuild = Promise.all([this.script]).then(
       ([script]) => new coBuild.CoBuild(script, options.scriptInfo),
     );
+
+    // Mark every exposed branch as handled so an early resolution failure
+    // cannot escape as an unhandled rejection.
+    for (const p of [this.script, this.cellDeps, this.filter, this.coBuild]) {
+      void p.catch(() => {});
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.ts` around lines 152 - 169, Update the promise
fan-out in the constructor around resolved, script, cellDeps, filter, and
coBuild so rejection from getKnownScript/getCellDeps is observed by every
branch, preventing unhandled rejections when callers await only a subset. Add
the shared rejection guard or otherwise attach equivalent handling to each
derived promise while preserving their existing resolved values and behavior.
🧹 Nitpick comments (2)
packages/coin/src/coin/coin.ts (2)

615-621: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Read the final amounts from res2.tx rather than tx.

This only works because ccc.Transaction.from returns the same instance for an existing Transaction, so tx happens to have the inputs added by completeInputsByAmount. Referencing res2.tx makes the data flow explicit and immune to a future clone-on-from change.

♻️ Proposed refactor
     return ccc.Transaction.from(
       await change(
         res2.tx,
-        (await this.getAmountBurned(tx)) -
-          (await this.getIntendedAmountBurned(tx)),
+        (await this.getAmountBurned(res2.tx)) -
+          (await this.getIntendedAmountBurned(res2.tx)),
       ),
     );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.ts` around lines 615 - 621, Update the amount
calculations in the returned transaction flow to pass res2.tx to getAmountBurned
and getIntendedAmountBurned instead of tx, while preserving the existing change
and ccc.Transaction.from behavior.

322-332: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Inputs are resolved one RPC at a time.

getInputsInfo awaits input.getCell(client) sequentially, so latency scales linearly with input count on every call — and completeInputsByAmount/complete call it repeatedly. Consider resolving in parallel (e.g. Promise.all over tx.inputs) before aggregating.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.ts` around lines 322 - 332, Update getInputsInfo
to resolve all tx.inputs concurrently with Promise.all rather than awaiting
input.getCell(client) sequentially in the async generator, then pass the
resolved cells to infoFrom while preserving the existing CoinInfo result.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@packages/coin/src/coin/coin.test.ts`:
- Around line 1748-1749: Update recipientLock2 in the test setup around
recipientLock1 to use a distinct recipient signer or address script, while
keeping recipientLock1 unchanged. Ensure the pairing assertions at the
referenced assertion blocks compare different locks so swapped to values are
detected.
- Around line 753-759: Update the minCapacity calculations in the test blocks
around the current assertion and the matching blocks near lines 1092 and 1143 to
pass a cloned completedTx.outputs[1] into ccc.CellOutput.from instead of the
original output. Keep the existing capacity assertions unchanged while ensuring
each baseline is computed from an independent output instance.

In `@packages/coin/src/coin/coin.ts`:
- Around line 152-169: Update the promise fan-out in the constructor around
resolved, script, cellDeps, filter, and coBuild so rejection from
getKnownScript/getCellDeps is observed by every branch, preventing unhandled
rejections when callers await only a subset. Add the shared rejection guard or
otherwise attach equivalent handling to each derived promise while preserving
their existing resolved values and behavior.

---

Nitpick comments:
In `@packages/coin/src/coin/coin.ts`:
- Around line 615-621: Update the amount calculations in the returned
transaction flow to pass res2.tx to getAmountBurned and getIntendedAmountBurned
instead of tx, while preserving the existing change and ccc.Transaction.from
behavior.
- Around line 322-332: Update getInputsInfo to resolve all tx.inputs
concurrently with Promise.all rather than awaiting input.getCell(client)
sequentially in the async generator, then pass the resolved cells to infoFrom
while preserving the existing CoinInfo result.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 377c8388-a7cd-493a-b05f-0e8352ea940f

📥 Commits

Reviewing files that changed from the base of the PR and between 627b291 and 0e295e7.

⛔ Files ignored due to path filters (2)
  • packages/coin/misc/basedirs/dist/package.json is excluded by !**/dist/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (28)
  • .changeset/early-oranges-lick.md
  • packages/coin/.npmignore
  • packages/coin/.prettierignore
  • packages/coin/README.md
  • packages/coin/eslint.config.mjs
  • packages/coin/misc/basedirs/dist.commonjs/package.json
  • packages/coin/package.json
  • packages/coin/prettier.config.cjs
  • packages/coin/src/barrel.ts
  • packages/coin/src/coBuild.ts
  • packages/coin/src/coin/coin.test.ts
  • packages/coin/src/coin/coin.ts
  • packages/coin/src/coin/coinInfo.ts
  • packages/coin/src/coin/error.ts
  • packages/coin/src/coin/index.ts
  • packages/coin/src/index.ts
  • packages/coin/src/xUdt/args.ts
  • packages/coin/src/xUdt/coinXUdt.ts
  • packages/coin/src/xUdt/index.ts
  • packages/coin/src/xUdt/xUdt.test.ts
  • packages/coin/tsconfig.json
  • packages/coin/tsdown.config.mts
  • packages/coin/typedoc.json
  • packages/coin/vitest.config.ts
  • packages/shell/package.json
  • packages/shell/src/barrel.ts
  • typedoc.config.mjs
  • vitest.config.mts
🚧 Files skipped from review as they are similar to previous changes (22)
  • packages/coin/typedoc.json
  • packages/coin/src/barrel.ts
  • typedoc.config.mjs
  • packages/coin/misc/basedirs/dist.commonjs/package.json
  • packages/coin/src/coin/index.ts
  • packages/coin/src/xUdt/index.ts
  • .changeset/early-oranges-lick.md
  • vitest.config.mts
  • packages/coin/vitest.config.ts
  • packages/coin/prettier.config.cjs
  • packages/shell/src/barrel.ts
  • packages/coin/src/index.ts
  • packages/coin/README.md
  • packages/coin/.prettierignore
  • packages/coin/tsconfig.json
  • packages/coin/src/coin/error.ts
  • packages/coin/tsdown.config.mts
  • packages/coin/src/coin/coinInfo.ts
  • packages/coin/package.json
  • packages/coin/eslint.config.mjs
  • packages/coin/src/coBuild.ts
  • packages/coin/src/xUdt/xUdt.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
packages/coin/src/coin/coin.test.ts (3)

930-944: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert on the returned transaction and tighten the count.

The returned tx is dropped and the assertions read the input object, so this only passes because Transaction.from hands back the same instance. With 3 mock coins available, toBeGreaterThan(2) also only admits one value.

♻️ Proposed refactor
-      const { addedCount } = await coin.completeInputsByAmount(
+      const { addedCount, tx: completedTx } = await coin.completeInputsByAmount(
         signer,
         tx,
         ccc.Zero, // No extra Coin amount needed
         extraCapacityNeeded, // Extra capacity needed
       );
 
-      // Should add Coins to cover the capacity requirement
-      expect(addedCount).toBeGreaterThan(2);
-
-      // Should have added at least one cell with capacity
-      expect(await coin.getInputsAmount(tx)).toBeGreaterThan(ccc.Zero);
+      // All 3 available Coins are pulled in to chase the capacity requirement
+      expect(addedCount).toBe(3);
+      expect(await coin.getInputsAmount(completedTx)).toBe(ccc.numFrom(300));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.test.ts` around lines 930 - 944, Update the
capacity-requirement test around coin.completeInputsByAmount to use and assert
on the returned transaction rather than the original tx object. Tighten the
addedCount expectation to require all three available mock coins, and read the
resulting input amount from the returned transaction.

1522-1535: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move mock cleanup into an afterEach.

vi.restoreAllMocks() inside a single test body is order-sensitive cleanup; every other block relies on re-installing spies in its own beforeEach. A file-level afterEach (or restoreMocks: true in the vitest config) makes isolation explicit for all tests.

♻️ Proposed refactor
+afterEach(() => {
+  vi.restoreAllMocks();
+});
       await expect(
         explicitSignerCoin.calculateInfo(signer),
       ).resolves.toBeDefined();
-      vi.restoreAllMocks();
     });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.test.ts` around lines 1522 - 1535, Move
vi.restoreAllMocks() out of the individual “uses a signer supplied to
calculateInfo” test and add file-level afterEach cleanup so mocks are restored
consistently after every test. Keep the existing beforeEach spy setup and test
behavior unchanged.

1047-1052: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

mockImplementationOnce couples this test to internal call counts.

The enclosing beforeEach already installed persistent mocks over mockCoins, which does not contain highCapCoin. Any second getCell/findCells lookup falls through and resolves undefined, so the inputs.length === 1 assertion depends on the implementation making exactly one call each. Prefer mockImplementation keyed on the outPoint.

♻️ Proposed refactor
-      vi.spyOn(signer, "findCells").mockImplementationOnce(async function* () {
+      vi.spyOn(signer, "findCells").mockImplementation(async function* () {
         yield highCapCoin;
       });
-      vi.spyOn(client, "getCell").mockImplementationOnce(
-        async () => highCapCoin,
-      );
+      vi.spyOn(client, "getCell").mockImplementation(async (outPoint) =>
+        highCapCoin.outPoint.eq(ccc.OutPoint.from(outPoint))
+          ? highCapCoin
+          : undefined,
+      );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.test.ts` around lines 1047 - 1052, Update the
signer.findCells and client.getCell mocks in the test to use persistent
mockImplementation handlers keyed by the requested outPoint, returning
highCapCoin for its matching outPoint and preserving the existing fallback
behavior for other lookups. Remove mockImplementationOnce so the inputs.length
assertion no longer depends on exact call counts.
packages/coin/src/xUdt/args.ts (1)

183-199: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Annotate the codec generics so DecodedType infers.

ESLint reports unsafe assignment on all six fields, meaning ccc.DecodedType<typeof CoinXUdtArgsCodec> is not inferring here — ccc.Codec.from is called without explicit type parameters at Line 89, so the decoded shape stays untyped. Supplying them (encode-in / decode-out) restores type safety for the constructor and removes the lint errors.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/xUdt/args.ts` around lines 183 - 199, Annotate the generic
parameters on the ccc.Codec.from call used to create CoinXUdtArgsCodec,
supplying the encode-in and decode-out types so ccc.DecodedType<typeof
CoinXUdtArgsCodec> infers the decoded shape and the six constructor assignments
remain type-safe.

Source: Linters/SAST tools

packages/coin/src/coin/coin.ts (1)

376-386: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Silent catch gives no signal when a Coin action fails to decode.

Tolerating undecodable actions is reasonable (the witness may carry other scripts' actions), but this value feeds the balance math in completeInputsByAmount (Line 480) and complete (Lines 588, 626). A corrupted Mint/Burn belonging to this coin is silently counted as zero, skewing the change amount with no diagnostic. Consider at least documenting the intent, or emitting a debug-level log.

♻️ Make the swallow intentional and observable
         try {
           const coinAction = CoinAction.fromBytes(action.data, {
             isExtraFieldIgnored: true,
           });
           acc += coinAction.match({
             Mint: (mint) => -mint.amount,
             Burn: (burn) => burn.amount,
             _: () => ccc.Zero,
           });
-        } catch (_) {}
+        } catch (err) {
+          // Actions in this witness may belong to other scripts or newer
+          // versions; treat anything we cannot decode as amount-neutral.
+          void err;
+        }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.ts` around lines 376 - 386, Update the catch
block around CoinAction.fromBytes in the action balance calculation to make the
intentional tolerance of undecodable actions observable, preferably by emitting
a debug-level diagnostic that includes the decode error. Preserve the existing
behavior of ignoring unsupported or malformed actions and continuing the
accumulator calculation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/coin/src/coin/coin.ts`:
- Around line 158-165: Update the filter initialization in the Coin constructor
so caller-provided options.filter are merged over the default filter rather than
replacing it, ensuring the coin type script constraint remains enforced while
allowing custom fields to override defaults. Preserve the existing
outputDataLenRange default unless explicitly overridden, and keep the resulting
filter compatible with completeInputs.

In `@packages/coin/src/xUdt/args.ts`:
- Around line 94-109: Update the flags calculation in the argument encoding flow
to coerce the final bitwise result to an unsigned 32-bit value before passing it
to ccc.numLeToBytes. Preserve the existing flag bits and
ownerScriptHash/extension handling, including the ownerModeInputType 0x80000000
case.

---

Nitpick comments:
In `@packages/coin/src/coin/coin.test.ts`:
- Around line 930-944: Update the capacity-requirement test around
coin.completeInputsByAmount to use and assert on the returned transaction rather
than the original tx object. Tighten the addedCount expectation to require all
three available mock coins, and read the resulting input amount from the
returned transaction.
- Around line 1522-1535: Move vi.restoreAllMocks() out of the individual “uses a
signer supplied to calculateInfo” test and add file-level afterEach cleanup so
mocks are restored consistently after every test. Keep the existing beforeEach
spy setup and test behavior unchanged.
- Around line 1047-1052: Update the signer.findCells and client.getCell mocks in
the test to use persistent mockImplementation handlers keyed by the requested
outPoint, returning highCapCoin for its matching outPoint and preserving the
existing fallback behavior for other lookups. Remove mockImplementationOnce so
the inputs.length assertion no longer depends on exact call counts.

In `@packages/coin/src/coin/coin.ts`:
- Around line 376-386: Update the catch block around CoinAction.fromBytes in the
action balance calculation to make the intentional tolerance of undecodable
actions observable, preferably by emitting a debug-level diagnostic that
includes the decode error. Preserve the existing behavior of ignoring
unsupported or malformed actions and continuing the accumulator calculation.

In `@packages/coin/src/xUdt/args.ts`:
- Around line 183-199: Annotate the generic parameters on the ccc.Codec.from
call used to create CoinXUdtArgsCodec, supplying the encode-in and decode-out
types so ccc.DecodedType<typeof CoinXUdtArgsCodec> infers the decoded shape and
the six constructor assignments remain type-safe.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e76a77d2-c93b-426e-89d3-0c1ce3742927

📥 Commits

Reviewing files that changed from the base of the PR and between 0e295e7 and ba1e079.

⛔ Files ignored due to path filters (2)
  • packages/coin/misc/basedirs/dist/package.json is excluded by !**/dist/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (28)
  • .changeset/early-oranges-lick.md
  • packages/coin/.npmignore
  • packages/coin/.prettierignore
  • packages/coin/README.md
  • packages/coin/eslint.config.mjs
  • packages/coin/misc/basedirs/dist.commonjs/package.json
  • packages/coin/package.json
  • packages/coin/prettier.config.cjs
  • packages/coin/src/barrel.ts
  • packages/coin/src/coBuild.ts
  • packages/coin/src/coin/coin.test.ts
  • packages/coin/src/coin/coin.ts
  • packages/coin/src/coin/coinInfo.ts
  • packages/coin/src/coin/error.ts
  • packages/coin/src/coin/index.ts
  • packages/coin/src/index.ts
  • packages/coin/src/xUdt/args.ts
  • packages/coin/src/xUdt/coinXUdt.ts
  • packages/coin/src/xUdt/index.ts
  • packages/coin/src/xUdt/xUdt.test.ts
  • packages/coin/tsconfig.json
  • packages/coin/tsdown.config.mts
  • packages/coin/typedoc.json
  • packages/coin/vitest.config.ts
  • packages/shell/package.json
  • packages/shell/src/barrel.ts
  • typedoc.config.mjs
  • vitest.config.mts
🚧 Files skipped from review as they are similar to previous changes (25)
  • packages/shell/package.json
  • packages/coin/typedoc.json
  • .changeset/early-oranges-lick.md
  • typedoc.config.mjs
  • packages/coin/src/barrel.ts
  • packages/coin/src/index.ts
  • packages/coin/src/xUdt/index.ts
  • packages/shell/src/barrel.ts
  • packages/coin/prettier.config.cjs
  • packages/coin/vitest.config.ts
  • vitest.config.mts
  • packages/coin/src/coin/error.ts
  • packages/coin/eslint.config.mjs
  • packages/coin/src/coin/index.ts
  • packages/coin/README.md
  • packages/coin/misc/basedirs/dist.commonjs/package.json
  • packages/coin/package.json
  • packages/coin/.npmignore
  • packages/coin/.prettierignore
  • packages/coin/tsconfig.json
  • packages/coin/src/coin/coinInfo.ts
  • packages/coin/src/xUdt/coinXUdt.ts
  • packages/coin/src/coBuild.ts
  • packages/coin/tsdown.config.mts
  • packages/coin/src/xUdt/xUdt.test.ts

Comment thread packages/coin/src/coin/coin.ts Outdated
Comment thread packages/coin/src/xUdt/args.ts
@Hanssen0
Hanssen0 force-pushed the feat/coin branch 5 times, most recently from 952c9c7 to c4617af Compare July 25, 2026 22:55
@Hanssen0
Hanssen0 requested a review from Copilot July 25, 2026 22:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 28 out of 30 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

Comment thread packages/coin/src/coin/coin.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
packages/coin/src/coin/coin.ts (2)

773-838: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

transfer and mint are identical except for the action type.

Both bodies duplicate output creation, setAmount, and appendActions; only the "Transfer"/"Mint" literal differs. Extracting a shared private helper keeps future changes (e.g. added action fields) from drifting between the two.

♻️ Proposed extraction
+  /** Shared implementation for `transfer` and `mint`. `@internal` */
+  protected async addValueOutputs(
+    type: "Transfer" | "Mint",
+    items: { to: ccc.ScriptLike; amount: ccc.NumLike }[],
+    txLike?: ccc.TransactionLike | null,
+  ): Promise<ccc.Transaction> {
+    let tx = ccc.Transaction.from(txLike ?? {});
+
+    for (const { to, amount } of items) {
+      const outputIndex = tx.addOutput({ lock: to, type: this.script }) - 1;
+      tx = await this.setAmount(tx, outputIndex, amount);
+    }
+
+    const { tx: txWithActions } = await this.coBuild.appendActions(
+      items.map((value) => CoinAction.from({ type, value })),
+      tx,
+    );
+    return txWithActions;
+  }

transfer and mint then become one-liners delegating with the respective action type.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.ts` around lines 773 - 838, Extract the shared
transaction-building logic from transfer and mint into a private helper that
accepts the transfers/mints collection and the CoinAction type. Have the helper
create outputs, apply setAmount, append the corresponding actions, and return
the updated transaction; reduce transfer and mint to delegations using
"Transfer" and "Mint" respectively.

355-361: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Input cells are fetched strictly sequentially.

Each input.getCell(client) awaits the previous one, so a transaction with many inputs costs N serial round-trips. If the client does not cache aggressively, consider resolving in batches (or tx.getInputsCapacity-style prefetch) while keeping the async-iterable contract for infoFrom.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/coin/src/coin/coin.ts` around lines 355 - 361, Update the async
generator passed to infoFrom in the transaction input flow so
input.getCell(client) requests are resolved concurrently or in batches instead
of awaiting each input strictly sequentially. Preserve the async-iterable
contract and yield each resolved cell with the existing input order and
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/coin/src/coin/coin.ts`:
- Around line 183-189: Update the normalized filter construction around
ClientIndexerSearchKeyFilter.from so caller-provided options are merged with the
default script, script length range, and output data length range rather than
replacing them; ensure the identifying normalizedScript remains pinned while
allowing supported caller fields to override defaults as intended.
- Around line 394-410: Update getIntendedAmountBurned so CoinAction.fromBytes or
action matching failures are surfaced instead of silently swallowed, allowing
malformed relevant actions to fail change computation; remove the empty catch or
rethrow with useful context. Add TSDoc describing the method’s intended amount
calculation and its failure behavior, consistent with the surrounding public
API.

In `@packages/coin/src/xUdt/coinXUdt.ts`:
- Around line 126-141: Update the coin option handling around the script branch
so a partially specified script containing only codeHash or only hashType is
rejected rather than routed to the known xUDT fallback. Preserve the existing
fully specified custom script path and the knownScript default only when no
script identifiers are supplied, allowing Coin.resolveOptions to surface the
invalid partial configuration.

---

Nitpick comments:
In `@packages/coin/src/coin/coin.ts`:
- Around line 773-838: Extract the shared transaction-building logic from
transfer and mint into a private helper that accepts the transfers/mints
collection and the CoinAction type. Have the helper create outputs, apply
setAmount, append the corresponding actions, and return the updated transaction;
reduce transfer and mint to delegations using "Transfer" and "Mint"
respectively.
- Around line 355-361: Update the async generator passed to infoFrom in the
transaction input flow so input.getCell(client) requests are resolved
concurrently or in batches instead of awaiting each input strictly sequentially.
Preserve the async-iterable contract and yield each resolved cell with the
existing input order and behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c7478433-39db-4838-af39-e55c8e02bf92

📥 Commits

Reviewing files that changed from the base of the PR and between 0e295e7 and c4617af.

⛔ Files ignored due to path filters (2)
  • packages/coin/misc/basedirs/dist/package.json is excluded by !**/dist/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (28)
  • .changeset/early-oranges-lick.md
  • packages/coin/.npmignore
  • packages/coin/.prettierignore
  • packages/coin/README.md
  • packages/coin/eslint.config.mjs
  • packages/coin/misc/basedirs/dist.commonjs/package.json
  • packages/coin/package.json
  • packages/coin/prettier.config.cjs
  • packages/coin/src/barrel.ts
  • packages/coin/src/coBuild.ts
  • packages/coin/src/coin/coin.test.ts
  • packages/coin/src/coin/coin.ts
  • packages/coin/src/coin/coinInfo.ts
  • packages/coin/src/coin/error.ts
  • packages/coin/src/coin/index.ts
  • packages/coin/src/index.ts
  • packages/coin/src/xUdt/args.ts
  • packages/coin/src/xUdt/coinXUdt.ts
  • packages/coin/src/xUdt/index.ts
  • packages/coin/src/xUdt/xUdt.test.ts
  • packages/coin/tsconfig.json
  • packages/coin/tsdown.config.mts
  • packages/coin/typedoc.json
  • packages/coin/vitest.config.ts
  • packages/shell/package.json
  • packages/shell/src/barrel.ts
  • typedoc.config.mjs
  • vitest.config.mts
🚧 Files skipped from review as they are similar to previous changes (25)
  • .changeset/early-oranges-lick.md
  • packages/shell/package.json
  • packages/shell/src/barrel.ts
  • packages/coin/.prettierignore
  • packages/coin/src/xUdt/index.ts
  • packages/coin/src/barrel.ts
  • typedoc.config.mjs
  • packages/coin/typedoc.json
  • packages/coin/src/coin/index.ts
  • vitest.config.mts
  • packages/coin/README.md
  • packages/coin/prettier.config.cjs
  • packages/coin/vitest.config.ts
  • packages/coin/misc/basedirs/dist.commonjs/package.json
  • packages/coin/src/index.ts
  • packages/coin/src/coin/error.ts
  • packages/coin/tsconfig.json
  • packages/coin/package.json
  • packages/coin/tsdown.config.mts
  • packages/coin/src/coin/coinInfo.ts
  • packages/coin/src/coBuild.ts
  • packages/coin/eslint.config.mjs
  • packages/coin/src/xUdt/args.ts
  • packages/coin/src/xUdt/xUdt.test.ts
  • packages/coin/src/coin/coin.test.ts

Comment thread packages/coin/src/coin/coin.ts
Comment thread packages/coin/src/coin/coin.ts
Comment thread packages/coin/src/xUdt/coinXUdt.ts
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