Skip to content

Commit

Permalink
Merge branch 'feat-token-bridge-creator' into feat-add-weth-gateway-r…
Browse files Browse the repository at this point in the history
…egistration
  • Loading branch information
TucksonDev committed Feb 8, 2024
2 parents fc82da8 + bd90710 commit 4f51836
Show file tree
Hide file tree
Showing 22 changed files with 430 additions and 342 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARBISCAN_API_KEY=
NITRO_TESTNODE_DEPLOYER_PRIVATE_KEY=0xb6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659
NITRO_TESTNODE_L2_ROLLUP_OWNER_PRIVATE_KEY=0xcb5790da63720727af975f42c79f69918580209889225fa7128c92402a6d3a65
NITRO_TESTNODE_L2_ROLLUP_OWNER_PRIVATE_KEY=0xdc04c5399f82306ec4b4d654a342f40e2e0620fe39950d967e1e574b32d4dd36
NITRO_TESTNODE_L3_ROLLUP_OWNER_PRIVATE_KEY=0xecdf21cb41c65afb51f91df408b7656e2c8739a5877f2814add0afd780cc210e
13 changes: 7 additions & 6 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ jobs:
- name: Restore node_modules
uses: OffchainLabs/actions/node-modules/restore@main

- name: Copy .env
run: cp ./.env.example ./.env

- name: Generate
run: yarn generate

Expand Down Expand Up @@ -81,16 +84,14 @@ jobs:
- name: Set up the local node
uses: OffchainLabs/actions/run-nitro-test-node@main
with:
nitro-testnode-ref: master
# don't deploy the regular token bridge using arbitrum-sdk, as it will be deployed through the TokenBridgeCreator
no-token-bridge: true
nitro-testnode-ref: release
# Use simple mode
no-simple: false
# RollupCreator on L1 is deployed by default
# RollupCreator on L2 is deployed with --l3node
l3-node: true
# L3 node with custom fee token when using --l3-fee-token
# TokenBridgeCreator on L1 is deployed with --tokenbridge
# TokenBridgeCreator on L2 is deployed with --l3-token-bridge
args: --l3-fee-token --tokenbridge --l3-token-bridge
args: --l3-fee-token

- name: Copy .env
run: cp ./.env.example ./.env
Expand Down
2 changes: 1 addition & 1 deletion examples/create-token-bridge-custom-fee-token/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ CUSTOM_FEE_TOKEN_ADDRESS=

# Orbit chain configuration
ORBIT_CHAIN_ID=
ORBIT_CHAIN_RPC=
ORBIT_CHAIN_RPC=
31 changes: 25 additions & 6 deletions examples/create-token-bridge-custom-fee-token/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ const parentChainPublicClient = createPublicClient({
transport: http(),
});

