A TypeScript SDK for interacting with the BaseMint Protocol - a free creation, gas-efficient NFT collection deployment and management platform built for the B3 ecosystem.
- Create NFTs with onchain addresses completely free
- Deploy collections with a single transaction
- Mint NFTs with a single transaction
- Supports both ERC721 and ERC1155 standards
- OpenSea-compatible metadata format
npm install @b3dotfun/basemint
# or
yarn add @b3dotfun/basemint
# or
pnpm add @b3dotfun/basemint
The BaseMint protocol provides a streamlined, gas-efficient workflow for NFT collections:
- 📝 Creators define collection parameters (metadata, settings, etc)
- 🔑 System generates cryptographic signatures stored off-chain
- 🎯 Deterministic collection address is pre-computed
- ⚡ Zero gas costs during this phase
- 💾 Collection data stored securely in BaseMint storage
- 🔍 Collections easily discoverable via predicted addresses
- 🖼️ Seamless integration with NFT marketplaces and grids
- 🏆 Support for both ERC721 & ERC1155 standards
- 🚀 First minter triggers on-chain deployment
- 💰 Single transaction covers deployment + first mint
- ✨ Collection deploys to pre-computed address
- 🎁 Special rewards for first minter
- 🌐 Open minting for all users
- 💫 Standard minting fees apply
- 📋 Optional whitelist & wallet limits
- 💎 All mints contribute to rewards
BaseMint features an innovative reward system that benefits all participants:
Type | Description | Badge |
---|---|---|
Creator | Collection originator | |
First Minter | Initial deployer | |
Game Owner | Platform integrator | |
Platform | Protocol fee |
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
Required Parameters | ||||
name |
string |
✅ | - | The name of your NFT collection |
symbol |
string |
✅ | - | The symbol/ticker for your collection (e.g., "BAYC") |
creator |
0x${string} |
✅ | - | The Ethereum address of the collection creator |
gameOwner |
0x${string} |
✅ | - | The Ethereum address of the game owner |
Optional Parameters | ||||
maxSupply |
bigint |
❌ | 10000n |
Maximum number of tokens that can be minted |
mintPrice |
bigint |
❌ | 0n |
Price per token in wei (use parseEther() for ETH values) |
maxPerWallet |
bigint |
❌ | 100n |
Maximum tokens that can be minted per wallet |
isWhitelistEnabled |
boolean |
❌ | false |
Whether whitelist-only minting is enabled |
startTime |
bigint |
❌ | 0n |
Unix timestamp when minting starts (0 = immediate) |
endTime |
bigint |
❌ | BigInt(Date.now() / 1000 + 86400 * 365 * 100) |
Unix timestamp when minting ends |
tokenStandard |
"ERC721" | "ERC1155" |
❌ | "ERC721" |
The token standard to use |
chainId |
number |
❌ | 1993 |
Chain ID (1993 = B3 Testnet, 8333 = B3 Mainnet) |
Metadata Parameters | ||||
baseURI |
string |
❌ | Generated BaseMint CDN URL | Base URI for token metadata |
description |
string |
❌ | "{name} minted on Basemint" |
Collection description |
image |
string |
❌ | "" |
Collection image URL |
external_url |
string |
❌ | "https://basemint.fun/nft/{uuid}" |
External website URL |
animation_url |
string |
❌ | null |
URL to multimedia attachment |
attributes |
Array<{trait_type: string, value: string | number}> |
❌ | null |
Collection-level attributes |
Security Parameters | ||||
whitelistMerkleRoot |
0x${string} |
❌ | 0x${"0".repeat(64)} |
Merkle root for whitelist verification |
Tracking Parameters | ||||
referrer |
string |
❌ | null |
Referrer ID for tracking (must be registered) |
import { createPublicClient, http } from 'viem'
import { b3Mainnet, BaseMintFactory } from '@b3dotfun/basemint'
// Initialize clients
const publicClient = createPublicClient({
chain: b3Mainnet,
transport: http(b3Mainnet.rpcUrls.default.http[0])
})
// Initialize factory
const factory = new BaseMintFactory({
publicClient,
chainId: b3Mainnet.id, // 8333 for mainnet or 1993 for testnet
walletClient // Your WalletClient
})
BaseMint SDK supports two storage strategies for your NFT collection metadata:
The BaseMint SDK includes a built-in storage service that handles off-chain metadata storage for your NFT collections. This service is powered by Cloudflare Workers and provides a secure, scalable solution for storing and managing collection metadata.
- Automatic metadata storage and retrieval
- Secure signature verification
- Referrer tracking system
- Bulk operations for collection management
import { createMetadata, OffchainStorageManager } from '@b3dotfun/basemint'
// Initialize your wallet client (creator or user)
const creatorClient = createWalletClient({
account: creatorAccount, // Your creator account
chain: b3Mainnet,
transport
})
// Initialize storage manager
const storage = new OffchainStorageManager()
// You can also pass in a wallet client if you want to do delete / update operations
// const storage = new OffchainStorageManager(creatorClient)
// Prepare collection metadata
const metadata = createMetadata({
// Required Fields
name: "My Awesome NFT Collection",
symbol: "AWESOME",
creator: creatorClient.account.address,
gameOwner: "0x...", // Your game owner address
// Optional Fields with Defaults
maxSupply: 1000n,
mintPrice: parseEther('0.1'),
maxPerWallet: 5n,
isWhitelistEnabled: false,
startTime: BigInt(Math.floor(Date.now() / 1000)), // Start now
endTime: BigInt(Math.floor(Date.now() / 1000) + 86400 * 7), // End in 7 days
tokenStandard: "ERC721",
chainId: b3Mainnet.id,
// Optional Metadata Fields (OpenSea Compatible)
description: "A collection of awesome NFTs created with BaseMint",
image: "https://your-collection-image.com/image.png",
external_url: "https://your-website.com",
animation_url: "https://your-3d-model.com/model.glb", // Optional - set if you are using a 3D model or video
attributes: [
{ trait_type: "Background", value: "Blue" },
{ trait_type: "Rarity", value: "Legendary" }
]
})
try {
// Generate creator signature
const creatorSignature = await generateCreatorSignature(
creatorClient,
publicClient,
factory.address,
metadata
)
// Submit to BaseMint Storage Service
console.log('Submitting collection to storage...')
const collectionResponse = await storage.submitCollection(
metadata,
creatorSignature
)
console.log('Collection submitted:', collectionResponse)
// Now, you can use the collectionResponse.predictedAddress to track the collection and query it later.
// Fetch the collection from storage
const storedCollection = await storage.getCollection(
collectionResponse.predictedAddress
)
console.log('Stored collection:', storedCollection)
// For example, getting a list of collections by creator:
const { collections } = await storage.queryCollections({
creator: creatorClient.account.address
})
console.log('Collections:', collections);
} catch (error) {
console.error('Error:', error)
}
No need to do this if you already followed option A (above). However, you can use your own storage if you want to. This example uses local storage.
import { createMetadata, generateCreatorSignature, generateDeployerSignature, verifyDeployerSignature } from '@b3dotfun/basemint'
// Create collection metadata
const metadata = createMetadata({
name: "My NFT Collection",
symbol: "MNFT",
baseURI: "ipfs://...", // Your IPFS/storage URI (optional for custom metadata)
creator: "0x..." as `0x${string}`,
gameOwner: "0x..." as `0x${string}`,
maxSupply: 1000n,
mintPrice: parseEther('0.1'),
maxPerWallet: 5n,
isWhitelistEnabled: true,
whitelistMerkleRoot: "0x..." as `0x${string}`,
startTime: BigInt(Date.now() / 1000),
endTime: BigInt(Date.now() / 1000 + 86400 * 7),
tokenStandard: "ERC721",
chainId: 1993
})
// Creator signs first - signs the metadata hash
const creatorSignature = await generateCreatorSignature(
walletClient,
publicClient,
metadata
)
// Deployer signs second - signs the deploy data (metadataHash + creatorSignature)
const deployerSignature = await generateDeployerSignature(
walletClient,
publicClient,
metadata,
creatorSignature
)
// Verify signatures if needed
const isValid = await verifyDeployerSignature(
publicClient,
metadata,
creatorSignature,
deployerSignature,
walletClient.account.address
)
console.log('Signature valid:', isValid)
// Predict collection address
const predictedAddress = await factory.predictCollectionAddress(
metadata,
creatorSignature, // Creator's signature is used in salt calculation
)
// Store metadata in local storage
// First, create a collection object with additional metadata
const collectionData = {
id: crypto.randomUUID(), // Unique identifier for the collection
...metadata,
image: "https://...", // Optional: Collection image URL
creator: {
address: metadata.creator,
name: `${metadata.creator.slice(0, 6)}...${metadata.creator.slice(-4)}` // Shortened address
},
createdAt: new Date().toISOString(),
creatorSignature,
predictedAddress,
chainId: 1993, // B3 Testnet
tokenStandard: "ERC721" // or "ERC1155"
}
// Get existing collections from localStorage
const existingCollections = JSON.parse(localStorage.getItem('nftCollections') || '[]')
// Add new collection
const updatedCollections = [...existingCollections, collectionData]
// Save to localStorage
localStorage.setItem('nftCollections', JSON.stringify(updatedCollections))
Once you have created your collection and stored its metadata (either using BaseMint Storage or your own solution), you can deploy it.
Collections can be stored offchain until someone actually wants to mint & deploy it. We will know the address of the collection ahead of time though, so for all intents and purposes, it's already onchain.
Here's how:
// Later, you or a user can deploy the collection by signing the deployer signature
const deployerSignature = await generateDeployerSignature(
deployerClient,
publicClient,
factory.address,
metadata,
creatorSignature
)
// Deploy the collection
console.log('Deploying collection...')
const tx = await factory.deployCollection(
metadata,
creatorSignature, // Creator's signature for verification
deployerSignature, // Deployer's signature for authorization
)
console.log('Deployment transaction:', tx)
// Wait for deployment
const receipt = await publicClient.waitForTransactionReceipt({ hash: tx })
console.log('Deployment complete:', receipt)
// Verify the collection is deployed
const isDeployed = await factory.isDeployed(predictedAddress)
console.log('Collection deployed successfully:', isDeployed)
console.log('Collection address:', predictedAddress)
// If you're using local storage, update the collection status
const collections = JSON.parse(localStorage.getItem('nftCollections') || '[]')
if (isDeployed) {
const updatedCollections = collections.map(c =>
c.predictedAddress === predictedAddress
? { ...c, isDeployed: true, deployedAt: new Date().toISOString() }
: c
)
localStorage.setItem('nftCollections', JSON.stringify(updatedCollections))
}
Key points about deployment:
- The deployer (first minter) must sign a deployment signature
- Both creator and deployer signatures are required for deployment
- The collection will deploy to the previously predicted address
- The first minter receives special rewards for deploying
- You can verify deployment status using
factory.isDeployed()
import { BaseMintCollection } from '@b3dotfun/basemint'
// Initialize collection
const collection = new BaseMintCollection({
publicClient,
address: predictedAddress,
tokenStandard: "ERC721",
walletClient
})
// For ERC721
const mintTx = await collection.mint(
1n, // amount
undefined, // tokenId (not needed for ERC721)
mintPrice,
proof // (Optional) merkle proof for whitelist
)
// For ERC1155
const mint1155Tx = await collection.mint(
5n, // amount
1n, // tokenId
mintPrice * 5n,
proof // (Optional) merkle proof for whitelist
)
// Get collection info
const info = await collection.getInfo()
console.log('Total Supply:', info.totalSupply)
console.log('Max Supply:', info.maxSupply)
User rewards are handled by the BaseMint Escrow contract. You can use the BaseMintEscrow
contract to get reward details and withdraw rewards.
import { BaseMintEscrow } from '@b3dotfun/basemint'
// Initialize escrow contract
const escrowAddress = await factory.getEscrowContract()
const escrow = new BaseMintEscrow({
publicClient,
address: escrowAddress,
walletClient
})
// Get reward rates
const rates = await escrow.getRewardRates()
console.log('Creator Rate:', rates.creatorRate)
console.log('First Minter Rate:', rates.firstMinterRate)
console.log('Game Owner Rate:', rates.gameOwnerRate)
console.log('Platform Rate:', rates.platformRate)
// Get collection reward details
const rewardDetails = await escrow.getCollectionRewardDetails(collectionAddress)
console.log('Total Rewards:', rewardDetails.totalRewards)
console.log('Unclaimed Rewards:', rewardDetails.unclaimedRewards)
console.log('Creator Share:', rewardDetails.creatorRewards)
console.log('First Minter Share:', rewardDetails.firstMinterRewards)
console.log('Game Owner Share:', rewardDetails.gameOwnerRewards)
console.log('Platform Share:', rewardDetails.platformRewards)
// Get active collections
const activeCollections = await escrow.getActiveCollections()
console.log('Active Collections:', activeCollections)
// Check if collection is active
const isActive = await escrow.isCollectionActive(collectionAddress)
console.log('Collection Active:', isActive)
// Withdraw accumulated rewards
const withdrawTx = await escrow.withdrawRewards()
When using the storage service, your metadata will be stored in OpenSea-compatible format:
const metadata = {
// Required Fields
name: "My NFT Collection", // Collection name
symbol: "MNFT", // Collection symbol
creator: "0x..." as `0x${string}`, // Creator's address
gameOwner: "0x..." as `0x${string}`, // Game owner address
// Optional Fields with Defaults
maxSupply: 1000n, // Default: 10000n
mintPrice: parseEther('0.1'), // Default: 0 ETH
maxPerWallet: 5n, // Default: 100n
isWhitelistEnabled: true, // Default: false
startTime: BigInt(Date.now() / 1000),// Default: 0 (immediate start)
endTime: BigInt(Date.now() / 1000 + 86400 * 7), // Default: 100 years
tokenStandard: "ERC721", // Default: "ERC721"
chainId: 1993, // Default: B3 Testnet (1993)
// Use chainId 8333 for B3 Mainnet
// Metadata Fields (OpenSea Compatible)
description: "My awesome NFT collection", // Default: "{name} minted on Basemint"
image: "https://...", // Default: ""
external_url: "https://...", // Default: "https://basemint.fun/nft/{uuid}"
animation_url: "https://...", // Optional: Multimedia attachment
attributes: [ // Optional: Collection traits
{ trait_type: "Background", value: "Blue" },
{ trait_type: "Rarity", value: 5 }
],
// Security & Tracking
whitelistMerkleRoot: "0x..." as `0x${string}`, // Default: 0x000...000
referrer: "my-referrer-id" // Optional: For tracking (must register first)
}
The SDK's OffchainStorageManager
class interacts with the following endpoints:
-
Create Collection (
POST /collections
)const collection = await storage.submitCollection(metadata, creatorSignature, referrer)
- Stores collection metadata and computes predicted address
- Generates OpenSea-compatible metadata
- Returns collection details including predicted address
-
referrer
is optional, but if provided, it will be used to track the collection deployment
-
Query Collections (
GET /collections
)const { collections, total } = await storage.queryCollections({ creator: "0x...", // Find by creator address gameOwner: "0x...", // Find by game owner address symbol: "MNFT", // Find by symbol referrer: "ref123", // Find by referrer ID chainId: 1993, // Find by chain ID page: 1, // Pagination - defaults to 1 limit: 10 // Results per page - defaults to 10 })
-
Get Collection (
GET /collections/:predictedAddress
)const collection = await storage.getCollection(predictedAddress)
- Retrieves collection metadata
- Returns collection details
-
Get Collection Count (
GET /collections/count
)const { count } = await storage.getCollectionCount({ creator: "0x...", // Find by creator address gameOwner: "0x...", // Find by game owner address symbol: "MNFT", // Find by symbol referrer: "ref123", // Find by referrer ID chainId: 1993 // Find by chain ID })
- Returns total count of collections matching the filters
- Accepts same filters as query endpoint (except pagination)
- Useful for implementing pagination UI
-
Delete Collection (
DELETE /collections
)await storage.deleteCollection(predictedAddress)
- Requires creator signature for verification
- Permanently removes collection metadata
The storage service includes a referrer tracking system that allows you to track collection deployments coming from your site:
// Register as a referrer (one-time setup)
await storage.registerReferrer("my-referrer-id")
// Query collections by referrer
const { collections } = await storage.queryCollections({
referrer: "my-referrer-id"
})
// Bulk delete collections (referrers only)
await storage.bulkDeleteCollections([
"uuid1",
"0xpredicted1"
])
The storage service provides detailed error messages. Here's how to handle common scenarios:
try {
await storage.submitCollection(metadata, creatorSignature)
} catch (error) {
if (error.message.includes('Invalid signature')) {
console.error('Creator signature verification failed')
} else if (error.message.includes('Referrer not found')) {
console.error('Invalid referrer ID')
} else if (error.message.includes('Collection exists')) {
console.error('Collection with this address already exists')
} else {
console.error('Unexpected error:', error)
}
}
-
Metadata Preparation
- Provide high-quality images (minimum 640x640 pixels)
- Use descriptive collection names and symbols
- Include comprehensive attributes for better marketplace integration
-
Security
- Always verify signatures before deployment
- Keep private keys secure
- Use appropriate chain IDs (1993 for testnet, 8333 for mainnet)
-
Performance
- Use pagination when querying multiple collections
- Implement proper error handling
- Cache frequently accessed metadata when possible
import { WhitelistManager } from '@b3dotfun/basemint'
// Create whitelist
const whitelist = new WhitelistManager([
{ address: "0x123..." },
{ address: "0x456..." }
])
// Get merkle root for deployment
const merkleRoot = whitelist.getRoot()
// Get proof for minting
const proof = whitelist.getProof("0x123...")
// Verify address in whitelist
const isValid = whitelist.verify("0x123...", proof)
import { NFTMetadataManager, MediaType } from '@b3dotfun/basemint'
// Generate metadata for different media types
const model3dMetadata = NFTMetadataManager.generateNFTMetadata(
collectionMetadata,
MediaType.MODEL_3D
)
const artworkMetadata = NFTMetadataManager.generateNFTMetadata(
collectionMetadata,
MediaType.ARTWORK
)
const videoMetadata = NFTMetadataManager.generateNFTMetadata(
collectionMetadata,
MediaType.VIDEO
)
// Convert to JSON format
console.log('3D Model Metadata:')
console.log(NFTMetadataManager.generateJSON(model3dMetadata))
// Available Media Types:
// MediaType.MODEL_3D - "3d_model"
// MediaType.ARTWORK - "artwork"
// MediaType.VIDEO - "video"
// MediaType.MEME - "meme"
import { getCollectionMintEvents, getRewardDistributionEvents } from '@b3dotfun/basemint'
// Track mints
const mintEvents = await getCollectionMintEvents(
publicClient,
collectionAddress,
"ERC721",
fromBlock,
toBlock
)
// Track rewards
const rewardEvents = await getRewardDistributionEvents(
publicClient,
escrowAddress,
fromBlock,
toBlock
)
// Register as a referrer
await storage.registerReferrer("my-referrer-id")
// Query collections by referrer
const { collections } = await storage.queryCollections({
referrer: "my-referrer-id"
})
// Delete collection
await storage.deleteCollection(predictedAddress)
// Bulk delete collections (for referrers)
await storage.bulkDeleteCollections([
"uuid1",
"0xpredicted1"
])
// Update reward rates (owner only)
await escrow.setRewardRates({
creatorRate: 4000, // 50%
firstMinterRate: 3000, // 20%
gameOwnerRate: 2000, // 20%
platformRate: 1000 // 10%
})
// Update recipient status (owner only)
await escrow.updateRecipient(
"CREATOR",
5000, // 50% in basis points
true // active
)
// Update platform address (owner only)
await escrow.updatePlatformAddress(newPlatformAddress)
// Update factory address (owner only)
await escrow.updateFactory(newFactoryAddress)
B3 & B3 Testnet are supported, with planned support for more networks in the future. Find out more about B3 here - B3 Docs.
import { b3Testnet, b3Mainnet } from '@b3dotfun/basemint'
// Base Mainnet
console.log('Chain ID:', b3Mainnet.id)
console.log('Name:', b3Mainnet.name)
console.log('RPC URL:', b3Mainnet.rpcUrls.default.http[0])
// Base Testnet (for development)
console.log('Chain ID:', b3Testnet.id)
console.log('Name:', b3Testnet.name)
console.log('RPC URL:', b3Testnet.rpcUrls.default.http[0])
Contract | Address |
---|---|
Factory | 0x5719E799dF42dc055A5a67ee851edf5CB5f9A392 |
Escrow | 0x615cb7cF5934B86D8CE8815bD0722Ba0345dae52 |
Simplified Factory | 0xFD564A1adc897795240aB0Da533Ed268D5cD2239 |
Simplified Escrow | 0x09b56d81416aC588dfE9155545227FE0Fd65eDc4 |
Contract | Address |
---|---|
Factory | 0xB43D65F9Cc683d03e29dAc6b2124317272b63140 |
Escrow | 0xfD9359A4C016e098E816415E835C6325280ADb52 |
Simplified Factory | 0x63434D03105191a603257478798Fc0CA8BD4289E |
Simplified Escrow | 0x5719E799dF42dc055A5a67ee851edf5CB5f9A392 |
The SDK uses descriptive error messages and types. Always wrap operations in try-catch:
try {
await collection.mint(1n, undefined, mintPrice, proof)
} catch (error) {
if (error.message.includes('Invalid merkle proof')) {
console.error('Address not in whitelist')
} else if (error.message.includes('Insufficient payment')) {
console.error('Incorrect mint price')
} else {
console.error('Unexpected error:', error)
}
}
-
🎨 Collection Management
- Deploy ERC721 and ERC1155 collections
- Customize collection parameters (name, symbol, supply, pricing)
- Set minting timeframes and limits
- Manage collection metadata and URIs
- Support for different media types (3D models, artwork, video, memes)
-
🔒 Secure Deployment
- Two-step signature verification process
- Creator signature validation
- Deployer signature validation
- Collection address prediction
-
🎯 Token Operations
- Mint ERC721 and ERC1155 tokens
- Whitelist-based minting with Merkle proofs
- Automatic price calculation
- Built-in parameter validation
- Gas-efficient transactions
-
💰 Reward Distribution
- Track creator rewards
- Monitor per-collection reward accumulation
- View total and unclaimed rewards per collection
- Track reward distribution per recipient type (creator, first minter, game owner, platform)
- Query historical distributions
- Monitor active collections
- Withdraw accumulated rewards
-
🛠 Developer Experience
- Full TypeScript support
- Comprehensive type definitions
- Built-in validation
- Error handling
- Event tracking
- Frontend-ready with wallet integration
-
⚡ Technical Features
- Modern viem-based architecture
- Gas-optimized contract interactions
- Automatic ABI handling
- Built-in type safety
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
The BaseMint Protocol smart contracts have been audited by Beosin. You can view the full audit report here.
If you discover a security vulnerability, please send an e-mail to contact@b3.fun. All security vulnerabilities will be promptly addressed.
Copyright © 2025 NPC Labs, Inc. All rights reserved.
This software and associated documentation files are proprietary and confidential. Unauthorized copying, distribution, modification, public display, or public performance of this software is strictly prohibited.