



`@ckb-ccc/udt` 提供一套 TypeScript SDK，用于在 CKB 上与用户自定义代币（User-Defined Token，简称 UDT）及 xUDT 标准交互。它构建于 SSRI 协议之上，同时支持符合 SSRI 规范的合约和传统 sUDT / xUDT 代币。

## 安装 [#安装]

<PackageBadges pkg="@ckb-ccc/udt" />

<Callout type="info">
  如果你使用的是 `@ckb-ccc/shell`，`udt` 命名空间已作为 `ccc.udt` 内置其中。
</Callout>

<Tabs items="['npm', 'yarn', 'pnpm']">
  <Tab value="npm">
    ```bash
    npm install @ckb-ccc/udt
    ```
  </Tab>

  <Tab value="yarn">
    ```bash
    yarn add @ckb-ccc/udt
    ```
  </Tab>

  <Tab value="pnpm">
    ```bash
    pnpm add @ckb-ccc/udt
    ```
  </Tab>
</Tabs>

## 导出 [#导出]

| 导出            | 说明                        |
| ------------- | ------------------------- |
| `Udt`         | 与 UDT 交互的主类               |
| `UdtPausable` | 支持紧急暂停、合规与风控管理的 UDT 代币扩展类 |

## `Udt` 类 [#udt-类]

`Udt` 继承自 `ssri.Trait`，为所有代币操作提供高级方法。

### 构造函数 [#构造函数]

```typescript
const udt = new Udt(
  code,    // ccc.OutPointLike——脚本代码 Cell 的 OutPoint
  script,  // ccc.ScriptLike——标识该代币的 Type Script
  config?, // { executor?: ssri.Executor | null }
);
```

### 读取方法 [#读取方法]

```typescript
// 代币元数据
const { res: name }     = await udt.name();     // string | undefined
const { res: symbol }   = await udt.symbol();   // string | undefined
const { res: decimals } = await udt.decimals(); // ccc.Num | undefined
const { res: icon }     = await udt.icon();     // string（data URI）| undefined
```

### `transfer` [#transfer]

将代币转移给一个或多个接收方：

```typescript
async transfer(
  signer: ccc.Signer,
  transfers: { to: ccc.ScriptLike; amount: ccc.NumLike }[],
  tx?: ccc.TransactionLike | null,
): Promise<ssri.ExecutorResponse<ccc.Transaction>>
```

### `mint` [#mint]

铸造新代币（仅限发行方）：

```typescript
async mint(
  signer: ccc.Signer,
  mints: { to: ccc.ScriptLike; amount: ccc.NumLike }[],
  tx?: ccc.TransactionLike | null,
): Promise<ssri.ExecutorResponse<ccc.Transaction>>
```

### `completeBy` [#completeby]

以 `signer` 的推荐地址作为找零地址，自动平衡 UDT 的输入/输出：

```typescript
async completeBy(
  tx: ccc.TransactionLike,
  from: ccc.Signer,
): Promise<ccc.Transaction>
```

### `completeChangeToLock` [#completechangetolock]

这个方法主要用于 UDT 转账交易中，确保交易的输入和输出 UDT 余额平衡。当输入的 UDT 数量超过输出时，**将多余的代币发送到指定的地址**。

```typescript
async completeChangeToLock(
  txLike: ccc.TransactionLike,
  signer: ccc.Signer,
  change: ccc.ScriptLike,       // 找零地址
): Promise<ccc.Transaction>
```

## 使用示例 [#使用示例]

### 发行 xUDT [#发行-xudt]

以下示例展示如何使用 CCC 发行 xUDT 代币（来自 CCC 示例应用）：

```typescript
// 获取 Signer 推荐地址的 Lock 脚本，设置代币元数据
const { script } = await signer.getRecommendedAddressObj();
const decimals = "8";
const symbol = "SUS";
const name = "Sample Token";

// 创建交易，包含一个输出
const susTx = ccc.Transaction.from({
  outputs: [{ lock: script }],
});

// 自动添加输入以满足容量需求
await susTx.completeInputsByCapacity(signer);

// 自动添加手续费
await susTx.completeFeeBy(signer);

// 签名并广播交易，返回交易哈希
const susTxHash = await signer.sendTransaction(susTx);
```

### 使用 Type ID 发行 xUDT [#使用-type-id-发行-xudt]

```typescript
// 1. 创建或使用现有 Type ID
const typeId = await ccc.Script.fromKnownScript(
  signer.client,
  ccc.KnownScript.TypeId,
  typeIdArgs,
);

// 2. 创建输出类型代理 Lock
const outputTypeLock = await ccc.Script.fromKnownScript(
  signer.client,
  ccc.KnownScript.OutputTypeProxyLock,
  typeId.hash(),
);

// 3. 创建所有者 Cell
const lockTx = ccc.Transaction.from({
  outputs: [{ lock: outputTypeLock }],
});
await lockTx.completeInputsByCapacity(signer);
await lockTx.completeFeeBy(signer);
const lockTxHash = await signer.sendTransaction(lockTx);

// 4. 铸造代币
const mintTx = ccc.Transaction.from({
  inputs: [
    { previousOutput: typeIdCell.outPoint },
    { previousOutput: { txHash: lockTxHash, index: 0 } },
  ],
  outputs: [
    typeIdCell.cellOutput,
    {
      lock: script,
      type: await ccc.Script.fromKnownScript(
        signer.client,
        ccc.KnownScript.XUdt,
        outputTypeLock.hash(),
      ),
    },
  ],
});
```

### 转移代币 [#转移代币]

```typescript
import { udt } from "@ckb-ccc/udt";
import { ccc } from "@ckb-ccc/shell";

const myToken = new udt.Udt(
  {
    txHash: "0x4e2e832e0b1e7b5994681b621b00c1e65f577ee4b440ef95fa07db9bb3d50269",
    index: 0,
  },
  {
    codeHash: "0xcc9dc33ef234e14bc788c43a4848556a5fb16401a04662fc55db9bb201987037",
    hashType: "type",
    args: "0x71fd1985b2971a9903e4d8ed0d59e6710166985217ca0681437883837b86162f",
  },
);

const { script: toScript } = await ccc.Address.fromString(
  "ckb1qzda0cr08m85hc8jlnfp3gog...",
  signer.client,
);

// 构建转账交易
const { res: tx } = await myToken.transfer(signer, [
  { to: toScript, amount: 100n },
]);

// 平衡 UDT 找零与容量
const completedTx = await myToken.completeBy(tx, signer);
await completedTx.completeInputsByCapacity(signer);
await completedTx.completeFeeBy(signer);

const txHash = await signer.sendTransaction(completedTx);
```

### 读取代币元数据 [#读取代币元数据]

```typescript
const { res: name }     = await myToken.name();
const { res: symbol }   = await myToken.symbol();
const { res: decimals } = await myToken.decimals();

console.log(`${name} (${symbol}), ${decimals} 位小数`);
```

### 铸造代币 [#铸造代币]

```typescript
const { res: tx } = await myToken.mint(signer, [
  { to: recipientScript, amount: 1_000_000n },
]);

const completedTx = await myToken.completeBy(tx, signer);
await completedTx.completeInputsByCapacity(signer);
await completedTx.completeFeeBy(signer);

await signer.sendTransaction(completedTx);
```

<Callout type="tip">
  `@ckb-ccc/udt` 依赖 `@ckb-ccc/ssri`。`ssri.Executor` 为可选参数——不传时，`Udt` 类会回退到直接构造交易，不从链上查询 SSRI 元数据。
</Callout>


---

> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ckbccc.com/llms.txt
> Use this file to discover all available pages before exploring further.
