From cd08eb85171c74c845bfd06c8f136d3e3b8743e9 Mon Sep 17 00:00:00 2001 From: alxdca Date: Tue, 14 Jul 2026 10:09:17 +0200 Subject: [PATCH 1/2] refactor: use single generic contract read function --- src/arbAggregatorPrepareTransactionRequest.ts | 5 +- src/arbAggregatorReadContract.ts | 30 --------- src/arbGasInfoReadContract.ts | 30 --------- src/arbOwnerPrepareTransactionRequest.ts | 4 +- src/arbOwnerReadContract.ts | 30 --------- src/contractRead.ts | 63 +++++++++++++++++++ src/contractTransactionRequests.ts | 17 +++-- src/decorators/arbAggregatorActions.ts | 22 +++++-- src/decorators/arbGasInfoPublicActions.ts | 22 +++++-- src/decorators/arbOwnerPublicActions.ts | 22 +++++-- .../rollupAdminLogicPublicActions.ts | 33 +++++++--- src/decorators/sequencerInboxActions.ts | 29 ++++++--- src/prepareUpgradeExecutorCallParameters.ts | 9 ++- ...llupAdminLogicPrepareTransactionRequest.ts | 4 +- src/rollupAdminLogicReadContract.ts | 42 ------------- ...sequencerInboxPrepareTransactionRequest.ts | 4 +- src/sequencerInboxReadContract.ts | 40 ------------ src/types/utils.ts | 4 -- src/upgradeExecutorEncodeFunctionData.ts | 5 +- 19 files changed, 184 insertions(+), 231 deletions(-) delete mode 100644 src/arbAggregatorReadContract.ts delete mode 100644 src/arbGasInfoReadContract.ts delete mode 100644 src/arbOwnerReadContract.ts create mode 100644 src/contractRead.ts delete mode 100644 src/rollupAdminLogicReadContract.ts delete mode 100644 src/sequencerInboxReadContract.ts diff --git a/src/arbAggregatorPrepareTransactionRequest.ts b/src/arbAggregatorPrepareTransactionRequest.ts index c2cc24806..fd82762ce 100644 --- a/src/arbAggregatorPrepareTransactionRequest.ts +++ b/src/arbAggregatorPrepareTransactionRequest.ts @@ -1,7 +1,7 @@ import { PublicClient, Address, Chain, Transport } from 'viem'; +import type { ExtractAbiFunctionNames } from 'abitype'; import { arbAggregatorABI, arbAggregatorAddress } from './contracts/ArbAggregator'; -import { GetFunctionName } from './types/utils'; import { ContractEncodeFunctionDataParameters, prepareContractCallParameters, @@ -9,7 +9,8 @@ import { } from './contractTransactionRequests'; type ArbAggregatorAbi = typeof arbAggregatorABI; -export type ArbAggregatorPrepareTransactionRequestFunctionName = GetFunctionName; +export type ArbAggregatorPrepareTransactionRequestFunctionName = + ExtractAbiFunctionNames; export type ArbAggregatorEncodeFunctionDataParameters< TFunctionName extends ArbAggregatorPrepareTransactionRequestFunctionName, > = ContractEncodeFunctionDataParameters; diff --git a/src/arbAggregatorReadContract.ts b/src/arbAggregatorReadContract.ts deleted file mode 100644 index 27a64555e..000000000 --- a/src/arbAggregatorReadContract.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Chain, GetFunctionArgs, PublicClient, ReadContractReturnType, Transport } from 'viem'; - -import { arbAggregatorABI, arbAggregatorAddress } from './contracts/ArbAggregator'; -import { GetFunctionName } from './types/utils'; - -export type ArbAggregatorAbi = typeof arbAggregatorABI; -export type ArbAggregatorFunctionName = GetFunctionName; - -export type ArbAggregatorReadContractParameters = { - functionName: TFunctionName; -} & GetFunctionArgs; - -export type ArbAggregatorReadContractReturnType = - ReadContractReturnType; - -export function arbAggregatorReadContract< - TChain extends Chain | undefined, - TFunctionName extends ArbAggregatorFunctionName, ->( - client: PublicClient, - params: ArbAggregatorReadContractParameters, -): Promise> { - // @ts-expect-error -- todo: fix viem type issue - return client.readContract({ - address: arbAggregatorAddress, - abi: arbAggregatorABI, - functionName: params.functionName, - args: params.args, - }); -} diff --git a/src/arbGasInfoReadContract.ts b/src/arbGasInfoReadContract.ts deleted file mode 100644 index b7c7c928a..000000000 --- a/src/arbGasInfoReadContract.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Chain, GetFunctionArgs, PublicClient, ReadContractReturnType, Transport } from 'viem'; - -import { arbGasInfoABI, arbGasInfoAddress } from './contracts/ArbGasInfo'; -import { GetFunctionName } from './types/utils'; - -export type ArbGasInfoAbi = typeof arbGasInfoABI; -export type ArbGasInfoFunctionName = GetFunctionName; - -export type ArbGasInfoReadContractParameters = { - functionName: TFunctionName; -} & GetFunctionArgs; - -export type ArbGasInfoReadContractReturnType = - ReadContractReturnType; - -export function arbGasInfoReadContract< - TChain extends Chain | undefined, - TFunctionName extends ArbGasInfoFunctionName, ->( - client: PublicClient, - params: ArbGasInfoReadContractParameters, -): Promise> { - // @ts-expect-error -- todo: fix viem type issue - return client.readContract({ - address: arbGasInfoAddress, - abi: arbGasInfoABI, - functionName: params.functionName, - args: params.args, - }); -} diff --git a/src/arbOwnerPrepareTransactionRequest.ts b/src/arbOwnerPrepareTransactionRequest.ts index e35e1dc06..b5497576e 100644 --- a/src/arbOwnerPrepareTransactionRequest.ts +++ b/src/arbOwnerPrepareTransactionRequest.ts @@ -1,7 +1,7 @@ import { PublicClient, Address, Chain, Transport } from 'viem'; +import type { ExtractAbiFunctionNames } from 'abitype'; import { arbOwnerABI, arbOwnerAddress } from './contracts/ArbOwner'; -import { GetFunctionName } from './types/utils'; import { TransactionRequestGasOverrides, applyPercentIncrease } from './utils/gasOverrides'; import { ContractEncodeFunctionDataParameters, @@ -10,7 +10,7 @@ import { } from './contractTransactionRequests'; type ArbOwnerAbi = typeof arbOwnerABI; -export type ArbOwnerPrepareTransactionRequestFunctionName = GetFunctionName; +export type ArbOwnerPrepareTransactionRequestFunctionName = ExtractAbiFunctionNames; export type ArbOwnerEncodeFunctionDataParameters< TFunctionName extends ArbOwnerPrepareTransactionRequestFunctionName, > = ContractEncodeFunctionDataParameters; diff --git a/src/arbOwnerReadContract.ts b/src/arbOwnerReadContract.ts deleted file mode 100644 index 78e450702..000000000 --- a/src/arbOwnerReadContract.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Chain, GetFunctionArgs, PublicClient, ReadContractReturnType, Transport } from 'viem'; - -import { arbOwnerPublicABI, arbOwnerPublicAddress } from './contracts/ArbOwnerPublic'; -import { GetFunctionName } from './types/utils'; - -export type ArbOwnerPublicAbi = typeof arbOwnerPublicABI; -export type ArbOwnerPublicFunctionName = GetFunctionName; - -export type ArbOwnerReadContractParameters = { - functionName: TFunctionName; -} & GetFunctionArgs; - -export type ArbOwnerReadContractReturnType = - ReadContractReturnType; - -export function arbOwnerReadContract< - TChain extends Chain | undefined, - TFunctionName extends ArbOwnerPublicFunctionName, ->( - client: PublicClient, - params: ArbOwnerReadContractParameters, -): Promise> { - // @ts-expect-error -- todo: fix viem type issue - return client.readContract({ - address: arbOwnerPublicAddress, - abi: arbOwnerPublicABI, - functionName: params.functionName, - args: params.args, - }); -} diff --git a/src/contractRead.ts b/src/contractRead.ts new file mode 100644 index 000000000..bb7d178b0 --- /dev/null +++ b/src/contractRead.ts @@ -0,0 +1,63 @@ +import type { + Abi, + AbiParametersToPrimitiveTypes, + ExtractAbiFunction, + ExtractAbiFunctionNames, +} from 'abitype'; +import type { + Address, + Chain, + PublicClient, + ReadContractParameters, + ReadContractReturnType, + Transport, +} from 'viem'; + +export type ContractReadFunctionName = ExtractAbiFunctionNames< + TAbi, + 'pure' | 'view' +>; + +type ContractReadArgs< + TAbi extends Abi, + TFunctionName extends ContractReadFunctionName, +> = AbiParametersToPrimitiveTypes['inputs']>; + +export type ContractReadParameters< + TAbi extends Abi, + TFunctionName extends ContractReadFunctionName, + TAddressParameters extends object = Record, +> = TAddressParameters & { functionName: TFunctionName } & (ContractReadArgs< + TAbi, + TFunctionName + > extends readonly [] + ? { args?: never } + : { args: ContractReadArgs }); + +export type ContractReadReturnType< + TAbi extends Abi, + TFunctionName extends ContractReadFunctionName, +> = ReadContractReturnType; + +export function createContractRead< + const TAbi extends Abi, + TAddressParameters extends object = Record, +>(abi: TAbi, getAddress: (parameters: TAddressParameters) => Address) { + return function contractRead< + TTransport extends Transport, + TChain extends Chain | undefined, + TFunctionName extends ContractReadFunctionName, + >( + client: PublicClient, + parameters: ContractReadParameters, + ): Promise> { + return client.readContract( + { + abi, + address: getAddress(parameters), + functionName: parameters.functionName, + args: parameters.args, + } as unknown as ReadContractParameters, + ); + }; +} diff --git a/src/contractTransactionRequests.ts b/src/contractTransactionRequests.ts index cc9450b61..b961b8c8d 100644 --- a/src/contractTransactionRequests.ts +++ b/src/contractTransactionRequests.ts @@ -1,5 +1,5 @@ +import type { Abi, ExtractAbiFunctionNames } from 'abitype'; import { - Abi, Address, Chain, encodeFunctionData as viemEncodeFunctionData, @@ -12,18 +12,15 @@ import { upgradeExecutorEncodeFunctionData, UpgradeExecutorFunctionName, } from './upgradeExecutorEncodeFunctionData'; -import { GetFunctionName } from './types/utils'; - -type ContractFunctionName = GetFunctionName; export type ContractEncodeFunctionDataParameters< TAbi extends Abi, - TFunctionName extends ContractFunctionName, + TFunctionName extends ExtractAbiFunctionNames, > = ViemEncodeFunctionDataParameters; type PrepareContractCallParameters< TAbi extends Abi, - TFunctionName extends ContractFunctionName, + TFunctionName extends ExtractAbiFunctionNames, > = Omit, 'abi'> & { abi: TAbi; to: Address; @@ -40,7 +37,7 @@ type PreparedContractCallParameters = { function encodeContractFunctionData< TAbi extends Abi, - TFunctionName extends ContractFunctionName, + TFunctionName extends ExtractAbiFunctionNames, >({ abi, functionName, args }: PrepareContractCallParameters) { return viemEncodeFunctionData({ abi, @@ -51,7 +48,7 @@ function encodeContractFunctionData< export function prepareContractCallParameters< TAbi extends Abi, - TFunctionName extends ContractFunctionName, + TFunctionName extends ExtractAbiFunctionNames, >(params: PrepareContractCallParameters): PreparedContractCallParameters { const { upgradeExecutor, value = BigInt(0) } = params; const data = encodeContractFunctionData(params); @@ -79,7 +76,7 @@ export function prepareContractCallParameters< type PrepareContractTransactionRequestParameters< TAbi extends Abi, - TFunctionName extends ContractFunctionName, + TFunctionName extends ExtractAbiFunctionNames, > = PrepareContractCallParameters & { account: Address; chainId: number; @@ -88,7 +85,7 @@ type PrepareContractTransactionRequestParameters< export async function prepareContractTransactionRequest< TAbi extends Abi, - TFunctionName extends ContractFunctionName, + TFunctionName extends ExtractAbiFunctionNames, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, >( diff --git a/src/decorators/arbAggregatorActions.ts b/src/decorators/arbAggregatorActions.ts index 2d6990472..b4d7b5060 100644 --- a/src/decorators/arbAggregatorActions.ts +++ b/src/decorators/arbAggregatorActions.ts @@ -1,17 +1,29 @@ import { Transport, Chain, PrepareTransactionRequestReturnType, PublicClient } from 'viem'; +import { arbAggregatorABI, arbAggregatorAddress } from '../contracts/ArbAggregator'; import { - arbAggregatorReadContract, - ArbAggregatorFunctionName, - ArbAggregatorReadContractParameters, - ArbAggregatorReadContractReturnType, -} from '../arbAggregatorReadContract'; + createContractRead, + ContractReadFunctionName, + ContractReadParameters, + ContractReadReturnType, +} from '../contractRead'; import { arbAggregatorPrepareTransactionRequest, ArbAggregatorPrepareTransactionRequestFunctionName, ArbAggregatorPrepareTransactionRequestParameters, } from '../arbAggregatorPrepareTransactionRequest'; +type ArbAggregatorFunctionName = ContractReadFunctionName; +type ArbAggregatorReadContractParameters = + ContractReadParameters; +type ArbAggregatorReadContractReturnType = + ContractReadReturnType; + +const arbAggregatorReadContract = createContractRead( + arbAggregatorABI, + () => arbAggregatorAddress, +); + export type ArbAggregatorActions = { arbAggregatorReadContract: ( args: ArbAggregatorReadContractParameters, diff --git a/src/decorators/arbGasInfoPublicActions.ts b/src/decorators/arbGasInfoPublicActions.ts index bc23c6b11..790f11e4d 100644 --- a/src/decorators/arbGasInfoPublicActions.ts +++ b/src/decorators/arbGasInfoPublicActions.ts @@ -1,11 +1,23 @@ import { Transport, Chain, PublicClient } from 'viem'; +import { arbGasInfoABI, arbGasInfoAddress } from '../contracts/ArbGasInfo'; import { - arbGasInfoReadContract, - ArbGasInfoFunctionName, - ArbGasInfoReadContractParameters, - ArbGasInfoReadContractReturnType, -} from '../arbGasInfoReadContract'; + createContractRead, + ContractReadFunctionName, + ContractReadParameters, + ContractReadReturnType, +} from '../contractRead'; + +type ArbGasInfoFunctionName = ContractReadFunctionName; +type ArbGasInfoReadContractParameters = + ContractReadParameters; +type ArbGasInfoReadContractReturnType = + ContractReadReturnType; + +const arbGasInfoReadContract = createContractRead( + arbGasInfoABI, + () => arbGasInfoAddress, +); // eslint-disable-next-line @typescript-eslint/no-unused-vars -- todo: remove generic if not breaking export type ArbGasInfoPublicActions = { diff --git a/src/decorators/arbOwnerPublicActions.ts b/src/decorators/arbOwnerPublicActions.ts index 0776fb17e..7c5f71b34 100644 --- a/src/decorators/arbOwnerPublicActions.ts +++ b/src/decorators/arbOwnerPublicActions.ts @@ -1,17 +1,29 @@ import { Transport, Chain, PrepareTransactionRequestReturnType, PublicClient } from 'viem'; +import { arbOwnerPublicABI, arbOwnerPublicAddress } from '../contracts/ArbOwnerPublic'; import { - arbOwnerReadContract, - ArbOwnerPublicFunctionName, - ArbOwnerReadContractParameters, - ArbOwnerReadContractReturnType, -} from '../arbOwnerReadContract'; + createContractRead, + ContractReadFunctionName, + ContractReadParameters, + ContractReadReturnType, +} from '../contractRead'; import { arbOwnerPrepareTransactionRequest, ArbOwnerPrepareTransactionRequestFunctionName, ArbOwnerPrepareTransactionRequestParameters, } from '../arbOwnerPrepareTransactionRequest'; +type ArbOwnerPublicFunctionName = ContractReadFunctionName; +type ArbOwnerReadContractParameters = + ContractReadParameters; +type ArbOwnerReadContractReturnType = + ContractReadReturnType; + +const arbOwnerReadContract = createContractRead( + arbOwnerPublicABI, + () => arbOwnerPublicAddress, +); + export type ArbOwnerPublicActions = { arbOwnerReadContract: ( args: ArbOwnerReadContractParameters, diff --git a/src/decorators/rollupAdminLogicPublicActions.ts b/src/decorators/rollupAdminLogicPublicActions.ts index eee4a4271..3db51c8a9 100644 --- a/src/decorators/rollupAdminLogicPublicActions.ts +++ b/src/decorators/rollupAdminLogicPublicActions.ts @@ -1,19 +1,36 @@ import { Transport, Chain, PrepareTransactionRequestReturnType, PublicClient, Address } from 'viem'; +import { RollupAdminLogic__factory } from '@arbitrum/sdk/dist/lib/abi/factories/RollupAdminLogic__factory'; import { - rollupAdminLogicReadContract, - RollupAdminLogicFunctionName, - RollupAdminLogicReadContractParameters, - RollupAdminLogicReadContractReturnType, -} from '../rollupAdminLogicReadContract'; + createContractRead, + ContractReadFunctionName, + ContractReadParameters, + ContractReadReturnType, +} from '../contractRead'; import { + RollupAdminLogicAbi, + RollupAdminLogicFunctionName, rollupAdminLogicPrepareTransactionRequest, RollupAdminLogicPrepareTransactionRequestParameters, } from '../rollupAdminLogicPrepareTransactionRequest'; +type RollupAdminLogicAddressParameters = { rollup: Address }; +type RollupAdminLogicReadFunctionName = ContractReadFunctionName; +type RollupAdminLogicReadContractParameters< + TFunctionName extends RollupAdminLogicReadFunctionName, +> = ContractReadParameters; +type RollupAdminLogicReadContractReturnType< + TFunctionName extends RollupAdminLogicReadFunctionName, +> = ContractReadReturnType; + +const rollupAdminLogicReadContract = createContractRead< + RollupAdminLogicAbi, + RollupAdminLogicAddressParameters +>(RollupAdminLogic__factory.abi as unknown as RollupAdminLogicAbi, ({ rollup }) => rollup); + type RollupAdminLogicReadContractArgs< TRollupAdminLogic extends Address | undefined, - TFunctionName extends RollupAdminLogicFunctionName, + TFunctionName extends RollupAdminLogicReadFunctionName, > = TRollupAdminLogic extends Address ? Omit, 'rollup'> & { rollup?: Address; @@ -32,7 +49,7 @@ export type RollupAdminLogicActions< TRollupAdminLogic extends Address | undefined, TChain extends Chain | undefined = Chain | undefined, > = { - rollupAdminLogicReadContract: ( + rollupAdminLogicReadContract: ( args: RollupAdminLogicReadContractArgs, ) => Promise>; @@ -54,7 +71,7 @@ export function rollupAdminLogicPublicActions< client: PublicClient, ) { const rollupAdminLogicExtensions: RollupAdminLogicActions = { - rollupAdminLogicReadContract: ( + rollupAdminLogicReadContract: ( args: RollupAdminLogicReadContractArgs, ) => { return rollupAdminLogicReadContract(client, { diff --git a/src/decorators/sequencerInboxActions.ts b/src/decorators/sequencerInboxActions.ts index b1586d7c4..6668d6649 100644 --- a/src/decorators/sequencerInboxActions.ts +++ b/src/decorators/sequencerInboxActions.ts @@ -1,19 +1,34 @@ import { Transport, Chain, PrepareTransactionRequestReturnType, PublicClient, Address } from 'viem'; +import { sequencerInboxABI } from '../contracts/SequencerInbox'; import { - sequencerInboxReadContract, - SequencerInboxReadContractParameters, - SequencerInboxReadContractReturnType, -} from '../sequencerInboxReadContract'; + createContractRead, + ContractReadFunctionName, + ContractReadParameters, + ContractReadReturnType, +} from '../contractRead'; import { + SequencerInboxAbi, SequencerInboxFunctionName, sequencerInboxPrepareTransactionRequest, SequencerInboxPrepareTransactionRequestParameters, } from '../sequencerInboxPrepareTransactionRequest'; +type SequencerInboxAddressParameters = { sequencerInbox: Address }; +type SequencerInboxReadFunctionName = ContractReadFunctionName; +type SequencerInboxReadContractParameters = + ContractReadParameters; +type SequencerInboxReadContractReturnType = + ContractReadReturnType; + +const sequencerInboxReadContract = createContractRead< + SequencerInboxAbi, + SequencerInboxAddressParameters +>(sequencerInboxABI, ({ sequencerInbox }) => sequencerInbox); + type SequencerInboxReadContractArgs< TSequencerInbox extends Address | undefined, - TFunctionName extends SequencerInboxFunctionName, + TFunctionName extends SequencerInboxReadFunctionName, > = TSequencerInbox extends Address ? Omit, 'sequencerInbox'> & { sequencerInbox?: Address; @@ -32,7 +47,7 @@ export type SequencerInboxActions< TSequencerInbox extends Address | undefined, TChain extends Chain | undefined = Chain | undefined, > = { - sequencerInboxReadContract: ( + sequencerInboxReadContract: ( args: SequencerInboxReadContractArgs, ) => Promise>; @@ -77,7 +92,7 @@ export function sequencerInboxActions< client: PublicClient, ) { const sequencerInboxExtensions: SequencerInboxActions = { - sequencerInboxReadContract: ( + sequencerInboxReadContract: ( args: SequencerInboxReadContractArgs, ) => { return sequencerInboxReadContract(client, { diff --git a/src/prepareUpgradeExecutorCallParameters.ts b/src/prepareUpgradeExecutorCallParameters.ts index b23e52552..5e95a9982 100644 --- a/src/prepareUpgradeExecutorCallParameters.ts +++ b/src/prepareUpgradeExecutorCallParameters.ts @@ -1,5 +1,5 @@ import { Address } from 'viem'; -import { GetFunctionName } from './types/utils'; +import type { ExtractAbiFunctionNames } from 'abitype'; import { sequencerInboxABI } from './contracts/SequencerInbox'; import { arbOwnerABI } from './contracts/ArbOwner'; import { inboxABI } from './contracts/Inbox'; @@ -10,16 +10,15 @@ import { } from './contractTransactionRequests'; type ABIs = typeof sequencerInboxABI | typeof arbOwnerABI | typeof inboxABI; -type FunctionName = GetFunctionName; type EncodeFunctionDataParameters< TAbi extends ABIs, - TFunctionName extends FunctionName, + TFunctionName extends ExtractAbiFunctionNames, > = ContractEncodeFunctionDataParameters; type PrepareUpgradeExecutorCallParameters< TAbi extends ABIs, - TFunctionName extends FunctionName, + TFunctionName extends ExtractAbiFunctionNames, > = Omit, 'abi'> & { abi: TAbi; to: Address; @@ -30,7 +29,7 @@ type PrepareUpgradeExecutorCallParameters< export function prepareUpgradeExecutorCallParameters< TAbi extends ABIs, - TFunctionName extends FunctionName, + TFunctionName extends ExtractAbiFunctionNames, >(params: PrepareUpgradeExecutorCallParameters) { return prepareContractCallParameters(params); } diff --git a/src/rollupAdminLogicPrepareTransactionRequest.ts b/src/rollupAdminLogicPrepareTransactionRequest.ts index 1d0dc647a..a3ba30650 100644 --- a/src/rollupAdminLogicPrepareTransactionRequest.ts +++ b/src/rollupAdminLogicPrepareTransactionRequest.ts @@ -1,8 +1,8 @@ import { PublicClient, Address, Transport, Chain } from 'viem'; +import type { ExtractAbiFunctionNames } from 'abitype'; import { rollupABI } from './contracts/Rollup'; -import { GetFunctionName } from './types/utils'; import { validateParentChain } from './types/ParentChain'; import { ContractEncodeFunctionDataParameters, @@ -11,7 +11,7 @@ import { } from './contractTransactionRequests'; export type RollupAdminLogicAbi = typeof rollupABI; -export type RollupAdminLogicFunctionName = GetFunctionName; +export type RollupAdminLogicFunctionName = ExtractAbiFunctionNames; type RollupAdminLogicEncodeFunctionDataParameters< TFunctionName extends RollupAdminLogicFunctionName, diff --git a/src/rollupAdminLogicReadContract.ts b/src/rollupAdminLogicReadContract.ts deleted file mode 100644 index a3ca90c2e..000000000 --- a/src/rollupAdminLogicReadContract.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { - Address, - Chain, - GetFunctionArgs, - PublicClient, - ReadContractParameters, - ReadContractReturnType, - Transport, -} from 'viem'; -import { RollupAdminLogic__factory } from '@arbitrum/sdk/dist/lib/abi/factories/RollupAdminLogic__factory'; - -import { GetFunctionName } from './types/utils'; -import { rollupABI } from './contracts/Rollup'; - -export type RollupAdminLogicAbi = typeof rollupABI; -export type RollupAdminLogicFunctionName = GetFunctionName; - -export type RollupAdminLogicReadContractParameters< - TFunctionName extends RollupAdminLogicFunctionName, -> = { - functionName: TFunctionName; - rollup: Address; -} & GetFunctionArgs; - -export type RollupAdminLogicReadContractReturnType< - TFunctionName extends RollupAdminLogicFunctionName, -> = ReadContractReturnType; - -export function rollupAdminLogicReadContract< - TChain extends Chain | undefined, - TFunctionName extends RollupAdminLogicFunctionName, ->( - client: PublicClient, - params: RollupAdminLogicReadContractParameters, -): Promise> { - return client.readContract({ - address: params.rollup, - abi: RollupAdminLogic__factory.abi, - functionName: params.functionName, - args: params.args, - } as unknown as ReadContractParameters); -} diff --git a/src/sequencerInboxPrepareTransactionRequest.ts b/src/sequencerInboxPrepareTransactionRequest.ts index 8bcdefa73..df7a91781 100644 --- a/src/sequencerInboxPrepareTransactionRequest.ts +++ b/src/sequencerInboxPrepareTransactionRequest.ts @@ -1,7 +1,7 @@ import { PublicClient, Address, Transport, Chain } from 'viem'; +import type { ExtractAbiFunctionNames } from 'abitype'; import { sequencerInboxABI } from './contracts/SequencerInbox'; -import { GetFunctionName } from './types/utils'; import { validateParentChain } from './types/ParentChain'; import { ContractEncodeFunctionDataParameters, @@ -10,7 +10,7 @@ import { } from './contractTransactionRequests'; export type SequencerInboxAbi = typeof sequencerInboxABI; -export type SequencerInboxFunctionName = GetFunctionName; +export type SequencerInboxFunctionName = ExtractAbiFunctionNames; type SequencerInboxEncodeFunctionDataParameters = ContractEncodeFunctionDataParameters; diff --git a/src/sequencerInboxReadContract.ts b/src/sequencerInboxReadContract.ts deleted file mode 100644 index 7167b01e2..000000000 --- a/src/sequencerInboxReadContract.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - Address, - Chain, - GetFunctionArgs, - PublicClient, - ReadContractReturnType, - Transport, -} from 'viem'; - -import { sequencerInboxABI } from './contracts/SequencerInbox'; -import { - SequencerInboxAbi, - SequencerInboxFunctionName, -} from './sequencerInboxPrepareTransactionRequest'; - -export type SequencerInboxReadContractParameters = - { - functionName: TFunctionName; - // SequencerInbox address is different for each rollup, so user needs to pass it as a parameter - sequencerInbox: Address; - } & GetFunctionArgs; - -export type SequencerInboxReadContractReturnType = - ReadContractReturnType; - -export function sequencerInboxReadContract< - TChain extends Chain | undefined, - TFunctionName extends SequencerInboxFunctionName, ->( - client: PublicClient, - params: SequencerInboxReadContractParameters, -): Promise> { - // @ts-expect-error -- todo: fix viem type issue - return client.readContract({ - address: params.sequencerInbox, - abi: sequencerInboxABI, - functionName: params.functionName, - args: params.args, - }); -} diff --git a/src/types/utils.ts b/src/types/utils.ts index 4241ba1e5..48b82c8d8 100644 --- a/src/types/utils.ts +++ b/src/types/utils.ts @@ -1,12 +1,8 @@ -import { Abi } from 'viem'; - // https://twitter.com/mattpocockuk/status/1622730173446557697 export type Prettify = { [K in keyof T]: T[K]; } & {}; -export type GetFunctionName = Extract['name']; - /** * Creates a new type by making the specified keys required while keeping the remaining keys optional. * diff --git a/src/upgradeExecutorEncodeFunctionData.ts b/src/upgradeExecutorEncodeFunctionData.ts index c7fc86120..052e10ae8 100644 --- a/src/upgradeExecutorEncodeFunctionData.ts +++ b/src/upgradeExecutorEncodeFunctionData.ts @@ -1,7 +1,8 @@ import { encodeFunctionData, EncodeFunctionDataParameters, keccak256, toHex } from 'viem'; +import type { ExtractAbiFunctionNames } from 'abitype'; import { upgradeExecutorABI } from './contracts/UpgradeExecutor'; -import { GetFunctionName, Prettify } from './types/utils'; +import { Prettify } from './types/utils'; // Roles /** @@ -19,7 +20,7 @@ export type UpgradeExecutorRole = // Types for upgradeExecutorEncodeFunctionData export type UpgradeExecutorAbi = typeof upgradeExecutorABI; -export type UpgradeExecutorFunctionName = GetFunctionName; +export type UpgradeExecutorFunctionName = ExtractAbiFunctionNames; export type UpgradeExecutorEncodeFunctionDataParameters< TFunctionName extends UpgradeExecutorFunctionName, > = Prettify, 'abi'>>; From 169800e977b0133e5b19f40738fc00e86dbbf669 Mon Sep 17 00:00:00 2001 From: alxdca Date: Wed, 15 Jul 2026 11:18:22 +0200 Subject: [PATCH 2/2] refactor: remove read wrapper --- examples/set-new-validators/index.ts | 27 +- examples/setup-aep-fee-router/index.ts | 48 ++-- examples/setup-fast-withdrawal/index.ts | 25 +- .../setup-fee-distributor-contract/index.ts | 18 +- ...t.ts => arbAggregator.integration.test.ts} | 31 +- ...wnerPrepareTransactionRequest.unit.test.ts | 40 +-- src/contractRead.ts | 63 ---- src/decorators/arbAggregatorActions.ts | 49 ---- src/decorators/arbGasInfoPublicActions.ts | 36 --- .../arbOwnerPublicActions.integration.test.ts | 128 --------- src/decorators/arbOwnerPublicActions.ts | 48 ---- ...ActionsUpgradeExecutor.integration.test.ts | 138 --------- .../rollupAdminLogicActions.unit.test.ts | 166 ----------- ...dminLogicPublicActions.integration.test.ts | 155 ---------- .../rollupAdminLogicPublicActions.ts | 95 ------- .../sequencerInboxActions.integration.test.ts | 268 ------------------ src/decorators/sequencerInboxActions.ts | 114 -------- .../sequencerInboxActions.unit.test.ts | 110 ------- src/getBatchPosters.integration.test.ts | 10 +- src/getKeysets.integration.test.ts | 19 +- src/getValidators.integration.test.ts | 10 +- src/index.ts | 36 ++- ...ogicPrepareTransactionRequest.unit.test.ts | 95 +++++++ ...nboxPrepareTransactionRequest.unit.test.ts | 95 +++++++ 24 files changed, 333 insertions(+), 1491 deletions(-) rename src/{decorators/arbAggregatorActions.integration.test.ts => arbAggregator.integration.test.ts} (71%) rename src/{decorators => }/arbOwnerPrepareTransactionRequest.unit.test.ts (68%) delete mode 100644 src/contractRead.ts delete mode 100644 src/decorators/arbAggregatorActions.ts delete mode 100644 src/decorators/arbGasInfoPublicActions.ts delete mode 100644 src/decorators/arbOwnerPublicActions.integration.test.ts delete mode 100644 src/decorators/arbOwnerPublicActions.ts delete mode 100644 src/decorators/arbOwnerPublicActionsUpgradeExecutor.integration.test.ts delete mode 100644 src/decorators/rollupAdminLogicActions.unit.test.ts delete mode 100644 src/decorators/rollupAdminLogicPublicActions.integration.test.ts delete mode 100644 src/decorators/rollupAdminLogicPublicActions.ts delete mode 100644 src/decorators/sequencerInboxActions.integration.test.ts delete mode 100644 src/decorators/sequencerInboxActions.ts delete mode 100644 src/decorators/sequencerInboxActions.unit.test.ts create mode 100644 src/rollupAdminLogicPrepareTransactionRequest.unit.test.ts create mode 100644 src/sequencerInboxPrepareTransactionRequest.unit.test.ts diff --git a/examples/set-new-validators/index.ts b/examples/set-new-validators/index.ts index dd4e68b6b..157443002 100644 --- a/examples/set-new-validators/index.ts +++ b/examples/set-new-validators/index.ts @@ -4,7 +4,8 @@ import { arbitrumSepolia } from 'viem/chains'; import { createRollupFetchTransactionHash, createRollupPrepareTransactionReceipt, - rollupAdminLogicPublicActions, + rollupABI, + rollupAdminLogicPrepareTransactionRequest, // Uncomment it when you want to use getValidators() to get validator status // getValidators, } from '@arbitrum/chain-sdk'; @@ -39,11 +40,7 @@ const parentChain = arbitrumSepolia; const parentChainPublicClient = createPublicClient({ chain: parentChain, transport: http(process.env.PARENT_CHAIN_RPC), -}).extend( - rollupAdminLogicPublicActions({ - rollup: process.env.ROLLUP_ADDRESS as Address, - }), -); +}); // load the deployer account const deployer = privateKeyToAccount(sanitizePrivateKey(process.env.ROLLUP_OWNER_PRIVATE_KEY)); @@ -70,7 +67,9 @@ async function main() { const newValidatorStatus = [true]; // check the status of this address in validator list before executing - const beforeStatus = await parentChainPublicClient.rollupAdminLogicReadContract({ + const beforeStatus = await parentChainPublicClient.readContract({ + address: coreContracts.rollup, + abi: rollupABI, functionName: 'isValidator', args: [newValidators[0]], }); @@ -90,8 +89,9 @@ async function main() { */ // prepare set validator transaction request - const setValidatorTransactionRequest = - await parentChainPublicClient.rollupAdminLogicPrepareTransactionRequest({ + const setValidatorTransactionRequest = await rollupAdminLogicPrepareTransactionRequest( + parentChainPublicClient, + { functionName: 'setValidator', args: [ newValidators, // validator address list @@ -99,7 +99,9 @@ async function main() { ], upgradeExecutor: coreContracts.upgradeExecutor, account: deployer.address, - }); + rollup: coreContracts.rollup, + }, + ); // sign and send the transaction const setValidatorTransactionHash = await parentChainPublicClient.sendRawTransaction({ @@ -118,10 +120,11 @@ async function main() { ); // Check the status of this address in validator list before executing - const afterStatus = await parentChainPublicClient.rollupAdminLogicReadContract({ + const afterStatus = await parentChainPublicClient.readContract({ + address: coreContracts.rollup, + abi: rollupABI, functionName: 'isValidator', args: [newValidators[0]], - rollup: coreContracts.rollup, }); console.log( diff --git a/examples/setup-aep-fee-router/index.ts b/examples/setup-aep-fee-router/index.ts index bdaa8ff69..61d0e960f 100644 --- a/examples/setup-aep-fee-router/index.ts +++ b/examples/setup-aep-fee-router/index.ts @@ -12,8 +12,9 @@ import { feeRouterDeployRewardDistributor, createRollupFetchCoreContracts, createTokenBridgeFetchTokenBridgeContracts, - arbOwnerPublicActions, - arbGasInfoPublicActions, + arbOwnerPrepareTransactionRequest, + arbOwnerPublicConfig, + arbGasInfoConfig, parentChainIsArbitrum, ParentChainId, } from '@arbitrum/chain-sdk'; @@ -77,9 +78,10 @@ const orbitChain = defineChain({ }, testnet: true, }); -const orbitChainPublicClient = createPublicClient({ chain: orbitChain, transport: http() }) - .extend(arbOwnerPublicActions) - .extend(arbGasInfoPublicActions); +const orbitChainPublicClient = createPublicClient({ + chain: orbitChain, + transport: http(), +}); const orbitChainWalletClient = createWalletClient({ chain: orbitChain, transport: http(), @@ -118,12 +120,14 @@ async function main() { }); // getting Orbit base fee collector (infraFeeAccount) - const infraFeeAccount = await orbitChainPublicClient.arbOwnerReadContract({ + const infraFeeAccount = await orbitChainPublicClient.readContract({ + ...arbOwnerPublicConfig, functionName: 'getInfraFeeAccount', }); // getting Orbit surplus fee collector (networkFeeAccount) - const networkFeeAccount = await orbitChainPublicClient.arbOwnerReadContract({ + const networkFeeAccount = await orbitChainPublicClient.readContract({ + ...arbOwnerPublicConfig, functionName: 'getNetworkFeeAccount', }); @@ -131,8 +135,7 @@ async function main() { // Note: Arbiscan (Sepolia) doesn't have the updated ABI for ArbGasInfo, so we need to // fetch the reward recipient this way const parentChainRewardRecipient = await orbitChainPublicClient.readContract({ - address: '0x000000000000000000000000000000000000006C', - abi: parseAbi(['function getL1RewardRecipient() view returns (address)']), + ...arbGasInfoConfig, functionName: 'getL1RewardRecipient', }); @@ -236,13 +239,15 @@ async function main() { console.log('Setting the RewardDistributors as the fee new collectors...'); // setting Orbit base fee collector (infraFeeAccount) - const setOrbitBaseFeeCollectorTransactionRequest = - await orbitChainPublicClient.arbOwnerPrepareTransactionRequest({ + const setOrbitBaseFeeCollectorTransactionRequest = await arbOwnerPrepareTransactionRequest( + orbitChainPublicClient, + { functionName: 'setInfraFeeAccount', args: [feeCollectorToRewardDistributor['infraFeeAccount']], upgradeExecutor: tokenBridgeContracts.orbitChainContracts.upgradeExecutor, account: chainOwner.address, - }); + }, + ); await orbitChainPublicClient.sendRawTransaction({ serializedTransaction: await chainOwner.signTransaction( setOrbitBaseFeeCollectorTransactionRequest, @@ -250,13 +255,15 @@ async function main() { }); // setting Orbit surplus fee collector (networkFeeAccount) - const setOrbitSurplusFeeCollectorTransactionRequest = - await orbitChainPublicClient.arbOwnerPrepareTransactionRequest({ + const setOrbitSurplusFeeCollectorTransactionRequest = await arbOwnerPrepareTransactionRequest( + orbitChainPublicClient, + { functionName: 'setNetworkFeeAccount', args: [feeCollectorToRewardDistributor['networkFeeAccount']], upgradeExecutor: tokenBridgeContracts.orbitChainContracts.upgradeExecutor, account: chainOwner.address, - }); + }, + ); await orbitChainPublicClient.sendRawTransaction({ serializedTransaction: await chainOwner.signTransaction( setOrbitSurplusFeeCollectorTransactionRequest, @@ -265,7 +272,7 @@ async function main() { // setting parent chain surplus fee collector (L1RewardRecipient) const setParentChainSurplusFeeCollectorTransactionRequest = - await orbitChainPublicClient.arbOwnerPrepareTransactionRequest({ + await arbOwnerPrepareTransactionRequest(orbitChainPublicClient, { functionName: 'setL1PricingRewardRecipient', args: [feeCollectorToRewardDistributor['parentChainRewardRecipient']], upgradeExecutor: tokenBridgeContracts.orbitChainContracts.upgradeExecutor, @@ -278,7 +285,8 @@ async function main() { }); // checking that the fee collectors were correctly set - const currentInfraFeeAccount = await orbitChainPublicClient.arbOwnerReadContract({ + const currentInfraFeeAccount = await orbitChainPublicClient.readContract({ + ...arbOwnerPublicConfig, functionName: 'getInfraFeeAccount', }); if (currentInfraFeeAccount != feeCollectorToRewardDistributor['infraFeeAccount']) { @@ -290,7 +298,8 @@ async function main() { `Orbit base fee collector correctly set to the RewardDistributor contract ${currentInfraFeeAccount}`, ); - const currentNetworkFeeAccount = await orbitChainPublicClient.arbOwnerReadContract({ + const currentNetworkFeeAccount = await orbitChainPublicClient.readContract({ + ...arbOwnerPublicConfig, functionName: 'getNetworkFeeAccount', }); if (currentNetworkFeeAccount != feeCollectorToRewardDistributor['networkFeeAccount']) { @@ -303,8 +312,7 @@ async function main() { ); const currentParentChainRewardRecipient = await orbitChainPublicClient.readContract({ - address: '0x000000000000000000000000000000000000006C', - abi: parseAbi(['function getL1RewardRecipient() view returns (address)']), + ...arbGasInfoConfig, functionName: 'getL1RewardRecipient', }); if ( diff --git a/examples/setup-fast-withdrawal/index.ts b/examples/setup-fast-withdrawal/index.ts index 13a2772bd..25a22704c 100644 --- a/examples/setup-fast-withdrawal/index.ts +++ b/examples/setup-fast-withdrawal/index.ts @@ -5,7 +5,8 @@ import { createRollupPrepareTransactionReceipt, createSafePrepareTransactionReceipt, createSafePrepareTransactionRequest, - rollupAdminLogicPublicActions, + rollupABI, + rollupAdminLogicPrepareTransactionRequest, setAnyTrustFastConfirmerPrepareTransactionRequest, } from '@arbitrum/chain-sdk'; import { sanitizePrivateKey, getParentChainFromId } from '@arbitrum/chain-sdk/utils'; @@ -59,11 +60,7 @@ const parentChain = getParentChainFromId(Number(process.env.PARENT_CHAIN_ID)); const parentChainPublicClient = createPublicClient({ chain: parentChain, transport: http(), -}).extend( - rollupAdminLogicPublicActions({ - rollup: rollupAddress, - }), -); +}); // load the deployer account const safeOwner = privateKeyToAccount(sanitizePrivateKey(process.env.CHAIN_OWNER_PRIVATE_KEY)); @@ -158,8 +155,9 @@ async function main() { // prepare set validator transaction request const fcValidatorsStatus = Array(fcValidators.length).fill(true); - const setValidatorTransactionRequest = - await parentChainPublicClient.rollupAdminLogicPrepareTransactionRequest({ + const setValidatorTransactionRequest = await rollupAdminLogicPrepareTransactionRequest( + parentChainPublicClient, + { functionName: 'setValidator', args: [ fcValidators, // validator address list @@ -167,7 +165,9 @@ async function main() { ], upgradeExecutor: upgradeExecutorAddress, account: safeOwner.address, - }); + rollup: rollupAddress, + }, + ); // sign and send the transaction const setValidatorTransactionHash = await parentChainPublicClient.sendRawTransaction({ @@ -249,18 +249,21 @@ async function main() { console.log('---'); // get current minimumAssertionPeriod - const currentMinimumAssertionPeriod = await parentChainPublicClient.rollupAdminLogicReadContract({ + const currentMinimumAssertionPeriod = await parentChainPublicClient.readContract({ + address: rollupAddress, + abi: rollupABI, functionName: 'minimumAssertionPeriod', }); if (currentMinimumAssertionPeriod !== minimumAssertionPeriod) { // prepare setMinimumAssertionPeriod transaction request const setMinimumAssertionPeriodTransactionRequest = - await parentChainPublicClient.rollupAdminLogicPrepareTransactionRequest({ + await rollupAdminLogicPrepareTransactionRequest(parentChainPublicClient, { functionName: 'setMinimumAssertionPeriod', args: [minimumAssertionPeriod], upgradeExecutor: upgradeExecutorAddress, account: safeOwner.address, + rollup: rollupAddress, }); // sign and send the transaction diff --git a/examples/setup-fee-distributor-contract/index.ts b/examples/setup-fee-distributor-contract/index.ts index 38278285a..d48770791 100644 --- a/examples/setup-fee-distributor-contract/index.ts +++ b/examples/setup-fee-distributor-contract/index.ts @@ -11,7 +11,8 @@ import { feeRouterDeployRewardDistributor, createRollupFetchCoreContracts, createTokenBridgeFetchTokenBridgeContracts, - arbOwnerPublicActions, + arbOwnerPrepareTransactionRequest, + arbOwnerPublicConfig, } from '@arbitrum/chain-sdk'; import { getParentChainFromId, sanitizePrivateKey } from '@arbitrum/chain-sdk/utils'; import { config } from 'dotenv'; @@ -58,9 +59,7 @@ const orbitChain = defineChain({ }, testnet: true, }); -const orbitChainPublicClient = createPublicClient({ chain: orbitChain, transport: http() }).extend( - arbOwnerPublicActions, -); +const orbitChainPublicClient = createPublicClient({ chain: orbitChain, transport: http() }); const orbitChainWalletClient = createWalletClient({ chain: orbitChain, transport: http(), @@ -149,20 +148,23 @@ async function main() { console.log( 'Setting the RewardDistributor as the collector of the Orbit chain execution fees...', ); - const setFeeCollectorTransactionRequest = - await orbitChainPublicClient.arbOwnerPrepareTransactionRequest({ + const setFeeCollectorTransactionRequest = await arbOwnerPrepareTransactionRequest( + orbitChainPublicClient, + { functionName: 'setInfraFeeAccount', args: [rewardDistributorAddress], upgradeExecutor: tokenBridgeContracts.orbitChainContracts.upgradeExecutor, account: chainOwner.address, - }); + }, + ); await orbitChainPublicClient.sendRawTransaction({ serializedTransaction: await chainOwner.signTransaction(setFeeCollectorTransactionRequest), }); // checking that the fee collector was correctly set - const currentFeeCollector = await orbitChainPublicClient.arbOwnerReadContract({ + const currentFeeCollector = await orbitChainPublicClient.readContract({ + ...arbOwnerPublicConfig, functionName: 'getInfraFeeAccount', }); if (currentFeeCollector != rewardDistributorAddress) { diff --git a/src/decorators/arbAggregatorActions.integration.test.ts b/src/arbAggregator.integration.test.ts similarity index 71% rename from src/decorators/arbAggregatorActions.integration.test.ts rename to src/arbAggregator.integration.test.ts index 5e39563fe..78d2a5460 100644 --- a/src/decorators/arbAggregatorActions.integration.test.ts +++ b/src/arbAggregator.integration.test.ts @@ -2,9 +2,10 @@ import { it, expect, describe } from 'vitest'; import { createPublicClient, http } from 'viem'; import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; -import { nitroTestnodeL2 } from '../chains'; -import { arbAggregatorActions } from './arbAggregatorActions'; -import { getNitroTestnodePrivateKeyAccounts } from '../testHelpers'; +import { nitroTestnodeL2 } from './chains'; +import { arbAggregatorConfig } from './contracts/ArbAggregator'; +import { arbAggregatorPrepareTransactionRequest } from './arbAggregatorPrepareTransactionRequest'; +import { getNitroTestnodePrivateKeyAccounts } from './testHelpers'; const testnodeAccounts = getNitroTestnodePrivateKeyAccounts(); const l2RollupOwner = testnodeAccounts.l2RollupOwner; @@ -13,18 +14,20 @@ const randomAccount = privateKeyToAccount(generatePrivateKey()); const nitroTestnodeL2Client = createPublicClient({ chain: nitroTestnodeL2, transport: http(), -}).extend(arbAggregatorActions); +}); -describe('ArgAggregator decorator tests', () => { +describe('ArbAggregator actions', () => { it('successfully fetches the batch posters and the fee collectors', async () => { - const batchPosters = await nitroTestnodeL2Client.arbAggregatorReadContract({ + const batchPosters = await nitroTestnodeL2Client.readContract({ + ...arbAggregatorConfig, functionName: 'getBatchPosters', }); expect(batchPosters).toHaveLength(2); expect(batchPosters[0]).toEqual('0xA4b000000000000000000073657175656e636572'); - const batchPosterFeeCollector = await nitroTestnodeL2Client.arbAggregatorReadContract({ + const batchPosterFeeCollector = await nitroTestnodeL2Client.readContract({ + ...arbAggregatorConfig, functionName: 'getFeeCollector', args: [batchPosters[0]], }); @@ -34,25 +37,29 @@ describe('ArgAggregator decorator tests', () => { it('succesfully updates the fee collector of a batch poster', async () => { // Get the batch posters - const batchPosters = await nitroTestnodeL2Client.arbAggregatorReadContract({ + const batchPosters = await nitroTestnodeL2Client.readContract({ + ...arbAggregatorConfig, functionName: 'getBatchPosters', }); // Set the fee collector of the batch poster to the random address - const setFeeCollectorTransactionRequest = - await nitroTestnodeL2Client.arbAggregatorPrepareTransactionRequest({ + const setFeeCollectorTransactionRequest = await arbAggregatorPrepareTransactionRequest( + nitroTestnodeL2Client, + { functionName: 'setFeeCollector', args: [batchPosters[1], randomAccount.address], upgradeExecutor: false, account: l2RollupOwner.address, - }); + }, + ); const txHash = await nitroTestnodeL2Client.sendRawTransaction({ serializedTransaction: await l2RollupOwner.signTransaction(setFeeCollectorTransactionRequest), }); await nitroTestnodeL2Client.waitForTransactionReceipt({ hash: txHash }); // Check the fee collector has changed - const batchPosterFeeCollector = await nitroTestnodeL2Client.arbAggregatorReadContract({ + const batchPosterFeeCollector = await nitroTestnodeL2Client.readContract({ + ...arbAggregatorConfig, functionName: 'getFeeCollector', args: [batchPosters[1]], }); diff --git a/src/decorators/arbOwnerPrepareTransactionRequest.unit.test.ts b/src/arbOwnerPrepareTransactionRequest.unit.test.ts similarity index 68% rename from src/decorators/arbOwnerPrepareTransactionRequest.unit.test.ts rename to src/arbOwnerPrepareTransactionRequest.unit.test.ts index 57442960f..ecbd5e9a4 100644 --- a/src/decorators/arbOwnerPrepareTransactionRequest.unit.test.ts +++ b/src/arbOwnerPrepareTransactionRequest.unit.test.ts @@ -7,19 +7,20 @@ import { createPublicClient, http, } from 'viem'; -import { nitroTestnodeL2 } from '../chains'; -import { arbOwnerPublicActions } from './arbOwnerPublicActions'; +import { nitroTestnodeL2 } from './chains'; +import { arbOwnerPublicConfig } from './contracts/ArbOwnerPublic'; +import { arbOwnerPrepareTransactionRequest } from './arbOwnerPrepareTransactionRequest'; import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; const client = createPublicClient({ chain: nitroTestnodeL2, transport: http(), -}).extend(arbOwnerPublicActions); +}); const randomAccount = privateKeyToAccount(generatePrivateKey()); it('Infer parameters based on function name', async () => { await expect( - client.arbOwnerPrepareTransactionRequest({ + arbOwnerPrepareTransactionRequest(client, { functionName: 'addChainOwner', // @ts-expect-error Args are missing args: [], @@ -29,7 +30,7 @@ it('Infer parameters based on function name', async () => { ).rejects.toThrow(AbiEncodingLengthMismatchError); await expect( - client.arbOwnerPrepareTransactionRequest({ + arbOwnerPrepareTransactionRequest(client, { functionName: 'addChainOwner', // @ts-expect-error Args are of the wrong type args: [10n], @@ -39,27 +40,26 @@ it('Infer parameters based on function name', async () => { ).rejects.toThrow(InvalidAddressError); await expect( - client - // @ts-expect-error Args are required for `addChainOwner` - .arbOwnerPrepareTransactionRequest({ - functionName: 'addChainOwner', - upgradeExecutor: false, - account: randomAccount.address, - }), - ).rejects.toThrow(AbiEncodingLengthMismatchError); - - expectTypeOf>().toBeCallableWith( - { + arbOwnerPrepareTransactionRequest(client, { functionName: 'addChainOwner', - args: [randomAccount.address], upgradeExecutor: false, account: randomAccount.address, - }, - ); + // @ts-expect-error Args are required for `addChainOwner` + args: undefined, + }), + ).rejects.toThrow(AbiEncodingLengthMismatchError); + + expectTypeOf(arbOwnerPrepareTransactionRequest).toBeCallableWith(client, { + functionName: 'addChainOwner', + args: [randomAccount.address], + upgradeExecutor: false, + account: randomAccount.address, + }); // Function doesn't exist await expect( - client.arbOwnerReadContract({ + client.readContract({ + ...arbOwnerPublicConfig, // @ts-expect-error Function not available functionName: 'notExisting', }), diff --git a/src/contractRead.ts b/src/contractRead.ts deleted file mode 100644 index bb7d178b0..000000000 --- a/src/contractRead.ts +++ /dev/null @@ -1,63 +0,0 @@ -import type { - Abi, - AbiParametersToPrimitiveTypes, - ExtractAbiFunction, - ExtractAbiFunctionNames, -} from 'abitype'; -import type { - Address, - Chain, - PublicClient, - ReadContractParameters, - ReadContractReturnType, - Transport, -} from 'viem'; - -export type ContractReadFunctionName = ExtractAbiFunctionNames< - TAbi, - 'pure' | 'view' ->; - -type ContractReadArgs< - TAbi extends Abi, - TFunctionName extends ContractReadFunctionName, -> = AbiParametersToPrimitiveTypes['inputs']>; - -export type ContractReadParameters< - TAbi extends Abi, - TFunctionName extends ContractReadFunctionName, - TAddressParameters extends object = Record, -> = TAddressParameters & { functionName: TFunctionName } & (ContractReadArgs< - TAbi, - TFunctionName - > extends readonly [] - ? { args?: never } - : { args: ContractReadArgs }); - -export type ContractReadReturnType< - TAbi extends Abi, - TFunctionName extends ContractReadFunctionName, -> = ReadContractReturnType; - -export function createContractRead< - const TAbi extends Abi, - TAddressParameters extends object = Record, ->(abi: TAbi, getAddress: (parameters: TAddressParameters) => Address) { - return function contractRead< - TTransport extends Transport, - TChain extends Chain | undefined, - TFunctionName extends ContractReadFunctionName, - >( - client: PublicClient, - parameters: ContractReadParameters, - ): Promise> { - return client.readContract( - { - abi, - address: getAddress(parameters), - functionName: parameters.functionName, - args: parameters.args, - } as unknown as ReadContractParameters, - ); - }; -} diff --git a/src/decorators/arbAggregatorActions.ts b/src/decorators/arbAggregatorActions.ts deleted file mode 100644 index b4d7b5060..000000000 --- a/src/decorators/arbAggregatorActions.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Transport, Chain, PrepareTransactionRequestReturnType, PublicClient } from 'viem'; - -import { arbAggregatorABI, arbAggregatorAddress } from '../contracts/ArbAggregator'; -import { - createContractRead, - ContractReadFunctionName, - ContractReadParameters, - ContractReadReturnType, -} from '../contractRead'; -import { - arbAggregatorPrepareTransactionRequest, - ArbAggregatorPrepareTransactionRequestFunctionName, - ArbAggregatorPrepareTransactionRequestParameters, -} from '../arbAggregatorPrepareTransactionRequest'; - -type ArbAggregatorFunctionName = ContractReadFunctionName; -type ArbAggregatorReadContractParameters = - ContractReadParameters; -type ArbAggregatorReadContractReturnType = - ContractReadReturnType; - -const arbAggregatorReadContract = createContractRead( - arbAggregatorABI, - () => arbAggregatorAddress, -); - -export type ArbAggregatorActions = { - arbAggregatorReadContract: ( - args: ArbAggregatorReadContractParameters, - ) => Promise>; - - arbAggregatorPrepareTransactionRequest: < - TFunctionName extends ArbAggregatorPrepareTransactionRequestFunctionName, - >( - args: ArbAggregatorPrepareTransactionRequestParameters, - ) => Promise & { chainId: number }>; -}; - -export function arbAggregatorActions< - TTransport extends Transport = Transport, - TChain extends Chain | undefined = Chain | undefined, ->(client: PublicClient): ArbAggregatorActions { - return { - arbAggregatorReadContract: (args) => arbAggregatorReadContract(client, args), - - arbAggregatorPrepareTransactionRequest: (args) => - arbAggregatorPrepareTransactionRequest(client, args), - }; -} diff --git a/src/decorators/arbGasInfoPublicActions.ts b/src/decorators/arbGasInfoPublicActions.ts deleted file mode 100644 index 790f11e4d..000000000 --- a/src/decorators/arbGasInfoPublicActions.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Transport, Chain, PublicClient } from 'viem'; - -import { arbGasInfoABI, arbGasInfoAddress } from '../contracts/ArbGasInfo'; -import { - createContractRead, - ContractReadFunctionName, - ContractReadParameters, - ContractReadReturnType, -} from '../contractRead'; - -type ArbGasInfoFunctionName = ContractReadFunctionName; -type ArbGasInfoReadContractParameters = - ContractReadParameters; -type ArbGasInfoReadContractReturnType = - ContractReadReturnType; - -const arbGasInfoReadContract = createContractRead( - arbGasInfoABI, - () => arbGasInfoAddress, -); - -// eslint-disable-next-line @typescript-eslint/no-unused-vars -- todo: remove generic if not breaking -export type ArbGasInfoPublicActions = { - arbGasInfoReadContract: ( - args: ArbGasInfoReadContractParameters, - ) => Promise>; -}; - -export function arbGasInfoPublicActions< - TTransport extends Transport = Transport, - TChain extends Chain | undefined = Chain | undefined, ->(client: PublicClient): ArbGasInfoPublicActions { - return { - arbGasInfoReadContract: (args) => arbGasInfoReadContract(client, args), - }; -} diff --git a/src/decorators/arbOwnerPublicActions.integration.test.ts b/src/decorators/arbOwnerPublicActions.integration.test.ts deleted file mode 100644 index 6f51ace83..000000000 --- a/src/decorators/arbOwnerPublicActions.integration.test.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { it, expect } from 'vitest'; -import { createPublicClient, http } from 'viem'; -import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; - -import { nitroTestnodeL2 } from '../chains'; -import { arbOwnerPublicActions } from './arbOwnerPublicActions'; -import { getNitroTestnodePrivateKeyAccounts } from '../testHelpers'; - -// l2 owner private key -const devPrivateKey = getNitroTestnodePrivateKeyAccounts().l2RollupOwner.privateKey; - -const owner = privateKeyToAccount(devPrivateKey); -const randomAccount = privateKeyToAccount(generatePrivateKey()); - -const client = createPublicClient({ - chain: nitroTestnodeL2, - transport: http(), -}).extend(arbOwnerPublicActions); - -it('successfully fetches network fee receiver', async () => { - const result = await client.arbOwnerReadContract({ - functionName: 'getNetworkFeeAccount', - }); - - expect(result).toEqual(owner.address); -}); - -it('succesfully fetches chain owners', async () => { - const result = await client.arbOwnerReadContract({ - functionName: 'getAllChainOwners', - }); - - expect(result).toContain(owner.address); -}); - -it('succesfully adds chain owner', async () => { - const isOwnerInitially = await client.arbOwnerReadContract({ - functionName: 'isChainOwner', - args: [randomAccount.address], - }); - - // assert account is not already an owner - expect(isOwnerInitially).toEqual(false); - - const transactionRequest = await client.arbOwnerPrepareTransactionRequest({ - functionName: 'addChainOwner', - args: [randomAccount.address], - upgradeExecutor: false, - account: owner.address, - }); - - // submit tx to add chain owner - const txHash = await client.sendRawTransaction({ - serializedTransaction: await owner.signTransaction(transactionRequest), - }); - - await client.waitForTransactionReceipt({ hash: txHash }); - - const isOwner = await client.arbOwnerReadContract({ - functionName: 'isChainOwner', - args: [randomAccount.address], - }); - - // assert account is now owner - expect(isOwner).toEqual(true); -}); - -it('succesfully removes chain owner', async () => { - const isOwnerInitially = await client.arbOwnerReadContract({ - functionName: 'isChainOwner', - args: [randomAccount.address], - }); - - // assert account is an owner - expect(isOwnerInitially).toEqual(true); - - const transactionRequest = await client.arbOwnerPrepareTransactionRequest({ - functionName: 'removeChainOwner', - args: [randomAccount.address], - upgradeExecutor: false, - account: owner.address, - }); - - // submit tx to remove chain owner - const txHash = await client.sendRawTransaction({ - serializedTransaction: await owner.signTransaction(transactionRequest), - }); - - await client.waitForTransactionReceipt({ hash: txHash }); - - const isOwner = await client.arbOwnerReadContract({ - functionName: 'isChainOwner', - args: [randomAccount.address], - }); - - // assert account is no longer chain owner - expect(isOwner).toEqual(false); -}); - -it('succesfully updates infra fee receiver', async () => { - const initialInfraFeeReceiver = await client.arbOwnerReadContract({ - functionName: 'getInfraFeeAccount', - }); - - // assert account is not already infra fee receiver - expect(initialInfraFeeReceiver).not.toEqual(randomAccount.address); - - const transactionRequest = await client.arbOwnerPrepareTransactionRequest({ - functionName: 'setInfraFeeAccount', - args: [randomAccount.address], - upgradeExecutor: false, - account: owner.address, - }); - - // submit tx to update infra fee receiver - const txHash = await client.sendRawTransaction({ - serializedTransaction: await owner.signTransaction(transactionRequest), - }); - - await client.waitForTransactionReceipt({ hash: txHash }); - - const infraFeeReceiver = await client.arbOwnerReadContract({ - functionName: 'getInfraFeeAccount', - }); - - // assert account is now infra fee receiver - expect(infraFeeReceiver).toEqual(randomAccount.address); -}); diff --git a/src/decorators/arbOwnerPublicActions.ts b/src/decorators/arbOwnerPublicActions.ts deleted file mode 100644 index 7c5f71b34..000000000 --- a/src/decorators/arbOwnerPublicActions.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Transport, Chain, PrepareTransactionRequestReturnType, PublicClient } from 'viem'; - -import { arbOwnerPublicABI, arbOwnerPublicAddress } from '../contracts/ArbOwnerPublic'; -import { - createContractRead, - ContractReadFunctionName, - ContractReadParameters, - ContractReadReturnType, -} from '../contractRead'; -import { - arbOwnerPrepareTransactionRequest, - ArbOwnerPrepareTransactionRequestFunctionName, - ArbOwnerPrepareTransactionRequestParameters, -} from '../arbOwnerPrepareTransactionRequest'; - -type ArbOwnerPublicFunctionName = ContractReadFunctionName; -type ArbOwnerReadContractParameters = - ContractReadParameters; -type ArbOwnerReadContractReturnType = - ContractReadReturnType; - -const arbOwnerReadContract = createContractRead( - arbOwnerPublicABI, - () => arbOwnerPublicAddress, -); - -export type ArbOwnerPublicActions = { - arbOwnerReadContract: ( - args: ArbOwnerReadContractParameters, - ) => Promise>; - - arbOwnerPrepareTransactionRequest: < - TFunctionName extends ArbOwnerPrepareTransactionRequestFunctionName, - >( - args: ArbOwnerPrepareTransactionRequestParameters, - ) => Promise & { chainId: number }>; -}; - -export function arbOwnerPublicActions< - TTransport extends Transport = Transport, - TChain extends Chain | undefined = Chain | undefined, ->(client: PublicClient): ArbOwnerPublicActions { - return { - arbOwnerReadContract: (args) => arbOwnerReadContract(client, args), - - arbOwnerPrepareTransactionRequest: (args) => arbOwnerPrepareTransactionRequest(client, args), - }; -} diff --git a/src/decorators/arbOwnerPublicActionsUpgradeExecutor.integration.test.ts b/src/decorators/arbOwnerPublicActionsUpgradeExecutor.integration.test.ts deleted file mode 100644 index 7de4d8d96..000000000 --- a/src/decorators/arbOwnerPublicActionsUpgradeExecutor.integration.test.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { it, expect } from 'vitest'; -import { Address, createPublicClient, http } from 'viem'; -import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; -import { nitroTestnodeL3 } from '../chains'; -import { arbOwnerPublicActions } from './arbOwnerPublicActions'; -import { arbGasInfoPublicActions } from './arbGasInfoPublicActions'; -import { getNitroTestnodePrivateKeyAccounts } from '../testHelpers'; - -// L3 Owner Private Key -const devPrivateKey = getNitroTestnodePrivateKeyAccounts().l3RollupOwner.privateKey; - -// L3 Upgrade Executor Address -const upgradeExecutorAddress: Address = '0x24198F8A339cd3C47AEa3A764A20d2dDaB4D1b5b'; - -const owner = privateKeyToAccount(devPrivateKey); -const randomAccount = privateKeyToAccount(generatePrivateKey()); - -// Client for arb owner public actions -const client = createPublicClient({ - chain: nitroTestnodeL3, - transport: http(), -}) - .extend(arbOwnerPublicActions) - .extend(arbGasInfoPublicActions); - -it('succesfully adds chain owner using upgrade executor', async () => { - // Checks if random address is not a chain owner yet - const isOwnerInitially = await client.arbOwnerReadContract({ - functionName: 'isChainOwner', - args: [randomAccount.address], - }); - - expect(isOwnerInitially).toEqual(false); - - // Adding random address as chain owner using upgrade executor - const transactionRequest = await client.arbOwnerPrepareTransactionRequest({ - functionName: 'addChainOwner', - args: [randomAccount.address], - upgradeExecutor: upgradeExecutorAddress, - account: owner.address, - }); - - // submit tx to add chain owner - const txHash = await client.sendRawTransaction({ - serializedTransaction: await owner.signTransaction(transactionRequest), - }); - await client.waitForTransactionReceipt({ hash: txHash }); - - const isOwner = await client.arbOwnerReadContract({ - functionName: 'isChainOwner', - args: [randomAccount.address], - }); - // assert account is now owner - expect(isOwner).toEqual(true); -}); - -it('succesfully removes chain owner', async () => { - const isOwnerInitially = await client.arbOwnerReadContract({ - functionName: 'isChainOwner', - args: [randomAccount.address], - }); - - // assert account is an owner - expect(isOwnerInitially).toEqual(true); - - const transactionRequest = await client.arbOwnerPrepareTransactionRequest({ - functionName: 'removeChainOwner', - args: [randomAccount.address], - upgradeExecutor: upgradeExecutorAddress, - account: owner.address, - }); - - // submit tx to remove chain owner - const txHash = await client.sendRawTransaction({ - serializedTransaction: await owner.signTransaction(transactionRequest), - }); - await client.waitForTransactionReceipt({ hash: txHash }); - - const isOwner = await client.arbOwnerReadContract({ - functionName: 'isChainOwner', - args: [randomAccount.address], - }); - - // assert account is no longer chain owner - expect(isOwner).toEqual(false); -}); - -it('successfully updates infra fee receiver', async () => { - const initialInfraFeeReceiver = await client.arbOwnerReadContract({ - functionName: 'getInfraFeeAccount', - }); - - // assert account is not already infra fee receiver - expect(initialInfraFeeReceiver).not.toEqual(randomAccount.address); - - const transactionRequest = await client.arbOwnerPrepareTransactionRequest({ - functionName: 'setInfraFeeAccount', - args: [randomAccount.address], - upgradeExecutor: upgradeExecutorAddress, - account: owner.address, - }); - - // submit tx to update infra fee receiver - const txHash = await client.sendRawTransaction({ - serializedTransaction: await owner.signTransaction(transactionRequest), - }); - await client.waitForTransactionReceipt({ hash: txHash }); - - const infraFeeReceiver = await client.arbOwnerReadContract({ - functionName: 'getInfraFeeAccount', - }); - - // assert account is now infra fee receiver - expect(infraFeeReceiver).toEqual(randomAccount.address); -}); - -it('successfully updates L2 Base Fee Estimate Inertia on Orbit chain', async () => { - const l2BaseFeeEstimateInertia = BigInt(9); - const transactionRequest = await client.arbOwnerPrepareTransactionRequest({ - functionName: 'setL1BaseFeeEstimateInertia', - args: [l2BaseFeeEstimateInertia], - upgradeExecutor: upgradeExecutorAddress, - account: owner.address, - }); - - // submit tx to update infra fee receiver - const txHash = await client.sendRawTransaction({ - serializedTransaction: await owner.signTransaction(transactionRequest), - }); - await client.waitForTransactionReceipt({ hash: txHash }); - - const newL2BaseFeeEstimateInertia = await client.arbGasInfoReadContract({ - functionName: 'getL1BaseFeeEstimateInertia', - }); - - // assert account is now infra fee receiver - expect(newL2BaseFeeEstimateInertia).toEqual(l2BaseFeeEstimateInertia); -}); diff --git a/src/decorators/rollupAdminLogicActions.unit.test.ts b/src/decorators/rollupAdminLogicActions.unit.test.ts deleted file mode 100644 index 12d7e0b94..000000000 --- a/src/decorators/rollupAdminLogicActions.unit.test.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { it, expect, expectTypeOf, describe, vi } from 'vitest'; - -import { - AbiEncodingLengthMismatchError, - AbiFunctionNotFoundError, - InvalidAddressError, - createPublicClient, - http, - createClient, - ClientConfig, -} from 'viem'; -import { rollupAdminLogicPublicActions } from './rollupAdminLogicPublicActions'; -import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; -import { RollupAdminLogic__factory } from '@arbitrum/sdk/dist/lib/abi/factories/RollupAdminLogic__factory'; -import { mainnet } from 'viem/chains'; - -const rollupAdminLogicAddress = '0x5eF0D09d1E6204141B4d37530808eD19f60FBa35'; - -const client = createPublicClient({ - chain: mainnet, - transport: http(), -}).extend(rollupAdminLogicPublicActions({ rollup: rollupAdminLogicAddress })); - -const randomAccount = privateKeyToAccount(generatePrivateKey()); - -// Mock readContract (called internally with client.rollupAdminLogicReadContract) -vi.mock('viem', async () => { - const viem: Record = await vi.importActual('viem'); - - return { - ...viem, - createPublicClient: (args: ClientConfig) => { - const client = createClient(args); - Object.assign(client, { - readContract: vi.fn(), - }); - return client; - }, - }; -}); - -describe('RollupAdminLogic parameter:', () => { - it('require rollupAdminLogic parameter if not passed initially to the actions during initialization', () => { - const clientWithoutRollupAdminLogicAddress = createPublicClient({ - chain: mainnet, - transport: http(), - }).extend(rollupAdminLogicPublicActions({})); - - // @ts-expect-error rollupAdminLogic is required - clientWithoutRollupAdminLogicAddress.rollupAdminLogicReadContract({ - functionName: 'amountStaked', - args: [randomAccount.address], - }); - - expectTypeOf< - typeof clientWithoutRollupAdminLogicAddress.rollupAdminLogicReadContract<'amountStaked'> - >().toBeCallableWith({ - functionName: 'amountStaked', - args: [randomAccount.address], - rollup: rollupAdminLogicAddress, - }); - }); - - it("Doesn't require rollupAdminLogic parameter if passed initially to the actions during initialization", async () => { - const clientWithRollupAdminLogicAddress = createPublicClient({ - chain: mainnet, - transport: http(), - }).extend(rollupAdminLogicPublicActions({ rollup: rollupAdminLogicAddress })); - - expectTypeOf< - typeof clientWithRollupAdminLogicAddress.rollupAdminLogicReadContract<'amountStaked'> - >().toBeCallableWith({ - functionName: 'amountStaked', - args: [randomAccount.address], - }); - - await clientWithRollupAdminLogicAddress.rollupAdminLogicReadContract({ - functionName: 'amountStaked', - args: [randomAccount.address], - }); - - expect(clientWithRollupAdminLogicAddress.readContract).toHaveBeenCalledWith({ - address: rollupAdminLogicAddress, - abi: RollupAdminLogic__factory.abi, - functionName: 'amountStaked', - args: [randomAccount.address], - }); - }); - - it('Allow rollupAdminLogic override parameter if passed initially to the actions during initialization', async () => { - const clientWithRollupAdminLogicAddress = createPublicClient({ - chain: mainnet, - transport: http(), - }).extend(rollupAdminLogicPublicActions({ rollup: rollupAdminLogicAddress })); - - expectTypeOf< - typeof clientWithRollupAdminLogicAddress.rollupAdminLogicReadContract<'amountStaked'> - >().toBeCallableWith({ - functionName: 'amountStaked', - args: [randomAccount.address], - rollup: rollupAdminLogicAddress, - }); - - await clientWithRollupAdminLogicAddress.rollupAdminLogicReadContract({ - functionName: 'amountStaked', - args: [randomAccount.address], - rollup: randomAccount.address, - }); - - expect(clientWithRollupAdminLogicAddress.readContract).toHaveBeenCalledWith({ - address: randomAccount.address, - abi: RollupAdminLogic__factory.abi, - functionName: 'amountStaked', - args: [randomAccount.address], - }); - }); -}); - -it('Infer parameters based on function name', async () => { - await expect( - client.rollupAdminLogicPrepareTransactionRequest({ - functionName: 'setLoserStakeEscrow', - // @ts-expect-error Args are missing - args: [], - upgradeExecutor: false, - account: randomAccount.address, - }), - ).rejects.toThrowError(AbiEncodingLengthMismatchError); - - await expect( - client.rollupAdminLogicPrepareTransactionRequest({ - functionName: 'setLoserStakeEscrow', - // @ts-expect-error Args are of the wrong type - args: [true], - upgradeExecutor: false, - account: randomAccount.address, - }), - ).rejects.toThrowError(InvalidAddressError); - - await expect( - client - // @ts-expect-error Args are required for `setLoserStakeEscrow` - .rollupAdminLogicPrepareTransactionRequest({ - functionName: 'setLoserStakeEscrow', - upgradeExecutor: false, - account: randomAccount.address, - }), - ).rejects.toThrow(AbiEncodingLengthMismatchError); - - expectTypeOf< - typeof client.rollupAdminLogicPrepareTransactionRequest<'setLoserStakeEscrow'> - >().toBeCallableWith({ - functionName: 'setLoserStakeEscrow', - args: [randomAccount.address], - upgradeExecutor: false, - account: randomAccount.address, - }); - - // Function doesn't exist - await expect( - client.rollupAdminLogicPrepareTransactionRequest({ - // @ts-expect-error Function not available - functionName: 'notExisting', - }), - ).rejects.toThrowError(AbiFunctionNotFoundError); -}); diff --git a/src/decorators/rollupAdminLogicPublicActions.integration.test.ts b/src/decorators/rollupAdminLogicPublicActions.integration.test.ts deleted file mode 100644 index bb3ad8227..000000000 --- a/src/decorators/rollupAdminLogicPublicActions.integration.test.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { it, expect } from 'vitest'; -import { createPublicClient, http } from 'viem'; -import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; - -import { nitroTestnodeL2 } from '../chains'; -import { rollupAdminLogicPublicActions } from './rollupAdminLogicPublicActions'; -import { - getInformationFromTestnode, - getNitroTestnodePrivateKeyAccounts, - testHelper_getRollupCreatorVersionFromEnv, -} from '../testHelpers'; -import { getValidators } from '../getValidators'; - -const { l3RollupOwner } = getNitroTestnodePrivateKeyAccounts(); -const { l3Rollup, l3UpgradeExecutor } = getInformationFromTestnode(); - -const rollupCreatorVersion = testHelper_getRollupCreatorVersionFromEnv(); -// https://github.com/OffchainLabs/nitro-testnode/blob/release/test-node.bash#L634 -// https://github.com/OffchainLabs/nitro-contracts/blob/v3.2.0/scripts/rollupCreation.ts#L254-L261 -// https://github.com/OffchainLabs/nitro-contracts/blob/v2.1.3/scripts/rollupCreation.ts#L237-L243 -const expectedInitialValidators = rollupCreatorVersion === 'v3.2' ? 11 : 10; - -const client = createPublicClient({ - chain: nitroTestnodeL2, - transport: http(), -}).extend( - rollupAdminLogicPublicActions({ - rollup: l3Rollup, - }), -); - -it('successfully set validators', async () => { - const randomAccounts = [ - privateKeyToAccount(generatePrivateKey()).address, - privateKeyToAccount(generatePrivateKey()).address, - ]; - - const { validators: initialValidators, isAccurate: isAccurateInitially } = await getValidators( - client, - { - rollup: l3Rollup, - }, - ); - - expect(initialValidators).toHaveLength(expectedInitialValidators); - expect(isAccurateInitially).toBeTruthy(); - - const tx = await client.rollupAdminLogicPrepareTransactionRequest({ - functionName: 'setValidator', - args: [randomAccounts, [true, false]], - account: l3RollupOwner.address, - upgradeExecutor: l3UpgradeExecutor, - rollup: l3Rollup, - }); - - const txHash = await client.sendRawTransaction({ - serializedTransaction: await l3RollupOwner.signTransaction(tx), - }); - - await client.waitForTransactionReceipt({ - hash: txHash, - }); - - const validators = await Promise.all([ - client.rollupAdminLogicReadContract({ - functionName: 'isValidator', - args: [randomAccounts[0]], - rollup: l3Rollup, - }), - client.rollupAdminLogicReadContract({ - functionName: 'isValidator', - args: [randomAccounts[1]], - rollup: l3Rollup, - }), - ]); - - const { validators: currentValidators, isAccurate: currentIsAccurate } = await getValidators( - client, - { rollup: l3Rollup }, - ); - expect(validators).toEqual([true, false]); - expect(currentValidators).toEqual(initialValidators.concat(randomAccounts[0])); - expect(currentIsAccurate).toBeTruthy(); - - const revertTx = await client.rollupAdminLogicPrepareTransactionRequest({ - functionName: 'setValidator', - args: [randomAccounts, [false, false]], - account: l3RollupOwner.address, - upgradeExecutor: l3UpgradeExecutor, - rollup: l3Rollup, - }); - - const revertTxHash = await client.sendRawTransaction({ - serializedTransaction: await l3RollupOwner.signTransaction(revertTx), - }); - await client.waitForTransactionReceipt({ - hash: revertTxHash, - }); - - const { validators: revertedValidators, isAccurate: revertedIsAccurate } = await getValidators( - client, - { - rollup: l3Rollup, - }, - ); - expect(revertedValidators).toEqual(initialValidators); - expect(revertedIsAccurate).toBeTruthy(); -}); - -it('successfully enable/disable whitelist', async () => { - const whitelistDisabledBefore = await client.rollupAdminLogicReadContract({ - functionName: 'validatorWhitelistDisabled', - }); - - // By default whitelist is not disabled - expect(whitelistDisabledBefore).toEqual(false); - - const tx = await client.rollupAdminLogicPrepareTransactionRequest({ - functionName: 'setValidatorWhitelistDisabled', - args: [true], - account: l3RollupOwner.address, - rollup: l3Rollup, - upgradeExecutor: l3UpgradeExecutor, - }); - - const txHash = await client.sendRawTransaction({ - serializedTransaction: await l3RollupOwner.signTransaction(tx), - }); - await client.waitForTransactionReceipt({ - hash: txHash, - }); - - const whitelistDisabled = await client.rollupAdminLogicReadContract({ - functionName: 'validatorWhitelistDisabled', - rollup: l3Rollup, - }); - - expect(whitelistDisabled).toEqual(true); - - // Revert changes, so test can be run multiple time without issues - const revertTx = await client.rollupAdminLogicPrepareTransactionRequest({ - functionName: 'setValidatorWhitelistDisabled', - args: [false], - account: l3RollupOwner.address, - rollup: l3Rollup, - upgradeExecutor: l3UpgradeExecutor, - }); - - const revertTxHash = await client.sendRawTransaction({ - serializedTransaction: await l3RollupOwner.signTransaction(revertTx), - }); - await client.waitForTransactionReceipt({ - hash: revertTxHash, - }); -}); diff --git a/src/decorators/rollupAdminLogicPublicActions.ts b/src/decorators/rollupAdminLogicPublicActions.ts deleted file mode 100644 index 3db51c8a9..000000000 --- a/src/decorators/rollupAdminLogicPublicActions.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { Transport, Chain, PrepareTransactionRequestReturnType, PublicClient, Address } from 'viem'; -import { RollupAdminLogic__factory } from '@arbitrum/sdk/dist/lib/abi/factories/RollupAdminLogic__factory'; - -import { - createContractRead, - ContractReadFunctionName, - ContractReadParameters, - ContractReadReturnType, -} from '../contractRead'; -import { - RollupAdminLogicAbi, - RollupAdminLogicFunctionName, - rollupAdminLogicPrepareTransactionRequest, - RollupAdminLogicPrepareTransactionRequestParameters, -} from '../rollupAdminLogicPrepareTransactionRequest'; - -type RollupAdminLogicAddressParameters = { rollup: Address }; -type RollupAdminLogicReadFunctionName = ContractReadFunctionName; -type RollupAdminLogicReadContractParameters< - TFunctionName extends RollupAdminLogicReadFunctionName, -> = ContractReadParameters; -type RollupAdminLogicReadContractReturnType< - TFunctionName extends RollupAdminLogicReadFunctionName, -> = ContractReadReturnType; - -const rollupAdminLogicReadContract = createContractRead< - RollupAdminLogicAbi, - RollupAdminLogicAddressParameters ->(RollupAdminLogic__factory.abi as unknown as RollupAdminLogicAbi, ({ rollup }) => rollup); - -type RollupAdminLogicReadContractArgs< - TRollupAdminLogic extends Address | undefined, - TFunctionName extends RollupAdminLogicReadFunctionName, -> = TRollupAdminLogic extends Address - ? Omit, 'rollup'> & { - rollup?: Address; - } - : RollupAdminLogicReadContractParameters; -type rollupAdminLogicPrepareTransactionRequestArgs< - TRollupAdminLogic extends Address | undefined, - TFunctionName extends RollupAdminLogicFunctionName, -> = TRollupAdminLogic extends Address - ? Omit, 'rollup'> & { - rollup?: Address; - } - : RollupAdminLogicPrepareTransactionRequestParameters; - -export type RollupAdminLogicActions< - TRollupAdminLogic extends Address | undefined, - TChain extends Chain | undefined = Chain | undefined, -> = { - rollupAdminLogicReadContract: ( - args: RollupAdminLogicReadContractArgs, - ) => Promise>; - - rollupAdminLogicPrepareTransactionRequest: ( - args: rollupAdminLogicPrepareTransactionRequestArgs, - ) => Promise & { chainId: number }>; -}; - -export function rollupAdminLogicPublicActions< - TParams extends { rollup?: Address }, - TTransport extends Transport = Transport, - TChain extends Chain | undefined = Chain, ->({ - rollup, -}: TParams): ( - client: PublicClient, -) => RollupAdminLogicActions { - return function rollupAdminLogicActionsWithRollupAdminLogicAddress( - client: PublicClient, - ) { - const rollupAdminLogicExtensions: RollupAdminLogicActions = { - rollupAdminLogicReadContract: ( - args: RollupAdminLogicReadContractArgs, - ) => { - return rollupAdminLogicReadContract(client, { - ...args, - rollup: args.rollup || rollup, - } as RollupAdminLogicReadContractParameters); - }, - rollupAdminLogicPrepareTransactionRequest: < - TFunctionName extends RollupAdminLogicFunctionName, - >( - args: rollupAdminLogicPrepareTransactionRequestArgs, - ) => { - return rollupAdminLogicPrepareTransactionRequest(client, { - ...args, - rollup: args.rollup || rollup, - } as RollupAdminLogicPrepareTransactionRequestParameters); - }, - }; - return rollupAdminLogicExtensions; - }; -} diff --git a/src/decorators/sequencerInboxActions.integration.test.ts b/src/decorators/sequencerInboxActions.integration.test.ts deleted file mode 100644 index 0af77eabb..000000000 --- a/src/decorators/sequencerInboxActions.integration.test.ts +++ /dev/null @@ -1,268 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { createPublicClient, http, zeroAddress } from 'viem'; -import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; - -import { nitroTestnodeL2 } from '../chains'; -import { - getNitroTestnodePrivateKeyAccounts, - getInformationFromTestnode, - createRollupHelper, -} from '../testHelpers'; -import { sequencerInboxActions } from './sequencerInboxActions'; -import { sequencerInboxABI } from '../contracts/SequencerInbox'; - -const { l3RollupOwner, l3TokenBridgeDeployer, deployer } = getNitroTestnodePrivateKeyAccounts(); - -const randomAccount = privateKeyToAccount(generatePrivateKey()); - -const { l3SequencerInbox, l3Bridge, l3Rollup, l3BatchPoster, l3UpgradeExecutor } = - getInformationFromTestnode(); - -const client = createPublicClient({ - chain: nitroTestnodeL2, - transport: http(), -}).extend(sequencerInboxActions({ sequencerInbox: l3SequencerInbox })); - -describe('sequencerInboxReadContract', () => { - it('successfully fetches batchCount', async () => { - const batchCount = await client.sequencerInboxReadContract({ - functionName: 'batchCount', - }); - expect(Number(batchCount)).greaterThan(0); - }); - - it('successfully fetches bridge', async () => { - const result = await client.sequencerInboxReadContract({ - functionName: 'bridge', - sequencerInbox: l3SequencerInbox, - }); - - expect(result.toLowerCase()).toEqual(l3Bridge.toLowerCase()); - }); - - it('successfully fetches dasKeySetInfo', async () => { - const [isValidKeyset, creationBlock] = await client.sequencerInboxReadContract({ - functionName: 'dasKeySetInfo', - sequencerInbox: l3SequencerInbox, - args: ['0x0000000000000000000000000000000000000000000000000000000000000000'], - }); - - expect(isValidKeyset).toEqual(false); - expect(creationBlock).toEqual(0n); - }); - - it('successfully call inboxAccs', async () => { - const result = await client.sequencerInboxReadContract({ - functionName: 'inboxAccs', - sequencerInbox: l3SequencerInbox, - args: [0n], - }); - - expect(result).not.toEqual(zeroAddress); - }); - - it('successfully call isBatchPoster', async () => { - const result = await client.sequencerInboxReadContract({ - functionName: 'isBatchPoster', - sequencerInbox: l3SequencerInbox, - args: [randomAccount.address], - }); - const resultWithBatchPoster = await client.sequencerInboxReadContract({ - functionName: 'isBatchPoster', - sequencerInbox: l3SequencerInbox, - args: [l3BatchPoster], - }); - - expect(result).toEqual(false); - expect(resultWithBatchPoster).toEqual(true); - }); - - it('successfully call isValidKeysetHash', async () => { - const result = await client.sequencerInboxReadContract({ - functionName: 'isValidKeysetHash', - sequencerInbox: l3SequencerInbox, - args: ['0x0000000000000000000000000000000000000000000000000000000000000000'], - }); - - expect(result).toEqual(false); - }); - - it('successfully call maxTimeVariation', async () => { - const result = await client.sequencerInboxReadContract({ - functionName: 'maxTimeVariation', - sequencerInbox: l3SequencerInbox, - }); - - expect(result).toEqual([5760n, 12n, 86400n, 3600n]); - }); - - it('successfully call rollup', async () => { - const result = await client.sequencerInboxReadContract({ - functionName: 'rollup', - sequencerInbox: l3SequencerInbox, - }); - - expect(result.toLowerCase()).toEqual(l3Rollup.toLowerCase()); - }); - - it('successfully call totalDelayedMessagesRead', async () => { - const result = await client.sequencerInboxReadContract({ - functionName: 'totalDelayedMessagesRead', - sequencerInbox: l3SequencerInbox, - }); - - expect(Number(result)).greaterThan(0); - }); -}); - -describe('sequencerInboxPrepareTransactionRequest', () => { - it('successfully call setValidKeyset', async () => { - // Keyset needs to be set on anytrust chain - 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 keyset = - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002560000000000000002000000000000000201216006dcb5e56764bb72e6a45e6deb301ca85d8c4315c1da2efa29927f2ac8fb25571ce31d2d603735fe03196f6d56bcbf9a1999a89a74d5369822c4445d676c15ed52e5008daa775dc9a839c99ff963a19946ac740579874dac4f639907ae1bc69f0c6694955b524d718ca445831c5375393773401f33725a79661379dddabd5fff28619dc070befd9ed73d699e5c236c1a163be58ba81002b6130709bc064af5d7ba947130b72056bf17263800f1a3ab2269c6a510ef8e7412fd56d1ef1b916a1306e3b1d9c82c099371bd9861582acaada3a16e9dfee5d0ebce61096598a82f112d0a935e8cab5c48d82e3104b0c7ba79157dad1a019a3e7f6ad077b8e6308b116fec0f58239622463c3631fa01e2b4272409215b8009422c16715dbede5909060121600835f995f2478f24892d050daa289f8b6b9c1b185bcd28532f88d610c2642a2dc6f3509740236d33c3e2d9136aab17f819c8c671293bba277717762e8d1c1f7bac9e17dd28d2939a959bb38e500f9c11c38cebbc426e2dea97c40175a655d17400ae6c75ff49e884c79469249e70953258854b64fa8445c585ad45dc6dc6975501c6af7cff7074202c687f8a7bf1a3ac192689755f232275b4c8421b1a5669e9b904c29a292cdf961b783a7c0b4ce736900de4d8c63c5f85a65cb44af34bef840acef84ab75f44c4c9137610b68107aff3bbdcc19119c7a927c115b7b9bfb27d85c500ee77d13ec5a97a3ae6bf51d3b70a5502e8416de7b5eb8e9feee376411ca35c8a7f3f597c7606578cf96a4715ce5a35cf48e39c0a1faa2dee22d74e681900000000000000000000'; - const transactionRequest = await client.sequencerInboxPrepareTransactionRequest({ - functionName: 'setValidKeyset', - sequencerInbox: sequencerInbox, - args: [keyset], - account: l3TokenBridgeDeployer.address, - upgradeExecutor: 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[0].args.keysetHash; - - const result = await client.sequencerInboxReadContract({ - functionName: 'isValidKeysetHash', - sequencerInbox, - args: [keysetHash!], - }); - - expect(result).toEqual(true); - }); - - it('successfully call setIsBatchPoster', async () => { - const resultBefore = await client.sequencerInboxReadContract({ - functionName: 'isBatchPoster', - sequencerInbox: l3SequencerInbox, - args: [randomAccount.address], - }); - expect(resultBefore).toEqual(false); - - const transactionRequest = await client.sequencerInboxPrepareTransactionRequest({ - functionName: 'setIsBatchPoster', - sequencerInbox: l3SequencerInbox, - args: [randomAccount.address, true], - account: l3RollupOwner.address, - upgradeExecutor: l3UpgradeExecutor, - }); - - const txHash = await client.sendRawTransaction({ - serializedTransaction: await l3RollupOwner.signTransaction(transactionRequest), - }); - - await client.waitForTransactionReceipt({ hash: txHash }); - - const result = await client.sequencerInboxReadContract({ - functionName: 'isBatchPoster', - sequencerInbox: l3SequencerInbox, - args: [randomAccount.address], - }); - expect(result).toEqual(true); - - // Revert the change and assert - const revertTransactionRequest = await client.sequencerInboxPrepareTransactionRequest({ - functionName: 'setIsBatchPoster', - sequencerInbox: l3SequencerInbox, - args: [randomAccount.address, false], - account: l3RollupOwner.address, - upgradeExecutor: l3UpgradeExecutor, - }); - const revertTxHash = await client.sendRawTransaction({ - serializedTransaction: await l3RollupOwner.signTransaction(revertTransactionRequest), - }); - - await client.waitForTransactionReceipt({ hash: revertTxHash }); - - const resultAfterReverting = await client.sequencerInboxReadContract({ - functionName: 'isBatchPoster', - sequencerInbox: l3SequencerInbox, - args: [randomAccount.address], - }); - expect(resultAfterReverting).toEqual(false); - }); - - it('successfully call setMaxTimeVariation', async () => { - const resultBefore = await client.sequencerInboxReadContract({ - functionName: 'maxTimeVariation', - sequencerInbox: l3SequencerInbox, - }); - - const transactionRequest = await client.sequencerInboxPrepareTransactionRequest({ - functionName: 'setMaxTimeVariation', - sequencerInbox: l3SequencerInbox, - upgradeExecutor: l3UpgradeExecutor, - args: [ - { - delayBlocks: 2_880n, - futureBlocks: 6n, - delaySeconds: 43_200n, - futureSeconds: 1_800n, - }, - ], - account: l3RollupOwner.address, - }); - const txHash = await client.sendRawTransaction({ - serializedTransaction: await l3RollupOwner.signTransaction(transactionRequest), - }); - - await client.waitForTransactionReceipt({ hash: txHash }); - - const result = await client.sequencerInboxReadContract({ - functionName: 'maxTimeVariation', - sequencerInbox: l3SequencerInbox, - }); - expect(result).toEqual([2_880n, 6n, 43_200n, 1_800n]); - - // Revert the change, so read test still work - const transactionRequestRevert = await client.sequencerInboxPrepareTransactionRequest({ - functionName: 'setMaxTimeVariation', - sequencerInbox: l3SequencerInbox, - upgradeExecutor: l3UpgradeExecutor, - args: [ - { - delayBlocks: resultBefore[0], - futureBlocks: resultBefore[1], - delaySeconds: resultBefore[2], - futureSeconds: resultBefore[3], - }, - ], - account: l3RollupOwner.address, - }); - const revertTxHash = await client.sendRawTransaction({ - serializedTransaction: await l3RollupOwner.signTransaction(transactionRequestRevert), - }); - - await client.waitForTransactionReceipt({ hash: revertTxHash }); - }); -}); diff --git a/src/decorators/sequencerInboxActions.ts b/src/decorators/sequencerInboxActions.ts deleted file mode 100644 index 6668d6649..000000000 --- a/src/decorators/sequencerInboxActions.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { Transport, Chain, PrepareTransactionRequestReturnType, PublicClient, Address } from 'viem'; - -import { sequencerInboxABI } from '../contracts/SequencerInbox'; -import { - createContractRead, - ContractReadFunctionName, - ContractReadParameters, - ContractReadReturnType, -} from '../contractRead'; -import { - SequencerInboxAbi, - SequencerInboxFunctionName, - sequencerInboxPrepareTransactionRequest, - SequencerInboxPrepareTransactionRequestParameters, -} from '../sequencerInboxPrepareTransactionRequest'; - -type SequencerInboxAddressParameters = { sequencerInbox: Address }; -type SequencerInboxReadFunctionName = ContractReadFunctionName; -type SequencerInboxReadContractParameters = - ContractReadParameters; -type SequencerInboxReadContractReturnType = - ContractReadReturnType; - -const sequencerInboxReadContract = createContractRead< - SequencerInboxAbi, - SequencerInboxAddressParameters ->(sequencerInboxABI, ({ sequencerInbox }) => sequencerInbox); - -type SequencerInboxReadContractArgs< - TSequencerInbox extends Address | undefined, - TFunctionName extends SequencerInboxReadFunctionName, -> = TSequencerInbox extends Address - ? Omit, 'sequencerInbox'> & { - sequencerInbox?: Address; - } - : SequencerInboxReadContractParameters; -type SequencerInboxPrepareTransactionRequestArgs< - TSequencerInbox extends Address | undefined, - TFunctionName extends SequencerInboxFunctionName, -> = TSequencerInbox extends Address - ? Omit, 'sequencerInbox'> & { - sequencerInbox?: Address; - } - : SequencerInboxPrepareTransactionRequestParameters; - -export type SequencerInboxActions< - TSequencerInbox extends Address | undefined, - TChain extends Chain | undefined = Chain | undefined, -> = { - sequencerInboxReadContract: ( - args: SequencerInboxReadContractArgs, - ) => Promise>; - - sequencerInboxPrepareTransactionRequest: ( - args: SequencerInboxPrepareTransactionRequestArgs, - ) => Promise & { chainId: number }>; -}; - -/** - * Set of actions that can be performed on the sequencerInbox contract through wagmi public client - * - * @param {Object} sequencerInbox - Address of the sequencerInbox core contract - * User can still overrides sequencerInbox address, - * by passing it as an argument to sequencerInboxReadContract/sequencerInboxPrepareTransactionRequest calls - * - * @returns {Function} sequencerInboxActionsWithSequencerInbox - Function passed to client.extends() to extend the public client - * - * @example - * const client = createPublicClient({ - * chain: arbitrumOne, - * transport: http(), - * }).extend(sequencerInboxActions(coreContracts.sequencerInbox)); - * - * // SequencerInbox is set to `coreContracts.sequencerInbox` for every call - * client.sequencerInboxReadContract({ - * functionName: 'inboxAccs', - * }); - * - * // Overriding sequencerInbox address for this call only - * client.sequencerInboxReadContract({ - * functionName: 'inboxAccs', - * sequencerInbox: contractAddress.anotherSequencerInbox - * }); - */ - -export function sequencerInboxActions< - TParams extends { sequencerInbox?: Address }, - TTransport extends Transport = Transport, - TChain extends Chain | undefined = Chain | undefined, ->({ sequencerInbox }: TParams) { - return function sequencerInboxActionsWithSequencerInbox( - client: PublicClient, - ) { - const sequencerInboxExtensions: SequencerInboxActions = { - sequencerInboxReadContract: ( - args: SequencerInboxReadContractArgs, - ) => { - return sequencerInboxReadContract(client, { - ...args, - sequencerInbox: args.sequencerInbox || sequencerInbox, - } as SequencerInboxReadContractParameters); - }, - sequencerInboxPrepareTransactionRequest: ( - args: SequencerInboxPrepareTransactionRequestArgs, - ) => { - return sequencerInboxPrepareTransactionRequest(client, { - ...args, - sequencerInbox: args.sequencerInbox || sequencerInbox, - } as SequencerInboxPrepareTransactionRequestParameters); - }, - }; - return sequencerInboxExtensions; - }; -} diff --git a/src/decorators/sequencerInboxActions.unit.test.ts b/src/decorators/sequencerInboxActions.unit.test.ts deleted file mode 100644 index cfb858e67..000000000 --- a/src/decorators/sequencerInboxActions.unit.test.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { it, expect, expectTypeOf, describe } from 'vitest'; - -import { - AbiEncodingLengthMismatchError, - AbiFunctionNotFoundError, - InvalidAddressError, - createPublicClient, - http, -} from 'viem'; -import { nitroTestnodeL2 } from '../chains'; -import { sequencerInboxActions } from './sequencerInboxActions'; -import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; - -const l3SequencerInbox = '0x42b5da0625cf278067955f07045f63cafd79274f'; - -const client = createPublicClient({ - chain: nitroTestnodeL2, - transport: http(), -}).extend(sequencerInboxActions({ sequencerInbox: l3SequencerInbox })); - -const randomAccount = privateKeyToAccount(generatePrivateKey()); - -describe('SequencerInbox parameter:', () => { - it('require sequencerInbox parameter if not passed initially to the actions during initialization', () => { - const clientWithoutSequencerInboxAddress = createPublicClient({ - chain: nitroTestnodeL2, - transport: http(), - }).extend(sequencerInboxActions({})); - - // @ts-expect-error sequencerInbox is required - clientWithoutSequencerInboxAddress.sequencerInboxReadContract({ - functionName: 'inboxAccs', - args: [10n], - }); - }); - - it('Doesn`t require sequencerInbox parameter if passed initially to the actions during initialization', () => { - const clientWithSequencerInboxAddress = createPublicClient({ - chain: nitroTestnodeL2, - transport: http(), - }).extend(sequencerInboxActions({ sequencerInbox: l3SequencerInbox })); - - clientWithSequencerInboxAddress.sequencerInboxReadContract({ - functionName: 'inboxAccs', - args: [10n], - }); - }); - - it('Allow sequencerInbox override parameter if passed initially to the actions during initialization', () => { - const clientWithSequencerInboxAddress = createPublicClient({ - chain: nitroTestnodeL2, - transport: http(), - }).extend(sequencerInboxActions({ sequencerInbox: l3SequencerInbox })); - - clientWithSequencerInboxAddress.sequencerInboxReadContract({ - functionName: 'inboxAccs', - args: [10n], - sequencerInbox: randomAccount.address, - }); - }); -}); - -it('Infer parameters based on function name', async () => { - await expect( - client.sequencerInboxPrepareTransactionRequest({ - functionName: 'setIsBatchPoster', - // @ts-expect-error Args are missing - args: [], - upgradeExecutor: false, - account: randomAccount.address, - }), - ).rejects.toThrowError(AbiEncodingLengthMismatchError); - - await expect( - client.sequencerInboxPrepareTransactionRequest({ - functionName: 'setIsBatchPoster', - // @ts-expect-error Args are of the wrong type - args: [10n, true], - upgradeExecutor: false, - account: randomAccount.address, - }), - ).rejects.toThrowError(InvalidAddressError); - - await expect( - client - // @ts-expect-error Args are required for `setIsBatchPoster` - .sequencerInboxPrepareTransactionRequest({ - functionName: 'setIsBatchPoster', - upgradeExecutor: false, - account: randomAccount.address, - }), - ).rejects.toThrow(AbiEncodingLengthMismatchError); - - expectTypeOf< - typeof client.sequencerInboxPrepareTransactionRequest<'setIsBatchPoster'> - >().toBeCallableWith({ - functionName: 'setIsBatchPoster', - args: [randomAccount.address, true], - upgradeExecutor: false, - account: randomAccount.address, - }); - - // Function doesn't exist - await expect( - client.sequencerInboxPrepareTransactionRequest({ - // @ts-expect-error Function not available - functionName: 'notExisting', - }), - ).rejects.toThrowError(AbiFunctionNotFoundError); -}); diff --git a/src/getBatchPosters.integration.test.ts b/src/getBatchPosters.integration.test.ts index eff0dd0f4..c60ba4894 100644 --- a/src/getBatchPosters.integration.test.ts +++ b/src/getBatchPosters.integration.test.ts @@ -3,9 +3,9 @@ import { Address, createPublicClient, http } from 'viem'; import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; import { nitroTestnodeL2 } from './chains'; -import { sequencerInboxActions } from './decorators/sequencerInboxActions'; import { getInformationFromTestnode, getNitroTestnodePrivateKeyAccounts } from './testHelpers'; import { getBatchPosters } from './getBatchPosters'; +import { sequencerInboxPrepareTransactionRequest } from './sequencerInboxPrepareTransactionRequest'; const { l3RollupOwner } = getNitroTestnodePrivateKeyAccounts(); const { l3Rollup, l3UpgradeExecutor, l3SequencerInbox } = getInformationFromTestnode(); @@ -13,14 +13,10 @@ const { l3Rollup, l3UpgradeExecutor, l3SequencerInbox } = getInformationFromTest const client = createPublicClient({ chain: nitroTestnodeL2, transport: http(), -}).extend( - sequencerInboxActions({ - sequencerInbox: l3SequencerInbox, - }), -); +}); async function setBatchPoster(batchPoster: Address, state: boolean) { - const tx = await client.sequencerInboxPrepareTransactionRequest({ + const tx = await sequencerInboxPrepareTransactionRequest(client, { functionName: 'setIsBatchPoster', args: [batchPoster, state], account: l3RollupOwner.address, diff --git a/src/getKeysets.integration.test.ts b/src/getKeysets.integration.test.ts index e839f4993..8d8768854 100644 --- a/src/getKeysets.integration.test.ts +++ b/src/getKeysets.integration.test.ts @@ -10,25 +10,16 @@ import { } from 'viem'; import { nitroTestnodeL2 } from './chains'; -import { sequencerInboxActions } from './decorators/sequencerInboxActions'; -import { - createRollupHelper, - getInformationFromTestnode, - getNitroTestnodePrivateKeyAccounts, -} from './testHelpers'; +import { createRollupHelper, getNitroTestnodePrivateKeyAccounts } from './testHelpers'; import { getKeysets } from './getKeysets'; +import { sequencerInboxPrepareTransactionRequest } from './sequencerInboxPrepareTransactionRequest'; -const { l3SequencerInbox } = getInformationFromTestnode(); const { l3TokenBridgeDeployer, deployer } = getNitroTestnodePrivateKeyAccounts(); const client = createPublicClient({ chain: nitroTestnodeL2, transport: http(), -}).extend( - sequencerInboxActions({ - sequencerInbox: l3SequencerInbox, - }), -); +}); async function sendKeysetTransaction({ account, @@ -55,7 +46,7 @@ async function setValidKeyset({ upgradeExecutor: Address; account: PrivateKeyAccount; }) { - const tx = await client.sequencerInboxPrepareTransactionRequest({ + const tx = await sequencerInboxPrepareTransactionRequest(client, { functionName: 'setValidKeyset', args: [keysetBytes], account: account.address, @@ -75,7 +66,7 @@ async function invalidateKeyset({ upgradeExecutor: Address; account: PrivateKeyAccount; }) { - const tx = await client.sequencerInboxPrepareTransactionRequest({ + const tx = await sequencerInboxPrepareTransactionRequest(client, { functionName: 'invalidateKeysetHash', args: [keysetHash], account: account.address, diff --git a/src/getValidators.integration.test.ts b/src/getValidators.integration.test.ts index 8aa215ced..b2d171e6f 100644 --- a/src/getValidators.integration.test.ts +++ b/src/getValidators.integration.test.ts @@ -3,13 +3,13 @@ import { Address, createPublicClient, http } from 'viem'; import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; import { nitroTestnodeL2 } from './chains'; -import { rollupAdminLogicPublicActions } from './decorators/rollupAdminLogicPublicActions'; import { getInformationFromTestnode, getNitroTestnodePrivateKeyAccounts, testHelper_getRollupCreatorVersionFromEnv, } from './testHelpers'; import { getValidators } from './getValidators'; +import { rollupAdminLogicPrepareTransactionRequest } from './rollupAdminLogicPrepareTransactionRequest'; const { l3RollupOwner } = getNitroTestnodePrivateKeyAccounts(); const { l3Rollup, l3UpgradeExecutor } = getInformationFromTestnode(); @@ -23,14 +23,10 @@ const expectedInitialValidators = rollupCreatorVersion === 'v3.2' ? 11 : 10; const client = createPublicClient({ chain: nitroTestnodeL2, transport: http(), -}).extend( - rollupAdminLogicPublicActions({ - rollup: l3Rollup, - }), -); +}); async function setValidator(validator: Address, state: boolean) { - const tx = await client.rollupAdminLogicPrepareTransactionRequest({ + const tx = await rollupAdminLogicPrepareTransactionRequest(client, { functionName: 'setValidator', args: [[validator], [state]], account: l3RollupOwner.address, diff --git a/src/index.ts b/src/index.ts index 05db54fb0..d0c12db42 100644 --- a/src/index.ts +++ b/src/index.ts @@ -70,24 +70,32 @@ import { import { arbOwnerPrepareFunctionData, ArbOwnerPrepareFunctionDataParameters, + arbOwnerPrepareTransactionRequest, + ArbOwnerPrepareTransactionRequestParameters, } from './arbOwnerPrepareTransactionRequest'; -import { arbOwnerPublicActions } from './decorators/arbOwnerPublicActions'; -import { arbGasInfoPublicActions } from './decorators/arbGasInfoPublicActions'; +import { arbOwnerPublicConfig } from './contracts/ArbOwnerPublic'; +import { arbGasInfoConfig } from './contracts/ArbGasInfo'; +import { arbAggregatorConfig } from './contracts/ArbAggregator'; +import { sequencerInboxABI } from './contracts/SequencerInbox'; +import { rollupABI } from './contracts/Rollup'; import { arbAggregatorPrepareFunctionData, ArbAggregatorPrepareFunctionDataParameters, + arbAggregatorPrepareTransactionRequest, + ArbAggregatorPrepareTransactionRequestParameters, } from './arbAggregatorPrepareTransactionRequest'; -import { arbAggregatorActions } from './decorators/arbAggregatorActions'; import { sequencerInboxPrepareFunctionData, SequencerInboxPrepareFunctionDataParameters, + sequencerInboxPrepareTransactionRequest, + SequencerInboxPrepareTransactionRequestParameters, } from './sequencerInboxPrepareTransactionRequest'; -import { sequencerInboxActions } from './decorators/sequencerInboxActions'; import { rollupAdminLogicPrepareFunctionData, RollupAdminLogicPrepareFunctionDataParameters, + rollupAdminLogicPrepareTransactionRequest, + RollupAdminLogicPrepareTransactionRequestParameters, } from './rollupAdminLogicPrepareTransactionRequest'; -import { rollupAdminLogicPublicActions } from './decorators/rollupAdminLogicPublicActions'; import { ChainConfig, ChainConfigArbitrumParams } from './types/ChainConfig'; import { CoreContracts } from './types/CoreContracts'; @@ -197,23 +205,31 @@ import { import { prepareArbitrumNetwork } from './utils/registerNewNetwork'; export { - arbOwnerPublicActions, arbOwnerPrepareFunctionData, ArbOwnerPrepareFunctionDataParameters, + arbOwnerPrepareTransactionRequest, + ArbOwnerPrepareTransactionRequestParameters, + arbOwnerPublicConfig, // - arbGasInfoPublicActions, + arbGasInfoConfig, // - arbAggregatorActions, + arbAggregatorConfig, arbAggregatorPrepareFunctionData, ArbAggregatorPrepareFunctionDataParameters, + arbAggregatorPrepareTransactionRequest, + ArbAggregatorPrepareTransactionRequestParameters, // - sequencerInboxActions, + sequencerInboxABI, sequencerInboxPrepareFunctionData, SequencerInboxPrepareFunctionDataParameters, + sequencerInboxPrepareTransactionRequest, + SequencerInboxPrepareTransactionRequestParameters, // - rollupAdminLogicPublicActions, + rollupABI, rollupAdminLogicPrepareFunctionData, RollupAdminLogicPrepareFunctionDataParameters, + rollupAdminLogicPrepareTransactionRequest, + RollupAdminLogicPrepareTransactionRequestParameters, // createRollupEncodeFunctionData, // diff --git a/src/rollupAdminLogicPrepareTransactionRequest.unit.test.ts b/src/rollupAdminLogicPrepareTransactionRequest.unit.test.ts new file mode 100644 index 000000000..116a2e27c --- /dev/null +++ b/src/rollupAdminLogicPrepareTransactionRequest.unit.test.ts @@ -0,0 +1,95 @@ +import { it, expect, expectTypeOf } from 'vitest'; + +import { + AbiEncodingLengthMismatchError, + AbiFunctionNotFoundError, + InvalidAddressError, + createPublicClient, + http, +} from 'viem'; +import { rollupAdminLogicPrepareTransactionRequest } from './rollupAdminLogicPrepareTransactionRequest'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import { mainnet } from 'viem/chains'; + +const rollupAdminLogicAddress = '0x5eF0D09d1E6204141B4d37530808eD19f60FBa35'; + +const client = createPublicClient({ + chain: mainnet, + transport: http(), +}); + +const randomAccount = privateKeyToAccount(generatePrivateKey()); + +it('requires the Rollup address', () => { + if (false) { + // @ts-expect-error rollup is required + rollupAdminLogicPrepareTransactionRequest(client, { + functionName: 'setLoserStakeEscrow', + args: [randomAccount.address], + upgradeExecutor: false, + account: randomAccount.address, + }); + } + + expectTypeOf(rollupAdminLogicPrepareTransactionRequest).toBeCallableWith(client, { + functionName: 'setLoserStakeEscrow', + args: [randomAccount.address], + rollup: rollupAdminLogicAddress, + upgradeExecutor: false, + account: randomAccount.address, + }); +}); + +it('Infer parameters based on function name', async () => { + await expect( + rollupAdminLogicPrepareTransactionRequest(client, { + functionName: 'setLoserStakeEscrow', + // @ts-expect-error Args are missing + args: [], + upgradeExecutor: false, + account: randomAccount.address, + rollup: rollupAdminLogicAddress, + }), + ).rejects.toThrowError(AbiEncodingLengthMismatchError); + + await expect( + rollupAdminLogicPrepareTransactionRequest(client, { + functionName: 'setLoserStakeEscrow', + // @ts-expect-error Args are of the wrong type + args: [true], + upgradeExecutor: false, + account: randomAccount.address, + rollup: rollupAdminLogicAddress, + }), + ).rejects.toThrowError(InvalidAddressError); + + await expect( + rollupAdminLogicPrepareTransactionRequest(client, { + functionName: 'setLoserStakeEscrow', + upgradeExecutor: false, + account: randomAccount.address, + rollup: rollupAdminLogicAddress, + // @ts-expect-error Args are required for `setLoserStakeEscrow` + args: undefined, + }), + ).rejects.toThrow(AbiEncodingLengthMismatchError); + + expectTypeOf(rollupAdminLogicPrepareTransactionRequest).toBeCallableWith(client, { + functionName: 'setLoserStakeEscrow', + args: [randomAccount.address], + upgradeExecutor: false, + account: randomAccount.address, + rollup: rollupAdminLogicAddress, + }); + + // Function doesn't exist + await expect( + rollupAdminLogicPrepareTransactionRequest(client, { + // @ts-expect-error Function not available + functionName: 'notExisting', + upgradeExecutor: false, + account: randomAccount.address, + rollup: rollupAdminLogicAddress, + }), + ).rejects.toThrowError(AbiFunctionNotFoundError); +}); diff --git a/src/sequencerInboxPrepareTransactionRequest.unit.test.ts b/src/sequencerInboxPrepareTransactionRequest.unit.test.ts new file mode 100644 index 000000000..3735e47ea --- /dev/null +++ b/src/sequencerInboxPrepareTransactionRequest.unit.test.ts @@ -0,0 +1,95 @@ +import { it, expect, expectTypeOf } from 'vitest'; + +import { + AbiEncodingLengthMismatchError, + AbiFunctionNotFoundError, + InvalidAddressError, + createPublicClient, + http, +} from 'viem'; +import { nitroTestnodeL2 } from './chains'; +import { sequencerInboxPrepareTransactionRequest } from './sequencerInboxPrepareTransactionRequest'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; + +const l3SequencerInbox = '0x42b5da0625cf278067955f07045f63cafd79274f'; + +const client = createPublicClient({ + chain: nitroTestnodeL2, + transport: http(), +}); + +const randomAccount = privateKeyToAccount(generatePrivateKey()); + +it('requires the SequencerInbox address', () => { + if (false) { + // @ts-expect-error sequencerInbox is required + sequencerInboxPrepareTransactionRequest(client, { + functionName: 'setIsBatchPoster', + args: [randomAccount.address, true], + upgradeExecutor: false, + account: randomAccount.address, + }); + } + + expectTypeOf(sequencerInboxPrepareTransactionRequest).toBeCallableWith(client, { + functionName: 'setIsBatchPoster', + args: [randomAccount.address, true], + sequencerInbox: l3SequencerInbox, + upgradeExecutor: false, + account: randomAccount.address, + }); +}); + +it('Infer parameters based on function name', async () => { + await expect( + sequencerInboxPrepareTransactionRequest(client, { + functionName: 'setIsBatchPoster', + // @ts-expect-error Args are missing + args: [], + upgradeExecutor: false, + account: randomAccount.address, + sequencerInbox: l3SequencerInbox, + }), + ).rejects.toThrowError(AbiEncodingLengthMismatchError); + + await expect( + sequencerInboxPrepareTransactionRequest(client, { + functionName: 'setIsBatchPoster', + // @ts-expect-error Args are of the wrong type + args: [10n, true], + upgradeExecutor: false, + account: randomAccount.address, + sequencerInbox: l3SequencerInbox, + }), + ).rejects.toThrowError(InvalidAddressError); + + await expect( + sequencerInboxPrepareTransactionRequest(client, { + functionName: 'setIsBatchPoster', + upgradeExecutor: false, + account: randomAccount.address, + sequencerInbox: l3SequencerInbox, + // @ts-expect-error Args are required for `setIsBatchPoster` + args: undefined, + }), + ).rejects.toThrow(AbiEncodingLengthMismatchError); + + expectTypeOf(sequencerInboxPrepareTransactionRequest).toBeCallableWith(client, { + functionName: 'setIsBatchPoster', + args: [randomAccount.address, true], + upgradeExecutor: false, + account: randomAccount.address, + sequencerInbox: l3SequencerInbox, + }); + + // Function doesn't exist + await expect( + sequencerInboxPrepareTransactionRequest(client, { + // @ts-expect-error Function not available + functionName: 'notExisting', + upgradeExecutor: false, + account: randomAccount.address, + sequencerInbox: l3SequencerInbox, + }), + ).rejects.toThrowError(AbiFunctionNotFoundError); +});