// define chain config for the child chain
const childChain = defineChain({
// define chain config for the orbit chain
const orbitChain = defineChain({
id: Number(process.env.ORBIT_CHAIN_ID),
network: 'Orbit chain',
name: 'orbit',
Expand All @@ -65,7 +65,7 @@ const childChain = defineChain({
},
testnet: true,
});
const childChainPublicClient = createPublicClient({ chain: childChain, transport: http() });
const orbitChainPublicClient = createPublicClient({ chain: orbitChain, transport: http() });

// load the rollup owner account
const rollupOwner = privateKeyToAccount(sanitizePrivateKey(process.env.ROLLUP_OWNER_PRIVATE_KEY));
Expand All @@ -77,7 +77,7 @@ async function main() {
// prepare transaction to approve custom fee token spend
const allowanceParams = {
nativeToken,
account: rollupOwner.address,
owner: rollupOwner.address,
publicClient: parentChainPublicClient,
};
if (!(await createTokenBridgeEnoughCustomFeeTokenAllowance(allowanceParams))) {
Expand Down Expand Up @@ -108,11 +108,12 @@ async function main() {
rollupOwner: rollupOwner.address,
},
parentChainPublicClient,
childChainPublicClient,
orbitChainPublicClient,
account: rollupOwner.address,
});

// sign and send the transaction
console.log(`Deploying the TokenBridge...`);
const txHash = await parentChainPublicClient.sendRawTransaction({
serializedTransaction: await rollupOwner.signTransaction(txRequest),
});
Expand All @@ -121,8 +122,26 @@ async function main() {
const txReceipt = createTokenBridgePrepareTransactionReceipt(
await parentChainPublicClient.waitForTransactionReceipt({ hash: txHash }),
);

console.log(`Deployed in ${getBlockExplorerUrl(parentChain)}/tx/${txReceipt.transactionHash}`);

// wait for retryables to execute
console.log(`Waiting for retryable tickets to execute on the Orbit chain...`);
const orbitChainRetryableReceipts = await txReceipt.waitForRetryables({
orbitPublicClient: orbitChainPublicClient,
});
console.log(`Retryables executed`);
console.log(
`Transaction hash for first retryable is ${orbitChainRetryableReceipts[0].transactionHash}`,
);
console.log(
`Transaction hash for second retryable is ${orbitChainRetryableReceipts[1].transactionHash}`,
);

// fetching the TokenBridge contracts
const tokenBridgeContracts = await txReceipt.getTokenBridgeContracts({
parentChainPublicClient,
});
console.log(`TokenBridge contracts:`, tokenBridgeContracts);
}

main();
2 changes: 1 addition & 1 deletion examples/create-token-bridge-eth/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ ROLLUP_OWNER_PRIVATE_KEY=

# Orbit chain configuration
ORBIT_CHAIN_ID=
ORBIT_CHAIN_RPC=
ORBIT_CHAIN_RPC=
38 changes: 29 additions & 9 deletions examples/create-token-bridge-eth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ if (typeof process.env.ORBIT_CHAIN_RPC === 'undefined') {
const parentChain = arbitrumSepolia;
const parentChainPublicClient = createPublicClient({ chain: parentChain, transport: http() });

// define chain config for the child chain
const childChain = defineChain({
// define chain config for the orbit chain
const orbitChain = defineChain({
id: Number(process.env.ORBIT_CHAIN_ID),
network: 'Orbit chain',
name: 'orbit',
Expand All @@ -58,7 +58,7 @@ const childChain = defineChain({
},
testnet: true,
});
const childChainPublicClient = createPublicClient({ chain: childChain, transport: http() });
const orbitChainPublicClient = createPublicClient({ chain: orbitChain, transport: http() });

// load the rollup owner account
const rollupOwner = privateKeyToAccount(sanitizePrivateKey(process.env.ROLLUP_OWNER_PRIVATE_KEY));
Expand All @@ -71,11 +71,12 @@ async function main() {
rollupOwner: rollupOwner.address,
},
parentChainPublicClient,
childChainPublicClient,
orbitChainPublicClient,
account: rollupOwner.address,
});

// sign and send the transaction
console.log(`Deploying the TokenBridge...`);
const txHash = await parentChainPublicClient.sendRawTransaction({
serializedTransaction: await rollupOwner.signTransaction(txRequest),
});
Expand All @@ -84,17 +85,26 @@ async function main() {
const txReceipt = createTokenBridgePrepareTransactionReceipt(
await parentChainPublicClient.waitForTransactionReceipt({ hash: txHash }),
);

console.log(`Deployed in ${getBlockExplorerUrl(parentChain)}/tx/${txReceipt.transactionHash}`);

// waiting for retryables to execute, to prevent race conditions
await txReceipt.waitForRetryables({ orbitPublicClient: childChainPublicClient });
// wait for retryables to execute
console.log(`Waiting for retryable tickets to execute on the Orbit chain...`);
const orbitChainRetryableReceipts = await txReceipt.waitForRetryables({
orbitPublicClient: orbitChainPublicClient,
});
console.log(`Retryables executed`);
console.log(
`Transaction hash for first retryable is ${orbitChainRetryableReceipts[0].transactionHash}`,
);
console.log(
`Transaction hash for second retryable is ${orbitChainRetryableReceipts[1].transactionHash}`,
);

// set weth gateway
const setWethGatewayTxRequest = await createTokenBridgePrepareSetWethGatewayTransactionRequest({
rollup: process.env.ROLLUP_ADDRESS as `0x${string}`,
parentChainPublicClient,
childChainPublicClient,
orbitChainPublicClient,
account: rollupOwner.address,
gasOverrides: {
retryableTicketGasLimit: {
Expand All @@ -120,7 +130,17 @@ async function main() {
);

// Wait for retryables to execute
await setWethGatewayTxReceipt.waitForRetryables({ orbitPublicClient: childChainPublicClient });
const orbitChainSetWethGatewayRetryableReceipt = await setWethGatewayTxReceipt.waitForRetryables({ orbitPublicClient: orbitChainPublicClient });
console.log(`Retryables executed`);
console.log(
`Transaction hash for retryable is ${orbitChainSetWethGatewayRetryableReceipt.transactionHash}`,
);

// fetching the TokenBridge contracts
const tokenBridgeContracts = await txReceipt.getTokenBridgeContracts({
parentChainPublicClient,
});
console.log(`TokenBridge contracts:`, tokenBridgeContracts);
}

main();
3 changes: 1 addition & 2 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { parseEther } from 'viem';

export const deterministicFactoriesDeploymentEstimatedFees = parseEther(String('0.125'));
export const createTokenBridgeEstimatedFees = parseEther(String('0.02'));
export const createTokenBridgeDefaultRetryablesFees = parseEther('0.02');
export const createTokenBridgeDefaultGasLimit = 5_000_000n;
export const createTokenBridgeDefaultValue = parseEther('0.02');
31 changes: 25 additions & 6 deletions src/createRollupPrepareTransactionRequest.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Address, PublicClient, encodeFunctionData } from 'viem';
import { Address, PublicClient, encodeFunctionData, zeroAddress } from 'viem';

import { CreateRollupFunctionInputs, CreateRollupParams } from './createRollup';
import { defaults } from './createRollupDefaults';
Expand All @@ -9,6 +9,7 @@ import { validParentChainId } from './types/ParentChain';
import { isCustomFeeTokenAddress } from './utils/isCustomFeeTokenAddress';
import { ChainConfig } from './types/ChainConfig';
import { isAnyTrustChainConfig } from './utils/isAnyTrustChainConfig';
import { fetchDecimals } from './utils/erc20';

function createRollupEncodeFunctionData(args: CreateRollupFunctionInputs) {
return encodeFunctionData({
Expand All @@ -30,15 +31,33 @@ export async function createRollupPrepareTransactionRequest({
const chainId = publicClient.chain?.id;

if (!validParentChainId(chainId)) {
throw new Error('chainId is undefined');
throw new Error(`"publicClient.chain" can't be undefined.`);
}

if (params.batchPoster === zeroAddress) {
throw new Error(`"params.batchPoster" can't be set to the zero address.`);
}

if (params.validators.length === 0 || params.validators.includes(zeroAddress)) {
throw new Error(`"params.validators" can't be empty or contain the zero address.`);
}

const chainConfig: ChainConfig = JSON.parse(params.config.chainConfig);

if (isCustomFeeTokenAddress(params.nativeToken) && !isAnyTrustChainConfig(chainConfig)) {
throw new Error(
`Custom fee token can only be used on AnyTrust chains. Set "arbitrum.DataAvailabilityCommittee" to "true" in the chain config.`,
);
if (isCustomFeeTokenAddress(params.nativeToken)) {
// custom fee token is only allowed for anytrust chains
if (!isAnyTrustChainConfig(chainConfig)) {
throw new Error(
`"params.nativeToken" can only be used on AnyTrust chains. Set "arbitrum.DataAvailabilityCommittee" to "true" in the chain config.`,
);
}

// custom fee token is only allowed to have 18 decimals
if ((await fetchDecimals({ address: params.nativeToken, publicClient })) !== 18) {
throw new Error(
`"params.nativeToken" can only be configured with a token that uses 18 decimals.`,
);
}
}

const maxDataSize = createRollupGetMaxDataSize(chainId);
Expand Down
Loading

0 comments on commit 4f51836

Please sign in to comment.