Skip to main content

How to deploy a Rollup chain using the Orbit SDK

RaaS providers

It is highly recommended to work with a Rollup-as-a-Service (RaaS) provider if you intend to deploy a production chain. You can find a list of RaaS providers here.

Creating a new Orbit chain involves deploying a set of contracts on your chain's parent chain. These contracts are:

  • Bridge contracts: used to send cross-chain messages between the Orbit chain and its parent chain, including batches posted by the sequencer
  • Rollup contracts: used by validators to create and confirm assertions of the current state of the Orbit chain
  • Challenge protocol contracts: used by validators to dispute current assertions of the state of the chain, and ultimately resolve those disputes

You can explore the code of these contracts in the nitro-contracts repository.

This page explains how to deploy a Rollup Orbit chain using the Orbit SDK. See the Overview for an introduction to the process of creating and configuring an Orbit chain.

Parameters used when deploying a new chain

Before we describe the process of creating a chain using the Orbit SDK, let's see what configuration options we have available when creating a chain.

Deploying a new Orbit chain is done through a RollupCreator contract that processes the creation of the needed contracts and sends the initialization messages from the parent chain to the newly created Orbit chain.

RollupCreator has a createRollup function that deploys your chain's core contracts to the parent chain. createRollup takes a complex struct called RollupDeploymentParams as its only input. This struct defines the parameters of the Orbit chain to be created.

struct RollupDeploymentParams {
Config config;
address[] validators;
uint256 maxDataSize;
address nativeToken;
bool deployFactoriesToL2;
uint256 maxFeePerGasForRetryables;
address[] batchPosters;
address batchPosterManager;
}

The following table describes RollupDeploymentParams's parameters:

ParameterTypeDescription
configConfigThe chain's configuration, explained below.
validatorsaddress[]Initial set of validator addresses. Validators are responsible for validating the chain state and posting assertions (RBlocks) back to the parent chain. They also monitor the chain and initiate challenges against potentially faulty assertions submitted by other validators.
maxDataSizeuint256Maximum message size for the Inbox contract (117964 for L2 chains, and 104857 for L3 chains).
nativeTokenaddressAddress of the token contract in the parent chain, used for paying gas fees on the Orbit chain. It can be set to ETH for regular chains or to any ERC-20 token for custom gas token Orbit chains.
deployFactoriesToL2boolWhether or not to deploy several deterministic factory contracts to the Orbit chain.
maxFeePerGasForRetryablesuint256Gas price bid to use when sending the retryable tickets.
batchPostersaddress[]Initial set of batch poster addresses. Batch posters batch and compress transactions on the Orbit chain and transmit them back to the parent chain.
batchPosterManageraddressAddress of the account responsible for managing currently active batch posters. Not mandatory, as these actions can also be taken by the chain owner.

The Config struct used in the previous configuration looks like this:

struct Config {
uint64 confirmPeriodBlocks;
address stakeToken;
uint256 baseStake;
bytes32 wasmModuleRoot;
address owner;
address loserStakeEscrow;
uint256 chainId;
string chainConfig;
uint256 minimumAssertionPeriod;
uint64 validatorAfkBlocks;
uint256[] miniStakeValues;
ISequencerInbox.MaxTimeVariation sequencerInboxMaxTimeVariation;
uint256 layerZeroBlockEdgeHeight;
uint256 layerZeroBigStepEdgeHeight;
uint256 layerZeroSmallStepEdgeHeight;
AssertionState genesisAssertionState;
uint256 genesisInboxCount;
address anyTrustFastConfirmer;
uint8 numBigStepLevel;
uint64 challengeGracePeriodBlocks;
BufferConfig bufferConfig;
}

Most of these parameters don't need to be configured, since the Orbit SDK will provide the right default values for them. However, the following table describes some of the parameters that you might want to configure:

ParameterTypeDescription
confirmPeriodBlocksuint64Sets the challenge period in terms of blocks, which is the time allowed for validators to dispute or challenge state assertions. Learn more about it in Customizable challenge period.
stakeTokenaddressAddress of the token that validators must stake to participate in the chain's validation process.
baseStakeuint256Orbit chain validator nodes must stake a certain amount to incentivize honest participation. This parameter specifies this amount.
wasmModuleRootaddressHash of the WASM module root to be used when validating.
owneraddressAccount address responsible for deploying, owning, and managing your Orbit chain's base contracts on its parent chain.
loserStakeEscrowaddressAddress that will receive any extra stakes deposited in the same assertion (when creating disputes).
chainIduint256Your chain's unique identifier. It differentiates your chain from others in the ecosystem.
chainConfigstringAdditional chain configuration, explained below.

The chainConfig parameter within the Config struct is a stringified JSON object that looks like this:

