# viem ile mint etme

Damgalama süreci üzerinde ayrıntılı kontrolü tercih eden geliştiriciler için, saf TypeScript'i kullanabilirsiniz [viem](https://viem.sh/)EVM tabanlı projeler için bir TypeScript arayüzü.  [Ethers.js kütüphanesi](https://ethers.org/) de sağlam bir yaklaşımdır.

Şuraya geçmek *vanilya* thirdweb gibi çerçevelere güvenmek yerine biraz daha fazla iş yapmanızı gerektirir. Örneğin, kendi IPFS düğümünüzü çalıştırmadığınız sürece, ücretli olan NFT depolama platformlarına güvenmeniz gerekecektir.

{% hint style="success" %}
Bu örnek [Pinata](https://pinata.cloud/) ifadesini bir IPFS barındırıcısı olarak kullanır.\
Ayrıca bir [OpenZeppelin ERC-721 kontratı](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol) Chiliz Chain üzerine kendiniz dağıtmanız gerekir. [Remix IDE](https://remix.ethereum.org/) bunu tarayıcı içinde yapmanızı sağlar. Kontratı bir blok gezgini kullanarak doğrulamayı unutmayın!
{% endhint %}

Şimdi, kuralım `viem`, `Pinata SDK`, ve `dotenv` modülünü:

```bash
npm i viem pinata dotenv
```

İhtiyaçlarınıza uygun olacak şekilde `.env` dosyanızı yapılandırın:

```
# Cüzdan / sözleşme
PRIVATE_KEY=0xabc...                      # yalnızca sunucu tarafında
CONTRACT_ADDRESS=0xYourErc721Address
RECIPIENT=0xRecipientOrLeaveEmpty         # isteğe bağlı; varsayılan olarak basım yapan kişi

# Pinata
PINATA_JWT=eyJhbGciOi...                  # Pinata kontrol panelinden JWT
PINATA_GATEWAY=your-subdomain.mypinata.cloud

# Tekli basım
IMAGE_PATH=./art/image.png
NAME=My Chiliz NFT
DESCRIPTION=viem ile Chiliz üzerinde basıldı

# Toplu basım
IMAGES_DIR=./art
NAME_PREFIX=Benim Chiliz NFT'm
BATCH_DESCRIPTION=viem ile Chiliz üzerinde toplu olarak basıldı
```

Şimdi kodun içine dalalım.\
\&#xNAN;*Bundan ilham alın, aynen kullanmayın!*

## Tek bir NFT basma

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

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

import { createWalletClient, createPublicClient, http, parseEventLogs } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import type { Address } from 'viem';
import { chiliz, spicy } from 'viem/chains';
import { PinataSDK } from 'pinata';

// Minimal ABI: safeMint(to, uri) + tokenURI + Transfer
const abi = [
  { type: 'function', name: 'safeMint', stateMutability: 'nonpayable',
    inputs: [{ name: 'to', type: 'address' }, { name: 'uri', type: 'string' }], outputs: [] },
  { type: 'function', name: 'tokenURI', stateMutability: 'view',
    inputs: [{ name: 'tokenId', type: 'uint256' }], outputs: [{ type: 'string' }] },
  { type: 'event', name: 'Transfer',
    inputs: [
      { name: 'from', type: 'address', indexed: true },
      { name: 'to', type: 'address', indexed: true },
      { name: 'tokenId', type: 'uint256', indexed: true },
    ]},
] as const;

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() {
  // Ağınızı seçin: Chiliz testnet için `spicy` kullanın, Chiliz Chain Mainnet için `chiliz`e geçin.
  const chain = spicy; // Mainnet için `chiliz` olarak değiştirin

  const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
  const walletClient = createWalletClient({ account, chain, transport: http() });
  const publicClient = createPublicClient({ chain, transport: http() });

  const address = process.env.CONTRACT_ADDRESS as Address;
  const recipient = (process.env.RECIPIENT as Address) || account.address;

  // IPFS yüklemesi (Pinata)
  const pinata = new PinataSDK({
    pinataJwt: process.env.PINATA_JWT!,
    pinataGateway: process.env.PINATA_GATEWAY!,
  });

  const filePath = process.env.IMAGE_PATH!;
  const fileBlob = new Blob([fs.readFileSync(filePath)], { type: guessMime(filePath) });
  const fileObj = new File([fileBlob], path.basename(filePath), { type: guessMime(filePath) });

  const up = await pinata.upload.public.file(fileObj);
  const imageUri = `ipfs://${up.cid}`;

  const meta = await pinata.upload.public.json({
    name: process.env.NAME!,
    description: process.env.DESCRIPTION!,
    image: imageUri,
  });
  const metadataUri = `ipfs://${meta.cid}`;

  // viem aracılığıyla zincir üzerinde basım
  const txHash = await walletClient.writeContract({
    address,
    abi,
    functionName: 'safeMint',
    args: [recipient, metadataUri],
  });

  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });

  const ZERO = '0x0000000000000000000000000000000000000000';
  const logs = parseEventLogs({ abi, logs: receipt.logs, eventName: 'Transfer' });
  const mintLog = logs.find(l => (l.args as any).from?.toLowerCase?.() === ZERO);
  const tokenId = mintLog ? (mintLog.args as any).tokenId : undefined;

  console.log('tx:', txHash, '| tokenId:', tokenId ?? '(ayrıştırılamadı)', '| tokenURI:', metadataUri);
}

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

