概览

铸造是在您的收藏中创建新 NFT 代币的过程。CreateKit 提供了一个独特的两阶段铸造系统,优化了燃气效率和用户体验。

铸造阶段

阶段 1:部署和首次铸造

首次铸造操作是特殊的 - 它在单个交易中部署集合合约并铸造第一个代币:
部署和首次铸造
import { CollectionManager } from '@b3dotfun/basemint'

const collectionManager = new CollectionManager(publicClient)

// 假设我们有收藏元数据和创建者签名
const predictedAddress = collectionManager.predictCollectionAddress(
  collectionMetadata,
  creatorSignature
)

// 生成部署者签名
const deployerSignature = await collectionManager.generateDeployerSignature(
  walletClient,
  predictedAddress
)

// 创建集合实例
const collection = collectionManager.createCollection(
  predictedAddress,
  collectionMetadata.tokenStandard
)

// 部署并铸造首个 NFT
const mintTx = await collection.mint(
  walletClient,
  1n, // 数量
  undefined, // 元数据 URI(使用 baseURI)
  collectionMetadata.mintPrice || 0n,
  [], // 白名单证明(公开为空)
  creatorSignature, // 首次铸造所需
  deployerSignature // 首次铸造所需
)

console.log(`🚀 集合部署并首个代币铸造完成:${mintTx}`)

阶段 2:常规铸造

部署后,后续的铸造更简单,只需要标准参数:
常规铸造
// 对于部署后的后续铸造
const regularMintTx = await collection.mint(
  walletClient,
  1n, // 数量
  undefined, // 元数据 URI
  collectionMetadata.mintPrice || 0n,
  [] // 白名单证明
  // 常规铸造不需要签名
)

console.log(`✨ 代币铸造完成:${regularMintTx}`)

代币标准

CreateKit 支持 ERC721 和 ERC1155 标准,具有不同的铸造行为:
ERC721 独特代币
// ERC721 - 每个代币都是独特的
const erc721Collection = collectionManager.createCollection(
  predictedAddress,
  "ERC721"
)

// ERC721 总是铸造数量为 1
await erc721Collection.mint(
  walletClient,
  1n, // 对于 ERC721 总是 1
  "https://example.com/metadata/1.json", // 此代币的独特元数据
  parseEther("0.01"),
  []
)

// 每次铸造都会创建一个新的独特代币 ID
// 代币 ID 递增:1, 2, 3, 等。

定价和支付

固定定价

固定价格铸造
import { parseEther } from 'viem'

const fixedPriceCollection = {
  name: "固定价格集合",
  symbol: "FPC",
  creator: account.address,
  gameOwner: account.address,
  mintPrice: parseEther("0.01"), // 每个代币 0.01 ETH
  maxPerWallet: 5n
}

// 以固定价格铸造
await collection.mint(
  walletClient,
  2n, // 数量
  undefined,
  parseEther("0.02"), // 2 * 0.01 ETH
  []
)

免费铸造

免费铸造
const freeCollection = {
  name: "免费集合",
  symbol: "FREE",
  creator: account.address,
  gameOwner: account.address,
  mintPrice: 0n, // 免费铸造
  maxPerWallet: 10n
}

// 免费铸造(只需支付燃气费)
await collection.mint(
  walletClient,
  1n,
  undefined,
  0n, // 无需支付
  []
)

动态定价

动态定价逻辑
// 在您的应用程序中自定义定价逻辑
function calculateMintPrice(totalSupply: bigint, basePrice: bigint): bigint {
  // 价格随供应量增加
  const priceMultiplier = totalSupply / 1000n + 1n
  return basePrice * priceMultiplier
}

// 获取当前供应量并计算价格
const currentSupply = await collection.totalSupply()
const dynamicPrice = calculateMintPrice(currentSupply, parseEther("0.001"))

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

白名单铸造

CreateKit 支持基于 Merkle 树的白名单,用于独家铸造:

设置白名单

白名单设置
import { WhitelistManager } from '@b3dotfun/basemint'

// 使用地址创建白名单
const whitelist = new WhitelistManager([
  { address: "0x1234567890123456789012345678901234567890" },
  { address: "0x2345678901234567890123456789012345678901" },
  { address: "0x3456789012345678901234567890123456789012" }
])

// 获取集合部署的 Merkle 根
const merkleRoot = whitelist.getRoot()

const whitelistCollection = {
  name: "白名单集合",
  symbol: "WLC",
  creator: account.address,
  gameOwner: account.address,
  isWhitelistEnabled: true,
  whitelistMerkleRoot: merkleRoot,
  mintPrice: parseEther("0.005")
}

白名单铸造

使用白名单证明铸造
// 获取铸造地址的证明
const userAddress = account.address
const proof = whitelist.getProof(userAddress)

// 验证用户是否在白名单中(可选检查)
const isWhitelisted = whitelist.verify(userAddress, proof)
if (!isWhitelisted) {
  throw new Error("地址不在白名单中")
}

// 使用白名单证明铸造
await collection.mint(
  walletClient,
  1n,
  undefined,
  parseEther("0.005"),
  proof // 提供白名单证明
)

铸造限制和控制

每个钱包的限制

钱包限制
// 设置每个钱包的最大代币数量
const limitedCollection = {
  name: "限量集合",
  symbol: "LTD",
  creator: account.address,
  gameOwner: account.address,
  maxPerWallet: 3n, // 每个钱包最多 3 个代币
  maxSupply: 1000n
}

// 铸造前检查当前余额
const currentBalance = await collection.balanceOf(account.address)
const maxPerWallet = await collection.maxPerWallet()

if (currentBalance >= maxPerWallet) {
  throw new Error("钱包限额已超")
}

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

