An SDK for interacting with Basemint NFT Creator Protocol
npm install @b3dotfun/basemint
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
``bash`
npm install @b3dotfun/basemintor
yarn add @b3dotfun/basemintor
pnpm add @b3dotfun/basemint
The BaseMint protocol provides a streamlined, gas-efficient workflow for NFT collections:
BaseMint features an innovative reward system that benefits all participants:
| 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 |maxSupply
| Optional Parameters |
| | 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) |baseURI
| Metadata Parameters |
| | 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 |whitelistMerkleRoot
| Security Parameters |
| | 0x${string} | ❌ | 0x${"0".repeat(64)} | Merkle root for whitelist verification |referrer
| Tracking Parameters |
| | string | ❌ | null | Referrer ID for tracking (must be registered) |
`typescript
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:
#### Option A: Using BaseMint Storage Service

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.
#### Features
- Automatic metadata storage and retrieval
- Secure signature verification
- Referrer tracking system
- Bulk operations for collection management
`typescript
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)
}
`
#### Option B: Using Your Own Storage
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.
`typescript
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},0x${string}
gameOwner: "0x..." as ,0x${string}
maxSupply: 1000n,
mintPrice: parseEther('0.1'),
maxPerWallet: 5n,
isWhitelistEnabled: true,
whitelistMerkleRoot: "0x..." as ,
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:
`typescript
// 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()
`typescript
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)
`
contract to get reward details and withdraw rewards.`typescript
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()
`Advanced Usage
#### Metadata Format
When using the storage service, your metadata will be stored in OpenSea-compatible format:
`typescript
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)
}
`#### Storage Service API Endpoints
The SDK's
OffchainStorageManager class interacts with the following endpoints:1. Create Collection (
POST /collections)
`typescript
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 deployment2. Query Collections (
GET /collections)
`typescript
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
})
`3. Get Collection (
GET /collections/:predictedAddress)
`typescript
const collection = await storage.getCollection(predictedAddress)
`
- Retrieves collection metadata
- Returns collection details4. Get Collection Count (
GET /collections/count)
`typescript
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 UI5. Delete Collection (
DELETE /collections)
`typescript
await storage.deleteCollection(predictedAddress)
`
- Requires creator signature for verification
- Permanently removes collection metadata
#### Referrer System
The storage service includes a referrer tracking system that allows you to track collection deployments coming from your site:
`typescript
// 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"
])
`#### Error Handling
The storage service provides detailed error messages. Here's how to handle common scenarios:
`typescript
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)
}
}
`#### Best Practices
1. Metadata Preparation
- Provide high-quality images (minimum 640x640 pixels)
- Use descriptive collection names and symbols
- Include comprehensive attributes for better marketplace integration
2. Security
- Always verify signatures before deployment
- Keep private keys secure
- Use appropriate chain IDs (1993 for testnet, 8333 for mainnet)
3. Performance
- Use pagination when querying multiple collections
- Implement proper error handling
- Cache frequently accessed metadata when possible
$3
`typescript
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)
`$3
`typescript
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"
`$3
`typescript
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
)
`$3
`typescript
// 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"
])
`$3
`typescript
// 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)
`Supported Networks
B3 & B3 Testnet are supported, with planned support for more networks in the future.
Find out more about B3 here - B3 Docs.`typescript
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 Addresses
$3
| Contract | Address |
|----------|---------|
| Factory | 0x5719E799dF42dc055A5a67ee851edf5CB5f9A392 |
| Escrow | 0x615cb7cF5934B86D8CE8815bD0722Ba0345dae52 |
| Simplified Factory | 0xFD564A1adc897795240aB0Da533Ed268D5cD2239 |
| Simplified Escrow | 0x09b56d81416aC588dfE9155545227FE0Fd65eDc4 |$3
| Contract | Address |
|----------|---------|
| Factory | 0xB43D65F9Cc683d03e29dAc6b2124317272b63140 |
| Escrow | 0xfD9359A4C016e098E816415E835C6325280ADb52 |
| Simplified Factory | 0x63434D03105191a603257478798Fc0CA8BD4289E |
| Simplified Escrow | 0x5719E799dF42dc055A5a67ee851edf5CB5f9A392 |Error Handling
The SDK uses descriptive error messages and types. Always wrap operations in try-catch:
`typescript
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)
}
}
`
Features
- 🎨 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
Contributing
1. Fork the repository
2. Create your feature branch (
git checkout -b feature/amazing-feature)
3. Commit your changes (git commit -m 'Add some amazing feature')
4. Push to the branch (git push origin feature/amazing-feature`)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.