Tinjauan Umum

Minting adalah proses pembuatan token NFT baru dalam koleksi Anda. CreateKit menyediakan sistem minting dua fase yang unik yang mengoptimalkan efisiensi gas dan pengalaman pengguna.

Fase Minting

Fase 1: Penyebaran & Mint Pertama

Operasi mint pertama adalah spesial - ia men-deploy kontrak koleksi dan mencetak token pertama dalam satu transaksi:
Deploy dan Mint Pertama
import { CollectionManager } from '@b3dotfun/basemint'

const collectionManager = new CollectionManager(publicClient)

// Asumsikan kita memiliki metadata koleksi dan tanda tangan pembuat
const predictedAddress = collectionManager.predictCollectionAddress(
  collectionMetadata,
  creatorSignature
)

// Hasilkan tanda tangan deployer
const deployerSignature = await collectionManager.generateDeployerSignature(
  walletClient,
  predictedAddress
)

// Buat instance koleksi
const collection = collectionManager.createCollection(
  predictedAddress,
  collectionMetadata.tokenStandard
)

// Deploy dan mint NFT pertama
const mintTx = await collection.mint(
  walletClient,
  1n, // kuantitas
  undefined, // URI metadata (menggunakan baseURI)
  collectionMetadata.mintPrice || 0n,
  [], // bukti whitelist (kosong untuk umum)
  creatorSignature, // Diperlukan untuk mint pertama
  deployerSignature // Diperlukan untuk mint pertama
)

console.log(`🚀 Koleksi dideploy dan token pertama dicetak: ${mintTx}`)

Fase 2: Minting Reguler

Setelah penyebaran, minting berikutnya lebih sederhana dan hanya memerlukan parameter standar:
Minting Reguler
// Untuk minting berikutnya (setelah penyebaran)
const regularMintTx = await collection.mint(
  walletClient,
  1n, // kuantitas
  undefined, // URI metadata
  collectionMetadata.mintPrice || 0n,
  [] // bukti whitelist
  // Tidak perlu tanda tangan untuk minting reguler
)

console.log(`✨ Token dicetak: ${regularMintTx}`)

Standar Token

CreateKit mendukung standar ERC721 dan ERC1155 dengan perilaku minting yang berbeda:
Token Unik ERC721
// ERC721 - Setiap token adalah unik
const erc721Collection = collectionManager.createCollection(
  predictedAddress,
  "ERC721"
)

// ERC721 selalu mencetak kuantitas 1
await erc721Collection.mint(
  walletClient,
  1n, // Selalu 1 untuk ERC721
  "https://example.com/metadata/1.json", // Metadata unik untuk token ini
  parseEther("0.01"),
  []
)

// Setiap minting menciptakan ID token unik baru
// ID Token bertambah: 1, 2, 3, dll.

Penetapan Harga dan Pembayaran

Harga Tetap

Minting Harga Tetap
import { parseEther } from 'viem'

const fixedPriceCollection = {
  name: "Koleksi Harga Tetap",
  symbol: "FPC",
  creator: account.address,
  gameOwner: account.address,
  mintPrice: parseEther("0.01"), // 0.01 ETH per token
  maxPerWallet: 5n
}

// Mint dengan harga tetap
await collection.mint(
  walletClient,
  2n, // kuantitas
  undefined,
  parseEther("0.02"), // 2 * 0.01 ETH
  []
)

Minting Gratis

Minting Gratis
const freeCollection = {
  name: "Koleksi Gratis",
  symbol: "FREE",
  creator: account.address,
  gameOwner: account.address,
  mintPrice: 0n, // Minting gratis
  maxPerWallet: 10n
}

// Mint secara gratis (hanya biaya gas)
await collection.mint(
  walletClient,
  1n,
  undefined,
  0n, // Tidak memerlukan pembayaran
  []
)

Penetapan Harga Dinamis

Logika Penetapan Harga Dinamis
// Logika penetapan harga kustom di aplikasi Anda
function calculateMintPrice(totalSupply: bigint, basePrice: bigint): bigint {
  // Harga meningkat dengan pasokan
  const priceMultiplier = totalSupply / 1000n + 1n
  return basePrice * priceMultiplier
}

// Dapatkan pasokan saat ini dan hitung harga
const currentSupply = await collection.totalSupply()
const dynamicPrice = calculateMintPrice(currentSupply, parseEther("0.001"))

await collection.mint(
  walletClient,
  1n,
  undefined,
  dynamicPrice,
  []
)

Minting Whitelist

CreateKit mendukung whitelisting berbasis pohon Merkle untuk minting eksklusif:

Pengaturan Whitelist

Pengaturan Whitelist
import { WhitelistManager } from '@b3dotfun/basemint'

// Buat whitelist dengan alamat
const whitelist = new WhitelistManager([
  { address: "0x1234567890123456789012345678901234567890" },
  { address: "0x2345678901234567890123456789012345678901" },
  { address: "0x3456789012345678901234567890123456789012" }
])

