Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add prepareArbitrumNetwork #221

Merged
merged 12 commits into from
Oct 31, 2024
17 changes: 13 additions & 4 deletions src/createRollupFetchTransactionHash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type CreateRollupFetchTransactionHashParams<TChain extends Chain | undefi
fromBlock?: bigint;
};

const RollupInitializedEventAbi: AbiEvent = {
const RollupInitializedEventAbi = {
anonymous: false,
inputs: [
{
Expand All @@ -28,9 +28,9 @@ const RollupInitializedEventAbi: AbiEvent = {
],
name: 'RollupInitialized',
type: 'event',
};
} as const satisfies AbiEvent;

export async function createRollupFetchTransactionHash<TChain extends Chain | undefined>({
export async function getRollupInitializedEvents<TChain extends Chain | undefined>({
rollup,
publicClient,
fromBlock,
Expand All @@ -48,8 +48,17 @@ export async function createRollupFetchTransactionHash<TChain extends Chain | un
);
}

return rollupInitializedEvents;
}

export async function createRollupFetchTransactionHash<TChain extends Chain | undefined>({
rollup,
publicClient,
fromBlock,
}: CreateRollupFetchTransactionHashParams<TChain>) {
// Get the transaction hash that emitted that event
const transactionHash = rollupInitializedEvents[0].transactionHash;
const transactionHash = (await getRollupInitializedEvents({ rollup, publicClient, fromBlock }))[0]
.transactionHash;

if (!transactionHash) {
throw new Error(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`prepareRegisterNewNetworkParams > should create orbit chain network object (Xai) 1`] = `
{
"chainId": 660279,
"confirmPeriodBlocks": 45818,
"ethBridge": {
"bridge": "0x7dd8A76bdAeBE3BBBaCD7Aa87f1D4FDa1E60f94f",
"inbox": "0xaE21fDA3de92dE2FDAF606233b2863782Ba046F9",
"outbox": "0x1E400568AD4840dbE50FB32f306B842e9ddeF726",
"rollup": "0xc47dacfbaa80bd9d8112f4e8069482c2a3221336",
"sequencerInbox": "0x995a9d3ca121D48d21087eDE20bc8acb2398c8B1",
},
"isCustom": true,
"isTestnet": false,
"name": "660279-arbitrum-network",
"nativeToken": "0x4Cb9a7AE498CEDcBb5EAe9f25736aE7d428C9D66",
"parentChainId": 42161,
"retryableLifetimeSeconds": 604800,
"tokenBridge": {
"childCustomGateway": "0x96551194230725c72ACF8E9573B1382CCBC70635",
"childErc20Gateway": "0x0c71417917D24F4A6A6A55559B98c5cCEcb33F7a",
"childGatewayRouter": "0xd096e8dE90D34de758B0E0bA4a796eA2e1e272cF",
"childMultiCall": "0xEEC168551A85911Ec3A905e0561b656979f3ea67",
"childProxyAdmin": "0x56800fDCFbE19Ea3EE9d115dAC30d95d6459c44E",
"childWeth": "0x0000000000000000000000000000000000000000",
"childWethGateway": "0x0000000000000000000000000000000000000000",
"parentCustomGateway": "0xb15A0826d65bE4c2fDd961b72636168ee70Af030",
"parentErc20Gateway": "0xb591cE747CF19cF30e11d656EB94134F523A9e77",
"parentGatewayRouter": "0x22CCA5Dc96a4Ac1EC32c9c7C5ad4D66254a24C35",
"parentMultiCall": "0x90B02D9F861017844F30dFbdF725b6aa84E63822",
"parentProxyAdmin": "0x041F85dD87c46B941dc9b15c6628B19ee5358485",
"parentWeth": "0x0000000000000000000000000000000000000000",
"parentWethGateway": "0x0000000000000000000000000000000000000000",
},
}
`;
37 changes: 37 additions & 0 deletions src/utils/__snapshots__/registerNewNetwork.unit.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`prepareRegisterNewNetworkParams > should create orbit chain network object (Xai) 1`] = `
{
"chainId": 660279,
"confirmPeriodBlocks": 45818,
"ethBridge": {
"bridge": "0x7dd8A76bdAeBE3BBBaCD7Aa87f1D4FDa1E60f94f",
"inbox": "0xaE21fDA3de92dE2FDAF606233b2863782Ba046F9",
"outbox": "0x1E400568AD4840dbE50FB32f306B842e9ddeF726",
"rollup": "0xc47dacfbaa80bd9d8112f4e8069482c2a3221336",
"sequencerInbox": "0x995a9d3ca121D48d21087eDE20bc8acb2398c8B1",
},
"isCustom": true,
"isTestnet": false,
"name": "660279-arbitrum-network",
"nativeToken": "0x4Cb9a7AE498CEDcBb5EAe9f25736aE7d428C9D66",
"parentChainId": 42161,
"retryableLifetimeSeconds": 604800,
"tokenBridge": {
"childCustomGateway": "0x96551194230725c72ACF8E9573B1382CCBC70635",
"childErc20Gateway": "0x0c71417917D24F4A6A6A55559B98c5cCEcb33F7a",
"childGatewayRouter": "0xd096e8dE90D34de758B0E0bA4a796eA2e1e272cF",
"childMultiCall": "0xEEC168551A85911Ec3A905e0561b656979f3ea67",
"childProxyAdmin": "0x56800fDCFbE19Ea3EE9d115dAC30d95d6459c44E",
"childWeth": "0x0000000000000000000000000000000000000000",
"childWethGateway": "0x0000000000000000000000000000000000000000",
"parentCustomGateway": "0xb15A0826d65bE4c2fDd961b72636168ee70Af030",
"parentErc20Gateway": "0xb591cE747CF19cF30e11d656EB94134F523A9e77",
"parentGatewayRouter": "0x22CCA5Dc96a4Ac1EC32c9c7C5ad4D66254a24C35",
"parentMultiCall": "0x90B02D9F861017844F30dFbdF725b6aa84E63822",
"parentProxyAdmin": "0x041F85dD87c46B941dc9b15c6628B19ee5358485",
"parentWeth": "0x0000000000000000000000000000000000000000",
"parentWethGateway": "0x0000000000000000000000000000000000000000",
},
}
`;
91 changes: 91 additions & 0 deletions src/utils/registerNewNetwork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,88 @@ import {
registerCustomArbitrumNetwork,
} from '@arbitrum/sdk';
import { testnets } from '../chains';
import {
createRollupFetchTransactionHash,
getRollupInitializedEvents,
} from '../createRollupFetchTransactionHash';
import { Address, Chain, PublicClient, Transport } from 'viem';
import { publicClientToProvider } from '../ethers-compat/publicClientToProvider';
import { createRollupPrepareTransactionReceipt } from '../createRollupPrepareTransactionReceipt';
import { createTokenBridgeFetchTokenBridgeContracts } from '../createTokenBridgeFetchTokenBridgeContracts';

const isTestnet = (parentChainId: number) => {
return testnets.some((testnet) => testnet.id === parentChainId);
};

export async function prepareRegisterNewNetworkParams<TChain extends Chain | undefined>({
parentChainPublicClient,
rollupAddress,
}: {
parentChainPublicClient: PublicClient<Transport, TChain>;
rollupAddress: Address;
}): Promise<ArbitrumNetwork> {
spsjvc marked this conversation as resolved.
Show resolved Hide resolved
const rollupInitializedEvent = await getRollupInitializedEvents({
rollup: rollupAddress,
publicClient: parentChainPublicClient,
});

// Fetch orbit chain chainId
const { chainId } = rollupInitializedEvent[0].args;
if (!chainId) {
throw new Error("RollupInitialized event doesn't contain chainId");
}

// Fetch native token address and TokenBridge address
const rollupCreationtransactionHash = await createRollupFetchTransactionHash({
rollup: rollupAddress,
publicClient: parentChainPublicClient,
});
const transactionReceipt = createRollupPrepareTransactionReceipt(
await parentChainPublicClient.waitForTransactionReceipt({
hash: rollupCreationtransactionHash,
}),
);
const { nativeToken, inbox, adminProxy } = transactionReceipt.getCoreContracts();
const { parentChainId, ethBridge, confirmPeriodBlocks } =
await getArbitrumNetworkInformationFromRollup(
rollupAddress,
publicClientToProvider(parentChainPublicClient),
);
const { parentChainContracts, orbitChainContracts } =
await createTokenBridgeFetchTokenBridgeContracts({
inbox,
parentChainPublicClient,
});

return {
name: String(`${chainId}-arbitrum-network`),
chainId: Number(chainId),
parentChainId,
confirmPeriodBlocks,
ethBridge,
isCustom: true,
isTestnet: isTestnet(parentChainId),
nativeToken,
tokenBridge: {
parentGatewayRouter: parentChainContracts.router,
childGatewayRouter: orbitChainContracts.router,
parentErc20Gateway: parentChainContracts.standardGateway,
childErc20Gateway: orbitChainContracts.standardGateway,
parentCustomGateway: parentChainContracts.customGateway,
childCustomGateway: orbitChainContracts.customGateway,
parentWethGateway: parentChainContracts.wethGateway,
childWethGateway: orbitChainContracts.wethGateway,
parentWeth: parentChainContracts.weth,
childWeth: orbitChainContracts.weth,
parentProxyAdmin: adminProxy,
childProxyAdmin: orbitChainContracts.proxyAdmin,
parentMultiCall: parentChainContracts.multicall,
childMultiCall: orbitChainContracts.multicall,
},
retryableLifetimeSeconds: 7 * 24 * 60 * 60, // 7 days
spsjvc marked this conversation as resolved.
Show resolved Hide resolved
} satisfies ArbitrumNetwork;
}

export const registerNewNetwork = async (
parentProvider: JsonRpcProvider,
childProvider: JsonRpcProvider,
Expand All @@ -31,3 +108,17 @@ export const registerNewNetwork = async (

return registerCustomArbitrumNetwork(arbitrumNetwork);
};

export async function registerNewNetworkFromParentPublicClient<TChain extends Chain | undefined>({
spsjvc marked this conversation as resolved.
Show resolved Hide resolved
parentChainPublicClient,
rollupAddress,
}: {
parentChainPublicClient: PublicClient<Transport, TChain>;
rollupAddress: Address;
}): Promise<ArbitrumNetwork> {
const arbitrumNetwork = await prepareRegisterNewNetworkParams({
parentChainPublicClient,
rollupAddress,
});
return registerCustomArbitrumNetwork(arbitrumNetwork);
}
49 changes: 49 additions & 0 deletions src/utils/registerNewNetwork.unit.test.ts
spsjvc marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { describe, expect, it } from 'vitest';
import { createPublicClient, http } from 'viem';

import {
prepareRegisterNewNetworkParams,
registerNewNetworkFromParentPublicClient,
} from './registerNewNetwork';
import { arbitrum } from 'viem/chains';
import { getArbitrumNetwork } from '@arbitrum/sdk';

const xaiRollupAddress = '0xc47dacfbaa80bd9d8112f4e8069482c2a3221336';
const client = createPublicClient({
chain: arbitrum,
transport: http(),
});

describe('prepareRegisterNewNetworkParams', () => {
it(`should create orbit chain network object (Xai)`, async () => {
const network = await prepareRegisterNewNetworkParams({
parentChainPublicClient: client,
rollupAddress: xaiRollupAddress,
});

expect(network).toMatchSnapshot();
});
});

describe('registerNewNetworkFromParentPublicClient', () => {
it('should create and register orbit chain network object (Xai)', async () => {
const xaiChainId = 660279;
const preparedNetwork = await prepareRegisterNewNetworkParams({
parentChainPublicClient: client,
rollupAddress: xaiRollupAddress,
});

// Network is not registered yet
expect(() => getArbitrumNetwork(xaiChainId)).toThrowError();

const network = await registerNewNetworkFromParentPublicClient({
parentChainPublicClient: client,
rollupAddress: xaiRollupAddress,
});

expect(network).toEqual(preparedNetwork);
// Network is now registered
const xaiNetwork = getArbitrumNetwork(xaiChainId);
expect(xaiNetwork).toEqual(network);
});
});