A fully on-chain generative NFT project that guarantees configurable rarity for each trait and strict uniqueness of every NFT (no duplicate combinations possible). All traits and images are generated and stored on-chain using Solidity smart contracts.
- 100% On-Chain: All images and metadata generated on-chain
- Configurable Rarity: Fine-tune rarity weights via JSON configuration
- Guaranteed Uniqueness: No duplicate trait combinations possible
- Multi-Phase Minting: GTD (free), Whitelist, and Public phases
- Automatic Verification: All contracts verified on BaseScan
- Web3 Integration: Includes a minting dapp
Dgenz_Onchain/
βββ π layers/ # PNG trait images (organize by category)
βββ π svgs/ # Generated SVGs (auto-generated)
βββ π contracts/ # Solidity smart contracts
β βββ DgenzOC.sol # Main NFT contract
β βββ SVGAssembler.sol # SVG assembly contract
β βββ DgenzTraits.sol # Trait definitions library
β βββ DgenzRarity.sol # Rarity calculation library
β βββ BackgroundRenderer.sol # Background SVG renderer
β βββ RaceRenderer.sol # Race SVG renderer
β βββ OutfitRenderer.sol # Outfit SVG renderer
β βββ EyesRenderer.sol # Eyes SVG renderer
β βββ TopHeadRenderer.sol # Top head SVG renderer
β βββ AccessoryRenderer.sol # Accessory SVG renderer
β βββ MouthRenderer.sol # Mouth SVG renderer
β βββ CheckmarkRenderer.sol # Checkmark SVG renderer
βββ π scripts/ # Deployment and utility scripts
βββ π webapp/ # Minting dapp (Next.js)
βββ π generate_all.js # Main generation script
βββ π compile_and_deploy.js # Full deployment workflow
βββ π import_allowlist.js # Allowlist import utility
βββ π update_webapp.js # Webapp configuration updater
βββ π calculate_bytecode_size.js # Contract size calculator
βββ π calculate_total_combinations.js # Trait combination calculator
βββ π rarity_config.json # Trait rarity configuration
βββ π shared_layers_order.json # Layer ordering configuration
βββ π deployed_addresses.json # Deployed contract addresses
βββ π gtd_list.csv # GTD allowlist (CSV format)
βββ π whitelist.csv # Whitelist allowlist (CSV format)
βββ π README.md # This documentation file
Edit generate_all.js to customize your collection:
const TRAITS_LIB = 'DgenzTraits'; // Traits library name
const CONTRACT_NAME = 'DgenzOC'; // Contract name
const COLLECTION_NAME = 'Dgenz Onchain'; // Collection name
const SYMBOL = 'DGOC'; // Symbol
const COLLECTION_DESCRIPTION = '1069 Dgenz Onchain.'; // Collection description
const ROYALTY_FEE_BPS = 690; // 690 = 6,9% (in basis points)
const MAX_SUPPLY = 1069; // Max supply
const MAX_MINT_PER_ADDRESS_GTD = 1; // Max mint per address in GTD phase
const MAX_MINT_PER_ADDRESS_WHITELIST = 3; // Max mint per address in Whitelist phase
const MAX_MINT_PER_ADDRESS_PUBLIC = 5; // Max mint per address in Public phase
const WHITELIST_PRICE = '0.0003 ether'; // Price for whitelist mint
const PUBLIC_PRICE = '0.00069 ether'; // Price for public mint
const MINT_COUNT_ON_DEPLOY = 1; // Number of NFTs to mint during deploymentConfigure the trait order in generate_all.js:
const LAYER_ORDER = [
'Background',
'Race',
'Outfit',
'Eyes',
'Top Head',
'Accessory',
'Mouth',
'Checkmark'
];- Add PNG files to appropriate
layers/subfolder - Run generation:
node generate_all.js - Deploy:
npx hardhat run compile_and_deploy.js --network base
npm installCreate a .env file:
PRIVATE_KEY=your_private_key
RPC_URL=https://base-mainnet.g.alchemy.com/v2/YOUR_API_KEY
BASESCAN_API_KEY=your_basescan_api_keyPlace PNG trait images in layers/ subfolders:
layers/
βββ Background/
βββ Race/
βββ Outfit/
βββ Eyes/
βββ Top Head/
βββ Accessory/
βββ Mouth/
βββ Checkmark/
node generate_rarity_config.jsEdit rarity_config.json to set trait weights.
node generate_all.jsnpx hardhat run compile_and_deploy.js --network baseflowchart TD
A[Prepare PNG Layers] --> B[Configure rarity_config.json]
B --> C[Run generate_all.js]
C --> D[Contracts Generated]
D --> E[Deploy with compile_and_deploy.js]
E --> F[Contracts Deployed & Verified]
F --> G[Set up allowlists]
G --> H[Configure webapp]
H --> I[Launch Collection]
graph TD
A[DgenzOC - Main Contract] --> B[SVGAssembler]
B --> C[BackgroundRenderer]
B --> D[RaceRenderer]
B --> E[OutfitRenderer]
B --> F[EyesRenderer]
B --> G[TopHeadRenderer]
B --> H[AccessoryRenderer]
B --> I[MouthRenderer]
B --> J[CheckmarkRenderer]
A --> K[DgenzTraits Library]
A --> L[DgenzRarity Library]
- DgenzOC: Main ERC721 contract with minting logic
- SVGAssembler: Combines trait SVGs into final image
- Renderer Contracts: Store SVG code for each trait
- DgenzTraits: Trait definitions and metadata
- DgenzRarity: Weighted random selection logic
The contract supports three minting phases:
- GTD Phase (0): Free minting for GTD-listed addresses
- Whitelist Phase (1): 0.0003 ETH for whitelist-listed addresses
- Public Phase (2): 0.00069 ETH for everyone
# Set minting phase
npx hardhat run scripts/set_phase.js --network base 1
# Pause/Unpause minting
npx hardhat console --network base
const contract = await ethers.getContractAt("DgenzOC", "CONTRACT_ADDRESS");
await contract.pause(); // or await contract.unpause();# Import GTD list (adds to both GTD and Whitelist)
node import_allowlist.js gtd
# Import whitelist (adds to Whitelist only)
node import_allowlist.js whitelistCreate CSV files (gtd_list.csv, whitelist.csv) with one address per line.
Note: GTD addresses are automatically added to both GTD and Whitelist lists, while Whitelist addresses are only added to the Whitelist.
node update_webapp.js
cd webapp
npm install
# Add NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID to .env.local
# Edit page.tsx
npm run devmint(uint256 quantity)- Mint NFTstokenURI(uint256 tokenId)- Get token metadata and SVG imagegetMintPrice(address minter)- Get mint price for a given addressgetMaxMintPerAddress(address minter)- Get maximum mint per addresstotalSupply()- Get total number of minted tokenstotalMinted()- Alias for totalSupply() (ERC721A compatibility)currentPhase()- Get current minting phase (GTD, WHITELIST, PUBLIC)supportsInterface(bytes4 interfaceId)- Check ERC interface supportgetRoyaltyInfo(uint256 tokenId, uint256 salePrice)- Get royalty information
setPhase(MintPhase phase)- Change minting phase (GTD, WHITELIST, PUBLIC)addToGTDList(address[] calldata addrs)- Add addresses to GTD listaddToWhitelist(address[] calldata addrs)- Add addresses to whitelistpause()- Pause minting (emergency control)unpause()- Resume minting after pausewithdraw()- Withdraw contract funds to ownerbumpRandomness(uint256 extra)- Improve entropy of random generation system
mintedPerAddress(address)- Number of tokens minted per addressisGTDListed(address)- Check if address is in GTD listisWhitelistListed(address)- Check if address is in whitelisttokenTraits(uint256 tokenId)- Get traits of a specific tokenisCombinationMinted(bytes32 hash)- Check if a trait combination has already been minted
GTD_PRICE- Price for GTD phase (0 ETH)WHITELIST_PRICE- Price for whitelist phase (0.0003 ETH)PUBLIC_PRICE- Price for public phase (0.00069 ETH)MAX_SUPPLY- Maximum supply (1069)MAX_MINT_PER_ADDRESS_GTD- Max mint per address in GTD phase (1)MAX_MINT_PER_ADDRESS_WHITELIST- Max mint per address in whitelist phase (3)MAX_MINT_PER_ADDRESS_PUBLIC- Max mint per address in public phase (5)
_generateSeedFromHash(bytes32 hash, uint256 salt)- Generate random seed from hash_generateTraitsFromHash(bytes32 hash)- Generate traits from hash_random(uint256 tokenId, uint256 salt)- Internal random generation function_random(uint256 tokenId, uint256 salt, uint8 max)- Version with maximum limit
_buildAttributes(Traits memory t)- Build JSON attributes for metadata_addAttribute(string memory result, bool first, string memory traitName, string memory traitValue)- Add attribute to metadata_attribute(string memory trait_type, string memory value)- Format individual attribute_base64(bytes memory data)- Encode data to base64 for image URIs
Minted(address indexed minter, uint256 indexed tokenId)- Emitted when minting a tokenWithdrawn(address indexed to, uint256 amount)- Emitted when withdrawing fundsPhaseChanged(MintPhase indexed oldPhase, MintPhase indexed newPhase)- Emitted when changing phase
- Never share private keys - Use dedicated wallets
- Test on testnets - Deploy to Base Sepolia first
- Fund your wallet - Ensure sufficient ETH for gas
- Review contracts - Check generated code before mainnet
- Node.js >= 18
- Hardhat
- Base network RPC URL
- BaseScan API key
- Wallet with ETH for gas
"Stack too deep" errors
- Ensure
viaIR: trueinhardhat.config.js - Reduce number of traits per layer
Environment variable errors
- Use
npx hardhat runinstead ofnode - Check
.envfile configuration
Contract verification fails
- Wait 10-15 seconds after deployment
- Check constructor arguments match
Minting fails
- Check current phase and pricing
- Ensure wallet has sufficient ETH
- Verify contract is not paused
For questions or support:
- Contact: @0x_Quickosss
MIT License
Ready to launch your on-chain NFT collection! π