{
chainId: number;
homesteadBlock: number;
daoForkBlock: null;
daoForkSupport: boolean;
eip150Block: number;
eip150Hash: string;
eip155Block: number;
eip158Block: number;
byzantiumBlock: number;
constantinopleBlock: number;
petersburgBlock: number;
istanbulBlock: number;
muirGlacierBlock: number;
berlinBlock: number;
londonBlock: number;
clique: {
period: number;
epoch: number;
}
arbitrum: {
EnableArbOS: boolean;
AllowDebugPrecompiles: boolean;
DataAvailabilityCommittee: boolean;
InitialArbOSVersion: number;
InitialChainOwner: Address;
GenesisBlockNum: number;
MaxCodeSize: number;
MaxInitCodeSize: number;
}
}

Again, most of these parameters don't need to be configured, since the Orbit SDK will provide the right default values for them. However, the following table describes some of the parameters that you might want to configure:

ParameterTypeDescription
chainIdnumberYour chain's unique identifier. It differentiates your chain from others in the ecosystem.
arbitrum.DataAvailabilityCommitteeboolWhether or not to use a Data Avalability Committee (DAC) to store your chain's data (this should be false for Rollup chains, and true for AnyTrust chains).
arbitrum.InitialArbOSVersionnumberArbOS version to use (it should be the latest ArbOS version available).
arbitrum.InitialChainOwneraddressAccount address responsible for deploying, owning, and managing your Orbit chain's base contracts on its parent chain.
arbitrum.MaxCodeSizenumberSets the maximum size for contract bytecodes on the chain (it's recommended to use the default 24Kb, and not set it higher than 96Kb).
arbitrum.MaxInitCodeSizenumberMaximum initialization bytecode size allowed (usually double the amount set in MaxCodeSize).
info

The chainId and InitialChainOwner parameters must be equal to the chainId and owner defined in the Config struct.

How to create a new Rollup chain using the Orbit SDK

Now, let's look at the methods to use when creating a new Rollup Orbit chain with the Orbit SDK.

Example script

The Orbit SDK includes an example script for creating an Orbit chain. We recommend that you first understand the process described in this section and then check the create-rollup-eth script.

1. Create the chain configuration object

The prepareChainConfig function creates a chainConfig structure like the one defined in the previous section. It sets the appropriate defaults for most of the parameters, allowing you to override any of these defaults. However, the chainId and InitialChainOwner parameters must be set to the desired values.

Below is an example of how to use prepareChainConfig to obtain the chain configuration for a Rollup chain with a specific chainId and InitialChainOwner:

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

const chainConfig = prepareChainConfig({
chainId: 123_456,
arbitrum: {
InitialChainOwner: 0x123...890,
DataAvailabilityCommittee: false,
},
});

Once we have the chainConfig, we can use the function createRollupPrepareDeploymentParamsConfig to craft a Config structure like the one defined in the section above. Again, this function will set the appropriate defaults for most parameters, allowing you to override any of these defaults. However, the chainId and owner parameters must be set to the desired values. Additionally, a public client of the parent chain must be passed as an argument to the function.

Below is an example of how to use createRollupPrepareDeploymentParamsConfig to obtain the chain configuration for a Rollup chain with a specific chainId and owner:

import { createPublicClient, http } from 'viem';
import { createRollupPrepareDeploymentParamsConfig } from '@arbitrum/orbit-sdk';

const parentChainPublicClient = createPublicClient({
chain: parentChain,
transport: http(),
});

const createRollupConfig = createRollupPrepareDeploymentParamsConfig(parentChainPublicClient, {
chainId: 123_456,
owner: 0x123...890,
chainConfig: chainConfig,
});

2. Deploy the Rollup Orbit chain

With the new crafted configuration, we can call the createRollup method which will send the transaction to the RollupCreator contract and wait until it is executed.

Besides the Config structure created in the previous step, other parameters from the RollupDeploymentParams structure can be passed to override the defaults set by the Orbit SDK. Batch poster and validator addresses must be set to the desired values. Additionally, a public client of the parent chain and a deployer PrivateKeyAccount must be passed as arguments to the function.

Below is an example of how to use createRollup using the createRollupConfig crafted in the previous step:

import { createPublicClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { createRollup } from '@arbitrum/orbit-sdk';

const deployer = privateKeyToAccount(deployerPrivateKey);
const parentChainPublicClient = createPublicClient({
chain: parentChain,
transport: http(),
});

const createRollupResults = await createRollup({
params: {
config: createRollupConfig,
batchPosters: [batchPoster],
validators: [validator],
},
account: deployer,
parentChainPublicClient,
});

3. Understand the returned data

After calling createRollup, an object of type CreateRollupResults is returned with the following fields:

type CreateRollupResults = {
// The transaction sent
transaction: CreateRollupTransaction;
// The transaction receipt
transactionReceipt: CreateRollupTransactionReceipt;
// An object with the addresses of the contracts created
coreContracts: CoreContracts;
};

4. Next step

Once the chain's contracts are created, you can move to the next step: configure your Orbit chain's node.