Deploy Native Token Transfers (NTT) to EVM Chains#
Native Token Transfers (NTT) enable seamless multichain transfers of ERC-20 tokens on supported EVM-compatible chains using Wormhole's messaging protocol. Instead of creating wrapped tokens, NTT allows native assets to move across chains while maintaining their original properties.
This guide walks you through deploying NTT on EVM chains, including setting up dependencies, configuring token compatibility, and using the NTT CLI to deploy in hub-and-spoke or burn-and-mint mode.
Deploy Your Token and Ensure Compatibility#
If you still need to do so, deploy the token contract to the destination or spoke chains.
Requirements for Token Deployment#
Wormhole’s NTT framework supports two deployment models: burn-and-mint and hub-and-spoke. Both require an ERC-20 token (new or existing).
Burn-and-Mint
Tokens must implement the following non-standard ERC-20 functions:
burn(uint256 amount)
mint(address account, uint256 amount)
These functions aren't part of the standard ERC-20 interface. Refer to the INttToken
interface for all required functions, errors, and events.
INttToken
Interface
// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
interface INttToken {
/// @notice Error when the caller is not the minter.
/// @dev Selector 0x5fb5729e.
/// @param caller The caller of the function.
error CallerNotMinter(address caller);
/// @notice Error when the minter is the zero address.
/// @dev Selector 0x04a208c7.
error InvalidMinterZeroAddress();
/// @notice Error when insufficient balance to burn the amount.
/// @dev Selector 0xcf479181.
/// @param balance The balance of the account.
/// @param amount The amount to burn.
error InsufficientBalance(uint256 balance, uint256 amount);
/// @notice The minter has been changed.
/// @dev Topic0
/// 0x0b5e7be615a67a819aff3f47c967d1535cead1b98db60fafdcbf22dcaa8fa5a9.
/// @param newMinter The new minter.
event NewMinter(address previousMinter, address newMinter);
// NOTE: the `mint` method is not present in the standard ERC20 interface.
function mint(address account, uint256 amount) external;
// NOTE: the `setMinter` method is not present in the standard ERC20 interface.
function setMinter(address newMinter) external;
// NOTE: NttTokens in `burn` mode require the `burn` method to be present.
// This method is not present in the standard ERC20 interface, but is
// found in the `ERC20Burnable` interface.
function burn(uint256 amount) external;
}
You’ll also need to set mint authority to the relevant NttManager
contract. Example deployment scripts are available in the example-ntt-token
GitHub repository.
Hub-and-Spoke Mode
Tokens only need to be ERC-20 compliant. The hub chain serves as the source of truth for supply consistency, while only spoke chains need to support minting and burning. For example, if Ethereum is the hub and Polygon is a spoke:
- Tokens are locked on Ethereum
- Tokens are minted or burned on Polygon
This setup maintains a consistent total supply across all chains.
NTT Manager Deployment Parameters#
This table compares the configuration parameters available when deploying the NTT Manager using the CLI versus a manual deployment with a Forge script. It highlights which options are configurable via each method, whether values are auto-detected or hardcoded, and includes additional comments to help guide deployment decisions.
Parameter |
Forge Script | CLI | Both | Comments |
---|---|---|---|---|
token |
Input | --token <address> |
Yes | |
mode |
Input | --mode <locking/burning> |
Yes | Key decision: hub-and-spoke or mint-and-burn |
wormhole |
Input | Auto-detected via SDK/ChainContext |
Similar | |
wormholeRelayer |
Input | Auto-detected via on-chain query/SDK | Similar | |
specialRelayer |
Input | Not exposed | No | Take into consideration if using custom relaying. Not recommended |
decimals |
Input, overridable | Auto-detected via token contract, not overridable | Similar | |
wormholeChainId |
Queried from Wormhole contract | --chain (network param, mapped internally) |
Yes | |
rateLimitDuration |
Hardcoded (86400 ) |
Hardcoded (86400 ) |
Yes | Rate limit duration. A day is normal but worth deciding |
shouldSkipRatelimiter |
Hardcoded (false ) |
Hardcoded (false ) |
Yes | If rate limit should be disabled (when the manager supports it) |
consistencyLevel |
Hardcoded (202 ) |
Hardcoded (202 ) |
Yes | 202 (finalized) is the standard — lower is not recommended |
gasLimit |
Hardcoded (500000 ) |
Hardcoded (500000 ) |
Yes | |
outboundLimit |
Computed | Auto-detected/Hardcoded | Similar | Relative to rate limit |
Deploy NTT#
Before deploying NTT contracts on EVM chains, you need to scaffold a project and initialize your deployment configuration.
Install the NTT CLI and Scaffold a New Project
Before proceeding, make sure you have the NTT CLI installed and a project initialized.
Follow these steps (or see the Get Started guide):
-
Install the NTT CLI:
curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash
Verify installation:
-
Initialize a new NTT project:
-
Create the deployment config**:
This generates a
deployment.json
file where your deployment settings will be stored.
Once you've completed those steps, return here to proceed with adding your EVM chains and deploying contracts.
Ensure you have set up your environment correctly:
Add each chain you'll be deploying to. The following example demonstrates configuring NTT in burn-and-mint mode on Ethereum Sepolia and Arbitrum Sepolia:
# Set scanner API Keys as environment variables
export SEPOLIA_SCAN_API_KEY=INSERT_ETHERSCAN_SEPOLIA_API_KEY
export ARBITRUMSEPOLIA_SCAN_API_KEY=INSERT_ARBISCAN_SEPOLIA_API_KEY
# Add each chain
# The contracts will be automatically verified using the scanner API keys above
ntt add-chain Sepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS
ntt add-chain ArbitrumSepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS
While not recommended, you can pass the -skip-verify
flag to the ntt add-chain
command if you want to skip contract verification.
The ntt add-chain
command takes the following parameters:
- Name of each chain
- Version of NTT to deploy (use
--latest
for the latest contract versions) - Mode (either
burning
orlocking
) - Your token contract address
The NTT CLI prints detailed logs and transaction hashes, so you can see exactly what's happening under the hood.
Configure NTT#
The NTT CLI takes inspiration from git. You can run:
ntt status
- checks whether yourdeployment.json
file is consistent with what is on-chain-
ntt pull
- syncs yourdeployment.json
file with the on-chain configuration and set up rate limits with the appropriate number of decimals, depending on the specific chain. For example:For Solana, the limits are set with 9 decimal places:
For Sepolia (Ethereum Testnet), the limits are set with 18 decimal places:
This initial configuration ensures that the rate limits are correctly represented for each chain's token precision
-
ntt push
- syncs the on-chain configuration with local changes made to yourdeployment.json
file
After you deploy the NTT contracts, ensure that the deployment is properly configured and your local representation is consistent with the actual on-chain state by running ntt status
and following the instructions shown on the screen.
Set Token Minter to NTT Manager#
The final step in the deployment process is to set the NTT Manager as a minter of your token on all chains you have deployed to in burning
mode. When performing a hub-and-spoke deployment, it is only necessary to set the NTT Manager as a minter of the token on each spoke chain.
Note
The required NTT Manager address can be found in the deployment.json
file.
-
If you followed the
INttToken
interface, you can execute thesetMinter(address newMinter)
function -
If you have a custom process to manage token minters, you should now follow that process to add the corresponding NTT Manager as a minter
By default, NTT transfers to EVM blockchains support automatic relaying via the Wormhole relayer, which doesn't require the user to perform a transaction on the destination chain to complete the transfer.
Important
To proceed with testing and find integration examples, check out the NTT Post Deployment page.