diff --git a/src/actions/buildSetConfirmPeriodBlocks.ts b/src/actions/buildSetConfirmPeriodBlocks.ts new file mode 100644 index 00000000..d59c531d --- /dev/null +++ b/src/actions/buildSetConfirmPeriodBlocks.ts @@ -0,0 +1,43 @@ +import { Chain, PrepareTransactionRequestParameters, PublicClient, Transport } from 'viem'; +import { rollupABI } from '../contracts/Rollup'; +import { + WithAccount, + ActionParameters, + WithUpgradeExecutor, + PrepareTransactionRequestReturnTypeWithChainId, +} from '../types/Actions'; +import { Prettify } from '../types/utils'; +import { getRollupAddress } from '../getRollupAddress'; +import { validateParentChainPublicClient } from '../types/ParentChain'; +import { prepareUpgradeExecutorCallParameters } from '../prepareUpgradeExecutorCallParameters'; + +export type BuildSetConfirmPeriodBlocksParameters = Prettify< + WithUpgradeExecutor< + WithAccount> + > +>; + +export type BuildSetConfirmPeriodBlocksReturnType = PrepareTransactionRequestReturnTypeWithChainId; + +export async function buildSetConfirmPeriodBlocks( + client: PublicClient, + { params, account, upgradeExecutor, ...args }: BuildSetConfirmPeriodBlocksParameters, +): Promise { + const validatedPublicClient = validateParentChainPublicClient(client); + const rollupAdminLogicAddress = + 'sequencerInbox' in args ? await getRollupAddress(client, args) : args.rollupAdminLogic; + + const request = await client.prepareTransactionRequest({ + chain: client.chain as Chain | undefined, + account, + ...prepareUpgradeExecutorCallParameters({ + to: rollupAdminLogicAddress, + upgradeExecutor, + args: [params.newPeriod], + abi: rollupABI, + functionName: 'setConfirmPeriodBlocks', + }), + } satisfies PrepareTransactionRequestParameters); + + return { ...request, chainId: validatedPublicClient.chain.id }; +} diff --git a/src/actions/buildSetExtraChallengeTimeBlocks.ts b/src/actions/buildSetExtraChallengeTimeBlocks.ts new file mode 100644 index 00000000..a0225ef1 --- /dev/null +++ b/src/actions/buildSetExtraChallengeTimeBlocks.ts @@ -0,0 +1,44 @@ +import { Chain, PrepareTransactionRequestParameters, PublicClient, Transport } from 'viem'; +import { rollupABI } from '../contracts/Rollup'; +import { + WithAccount, + ActionParameters, + WithUpgradeExecutor, + PrepareTransactionRequestReturnTypeWithChainId, +} from '../types/Actions'; +import { Prettify } from '../types/utils'; +import { getRollupAddress } from '../getRollupAddress'; +import { validateParentChainPublicClient } from '../types/ParentChain'; +import { prepareUpgradeExecutorCallParameters } from '../prepareUpgradeExecutorCallParameters'; + +export type BuildSetExtraChallengeTimeBlocksParameters = Prettify< + WithUpgradeExecutor< + WithAccount> + > +>; + +export type BuildSetExtraChallengeTimeBlocksReturnType = + PrepareTransactionRequestReturnTypeWithChainId; + +export async function buildSetExtraChallengeTimeBlocks( + client: PublicClient, + { params, account, upgradeExecutor, ...args }: BuildSetExtraChallengeTimeBlocksParameters, +): Promise { + const validatedPublicClient = validateParentChainPublicClient(client); + const rollupAdminLogicAddress = + 'sequencerInbox' in args ? await getRollupAddress(client, args) : args.rollupAdminLogic; + + const request = await client.prepareTransactionRequest({ + chain: client.chain as Chain | undefined, + account, + ...prepareUpgradeExecutorCallParameters({ + to: rollupAdminLogicAddress, + upgradeExecutor, + args: [params.newExtraTimeBlocks], + abi: rollupABI, + functionName: 'setExtraChallengeTimeBlocks', + }), + } satisfies PrepareTransactionRequestParameters); + + return { ...request, chainId: validatedPublicClient.chain.id }; +} diff --git a/src/actions/buildSetMinimumAssertionPeriod.ts b/src/actions/buildSetMinimumAssertionPeriod.ts new file mode 100644 index 00000000..5dff3ce1 --- /dev/null +++ b/src/actions/buildSetMinimumAssertionPeriod.ts @@ -0,0 +1,44 @@ +import { Chain, PrepareTransactionRequestParameters, PublicClient, Transport } from 'viem'; +import { rollupABI } from '../contracts/Rollup'; +import { + WithAccount, + ActionParameters, + PrepareTransactionRequestReturnTypeWithChainId, + WithUpgradeExecutor, +} from '../types/Actions'; +import { Prettify } from '../types/utils'; +import { getRollupAddress } from '../getRollupAddress'; +import { validateParentChainPublicClient } from '../types/ParentChain'; +import { prepareUpgradeExecutorCallParameters } from '../prepareUpgradeExecutorCallParameters'; + +export type BuildSetMinimumAssertionPeriodParameters = Prettify< + WithUpgradeExecutor< + WithAccount> + > +>; + +export type BuildSetMinimumAssertionPeriodReturnType = + PrepareTransactionRequestReturnTypeWithChainId; + +export async function buildSetMinimumAssertionPeriod( + client: PublicClient, + { params, account, upgradeExecutor, ...args }: BuildSetMinimumAssertionPeriodParameters, +): Promise { + const validatedPublicClient = validateParentChainPublicClient(client); + const rollupAdminLogicAddress = + 'sequencerInbox' in args ? await getRollupAddress(client, args) : args.rollupAdminLogic; + + const request = await client.prepareTransactionRequest({ + chain: client.chain as Chain | undefined, + account, + ...prepareUpgradeExecutorCallParameters({ + to: rollupAdminLogicAddress, + upgradeExecutor, + args: [params.newPeriod], + abi: rollupABI, + functionName: 'setMinimumAssertionPeriod', + }), + } satisfies PrepareTransactionRequestParameters); + + return { ...request, chainId: validatedPublicClient.chain.id }; +} diff --git a/src/actions/buildSetValidator.ts b/src/actions/buildSetValidator.ts new file mode 100644 index 00000000..09615b36 --- /dev/null +++ b/src/actions/buildSetValidator.ts @@ -0,0 +1,56 @@ +import { Address, Chain, PrepareTransactionRequestParameters, PublicClient, Transport } from 'viem'; +import { rollupABI } from '../contracts/Rollup'; +import { + WithAccount, + ActionParameters, + WithUpgradeExecutor, + PrepareTransactionRequestReturnTypeWithChainId, +} from '../types/Actions'; +import { Prettify } from '../types/utils'; +import { getRollupAddress } from '../getRollupAddress'; +import { validateParentChainPublicClient } from '../types/ParentChain'; +import { prepareUpgradeExecutorCallParameters } from '../prepareUpgradeExecutorCallParameters'; + +export type BuildSetIsValidatorParameters = Prettify< + WithUpgradeExecutor< + WithAccount< + ActionParameters< + { + add: Address[]; + remove: Address[]; + }, + 'rollupAdminLogic', + Curried + > + > + > +>; + +export type BuildSetIsValidatorReturnType = PrepareTransactionRequestReturnTypeWithChainId; + +export async function buildSetValidators( + client: PublicClient, + { account, upgradeExecutor, params, ...args }: BuildSetIsValidatorParameters, +): Promise { + const validatedPublicClient = validateParentChainPublicClient(client); + const rollupAdminLogicAddress = + 'sequencerInbox' in args ? await getRollupAddress(client, args) : args.rollupAdminLogic; + const { add: addressesToAdd, remove: addressesToRemove } = params; + + const addState: boolean[] = new Array(addressesToAdd.length).fill(true); + const removeState: boolean[] = new Array(addressesToRemove.length).fill(false); + + const request = await client.prepareTransactionRequest({ + chain: client.chain as Chain | undefined, + account, + ...prepareUpgradeExecutorCallParameters({ + to: rollupAdminLogicAddress, + upgradeExecutor, + args: [addressesToAdd.concat(addressesToRemove), addState.concat(removeState)], + abi: rollupABI, + functionName: 'setValidator', + }), + } satisfies PrepareTransactionRequestParameters); + + return { ...request, chainId: validatedPublicClient.chain.id }; +} diff --git a/src/actions/buildSetValidatorWhitelistDisabled.ts b/src/actions/buildSetValidatorWhitelistDisabled.ts new file mode 100644 index 00000000..88a1a52f --- /dev/null +++ b/src/actions/buildSetValidatorWhitelistDisabled.ts @@ -0,0 +1,70 @@ +import { Chain, PrepareTransactionRequestParameters, PublicClient, Transport } from 'viem'; +import { rollupABI } from '../contracts/Rollup'; +import { + WithAccount, + ActionParameters, + WithUpgradeExecutor, + PrepareTransactionRequestReturnTypeWithChainId, +} from '../types/Actions'; +import { Prettify } from '../types/utils'; +import { getRollupAddress } from '../getRollupAddress'; +import { validateParentChainPublicClient } from '../types/ParentChain'; +import { prepareUpgradeExecutorCallParameters } from '../prepareUpgradeExecutorCallParameters'; + +export type BuildSetValidatorWhitelistDisabledParameters = + Prettify>>>; + +export type BuildSetValidatorWhitelistDisabledReturnType = + PrepareTransactionRequestReturnTypeWithChainId; + +export async function buildSetValidatorWhitelistDisabled( + client: PublicClient, + { + account, + upgradeExecutor, + params, + ...args + }: BuildSetValidatorWhitelistDisabledParameters & { params: { enable: boolean } }, +): Promise { + const validatedPublicClient = validateParentChainPublicClient(client); + const rollupAdminLogicAddress = + 'sequencerInbox' in args ? await getRollupAddress(client, args) : args.rollupAdminLogic; + + const request = await client.prepareTransactionRequest({ + chain: client.chain as Chain | undefined, + account, + ...prepareUpgradeExecutorCallParameters({ + to: rollupAdminLogicAddress, + upgradeExecutor, + args: [params.enable], + abi: rollupABI, + functionName: 'setValidatorWhitelistDisabled', + }), + } satisfies PrepareTransactionRequestParameters); + + return { ...request, chainId: validatedPublicClient.chain.id }; +} + +export async function buildEnableValidatorWhitelist( + client: PublicClient, + args: BuildSetValidatorWhitelistDisabledParameters, +): Promise { + return buildSetValidatorWhitelistDisabled(client, { + ...args, + params: { + enable: true, + }, + }); +} + +export async function buildDisableValidatorWhitelist( + client: PublicClient, + args: BuildSetValidatorWhitelistDisabledParameters, +): Promise { + return buildSetValidatorWhitelistDisabled(client, { + ...args, + params: { + enable: false, + }, + }); +} diff --git a/src/actions/buildSetWasmModuleRoot.ts b/src/actions/buildSetWasmModuleRoot.ts new file mode 100644 index 00000000..b2e1cd62 --- /dev/null +++ b/src/actions/buildSetWasmModuleRoot.ts @@ -0,0 +1,51 @@ +import { Chain, Hex, PrepareTransactionRequestParameters, PublicClient, Transport } from 'viem'; +import { rollupABI } from '../contracts/Rollup'; +import { + WithAccount, + ActionParameters, + WithUpgradeExecutor, + PrepareTransactionRequestReturnTypeWithChainId, +} from '../types/Actions'; +import { Prettify } from '../types/utils'; +import { getRollupAddress } from '../getRollupAddress'; +import { validateParentChainPublicClient } from '../types/ParentChain'; +import { prepareUpgradeExecutorCallParameters } from '../prepareUpgradeExecutorCallParameters'; + +export type BuildSetWasmModuleRootParameters = Prettify< + WithUpgradeExecutor< + WithAccount< + ActionParameters< + { + newWasmModuleRoot: Hex; + }, + 'rollupAdminLogic', + Curried + > + > + > +>; + +export type BuildSetWasmModuleRootReturnType = PrepareTransactionRequestReturnTypeWithChainId; + +export async function buildSetWasmModuleRoot( + client: PublicClient, + { account, upgradeExecutor, params, ...args }: BuildSetWasmModuleRootParameters, +): Promise { + const validatedPublicClient = validateParentChainPublicClient(client); + const rollupAdminLogicAddress = + 'sequencerInbox' in args ? await getRollupAddress(client, args) : args.rollupAdminLogic; + + const request = await client.prepareTransactionRequest({ + chain: client.chain as Chain | undefined, + account, + ...prepareUpgradeExecutorCallParameters({ + to: rollupAdminLogicAddress, + upgradeExecutor, + args: [params.newWasmModuleRoot], + abi: rollupABI, + functionName: 'setWasmModuleRoot', + }), + } satisfies PrepareTransactionRequestParameters); + + return { ...request, chainId: validatedPublicClient.chain.id }; +} diff --git a/src/getRollupAddress.ts b/src/getRollupAddress.ts new file mode 100644 index 00000000..59a7428b --- /dev/null +++ b/src/getRollupAddress.ts @@ -0,0 +1,22 @@ +import { Address, Chain, PublicClient, Transport } from 'viem'; +import { sequencerInboxABI } from './contracts/SequencerInbox'; + +const cache: Record = {}; +export async function getRollupAddress( + publicClient: PublicClient, + params: { sequencerInbox: Address }, +): Promise
{ + const addressFromCache = cache[`${publicClient.chain.id}_${params.sequencerInbox}`]; + if (addressFromCache) { + return addressFromCache; + } + + // Otherwise, fetch the rollup address from sequencerInbox contract + const rollupAddress = await publicClient.readContract({ + functionName: 'rollup', + address: params.sequencerInbox, + abi: sequencerInboxABI, + }); + cache[`${publicClient.chain.id}_${params.sequencerInbox}`] = rollupAddress; + return rollupAddress; +} diff --git a/src/prepareUpgradeExecutorCallParameters.ts b/src/prepareUpgradeExecutorCallParameters.ts index dcde21c0..ca368c70 100644 --- a/src/prepareUpgradeExecutorCallParameters.ts +++ b/src/prepareUpgradeExecutorCallParameters.ts @@ -5,13 +5,14 @@ import { } from 'viem'; import { GetFunctionName } from './types/utils'; import { sequencerInboxABI } from './contracts/SequencerInbox'; +import { rollupABI } from './contracts/Rollup'; import { arbOwnerABI } from './contracts/ArbOwner'; import { upgradeExecutorEncodeFunctionData, UpgradeExecutorFunctionName, } from './upgradeExecutorEncodeFunctionData'; -type ABIs = typeof sequencerInboxABI | typeof arbOwnerABI; +type ABIs = typeof sequencerInboxABI | typeof arbOwnerABI | typeof rollupABI; type FunctionName = GetFunctionName; type EncodeFunctionDataParameters< diff --git a/src/types/Actions.ts b/src/types/Actions.ts index 71093865..dd028e92 100644 --- a/src/types/Actions.ts +++ b/src/types/Actions.ts @@ -12,11 +12,11 @@ type isEmptyObject = Args extends Record ? true : false; export type ActionParameters = Prettify< Curried extends false ? 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 + ? { [key in ContractName]: Address } | { sequencerInbox: Address } // Contract wasn't curried. Args is an empty object. Only requires the contract name + : { params: Args } & ({ [key in ContractName]: Address } | { sequencerInbox: 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 + ? { [key in ContractName]: Address } | { sequencerInbox: Address } | void // Contract was curried. Args is empty. Only requires the contract name. Allows no parameters + : { params: Args } & ({ [key in ContractName]?: Address } | { sequencerInbox?: Address }) // Contract was curried. Args is not empty. Requires params, contract name is optional >; export type WithAccount = Args & {