Automatic Token Migration with Deadline and Burning

Imagine: you've deployed a new ERC-20 token with improved tokenomics or fixed a critical vulnerability in an old contract. Now you need all holders to switch to the new token. Without a deadline mechanism, some users never migrate—old tokens remain in circulation, the protocol must hold liquidity fo

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1450
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1308
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1003
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1269
  • image_logo-advance_0.webp
    B2B Advance company logo design
    717
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1008

Imagine: you've deployed a new ERC-20 token with improved tokenomics or fixed a critical vulnerability in an old contract. Now you need all holders to switch to the new token. Without a deadline mechanism, some users never migrate—old tokens remain in circulation, the protocol must hold liquidity forever, and the market suffers from parallel circulation of two assets. We develop migration systems that solve this problem completely: automatic migration with deadline and burning. Across 50+ projects, we've developed a standard architecture covering 90% of scenarios. Gas optimization can save holders up to $0.50 per transaction and the project up to $2,000 on contract architecture. Evaluate your project in one day—just contact us.

How the Migration System Works: Contract Architecture

The system consists of three participants: OldToken — the existing ERC-20, NewToken — the new token with a mint function or sufficient supply, and MigrationContract — an intermediary contract managing the swap, deadline, and burning.

// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable2Step.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; contract TokenMigration is Ownable2Step, ReentrancyGuard { IERC20 public immutable oldToken; IERC20 public immutable newToken; uint256 public immutable migrationDeadline; uint256 public immutable migrationRatio; // новых токенов за 1 старый (18 decimals) uint256 public totalMigrated; bool public unmigatedBurned; event Migrated(address indexed user, uint256 oldAmount, uint256 newAmount); event UnmigratedBurned(uint256 amount); constructor( address _oldToken, address _newToken, uint256 _deadline, // Unix timestamp uint256 _ratio // 1e18 = 1:1, 2e18 = 2 новых за 1 старый ) Ownable2Step(msg.sender) { require(_deadline > block.timestamp + 30 days, "Deadline too soon"); oldToken = IERC20(_oldToken); newToken = IERC20(_newToken); migrationDeadline = _deadline; migrationRatio = _ratio; } function migrate(uint256 amount) external nonReentrant { require(block.timestamp < migrationDeadline, "Migration closed"); require(amount > 0, "Zero amount"); uint256 newAmount = amount * migrationRatio / 1e18; require(newAmount > 0, "Below minimum"); totalMigrated += amount; // Получаем старые токены от пользователя oldToken.transferFrom(msg.sender, address(this), amount); // Выдаём новые токены newToken.transfer(msg.sender, newAmount); emit Migrated(msg.sender, amount, newAmount); } } 

Why Ownable2Step Is Important for Migration Contracts?

Regular Ownable allows transferring ownership in one step: transferOwnership(newOwner). If you mis-enter the address, the contract is lost forever. Ownable2Step (OpenZeppelin documentation) requires the new owner to accept rights in a separate transaction. According to OpenZeppelin docs, two-step ownership prevents accidental loss of control. For a contract managing token migration with a deadline, this is critical—a mistake could cost control over the entire migration.

Burn Mechanism After Deadline

After the deadline expires, all unmigrated old tokens that have accumulated on the contract must be burned. Also, unused new tokens should be returned or burned.

