# 转移通证和 NFT

本指南将逐步引导您使用 OCAP Client 在账户之间转移可替代通证（包括原生通证和自定义通证）和非替代通证（NFT 或资产）。所有转移操作的主要方法是 `client.transfer()`。

需要记住的一个关键特性是，当新账户首次接收到入账交易时，它会自动在链上创建。这意味着您可以将通证或资产转移到一个全新的地址，而无需接收方进行任何预先设置。


## `transfer` 方法

`client.transfer()` 方法是一个多功能的辅助函数，可简化发送资产和通证的过程。它通过一次调用即可构建、签署相应的交易（`transferV2Tx`）并将其发送到区块链。

### 参数

<x-field-group>
  <x-field data-name="to" data-type="string" data-required="true">
    <x-field-desc markdown>接收方的账户地址。必须是有效的 DID 地址。</x-field-desc>
  </x-field>
  <x-field data-name="wallet" data-type="WalletObject" data-required="true" data-desc="用于签署交易的发送方钱包对象。"></x-field>
  <x-field data-name="token" data-type="number" data-default="0">
    <x-field-desc markdown>要转移的链上原生通证的数量。客户端会自动处理到正确小数单位的转换。</x-field-desc>
  </x-field>
  <x-field data-name="assets" data-type="string[]" data-default="[]" data-desc="要转移的资产地址（NFT）数组。"></x-field>
  <x-field data-name="tokens" data-type="object[]" data-default="[]">
    <x-field-desc markdown>要转移的自定义可替代通证对象数组。</x-field-desc>
    <x-field data-name="address" data-type="string" data-required="true" data-desc="自定义通证合约的地址。"></x-field>
    <x-field data-name="value" data-type="number" data-required="true" data-desc="要转移的自定义通证的数量。"></x-field>
  </x-field>
  <x-field data-name="memo" data-type="string" data-required="false" data-desc="交易中包含的可选消息或备注。"></x-field>
  <x-field data-name="delegator" data-type="string" data-required="false">
    <x-field-desc markdown>如果 `wallet` 代表另一个账户操作，此处应为委托账户的地址。更多详情请参阅[委托权限](./how-to-guides-delegate-permissions.md)指南。</x-field-desc>
  </x-field>
</x-field-group>

### 返回值

<x-field data-name="Promise<string>" data-type="Promise">
  <x-field-desc markdown>一个 Promise，在成功提交到区块链后会解析为交易哈希值。</x-field-desc>
</x-field>


## 分步示例

### 前提条件

在开始之前，请确保您已具备：

1. 一个已初始化的 `GraphQLClient`，已连接到链主机，例如 `https://beta.abtnetwork.io`。
2. 一个发送方的钱包对象 (`senderWallet`)，其中存有足够的通证以支付转账和交易费用。
3. 一个接收方的钱包对象 (`recipientWallet`)，用于获取其地址。接收方的账户此时无需已在链上存在。

```javascript Basic Setup icon=logos:javascript
import GraphQLClient from '@ocap/client';
import { fromRandom } from '@ocap/wallet';

// 1. 初始化客户端
const client = new GraphQLClient({ endpoint: 'https://beta.abtnetwork.io/api' });

// 2. 为发送方和接收方创建钱包
// 在实际应用中，发送方的钱包应为加载而非随机创建。
const senderWallet = fromRandom(); // 假设此钱包已有资金
const recipientWallet = fromRandom();

console.log(`Sender Address: ${senderWallet.address}`);
console.log(`Recipient Address: ${recipientWallet.address}`);

// 如需为本示例中的发送方钱包充值，请使用水龙头：
// https://faucet.abtnetwork.io/
```

### 示例 1：转移原生通证

此示例展示了如何从发送方发送 10 个原生通证给接收方。

```javascript Transfer Native Tokens icon=logos:javascript
async function transferNativeTokens() {
  try {
    const hash = await client.transfer({
      to: recipientWallet.address,
      token: 10, // 要发送的原生通证数量
      wallet: senderWallet,
      memo: 'Sending you 10 native tokens!'
    });
    console.log('Native token transfer successful. Tx Hash:', hash);
  } catch (err) {
    console.error('Error transferring tokens:', err);
  }
}

transferNativeTokens();
```

### 示例 2：转移 NFT（资产）

要转移 NFT，您需要其唯一的资产地址。首先，您需要创建或获取一个资产（请参阅[管理资产 (NFT)](./how-to-guides-manage-assets.md)）。在本示例中，我们假设 `senderWallet` 已拥有一个地址为 `zNKj...` 的 NFT。

```javascript Transfer an NFT icon=logos:javascript
async function transferNFT() {
  // 假设这是 senderWallet 拥有的一个 NFT 的地址
  const nftAddress = 'zNKjL4wTmxQPk5nN2ADDPCd58286b2de3f3e';

  try {
    const hash = await client.transfer({
      to: recipientWallet.address,
      assets: [nftAddress], // 资产地址数组
      wallet: senderWallet,
      memo: 'Here is the NFT you wanted.'
    });
    console.log('NFT transfer successful. Tx Hash:', hash);
  } catch (err) {
    console.error('Error transferring NFT:', err);
  }
}

transferNFT();
```

### 示例 3：转移自定义通证

此示例演示了如何转移自定义可替代通证。您需要该通证的合约地址。有关创建自定义通证的信息，请参阅[管理通证](./how-to-guides-manage-tokens.md)指南。

```javascript Transfer Custom Tokens icon=logos:javascript
async function transferCustomToken() {
  // 假设这是 senderWallet 拥有的一个自定义通证的地址
  const customTokenAddress = 'z37bA4x...'; 

  try {
    const hash = await client.transfer({
      to: recipientWallet.address,
      wallet: senderWallet,
      tokens: [
        { address: customTokenAddress, value: 50 } // 50 单位的自定义通证
      ],
      memo: 'Sending 50 custom tokens.'
    });
    console.log('Custom token transfer successful. Tx Hash:', hash);
  } catch (err) {
    console.error('Error transferring custom token:', err);
  }
}

transferCustomToken();
```

### 示例 4：组合转移

您可以将原生通证、自定义通证和多个 NFT 在一次原子交易中全部发送。这种方式非常高效。

```javascript Combined Transfer icon=logos:javascript
async function combinedTransfer() {
  // 假设这些是 senderWallet 拥有的资产和通证的地址
  const nftAddress1 = 'zNKjL4wTmxQPk5nN2ADDPCd58286b2de3f3e';
  const nftAddress2 = 'zNKiabcdeQPk5nN2ADDPCd58286b2defghj';
  const customTokenAddress = 'z37bA4x...'; // 自定义可替代通证的地址

  try {
    const hash = await client.transfer({
      to: recipientWallet.address,
      wallet: senderWallet,
      token: 5, // 5 个原生通证
      assets: [nftAddress1, nftAddress2], // 包含两个 NFT 的数组
      tokens: [
        { address: customTokenAddress, value: 50 } // 50 单位的自定义通证
      ],
      memo: 'Sending a mix of tokens and NFTs.'
    });
    console.log('Combined transfer successful. Tx Hash:', hash);
  } catch (err) {
    console.error('Error with combined transfer:', err);
  }
}

combinedTransfer();
```

通过遵循这些示例，您可以轻松地在您的应用程序中实现通证和 NFT 的转移。有关创建您希望转移的项目的更多详细信息，请参阅相关指南。

### 延伸阅读

* [如何管理资产 (NFT)](./how-to-guides-manage-assets.md)
* [如何管理通证](./how-to-guides-manage-tokens.md)
* [高级 API](./api-reference-transaction-helpers.md)
