Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 2 additions & 0 deletions examples/get-chain-contract-versions/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
INBOX_ADDRESS=0xaE21fDA3de92dE2FDAF606233b2863782Ba046F9
PARENT_CHAIN_RPC=https://arb1.arbitrum.io/rpc
57 changes: 57 additions & 0 deletions examples/get-chain-contract-versions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Get Orbit chain contract versions

This example uses the SDK's `getOrbitChainContractVersions` helper to inspect the deployed Nitro contract versions for an Orbit chain on Arbitrum.

It runs against the current repository checkout, so `pnpm dev` builds the local SDK before executing the example.

It requires:

- an inbox address for the chain you want to inspect
- a parent chain RPC URL

Optional:

- Docker installed and available on `PATH` when `EXECUTION_MODE=docker`
- a custom Orbit Actions image via `ORBIT_ACTIONS_IMAGE` when using docker mode

## Setup

1. Install dependencies

```bash
pnpm install
```

2. Create `.env`

```bash
cp .env.example .env
```

3. Run the example

```bash
pnpm dev
```

## Parent-chain RPC behavior

The example passes `INBOX_ADDRESS` and `PARENT_CHAIN_RPC` directly to the SDK helper. It does not derive or require a separate parent chain id.

By default the SDK uses the native `orbit-actions` versioner:

```env
PARENT_CHAIN_RPC=https://arb1.arbitrum.io/rpc
```

If you want to force Docker execution instead, set:

```env
EXECUTION_MODE=docker
```

In docker mode, the SDK runs `yarn orbit:contracts:version` inside the configured Orbit Actions image. For local RPC URLs, it rewrites `PARENT_CHAIN_RPC` from `localhost` / `127.0.0.1` to `host.docker.internal`, and adds Docker's `host-gateway` mapping so the container can reach the host on Linux Docker Engine as well as Docker Desktop.

This example uses the SDK's default pinned `chain-actions` image in docker mode. If you need a custom image, set `ORBIT_ACTIONS_IMAGE`.

The script logs the discovered contract versions and any upgrade recommendation to stdout.
35 changes: 35 additions & 0 deletions examples/get-chain-contract-versions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { config } from 'dotenv';
import { getOrbitChainContractVersions } from '@arbitrum/chain-sdk';
import { isAddress } from 'viem';

config();

const inboxAddress = process.env.INBOX_ADDRESS;
const parentChainRpc = process.env.PARENT_CHAIN_RPC;
const executionMode = process.env.EXECUTION_MODE === 'docker' ? 'docker' : 'native';
const orbitActionsImage = process.env.ORBIT_ACTIONS_IMAGE;

async function main() {
if (!inboxAddress || !isAddress(inboxAddress)) {
throw new Error('Please provide a valid "INBOX_ADDRESS" environment variable');
}

if (!parentChainRpc) {
throw new Error('Please provide the "PARENT_CHAIN_RPC" environment variable');
}

console.log('Getting Orbit chain contract versions...');
const result = await getOrbitChainContractVersions(
inboxAddress,
parentChainRpc,
executionMode,
orbitActionsImage,
);

console.log(result);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
17 changes: 17 additions & 0 deletions examples/get-chain-contract-versions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "get-chain-contract-versions",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "tsc --outDir dist && node ./dist/index.js",
"predev": "pnpm --dir ../.. build"
},
"devDependencies": {
"@types/node": "^20.9.0",
"typescript": "^5.2.2"
},
"dependencies": {
"@arbitrum/chain-sdk": "workspace:*"
}
}
4 changes: 4 additions & 0 deletions examples/get-chain-contract-versions/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../tsconfig.base.json",
"include": ["./**/*"]
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
},
"devDependencies": {
"@offchainlabs/prettier-config": "0.2.1",
"@types/node": "^20.9.0",
"@wagmi/cli": "^1.5.2",
"audit-ci": "^7.0.1",
"dotenv": "^16.3.1",
Expand Down
53 changes: 43 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ export const createRollupDefaultRetryablesFees = parseEther('0.125');
* Approximate value necessary to pay for retryables fees for `createTokenBridge`.
*/
export const createTokenBridgeDefaultRetryablesFees = parseEther('0.02');

export const DEFAULT_ORBIT_ACTIONS_IMAGE =
'offchainlabs/chain-actions@sha256:150d84f832ea4361bbe4876ecc89d4e5433f49b31b11d55229282b6568042c75';
101 changes: 101 additions & 0 deletions src/getOrbitChainContractVersions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import type { Address } from 'viem';

import { runOrbitVersioner } from 'orbit-actions';

import { DEFAULT_ORBIT_ACTIONS_IMAGE } from './constants';
import { runDockerCommand } from './runDockerCommand';

export type GetOrbitChainContractVersionsResult = {
versions: Record<string, string | null>;
upgradeRecommendation: unknown;
};

function getDockerNetworkConfig(parentChainRpc: string): {
rpcUrl: string;
dockerRunArgs?: string[];
} {
const parsed = new URL(parentChainRpc);

if (parsed.hostname !== 'localhost' && parsed.hostname !== '127.0.0.1') {
return {
rpcUrl: parentChainRpc,
};
}

parsed.hostname = 'host.docker.internal';

return {
rpcUrl: parsed.toString(),
dockerRunArgs: ['--add-host', 'host.docker.internal:host-gateway'],
};
}

function parseOrbitChainContractVersionsResult(
result: string | GetOrbitChainContractVersionsResult,
): GetOrbitChainContractVersionsResult {
const parsed =
typeof result === 'string'
? (() => {
try {
return JSON.parse(result) as unknown;
} catch {
throw new Error('Failed to parse Orbit chain contract versions');
}
})()
: result;

if (
typeof parsed !== 'object' ||
parsed === null ||
!('versions' in parsed) ||
!('upgradeRecommendation' in parsed)
) {
throw new Error('Failed to parse Orbit chain contract versions');
}

return parsed as GetOrbitChainContractVersionsResult;
}

async function getOrbitChainContractVersionsWithDocker(
inboxAddress: Address,
parentChainRpc: string,
image: string,
): Promise<GetOrbitChainContractVersionsResult> {
const dockerConfig = getDockerNetworkConfig(parentChainRpc);

const { stdout } = await runDockerCommand({
image,
entrypoint: 'yarn',
...(dockerConfig.dockerRunArgs ? { dockerRunArgs: dockerConfig.dockerRunArgs } : {}),
command: ['--silent', 'orbit:contracts:version'],
env: {
INBOX_ADDRESS: inboxAddress,
PARENT_CHAIN_RPC: dockerConfig.rpcUrl,
JSON_OUTPUT: 'true',
},
});

return parseOrbitChainContractVersionsResult(stdout);
}

async function getOrbitChainContractVersionsWithNative(
inboxAddress: Address,
parentChainRpc: string,
): Promise<GetOrbitChainContractVersionsResult> {
const result = await runOrbitVersioner(inboxAddress, parentChainRpc, true);

return parseOrbitChainContractVersionsResult(result);
}

export async function getOrbitChainContractVersions(
inboxAddress: Address,
parentChainRpc: string,
executionMode = 'native',
image = DEFAULT_ORBIT_ACTIONS_IMAGE,
): Promise<GetOrbitChainContractVersionsResult> {
if (executionMode.toLowerCase() === 'docker') {
return getOrbitChainContractVersionsWithDocker(inboxAddress, parentChainRpc, image);
}

return getOrbitChainContractVersionsWithNative(inboxAddress, parentChainRpc);
}
Loading
Loading