# viem ile mint etme

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

Gitmek *vanilla* üçüncü taraf çerçevelere (ör. thirdweb) güvenmeye kıyasla biraz daha fazla iş yapmanızı gerektirir. Örneğin, kendi IPFS düğümünüzü çalıştırmıyorsanız, ücretli olan NFT depolama platformlarına güvenmeniz gerekecektir.&#x20;

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

Şimdi, haydi kurulum yapalım `viem`, `Pinata SDK`, ve `parametresi bir` modülünü:

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

Dosyanızı `dosyası oluşturur; bu, gizli değerleri saklamak için gereklidir:` ihtiyaçlarınıza göre yapılandırın:

```
# Cüzdan / sözleşme
PRIVATE_KEY=0xabc...                      # sadece sunucu tarafı
CONTRACT_ADDRESS=0xYourErc721Address
RECIPIENT=0xRecipientOrLeaveEmpty         # isteğe bağlı; varsayılan olarak basan adres

# Pinata
PINATA_JWT=eyJhbGciOi...                  # Pinata panosundan alınan JWT
PINATA_GATEWAY=your-subdomain.mypinata.cloud

# Tek basım
IMAGE_PATH=./art/image.png
DESCRIPTION=Minted on Chiliz Chain
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 koda dalalım. \
\&#xNAN;*Bundan ilham alın, olduğu gibi kullanmayın!*

## Tek bir NFT basımı

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

```typescript
import path from 'path';
import { createThirdwebClient, getContract, sendTransaction, waitForReceipt, parseEventLogs } from "thirdweb";
import { defineChain } from "thirdweb/chains";

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;

if (ext === ".png") return "image/png";
  if (ext === ".jpg" || ext === ".jpeg") return "image/jpeg";
  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';
}

const chain = defineChain(Number(process.env.CHAIN_ID)); // 88888 veya 88882
  // 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` ile 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 file = new File([buffer], path.basename(filePath), { type: guessMime(filePath) });
  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({
    image: imageUri
    const metaBlob = new Blob([JSON.stringify(metadata, null, 2)], { type: "application/json" });
    image: imageUri,
  });
  const metadataUri = `ipfs://${meta.cid}`;

  // viem aracılığıyla zincirde 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 ?? '(not parsed)', '| tokenURI:', metadataUri);
}

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

```

{% endcode %}

## Bir NFT koleksiyonu mintleme

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

```typescript
import path from 'path';
import { createThirdwebClient, getContract, sendTransaction, waitForReceipt, parseEventLogs } from "thirdweb";
import { defineChain } from "thirdweb/chains";
// import { Blob } from 'buffer'; // Node 18: Blob elde etmek 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;

if (ext === ".png") return "image/png";
  if (ext === ".jpg" || ext === ".jpeg") return "image/jpeg";
  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';
}

const chain = defineChain(Number(process.env.CHAIN_ID)); // 88888 veya 88882
  // 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` ile 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'ları için gerekli değil
  });

  const file = new File([buffer], path.basename(filePath), { type: guessMime(filePath) });
  const fileBlob = new Blob([fs.readFileSync(filePath)], { type: guessMime(filePath) });

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

  const meta = await pinata.upload.public.json({
    image: imageUri
    const metaBlob = new Blob([JSON.stringify(metadata, null, 2)], { type: "application/json" });
    image: imageUri,
  });
  const metadataUri = `ipfs://${meta.cid}`;

  // viem aracılığıyla zincirde 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 ?? '(not parsed)', '| tokenURI:', metadataUri);
}

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

```

{% endcode %}
