On-chain typeface and NFT project featuring unique colors and editable text rendered as SVGs on-chain.
capsules/
├── contracts/ # Solidity smart contracts
│ ├── CapsulesTypeface.sol # Simple typeface contract (no token integration)
│ ├── CapsulesTypefaceExperience.sol # Typeface with CapsuleToken integration
│ ├── CapsuleToken.sol # NFT token contract
│ ├── CapsuleRenderer.sol # SVG rendering logic
│ ├── CapsuleMetadata.sol # Metadata generation
│ ├── Typeface.sol # Base typeface contract
│ ├── TypefaceExpandable.sol # Expandable typeface base
│ └── interfaces/ # Contract interfaces
├── scripts/ # Deployment and utility scripts
│ ├── deploy-typeface.ts # Deploy CapsulesTypeface (no token)
│ ├── store-fonts.ts # Store font data on-chain
│ ├── deploy.ts # Deploy full system (Experience version)
│ └── utils.ts # Shared utilities
├── test/ # Contract tests
├── deployments/ # Deployment artifacts (see below)
├── fonts.ts # Base64-encoded font data
├── pureColors.ts # Pure color definitions
└── hardhat.config.ts # Hardhat configuration
Deployment artifacts are stored in the deployments/ directory, organized by contract type and network:
deployments/typeface/
├── mainnet/
│ ├── CapsulesTypeface.json # Contract ABI and address
│ └── CapsulesTypeface.arguments.js # Constructor arguments
├── base/
├── optimism/
├── arbitrum/
├── sepolia/
├── baseSepolia/
├── optimismSepolia/
└── arbitrumSepolia/
deployments/
├── mainnet/
│ ├── CapsulesTypefaceExperience.json
│ ├── CapsuleToken.json
│ ├── CapsuleRenderer.json
│ └── CapsuleMetadata.json
└── [other networks...]
The CapsulesTypefaceExperience contract was originally deployed to Ethereum mainnet as "CapsulesTypeface". This version includes full integration with:
- CapsuleToken: NFT contract that mints tokens when fonts are stored
- CapsuleRenderer: Renders Capsules as SVGs
- CapsuleMetadata: Generates token metadata
- Patron System: Tracks which address stored each font
This integrated system creates an "experience" where storing fonts on-chain mints special NFTs to the patron.
CapsulesTypeface—a simplified version of the (now) CapsulesTypefaceExperience contract without any token integration—is deployed to other chains (Base, Optimism, Arbitrum, testnets, etc.). This allows the typeface to be used across multiple chains without the complexity of the full NFT system.
Key Differences:
- CapsulesTypeface: Simple, standalone typeface contract
- CapsulesTypefaceExperience: Full system with NFT minting and patron tracking
- Node.js v16+
- Hardhat
- A
pk.txtfile in the root directory containing your deployer private key
npm installThe project supports the following networks (configured in hardhat.config.ts):
Mainnets:
mainnet- Ethereumbase- Baseoptimism- Optimismarbitrum- Arbitrum
Testnets:
sepolia- Ethereum SepoliabaseSepolia- Base SepoliaoptimismSepolia- Optimism SepoliaarbitrumSepolia- Arbitrum Sepolia
Deploys the simple typeface contract and sets font hashes.
npx hardhat run scripts/deploy-typeface.ts --network <network-name>Example:
npx hardhat run scripts/deploy-typeface.ts --network base
npx hardhat run scripts/deploy-typeface.ts --network optimismSepoliaWhat it does:
- Deploys
CapsulesTypefacecontract - Sets source hashes for all fonts using
setSourceHashes() - Saves deployment artifacts to
deployments/typeface/<network>/
Output:
deployments/typeface/<network>/CapsulesTypeface.json- Contract ABI and addressdeployments/typeface/<network>/CapsulesTypeface.arguments.js- Constructor arguments
Constants used:
OPERATOR_ADDRESS: in order to allow the deployer wallet (from pk.txt) to store fonts usingscripts/store-fonts.ts, this must be the deployer addressDONATION_ADDRESS: funds receiver for the Typeface contract
Stores the actual font data on-chain for a previously deployed contract.
npx hardhat run scripts/store-fonts.ts --network <network-name>Example:
npx hardhat run scripts/store-fonts.ts --network base
npx hardhat run scripts/store-fonts.ts --network optimismSepoliaWhat it does:
- Reads deployment info from
deployments/typeface/<network>/CapsulesTypeface.json - Connects to the deployed contract
- For each font (100, 200, 300, etc.):
- Checks if already stored (skips if yes)
- Converts base64 font data to bytes
- Calls
setSource()with the font data - Shows gas usage and progress
- Transfers operator role to
OWNER_ADDRESSafter all fonts are stored
Features:
- Idempotent: Can be run multiple times, skips already-stored fonts
- Resumable: If interrupted, re-run to continue where it left off
- Progress tracking: Shows real-time progress with gas usage
- Network-specific gas limits: Automatically adjusts for each network
Gas Limits by Network:
- Sepolia: 15M gas per transaction
- Other networks: 25M gas per transaction
Note: Storing fonts is expensive! Each font requires a separate transaction with significant gas costs.
For deploying the full integrated system with token functionality:
npx hardhat run scripts/deploy.ts --network <network-name>What it deploys:
CapsuleMetadataCapsulesTypefaceExperience(with token integration)CapsuleRendererCapsuleToken
Note: This is the original system deployed on Ethereum mainnet.
npx hardhat compilenpx hardhat testAfter deployment, verify on block explorers:
npx hardhat verify --network <network-name> <contract-address> <constructor-args>- Requires minimum
maxPriorityFeePerGasof 1 gwei - Scripts automatically handle this for Optimism networks
- Lower block gas limit (~16.7M)
- Scripts use 15M gas limit to stay under cap
- Standard gas limits apply (25M)
- Base uses public RPC endpoints
- Arbitrum has higher gas limits but cost is tied to L1
Font data is stored in fonts.ts as base64-encoded strings:
export const FONTS = {
100: "d09GRk9UVE8AAC8M...", // Thin
200: "d09GRk9UVE8AAC8Y...", // Extra Light
300: "d09GRk9UVE8AADAo...", // Light
// ... etc
};When storing on-chain, the base64 strings are converted to bytes using Buffer.from(fontData), which treats each character as a byte. This ensures the data can be read back as base64 directly from the contract.
# 1. Deploy contract
npx hardhat run scripts/deploy-typeface.ts --network base
# 2. Store fonts (can be done later when gas is cheaper)
npx hardhat run scripts/store-fonts.ts --network base
# 3. (Optional) Verify on block explorer
npx hardhat verify --network base <contract-address> \
"0x63A2368F4B509438ca90186cb1C15156713D5834" \
"0xE1054192960FA3c6178E90f6Bc14cbe6146413e4"# Deploy to multiple chains
npx hardhat run scripts/deploy-typeface.ts --network base
npx hardhat run scripts/deploy-typeface.ts --network optimism
npx hardhat run scripts/deploy-typeface.ts --network arbitrum
# Store fonts on each chain (can be parallelized)
npx hardhat run scripts/store-fonts.ts --network base
npx hardhat run scripts/store-fonts.ts --network optimism
npx hardhat run scripts/store-fonts.ts --network arbitrumGPL-3.0