Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add rollup creation
  • Loading branch information
TucksonDev committed Oct 23, 2025
commit 42c263f2f65eb2e4d1a0e58e5b79666c43d4a68d
15 changes: 15 additions & 0 deletions examples/generate-genesis-file/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,18 @@ L1_BASE_FEE=1000000000 # 1 gwei

# Nitro node image
NITRO_NODE_IMAGE=offchainlabs/nitro-node:v3.7.4-9244576

#################################
# Rollup creation configuration #
#################################
CREATE_ROLLUP=true

# Required
DEPLOYER_PRIVATE_KEY=

# Optional (these will be randomly generated if not provided)
BATCH_POSTER_PRIVATE_KEY=
VALIDATOR_PRIVATE_KEY=

# (Optional) Infura RPC endpoint for the parent chain (Arbitrum Sepolia), if not provided, the script might fail with timeout
PARENT_CHAIN_RPC=https://arbitrum-sepolia.infura.io/v3/YOUR_API_KEY
123 changes: 122 additions & 1 deletion examples/generate-genesis-file/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { Address, createPublicClient, http, toHex } from 'viem';
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
import { arbitrumSepolia } from 'viem/chains';
import { createRollupPrepareDeploymentParamsConfig, createRollup } from '@arbitrum/orbit-sdk';
import { sanitizePrivateKey } from '@arbitrum/orbit-sdk/utils';
import { config } from 'dotenv';
import { execSync } from 'child_process';
import * as fs from 'fs';
config();

// Env variables check
Expand All @@ -12,7 +18,30 @@ if (typeof process.env.L1_BASE_FEE === 'undefined') {
const nitroNodeImage = process.env.NITRO_NODE_IMAGE;
const l1BaseFee = Number(process.env.L1_BASE_FEE);

function main() {
// Optional checks when creating a rollup
if (process.env.CREATE_ROLLUP === 'true') {
// Check environment variables
if (typeof process.env.DEPLOYER_PRIVATE_KEY === 'undefined') {
throw new Error(`Please provide the "DEPLOYER_PRIVATE_KEY" environment variable`);
}

if (typeof process.env.PARENT_CHAIN_RPC === 'undefined' || process.env.PARENT_CHAIN_RPC === '') {
console.warn(
`Warning: you may encounter timeout errors while running the script with the default rpc endpoint. Please provide the "PARENT_CHAIN_RPC" environment variable instead.`,
);
}
}

// Helpers
function withFallbackPrivateKey(privateKey: string | undefined): `0x${string}` {
if (typeof privateKey === 'undefined' || privateKey === '') {
return generatePrivateKey();
}

return sanitizePrivateKey(privateKey);
}

async function main() {
// Step 0 - Build genesis file generator container from Github
// Note: remove this step once we have a public image
console.log(`Build genesis file generator container...`);
Expand Down Expand Up @@ -45,6 +74,98 @@ function main() {
console.log('Genesis file generated: genesis.json');
console.log(`Block hash: ${genesisBlockHash}`);
console.log(`SendRoot hash: ${sendRootHash}`);

// Step 4 - Create Rollup (optional)
if (process.env.CREATE_ROLLUP === 'true') {
// load or generate a random batch poster account
const batchPosterPrivateKey = withFallbackPrivateKey(process.env.BATCH_POSTER_PRIVATE_KEY);
const batchPoster = privateKeyToAccount(batchPosterPrivateKey).address;

// load or generate a random validator account
const validatorPrivateKey = withFallbackPrivateKey(process.env.VALIDATOR_PRIVATE_KEY);
const validator = privateKeyToAccount(validatorPrivateKey).address;

// set the parent chain and create a public client for it
const parentChain = arbitrumSepolia;
const parentChainPublicClient = createPublicClient({
chain: parentChain,
transport: http(process.env.PARENT_CHAIN_RPC),
});

// load the deployer account
const deployer = privateKeyToAccount(sanitizePrivateKey(process.env.DEPLOYER_PRIVATE_KEY!));

// The following env variables must exist, otherwise the genesis generation would have failed
const chainId = Number(process.env.CHAIN_ID!);
const chainOwner = process.env.CHAIN_OWNER as Address;

// Load chain config from the genesis file
let genesisFileContents: string;
try {
genesisFileContents = fs.readFileSync('genesis.json', { encoding: 'utf8' });
} catch (err) {
console.error('Failed to read generated genesis.json file');
throw err;
}
const genesisConfiguration = JSON.parse(genesisFileContents);

// Check whether or not we need to deploy the L2 factories (since they are included in the genesis file by default)
const l2Factories = [
// Arachnid's deterministic deployment proxy
'0x4e59b44847b379578588920cA78FbF26c0B4956C',
// Zoltu's deterministic deployment proxy
'0x7A0D94F55792C434d74a40883C6ed8545E406D12',
// ERC-2470 Singleton Factory
'0xce0042B868300000d44A59004Da54A005ffdcf9f',
// ERC-1820: Pseudo-introspection Registry Contract
'0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24',
] as const;

const allocKeys = new Set(
Object.keys(genesisConfiguration.alloc ?? {}).map((k) => k.toLowerCase()),
);
const hasAllFactories = l2Factories.every((a) => allocKeys.has(a.toLowerCase()));

// Prepare the genesis assertion state
const genesisAssertionState = {
globalState: {
bytes32Vals: [genesisBlockHash as `0x${string}`, sendRootHash as `0x${string}`] as [
`0x${string}`,
`0x${string}`,
],
// Set inbox position to 1
u64Vals: [1n, 0n] as [bigint, bigint],
},
machineStatus: 0, // Running
endHistoryRoot: toHex(0, { size: 32 }),
};
Comment on lines +165 to +176
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prepareGenesisAssertionState(params: { genesisBlockHash: Hex, sendRootHash: Hex }): GenesisAssertionState


console.log('');
console.log('------------------');
console.log('Creating Rollup...');
console.log('------------------');
const createRollupConfig = createRollupPrepareDeploymentParamsConfig(parentChainPublicClient, {
chainId: BigInt(chainId),
owner: chainOwner,
chainConfig: genesisConfiguration.config,
genesisAssertionState,
});

try {
await createRollup({
params: {
config: createRollupConfig,
batchPosters: [batchPoster],
validators: [validator],
deployFactoriesToL2: !hasAllFactories,
},
account: deployer,
parentChainPublicClient,
});
} catch (error) {
console.error(`Rollup creation failed with error: ${error}`);
}
}
}

main();
Loading