Skip to main content

How to Deploy an Orbit chain using the Orbit SDK

This document explains how to use the Orbit SDK to deploy a Orbit chain.

UNDER CONSTRUCTION

This document is under construction and may change significantly as we incorporate style guidance and feedback from readers. Feel free to request specific clarifications by clicking the Request an update button at the top of this document.

The Arbitrum Orbit SDK lets you programmatically create and manage your own Orbit chain(s). Its capabilities include:

  • Configuration and deployment of your Orbit chain's core contracts
  • Initialization of your chain and management of its configuration post-deployment

Select a chain type

There are three types of Orbit chains. Select the chain type that best fits your needs:

  • Rollup chains offer Ethereum-grade security by batching, compressing, and posting data to the parent chain, similarly to Arbitrum One.
  • Use case: Ideal for applications that require high security guarantees.

Prepare your Rollup Orbit chain configuration object parameters

prepareChainConfig API:

For an easier config preparation, the Orbit SDK provides the prepareChainConfig API, which takes config parameters as arguments and returns a chainConfig JSON string. Any parameters not provided will default to standard values, which are detailed in the Orbit SDK repository.

Here are the parameters you can use with prepareChainConfig:

ParameterDescription
chainIdYour Orbit chain's unique identifier. It differentiates your chain from others in the ecosystem.
DataAvailabilityCommitteeSet to false, this boolean makes your chain as a Rollup, set to true configures it as an AnyTrust chain.
InitialChainOwnerIdentifies who owns and controls the chain.
MaxCodeSize Sets the maximum size for contract bytecodes on the Orbit chain. e.g. Ethereum mainnet has a limit of 24,576 Bytes.
MaxInitCodeSizeSimilar to MaxCodeSize, defines the maximum size for your Orbit chain's initialization code. e.g. Ethereum mainnet limit is 49,152 Bytes.

Below is an example of how to use prepareChainConfig to set up a Rollup chain with a specific chainId, an InitialChainOwner (named as deployer_address):

import { prepareChainConfig } from '@arbitrum/orbit-sdk';

const chainConfig = prepareChainConfig({
chainId: Some_Chain_ID,
arbitrum: { InitialChainOwner: deployer_address, DataAvailabilityCommittee: false },
});

createRollupPrepareConfig API:

This API is designed to take parameters defined in the Config struct and fill in the rest with default values. It outputs a complete Config struct that is ready for use.

For example, to create a Config struct with a specific chain ID (chainId), an owner address (deployer_address), and a chainConfig as described in the previous section, you would use the Orbit SDK as follows:

import { createRollupPrepareConfig } from '@arbitrum/orbit-sdk';

const config = createRollupPrepareConfig({
chainId: BigInt(chainId),
owner: deployer.address,
chainConfig,
});

Deploy your Orbit chain

Orbit SDK provides the createRollupPrepareTransactionRequest helper to prepare your transaction:

createRollupPrepareTransactionRequest API:

This API accepts parameters defined in the RollupDeploymentParams struct, applying defaults where necessary, and generates the RollupDeploymentParams. This struct is then used to create a raw transaction which calls the createRollup function of the RollupCreator contract. As discussed in previous sections, this function deploys and initializes all core Orbit contracts.

For instance, to deploy using the Orbit SDK with a Config equal to config, a batchPoster, and a set of validators such as [validator], the process would look like this:

import { createRollupPrepareTransactionRequest } from '@arbitrum/orbit-sdk';

const request = await createRollupPrepareTransactionRequest({
params: {
config,
batchPoster,
validators: [validator],
},
account: deployer_address,
publicClient,
});

After creating the raw transaction, you need to sign and broadcast it to the network, as shown in the create-rollup-eth example.

Get the orbit chain information after deployment

Once you've successfully deployed your Orbit chain, the next step is to retrieve detailed information about the deployment. The Orbit SDK provides a convenient way to do this through the createRollupPrepareTransactionReceipt API.

