> ## Documentation Index
> Fetch the complete documentation index at: https://docs.caldera.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploying MetaToken Spoke

> Guide for self-service MetaToken spoke deployment

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](/metalayer/protocol/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](#next-steps) below for more information.

## Source Code

All MetaToken contracts are open source and available in the [metatoken-contracts](https://github.com/ConstellationCrypto/metatoken-contracts) repository. The contracts include comprehensive inline documentation.

The spoke implementation is located at [MetaERC20Spoke.sol](https://github.com/ConstellationCrypto/metatoken-contracts/blob/main/src/token/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:

| Parameter           | Type      | Description                                                                                                                                                                                                                                                               |
| ------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `metalayerDomain`   | `uint32`  | The 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](/metalayer/resources/contract-deployments) for domain IDs.      |
| `hubDomain`         | `uint32`  | The 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.                                                            |
| `metaERC20Version`  | `uint8`   | MetaToken protocol version. Currently `1`. Must match the hub's version to ensure message compatibility across all spokes.                                                                                                                                                |
| `metalayerRouter`   | `address` | The MetalayerRouter contract address on this chain. See [contract deployments](/metalayer/resources/contract-deployments).                                                                                                                                                |
| `tokenName`         | `string`  | ERC20 token name (e.g., "My Token").                                                                                                                                                                                                                                      |
| `tokenSymbol`       | `string`  | ERC20 token symbol (e.g., "MTK").                                                                                                                                                                                                                                         |
| `tokenDecimals`     | `uint8`   | Token decimals. Must exactly match the hub's token decimals. Typically `18` for standard ERC20 tokens.                                                                                                                                                                    |
| `securityThreshold` | `uint256` | Amount (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. |
| `ttlWindow`         | `uint256` | Time-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).                                                                       |
| `owner`             | `address` | Admin 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.

```solidity theme={null}
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:

```solidity theme={null}
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";

ProxyAdmin proxyAdmin = new ProxyAdmin(ownerAddress);
```

### 2. Deploy the Implementation

Deploy the [MetaERC20Spoke](https://github.com/ConstellationCrypto/metatoken-contracts/blob/main/src/token/MetaERC20Spoke.sol) implementation contract.

```solidity theme={null}
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.

```solidity theme={null}
// 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.

```solidity theme={null}
hub.setDomainAddressBatch(
    [spokeDomain],
    [spokeAddress.addressToBytes32()]
);
```

**Register hub on spoke:**
Call `setDomainAddressBatch` on your spoke to register the hub's address.

```solidity theme={null}
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:

```solidity theme={null}
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

<CardGroup cols={2}>
  <Card title="Contact Team" icon="message" href="https://t.me/james_caldera">
    Contact for production MetaToken deployments
  </Card>

  <Card title="Protocol Overview" icon="book" href="/metalayer/protocol/metatoken">
    Learn about MetaToken architecture
  </Card>
</CardGroup>
