Skip to content

Commit

Permalink
feat: add createRollupFetchTransactionHash (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
TucksonDev authored Jan 24, 2024
1 parent 2a7d274 commit b7b0c4f
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 58 deletions.
95 changes: 37 additions & 58 deletions src/createRollup.integration.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
71 changes: 71 additions & 0 deletions src/createRollupFetchTransactionHash.ts
Original file line number Diff line number Diff line change
@@ -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;
}
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import {
createRollupPrepareTransactionReceipt,
CreateRollupTransactionReceipt,
} from './createRollupPrepareTransactionReceipt';
import {
createRollupFetchTransactionHash,
CreateRollupFetchTransactionHashParams,
} from './createRollupFetchTransactionHash';
import { setValidKeyset, SetValidKeysetParams } from './setValidKeyset';
import {
setValidKeysetPrepareTransactionRequest,
Expand Down Expand Up @@ -58,6 +62,8 @@ export {
CreateRollupTransaction,
createRollupPrepareTransactionReceipt,
CreateRollupTransactionReceipt,
createRollupFetchTransactionHash,
CreateRollupFetchTransactionHashParams,
setValidKeyset,
SetValidKeysetParams,
setValidKeysetPrepareTransactionRequest,
Expand Down
86 changes: 86 additions & 0 deletions src/utils/testHelpers.ts
Original file line number Diff line number Diff line change
@@ -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<CreateTestRollupResult> {
// 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,
};
}

0 comments on commit b7b0c4f

Please sign in to comment.