After sending the signed transaction and receiving the transaction receipt, you can use the createRollupPrepareTransactionReceipt API to parse this receipt and extract the relevant data. This process will provide comprehensive details about the deployed chain, such as contract addresses, configuration settings, and other information.

Here's an example of how to use the Orbit SDK to get data from a deployed Orbit chain:

import { createRollupPrepareTransactionReceipt } from '@arbitrum/orbit-sdk';

const data = createRollupPrepareTransactionReceipt(txReceipt);

In this example, txReceipt refers to the transaction receipt you received after deploying the chain. By passing this receipt to the createRollupPrepareTransactionReceipt function, you can easily access a wealth of information about your Orbit chain. This feature of the Orbit SDK simplifies the post-deployment process, allowing you to quickly and efficiently gather all necessary details about your chain for further use or reference.

Configure a Node running your Rollup Orbit chain

Once you have successfully deployed and initialized the Orbit core contracts, the next step is configuring and running your Orbit chain using a Node Config JSON file describing all the configurations for the Arbitrum Node, including settings for the Batch-poster, Validator, and the chain itself.

Example for a Rollup Orbit Chain:

{
'chain': {
'info-json': stringifyInfoJson([...]),
'name': chainName,
// Additional chain-specific configurations
},
'parent-chain': {
connection: {
url: parentChainRpcUrl,
},
},
'http': {
addr: '0.0.0.0',
port: 8449,
vhosts: '*',
corsdomain: '*',
api: ['eth', 'net', 'web3', 'arb', 'debug'],
},
'node': {
// Node-specific settings including sequencer, batch-poster, staker configurations
},
};

Here are some inputs details from the example above:

ParametersDescription
chainDetails about the hosted chain, including chain ID, name, and core contracts.
parent-chainInformation for connecting to the parent chain.
httpConfiguration parameters for the HTTP server.
nodeSpecific node settings, including sequencer and batch-poster configurations.

Preparing your node config file

The Node Config file includes three fields types:

  1. Information from the Orbit deployment chain: Such as the addresses of the core contracts.
  2. Parameters configurable by the chain deployer: These parameters, like max-block-speed, can be adjusted to modify your chain's behavior.
  3. Fields not typically configured: Like the HTTP section, which usually remains standard.

Let's explore the parameters allowing you to set up a stable, and secure Orbit chain tailored to your project's requirements:

Node config generation with Orbit SDK

Generating a Node Config JSON file to initiate your Orbit chain is a step in the deployment process. The Orbit SDK simplifies this task with an API named prepareNodeConfig. This API takes specific parameters for your Orbit chain and returns a JSON file that can be used as the Node Config to initiate the chain.

Here’s an example of using the prepareNodeConfig API to generate the node config:

const nodeConfig = prepareNodeConfig({
chainName: 'My Orbit Chain',
chainConfig,
coreContracts,
batchPosterPrivateKey: 'BATCH_POSTER_PRIVATE_KEY_HERE',
validatorPrivateKey: 'VALIDATOR_PRIVATE_KEY_HERE',
parentChainId: parentChain_chain_id,
parentChainRpcUrl: parentChain_RPC_URL,
});

Here are some details about the parameters used in the example above:

ParametersDescription
chainNameThe name you have chosen for your Orbit chain.
chainConfigConfiguration used for chain deployment, returned from the createRollupPrepareTransactionReceipt API.
coreContractsAddresses of your newly deployed Orbit chain's, also returned from the createRollupPrepareTransactionReceipt API.
batchPosterPrivateKey Private key of the batch-poster account, used for signing batch-posting transactions and related functions.
validatorPrivateKeyPrivate key of the validator(s), used for validating state, posting Rollup Blocks (RBlocks) to the parent chain, and initiating challenges if necessary.
parentChainIdChain ID of the parent chain where your Orbit chain is deployed.
parentChainRpcUrlParent chain's RPC URL.