// Dapatkan akar merkle untuk penyebaran koleksi
const merkleRoot = whitelist.getRoot()

const whitelistCollection = {
  name: "Koleksi Whitelist",
  symbol: "WLC",
  creator: account.address,
  gameOwner: account.address,
  isWhitelistEnabled: true,
  whitelistMerkleRoot: merkleRoot,
  mintPrice: parseEther("0.005")
}

Minting dengan Bukti Whitelist

Minting dengan Bukti Whitelist
// Dapatkan bukti untuk alamat minting
const userAddress = account.address
const proof = whitelist.getProof(userAddress)

// Verifikasi pengguna ada di whitelist (pemeriksaan opsional)
const isWhitelisted = whitelist.verify(userAddress, proof)
if (!isWhitelisted) {
  throw new Error("Alamat tidak dalam whitelist")
}

// Mint dengan bukti whitelist
await collection.mint(
  walletClient,
  1n,
  undefined,
  parseEther("0.005"),
  proof // Sediakan bukti whitelist
)

Batasan dan Kontrol Minting

Batas Per-Wallet

Batas Wallet
// Tetapkan token maksimum per wallet
const limitedCollection = {
  name: "Koleksi Terbatas",
  symbol: "LTD",
  creator: account.address,
  gameOwner: account.address,
  maxPerWallet: 3n, // Maksimum 3 token per wallet
  maxSupply: 1000n
}

// Periksa saldo saat ini sebelum minting
const currentBalance = await collection.balanceOf(account.address)
const maxPerWallet = await collection.maxPerWallet()

if (currentBalance >= maxPerWallet) {
  throw new Error("Batas wallet terlampaui")
}

await collection.mint(walletClient, 1n, undefined, 0n, [])

Kontrol Berbasis Waktu

Kontrol Waktu
const timedCollection = {
  name: "Rilis Berbasis Waktu",
  symbol: "TIME",
  creator: account.address,
  gameOwner: account.address,
  startTime: BigInt(Math.floor(Date.now() / 1000) + 3600), // Mulai dalam 1 jam
  endTime: BigInt(Math.floor(Date.now() / 1000) + 86400), // Berakhir dalam 24 jam
}

// Periksa apakah minting saat ini aktif
const currentTime = BigInt(Math.floor(Date.now() / 1000))
const startTime = await collection.startTime()
const endTime = await collection.endTime()

const isMintingActive = currentTime >= startTime && currentTime <= endTime

if (!isMintingActive) {
  throw new Error("Minting saat ini tidak aktif")
}

Penanganan Metadata

Metadata Otomatis

CreateKit dapat secara otomatis menghasilkan metadata berdasarkan pengaturan koleksi:
Metadata Otomatis
// Menggunakan baseURI untuk metadata otomatis
const autoMetadataCollection = {
  name: "Koleksi Metadata Otomatis",
  symbol: "AMC",
  creator: account.address,
  gameOwner: account.address,
  // baseURI akan dihasilkan secara otomatis oleh CDN BaseMint
}

// Mint dengan metadata otomatis (gunakan undefined untuk URI)
await collection.mint(
  walletClient,
  1n,
  undefined, // Menggunakan baseURI + tokenId
  0n,
  []
)

// Metadata akan tersedia di: {baseURI}/{tokenId}

Metadata Kustom

URI Metadata Kustom
// Sediakan URI metadata spesifik untuk setiap token
const customMetadataURIs = [
  "https://myapi.com/metadata/special-sword.json",
  "https://myapi.com/metadata/rare-shield.json",
  "https://myapi.com/metadata/epic-helmet.json"
]

for (const metadataURI of customMetadataURIs) {
  await collection.mint(
    walletClient,
    1n,
    metadataURI, // Metadata kustom untuk token ini
    parseEther("0.01"),
    []
  )
}

Minting Batch

Untuk koleksi ERC1155, Anda dapat mencetak beberapa token secara efisien:
Minting Batch
// Satu transaksi, beberapa token
await erc1155Collection.mint(
  walletClient,
  10n, // Mencetak 10 token dari jenis yang sama
  "https://example.com/metadata/resource.json",
  parseEther("0.001") * 10n, // Harga total untuk semua token
  []
)

// Untuk jenis token yang berbeda, gunakan transaksi terpisah
const tokenTypes = [
  { uri: "https://example.com/wood.json", quantity: 5n },
  { uri: "https://example.com/stone.json", quantity: 3n },
  { uri: "https://example.com/gold.json", quantity: 1n }
]

for (const tokenType of tokenTypes) {
  await erc1155Collection.mint(
    walletClient,
    tokenType.quantity,
    tokenType.uri,
    calculatePrice(tokenType.quantity),
    []
  )
}

Penanganan Kesalahan

