feat: add UDT balance and transfer CLI commands#447
Conversation
最终质量评估报告目标 PR:#447 feat: add UDT balance and transfer CLI commands 1. 变更摘要变更范围
风险等级分布
2. 专家发现汇总(按严重程度排序)Critical
High
Medium
3. 对抗性审查质疑与回应
4. 未解决冲突
5. 最终建议
阻塞性修复清单(合并前必须完成)
复测要求完成上述修复后,必须:
6. 遗留风险
结论:PR #447 在接口层面覆盖了需求 #445,但存在高置信度的链上交易构造缺陷、SDK 单测真空、输入校验薄弱及安全风险。建议按上述清单修复并在真实 devnet 复测通过后,方可合并。 |
Add offckb udt-balance and udt-transfer commands leveraging the CCC SDK. Supports both SUDT and xUDT via --kind. - udt-balance: query UDT balance for an address - udt-transfer: transfer UDT amount to an address with change output Closes ckb-devrel#445 Co-Authored-By: Claude <noreply@anthropic.com>
- Reuse existing balance/transfer commands via --udt-type-args/--udt-kind flags - Make balance default show CKB plus detected SUDT/xUDT balances - Replace udt-balance/udt-transfer with udt issue/destroy subcommands - Add detectUdtBalances, udtIssue, and udtDestroy to CKB SDK - Update tests for the revised CLI Co-Authored-By: Claude <noreply@anthropic.com>
- Add minor changeset for the new UDT issue/destroy commands and balance/transfer reuse. - Apply prettier formatting to src/cmd/transfer.ts. Co-Authored-By: Claude <noreply@anthropic.com>
- Use minimal cell capacity (capacity: 0) instead of hardcoded 61 CKB for UDT outputs - Add missing cell deps in udtTransfer - Reject full UDT destroy to avoid potential script rejection - Add max input cell limit for udtDestroy - Skip corrupted UDT cells in balance detection instead of failing - Remove hard 500-cell cap on UDT balance scan (now 1000 with warning) - Add input validation: amount, type args length, UDT kind enum - Warn when --type-args is provided for SUDT issue - Remove process.exit(0) from balance command - Support filtering balance by --udt-kind alone - Add CLI enum choices for --udt-kind and --kind - Add SDK-level UDT tests and expand validator tests Co-Authored-By: Claude <noreply@anthropic.com>
de06cff to
5ba6515
Compare
humble-little-bear
left a comment
There was a problem hiding this comment.
Code review results from the Multica Code-Review-Squad. See the summary comment below for the full report.
| .addOption(new Option('--kind <kind>', 'Specify the UDT kind').choices(['sudt', 'xudt']).default('sudt')) | ||
| .option('--type-args <typeArgs>', 'Specify the UDT type script args (xudt only; defaults to signer lock hash)') | ||
| .option('--to <toAddress>', 'Specify the receiver address (defaults to signer)') | ||
| .option('--privkey <privkey>', 'Specify the private key to issue UDT') |
There was a problem hiding this comment.
🛑 [CRITICAL / Security] Accepting the private key via --privkey exposes it to any process on the same host (ps, /proc/<pid>/cmdline). The same risk exists at line 192 for udt destroy. Please read the key from an environment variable (OFFCKB_PRIVATE_KEY) or a file (--privkey-file) instead.
| logger.info(` ${udt.kind} (args=${udt.args}): ${udt.balance}`); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
balanceOf ended with process.exit(0); removing it may leave the CKB client’s HTTP/fetch keep-alive handles open, causing the CLI process to hang. Consider restoring process.exit(0) or explicitly closing the client.
| outputsData, | ||
| }); | ||
|
|
||
| const systemScripts = this.getSystemScripts(); |
There was a problem hiding this comment.
udtTransfer (L336-342), udtIssue (L405-408) and udtDestroy (L468-471). Extract a private helper such as getUdtScriptInfo(kind) to keep the three call sites consistent.
| .command('issue <amount>') | ||
| .description('Issue new UDT tokens, only devnet and testnet') | ||
| .option('--network <network>', 'Specify the network', 'devnet') | ||
| .addOption(new Option('--kind <kind>', 'Specify the UDT kind').choices(['sudt', 'xudt']).default('sudt')) |
There was a problem hiding this comment.
--kind here, but transfer/balance use --udt-kind. Unifying the flag name would make the CLI more predictable for users.
|
|
||
| export function validateUdtKind(kind?: string): asserts kind is 'sudt' | 'xudt' { | ||
| if (!kind) { | ||
| throw new Error('--udt-kind is required'); |
There was a problem hiding this comment.
--udt-kind is required, but udt issue/destroy expose --kind. The message will confuse users when the flag is missing.
| }); | ||
|
|
||
| describe('udtIssue type args handling', () => { | ||
| it('should warn when SUDT issue receives a user type args', async () => { |
There was a problem hiding this comment.
should warn when SUDT issue receives a user type args but it neither calls udtIssue nor asserts on logger.warn. Please rewrite or rename it.
| process.exit(0); | ||
| logger.info(`CKB: ${balanceInCKB}`); | ||
|
|
||
| const udtBalances = await ckb.detectUdtBalances(address); |
There was a problem hiding this comment.
balanceOf always triggers a full UDT scan (detectUdtBalances), even when the user only wants the CKB balance. Consider skipping the scan unless requested, or at least running the two queries in parallel.
| type.codeHash === codeHash && String(type.hashType) === hashType; | ||
|
|
||
| let scanned = 0; | ||
| for await (const cell of this.client.findCellsByLock(lock, undefined, true, 'asc')) { |
There was a problem hiding this comment.
findCellsByLock(lock, undefined, ...) fetches every live cell’s outputData and filters UDTs client-side. Filtering by SUDT/xUDT type script (e.g. prefix search on code hash) would reduce RPC traffic and processing significantly.
| } | ||
| } | ||
|
|
||
| export function validateUdtAmount(amount: string): bigint { |
There was a problem hiding this comment.
💡 [SUGGESTION / Correctness+Security] validateUdtAmount rejects negative/non-numeric input but does not enforce the u128 upper bound. Adding an explicit value <= (1n << 128n) - 1n check would give users a clearer error than relying on ccc.numToBytes to throw later.
| }); | ||
| } | ||
|
|
||
| async detectUdtBalances(address: string, { maxCells = 1000 }: { maxCells?: number } = {}): Promise<UdtBalanceInfo[]> { |
There was a problem hiding this comment.
💡 [SUGGESTION / Maintainability] The default scan limit 1000 is a magic number. Please define a named constant such as DEFAULT_UDT_SCAN_MAX_CELLS.
Review Report for PR #447摘要
CRITICAL(必须修复)1. [Security]
|
| Specialist | 被过滤项 | Challenger 结论 | 理由 |
|---|---|---|---|
| Correctness | udtTransfer 未防御 changeAmount < 0 |
DROP | completeInputsByUdt 在余额不足时已抛 ErrorTransactionInsufficientCoin,不会执行到 changeAmount 计算 |
| Maintainability | balance.ts 输出格式变更缺乏集中式格式化层 |
DROP | 仅一行字符串改动,引入 format.ts 属于过度设计 |
| Performance | 重复调用 getSystemScripts() / client.getKnownScript |
DROP | 前者为本地常量/文件读取,后者读取内存 scripts 映射,均非 RPC,缓存收益可忽略 |
| Performance | udtDestroy 先收集 cells 再添加 input |
DROP | maxInputCells 默认仅 100,内存与遍历开销可忽略 |
- 总体误报率:4 / 19 ≈ 21%
- 建议:Correctness Specialist 对 CCC SDK 的
completeInputsByUdt防御行为可进一步确认;Performance Specialist 在判断 RPC/内存开销时应先验证调用是否为网络/高成本操作。
修复检查清单(供开发者勾选)
- 修复 CRITICAL feat: embed built-in scripts in the devnet config #1:将
--privkey改为环境变量或--privkey-file读取 - 修复 WARNING Welcome to offckb Discussions! #2:恢复
balanceOf的process.exit(0)或显式关闭 client - 修复 WARNING General design discussion #3:抽取
getUdtScriptInfohelper 统一 SUDT/xUDT 分支 - 修复 WARNING refactor: rename docker/ckb -> docker/devnet #4:统一 UDT kind flag 命名
- 修复 WARNING feat: add init-chain/node cmd #5:修正
validateUdtKind错误消息 - 修复 WARNING feat: add lumos template and init command #6:重写/重命名
ckb.udt.test.ts中名不副实的测试用例 - 修复 WARNING refactor: manage all kinds of path #7:为
balance命令提供跳过 UDT 扫描的选项 - 修复 WARNING fix: make offckb node/list-hashes a one step cmd #8:
detectUdtBalances按 SUDT/xUDT type 过滤查询
- Extract getUdtScriptInfo helper to unify SUDT/xUDT script/cellDeps handling - Filter detectUdtBalances by UDT type script with prefix search instead of scanning all cells - Add --no-udt flag and parallel CKB/UDT queries in balance command - Restore process.exit(0) in balanceOf to prevent CLI hang - Unify UDT kind CLI flag to --udt-kind across balance/transfer/udt commands - Move UdtKind type to src/type/base.ts and reuse in validator - Add u128 upper bound check to validateUdtAmount - Add logTxSuccess helper to remove duplicated testnet/devnet success logging - Fix ckb.udt.test.ts test title/content mismatch and cover SUDT type-args warning - Update tests for renamed udtKind option and process.exit mocking Co-Authored-By: Claude <noreply@anthropic.com>
This PR adds simple UDT token operations to the offckb CLI, leveraging the CCC SDK.
New commands
offckb udt-balance [address] --type-args <args> [--kind sudt|xudt]– query the UDT balance of an address.offckb udt-transfer [toAddress] [amount] --type-args <args> --privkey <privkey> [--kind sudt|xudt]– transfer UDT tokens to an address.Implementation notes
src/sdk/ckb.tsgainsbuildUdtTypeScript,udtBalance, andudtTransfermethods.src/cmd/udt.tsprovides the command handlers.src/cli.tsregisters the new commands.tests/udt.test.tsadds unit tests for the command handlers.Both SUDT and xUDT are supported via the
--kindflag (default:sudt).Closes #445
🤖 Generated with Claude Code