If you don't have the chainConfig and coreContracts readily available, you can obtain them using the createRollupPrepareTransaction and createRollupPrepareTransactionReceipt APIs.

Here's an example of how to extract chainConfig and coreContracts using just the transaction hash from your deployment:

import {
ChainConfig,
createRollupPrepareTransaction,
createRollupPrepareTransactionReceipt,
} from '@arbitrum/orbit-sdk';

const tx = createRollupPrepareTransaction({ hash: txHash });
const txReceipt = createRollupPrepareTransactionReceipt({ hash: txHash });
const chainConfig: ChainConfig = JSON.parse(tx.getInputs()[0].config.chainConfig);
const coreContracts = txReceipt.getCoreContracts();

This process ensures that all necessary configurations and contract details are included in your Node Config.

Deploy a token bridge

The Arbitrum Nitro stack doesn't natively support specific token bridging standards at the protocol level. Instead, Offchain Labs designed a "canonical bridge" that ensures seamless token transfers between the parent and child chains.

The token bridge architecture includes contracts deployed on the parent chain and on your Orbit chain.These entities communicate via the Retryable Ticket protocol, ensuring efficient and secure interactions.

Token bridge deployment steps

Once an Orbit chain has been deployed and initialized, the bridge contracts need to be deployed on both the parent and child chains. This process involves several steps:

  1. Token bridge contract deployment
  2. Transaction recipient and checking for deployment on child chain
  3. Deployment information and contract addresses
  4. Setting up the WETH gateway

1. Token bridge contract deployment

Deploying token bridge contracts is the first step in creating a bridge between the parent and the Orbit chain.

The deployment process is the same as Orbit chain contracts', where a primary contract facilitates the deployment of core contracts. The token bridge contracts are deployed on the parent and child chains by TokenBridgeCreator. TokenBridgeCreator does it in a single transaction using the Retryable Tickets protocol .

Orbit SDK provides an API that automates the deployment by interacting with the TokenBridgeCreator contract. The API is createTokenBridgePrepareTransactionRequest, which processes the necessary inputs and generates a transaction request tailored for token bridge deployment.

Example:

const txRequest = await createTokenBridgePrepareTransactionRequest({
params: {
rollup: rollupContractAddress,
rollupOwner: rollupOwnerAddress,
},
parentChainPublicClient,
orbitChainPublicClient,
account: rollupOwnerAddress,
});

Here are the parameters used in the above example:

ParameterDescription
rollupContractAddressOrbit chain's Rollup contract address.
rollupOwnerAddressRollup owner's address.
parentChainPublicClientParent chain's public client, as defined by Viem.
orbitChainPublicClientOrbit chain's public client, as defined by Viem.

For more insights into these variables and their usage, consider exploring this token bridge deployment example.

Following the creation of the raw transaction, the next steps involve signing it and broadcasting it to the relevant blockchain network to complete the deployment process.

2. Transaction recipient and checking for deployment on child chain

After sending the deployment transaction, you will need to retrieve the transaction receipt and verify the successful deployment of the contracts on both the parent and child chains.

Our Orbit SDK includes a dedicated API for this purpose, named createTokenBridgePrepareTransactionReceipt, which simplifies the process of obtaining the deployment transaction's recipient.

Example:

const txReceipt = createTokenBridgePrepareTransactionReceipt(
await parentChainPublicClient.waitForTransactionReceipt({ hash: txHash }),
);

In this scenario, txHash represents the hash of the deployment transaction initiated in the previous step. The waitForTransactionReceipt API from Viem captures the transaction's recipient on the parent chain. The createTokenBridgePrepareTransactionReceipt API enhances the basic functionality provided by Viem's waitForTransactionReceipt, introducing a specialized method named waitForRetryables to handle the outcome (in this case, txReceipt).

By employing the waitForRetryables method, you can ensure the success of Retryable Tickets on the parent chain.