function burnUnmigrated() external onlyOwner { require(block.timestamp >= migrationDeadline, "Deadline not reached"); require(!unmigatedBurned, "Already burned"); unmigatedBurned = true; // Сжигаем старые токены, которые пришли через migrate() uint256 oldBalance = oldToken.balanceOf(address(this)); if (oldBalance > 0) { IBurnable(address(oldToken)).burn(oldBalance); // Если старый токен не имеет burn() — отправляем на dead address // oldToken.transfer(address(0xdead), oldBalance); } // Возвращаем нераспределённые новые токены в treasury uint256 newBalance = newToken.balanceOf(address(this)); if (newBalance > 0) { newToken.transfer(owner(), newBalance); } emit UnmigratedBurned(oldBalance); } 

What if the Old Token Doesn't Have a burn() Function?

Most legacy tokens lack a burn function. Options:

  1. Send to 0x000...dEaD — unofficial burn address, tokens permanently inaccessible.
  2. Send to address(0) — only if the token allows transfer to zero address (many check to != address(0)).
  3. Custom burn function in MigrationContract via IUpgradeableToken(oldToken).burnFrom() — only if the migration contract has BURNER_ROLE.

Comparison of Burning Options for Tokens Without burn

Method Reversibility Address Risks
Transfer to dead address No 0x000...dEaD Unofficial, could be cleared
Transfer to address(0) No 0x000...000 Many contracts check != 0
Call burnFrom with role Yes, if role revoked Internal burn Requires role setup

Comparison of Migration Methods

Method Gas for User Approve Required? Deadline Risk Suitable For
Direct (transferFrom) High (2 tx) Yes Stale tokens remain with user Simple cases, ERC-20 with burn
Snapshot + Merkle Proof Low (1 tx) No Tokens not withdrawn, trust required Post-hacks, upgrades without time window
Burning via dead address Medium (1 tx) No Irreversible When no burn function

How Snapshot Migration Works (Merkle Proof)

If migration is based on a snapshot (balances at a specific block before deploying the new contract), users do not send old tokens—they prove entitlement to new tokens via Merkle Proof. This reduces gas costs by 40-60% compared to direct migration. Direct migration with transferFrom requires two transactions—approve and migrate. Snapshot migration with Merkle Proof is 2x faster, needing only one claim transaction, and gas costs are reduced 2-3x. We use the OpenZeppelin library MerkleProof for verification.

contract SnapshotMigration is Ownable2Step { bytes32 public immutable merkleRoot; mapping(address => bool) public claimed; constructor(bytes32 _merkleRoot, uint256 _deadline) { merkleRoot = _merkleRoot; migrationDeadline = _deadline; } function claim(uint256 amount, bytes32[] calldata proof) external { require(block.timestamp < migrationDeadline, "Expired"); require(!claimed[msg.sender], "Already claimed"); bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount)); require(MerkleProof.verify(proof, merkleRoot, leaf), "Invalid proof"); claimed[msg.sender] = true; newToken.transfer(msg.sender, amount); emit Claimed(msg.sender, amount); } } 

Generate the Merkle Tree off-chain using @openzeppelin/merkle-tree or a custom script based on a balance snapshot. The snapshot is taken via The Graph subgraph or archival node query.

How Tokens in Vesting Contracts Are Handled During Migration

If old tokens are held in vesting contracts, they cannot be migrated directly by users. Options:

  1. A special admin function that migrates tokens directly from the vesting contract (requires integration with the specific vesting contract).
  2. Automatic migration via Tenderly Web3 Actions or a keeper after vesting expires.

User Notifications and Progress Monitoring

The contract should emit events with sufficient information to build a dashboard:

event MigrationProgress( uint256 totalMigrated, uint256 totalOldSupply, uint256 deadline, uint256 timestamp ); 

A subgraph on The Graph indexes events and provides a GraphQL API for the frontend: percentage of migration completed, number of unique addresses migrated, kinetics over time.

An important practical point: large holders (>1% supply) need to be notified directly before the public migration launch. Exchanges, protocols, funds—they may have internal processes that take time. The deadline should allow at least 90 days even for simple migrations.

What We Deliver: Full Package

The work includes:

  • Development of migration smart contracts (Solidity 0.8.x, OpenZeppelin).
  • Integration with the existing token (OldToken) and deployment of the new one (NewToken).
  • Configuration of deadline and burning mechanism.
  • Development of snapshot-based migration (Merkle Proof) if needed.
  • Subgraph for monitoring and frontend dashboard (React + The Graph).
  • Contract audit with report (in partnership with certified auditors).
  • Post-migration support for 30 days.
  • Documentation for users and integration instructions.

Timelines and Cost

Development timelines: 3-5 business days for a basic migration system, 7-10 days for snapshot-based with Merkle Proof and subgraph. Cost is calculated individually—request a commercial proposal. Evaluate your project for free—our engineers with 10+ years of experience in blockchain development will analyze your architecture and suggest the optimal solution. Request a consultation right now.