基于时间的控制

时间控制
const timedCollection = {
  name: "定时发布",
  symbol: "TIME",
  creator: account.address,
  gameOwner: account.address,
  startTime: BigInt(Math.floor(Date.now() / 1000) + 3600), // 1 小时后开始
  endTime: BigInt(Math.floor(Date.now() / 1000) + 86400), // 24 小时后结束
}

// 检查铸造是否当前活跃
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("当前未激活铸造")
}

元数据处理

自动元数据

CreateKit 可以根据集合设置自动生成元数据:
自动生成的元数据
// 使用 baseURI 自动生成元数据
const autoMetadataCollection = {
  name: "自动元数据集合",
  symbol: "AMC",
  creator: account.address,
  gameOwner: account.address,
  // baseURI 将由 BaseMint CDN 自动生成
}

// 使用自动元数据铸造(对 URI 传递 undefined)
await collection.mint(
  walletClient,
  1n,
  undefined, // 使用 baseURI + tokenId
  0n,
  []
)

// 元数据将在:{baseURI}/{tokenId} 处可用

自定义元数据

自定义元数据 URIs
// 为每个代币提供特定的元数据 URI
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, // 此代币的自定义元数据
    parseEther("0.01"),
    []
  )
}

批量铸造

对于 ERC1155 集合,您可以高效地铸造多个代币:
批量铸造
// 单个交易,多个代币
await erc1155Collection.mint(
  walletClient,
  10n, // 铸造相同类型的 10 个代币
  "https://example.com/metadata/resource.json",
  parseEther("0.001") * 10n, // 所有代币的总价格
  []
)

// 对于不同类型的代币,使用单独的交易
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),
    []
  )
}

错误处理

全面的错误处理
async function safeMint(
  collection: any,
  walletClient: any,
  quantity: bigint,
  metadataURI: string | undefined,
  mintPrice: bigint,
  proof: string[]
) {
  try {
    // 铸造前验证
    const isDeployed = await collection.isDeployed()
    if (!isDeployed) {
      throw new Error("集合尚未部署")
    }

    const currentSupply = await collection.totalSupply()
    const maxSupply = await collection.maxSupply()
    if (currentSupply + quantity > maxSupply) {
      throw new Error("将超出最大供应量")
    }

    const userBalance = await collection.balanceOf(walletClient.account.address)
    const maxPerWallet = await collection.maxPerWallet()
    if (userBalance + quantity > maxPerWallet) {
      throw new Error("将超出钱包限额")
    }

    // 检查支付金额
    const requiredPayment = await collection.mintPrice() * quantity
    if (mintPrice < requiredPayment) {
      throw new Error("支付不足")
    }

    // 尝试铸造
    const tx = await collection.mint(
      walletClient,
      quantity,
      metadataURI,
      mintPrice,
      proof
    )

    console.log(`✅ 铸造成功:${tx}`)
    return tx

  } catch (error: any) {
    if (error.message.includes('Invalid merkle proof')) {
      console.error('❌ 地址不在白名单中')
    } else if (error.message.includes('Insufficient payment')) {
      console.error('❌ 铸造价格错误')
    } else if (error.message.includes('Max per wallet exceeded')) {
      console.error('❌ 钱包限额已达')
    } else {
      console.error('❌ 铸造失败:', error.message)
    }
    throw error
  }
}

燃气优化

高效铸造模式

燃气效率高的铸造
// 对于 ERC1155:在一个交易中铸造多个代币
await erc1155Collection.mint(
  walletClient,
  10n, // 比 10 个单独的交易更节省燃气
  metadataURI,
  totalPrice,
  proof
)

// 对于 ERC721:考虑在应用程序级别进行批量操作
const mintPromises = []
for (let i = 0; i < 5; i++) {
  mintPromises.push(
    collection.mint(walletClient, 1n, undefined, mintPrice, proof)
  )
}

// 并发执行铸造(注意管理 nonce)
const results = await Promise.all(mintPromises)

燃气价格管理

燃气价格优化
import { createWalletClient, http } from 'viem'

// 自定义燃气配置
const optimizedWalletClient = createWalletClient({
  chain: b3Testnet,
  transport: http(),
  account,
  // 燃气配置
  gasPrice: parseGwei('20'), // 自定义燃气价格
})

// 或使用动态燃气定价
const gasPrice = await publicClient.getGasPrice()
const adjustedGasPrice = gasPrice * 110n / 100n // 当前价格上 10%

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

监控和分析

铸造事件跟踪

事件监控
import { getCollectionMintEvents } from '@b3dotfun/basemint'

// 跟踪铸造事件
const fromBlock = await publicClient.getBlockNumber() - 1000n
const toBlock = await publicClient.getBlockNumber()

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

console.log("近期铸造:", mintEvents.map(event => ({
  minter: event.args.minter,
  tokenId: event.args.tokenId?.toString(),
  quantity: event.args.quantity?.toString(),
  blockNumber: event.blockNumber
})))

实时监控

实时铸造监控
// 观察新的铸造事件
const unwatch = publicClient.watchContractEvent({
  address: collection.address,
  abi: collection.abi,
  eventName: 'Transfer', // 或 'TransferSingle' 对于 ERC1155
  onLogs: (logs) => {
    logs.forEach(log => {
      console.log('检测到新铸造:', {
        from: log.args.from,
        to: log.args.to,
        tokenId: log.args.tokenId?.toString()
      })
    })
  }
})

// 完成后停止观察
// unwatch()

最佳实践

用户体验

  • 在铸造过程中提供清晰的反馈
  • 预先显示估计的燃气费用
  • 实现适当的加载状态
  • 优雅地处理错误,提供用户友好的消息