# 管理資產 (NFT)

本指南將全面介紹如何使用 OCAP Client 管理非同質化代幣 (NFT) 的整個生命週期，NFT 也稱為資產。您將學習如何從頭開始建立新資產、更新其屬性、建立資產工廠以進行標準化鑄造，以及從該工廠獲取新資產。


## 建立新資產

您可以使用 `createAsset` 方法在區塊鏈上建立一個獨特的獨立資產。每個資產都會被分配一個獨一無二的鏈上地址，該地址由其初始屬性衍生而來。

```javascript icon=logos:javascript
const { wallet } = getWallet(); // 使用者的錢包物件

async function createNewAsset() {
  try {
    const [hash, address] = await client.createAsset({
      moniker: 'My Unique Digital Artwork',
      data: {
        typeUrl: 'json',
        value: { 
          description: 'A one-of-a-kind piece created by Artist X.',
          imageUrl: 'https://example.com/path/to/image.png',
        },
      },
      readonly: true,
      transferrable: true,
      wallet: wallet,
    });

    console.log(`Asset creation transaction sent: ${hash}`);
    console.log(`New asset address: ${address}`);
    return address;
  } catch (error) {
    console.error('Error creating asset:', error);
  }
}

createNewAsset();
```

### 參數

<x-field-group>
  <x-field data-name="moniker" data-type="string" data-required="true" data-desc="資產的名稱。"></x-field>
  <x-field data-name="parent" data-type="string" data-default="''" data-required="false" data-desc="父資產的地址（如果有的話）。"></x-field>
  <x-field data-name="data" data-type="object" data-required="true" data-desc="資產的資料負載，必須包含 typeUrl 和 value。"></x-field>
  <x-field data-name="readonly" data-type="boolean" data-default="false" data-required="false" data-desc="若為 true，資產在建立後無法更新。"></x-field>
  <x-field data-name="transferrable" data-type="boolean" data-default="true" data-required="false" data-desc="若為 true，資產可以轉移到另一個帳戶。"></x-field>
  <x-field data-name="ttl" data-type="number" data-default="0" data-required="false" data-desc="資產首次消費後的存活時間（以秒為單位）。"></x-field>
  <x-field data-name="display" data-type="object" data-required="false" data-desc="包含資產顯示資訊的物件。"></x-field>
  <x-field data-name="endpoint" data-type="object" data-required="false" data-desc="包含資產端點詳細資訊的物件。"></x-field>
  <x-field data-name="tags" data-type="string[]" data-default="[]" data-required="false" data-desc="用於對資產進行分類的字串陣列。"></x-field>
  <x-field data-name="wallet" data-type="WalletObject" data-required="true" data-desc="資產初始擁有者的錢包物件。"></x-field>
  <x-field data-name="delegator" data-type="string" data-default="''" data-required="false" data-desc="透過委託授權此交易的帳戶地址。"></x-field>
</x-field-group>

### 返回值

一個 `Promise`，會解析為一個包含交易雜湊值和新資產鏈上地址的陣列。

<x-field data-name="response" data-type="Promise<[string, string]>" data-desc="[transactionHash, assetAddress]"></x-field>

---


## 更新現有資產

如果資產在建立時設定為 `readonly: false`，您可以使用 `updateAsset` 方法修改其 `moniker` 和 `data` 欄位。資產透過其唯一的地址來識別。

```javascript icon=logos:javascript
const { wallet } = getWallet(); // 使用者的錢包物件
const assetAddress = 'z362...'; // 要更新的資產地址

async function updateExistingAsset() {
  try {
    const hash = await client.updateAsset({
      address: assetAddress,
      moniker: 'My Updated Digital Artwork',
      data: {
        typeUrl: 'json',
        value: { 
          description: 'An updated description for my unique piece.',
          imageUrl: 'https://example.com/path/to/new_image.png',
        },
      },
      wallet: wallet,
    });

    console.log(`Asset update transaction sent: ${hash}`);
  } catch (error) {
    console.error('Error updating asset:', error);
  }
}

updateExistingAsset();
```

### 參數

<x-field-group>
  <x-field data-name="address" data-type="string" data-required="true" data-desc="要更新的資產的鏈上地址。"></x-field>
  <x-field data-name="moniker" data-type="string" data-required="true" data-desc="資產的新名稱。"></x-field>
  <x-field data-name="data" data-type="object" data-required="true" data-desc="資產更新後的資料負載。"></x-field>
  <x-field data-name="wallet" data-type="WalletObject" data-required="true" data-desc="目前資產擁有者的錢包物件。"></x-field>
