Langsung ke konten utama

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:
  • Minting ERC721
  • Minting ERC1155
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

I