Ikhtisar
CreateKit mendukung pengelolaan whitelist yang canggih menggunakan Merkle trees untuk verifikasi yang efisien gas. Ini memungkinkan Anda untuk membuat pengalaman minting eksklusif untuk alamat tertentu sambil menjaga skalabilitas dan keamanan.Dasar Whitelist
Cara Kerja Whitelist
- Pembuatan Off-chain: Membuat Merkle tree dari alamat yang masuk whitelist
- Penyimpanan On-chain: Menyimpan hanya akar Merkle di smart contract
- Verifikasi Bukti: Pengguna menyediakan bukti Merkle saat minting
- Efisiensi Gas: Biaya verifikasi konstan tanpa memandang ukuran whitelist
Dapat Diskalakan
Mendukung ribuan alamat dengan biaya gas minimal
Aman
Verifikasi alamat yang dijamin secara kriptografi
Fleksibel
Mudah untuk menghasilkan dan memperbarui konfigurasi whitelist
Transparan
Dapat diverifikasi on-chain tanpa mengungkapkan daftar lengkap
Menyiapkan Whitelist
Pembuatan Whitelist Dasar
Create Whitelist
Copy
Ask AI
import { WhitelistManager } from '@b3dotfun/basemint'
// Mendefinisikan alamat yang masuk whitelist
const whitelistedAddresses = [
{ address: "0x1234567890123456789012345678901234567890" },
{ address: "0x2345678901234567890123456789012345678901" },
{ address: "0x3456789012345678901234567890123456789012" },
{ address: "0x4567890123456789012345678901234567890123" },
{ address: "0x5678901234567890123456789012345678901234" }
]
// Membuat manajer whitelist
const whitelist = new WhitelistManager(whitelistedAddresses)
// Mendapatkan akar Merkle untuk penempatan kontrak
const merkleRoot = whitelist.getRoot()
console.log(`Akar Merkle: ${merkleRoot}`)
// Memverifikasi whitelist dibangun dengan benar
console.log(`Whitelist berisi ${whitelistedAddresses.length} alamat`)
Konfigurasi Whitelist Lanjutan
Whitelist with Metadata
Copy
Ask AI
// Entri whitelist dapat mencakup metadata tambahan
const advancedWhitelist = [
{
address: "0x1234567890123456789012345678901234567890",
alokasi: 5, // Maks 5 token untuk alamat ini
tier: "gold"
},
{
address: "0x2345678901234567890123456789012345678901",
alokasi: 3,
tier: "silver"
},
{
address: "0x3456789012345678901234567890123456789012",
alokasi: 1,
tier: "bronze"
}
]
// Membuat whitelist (hanya alamat yang digunakan untuk Merkle tree)
const whitelist = new WhitelistManager(
advancedWhitelist.map(entry => ({ address: entry.address }))
)
// Menyimpan metadata secara terpisah untuk logika aplikasi
const allocationMap = new Map(
advancedWhitelist.map(entry => [entry.address, entry.allocation])
)
Integrasi Koleksi
Koleksi yang Diaktifkan Whitelist
Whitelist Collection Setup
Copy
Ask AI
import { CollectionManager } from '@b3dotfun/basemint'
// Membuat koleksi dengan whitelist diaktifkan
const whitelistCollection = {
name: "Exclusive Collection",
symbol: "EXCL",
creator: account.address,
gameOwner: account.address,
// Konfigurasi whitelist
isWhitelistEnabled: true,
whitelistMerkleRoot: merkleRoot,
// Pengaturan koleksi
maxSupply: 1000n,
mintPrice: parseEther("0.01"),
maxPerWallet: 3n,
// Opsional: Gabungkan dengan akses berbasis waktu
startTime: BigInt(Math.floor(Date.now() / 1000) + 3600), // Whitelist dimulai dalam 1 jam
endTime: BigInt(Math.floor(Date.now() / 1000) + 86400 * 7), // Berakhir dalam 7 hari
}
// Menghasilkan tanda tangan dan penempatan
const creatorSignature = await collectionManager.generateCreatorSignature(
walletClient,
whitelistCollection
)
const predictedAddress = collectionManager.predictCollectionAddress(
whitelistCollection,
creatorSignature
)
console.log(`Koleksi whitelist akan ditempatkan di: ${predictedAddress}`)
Model Akses Hibrid
Phased Access
Copy
Ask AI
// Membuat koleksi dengan fase akses yang berbeda
const phasedCollection = {
name: "Phased Access Collection",
symbol: "PAC",
creator: account.address,
gameOwner: account.address,
// Fase 1: Hanya whitelist (24 jam pertama)
isWhitelistEnabled: true,
whitelistMerkleRoot: merkleRoot,
startTime: BigInt(Math.floor(Date.now() / 1000)),
// Catatan: Untuk fase 2 (akses publik), Anda akan memerlukan logika tambahan
// untuk menonaktifkan pemeriksaan whitelist setelah waktu tertentu
}
// Dalam aplikasi Anda, implementasikan logika fase
async function checkMintingPhase(collection: any): Promise<'whitelist' | 'public' | 'ended'> {
const now = BigInt(Math.floor(Date.now() / 1000))
const startTime = await collection.startTime()
const endTime = await collection.endTime()
const whitelistPhaseEnd = startTime + 86400n // 24 jam
if (now < startTime) {
throw new Error("Minting belum dimulai")
} else if (now < whitelistPhaseEnd) {
return 'whitelist'
} else if (now < endTime) {
return 'public'
} else {
return 'ended'
}
}
Verifikasi Whitelist
Menghasilkan Bukti
Generate Merkle Proofs
Copy
Ask AI
// Menghasilkan bukti untuk alamat tertentu
function generateProofForAddress(whitelist: WhitelistManager, address: string): string[] {
try {
const proof = whitelist.getProof(address)
console.log(`Bukti dihasilkan untuk ${address}:`, proof)
return proof
} catch (error) {
console.error(`Gagal menghasilkan bukti untuk ${address}:`, error)
throw new Error(`Alamat ${address} tidak dalam whitelist`)
}
}
// Memverifikasi bukti secara lokal (pemeriksaan opsional)
function verifyWhitelistProof(
whitelist: WhitelistManager,
address: string,
proof: string[]
): boolean {
const isValid = whitelist.verify(address, proof)
console.log(`Verifikasi bukti untuk ${address}: ${isValid ? '✅ Valid' : '❌ Invalid'}`)
return isValid
}
// Contoh penggunaan
const userAddress = "0x1234567890123456789012345678901234567890"
const proof = generateProofForAddress(whitelist, userAddress)
const isValid = verifyWhitelistProof(whitelist, userAddress, proof)
Generasi Bukti Batch
Batch Proof Generation
Copy
Ask AI
// Menghasilkan bukti untuk beberapa alamat
function generateBatchProofs(
whitelist: WhitelistManager,
addresses: string[]
): Map<string, string[]> {
const proofMap = new Map<string, string[]>()
for (const address of addresses) {
try {
const proof = whitelist.getProof(address)
proofMap.set(address, proof)
console.log(`✅ Bukti dihasilkan untuk ${address}`)
} catch (error) {
console.error(`❌ Gagal menghasilkan bukti untuk ${address}:`, error)
}
}
return proofMap
}
// Menghasilkan bukti untuk semua alamat yang masuk whitelist
const allAddresses = whitelistedAddresses.map(entry => entry.address)
const allProofs = generateBatchProofs(whitelist, allAddresses)
// Menyimpan bukti ke file atau database untuk penggunaan frontend
const proofData = {
merkleRoot,
proofs: Object.fromEntries(allProofs)
}
// Contoh: Simpan ke file JSON
import { writeFileSync } from 'fs'
writeFileSync('whitelist-proofs.json', JSON.stringify(proofData, null, 2))
Minting dengan Whitelist
Minting Whitelist Dasar
Whitelist Mint
Copy
Ask AI
async function mintWithWhitelist(
collection: any,
walletClient: any,
whitelist: WhitelistManager,
quantity: bigint = 1n
) {
const userAddress = walletClient.account.address
try {
// Menghasilkan bukti untuk pengguna
const proof = whitelist.getProof(userAddress)
// Memverifikasi bukti secara lokal (opsional)
const isValid = whitelist.verify(userAddress, proof)
if (!isValid) {
throw new Error("Bukti whitelist tidak valid")
}
// Mendapatkan harga mint
const mintPrice = await collection.mintPrice()
const totalPrice = mintPrice * quantity
// Mint dengan bukti whitelist
const tx = await collection.mint(
walletClient,
quantity,
undefined, // URI metadata
totalPrice,
proof // Bukti whitelist
)
console.log(`✅ Mint whitelist berhasil: ${tx}`)
return tx
} catch (error: any) {
if (error.message.includes('Invalid merkle proof')) {
console.error('❌ Alamat tidak dalam whitelist atau bukti tidak valid')
} else {
console.error('❌ Mint whitelist gagal:', error)
}
throw error
}
}
// Penggunaan
await mintWithWhitelist(collection, walletClient, whitelist, 2n)
Minting Whitelist Lanjutan
Advanced Whitelist Logic
Copy
Ask AI
async function advancedWhitelistMint(
collection: any,
walletClient: any,
whitelist: WhitelistManager,
allocationMap: Map<string, number>,
quantity: bigint
) {
const userAddress = walletClient.account.address
// Memeriksa alokasi pengguna
const maxAllocation = allocationMap.get(userAddress) || 0
if (maxAllocation === 0) {
throw new Error("Alamat tidak dalam whitelist")
}
// Memeriksa saldo saat ini terhadap alokasi
const currentBalance = await collection.balanceOf(userAddress)
const newBalance = currentBalance + quantity
if (newBalance > BigInt(maxAllocation)) {
throw new Error(`Akan melebihi alokasi. Maks: ${maxAllocation}, Saat ini: ${currentBalance}`)
}
// Menghasilkan bukti dan mint
const proof = whitelist.getProof(userAddress)
const mintPrice = await collection.mintPrice()
const tx = await collection.mint(
walletClient,
quantity,
undefined,
mintPrice * quantity,
proof
)
console.log(`✅ Mint whitelist lanjutan berhasil: ${tx}`)
return tx
}
Integrasi Frontend
React Hook untuk Status Whitelist
useWhitelistStatus Hook
Copy
Ask AI
import { useState, useEffect } from 'react'
import { useAccount } from 'wagmi'
interface WhitelistStatus {
isWhitelisted: boolean
proof: string[] | null
allocation: number
loading: boolean
error: string | null
}
export function useWhitelistStatus(
whitelist: WhitelistManager,
allocationMap?: Map<string, number>
): WhitelistStatus {
const { address } = useAccount()
const [status, setStatus] = useState<WhitelistStatus>({
isWhitelisted: false,
proof: null,
allocation: 0,
loading: true,
error: null
})
useEffect(() => {
async function checkWhitelistStatus() {
if (!address) {
setStatus({
isWhitelisted: false,
proof: null,
allocation: 0,
loading: false,
error: null
})
return
}
try {
setStatus(prev => ({ ...prev, loading: true, error: null }))
// Menghasilkan bukti
const proof = whitelist.getProof(address)
const isValid = whitelist.verify(address, proof)
const allocation = allocationMap?.get(address) || 0
setStatus({
isWhitelisted: isValid,
proof: isValid ? proof : null,
allocation,
loading: false,
error: null
})
} catch (error: any) {
setStatus({
isWhitelisted: false,
proof: null,
allocation: 0,
loading: false,
error: error.message
})
}
}
checkWhitelistStatus()
}, [address, whitelist, allocationMap])
return status
}
Komponen Status Whitelist
WhitelistStatus Component
Copy
Ask AI
import React from 'react'
import { useWhitelistStatus } from './useWhitelistStatus'
interface WhitelistStatusProps {
whitelist: WhitelistManager
allocationMap?: Map<string, number>
}
export function WhitelistStatus({ whitelist, allocationMap }: WhitelistStatusProps) {
const { isWhitelisted, allocation, loading, error } = useWhitelistStatus(
whitelist,
allocationMap
)
if (loading) {
return <div className="animate-pulse">Memeriksa status whitelist...</div>
}
if (error) {
return <div className="text-red-500">Error: {error}</div>
}
return (
<div className={`p-4 rounded-lg ${isWhitelisted ? 'bg-green-100' : 'bg-gray-100'}`}>
{isWhitelisted ? (
<div className="text-green-800">
<h3 className="font-bold">✅ Masuk Whitelist</h3>
<p>Anda dapat mint hingga {allocation} token</p>
</div>
) : (
<div className="text-gray-800">
<h3 className="font-bold">❌ Tidak Masuk Whitelist</h3>
<p>Alamat Anda tidak memenuhi syarat untuk minting whitelist</p>
</div>
)}
</div>
)
}
Beberapa Whitelist
Sistem Whitelist Bertingkat
Tiered Whitelists
Copy
Ask AI
// Membuat tingkatan yang berbeda dengan manfaat yang berbeda
const goldTierAddresses = [
{ address: "0x1111..." },
{ address: "0x2222..." }
]
const silverTierAddresses = [
{ address: "0x3333..." },
{ address: "0x4444..." }
]
const bronzeTierAddresses = [
{ address: "0x5555..." },
{ address: "0x6666..." }
]
// Membuat whitelist terpisah untuk setiap tingkatan
const goldWhitelist = new WhitelistManager(goldTierAddresses)
const silverWhitelist = new WhitelistManager(silverTierAddresses)
const bronzeWhitelist = new WhitelistManager(bronzeTierAddresses)
// Untuk smart contract, Anda mungkin menggabungkan semua tingkatan
const allTierAddresses = [
...goldTierAddresses,
...silverTierAddresses,
...bronzeTierAddresses
]
const combinedWhitelist = new WhitelistManager(allTierAddresses)
// Logika aplikasi untuk manfaat tingkatan
const tierBenefits = {
gold: { maxMint: 10, diskon: 0.2 },
silver: { maxMint: 5, diskon: 0.1 },
bronze: { maxMint: 2, diskon: 0.05 }
}
function getTierForAddress(address: string): 'gold' | 'silver' | 'bronze' | null {
if (goldTierAddresses.some(entry => entry.address === address)) return 'gold'
if (silverTierAddresses.some(entry => entry.address === address)) return 'silver'
if (bronzeTierAddresses.some(entry => entry.address === address)) return 'bronze'
return null
}
Akses Tingkatan Berbasis Waktu
Phased Tier Access
Copy
Ask AI
async function getActiveTierForTime(timestamp: number): Promise<'gold' | 'silver' | 'bronze' | 'public' | null> {
const phaseStartTime = 1640995200 // Contoh timestamp
const hoursSinceStart = (timestamp - phaseStartTime) / 3600
if (hoursSinceStart < 0) return null // Belum dimulai
if (hoursSinceStart < 1) return 'gold' // Jam pertama: hanya tingkatan emas
if (hoursSinceStart < 4) return 'silver' // 3 jam berikutnya: emas + perak
if (hoursSinceStart < 24) return 'bronze' // 20 jam berikutnya: semua tingkatan
return 'public' // Setelah 24 jam: akses publik
}
async function mintWithTierAccess(
collection: any,
walletClient: any,
address: string,
quantity: bigint
) {
const now = Math.floor(Date.now() / 1000)
const activeTier = await getActiveTierForTime(now)
const userTier = getTierForAddress(address)
// Memeriksa apakah pengguna dapat mint dalam fase saat ini
if (activeTier === 'public') {
// Minting publik - tidak memerlukan whitelist
await collection.mint(walletClient, quantity, undefined, mintPrice * quantity, [])
} else