</x-field-group>

### 返回值

一個 `Promise`，會解析為交易雜湊值。

<x-field data-name="response" data-type="Promise<string>" data-desc="transactionHash"></x-field>

---


## 建立資產工廠

資產工廠是建立多個相似資產的範本。它定義了鑄造新資產的結構、規則和邏輯，比單獨建立每個資產更有效率。這對於發行活動門票、證書或收藏品等使用場景非常理想。

```javascript icon=logos:javascript
const { wallet } = getWallet(); // 工廠擁有者的錢包

const factoryDefinition = {
  name: 'Conference Ticket Factory',
  description: 'Mints tickets for the 2024 Tech Conference.',
  limit: 1000, // 最多可鑄造 1000 張門票
  input: {
    // 定義鑄造資產所需的資料
    type: 'object',
    properties: {
      attendeeName: { type: 'string' },
      ticketType: { type: 'string', enum: ['General', 'VIP'] },
    },
  },
  output: {
    // 定義鑄造資產的結構
    moniker: 'Ticket for {{attendeeName}}',
    description: '{{ticketType}} admission for the 2024 Tech Conference.',
    transferrable: false, // 門票不可轉讓
  },
  hooks: [],
};

async function createFactory() {
  try {
    const [hash, factoryAddress] = await client.createAssetFactory({
      factory: factoryDefinition,
      wallet: wallet,
    });

    console.log(`Factory creation transaction sent: ${hash}`);
    console.log(`New factory address: ${factoryAddress}`);
  } catch (error) {
    console.error('Error creating asset factory:', error);
  }
}

createFactory();
```

### 參數

<x-field-group>
  <x-field data-name="factory" data-type="object" data-required="true" data-desc="一個定義工廠屬性和鑄造邏輯的物件。">
    <x-field data-name="name" data-type="string" data-required="true" data-desc="工廠的名稱。"></x-field>
    <x-field data-name="description" data-type="string" data-required="true" data-desc="工廠用途的描述。"></x-field>
    <x-field data-name="limit" data-type="number" data-default="0" data-required="false" data-desc="可從此工廠鑄造的資產最大數量。0 表示無限制。"></x-field>
    <x-field data-name="trustedIssuers" data-type="string[]" data-required="false" data-desc="授權從此工廠鑄造的帳戶地址列表。"></x-field>
    <x-field data-name="input" data-type="object" data-required="true" data-desc="定義鑄造資產所需的輸入資料。"></x-field>
    <x-field data-name="output" data-type="object" data-required="true" data-desc="定義將被鑄造的資產的結構和屬性。"></x-field>
    <x-field data-name="hooks" data-type="object[]" data-required="false" data-desc="在鑄造過程中執行的掛鉤列表。"></x-field>
    <x-field data-name="data" data-type="object" data-required="false" data-desc="與工廠一起儲存的額外任意資料。"></x-field>
  </x-field>
  <x-field data-name="wallet" data-type="WalletObject" data-required="true" data-desc="工廠擁有者的錢包物件。"></x-field>
</x-field-group>

### 返回值

一個 `Promise`，會解析為一個包含交易雜湊值和新工廠鏈上地址的陣列。

<x-field data-name="response" data-type="Promise<[string, string]>" data-desc="[transactionHash, factoryAddress]"></x-field>

---


## 從工廠獲取資產

從工廠獲取資產是一個兩步驟的過程。首先，您需要準備鑄造資料，這讓您可以預覽將要建立的資產。其次，您將交易提交到區塊鏈以正式獲取資產。

這種分離很有用，因為它允許應用程式在使用者簽署並提交最終交易之前，向使用者展示他們將要收到的內容。

### 步驟 1：準備資產資料

`preMintAsset` 方法會接收工廠地址和使用者提供的輸入，以產生最終的資產資料。此過程在鏈下發生，不需要交易。

```javascript icon=logos:javascript
const factoryAddress = 'z2...'; // 先前建立的工廠地址
const { wallet: issuerWallet } = getIssuerWallet(); // 工廠擁有者或受信任的發行者
const { wallet: userWallet } = getUserWallet(); // 將擁有新資產的使用者

async function prepareAssetForMinting() {
  try {
    const mintingData = await client.preMintAsset({
      factory: factoryAddress,
      inputs: {
        attendeeName: 'John Doe',
        ticketType: 'VIP',
      },
      owner: userWallet.address,
      wallet: issuerWallet,
    });

    console.log('Prepared asset data for minting:', mintingData);
    return mintingData;
  } catch (error) {
    console.error('Error preparing asset:', error);
  }
}
```

