Mint Stablecoins
Create new tokens by minting them to a specified address. Minting increases the total supply of your stablecoin.
Steps
Create a Stablecoin
Before you can mint tokens, you need to create a stablecoin. Follow the Create a Stablecoin guide to deploy your token.
Once you've created your token, you can proceed to grant the issuer role and mint tokens.
Grant the Issuer Role
Assign the issuer role to the address that will mint tokens. Minting requires the ISSUER_ROLE.
Grant Issuer Role
demoimport React from 'react'
import { Hooks } from 'tempo.ts/wagmi'
import { useQueryClient } from '@tanstack/react-query'
export function GrantIssuerRole() {
const queryClient = useQueryClient()
const tokenAddress = '0x...' // Your token address
const issuerAddress = '0x...' // Address to grant the issuer role
const grant = Hooks.token.useGrantRolesSync({
mutation: {
onSettled() {
queryClient.refetchQueries({ queryKey: ['hasRole'] })
},
},
})
const handleGrantIssuer = async () => {
await grant.mutate({
token: tokenAddress,
roles: ['issuer'],
to: issuerAddress,
feeToken: '0x20c0000000000000000000000000000000000001',
})
}
return (
<button
disabled={grant.isPending}
onClick={handleGrantIssuer}
type="button"
>
{grant.isPending ? 'Granting...' : 'Grant Issuer Role'}
</button>
)
}Mint Tokens to a Recipient
Now that the issuer role is granted, you can mint tokens to any address.
Mint Tokens
demoimport React from 'react'
import { Hooks } from 'tempo.ts/wagmi'
import { useConnection } from 'wagmi'
import { parseUnits, pad, stringToHex } from 'viem'
import { useQueryClient } from '@tanstack/react-query'
export function MintToken() {
const { address } = useConnection()
const queryClient = useQueryClient()
const tokenAddress = '0x...' // Your token address
const [recipient, setRecipient] = React.useState<string>('')
const [memo, setMemo] = React.useState<string>('')
const { data: metadata } = Hooks.token.useGetMetadata({
token: tokenAddress,
})
const mint = Hooks.token.useMintSync({
mutation: {
onSettled() {
queryClient.refetchQueries({ queryKey: ['getBalance'] })
},
},
})
const handleMint = () => {
if (!tokenAddress || !recipient || !metadata) return
mint.mutate({
amount: parseUnits('100', metadata.decimals),
to: recipient as `0x${string}`,
token: tokenAddress,
memo: memo ? pad(stringToHex(memo), { size: 32 }) : undefined,
feeToken: '0x20c0000000000000000000000000000000000001',
})
}
return (
<>
<div>
<label>Recipient address</label>
<input
type="text"
value={recipient}
onChange={(e) => setRecipient(e.target.value)}
placeholder="0x..."
/>
</div>
<div>
<label>Memo (optional)</label>
<input
type="text"
value={memo}
onChange={(e) => setMemo(e.target.value)}
placeholder="INV-12345"
/>
</div>
<button
disabled={!address || mint.isPending}
onClick={handleMint}
type="button"
>
{mint.isPending ? 'Minting...' : 'Mint'}
</button>
</>
)
}Recipes
Burning Stablecoins
To decrease supply, you can burn tokens from your own balance. Burning requires the ISSUER_ROLE and sufficient balance in the caller's account.
Burn Your Token
demoimport React from 'react'
import { Hooks } from 'tempo.ts/wagmi'
import { useConnection } from 'wagmi'
import { parseUnits, pad, stringToHex } from 'viem'
import { useQueryClient } from '@tanstack/react-query'
export function BurnToken() {
const { address } = useConnection()
const queryClient = useQueryClient()
const tokenAddress = '0x...' // Your token address
const [memo, setMemo] = React.useState<string>('')
const { data: metadata } = Hooks.token.useGetMetadata({
token: tokenAddress,
})
const burn = Hooks.token.useBurnSync({
mutation: {
onSettled() {
queryClient.refetchQueries({ queryKey: ['getBalance'] })
},
},
})
const handleBurn = () => {
if (!tokenAddress || !address || !metadata) return
burn.mutate({
amount: parseUnits('100', metadata.decimals),
token: tokenAddress,
memo: memo ? pad(stringToHex(memo), { size: 32 }) : undefined,
feeToken: '0x20c0000000000000000000000000000000000001',
})
}
return (
<>
<div>
<label>Memo (optional)</label>
<input
type="text"
value={memo}
onChange={(e) => setMemo(e.target.value)}
placeholder="INV-12345"
/>
</div>
<button
disabled={!address || burn.isPending}
onClick={handleBurn}
type="button"
>
{burn.isPending ? 'Burning...' : 'Burn'}
</button>
</>
)
}Best Practices
Monitor Supply Caps
If your token has a supply cap set, any mint() or mintWithMemo() call that would exceed the cap will revert with SupplyCapExceeded(). You must either:
- Burn tokens to reduce total supply below the cap
- Increase the supply cap (requires
DEFAULT_ADMIN_ROLE) - Remove the cap entirely by setting it to
type(uint256).max
Use getMetadata to check your token's total supply before minting.
Role Separation
Assign the issuer role to dedicated treasury or minting addresses separate from your admin address. This enhances security by limiting the privileges of any single address.