viem ile mintleme

Basım süreci üzerinde ayrıntılı kontrol isteyen geliştiriciler için, vanilla TypeScript'i kullanabilirsiniz viem, EVM tabanlı projeler için bir TypeScript arayüzü olan Ethers.js kütüphanesi 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.

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

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. Bundan ilham alın, olduğu gibi kullanmayın!

Tek bir NFT basımı

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)));

Bir NFT koleksiyonu mintleme

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)));

Last updated

Was this helpful?