From b7b0c4f322604b5d179e0db644083d07254749ad Mon Sep 17 00:00:00 2001 From: Tuckson <105675159+TucksonDev@users.noreply.github.com> Date: Wed, 24 Jan 2024 12:24:23 +0000 Subject: [PATCH] feat: add createRollupFetchTransactionHash (#30) --- src/createRollup.integration.test.ts | 95 ++++++++++--------------- src/createRollupFetchTransactionHash.ts | 71 ++++++++++++++++++ src/index.ts | 6 ++ src/utils/testHelpers.ts | 86 ++++++++++++++++++++++ 4 files changed, 200 insertions(+), 58 deletions(-) create mode 100644 src/createRollupFetchTransactionHash.ts create mode 100644 src/utils/testHelpers.ts diff --git a/src/createRollup.integration.test.ts b/src/createRollup.integration.test.ts index 15893e18..682a921e 100644 --- a/src/createRollup.integration.test.ts +++ b/src/createRollup.integration.test.ts @@ -1,76 +1,55 @@ -import { it, expect } from 'vitest'; +import { describe, it, expect } from 'vitest'; import { createPublicClient, http, parseGwei, zeroAddress } from 'viem'; import { nitroTestnodeL2 } from './chains'; -import { generateChainId } from './utils'; -import { prepareChainConfig } from './prepareChainConfig'; -import { createRollupPrepareConfig } from './createRollupPrepareConfig'; -import { createRollupPrepareTransaction } from './createRollupPrepareTransaction'; -import { createRollupPrepareTransactionRequest } from './createRollupPrepareTransactionRequest'; -import { createRollupPrepareTransactionReceipt } from './createRollupPrepareTransactionReceipt'; - import { getTestPrivateKeyAccount } from './testHelpers'; +import { createRollupFetchTransactionHash } from './createRollupFetchTransactionHash'; +import { createTestRollup } from './utils/testHelpers'; -const deployer = getTestPrivateKeyAccount(); - -const batchPoster = deployer.address; -const validators = [deployer.address]; - +// public client const publicClient = createPublicClient({ chain: nitroTestnodeL2, transport: http(), }); -it(`successfully deploys core contracts through rollup creator`, async () => { - // generate a random chain id - const chainId = generateChainId(); - - // create the chain config - const chainConfig = prepareChainConfig({ - chainId, - arbitrum: { InitialChainOwner: deployer.address }, - }); - - const config = createRollupPrepareConfig({ - chainId: BigInt(chainId), - owner: deployer.address, - chainConfig, - }); +// test inputs +const deployer = getTestPrivateKeyAccount(); +const batchPoster = deployer.address; +const validators = [deployer.address]; - // prepare the transaction for deploying the core contracts - const request = await createRollupPrepareTransactionRequest({ - params: { - config, - batchPoster, - validators, - }, - account: deployer.address, +describe(`createRollup`, async () => { + // create test rollup + const createRollupInformation = await createTestRollup({ + deployer, + batchPoster, + validators, publicClient, }); - // sign and send the transaction - const txHash = await publicClient.sendRawTransaction({ - serializedTransaction: await deployer.signTransaction(request), + it(`successfully deploys core contracts through rollup creator`, async () => { + // assert all inputs are correct + const [arg] = createRollupInformation.transaction.getInputs(); + expect(arg.config).toEqual(createRollupInformation.config); + expect(arg.batchPoster).toEqual(batchPoster); + expect(arg.validators).toEqual(validators); + expect(arg.maxDataSize).toEqual(104_857n); + expect(arg.nativeToken).toEqual(zeroAddress); + expect(arg.deployFactoriesToL2).toEqual(true); + expect(arg.maxFeePerGasForRetryables).toEqual(parseGwei('0.1')); + + // assert the transaction executed successfully + expect(createRollupInformation.transactionReceipt.status).toEqual('success'); + + // assert the core contracts were successfully obtained + expect(createRollupInformation.coreContracts).toBeDefined(); }); - // get the transaction - const tx = createRollupPrepareTransaction(await publicClient.getTransaction({ hash: txHash })); - - const [arg] = tx.getInputs(); - // assert all inputs are correct - expect(arg.config).toEqual(config); - expect(arg.batchPoster).toEqual(batchPoster); - expect(arg.validators).toEqual(validators); - expect(arg.maxDataSize).toEqual(104_857n); - expect(arg.nativeToken).toEqual(zeroAddress); - expect(arg.deployFactoriesToL2).toEqual(true); - expect(arg.maxFeePerGasForRetryables).toEqual(parseGwei('0.1')); + it('finds the transaction hash that created a specified deployed rollup contract', async () => { + const transactionHash = await createRollupFetchTransactionHash({ + rollup: createRollupInformation.coreContracts.rollup, + publicClient, + }); - // get the transaction receipt after waiting for the transaction to complete - const txReceipt = createRollupPrepareTransactionReceipt( - await publicClient.waitForTransactionReceipt({ hash: txHash }), - ); - - expect(txReceipt.status).toEqual('success'); - expect(() => txReceipt.getCoreContracts()).not.toThrowError(); + expect(transactionHash).toEqual(createRollupInformation.transactionReceipt.transactionHash); + }); }); diff --git a/src/createRollupFetchTransactionHash.ts b/src/createRollupFetchTransactionHash.ts new file mode 100644 index 00000000..1c759a07 --- /dev/null +++ b/src/createRollupFetchTransactionHash.ts @@ -0,0 +1,71 @@ +import { Address, PublicClient } from 'viem'; +import { AbiEvent } from 'abitype'; +import { ParentChainId } from './types/ParentChain'; +import { sepolia, arbitrumSepolia, nitroTestnodeL1, nitroTestnodeL2 } from './chains'; + +export type CreateRollupFetchTransactionHashParams = { + rollup: Address; + publicClient: PublicClient; +}; + +const RollupInitializedEventAbi: AbiEvent = { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'bytes32', + name: 'machineHash', + type: 'bytes32', + }, + { + indexed: false, + internalType: 'uint256', + name: 'chainId', + type: 'uint256', + }, + ], + name: 'RollupInitialized', + type: 'event', +}; + +const earliestRollupCreatorDeploymentBlockNumber = { + // testnet + [sepolia.id]: 4741823n, + [arbitrumSepolia.id]: 654628n, + [nitroTestnodeL1.id]: 0n, + [nitroTestnodeL2.id]: 0n, +}; + +export async function createRollupFetchTransactionHash({ + rollup, + publicClient, +}: CreateRollupFetchTransactionHashParams) { + // Find the RollupInitialized event from that Rollup contract + const chainId = await publicClient.getChainId(); + const fromBlock = + chainId in Object.keys(earliestRollupCreatorDeploymentBlockNumber) + ? earliestRollupCreatorDeploymentBlockNumber[chainId as ParentChainId] + : 'earliest'; + + const rollupInitializedEvents = await publicClient.getLogs({ + address: rollup, + event: RollupInitializedEventAbi, + fromBlock, + toBlock: 'latest', + }); + if (rollupInitializedEvents.length !== 1) { + throw new Error( + `Expected to find 1 RollupInitialized event for rollup address ${rollup} but found ${rollupInitializedEvents.length}`, + ); + } + + // Get the transaction hash that emitted that event + const transactionHash = rollupInitializedEvents[0].transactionHash; + if (!transactionHash) { + throw new Error( + `No transactionHash found in RollupInitialized event for rollup address ${rollup}`, + ); + } + + return transactionHash; +} diff --git a/src/index.ts b/src/index.ts index 6f5adbd3..2cb41fca 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,6 +22,10 @@ import { createRollupPrepareTransactionReceipt, CreateRollupTransactionReceipt, } from './createRollupPrepareTransactionReceipt'; +import { + createRollupFetchTransactionHash, + CreateRollupFetchTransactionHashParams, +} from './createRollupFetchTransactionHash'; import { setValidKeyset, SetValidKeysetParams } from './setValidKeyset'; import { setValidKeysetPrepareTransactionRequest, @@ -58,6 +62,8 @@ export { CreateRollupTransaction, createRollupPrepareTransactionReceipt, CreateRollupTransactionReceipt, + createRollupFetchTransactionHash, + CreateRollupFetchTransactionHashParams, setValidKeyset, SetValidKeysetParams, setValidKeysetPrepareTransactionRequest, diff --git a/src/utils/testHelpers.ts b/src/utils/testHelpers.ts new file mode 100644 index 00000000..1857d5de --- /dev/null +++ b/src/utils/testHelpers.ts @@ -0,0 +1,86 @@ +import { Address, PrivateKeyAccount, PublicClient } from 'viem'; +import { + CreateRollupPrepareConfigResult, + createRollupPrepareConfig, +} from '../createRollupPrepareConfig'; +import { createRollupPrepareTransactionRequest } from '../createRollupPrepareTransactionRequest'; +import { prepareChainConfig } from '../prepareChainConfig'; +import { generateChainId } from './generateChainId'; +import { + CreateRollupTransaction, + createRollupPrepareTransaction, +} from '../createRollupPrepareTransaction'; +import { + CreateRollupTransactionReceipt, + createRollupPrepareTransactionReceipt, +} from '../createRollupPrepareTransactionReceipt'; +import { CoreContracts } from '../types/CoreContracts'; + +export type CreateTestRollupParams = { + deployer: PrivateKeyAccount; + batchPoster: Address; + validators: Address[]; + publicClient: PublicClient; +}; + +export type CreateTestRollupResult = { + config: CreateRollupPrepareConfigResult; + transaction: CreateRollupTransaction; + transactionReceipt: CreateRollupTransactionReceipt; + coreContracts: CoreContracts; +}; + +export async function createTestRollup({ + deployer, + batchPoster, + validators, + publicClient, +}: CreateTestRollupParams): Promise { + // generate a random chain id + const chainId = generateChainId(); + + // create the chain config + const chainConfig = prepareChainConfig({ + chainId, + arbitrum: { InitialChainOwner: deployer.address }, + }); + + const config = createRollupPrepareConfig({ + chainId: BigInt(chainId), + owner: deployer.address, + chainConfig, + }); + + // prepare the transaction for deploying the core contracts + const request = await createRollupPrepareTransactionRequest({ + params: { + config, + batchPoster, + validators, + }, + account: deployer.address, + publicClient, + }); + + // sign and send the transaction + const txHash = await publicClient.sendRawTransaction({ + serializedTransaction: await deployer.signTransaction(request), + }); + + // get the transaction + const tx = createRollupPrepareTransaction(await publicClient.getTransaction({ hash: txHash })); + + // get the transaction receipt after waiting for the transaction to complete + const txReceipt = createRollupPrepareTransactionReceipt( + await publicClient.waitForTransactionReceipt({ hash: txHash }), + ); + + const coreContracts = txReceipt.getCoreContracts(); + + return { + config, + transaction: tx, + transactionReceipt: txReceipt, + coreContracts, + }; +}