Adding a Rollup to the Registry
To add a rollup to the registry, follow these steps:Fork the Initia Registry Repository
To make changes to the registry, you will need to fork the Initia Registry repository. This will create a copy of the repository in your own GitHub account.Add the Rollup to the Registry
Once you have forked the repository, you can add the rollup to the registry by following these steps:- Add a new folder with your rollup’s name in the
testnetsormainnetsfolder, depending on whether your rollup is currently live on the testnet or mainnet. - Add a
chain.jsonfile to the folder. This file will contain the metadata for your rollup to be used by the apps.
Example Chain Schema and Description
Example Chain Schema and Description
{
"$schema": "../../chain.schema.json",
"chain_name": "move",
"pretty_name": "Move",
"chain_id": "move-1",
"bech32_prefix": "init",
"network_type": "testnet",
"codebase": {
"git_repo": "https://github.com/initia-labs/minimove",
"recommended_version": "v1.0.7",
"binaries": {
"linux/amd64": "https://github.com/initia-labs/minimove/releases/download/v1.0.7/minimove_v1.0.7_Linux_x86_64.tar.gz",
"linux/arm64": "https://github.com/initia-labs/minimove/releases/download/v1.0.7/minimove_v1.0.7_Linux_aarch64.tar.gz",
"darwin/amd64": "https://github.com/initia-labs/minimove/releases/download/v1.0.7/minimove_v1.0.7_Darwin_x86_64.tar.gz",
"darwin/arm64": "https://github.com/initia-labs/minimove/releases/download/v1.0.7/minimove_v1.0.7_Darwin_aarch64.tar.gz"
},
"genesis": {
"genesis_url": "https://rpc-move-1.anvil.asia-southeast.initia.xyz/genesis"
}
},
"apis": {
"rpc": [
{
"address": "https://rpc-move-1.anvil.asia-southeast.initia.xyz"
}
],
"rest": [
{
"address": "https://rest-move-1.anvil.asia-southeast.initia.xyz"
}
],
"grpc": [
{
"address": "grpc-move-1.anvil.asia-southeast.initia.xyz:443"
}
],
"indexer": [
{
"address": "https://rollytics-api-move-1.anvil.asia-southeast.initia.xyz"
}
]
},
"explorers": [
{
"kind": "initia scan",
"url": "https://scan.testnet.initia.xyz/move-1",
"tx_page": "https://scan.testnet.initia.xyz/move-1/txs/${txHash}",
"account_page": "https://scan.testnet.initia.xyz/move-1/accounts/${accountAddress}"
}
],
"key_algos": ["secp256k1"],
"slip44": 118,
"fees": {
"fee_tokens": [
{
"denom": "l2/07b129ceb9c4b0bdef7db171ce1e22f90d34bc930058b23e21adf8cc938d8145",
"fixed_min_gas_price": 0.015
}
]
},
"images": [
{
"png": "https://raw.githubusercontent.com/initia-labs/initia-registry/main/images/minimove.png"
}
],
"logo_URIs": {
"png": "https://raw.githubusercontent.com/initia-labs/initia-registry/main/images/minimove.png"
},
"metadata": {
"op_bridge_id": "1458",
"op_denoms": ["uinit"],
"executor_uri": "https://opinit-api-move-1.anvil.asia-southeast.initia.xyz",
"ibc_channels": [
{
"chain_id": "initiation-2",
"port_id": "nft-transfer",
"channel_id": "channel-1",
"version": "ics721-1"
},
{
"chain_id": "initiation-2",
"port_id": "transfer",
"channel_id": "channel-0",
"version": "ics20-1"
}
],
"assetlist": "https://raw.githubusercontent.com/initia-labs/initia-registry/main/testnets/move/assetlist.json",
"minitia": {
"type": "minimove",
"version": "v1.0.7"
}
}
}
Description
General Information| Field | Description | Optional |
|---|---|---|
$schema | The schema definition file. (should always be ../../chain.schema.json) | No |
chain_name | The name of the rollup. | No |
chain_id | The chain ID of the rollup. | No |
website | The website of the rollup. | No |
pretty_name | A human-readable name for your rollup. | No |
status | The current status of the rollup (e.g., live). | No |
network_type | The type of network (one of mainnet, testnet, devnet). | No |
bech32_prefix | The Bech32 prefix used for addresses on the blockchain. | No |
daemon_name | The name of the daemon process for the blockchain (e.g., minitiad). | No |
node_home | The default home directory for the blockchain node. | No |
key_algos | The cryptographic algorithms supported for keys. | No |
slip44 | The SLIP-0044 identifier for the blockchain. | No |
description | A brief description of the rollup. | No |
| Field | Description | Optional |
|---|---|---|
fees | Details about the fee and fee tokens on the rollup. | No |
fee_tokens | Tokens used for fees, including their denominations and gas prices. | No |
| Field | Description | Optional |
|---|---|---|
staking | Information about staking on the rollup. | No |
staking_tokens | Tokens used for staking. | No |
| Field | Description | Optional |
|---|---|---|
codebase | Information about the blockchain’s codebase. | No |
git_repo | The URL of the Git repository for the rollup. | No |
recommended_version | The recommended version of the rollup software. This should in most cases be the latest version of the software. | No |
compatible_versions | Versions of the rollup software that are compatible. | No |
binaries | URLs for downloading binary files for different platforms. | No |
genesis | Information about the genesis block of the rollup. | No |
genesis_url | The URL to download the rollup genesis file. | No |
versions | List of versions of the rollup software. | No |
| Field | Description | Optional |
|---|---|---|
peers | Information about network peers. | No |
seeds | The list of seed nodes for the rollup. | No |
persistent_peers | The list of persistent peers for the rollup. | No |
| Field | Description | Optional |
|---|---|---|
apis | Information about the different endpoints for the rollup. | No |
rpc | RPC endpoints and their providers. | No |
rest | REST endpoints and their providers. | No |
grpc | gRPC endpoints and their providers. | No |
| Field | Description | Optional |
|---|---|---|
explorers | Blockchain explorers available for the network. | No |
kind | The type of explorer. | No |
url | The URL of the explorer. | No |
tx_page | The URL template for transaction pages. | No |
account_page | The URL template for account pages. | No |
| Field | Description | Optional |
|---|---|---|
images | URLs for images related to the blockchain. | No |
png | URL for the PNG image. | No |
svg | URL for the SVG image. | No |
logo_URIs | URLs for the blockchain logo. | No |
| Field | Description | Optional |
|---|---|---|
metadata | Additional metadata about the blockchain. | No |
op_bridge_id | The bridge ID for operations. | Yes |
op_denoms | Denominations used in by the OP Bridge. | Yes |
executor_uri | The URI for the executor service. | Yes |
ibc_channels | Information about IBC channels. | Yes |
chain_id | The chain ID for the IBC channel. | No |
port_id | The port ID for the IBC channel. | No |
channel_id | The channel ID for the IBC channel. | No |
version | The version of the IBC protocol used. | No |
assetlist | URL for the asset list JSON file. | Yes |
minitia | Specific metadata for the rollup. | No |
type | The type of chain (one of minimove, minievm, or miniwasm). | No |
version | The version of the rollup. | No |
- Create an
assetlist.jsonfile in the folder. This file will contain the metadata for the assets on your rollup to be used by the apps.
Example Assetlist Schema and Description
Example Assetlist Schema and Description
{
"$schema": "../../assetlist.schema.json",
"chain_name": "move",
"assets": [
{
"description": "The native token of Initia",
"denom_units": [
{
"denom": "l2/07b129ceb9c4b0bdef7db171ce1e22f90d34bc930058b23e21adf8cc938d8145",
"exponent": 0
},
{
"denom": "INIT",
"exponent": 6
}
],
"base": "l2/07b129ceb9c4b0bdef7db171ce1e22f90d34bc930058b23e21adf8cc938d8145",
"display": "INIT",
"traces": [
{
"type": "op",
"counterparty": {
"base_denom": "uinit",
"chain_name": "initia"
},
"chain": {
"bridge_id": "1"
}
}
],
"name": "Initia Native Token",
"symbol": "INIT",
"coingecko_id": "",
"images": [
{
"png": "https://raw.githubusercontent.com/initia-labs/initia-registry/main/testnets/minimove/images/INIT.png",
"svg": "https://raw.githubusercontent.com/initia-labs/initia-registry/main/testnets/minimove/images/INIT.svg"
}
],
"logo_URIs": {
"png": "https://raw.githubusercontent.com/initia-labs/initia-registry/main/testnets/minimove/images/INIT.png",
"svg": "https://raw.githubusercontent.com/initia-labs/initia-registry/main/testnets/minimove/images/INIT.svg"
}
},
]
}
| Field | Description | Optional |
|---|---|---|
| name | The name of the token | No |
| symbol | The symbol of the token | No |
| description | The description of the token | No |
| coingecko_id | The CoinGecko ID of the token | Yes |
| Field | Description | Optional |
|---|---|---|
| denom_units | List of denomination units | No |
| denom_units.denom | The denomination identifier (e.g. “uinit”, “INIT”) | No |
| denom_units.exponent | The exponent of the denomination (e.g. 0, 6) | No |
| Field | Description | Optional |
|---|---|---|
| base | The base denomination of the token (e.g. uinit, l2/…) | No |
| display | The display denomination identifier (e.g. INIT) | No |
| Field | Description | Optional |
|---|---|---|
| traces | List of trace information for the token | No |
| traces.type | The type of trace (e.g., “op”, “ibc”) | No |
| traces.counterparty | Information about the counterparty chain | No |
| traces.counterparty.base_denom | The base denomination on the counterparty chain | No |
| traces.counterparty.chain_name | The name of the counterparty chain | No |
| traces.counterparty.channel_id | The channel ID on the counterparty chain | Yes |
| traces.chain | Information about the current chain | No |
| traces.chain.bridge_id | The bridge ID on the current chain | Yes |
| traces.chain.channel_id | The channel ID on the current chain | Yes |
| traces.chain.path | The path on the current chain | Yes |
| Field | Description | Optional |
|---|---|---|
| images | List of image URIs for the token | No |
| images.png | The PNG image URI for the token | No |
| images.svg | The SVG image URI for the token | No |
| Field | Description | Optional |
|---|---|---|
| logo_URIs | Object containing logo URIs for the token | No |
| logo_URIs.png | The PNG logo URI for the token | No |
| logo_URIs.svg | The SVG logo URI for the token | No |
How to Derive a Bridged Token Denom
How to Derive a Bridged Token Denom
For tokens bridged from L1, the denom can vary depending on the type of bridge
used. In order for token bridging to work correctly, you must add the
appropriate denom to your assetlist.We have two scenarios for calculating the denom:IBC Denom
- OP Denom: The denom used in the OP Bridge
- IBC Denom: The denom used in the IBC Bridge
denom.ts
import { RESTClient } from '@initia/initia.js'
/**
*
* Queries the Initia REST API to find the L2 (Layer 2) denomination
* corresponding to a given L1 (Layer 1) denomination, for a specific bridge ID.
*
* @param {string} uri - The REST endpoint for the Initia network (e.g., "https://rest.testnet.initia.xyz").
* @param {number} bridge_id - The bridge ID (e.g., 1).
* @param {string} l1_denom - The L1 denomination (e.g., "uinit").
* @returns {Promise<string>} - The corresponding L2 denomination (e.g., "l2/...").
*/
export async function opDenomByL1Denom(
uri: string,
bridge_id: number,
l1_denom: string,
): Promise<string> {
const restClient = new RESTClient(uri)
const tokenPair = await restClient.ophost.tokenPairByL1Denom(
bridge_id,
l1_denom,
)
return tokenPair.l2_denom
}
/**
*
* Queries the Initia REST API to find the L1 (Layer 1) denomination
* corresponding to a given L2 (Layer 2) denomination, for a specific bridge ID.
*
* @param {string} uri - The REST endpoint for the Initia network (e.g., "https://rest.testnet.initia.xyz").
* @param {number} bridge_id - The bridge ID (e.g., 1).
* @param {string} l2_denom - The L2 denomination (e.g., "l2/xyz...").
* @returns {Promise<string>} - The corresponding L1 denomination (e.g., "uinit").
*/
export async function opDenomByL2Denom(
uri: string,
bridge_id: number,
l2_denom: string,
): Promise<string> {
const restClient = new RESTClient(uri)
const tokenPair = await restClient.ophost.tokenPairByL2Denom(
bridge_id,
l2_denom,
)
return tokenPair.l1_denom
}
async function main() {
// Example usage of opDenomByL1Denom and opDenomByL2Denom
const uri = 'https://rest.testnet.initia.xyz'
const bridge_id = 1
const l1_denom = 'uinit'
const l2_denom =
'l2/07b129ceb9c4b0bdef7db171ce1e22f90d34bc930058b23e21adf8cc938d8145'
const l2_denom_for_l1_denom = await opDenomByL1Denom(uri, bridge_id, l1_denom)
console.log(`L2 denom for L1 denom "${l1_denom}":`, l2_denom_for_l1_denom)
const l1_denom_for_l2_denom = await opDenomByL2Denom(uri, bridge_id, l2_denom)
console.log(`L1 denom for L2 denom "${l2_denom}":`, l1_denom_for_l2_denom)
}
main().catch((error) => {
console.error('Error in main:', error)
})
denom.ts
import { RESTClient, sha256 } from '@initia/initia.js'
interface DenomTrace {
denom_trace: {
path: string
base_denom: string
}
}
/**
*
* Takes a full trace string (e.g., "transfer/channel-0/uinit"), computes its SHA-256 hash,
* and returns it in uppercase as "ibc/<HASH>".
*
* @param {string} fullTrace - For example, "transfer/channel-0/uinit".
* @returns {string} - For example, "ibc/2A3B4C...".
*/
function makeIBCHash(fullTrace: string): string {
const shaSum = sha256(Buffer.from(fullTrace))
const hash = Buffer.from(shaSum).toString('hex').toUpperCase()
return `ibc/${hash}`
}
/**
*
* Retrieves the original "transfer/..." full trace (e.g., "transfer/channel-0/uinit")
* from an IBC denom that starts with "ibc/...". It queries the IBC module's
* `denom_traces` endpoint to get the path and base denom.
*
* @param {RESTClient} restClient - The RESTClient instance for the chain.
* @param {string} denom - The IBC denom (must start with "ibc/").
* @returns {Promise<string>} - The combined path and base denom (e.g., "transfer/channel-0/uinit").
*/
async function getFullTrace(
restClient: RESTClient,
denom: string,
): Promise<string> {
if (!denom.startsWith('ibc/')) {
throw Error('Not an IBC denom')
}
const trace = await restClient.apiRequester.get<DenomTrace>(
`/ibc/apps/transfer/v1/denom_traces/${denom}`,
)
return `${trace.denom_trace.path}/${trace.denom_trace.base_denom}`
}
/**
*
* Takes a denom from chain A (e.g., "uinit" or "ibc/...") and determines how it is
* represented on chain B. This may result in a hashed IBC denom ("ibc/...") or
* a "transfer/..." full trace string.
*
* 1. If the input denom starts with "ibc/", retrieve the original full trace using `getFullTrace`.
* 2. If the resulting full trace starts with "transfer/{chainAChannel}/...", it indicates
* the token originally came from chain B (unwind logic).
* 3. Otherwise, prepend "transfer/{chainBChannel}/..." (wind logic).
* 4. Finally, if the resulting string begins with "transfer/", convert it to an IBC hash
* using `makeIBCHash`. Otherwise, return it as is.
*
* @param {RESTClient} restClient - The RESTClient for chain A.
* @param {string} denom - The denom used on chain A (e.g., "uinit" or "ibc/...").
* @param {string} chainAChannel - The channel ID on chain A (e.g., "channel-1").
* @param {string} chainBChannel - The channel ID on chain B (e.g., "channel-2").
* @returns {Promise<string>} - The resulting IBC denom (e.g., "ibc/...") or a "transfer/..." full trace.
*/
export async function ibcDenom(
restClient: RESTClient,
denom: string,
chainAChannel: string,
chainBChannel: string,
): Promise<string> {
let wind = true
let fullTrace = denom
// If denom starts with "ibc/", retrieve the original trace
if (denom.startsWith('ibc/')) {
fullTrace = await getFullTrace(restClient, denom)
// If the token's trace starts with "transfer/chainAChannel/", token originated from chain B
if (fullTrace.startsWith(`transfer/${chainAChannel}/`)) {
wind = false
}
}
// Depending on wind/unwind, construct the trace for chain B
let fullTraceOnChainB: string
if (wind) {
// Wind: prepend "transfer/{chainBChannel}/"
fullTraceOnChainB = `transfer/${chainBChannel}/${fullTrace}`
} else {
// Unwind: remove "transfer/{chainAChannel}/"
fullTraceOnChainB = fullTrace.slice(`transfer/${chainAChannel}/`.length)
}
// If it starts with "transfer/", convert to an IBC hash; otherwise, return as is
const denomInChainB = fullTraceOnChainB.startsWith('transfer/')
? makeIBCHash(fullTraceOnChainB)
: fullTraceOnChainB
return denomInChainB
}
async function main() {
// Example usage of ibcDenom
const denom = 'uinit' // or "ibc/..."
const restClientChainA = new RESTClient('https://rest.testnet.initia.xyz')
const channelA = 'channel-132' // Example channel ID for chain A
const channelB = 'channel-0' // Example channel ID for chain B
const ibcDenomStr = await ibcDenom(
restClientChainA,
denom,
channelA,
channelB,
)
console.log('Calculated IBC Denom:', ibcDenomStr)
}
main().catch((error) => {
console.error('Error in main:', error)
})
- (Optional) create an
imagesfolder to store the images for your rollup logo and token logos to link to in the two JSON files above.