Penanganan Kesalahan Komprehensif
async function safeMint(
  collection: any,
  walletClient: any,
  quantity: bigint,
  metadataURI: string | undefined,
  mintPrice: bigint,
  proof: string[]
) {
  try {
    // Validasi pra-mint
    const isDeployed = await collection.isDeployed()
    if (!isDeployed) {
      throw new Error("Koleksi belum dideploy")
    }

    const currentSupply = await collection.totalSupply()
    const maxSupply = await collection.maxSupply()
    if (currentSupply + quantity > maxSupply) {
      throw new Error("Akan melebihi pasokan maksimum")
    }

    const userBalance = await collection.balanceOf(walletClient.account.address)
    const maxPerWallet = await collection.maxPerWallet()
    if (userBalance + quantity > maxPerWallet) {
      throw new Error("Akan melebihi batas wallet")
    }

    // Periksa jumlah pembayaran
    const requiredPayment = await collection.mintPrice() * quantity
    if (mintPrice < requiredPayment) {
      throw new Error("Pembayaran tidak cukup")
    }

    // Coba mint
    const tx = await collection.mint(
      walletClient,
      quantity,
      metadataURI,
      mintPrice,
      proof
    )

    console.log(`✅ Mint berhasil: ${tx}`)
    return tx

  } catch (error: any) {
    if (error.message.includes('Invalid merkle proof')) {
      console.error('❌ Alamat tidak dalam whitelist')
    } else if (error.message.includes('Insufficient payment')) {
      console.error('❌ Harga mint salah')
    } else if (error.message.includes('Max per wallet exceeded')) {
      console.error('❌ Batas wallet tercapai')
    } else {
      console.error('❌ Mint gagal:', error.message)
    }
    throw error
  }
}

Optimasi Gas

Pola Minting Efisien

Minting Efisien Gas
// Untuk ERC1155: Mencetak beberapa token dalam satu transaksi
await erc1155Collection.mint(
  walletClient,
  10n, // Lebih efisien gas daripada 10 transaksi terpisah
  metadataURI,
  totalPrice,
  proof
)

// Untuk ERC721: Pertimbangkan operasi batch di tingkat aplikasi
const mintPromises = []
for (let i = 0; i < 5; i++) {
  mintPromises.push(
    collection.mint(walletClient, 1n, undefined, mintPrice, proof)
  )
}

// Eksekusi mint secara bersamaan (hati-hati dengan pengelolaan nonce)
const results = await Promise.all(mintPromises)

Manajemen Harga Gas

Optimasi Harga Gas
import { createWalletClient, http } from 'viem'

// Konfigurasi gas kustom
const optimizedWalletClient = createWalletClient({
  chain: b3Testnet,
  transport: http(),
  account,
  // Konfigurasi gas
  gasPrice: parseGwei('20'), // Harga gas kustom
})

// Atau gunakan penetapan harga gas dinamis
const gasPrice = await publicClient.getGasPrice()
const adjustedGasPrice = gasPrice * 110n / 100n // 10% di atas harga saat ini

await collection.mint(
  optimizedWalletClient,
  1n,
  undefined,
  mintPrice,
  proof,
  {
    gasPrice: adjustedGasPrice
  }
)

Monitoring dan Analitik

Pelacakan Event Mint

Monitoring Event
import { getCollectionMintEvents } from '@b3dotfun/basemint'

// Lacak event mint
const fromBlock = await publicClient.getBlockNumber() - 1000n
const toBlock = await publicClient.getBlockNumber()

const mintEvents = await getCollectionMintEvents(
  publicClient,
  collection.address,
  "ERC721",
  fromBlock,
  toBlock
)

console.log("Mint terbaru:", mintEvents.map(event => ({
  minter: event.args.minter,
  tokenId: event.args.tokenId?.toString(),
  quantity: event.args.quantity?.toString(),
  blockNumber: event.blockNumber
})))

Monitoring Real-time

Monitoring Mint Real-time
// Pantau event mint baru
const unwatch = publicClient.watchContractEvent({
  address: collection.address,
  abi: collection.abi,
  eventName: 'Transfer', // atau 'TransferSingle' untuk ERC1155
  onLogs: (logs) => {
    logs.forEach(log => {
      console.log('Mint baru terdeteksi:', {
        from: log.args.from,
        to: log.args.to,
        tokenId: log.args.tokenId?.toString()
      })
    })
  }
})

// Berhenti memantau saat selesai
// unwatch()

Praktik Terbaik

Pengalaman Pengguna

  • Berikan umpan balik yang jelas selama proses minting
  • Tampilkan perkiraan biaya gas di muka
  • Implementasikan status pemuatan yang tepat
  • Tangani kesalahan dengan pesan yang ramah pengguna

Interaksi Kontrak Cerdas

  • Selalu validasi parameter sebelum transaksi
  • Implementasikan penanganan kesalahan yang tepat
  • Gunakan batas dan harga gas yang sesuai
  • Uji secara menyeluruh di testnet

Langkah Selanjutnya