```

{% endcode %}

## NFT koleksiyonu basma

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

```typescript
import 'dotenv/config';
import fs from 'fs';
import path from 'path';
// import { Blob } from 'buffer'; // Node 18: Blob almak için bir sonraki satırın yorumunu kaldırın.

import { createWalletClient, createPublicClient, http, parseEventLogs } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import type { Address } from 'viem';
import { chiliz, spicy } from 'viem/chains';
import { PinataSDK } from 'pinata';

// Minimal ABI: safeMint(to, uri) + tokenURI + Transfer
const abi = [
  { type: 'function', name: 'safeMint', stateMutability: 'nonpayable',
    inputs: [{ name: 'to', type: 'address' }, { name: 'uri', type: 'string' }], outputs: [] },
  { type: 'function', name: 'tokenURI', stateMutability: 'view',
    inputs: [{ name: 'tokenId', type: 'uint256' }], outputs: [{ type: 'string' }] },
  { type: 'event', name: 'Transfer',
    inputs: [
      { name: 'from', type: 'address', indexed: true },
      { name: 'to', type: 'address', indexed: true },
      { name: 'tokenId', type: 'uint256', indexed: true },
    ]},
] as const;

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() {
  // Ağınızı seçin: Chiliz testnet için `spicy` kullanın, Mainnet için `chiliz`e geçin.
  const chain = spicy; // Mainnet için `chiliz` olarak değiştirin

  const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
  const walletClient = createWalletClient({ account, chain, transport: http() });
  const publicClient = createPublicClient({ chain, transport: http() });

  const address = process.env.CONTRACT_ADDRESS as Address;
  const recipient = (process.env.RECIPIENT as Address) || account.address;

  // IPFS yüklemesi (Pinata)
  const pinata = new PinataSDK({
    pinataJwt: process.env.PINATA_JWT!,
    pinataGateway: process.env.PINATA_GATEWAY!, // isteğe bağlı; ipfs:// URI'leri için gerekli değildir
  });

  const filePath = process.env.IMAGE_PATH!;
  const fileBlob = new Blob([fs.readFileSync(filePath)], { type: guessMime(filePath) });

  // Bir Blob'u doğrudan geçin
  const up = await pinata.upload.public.file(fileBlob);
  const imageUri = `ipfs://${up.cid}`;

  const meta = await pinata.upload.public.json({
    name: process.env.NAME!,
    description: process.env.DESCRIPTION!,
    image: imageUri,
  });
  const metadataUri = `ipfs://${meta.cid}`;

  // viem aracılığıyla zincir üzerinde basım
  const txHash = await walletClient.writeContract({
    address,
    abi,
    functionName: 'safeMint',
    args: [recipient, metadataUri],
  });

  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });

  const ZERO = '0x0000000000000000000000000000000000000000';
  const logs = parseEventLogs({ abi, logs: receipt.logs, eventName: 'Transfer' });
  const mintLog = logs.find(l => (l.args as any).from?.toLowerCase?.() === ZERO);
  const tokenId = mintLog ? (mintLog.args as any).tokenId : undefined;

  console.log('tx:', txHash, '| tokenId:', tokenId ?? '(ayrıştırılamadı)', '| tokenURI:', metadataUri);
}

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

```

{% endcode %}


---

# Agent Instructions: 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/tr-ai/develop/advanced/work-with-nfts/minting-with-viem.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.
