> For the complete documentation index, see [llms.txt](https://docs.chiliz.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.chiliz.com/jp/kaihatsu/joukyu/nft/thirdweb-mint.md).

# thirdweb での mint

[thirdweb](https://thirdweb.com/) は、複数のブロックチェーンネットワーク上で分散型アプリケーションを構築するためのツールとインフラを提供するプラットフォームです。SDK、API、構築済みコンポーネントによってブロックチェーン連携をシンプルにします。

NFT の mint に関して、thirdweb は監査済みコントラクトと充実した SDK に加え、洗練されたダッシュボードと IPFS アップロードを提供します。

## 単一の NFT を手動で mint する

画像を 1 枚アップロードして mint したいだけであれば、thirdweb はクリックで deploy できるインターフェースを提供しています。

まず、自分の Web3 ウォレットを所有者として thirdweb アカウントを作成します。これにより thirdweb ダッシュボードにアクセスできるようになります。

そこから、2 つの方法を選べます。

* thirdweb の [TokenERC721](https://thirdweb.com/thirdweb.eth/TokenERC721) ページと、その「Deploy Now」ボタンを使う。
* または、ダッシュボードの「Create Token」インターフェースを使う。

このページでは、それぞれを手短に見ていきましょう。\
さらに情報が必要な場合は、[thirdweb Developer Portal](https://portal.thirdweb.com/) を参照してください。

### TokenERC721 ページを使う

1. [TokenERC721](https://thirdweb.com/thirdweb.eth/TokenERC721) ページにアクセスします。これは NFT コレクションを作成するための thirdweb のコントラクトを利用します。
2. 「Deploy Now」をクリックして、コントラクトの deploy ページにアクセスします。

<figure><img src="/files/XxgENon3HCoInaM9JmpE" alt=""><figcaption></figcaption></figure>

3. 「Contract metadata」セクションを入力します。
   1. NFT コレクションを表す画像 (または単に mint したい画像) をアップロードします。
   2. コレクションに固有の名前とシンボル/ティッカーを付けます。
   3. 説明を付けます。
4. thirdweb は「Primary Sales」と「Royalties」の受取アドレスを自動的に入力します。これらの Web3 アドレスが本当に自分のウォレットのものであることを必ず確認してください。
5. 「Deploy Options」で Chiliz Chain (テストの場合は Chiliz Spicy Testnet) を選び、「Deploy Now」をクリックします。

<figure><img src="/files/rBX69HbhR3zpngiQrg3b" alt=""><figcaption></figcaption></figure>

6. thirdweb がコントラクトの deploy を開始し、Web3 ウォレットの確認モーダルが表示されます。これを承認して deploy を完了します。\
   ![](/files/tVYmSGP2C48Joq2FbVZ9)
7. 完了したら「View Contract」ボタンをクリックします。チェックリスト/進捗バーが表示された、thirdweb ダッシュボード上のコントラクトページに移動します。\
   ![](/files/JILYtkfUoOXY4vxGHZCk)
8. チェックリストからわかるように、ここまででやったのはコントラクトの deploy だけで、実際に NFT を mint する作業はまだ残っています。左カラムの「NFTs」メニュー項目をクリックして新しいページを開くと、現時点では空です。\
   ![](/files/fruhgtTEjt4tqeQW5Mz5)
9. 「Mint」ボタンをクリックすると、NFT の各属性を入力するフィールドを備えたサイドパネルが開きます。ここで NFT の metadata を作成します。\
   ![](/files/VuA25LyCoBML50QoQYqF)
10. 各種フィールドを入力します。「Artist\_name」や「Type\_of\_work」のように NFT コレクション固有のフィールドを作成したり、高度なオプションを探索したりできますが、このテストでは name、media file、description という最小限にとどめてかまいません。
11. サイドパネル下部の「Mint NFT」ボタンをクリックし、ウォレットからトランザクションを承認します。\
    ![](/files/BSsVOxRe4l7eecAWqe7f)
12. すると thirdweb は「NFTs」ページを表示し、あなたの NFT が NFT コントラクトに紐づいて表示されるようになります。

完了です! NFT を mint できました!

本当に Chiliz Chain 上にあるか確認するには、[Chiliscan](https://www.chiliscan.com/) (Spicy Testnet を使っている場合は [そのテストネット版](https://testnet.chiliscan.com/)) を開き、NFT のハッシュを検索フィールドにコピー&ペーストします。コントラクトがチェーン上にあることがすぐに確認でき、「Inventory」タブにはあなた (または少なくともあなたのウォレット ID) を所有者とする NFT が一覧表示されるはずです。

<figure><img src="/files/hWXLbUDA9AGbZVX0LmWu" alt=""><figcaption></figcaption></figure>

NFT を Chiliz Chain Mainnet で mint した場合、[Rarible](https://rarible.com/) や [OKX](https://www.okx.com/) などのマーケットプレイスのアカウントに表示されるはずです。そこから販売を始められます!

### 「Create Token」ボタンを使う

これは実のところ上の方法よりも簡単で、thirdweb に最近追加されたものです。

1. thirdweb ダッシュボードの任意のプロジェクトフォルダから、左サイドバーの「Tokens」オプションをクリックします。\
   ![](/files/n7pK9dePuUBcd0TvRvDJ)
2. 開いた「Tokens」ページで、右側の「Create Token」ボタンをクリックします。2 つのオプションを備えたモーダルウィンドウが開くので、「Create NFT Collection」を選びます。\
   ![](/files/bGrQSy9viDoxXVXl2vNm)
3. これにより、[TokenERC721](https://thirdweb.com/thirdweb.eth/TokenERC721) の deploy ページのステップバイステップ版に移動します (実際には ERC-721 Drop コントラクトを deploy します)。このコントラクトに必要なすべてのフィールドを入力し、「Next」ボタンを押します。
4. 次の画面は NFT そのものについてです。画像をアップロードし、その画像を説明するフィールドを入力して、「Next」ボタンを押します。
5. thirdweb は、これからローンチしようとしている NFT コレクションのサマリーを表示します。すべて正しいことを確認し、「Launch NFT Collection」ボタンをクリックします。
6. thirdweb がコントラクトの deploy、NFT の mint、条件の設定を一括で行います。Web3 ウォレットを通じて 3 つのトランザクションを承認する必要があります。\
   ![](/files/oNhG0OmmTz2OiQe63SC4)
7. 完了したら「View NFT」ボタンをクリックすると、thirdweb ダッシュボードに戻り、このコントラクト固有のページ (および紐づく NFT) が表示されます。

そこから、ブロックエクスプローラーを通じて本当にチェーン上にあるか確認したり、マーケットプレイスを通じて NFT の販売を始めたりできます。

## 単一の NFT をプログラムで mint する

ここでは [thirdweb v5 SDK](https://portal.thirdweb.com/references/typescript/v5) を使ったコードサンプルを示します。これはメディアファイルを IPFS にアップロードし、`metadata.json` ファイルを生成して、それも IPFS にアップロードします。

これには以下が必要です。

* Chiliz Chain 上に deploy 済みの ERC-721 コントラクト。この場合は他のツールではなく thirdweb を使って行うべきです。
* thirdweb 経由で deploy した ERC-721 コントラクトに紐づく thirdweb API key。smart contract のプロジェクトページの「Client ID」という名前で見つけられます。
* ローカルにインストールされた thirdweb SDK。`npm` を使ってインストールできます。

```bash
npm install thirdweb dotenv
```

`dotenv` パラメーターは `.env` ファイルを生成します。これは秘密の値を保存するために必要です。

```
THIRDWEB_SECRET_KEY=YOUR_TW_SECRET_KEY # From your thirdweb project's page.
PRIVATE_KEY=0xabc...                   # The Web3 wallet that will send the transaction.
CONTRACT_ADDRESS=0xYour721Address      # Your deployed TokenERC721 contract.
CHAIN_ID=88882                         # 88888=Mainnet, 88882=Spicy
IMAGE_PATH=./art/image.png             # The local path to your media file.
NAME=My Chiliz NFT
DESCRIPTION=Minted on Chiliz Chain
```

{% hint style="danger" %}
`PRIVATE_KEY` や `THIRDWEB_SECRET_KEY` をクライアントサイドのコードに絶対に露出させないでください!\
このファイルは安全なサーバー/CI 上に保管し、公開リポジトリにアップロードしないでください。
{% endhint %}

これですべての準備が整ったので、以下のスクリプトを参考にできます。これは次のことを行います。

1. メディアファイルを IPFS にアップロードする
2. `metadata.json` ファイルを構築してアップロードする
3. コントラクトの mintTo メソッドを使って NFT を mint する。
4. 結果として得られる `tokenId` と `tokenUrl` を表示する。

{% hint style="success" %}
これはあくまでサンプルコードです。自分のプロジェクトのコードに合わせて調整する必要があります!
{% endhint %}

{% code overflow="wrap" lineNumbers="true" fullWidth="true" %}

```typescript
import 'dotenv/config';
import fs from 'fs';
import path from 'path';

import { createThirdwebClient, getContract, sendTransaction, waitForReceipt, parseEventLogs } from "thirdweb";
import { defineChain } from "thirdweb/chains";
import { privateKeyToAccount } from "thirdweb/wallets";
import { mintTo, transferEvent, getNFT } from "thirdweb/extensions/erc721";
import { upload } from "thirdweb/storage";

function guessMime(p: string) {
  const ext = path.extname(p).toLowerCase();
  if (ext === ".png") return "image/png";
  if (ext === ".jpg" || ext === ".jpeg") return "image/jpeg";
  if (ext === ".webp") return "image/webp";
  if (ext === ".gif") return "image/gif";
  if (ext === ".mp4") return "video/mp4";
  if (ext === ".webm") return "video/webm";
  return "application/octet-stream";
}

async function main() {
  const client = createThirdwebClient({ secretKey: process.env.THIRDWEB_SECRET_KEY! });
  const chain = defineChain(Number(process.env.CHAIN_ID)); // 88888 or 88882
  const account = privateKeyToAccount({ client, privateKey: process.env.PRIVATE_KEY! });

  const contract = getContract({
    client,
    chain,
    address: process.env.CONTRACT_ADDRESS as `0x${string}`,
  });

  // Upload media file to IPFS
  const filePath = process.env.IMAGE_PATH!;
  const buffer = fs.readFileSync(filePath);
  const file = new File([buffer], path.basename(filePath), { type: guessMime(filePath) });

  const [imageUri] = await upload({ client, files: [file] }); // returns ipfs://... 
  // console.log("imageUri:", imageUri);

  // Build & upload metadata.json referencing IPFS imageUri
  const metadata = {
    name: process.env.NAME!,
    description: process.env.DESCRIPTION!,
    image: imageUri
  };
  const metaBlob = new Blob([JSON.stringify(metadata, null, 2)], { type: "application/json" });
  const metaFile = new File([metaBlob], "metadata.json", { type: "application/json" });

  const [metadataUri] = await upload({ client, files: [metaFile] });
  // console.log("metadataUri:", metadataUri);

  // Prepare & send mintTo transaction using the metadata URI
  // mintTo accepts a string to use directly as tokenURI.
  const tx = mintTo({
    contract,
    to: account.address,
    nft: metadataUri, // The tokenURI
  });

  const { transactionHash } = await sendTransaction({ transaction: tx, account });
  //console.log("tx:", transactionHash);

  const receipt = await waitForReceipt({ client, chain, transactionHash });

  // Parse Transfer event to display tokenId
  const events = parseEventLogs({ logs: receipt.logs, events: [transferEvent()] });
  const minted = events.find(e => e.eventName === "Transfer" && e.args.from === "0x0000000000000000000000000000000000000000");
  const tokenId = minted ? (minted.args.tokenId as bigint) : undefined;
  //console.log("tokenId:", tokenId?.toString() ?? "(not found)");

  if (tokenId !== undefined) {
    const nft = await getNFT({ contract, tokenId });
    //console.log("tokenURI (read back):", nft.tokenURI);
  }
}

main().catch((err) => (console.error(err), process.exit(1)));
```

{% endcode %}

参考にすべき重要なポイントは次のとおりです。

* `upload` はファイル (および JSON) を IPFS に保存し、`ipfs://…` URI を返します。
* `mintTo` は `tokenURI` として直接使う文字列を受け取ります。
* 標準的な ERC-721 の `Transfer` イベントをパースして、mint された `tokenId` を読み取ります。

## NFT のコレクションをプログラムで mint する

NFT のコレクションを mint することは、単一の NFT を mint することとそれほど変わりません。最も顕著な違いは、`.env` ファイルが `IMAGE_PATH` で単一の画像を指すのではなく、`IMAGE_DIR` ですべての画像を含むフォルダを指すことです。

```dotenv
THIRDWEB_SECRET_KEY=YOUR_TW_SECRET_KEY # From your thirdweb project's page.
PRIVATE_KEY=0xabc...                   # The Web3 wallet that will send the transaction.
CONTRACT_ADDRESS=0xYour721Address      # Your deployed TokenERC721 contract.
CHAIN_ID=88882                         # 88888=Mainnet, 88882=Spicy
IMAGE_PATH=./art                       # The local path to your media files.
NAME_PREFIX=My Chiliz NFT              # This will become: "My Chiliz NFT <n>"
DESCRIPTION=Minted on Chiliz Chain
```

そのため、ここで示すサンプルコードはこれを考慮に入れています。

{% code overflow="wrap" lineNumbers="true" fullWidth="true" %}

```typescript
import 'dotenv/config';
import fs from 'fs';
import path from 'path';

import { createThirdwebClient, getContract, sendTransaction, waitForReceipt, parseEventLogs } from "thirdweb";
import { defineChain } from "thirdweb/chains";
import { privateKeyToAccount } from "thirdweb/wallets";
import { mintTo, transferEvent, getNFT } from "thirdweb/extensions/erc721";
import { upload } from "thirdweb/storage";

function guessMime(p: string) {
  const ext = path.extname(p).toLowerCase();
  if (ext === ".png") return "image/png";
  if (ext === ".jpg" || ext === ".jpeg") return "image/jpeg";
  if (ext === ".webp") return "image/webp";
  if (ext === ".gif") return "image/gif";
  if (ext === ".mp4") return "video/mp4";
  if (ext === ".webm") return "video/webm";
  return "application/octet-stream";
}

// One way to gather all files
function listMediaFiles(dir: string) {
  const allow = new Set([".png", ".jpg", ".jpeg", ".webp", ".gif", ".mp4", ".webm", ".svg"]);
  return fs
    .readdirSync(dir)
    .filter((f) => allow.has(path.extname(f).toLowerCase()))
    .map((f) => path.join(dir, f));
}

async function main() {
  const client = createThirdwebClient({ secretKey: process.env.THIRDWEB_SECRET_KEY! });
  const chain = defineChain(Number(process.env.CHAIN_ID)); // 88888 or 88882
  const account = privateKeyToAccount({ client, privateKey: process.env.PRIVATE_KEY! }); 

  const contract = getContract({
    client,
    chain,
    address: process.env.CONTRACT_ADDRESS as `0x${string}`,
  });

  // Upload media files in a folder to IPFS
  const dirPath = process.env.IMAGES_DIR!;
  const filePaths = listMediaFiles(dirPath);
  if (!filePaths.length) {
    throw new Error(`No media files found in ${dirPath}`);
  }

  const fileObjs = filePaths.map((p) => {
    const buffer = fs.readFileSync(p);
    return new File([buffer], path.basename(p), { type: guessMime(p) });
  });

  const imageUris = await upload({ client, files: fileObjs }); // returns ["ipfs://...", ...]
  //console.log("Uploaded images to IPFS:", imageUris.length, "files");

  // Build & upload each metadata.json referencing its imageUri
  // Uses NAME and DESCRIPTION envs; names become "<NAME> #<index>"
  const namePrefix = process.env.NAME!;
  const description = process.env.DESCRIPTION!;

  // Create an array of File objects for metadata JSONs
  const metaFiles = imageUris.map((imageUri, i) => {
    const metadata = {
      name: `${namePrefix} #${i + 1}`,
      description,
      image: imageUri
    };
    const metaBlob = new Blob([JSON.stringify(metadata, null, 2)], { type: "application/json" });
    return new File([metaBlob], `metadata-${i + 1}.json`, { type: "application/json" });
  });

  const metadataUris = await upload({ client, files: metaFiles }); // ["ipfs://.../metadata-1.json", ...]
  //console.log("Uploaded metadata files to IPFS:", metadataUris.length);

  // Prepare & send mintTo transactions using the metadata URIs (sequential)
  const ZERO = "0x0000000000000000000000000000000000000000";

  for (let i = 0; i < metadataUris.length; i++) {
    const metadataUri = metadataUris[i];

    const tx = mintTo({
      contract,
      to: account.address,
      nft: metadataUri, // The tokenURI
    });

    const { transactionHash } = await sendTransaction({ transaction: tx, account });
    console.log(`[${i + 1}/${metadataUris.length}] tx:`, transactionHash);

    const receipt = await waitForReceipt({ client, chain, transactionHash });

    // Parse Transfer event to get tokenId for this mint
    const events = parseEventLogs({ logs: receipt.logs, events: [transferEvent()] });
    const minted = events.find(
      (e) => e.eventName === "Transfer" && typeof e.args.from === "string" && e.args.from.toLowerCase() === ZERO
    );
    const tokenId = minted ? (minted.args.tokenId as bigint) : undefined;

    // console.log(`[${i + 1}/${metadataUris.length}] tokenId:`, tokenId?.toString() ?? "(not found)");
    if (tokenId !== undefined) {
      const nft = await getNFT({ contract, tokenId });
      // console.log(`[${i + 1}/${metadataUris.length}] tokenURI (read back):`, nft.tokenURI);
    }
  }
}

main().catch((err) => (console.error(err), process.exit(1)));

```

{% endcode %}

詳細な変更点は次のとおりです。

* `IMAGES_DIR` が `IMAGE_PATH` を置き換えます。
* 複数の入力を集めるために `listMediaFiles` を追加しました。
* 画像用と metadata 用に `upload` をバッチ化しました (順序は保持されます)。
* 各 `metadataUri` を `mintTo` するループを回し、それぞれの `Transfer` イベントをパースして `tokenId` を取得します。
* 名前は既存の `NAME`/`DESCRIPTION` を使って自動的に番号付けされます: `NAME #1`、`NAME #2`、…。

繰り返しになりますが、これは自分のコードの参考としてご利用ください。そのまま使わないでください!

注意: lazy minting を行いたい場合、thirdweb の ERC-721 コントラクトには [`lazyMint` メソッド](https://portal.thirdweb.com/references/typescript/v5/erc721/lazyMint) があります。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.chiliz.com/jp/kaihatsu/joukyu/nft/thirdweb-mint.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
