permit are built into the chain, so you don’t build, audit, or maintain that logic yourself.
How B20 works
Every B20 token is created by the singleton B20 Factory, which returns a fully configured token in a single transaction. Two variants cover the common cases:- Asset — configurable decimals (6–18), plus a rebase multiplier, onchain announcements, and batched issuance. Use it for real-world assets, equities, and long-tail tokens.
- Stablecoin — fixed at 6 decimals with a self-declared ISO currency code. Use it for fiat-backed tokens.
permit. For the complete ABIs and precompile behavior, see the B20 native token standard spec.
The rest of this page walks through launching a B20 Asset token: create it, mint its initial supply, and verify the balance onchain. To accept the token as payment in an app, continue with Accept a B20 payment.
Before you begin
You need Base’s Foundry build (base-forge, base-cast, base-anvil). Install the Beryl-compatible v1.1.1 release via base-foundryup:
Terminal
Standard
forge cannot simulate calls to B20 precompile addresses (they hold no contract bytecode) and aborts with call to non-contract address. Base’s base-forge registers the precompiles into its EVM. It installs alongside your existing Foundry toolchain without overwriting it — use base-forge, base-cast, and base-anvil for all commands in this guide.Verify the Activation Registry is enabled
Terminal
Set up Foundry
Terminal
base = true flag to foundry.toml (under [profile.default]). base = true tells Base’s forge build to run the B20 precompiles inside its EVM, so the deploy script’s local simulation can call the factory:
foundry.toml
The interfaces compile with any Solidity
>=0.8.20 <0.9.0.Set up TypeScript and CLI clients
The task guides useviem@2.55.11 for application code and base-cast@v1.1.1 for operational commands. Install viem in a separate project and keep signing keys in environment variables:
Terminal
clients.ts
jq so policy-creation scripts can read PolicyCreated from transaction receipts:
.env
Choose a network
Pick a network with the B20 precompiles active, then create a.env inside your b20-quickstart project directory. For full network details, see Connecting to Base.
- Mainnet
- Base Sepolia
- Vibenet
- Local (base-anvil)
.env
If you don’t have an account,
base-cast wallet new prints a fresh address and key.Terminal
The command prints a non-zero balance. This account signs the deploy and the mint, and receives the minted supply.
Create your token
The factory’s single entry point iscreateB20(variant, salt, params, initCalls):
variant:ASSETorSTABLECOIN. This guide usesASSET.salt: caller-chosen entropy that fixes the deterministic token address.params: ABI-encoded name, symbol, initial admin, and decimals.initCalls: optional batch of config calls applied at creation.
1
Write the create script
Use
B20FactoryLib to encode params and initCalls. Create script/CreateToken.s.sol:script/CreateToken.s.sol
Asset decimals are fixed at creation and must be in
[6, 18]. The supply cap is optional; the no-cap sentinel is type(uint128).max (the cap can never exceed uint128.max).Want a stablecoin instead?
Want a stablecoin instead?
Use the Everything else in this guide — roles, supply cap, minting, and verification — works identically.
STABLECOIN variant and its params encoder. A stablecoin fixes decimals at 6 and carries an immutable ISO currency code (uppercase A–Z) instead of a configurable decimals value:2
Deploy the factory call
Terminal
0xB20f000000000000000000000000000000000000 (the same on every network); the tokens it creates start 0xB200...:If you see
TokenAlreadyExists, the salt keccak256("my-first-b20") is already registered on this network or anvil instance. Either restart base-anvil for a fresh state, or change the salt in the script to a unique value.Output
3
Capture the token address
Save the address to an environment variable so the next step needs no copy-paste. The broadcast artifact holds the return value:Appending to
Terminal
.env keeps TOKEN_ADDRESS available in later steps, even in a new terminal session.The broadcast path includes the chain ID, which the
CHAIN_ID value in your .env supplies: 84532 for Sepolia, 84538453 for Vibenet, 31337 for local base-anvil.Mint and verify
Minting requiresMINT_ROLE, which initCalls granted to your account.
1
Mint supply
Terminal
base-cast send prints a receipt with status 1 (success).2
Confirm the balance
Terminal
The token now holds minted supply onchain. Search
$TOKEN_ADDRESS in the explorer to view it.What you built
In this guide you:- Created a B20 Asset token with one
createB20call - Configured its admin, minter, and supply cap atomically via
initCalls - Minted supply
- Verified the balance onchain
Next steps
- Accept a B20 payment in an app: wire this token into a checkout flow that tags each payment with an order ID and reconciles it from onchain events.
- Gate transfers or mints with PolicyRegistry policies, add granular pause, or manage roles. See the B20 token standard.