Skip to main content
This guide covers the technical steps for deploying a MetaToken spoke contract on a supported chain. The MetaToken standard is open and permissionless, allowing anyone to deploy spoke contracts using the proxy pattern for upgradeability. Prerequisites: You must have a MetaToken hub already deployed on your canonical token chain. See the Deploying MetaToken Hub guide first if you haven’t deployed a hub yet. Deployment involves multi-chain coordination, domain configuration, and ongoing operational overhead including message monitoring, upgrades, and gas management. We strongly recommend contacting Caldera for end-to-end production deployments. See Next Steps below for more information.

Source Code

All MetaToken contracts are open source and available in the metatoken-contracts repository. The contracts include comprehensive inline documentation. The spoke implementation is located at MetaERC20Spoke.sol.

Deployment Architecture

MetaToken spokes use the OpenZeppelin TransparentUpgradeableProxy pattern for upgradeability. The deployment consists of:
  1. TransparentUpgradeableProxy: The proxy contract that users interact with
  2. ProxyAdmin: Controls proxy upgrades, owned by your admin address
  3. MetaERC20Spoke: The implementation contract with token logic
The proxy pattern allows you to upgrade the implementation logic while maintaining the same contract address and token balances.

Configuration Parameters

You will need to provide the following initialization parameters for the MetaERC20Spoke contract:
ParameterTypeDescription
metalayerDomainuint32The Metalayer domain ID for the chain you’re deploying to. This is a unique identifier assigned to each chain in the Metalayer network (e.g., 33139 for Apechain, 56 for BSC). See contract deployments for domain IDs.
hubDomainuint32The Metalayer domain ID where your MetaERC20Hub is deployed. This must match the hub’s localDomain parameter. The hub routes high-value transfers and processes unlock requests back to the canonical chain.
metaERC20Versionuint8MetaToken protocol version. Currently 1. Must match the hub’s version to ensure message compatibility across all spokes.
metalayerRouteraddressThe MetalayerRouter contract address on this chain. See contract deployments.
tokenNamestringERC20 token name (e.g., “My Token”).
tokenSymbolstringERC20 token symbol (e.g., “MTK”).
tokenDecimalsuint8Token decimals. Must exactly match the hub’s token decimals. Typically 18 for standard ERC20 tokens.
securityThresholduint256Amount (in token base units) above which transfers are routed through the hub for validator review instead of direct spoke-to-spoke. Setting to 0 forces all transfers through hub. Contact Caldera for recommendations based on your token’s value and security model.
ttlWindowuint256Time-to-live window for transfer records in seconds. Must coordinate with hub TTL settings to ensure transfers don’t expire prematurely. Typical values range from 1-7 days (86400-604800 seconds).
owneraddressAdmin address that receives DEFAULT_ADMIN_ROLE and ADMIN_ROLE. Should be a multisig or secure EOA.

Deployment Steps

1. Deploy the Proxy

Deploy a TransparentUpgradeableProxy contract. The proxy will be the permanent address that users interact with for the token.
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

// Deploy proxy with empty implementation initially
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
    address(0),           // initial implementation (can be address(0))
    proxyAdminAddress,    // ProxyAdmin contract address
    ""                    // empty initialization data
);
You’ll also need a ProxyAdmin contract to manage upgrades:
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";

ProxyAdmin proxyAdmin = new ProxyAdmin(ownerAddress);

2. Deploy the Implementation

Deploy the MetaERC20Spoke implementation contract.
import {MetaERC20Spoke} from "src/token/MetaERC20Spoke.sol";

MetaERC20Spoke implementation = new MetaERC20Spoke();
You will need all dependencies installed:
  • OpenZeppelin Contracts (Upgradeable)
  • Hyperlane Core Contracts

3. Point Proxy to Implementation

Use the ProxyAdmin to upgrade the proxy to point to your MetaERC20Spoke implementation and initialize it with the configuration parameters listed above.
// Upgrade and initialize the proxy
proxyAdmin.upgradeAndCall(
    ITransparentUpgradeableProxy(address(proxy)),
    address(implementation),
    initializationData
);
The spoke is now deployed and initialized at the proxy address.

4. Configure the Spoke

After deploying your spoke, configure domain mappings to enable cross-chain transfers. Register spoke on hub: Call setDomainAddressBatch on your MetaERC20Hub to register this spoke’s address.
hub.setDomainAddressBatch(
    [spokeDomain],
    [spokeAddress.addressToBytes32()]
);
Register hub on spoke: Call setDomainAddressBatch on your spoke to register the hub’s address.
spoke.setDomainAddressBatch(
    [hubDomain],
    [hubAddress.addressToBytes32()]
);
Register other spokes (optional): For direct spoke-to-spoke transfers, register each spoke’s address on every other spoke contract.

5. Test the Deployment

Initiate a small test transfer from hub to spoke:
hub.transferRemote{value: gasFee}(
    spokeDomain,
    recipientAddress.addressToBytes32(),
    smallAmount
);
Monitor the Hyperlane message delivery and verify the spoke mints the correct amount to the recipient.

Next Steps

Self-deploying MetaToken spokes involves significant ongoing operational complexity. Caldera’s managed MetaToken deployments provide:
  • Deterministic Addressing: Automated deployment tooling ensures consistent contract addresses across all chains
  • Ongoing Operations: Message monitoring, implementation upgrade coordination across all chains, and 24/7 incident response
  • Gas & State Management: Interchain Gas Paymaster funding, TTL pruning, and storage optimization
  • Production Support: Direct access to Caldera’s infrastructure and protocol teams