From 3f0f1ae52a03fe68c4be2f00df80d8d0aa43736c Mon Sep 17 00:00:00 2001 From: Christophe Deveaux Date: Tue, 3 Sep 2024 18:58:37 +0200 Subject: [PATCH 1/7] test: add integration tests for new SequencerInbox utils (#178) --- src/actions/buildInvalidateKeysetHash.ts | 2 +- .../sequencerInbox.integration.test.ts | 223 ++++++++++++++++++ 2 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 src/actions/sequencerInbox.integration.test.ts diff --git a/src/actions/buildInvalidateKeysetHash.ts b/src/actions/buildInvalidateKeysetHash.ts index 30b55039..68b92548 100644 --- a/src/actions/buildInvalidateKeysetHash.ts +++ b/src/actions/buildInvalidateKeysetHash.ts @@ -41,7 +41,7 @@ export async function buildInvalidateKeysetHash { + const defaultMaxTimeVariation = { + delayBlocks: 5_760n, + delaySeconds: 86_400n, + futureBlocks: 12n, + futureSeconds: 3_600n, + }; + it('getMaxTimeVariation successfully fetches max time variation', async () => { + const result = await getMaxTimeVariation(client, { + sequencerInbox: l3SequencerInbox, + }); + expect(result).toEqual(defaultMaxTimeVariation); + }); + + it('buildSetMaxTimeVariation successfully set max time varation', async () => { + async function setMaxTimeVariation(changes: { + delayBlocks: bigint; + futureBlocks: bigint; + delaySeconds: bigint; + futureSeconds: bigint; + }) { + const transactionRequest = await buildSetMaxTimeVariation(client, { + sequencerInbox: l3SequencerInbox, + upgradeExecutor: l3UpgradeExecutor, + ...changes, + + account: l3RollupOwner.address, + }); + const txHash = await client.sendRawTransaction({ + serializedTransaction: await l3RollupOwner.signTransaction(transactionRequest), + }); + + await client.waitForTransactionReceipt({ hash: txHash }); + } + + const changes = { + delayBlocks: 2_880n, + futureBlocks: 6n, + delaySeconds: 43_200n, + futureSeconds: 1_800n, + }; + await setMaxTimeVariation(changes); + const newResult = await getMaxTimeVariation(client, { + sequencerInbox: l3SequencerInbox, + }); + expect(newResult).toEqual(changes); + + await setMaxTimeVariation(defaultMaxTimeVariation); + const finalResult = await getMaxTimeVariation(client, { + sequencerInbox: l3SequencerInbox, + }); + expect(finalResult).toEqual(defaultMaxTimeVariation); + }); +}); + +describe('batch poster management', () => { + it('isBatchPoster successfully fetches whether or an address is a batch poster', async () => { + const isNotBatchPosterAddress = await isBatchPoster(client, { + sequencerInbox: l3SequencerInbox, + batchPoster: zeroAddress, + }); + expect(isNotBatchPosterAddress).toBeFalsy(); + const isBatchPosterAddress = await isBatchPoster(client, { + sequencerInbox: l3SequencerInbox, + batchPoster: l3BatchPoster, + }); + expect(isBatchPosterAddress).toBeTruthy(); + }); + + it('successfully enable or disable an address as batch poster', async () => { + const randomAddress = privateKeyToAccount(generatePrivateKey()).address; + const isRandomAddressBatchPoster = await isBatchPoster(client, { + sequencerInbox: l3SequencerInbox, + batchPoster: randomAddress, + }); + expect(isRandomAddressBatchPoster).toBeFalsy(); + + const enableTransactionRequest = await buildEnableBatchPoster(client, { + sequencerInbox: l3SequencerInbox, + upgradeExecutor: l3UpgradeExecutor, + batchPoster: randomAddress, + account: l3RollupOwner.address, + }); + const enableTxHash = await client.sendRawTransaction({ + serializedTransaction: await l3RollupOwner.signTransaction(enableTransactionRequest), + }); + await client.waitForTransactionReceipt({ hash: enableTxHash }); + const isRandomAddressBatchPosterAfterEnabling = await isBatchPoster(client, { + sequencerInbox: l3SequencerInbox, + batchPoster: randomAddress, + }); + expect(isRandomAddressBatchPosterAfterEnabling).toBeTruthy(); + + const disableTransactionRequest = await buildDisableBatchPoster(client, { + sequencerInbox: l3SequencerInbox, + upgradeExecutor: l3UpgradeExecutor, + batchPoster: randomAddress, + account: l3RollupOwner.address, + }); + const disableTxHash = await client.sendRawTransaction({ + serializedTransaction: await l3RollupOwner.signTransaction(disableTransactionRequest), + }); + await client.waitForTransactionReceipt({ hash: disableTxHash }); + const isRandomAddressBatchPosterAfterDisabling = await isBatchPoster(client, { + sequencerInbox: l3SequencerInbox, + batchPoster: randomAddress, + }); + expect(isRandomAddressBatchPosterAfterDisabling).toBeFalsy(); + }); +}); + +describe('keyset management', () => { + const keysetBytes = + '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002560000000000000002000000000000000201216006dcb5e56764bb72e6a45e6deb301ca85d8c4315c1da2efa29927f2ac8fb25571ce31d2d603735fe03196f6d56bcbf9a1999a89a74d5369822c4445d676c15ed52e5008daa775dc9a839c99ff963a19946ac740579874dac4f639907ae1bc69f0c6694955b524d718ca445831c5375393773401f33725a79661379dddabd5fff28619dc070befd9ed73d699e5c236c1a163be58ba81002b6130709bc064af5d7ba947130b72056bf17263800f1a3ab2269c6a510ef8e7412fd56d1ef1b916a1306e3b1d9c82c099371bd9861582acaada3a16e9dfee5d0ebce61096598a82f112d0a935e8cab5c48d82e3104b0c7ba79157dad1a019a3e7f6ad077b8e6308b116fec0f58239622463c3631fa01e2b4272409215b8009422c16715dbede5909060121600835f995f2478f24892d050daa289f8b6b9c1b185bcd28532f88d610c2642a2dc6f3509740236d33c3e2d9136aab17f819c8c671293bba277717762e8d1c1f7bac9e17dd28d2939a959bb38e500f9c11c38cebbc426e2dea97c40175a655d17400ae6c75ff49e884c79469249e70953258854b64fa8445c585ad45dc6dc6975501c6af7cff7074202c687f8a7bf1a3ac192689755f232275b4c8421b1a5669e9b904c29a292cdf961b783a7c0b4ce736900de4d8c63c5f85a65cb44af34bef840acef84ab75f44c4c9137610b68107aff3bbdcc19119c7a927c115b7b9bfb27d85c500ee77d13ec5a97a3ae6bf51d3b70a5502e8416de7b5eb8e9feee376411ca35c8a7f3f597c7606578cf96a4715ce5a35cf48e39c0a1faa2dee22d74e681900000000000000000000'; + async function deployAnyTrustChainWithKeyset(keyset: Hex) { + const batchPosters = [deployer.address]; + const validators = [deployer.address]; + + const { createRollupInformation } = await createRollupHelper({ + deployer: l3TokenBridgeDeployer, + batchPosters, + validators, + nativeToken: zeroAddress, + client, + }); + + const { sequencerInbox, upgradeExecutor } = createRollupInformation.coreContracts; + const transactionRequest = await buildSetValidKeyset(client, { + sequencerInbox: sequencerInbox, + keyset, + account: l3TokenBridgeDeployer.address, + upgradeExecutor, + }); + const transactionHash = await client.sendRawTransaction({ + serializedTransaction: await l3TokenBridgeDeployer.signTransaction(transactionRequest), + }); + await client.waitForTransactionReceipt({ hash: transactionHash }); + const logs = await client.getContractEvents({ + address: sequencerInbox, + abi: sequencerInboxABI, + eventName: 'SetValidKeyset', + }); + + const keysetHash = logs.find((log) => log.args.keysetBytes === keyset)?.args.keysetHash; + + return { + keysetHash, + sequencerInbox, + upgradeExecutor, + }; + } + + it('isValidKeysetHash successfully fetches whether a hash is a valid keyset hash', async () => { + const invalidKeysetHash = await isValidKeysetHash(client, { + sequencerInbox: l3SequencerInbox, + keysetHash: '0x0000000000000000000000000000000000000000000000000000000000000000', + }); + expect(invalidKeysetHash).toBeFalsy(); + + const { sequencerInbox, keysetHash } = await deployAnyTrustChainWithKeyset(keysetBytes); + + const result = await isValidKeysetHash(client, { + sequencerInbox, + keysetHash: keysetHash!, + }); + expect(result).toBeTruthy(); + }); + + it('successfully invalidate a keyset hash', async () => { + const { sequencerInbox, keysetHash, upgradeExecutor } = await deployAnyTrustChainWithKeyset( + keysetBytes, + ); + + const result = await isValidKeysetHash(client, { + sequencerInbox, + keysetHash: keysetHash!, + }); + expect(result).toBeTruthy(); + + const transactionRequest = await buildInvalidateKeysetHash(client, { + keysetHash: keysetHash!, + sequencerInbox, + account: l3TokenBridgeDeployer.address, + upgradeExecutor, + }); + const txHash = await client.sendRawTransaction({ + serializedTransaction: await l3TokenBridgeDeployer.signTransaction(transactionRequest), + }); + await client.waitForTransactionReceipt({ hash: txHash }); + + const resultAfterChange = await isValidKeysetHash(client, { + sequencerInbox, + keysetHash: keysetHash!, + }); + expect(resultAfterChange).toBeFalsy(); + }); +}); From c2ca2f223b5f7d9616ff4918a9a1ff23a327c11c Mon Sep 17 00:00:00 2001 From: spsjvc Date: Mon, 9 Sep 2024 12:42:34 +0200 Subject: [PATCH 2/7] test: update expected ArbOS and client versions (#180) --- src/utils/getArbOSVersion.unit.test.ts | 20 +++++++++++--------- src/utils/getClientVersion.unit.test.ts | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/utils/getArbOSVersion.unit.test.ts b/src/utils/getArbOSVersion.unit.test.ts index f3f8038b..a90aacee 100644 --- a/src/utils/getArbOSVersion.unit.test.ts +++ b/src/utils/getArbOSVersion.unit.test.ts @@ -1,21 +1,23 @@ import { it, expect } from 'vitest'; +import { createPublicClient, http } from 'viem'; +import { arbitrum as arbitrumOne, sepolia } from 'viem/chains'; import { getArbOSVersion } from './getArbOSVersion'; -import { createPublicClient, http } from 'viem'; -import { arbitrum, sepolia } from 'viem/chains'; -it('Returns the ArbOS version for arbitrum chain', async () => { - const arbProvider = createPublicClient({ - chain: arbitrum, +it('returns the ArbOS version of Arbitrum One', async () => { + const arbitrumOneClient = createPublicClient({ + chain: arbitrumOne, transport: http(), }); - expect(await getArbOSVersion(arbProvider)).toBe(20); + + expect(await getArbOSVersion(arbitrumOneClient)).toBe(31); }); -it('Throws if the provider is not an Arbitrum provider', async () => { - const sepoliaProvider = createPublicClient({ +it('throws if the chain is not an Arbitrum chain', async () => { + const sepoliaClient = createPublicClient({ chain: sepolia, transport: http(), }); - await expect(getArbOSVersion(sepoliaProvider)).rejects.toThrowError(); + + await expect(getArbOSVersion(sepoliaClient)).rejects.toThrowError(); }); diff --git a/src/utils/getClientVersion.unit.test.ts b/src/utils/getClientVersion.unit.test.ts index 9d8eda71..2481b8ba 100644 --- a/src/utils/getClientVersion.unit.test.ts +++ b/src/utils/getClientVersion.unit.test.ts @@ -11,10 +11,10 @@ const arbitrumSepoliaPublicClient = createPublicClient({ it('fetches client version with public client', async () => { const clientVersion = await getClientVersion(arbitrumSepoliaPublicClient); - expect(clientVersion.startsWith('nitro/v3')).toBeTruthy(); + expect(clientVersion.startsWith('nitro/')).toBeTruthy(); }); it('fetches client version with rpc url', async () => { const clientVersion = await getClientVersion('https://sepolia-rollup.arbitrum.io/rpc'); - expect(clientVersion.startsWith('nitro/v3')).toBeTruthy(); + expect(clientVersion.startsWith('nitro/')).toBeTruthy(); }); From a77dc3339dec98f89c490a244e277a950ff0756a Mon Sep 17 00:00:00 2001 From: spsjvc Date: Mon, 9 Sep 2024 13:04:50 +0200 Subject: [PATCH 3/7] refactor: split getters into separate files (#179) --- src/createRollup.ts | 2 +- ...createRollupEnoughCustomFeeTokenAllowance.ts | 2 +- ...eCustomFeeTokenApprovalTransactionRequest.ts | 2 +- src/createRollupPrepareTransactionRequest.ts | 2 +- src/createTokenBridge.ts | 5 +---- ...eTokenBridgeEnoughCustomFeeTokenAllowance.ts | 2 +- ...reateTokenBridgeFetchTokenBridgeContracts.ts | 2 +- ...eCustomFeeTokenApprovalTransactionRequest.ts | 2 +- ...reateTokenBridgePrepareTransactionRequest.ts | 2 +- src/utils/getBlockExplorerUrl.ts | 5 +++++ src/utils/getRollupCreatorAddress.ts | 16 ++++++++++++++++ ...tters.ts => getTokenBridgeCreatorAddress.ts} | 17 ----------------- src/utils/index.ts | 3 ++- 13 files changed, 32 insertions(+), 30 deletions(-) create mode 100644 src/utils/getBlockExplorerUrl.ts create mode 100644 src/utils/getRollupCreatorAddress.ts rename src/utils/{getters.ts => getTokenBridgeCreatorAddress.ts} (51%) diff --git a/src/createRollup.ts b/src/createRollup.ts index eeb20b37..fab36b79 100644 --- a/src/createRollup.ts +++ b/src/createRollup.ts @@ -8,7 +8,7 @@ import { } from './createRollupPrepareTransactionReceipt'; import { createRollupEnoughCustomFeeTokenAllowance } from './createRollupEnoughCustomFeeTokenAllowance'; import { createRollupPrepareCustomFeeTokenApprovalTransactionRequest } from './createRollupPrepareCustomFeeTokenApprovalTransactionRequest'; -import { getBlockExplorerUrl } from './utils/getters'; +import { getBlockExplorerUrl } from './utils/getBlockExplorerUrl'; import { CreateRollupTransaction, createRollupPrepareTransaction, diff --git a/src/createRollupEnoughCustomFeeTokenAllowance.ts b/src/createRollupEnoughCustomFeeTokenAllowance.ts index 1fa8e5e0..5ff4f2e4 100644 --- a/src/createRollupEnoughCustomFeeTokenAllowance.ts +++ b/src/createRollupEnoughCustomFeeTokenAllowance.ts @@ -1,7 +1,7 @@ import { Address, PublicClient, Transport, Chain } from 'viem'; import { fetchAllowance } from './utils/erc20'; -import { getRollupCreatorAddress } from './utils/getters'; +import { getRollupCreatorAddress } from './utils/getRollupCreatorAddress'; import { createRollupDefaultRetryablesFees } from './constants'; import { Prettify } from './types/utils'; diff --git a/src/createRollupPrepareCustomFeeTokenApprovalTransactionRequest.ts b/src/createRollupPrepareCustomFeeTokenApprovalTransactionRequest.ts index 6961882d..752d5433 100644 --- a/src/createRollupPrepareCustomFeeTokenApprovalTransactionRequest.ts +++ b/src/createRollupPrepareCustomFeeTokenApprovalTransactionRequest.ts @@ -2,7 +2,7 @@ import { Address, PublicClient, Transport, Chain } from 'viem'; import { approvePrepareTransactionRequest } from './utils/erc20'; import { validateParentChain } from './types/ParentChain'; -import { getRollupCreatorAddress } from './utils/getters'; +import { getRollupCreatorAddress } from './utils/getRollupCreatorAddress'; import { createRollupDefaultRetryablesFees } from './constants'; import { Prettify } from './types/utils'; diff --git a/src/createRollupPrepareTransactionRequest.ts b/src/createRollupPrepareTransactionRequest.ts index 76eee497..fa790d05 100644 --- a/src/createRollupPrepareTransactionRequest.ts +++ b/src/createRollupPrepareTransactionRequest.ts @@ -8,7 +8,7 @@ import { validateParentChain } from './types/ParentChain'; import { isCustomFeeTokenAddress } from './utils/isCustomFeeTokenAddress'; import { ChainConfig } from './types/ChainConfig'; import { isAnyTrustChainConfig } from './utils/isAnyTrustChainConfig'; -import { getRollupCreatorAddress } from './utils/getters'; +import { getRollupCreatorAddress } from './utils/getRollupCreatorAddress'; import { fetchDecimals } from './utils/erc20'; import { TransactionRequestGasOverrides, applyPercentIncrease } from './utils/gasOverrides'; diff --git a/src/createTokenBridge.ts b/src/createTokenBridge.ts index cc4291e7..25cea9ed 100644 --- a/src/createTokenBridge.ts +++ b/src/createTokenBridge.ts @@ -33,10 +33,7 @@ import { import { isCustomFeeTokenAddress } from './utils/isCustomFeeTokenAddress'; import { WithTokenBridgeCreatorAddressOverride } from './types/createTokenBridgeTypes'; import { TransactionRequestGasOverrides } from './utils/gasOverrides'; - -function getBlockExplorerUrl(chain: Chain | undefined) { - return chain?.blockExplorers?.default.url; -} +import { getBlockExplorerUrl } from './utils/getBlockExplorerUrl'; export type CreateTokenBridgeParams< TParentChain extends Chain | undefined, diff --git a/src/createTokenBridgeEnoughCustomFeeTokenAllowance.ts b/src/createTokenBridgeEnoughCustomFeeTokenAllowance.ts index 85daacbb..1d4fbb87 100644 --- a/src/createTokenBridgeEnoughCustomFeeTokenAllowance.ts +++ b/src/createTokenBridgeEnoughCustomFeeTokenAllowance.ts @@ -5,7 +5,7 @@ import { createTokenBridgeDefaultRetryablesFees } from './constants'; import { Prettify } from './types/utils'; import { WithTokenBridgeCreatorAddressOverride } from './types/createTokenBridgeTypes'; -import { getTokenBridgeCreatorAddress } from './utils/getters'; +import { getTokenBridgeCreatorAddress } from './utils/getTokenBridgeCreatorAddress'; export type CreateTokenBridgeEnoughCustomFeeTokenAllowanceParams = Prettify< diff --git a/src/createTokenBridgeFetchTokenBridgeContracts.ts b/src/createTokenBridgeFetchTokenBridgeContracts.ts index f4121be8..b1fff792 100644 --- a/src/createTokenBridgeFetchTokenBridgeContracts.ts +++ b/src/createTokenBridgeFetchTokenBridgeContracts.ts @@ -5,7 +5,7 @@ import { tokenBridgeCreatorABI } from './contracts/TokenBridgeCreator'; import { Prettify } from './types/utils'; import { WithTokenBridgeCreatorAddressOverride } from './types/createTokenBridgeTypes'; import { TokenBridgeContracts } from './types/TokenBridgeContracts'; -import { getTokenBridgeCreatorAddress } from './utils/getters'; +import { getTokenBridgeCreatorAddress } from './utils/getTokenBridgeCreatorAddress'; export type CreateTokenBridgeFetchTokenBridgeContractsParams = Prettify< diff --git a/src/createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest.ts b/src/createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest.ts index 814e8812..090258e7 100644 --- a/src/createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest.ts +++ b/src/createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest.ts @@ -5,7 +5,7 @@ import { approvePrepareTransactionRequest } from './utils/erc20'; import { Prettify } from './types/utils'; import { validateParentChain } from './types/ParentChain'; import { WithTokenBridgeCreatorAddressOverride } from './types/createTokenBridgeTypes'; -import { getTokenBridgeCreatorAddress } from './utils/getters'; +import { getTokenBridgeCreatorAddress } from './utils/getTokenBridgeCreatorAddress'; export type CreateTokenBridgePrepareCustomFeeTokenApprovalTransactionRequestParams< TChain extends Chain | undefined, diff --git a/src/createTokenBridgePrepareTransactionRequest.ts b/src/createTokenBridgePrepareTransactionRequest.ts index e357bf9f..b5c04f34 100644 --- a/src/createTokenBridgePrepareTransactionRequest.ts +++ b/src/createTokenBridgePrepareTransactionRequest.ts @@ -12,7 +12,7 @@ import { import { Prettify } from './types/utils'; import { WithTokenBridgeCreatorAddressOverride } from './types/createTokenBridgeTypes'; -import { getTokenBridgeCreatorAddress } from './utils/getters'; +import { getTokenBridgeCreatorAddress } from './utils/getTokenBridgeCreatorAddress'; export type TransactionRequestRetryableGasOverrides = { maxSubmissionCostForFactory?: GasOverrideOptions; diff --git a/src/utils/getBlockExplorerUrl.ts b/src/utils/getBlockExplorerUrl.ts new file mode 100644 index 00000000..11e45e43 --- /dev/null +++ b/src/utils/getBlockExplorerUrl.ts @@ -0,0 +1,5 @@ +import { Chain } from 'viem'; + +export function getBlockExplorerUrl(chain: Chain | undefined) { + return chain?.blockExplorers?.default.url; +} diff --git a/src/utils/getRollupCreatorAddress.ts b/src/utils/getRollupCreatorAddress.ts new file mode 100644 index 00000000..c3515c38 --- /dev/null +++ b/src/utils/getRollupCreatorAddress.ts @@ -0,0 +1,16 @@ +import { Client, Transport, Chain } from 'viem'; + +import { rollupCreatorAddress } from '../contracts/RollupCreator'; +import { validateParentChain } from '../types/ParentChain'; + +export function getRollupCreatorAddress( + client: Client, +) { + const chainId = validateParentChain(client); + + if (!rollupCreatorAddress[chainId]) { + throw new Error(`Parent chain not supported: ${chainId}`); + } + + return rollupCreatorAddress[chainId]; +} diff --git a/src/utils/getters.ts b/src/utils/getTokenBridgeCreatorAddress.ts similarity index 51% rename from src/utils/getters.ts rename to src/utils/getTokenBridgeCreatorAddress.ts index e22fa15f..5fe88893 100644 --- a/src/utils/getters.ts +++ b/src/utils/getTokenBridgeCreatorAddress.ts @@ -1,21 +1,8 @@ import { Client, Transport, Chain } from 'viem'; -import { rollupCreatorAddress } from '../contracts/RollupCreator'; import { tokenBridgeCreatorAddress } from '../contracts/TokenBridgeCreator'; import { validateParentChain } from '../types/ParentChain'; -export function getRollupCreatorAddress( - client: Client, -) { - const chainId = validateParentChain(client); - - if (!rollupCreatorAddress[chainId]) { - throw new Error(`Parent chain not supported: ${chainId}`); - } - - return rollupCreatorAddress[chainId]; -} - export function getTokenBridgeCreatorAddress( client: Client, ) { @@ -27,7 +14,3 @@ export function getTokenBridgeCreatorAddress( return tokenBridgeCreatorAddress[chainId]; } - -export function getBlockExplorerUrl(chain: Chain) { - return chain.blockExplorers?.default.url; -} diff --git a/src/utils/index.ts b/src/utils/index.ts index f9af6393..72b138ab 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -4,7 +4,8 @@ import { getParentChainLayer } from './getParentChainLayer'; import { sanitizePrivateKey } from './sanitizePrivateKey'; import { getArbOSVersion } from './getArbOSVersion'; import { getClientVersion } from './getClientVersion'; -import { getRollupCreatorAddress, getTokenBridgeCreatorAddress } from './getters'; +import { getRollupCreatorAddress } from './getRollupCreatorAddress'; +import { getTokenBridgeCreatorAddress } from './getTokenBridgeCreatorAddress'; export { generateChainId, From ab740390dbd55ea413b5cad1d19b653864d71d71 Mon Sep 17 00:00:00 2001 From: Christophe Deveaux Date: Tue, 10 Sep 2024 14:35:27 +0200 Subject: [PATCH 4/7] feat: move getters and setters params into object (#182) --- src/actions/buildInvalidateKeysetHash.ts | 10 +++- src/actions/buildSetIsBatchPoster.ts | 20 +++++-- src/actions/buildSetMaxTimeVariation.ts | 10 +++- src/actions/buildSetValidKeyset.ts | 10 +++- src/actions/getMaxTimeVariation.ts | 4 +- src/actions/isBatchPoster.ts | 6 +- src/actions/isValidKeysetHash.ts | 6 +- .../sequencerInbox.integration.test.ts | 55 ++++++++++++++----- src/types/Actions.ts | 18 +++--- 9 files changed, 92 insertions(+), 47 deletions(-) diff --git a/src/actions/buildInvalidateKeysetHash.ts b/src/actions/buildInvalidateKeysetHash.ts index 68b92548..fdc29550 100644 --- a/src/actions/buildInvalidateKeysetHash.ts +++ b/src/actions/buildInvalidateKeysetHash.ts @@ -28,10 +28,14 @@ export type BuildInvalidateKeysetHashReturnType = PrepareTransactionRequestRetur export async function buildInvalidateKeysetHash( client: PublicClient, - params: BuildInvalidateKeysetHashParameters, + { + account, + upgradeExecutor, + sequencerInbox: sequencerInboxAddress, + params, + }: BuildInvalidateKeysetHashParameters, ): Promise { const validatedPublicClient = validateParentChainPublicClient(client); - const { account, upgradeExecutor, sequencerInbox: sequencerInboxAddress, ...args } = params; const request = await client.prepareTransactionRequest({ chain: client.chain, @@ -39,7 +43,7 @@ export async function buildInvalidateKeysetHash( client: PublicClient, - params: BuildSetIsBatchPosterParameters & { enable: boolean }, + { + account, + upgradeExecutor, + sequencerInbox: sequencerInboxAddress, + params, + }: BuildSetIsBatchPosterParameters & { params: { enable: boolean } }, ): Promise { const validatedPublicClient = validateParentChainPublicClient(client); - const { account, upgradeExecutor, sequencerInbox: sequencerInboxAddress, ...args } = params; const request = await client.prepareTransactionRequest({ chain: client.chain, @@ -33,7 +37,7 @@ export async function buildSetIsBatchPoster( ...prepareUpgradeExecutorCallParameters({ to: sequencerInboxAddress, upgradeExecutor, - args: [args.batchPoster, args.enable], + args: [params.batchPoster, params.enable], abi: sequencerInboxABI, functionName: 'setIsBatchPoster', }), @@ -48,7 +52,10 @@ export async function buildEnableBatchPoster( ): Promise { return buildSetIsBatchPoster(client, { ...args, - enable: true, + params: { + ...args.params, + enable: true, + }, }); } @@ -58,6 +65,9 @@ export async function buildDisableBatchPoster( ): Promise { return buildSetIsBatchPoster(client, { ...args, - enable: false, + params: { + ...args.params, + enable: false, + }, }); } diff --git a/src/actions/buildSetMaxTimeVariation.ts b/src/actions/buildSetMaxTimeVariation.ts index aef110fa..3fad2176 100644 --- a/src/actions/buildSetMaxTimeVariation.ts +++ b/src/actions/buildSetMaxTimeVariation.ts @@ -24,10 +24,14 @@ export type BuildSetMaxTimeVariationReturnType = PrepareTransactionRequestReturn export async function buildSetMaxTimeVariation( client: PublicClient, - params: BuildSetMaxTimeVariationParameters, + { + account, + upgradeExecutor, + sequencerInbox: sequencerInboxAddress, + params, + }: BuildSetMaxTimeVariationParameters, ): Promise { const validatedPublicClient = validateParentChainPublicClient(client); - const { account, upgradeExecutor, sequencerInbox: sequencerInboxAddress, ...args } = params; const request = await client.prepareTransactionRequest({ chain: client.chain, @@ -35,7 +39,7 @@ export async function buildSetMaxTimeVariation ...prepareUpgradeExecutorCallParameters({ to: sequencerInboxAddress, upgradeExecutor, - args: [args], + args: [params], abi: sequencerInboxABI, functionName: 'setMaxTimeVariation', }), diff --git a/src/actions/buildSetValidKeyset.ts b/src/actions/buildSetValidKeyset.ts index c690a41c..666b1fda 100644 --- a/src/actions/buildSetValidKeyset.ts +++ b/src/actions/buildSetValidKeyset.ts @@ -28,10 +28,14 @@ export type BuildSetValidKeysetReturnType = PrepareTransactionRequestReturnTypeW export async function buildSetValidKeyset( client: PublicClient, - params: BuildSetValidKeysetParameters, + { + account, + upgradeExecutor, + sequencerInbox: sequencerInboxAddress, + params, + }: BuildSetValidKeysetParameters, ): Promise { const validatedPublicClient = validateParentChainPublicClient(client); - const { account, upgradeExecutor, sequencerInbox: sequencerInboxAddress, ...args } = params; const request = await client.prepareTransactionRequest({ chain: client.chain, @@ -39,7 +43,7 @@ export async function buildSetValidKeyset( ...prepareUpgradeExecutorCallParameters({ to: sequencerInboxAddress, upgradeExecutor, - args: [args.keyset], + args: [params.keyset], abi: sequencerInboxABI, functionName: 'setValidKeyset', }), diff --git a/src/actions/getMaxTimeVariation.ts b/src/actions/getMaxTimeVariation.ts index b0bfe82c..4924a757 100644 --- a/src/actions/getMaxTimeVariation.ts +++ b/src/actions/getMaxTimeVariation.ts @@ -17,12 +17,12 @@ export type GetMaxTimeVariationReturnType = { export async function getMaxTimeVariation( client: PublicClient, - args: GetMaxTimeVariationParameters, + { sequencerInbox }: GetMaxTimeVariationParameters, ): Promise { const [delayBlocks, futureBlocks, delaySeconds, futureSeconds] = await client.readContract({ abi: sequencerInboxABI, functionName: 'maxTimeVariation', - address: args.sequencerInbox, + address: sequencerInbox, }); return { delayBlocks, diff --git a/src/actions/isBatchPoster.ts b/src/actions/isBatchPoster.ts index f71b773f..39e24894 100644 --- a/src/actions/isBatchPoster.ts +++ b/src/actions/isBatchPoster.ts @@ -18,12 +18,12 @@ export type IsBatchPosterReturnType = ReadContractReturnType< export async function isBatchPoster( client: PublicClient, - args: IsBatchPosterParameters, + { sequencerInbox, params }: IsBatchPosterParameters, ): Promise { return client.readContract({ abi: sequencerInboxABI, functionName: 'isBatchPoster', - address: args.sequencerInbox, - args: [args.batchPoster], + address: sequencerInbox, + args: [params.batchPoster], }); } diff --git a/src/actions/isValidKeysetHash.ts b/src/actions/isValidKeysetHash.ts index 1a5e7007..3ef15828 100644 --- a/src/actions/isValidKeysetHash.ts +++ b/src/actions/isValidKeysetHash.ts @@ -19,12 +19,12 @@ export type IsValidKeysetHashReturnType = ReadContractReturnType< export async function isValidKeysetHash( client: PublicClient, - args: IsValidKeysetHashParameters, + { sequencerInbox, params }: IsValidKeysetHashParameters, ): Promise { return client.readContract({ abi: sequencerInboxABI, functionName: 'isValidKeysetHash', - address: args.sequencerInbox, - args: [args.keysetHash], + address: sequencerInbox, + args: [params.keysetHash], }); } diff --git a/src/actions/sequencerInbox.integration.test.ts b/src/actions/sequencerInbox.integration.test.ts index 1ebd1e3f..56ad1074 100644 --- a/src/actions/sequencerInbox.integration.test.ts +++ b/src/actions/sequencerInbox.integration.test.ts @@ -48,9 +48,8 @@ describe('max time variation management', () => { const transactionRequest = await buildSetMaxTimeVariation(client, { sequencerInbox: l3SequencerInbox, upgradeExecutor: l3UpgradeExecutor, - ...changes, - account: l3RollupOwner.address, + params: changes, }); const txHash = await client.sendRawTransaction({ serializedTransaction: await l3RollupOwner.signTransaction(transactionRequest), @@ -83,12 +82,16 @@ describe('batch poster management', () => { it('isBatchPoster successfully fetches whether or an address is a batch poster', async () => { const isNotBatchPosterAddress = await isBatchPoster(client, { sequencerInbox: l3SequencerInbox, - batchPoster: zeroAddress, + params: { + batchPoster: zeroAddress, + }, }); expect(isNotBatchPosterAddress).toBeFalsy(); const isBatchPosterAddress = await isBatchPoster(client, { sequencerInbox: l3SequencerInbox, - batchPoster: l3BatchPoster, + params: { + batchPoster: l3BatchPoster, + }, }); expect(isBatchPosterAddress).toBeTruthy(); }); @@ -97,15 +100,19 @@ describe('batch poster management', () => { const randomAddress = privateKeyToAccount(generatePrivateKey()).address; const isRandomAddressBatchPoster = await isBatchPoster(client, { sequencerInbox: l3SequencerInbox, - batchPoster: randomAddress, + params: { + batchPoster: randomAddress, + }, }); expect(isRandomAddressBatchPoster).toBeFalsy(); const enableTransactionRequest = await buildEnableBatchPoster(client, { sequencerInbox: l3SequencerInbox, upgradeExecutor: l3UpgradeExecutor, - batchPoster: randomAddress, account: l3RollupOwner.address, + params: { + batchPoster: randomAddress, + }, }); const enableTxHash = await client.sendRawTransaction({ serializedTransaction: await l3RollupOwner.signTransaction(enableTransactionRequest), @@ -113,15 +120,19 @@ describe('batch poster management', () => { await client.waitForTransactionReceipt({ hash: enableTxHash }); const isRandomAddressBatchPosterAfterEnabling = await isBatchPoster(client, { sequencerInbox: l3SequencerInbox, - batchPoster: randomAddress, + params: { + batchPoster: randomAddress, + }, }); expect(isRandomAddressBatchPosterAfterEnabling).toBeTruthy(); const disableTransactionRequest = await buildDisableBatchPoster(client, { sequencerInbox: l3SequencerInbox, upgradeExecutor: l3UpgradeExecutor, - batchPoster: randomAddress, account: l3RollupOwner.address, + params: { + batchPoster: randomAddress, + }, }); const disableTxHash = await client.sendRawTransaction({ serializedTransaction: await l3RollupOwner.signTransaction(disableTransactionRequest), @@ -129,7 +140,9 @@ describe('batch poster management', () => { await client.waitForTransactionReceipt({ hash: disableTxHash }); const isRandomAddressBatchPosterAfterDisabling = await isBatchPoster(client, { sequencerInbox: l3SequencerInbox, - batchPoster: randomAddress, + params: { + batchPoster: randomAddress, + }, }); expect(isRandomAddressBatchPosterAfterDisabling).toBeFalsy(); }); @@ -153,9 +166,11 @@ describe('keyset management', () => { const { sequencerInbox, upgradeExecutor } = createRollupInformation.coreContracts; const transactionRequest = await buildSetValidKeyset(client, { sequencerInbox: sequencerInbox, - keyset, account: l3TokenBridgeDeployer.address, upgradeExecutor, + params: { + keyset, + }, }); const transactionHash = await client.sendRawTransaction({ serializedTransaction: await l3TokenBridgeDeployer.signTransaction(transactionRequest), @@ -179,7 +194,9 @@ describe('keyset management', () => { it('isValidKeysetHash successfully fetches whether a hash is a valid keyset hash', async () => { const invalidKeysetHash = await isValidKeysetHash(client, { sequencerInbox: l3SequencerInbox, - keysetHash: '0x0000000000000000000000000000000000000000000000000000000000000000', + params: { + keysetHash: '0x0000000000000000000000000000000000000000000000000000000000000000', + }, }); expect(invalidKeysetHash).toBeFalsy(); @@ -187,7 +204,9 @@ describe('keyset management', () => { const result = await isValidKeysetHash(client, { sequencerInbox, - keysetHash: keysetHash!, + params: { + keysetHash: keysetHash!, + }, }); expect(result).toBeTruthy(); }); @@ -199,15 +218,19 @@ describe('keyset management', () => { const result = await isValidKeysetHash(client, { sequencerInbox, - keysetHash: keysetHash!, + params: { + keysetHash: keysetHash!, + }, }); expect(result).toBeTruthy(); const transactionRequest = await buildInvalidateKeysetHash(client, { - keysetHash: keysetHash!, sequencerInbox, account: l3TokenBridgeDeployer.address, upgradeExecutor, + params: { + keysetHash: keysetHash!, + }, }); const txHash = await client.sendRawTransaction({ serializedTransaction: await l3TokenBridgeDeployer.signTransaction(transactionRequest), @@ -216,7 +239,9 @@ describe('keyset management', () => { const resultAfterChange = await isValidKeysetHash(client, { sequencerInbox, - keysetHash: keysetHash!, + params: { + keysetHash: keysetHash!, + }, }); expect(resultAfterChange).toBeFalsy(); }); diff --git a/src/types/Actions.ts b/src/types/Actions.ts index ba515953..71093865 100644 --- a/src/types/Actions.ts +++ b/src/types/Actions.ts @@ -1,6 +1,8 @@ import { Address, PrepareTransactionRequestReturnType } from 'viem'; import { Prettify } from './utils'; +type isEmptyObject = Args extends Record ? true : false; + /** * Actions require contract address, but as part of decorators, the address might have been passed already to the decorator. * @@ -9,16 +11,12 @@ import { Prettify } from './utils'; */ export type ActionParameters = Prettify< Curried extends false - ? Args & { [key in ContractName]: Address } - : Args extends Record - ? - | { - [key in ContractName]: Address; - } - | void - : Args & { - [key in ContractName]?: Address; - } + ? isEmptyObject extends true + ? { [key in ContractName]: Address } // Contract wasn't curried. Args is an empty object. Only requires the contract name + : { params: Args } & { [key in ContractName]: Address } // Contract wasn't curried. Args is not empty. Requires both params and contract name + : isEmptyObject extends true + ? { [key in ContractName]: Address } | void // Contract was curried. Args is empty. Only requires the contract name. Allows no parameters + : { params: Args } & { [key in ContractName]?: Address } // Contract was curried. Args is not empty. Requires params, contract name is optional >; export type WithAccount = Args & { From 5fb25331e9c10bdb7da2ee05e7bd619d0fce9e10 Mon Sep 17 00:00:00 2001 From: spsjvc Date: Tue, 10 Sep 2024 14:55:44 +0200 Subject: [PATCH 5/7] chore: bump version --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index 316eca52..014cd073 100644 --- a/src/package.json +++ b/src/package.json @@ -1,7 +1,7 @@ { "name": "@arbitrum/orbit-sdk", "description": "TypeScript SDK for building Arbitrum Orbit chains", - "version": "0.19.0-beta.0", + "version": "0.19.0", "main": "./dist/index.js", "files": [ "./dist" From 15e0ddd92a206758bc28377072765fbed1eec34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20FP?= <105675159+TucksonDev@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:01:40 +0100 Subject: [PATCH 6/7] fix: update node params needed for fast withdrawal (#183) --- examples/setup-fast-withdrawal/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/setup-fast-withdrawal/index.ts b/examples/setup-fast-withdrawal/index.ts index f8ad21e3..2ca146c6 100644 --- a/examples/setup-fast-withdrawal/index.ts +++ b/examples/setup-fast-withdrawal/index.ts @@ -301,16 +301,15 @@ async function main() { // Batch poster configuration const timeDelay = getTimeDelayFromNumberOfBlocks(parentChain.id, minimumAssertionPeriod); - console.log('Your batch poster has to run at least nitro v3.1.1'); + console.log('Your batch poster has to run at least nitro v3.1.2'); console.log('Add the following parameter:'); console.log(`--node.batch-poster.max-delay=${timeDelay}`); console.log(''); // Validator configuration - console.log('Your validators have to run at least nitro v3.1.1'); + console.log('Your validators have to run at least nitro v3.1.2'); console.log('Add the following parameters:'); console.log(`--node.staker.enable-fast-confirmation=true`); - console.log(`--node.staker.fast-confirm-safe-address=${safeAddress}`); console.log(`--node.staker.make-assertion-interval=${timeDelay}`); console.log(''); From 2f33e44220ecac81465c83ee94ff2f28cd8c9936 Mon Sep 17 00:00:00 2001 From: Jason-W123 <147362502+Jason-W123@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:06:20 +0800 Subject: [PATCH 7/7] refactor: use getValidators method in set validators example (#185) --- examples/set-new-validators/index.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/examples/set-new-validators/index.ts b/examples/set-new-validators/index.ts index d8858e7b..d26f38b7 100644 --- a/examples/set-new-validators/index.ts +++ b/examples/set-new-validators/index.ts @@ -5,6 +5,8 @@ import { createRollupFetchTransactionHash, createRollupPrepareTransactionReceipt, rollupAdminLogicPublicActions, + // Uncomment it when you want to use getValidators() to get validator status + // getValidators, } from '@arbitrum/orbit-sdk'; import { sanitizePrivateKey } from '@arbitrum/orbit-sdk/utils'; import { config } from 'dotenv'; @@ -76,6 +78,17 @@ async function main() { `Before executing, the address ${newValidators[0]} status in validator list is ${beforeStatus}`, ); + /* + You can also use the following code to check validator status, it will return a list + of whitelist validators. + + console.log('Fetching current validator address list in the parent chain...'); + const beforeValidatorList = await getValidators(parentChainPublicClient, { + rollup: coreContracts.rollup, + }); + console.log(`Before executing, the validator list is ${beforeValidatorList.validators}`); + */ + // prepare set validator transaction request const setValidatorTransactionRequest = await parentChainPublicClient.rollupAdminLogicPrepareTransactionRequest({