Skip to main content

Burn & Mint Token

Deploy a cross-chain ERC20 that burns on the source chain and mints on the destination. Total supply stays constant — tokens are destroyed on one side and created on the other.

Use this when you control the token. If you need to bridge a token you don't control (like USDC), see Lock & Release.

Choosing a Bridge Pattern
PatternToken controlLiquidity neededDestination token
Burn & MintYou control itNoSame token (minted)
Lock & MintYou don't control itNoWrapped/synthetic version
Lock & ReleaseYou don't control itYes, pre-fundedOriginal token

Prerequisites

  • A working Hardhat project with VIA contracts — complete the Hello World guide first
  • Testnet tokens on two chains — see Testnet Tokens

Step 1: Copy the Contract

Copy VIAMintBurnTokenMinimal.sol from the Contract Source page into your contracts/ directory. See the full reference for API details.


Step 2: Deploy

Create scripts/deploy-token.ts:

import { ethers } from "hardhat";

async function main() {
const Token = await ethers.getContractFactory("VIAMintBurnTokenMinimal");
const token = await Token.deploy("My Token", "MTK", 1000000);
await token.waitForDeployment();
console.log("Deployed to:", await token.getAddress());
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
npx hardhat run scripts/deploy-token.ts --network sepolia
npx hardhat run scripts/deploy-token.ts --network amoy

Save both addresses.


Step 3: Configure

Same pattern as Hello World — Step 7. On each chain, call setMessageGateway() and setMessageEndpoints() pointing at the peer contract.


Step 4: Bridge Tokens

Create scripts/bridge.ts:

import { ethers } from "hardhat";

const TOKEN_ADDRESS = ""; // your contract on source chain
const DEST_CHAIN_ID = 80002; // Amoy
const RECIPIENT = ""; // recipient address on destination chain
const AMOUNT = ethers.parseEther("100");

async function main() {
const token = await ethers.getContractAt("VIAMintBurnTokenMinimal", TOKEN_ADDRESS);

const recipientBytes32 = ethers.zeroPadValue(RECIPIENT, 32);

console.log("Bridging", ethers.formatEther(AMOUNT), "tokens...");
const tx = await token.bridge(
recipientBytes32,
DEST_CHAIN_ID,
AMOUNT,
{ value: ethers.parseEther("0.001") }
);
await tx.wait();
console.log("TX:", tx.hash);
console.log("Tokens burned. Wait 1-5 minutes for mint on destination.");
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
npx hardhat run scripts/bridge.ts --network sepolia
caution

Burns are irreversible. If destination messageProcess() fails, source tokens are already burned. Recovery requires the owner to manually mint replacement tokens.


Next Steps