Example:

const orbitChainRetryableReceipts = await txReceipt.waitForRetryables({
orbitPublicClient: orbitChainPublicClient,
});

if (orbitChainRetryableReceipts[0].status !== 'success') {
throw new Error(
`Retryable status is not success: ${orbitChainRetryableReceipts[0].status}. Aborting...`,
);
}

console.log(`Retryable executed successfully`);

In this example, the waitForRetryables method is invoked on the txReceipt to monitor the execution of Retryable Tickets and verify their status. A success status indicates that the Retryable Tickets have been executed successfully, ensuring the contracts' deployment. It's important to note that this process involves two Retryable Tickets. You can check out a more comprehensive walkthrough of the example. This enhanced approach not only simplifies the retrieval of transaction receipts but also provides a reliable method for verifying contract deployment across chains.

3. Deployment information and contract addresses

Once you have completed the deployment and are assured that the Retryable Tickets are successful, you can use getTokenBridgeContracts to retrieve the deployment information and all the token bridge contracts' addresses.

Here's an example of how to get the contract addresses from the txReceipt generated in the previous steps:

const tokenBridgeContracts = await txReceipt.getTokenBridgeContracts({
parentChainPublicClient,
});

4. Setting up the WETH gateway

The last step in spinning up the token bridge for an ETH- based Orbit chain is setting up the WETH Gateway.

note

That step only applies to ETH-based Orbit chains, not Custom fee token orbit chains. Our canonical bridge design has a separate custom gateway for WETH to bridge it in and out of the Orbit chain.

You can find more info about WETH gateways in our "other gateways flavors" documentation.

So, after the token bridge has been deployed and you have secured a successful deployment on both parent and child chains, it's time to set the WETH gateway on both parent and child chains. To handle that, we have two APIs on our Orbit SDK:

1. createTokenBridgePrepareSetWethGatewayTransactionRequest:

This API helps you create the raw transaction which handles the WETH gateway on both parent and child chains.

Example:

const setWethGatewayTxRequest = await createTokenBridgePrepareSetWethGatewayTransactionRequest({
rollup: rollupContractAddress,
parentChainPublicClient,
orbitChainPublicClient,
account: rollupOwnerAddress,
retryableGasOverrides: {
gasLimit: {
percentIncrease: 200n,
},
},
});

In this example, rollupContractAddress is the address of Orbit chain's Rollup contract, and rollupOwnerAddress is the address of the Rollup owner. parentChainPublicClient and orbitChainPublicClient are the public clients of the parent and orbit chains. This API also has optional fields to override the Retryable ticket setups. In this example, percentIncrease is the buffer to increase the gas limit, thus securing successful retryable tickets.

After creating the raw transaction, you need to use Viem to sign it and broadcast it to the network.

2. createTokenBridgePrepareSetWethGatewayTransactionReceipt

After sending the transaction, you need to assess if the Retryable Tickets you just created have been successful. To do that we are using createTokenBridgePrepareSetWethGatewayTransactionReceipt API and thewaitForRetryables method of it to check for the success status of retryable tickets. For the example in this doc we can use this API as follow:

const setWethGatewayTxReceipt = createTokenBridgePrepareSetWethGatewayTransactionReceipt(
await parentChainPublicClient.waitForTransactionReceipt({
hash: setWethGatewayTxHash,
}),
);
const orbitChainSetWethGatewayRetryableReceipt = await setWethGatewayTxReceipt.waitForRetryables({
orbitPublicClient: orbitChainPublicClient,
});
if (orbitChainSetWethGatewayRetryableReceipt[0].status !== 'success') {
throw new Error(
`Retryable status is not success: ${orbitChainSetWethGatewayRetryableReceipt[0].status}. Aborting...`,
);
}
console.log(`Retryables executed successfully`);

In this example setWethGatewayTxHash is the hash of the transaction you sent, setting the WETH gateway on your Orbit chain.