### 步驟 2：發送交易

一旦鑄造資料準備好，使用者（未來的資產擁有者）簽署並發送 `acquireAsset` 交易。來自 `preMintAsset` 的 `itx` 物件將用作負載。

```javascript icon=logos:javascript
async function acquireNewAsset() {
  // 首先，從步驟 1 獲取鑄造資料
  const itx = await prepareAssetForMinting();
  if (!itx) return;

  try {
    const hash = await client.acquireAsset({
      itx: itx,
      wallet: userWallet, // 使用者的錢包簽署交易
    });

    console.log(`Asset acquisition transaction sent: ${hash}`);
    console.log(`New asset will be available at address: ${itx.address}`);
  } catch (error) {
    console.error('Error acquiring asset:', error);
  }
}

acquireNewAsset();
```

### `acquireAsset` 的參數

<x-field-group>
  <x-field data-name="itx" data-type="object" data-required="true" data-desc="從 `preMintAsset` 方法返回的內部交易物件。"></x-field>
  <x-field data-name="wallet" data-type="WalletObject" data-required="true" data-desc="正在獲取資產的使用者的錢包。"></x-field>
  <x-field data-name="delegator" data-type="string" data-default="''" data-required="false" data-desc="透過委託授權此交易的帳戶地址。"></x-field>
</x-field-group>

### 返回值

一個 `Promise`，會解析為 `acquireAsset` 操作的交易雜湊值。

<x-field data-name="response" data-type="Promise<string>" data-desc="transactionHash"></x-field>

---


## 從工廠鑄造資產

除了由使用者主導的 `acquireAsset` 流程外，授權的發行者（如工廠擁有者或受信任的發行者）也可以鑄造資產並將其直接發送到使用者的帳戶。此過程同樣使用 `preMintAsset` 來準備資料，但最終的交易是 `mintAsset`，由發行者簽署。

此流程適用於空投、頒發證書或任何接收使用者無需發起最終交易的情況。

### 步驟 1：準備資產資料

此步驟與獲取流程相同。發行者呼叫 `preMintAsset` 在鏈下產生交易負載（`itx`）。

```javascript icon=logos:javascript
const factoryAddress = 'z2...'; // 工廠地址
const { wallet: issuerWallet } = getIssuerWallet(); // 工廠擁有者或受信任的發行者
const userAddress = 'z1...'; // 將接收資產的使用者地址

async function prepareAssetForMinting() {
  try {
    const mintingData = await client.preMintAsset({
      factory: factoryAddress,
      inputs: {
        attendeeName: 'Jane Smith',
        ticketType: 'General',
      },
      owner: userAddress,
      wallet: issuerWallet, // 此處使用發行者的錢包
    });

    console.log('Prepared asset data for minting:', mintingData);
    return mintingData;
  } catch (error) {
    console.error('Error preparing asset:', error);
  }
}
```

### 步驟 2：發送鑄造交易

發行者使用準備好的 `itx` 物件呼叫 `mintAsset`。交易由發行者的錢包簽署，新建立的資產將分配給上一步驟中指定的所有者。

```javascript icon=logos:javascript
async function mintNewAsset() {
  // 首先，從步驟 1 獲取鑄造資料
  const itx = await prepareAssetForMinting();
  if (!itx) return;

  try {
    // 發行者的錢包簽署交易
    const hash = await client.mintAsset({
      itx: itx,
      wallet: issuerWallet,
    });

    console.log(`Asset minting transaction sent: ${hash}`);
    console.log(`New asset for ${userAddress} will be available at address: ${itx.address}`);
  } catch (error) {
    console.error('Error minting asset:', error);
  }
}

mintNewAsset();
```

### `mintAsset` 的參數

<x-field-group>
  <x-field data-name="itx" data-type="object" data-required="true" data-desc="從 `preMintAsset` 方法返回的內部交易物件。"></x-field>
  <x-field data-name="wallet" data-type="WalletObject" data-required="true" data-desc="正在鑄造資產的發行者的錢包。"></x-field>
</x-field-group>

### 返回值

一個 `Promise`，會解析為 `mintAsset` 操作的交易雜湊值。

<x-field data-name="response" data-type="Promise<string>" data-desc="transactionHash"></x-field>
