Skip to content

Commit 08e523d

Browse files
committed
test: deploy token bridge creator contracts on L2
1 parent f31888c commit 08e523d

File tree

5 files changed

+188
-45
lines changed

5 files changed

+188
-45
lines changed

.github/workflows/build-test.yml

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,54 @@ jobs:
269269
tags: |
270270
${{ env.NITRO_CONTRACTS_GHCR_IMAGE }}
271271
272+
publish-token-bridge-contracts-image:
273+
name: Publish Token Bridge Contracts Image
274+
runs-on: ubuntu-latest
275+
permissions:
276+
contents: read
277+
packages: write
278+
steps:
279+
- name: Checkout
280+
uses: actions/checkout@v4
281+
282+
- name: Set token bridge contracts image
283+
run: |
284+
echo "TOKEN_BRIDGE_CONTRACTS_GHCR_IMAGE=ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/chain-sdk-token-bridge-contracts:v1.2.2" >> "$GITHUB_ENV"
285+
286+
- name: Set up Docker Buildx
287+
uses: docker/setup-buildx-action@v3
288+
289+
- name: Log in to GHCR
290+
uses: docker/login-action@v3
291+
with:
292+
registry: ghcr.io
293+
username: ${{ github.actor }}
294+
password: ${{ secrets.GITHUB_TOKEN }}
295+
296+
- name: Check token bridge contracts image
297+
id: check-image
298+
run: |
299+
if docker manifest inspect "${TOKEN_BRIDGE_CONTRACTS_GHCR_IMAGE}" >/dev/null 2>&1; then
300+
echo "exists=true" >> "$GITHUB_OUTPUT"
301+
else
302+
echo "exists=false" >> "$GITHUB_OUTPUT"
303+
fi
304+
305+
- name: Build and push token bridge contracts image
306+
if: steps.check-image.outputs.exists != 'true'
307+
uses: docker/build-push-action@v6
308+
with:
309+
context: ./token-bridge-contracts
310+
file: ./token-bridge-contracts/Dockerfile
311+
push: true
312+
tags: |
313+
${{ env.TOKEN_BRIDGE_CONTRACTS_GHCR_IMAGE }}
314+
272315
test-integration-anvil:
273316
name: Test (Integration Anvil)
274-
needs: publish-nitro-contracts-image
317+
needs:
318+
- publish-nitro-contracts-image
319+
- publish-token-bridge-contracts-image
275320
runs-on: ubuntu-latest
276321
permissions:
277322
contents: read
@@ -283,6 +328,7 @@ jobs:
283328
- name: Set nitro contracts image
284329
run: |
285330
echo "NITRO_CONTRACTS_GHCR_IMAGE=ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/chain-sdk-nitro-contracts:v3.2.0-2f747c7" >> "$GITHUB_ENV"
331+
echo "TOKEN_BRIDGE_CONTRACTS_GHCR_IMAGE=ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/chain-sdk-token-bridge-contracts:v1.2.2" >> "$GITHUB_ENV"
286332
287333
- name: Log in to GHCR
288334
uses: docker/login-action@v3
@@ -294,6 +340,9 @@ jobs:
294340
- name: Load nitro contracts image
295341
run: docker pull "${NITRO_CONTRACTS_GHCR_IMAGE}"
296342

343+
- name: Load token bridge contracts image
344+
run: docker pull "${TOKEN_BRIDGE_CONTRACTS_GHCR_IMAGE}"
345+
297346
- name: Setup pnpm
298347
uses: pnpm/action-setup@v4
299348
with:

src/integrationTestHelpers/anvilHarness.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
createAccount,
4949
deployContract,
5050
deployRollupCreator,
51+
deployTokenBridgeCreator,
5152
ensureCreate2Factory,
5253
fundL2Deployer,
5354
refreshForkTime,
@@ -455,6 +456,22 @@ export async function setupAnvilTestStack(): Promise<AnvilTestStack> {
455456

456457
console.log('L2 rollup creator deployed\n');
457458

459+
console.log('Deploying L2 token bridge creator...');
460+
const l2TokenBridgeCreator = await deployTokenBridgeCreator(
461+
{
462+
networkName: dockerNetworkName,
463+
rpcUrl: `http://${l2ContainerName}:8449`,
464+
deployerPrivateKey: harnessDeployer.privateKey,
465+
wethAddress: customGasToken.address as Address,
466+
},
467+
{
468+
publicClient: l2Client,
469+
walletClient: blockAdvancerWalletClient,
470+
account: blockAdvancerAccount,
471+
},
472+
);
473+
console.log('L2 token bridge creator deployed\n');
474+
458475
await (
459476
await customGasToken.deposit({
460477
value: parseEther('10'),
@@ -475,7 +492,7 @@ export async function setupAnvilTestStack(): Promise<AnvilTestStack> {
475492
testnet: true,
476493
contracts: {
477494
rollupCreator: { address: l2RollupCreator },
478-
tokenBridgeCreator: { address: harnessDeployer.address },
495+
tokenBridgeCreator: { address: l2TokenBridgeCreator },
479496
weth: { address: customGasToken.address as Address },
480497
},
481498
});

src/integrationTestHelpers/anvilHarnessHelpers.ts

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ import { ethers } from 'ethers';
1414

1515
import { arbOwnerABI, arbOwnerAddress } from '../contracts/ArbOwner';
1616
import { testConstants } from './constants';
17-
import { dockerAsync, getNitroContractsImage } from './dockerHelpers';
17+
import {
18+
dockerAsync,
19+
getNitroContractsImage,
20+
getRollupCreatorDockerArgs,
21+
getTokenBridgeContractsImage,
22+
getTokenBridgeCreatorDockerArgs,
23+
} from './dockerHelpers';
1824
import type { PrivateKeyAccountWithPrivateKey } from '../testHelpers';
1925

2026
export type ContractArtifact = {
@@ -41,6 +47,14 @@ type DeployRollupCreatorParams = {
4147
chainId: number;
4248
};
4349

50+
type DeployTokenBridgeCreatorParams = {
51+
networkName: string;
52+
rpcUrl: string;
53+
deployerPrivateKey: `0x${string}`;
54+
wethAddress: Address;
55+
gasLimitForL2FactoryDeployment?: bigint;
56+
};
57+
4458
function sleep(ms: number) {
4559
return new Promise((resolve) => setTimeout(resolve, ms));
4660
}
@@ -68,41 +82,6 @@ async function getRequiredRetryableFunding(
6882
};
6983
}
7084

71-
function getRollupCreatorDockerArgs(
72-
params: Omit<DeployRollupCreatorParams, 'blockAdvancer'>,
73-
nitroContractsImage: string,
74-
) {
75-
return [
76-
'run',
77-
'--rm',
78-
'--network',
79-
params.networkName,
80-
'-e',
81-
`CUSTOM_RPC_URL=${params.rpcUrl}`,
82-
'-e',
83-
`CUSTOM_PRIVKEY=${params.deployerPrivateKey}`,
84-
'-e',
85-
`CUSTOM_CHAINID=${params.chainId}`,
86-
'-e',
87-
`FACTORY_OWNER=${params.factoryOwner}`,
88-
'-e',
89-
`MAX_DATA_SIZE=${params.maxDataSize}`,
90-
'-e',
91-
`POLLING_INTERVAL=${testConstants.NITRO_DEPLOY_POLLING_INTERVAL_MS}`,
92-
'-e',
93-
'DISABLE_VERIFICATION=true',
94-
'-e',
95-
'IGNORE_MAX_DATA_SIZE_WARNING=true',
96-
nitroContractsImage,
97-
'hardhat',
98-
'run',
99-
'--no-compile',
100-
'scripts/deployment.ts',
101-
'--network',
102-
'custom',
103-
];
104-
}
105-
10685
function parseRollupCreatorAddress(stdout: string): Address {
10786
const match = stdout.match(/\* RollupCreator created at address: (0x[0-9a-fA-F]{40})/);
10887
if (!match) {
@@ -112,6 +91,17 @@ function parseRollupCreatorAddress(stdout: string): Address {
11291
return match[1] as Address;
11392
}
11493

94+
function parseTokenBridgeCreatorAddress(stdout: string): Address {
95+
const match = stdout.match(/L1TokenBridgeCreator:\s*(0x[0-9a-fA-F]{40})/);
96+
if (!match) {
97+
throw new Error(
98+
`Failed to parse TokenBridgeCreator address from token bridge deploy output:\n${stdout}`,
99+
);
100+
}
101+
102+
return match[1] as Address;
103+
}
104+
115105
export function createAccount(privateKey?: Hex): PrivateKeyAccountWithPrivateKey {
116106
const normalizedPrivateKey = privateKey ?? generatePrivateKey();
117107
return {
@@ -345,7 +335,6 @@ export async function deployRollupCreator(
345335
blockAdvancer: BlockAdvancer,
346336
): Promise<Address> {
347337
const nitroContractsImage = getNitroContractsImage();
348-
const dockerRunStartedAt = Date.now();
349338
const stdout = await withBackgroundBlockAdvancing(blockAdvancer, () =>
350339
dockerAsync(
351340
getRollupCreatorDockerArgs(
@@ -361,11 +350,17 @@ export async function deployRollupCreator(
361350
),
362351
),
363352
);
364-
console.log(
365-
`[${new Date().toISOString()}] rollup creator docker run finished after ${
366-
Date.now() - dockerRunStartedAt
367-
}ms`,
368-
);
369353

370354
return parseRollupCreatorAddress(stdout);
371355
}
356+
357+
export async function deployTokenBridgeCreator(
358+
params: DeployTokenBridgeCreatorParams,
359+
blockAdvancer: BlockAdvancer,
360+
): Promise<Address> {
361+
const tokenBridgeContractsImage = getTokenBridgeContractsImage();
362+
const stdout = await withBackgroundBlockAdvancing(blockAdvancer, () =>
363+
dockerAsync(getTokenBridgeCreatorDockerArgs(params, tokenBridgeContractsImage)),
364+
);
365+
return parseTokenBridgeCreatorAddress(stdout);
366+
}

src/integrationTestHelpers/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ export const testConstants = {
55
DEFAULT_ANVIL_IMAGE: 'ghcr.io/foundry-rs/foundry:v1.3.1',
66
DEFAULT_NITRO_IMAGE: 'offchainlabs/nitro-node:v3.9.5-66e42c4',
77
DEFAULT_NITRO_CONTRACTS_IMAGE: 'ghcr.io/offchainlabs/chain-sdk-nitro-contracts:v3.2.0-2f747c7',
8+
DEFAULT_TOKEN_BRIDGE_CONTRACTS_IMAGE:
9+
'ghcr.io/offchainlabs/chain-sdk-token-bridge-contracts:v1.2.5',
810
DEPLOYER_PRIVATE_KEY:
911
'0x490d84b7602e4b470af4f86a3ad095607a8bb5a4fa8ba148f41fcfd236b4fdf5' as Address,
1012
DEFAULT_L2_CHAIN_ID: 421_337,

src/integrationTestHelpers/dockerHelpers.ts

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { execFile, execFileSync } from 'node:child_process';
22
import { rmSync } from 'node:fs';
33
import { join } from 'node:path';
44

5-
import { createPublicClient, http } from 'viem';
5+
import { createPublicClient, http, Address } from 'viem';
66

77
import { testConstants } from './constants';
88

@@ -51,6 +51,86 @@ export function getNitroContractsImage(): string {
5151
}
5252
}
5353

54+
export function getTokenBridgeContractsImage(): string {
55+
const image =
56+
process.env.TOKEN_BRIDGE_CONTRACTS_GHCR_IMAGE ??
57+
testConstants.DEFAULT_TOKEN_BRIDGE_CONTRACTS_IMAGE;
58+
try {
59+
docker(['image', 'inspect', image]);
60+
return image;
61+
} catch {
62+
const tokenBridgeContractsDir = join(process.cwd(), 'token-bridge-contracts');
63+
const dockerfilePath = join(tokenBridgeContractsDir, 'Dockerfile');
64+
docker(['build', '-f', dockerfilePath, '-t', image, tokenBridgeContractsDir]);
65+
66+
return image;
67+
}
68+
}
69+
70+
export function getRollupCreatorDockerArgs(params: {
71+
networkName: string;
72+
rpcUrl: string;
73+
deployerPrivateKey: `0x${string}`;
74+
factoryOwner: Address;
75+
maxDataSize: number;
76+
chainId: number;
77+
}, nitroContractsImage: string) {
78+
return [
79+
'run',
80+
'--rm',
81+
'--network',
82+
params.networkName,
83+
'-e',
84+
`CUSTOM_RPC_URL=${params.rpcUrl}`,
85+
'-e',
86+
`CUSTOM_PRIVKEY=${params.deployerPrivateKey}`,
87+
'-e',
88+
`CUSTOM_CHAINID=${params.chainId}`,
89+
'-e',
90+
`FACTORY_OWNER=${params.factoryOwner}`,
91+
'-e',
92+
`MAX_DATA_SIZE=${params.maxDataSize}`,
93+
'-e',
94+
`POLLING_INTERVAL=${testConstants.NITRO_DEPLOY_POLLING_INTERVAL_MS}`,
95+
'-e',
96+
'DISABLE_VERIFICATION=true',
97+
'-e',
98+
'IGNORE_MAX_DATA_SIZE_WARNING=true',
99+
nitroContractsImage,
100+
'hardhat',
101+
'run',
102+
'--no-compile',
103+
'scripts/deployment.ts',
104+
'--network',
105+
'custom',
106+
];
107+
}
108+
109+
export function getTokenBridgeCreatorDockerArgs(params: {
110+
networkName: string;
111+
rpcUrl: string;
112+
deployerPrivateKey: `0x${string}`;
113+
wethAddress: Address;
114+
gasLimitForL2FactoryDeployment?: bigint;
115+
}, tokenBridgeContractsImage: string) {
116+
return [
117+
'run',
118+
'--rm',
119+
'--network',
120+
params.networkName,
121+
'-e',
122+
`BASECHAIN_RPC=${params.rpcUrl}`,
123+
'-e',
124+
`BASECHAIN_DEPLOYER_KEY=${params.deployerPrivateKey}`,
125+
'-e',
126+
`BASECHAIN_WETH=${params.wethAddress}`,
127+
'-e',
128+
`GAS_LIMIT_FOR_L2_FACTORY_DEPLOYMENT=${params.gasLimitForL2FactoryDeployment ?? 10_000_000n}`,
129+
tokenBridgeContractsImage,
130+
'deploy:token-bridge-creator',
131+
];
132+
}
133+
54134
export function createDockerNetwork(networkName: string) {
55135
docker(['network', 'create', networkName]);
56136
}

0 commit comments

Comments
 (0)