Skip to content

Commit 74bc6be

Browse files
committed
Fix typing for prepareTransactionRequest
1 parent 831690a commit 74bc6be

7 files changed

+134
-102
lines changed

src/arbOwnerPrepareTransactionRequest.ts

Lines changed: 24 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,30 @@ import {
55
Address,
66
Chain,
77
Transport,
8+
GetFunctionArgs,
89
} from 'viem';
910

10-
import { arbOwner, ArbOSVersions } from './contracts';
11+
import { arbOwner, ArbOSVersions, ArbOwnerABIs } from './contracts';
1112
import { upgradeExecutorEncodeFunctionData } from './upgradeExecutor';
12-
import { GetFunctionName } from './types/utils';
13+
import { ArbOwnerPublicAbi, ArbOwnerPublicFunctionName } from './arbOwnerReadContract';
1314

14-
type ArbOwnerAbi = typeof arbOwner.abi;
15-
export type ArbOwnerPrepareTransactionRequestFunctionName = GetFunctionName<ArbOwnerAbi>;
1615
export type ArbOwnerEncodeFunctionDataParameters<
17-
TFunctionName extends ArbOwnerPrepareTransactionRequestFunctionName,
18-
> = EncodeFunctionDataParameters<ArbOwnerAbi, TFunctionName>;
19-
20-
function arbOwnerEncodeFunctionData<
21-
TFunctionName extends ArbOwnerPrepareTransactionRequestFunctionName,
22-
>({ functionName, abi, args }: ArbOwnerEncodeFunctionDataParameters<TFunctionName>) {
23-
return encodeFunctionData({
24-
abi,
25-
functionName,
26-
args,
27-
});
28-
}
29-
30-
type ArbOwnerPrepareFunctionDataParameters<
31-
TFunctionName extends ArbOwnerPrepareTransactionRequestFunctionName,
32-
> = ArbOwnerEncodeFunctionDataParameters<TFunctionName> & {
16+
TArbOsVersion extends ArbOSVersions,
17+
TFunctionName extends ArbOwnerPublicFunctionName<TArbOsVersion>,
18+
> = EncodeFunctionDataParameters<ArbOwnerPublicAbi<TArbOsVersion>, TFunctionName> & {
3319
upgradeExecutor: Address | false;
34-
abi: ArbOwnerAbi;
3520
};
21+
3622
function arbOwnerPrepareFunctionData<
37-
TFunctionName extends ArbOwnerPrepareTransactionRequestFunctionName,
38-
>(params: ArbOwnerPrepareFunctionDataParameters<TFunctionName>) {
23+
TArbOsVersion extends ArbOSVersions,
24+
TFunctionName extends ArbOwnerPublicFunctionName<TArbOsVersion>,
25+
>(params: ArbOwnerEncodeFunctionDataParameters<TArbOsVersion, TFunctionName>) {
3926
const { upgradeExecutor } = params;
4027

4128
if (!upgradeExecutor) {
4229
return {
4330
to: arbOwner.address,
44-
data: arbOwnerEncodeFunctionData(
45-
params as ArbOwnerEncodeFunctionDataParameters<TFunctionName>,
46-
),
31+
data: encodeFunctionData(params as EncodeFunctionDataParameters<ArbOwnerPublicAbi<TArbOsVersion>, TFunctionName>),
4732
value: BigInt(0),
4833
};
4934
}
@@ -54,37 +39,40 @@ function arbOwnerPrepareFunctionData<
5439
functionName: 'executeCall',
5540
args: [
5641
arbOwner.address, // target
57-
arbOwnerEncodeFunctionData(params as ArbOwnerEncodeFunctionDataParameters<TFunctionName>), // targetCallData
42+
encodeFunctionData(params as EncodeFunctionDataParameters<ArbOwnerPublicAbi<TArbOsVersion>, TFunctionName>), // targetCallData
5843
],
5944
}),
6045
value: BigInt(0),
6146
};
6247
}
6348

64-
export type ArbOwnerPrepareTransactionRequestParameters<TFunctionName extends ArbOwnerPrepareTransactionRequestFunctionName> = ArbOwnerEncodeFunctionDataParameters<TFunctionName> & {
65-
upgradeExecutor: Address | false;
49+
export type ArbOwnerPrepareTransactionRequestParameters<
50+
TArbOsVersion extends ArbOSVersions,
51+
TFunctionName extends ArbOwnerPublicFunctionName<TArbOsVersion>,
52+
> = {
53+
functionName: TFunctionName;
6654
account: Address;
67-
}
55+
upgradeExecutor: Address | false;
56+
} & GetFunctionArgs<ArbOwnerPublicAbi<TArbOsVersion>, TFunctionName>;
6857

6958
export async function arbOwnerPrepareTransactionRequest<
7059
TArbOsVersion extends ArbOSVersions,
71-
TFunctionName extends ArbOwnerPrepareTransactionRequestFunctionName,
7260
TChain extends Chain | undefined,
61+
TFunctionName extends ArbOwnerPublicFunctionName<TArbOsVersion>,
7362
>(
7463
client: PublicClient<Transport, TChain>,
75-
params: ArbOwnerPrepareTransactionRequestParameters<TFunctionName> & {
76-
arbOSVersion: TArbOsVersion;
64+
params: ArbOwnerPrepareTransactionRequestParameters<TArbOsVersion, TFunctionName> & {
65+
arbOsVersion: TArbOsVersion;
7766
},
7867
) {
7968
if (typeof client.chain === 'undefined') {
8069
throw new Error('[arbOwnerPrepareTransactionRequest] client.chain is undefined');
8170
}
8271

83-
// params is extending ArbOwnerPrepareFunctionDataParameters, it's safe to cast
8472
const { to, data, value } = arbOwnerPrepareFunctionData({
8573
...params,
86-
abi: arbOwner.abi,
87-
} as unknown as ArbOwnerPrepareFunctionDataParameters<TFunctionName>);
74+
abi: ArbOwnerABIs[params.arbOsVersion],
75+
} as unknown as ArbOwnerEncodeFunctionDataParameters<TArbOsVersion, TFunctionName>);
8876

8977
// @ts-ignore (todo: fix viem type issue)
9078
const request = await client.prepareTransactionRequest({

src/arbOwnerReadContract.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ export function arbOwnerReadContract<
2929
>(
3030
client: PublicClient<Transport, TChain>,
3131
params: ArbOwnerReadContractParameters<TArbOsVersion, TFunctionName> & {
32-
arbOSVersion: TArbOsVersion;
32+
arbOsVersion: TArbOsVersion;
3333
},
3434
): Promise<ArbOwnerReadContractReturnType<TArbOsVersion, TFunctionName>> {
3535
// @ts-ignore (todo: fix viem type issue)
3636
return client.readContract({
3737
address: arbOwnerPublic.address,
38-
abi: ArbOwnerABIs[params.arbOSVersion],
38+
abi: ArbOwnerABIs[params.arbOsVersion],
3939
functionName: params.functionName,
4040
args: params.args,
4141
});

src/contracts.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,13 @@ export const ArbOwnerABIs = {
216216
name: 'onlyOnArbOS10',
217217
outputs: [{ name: '', internalType: 'address[]', type: 'address[]' }],
218218
},
219+
{
220+
stateMutability: 'nonpayable',
221+
type: 'function',
222+
inputs: [{ name: 'recipient', internalType: 'address[]', type: 'address[]' }],
223+
name: 'setL1PricingRewardRecipient',
224+
outputs: [],
225+
},
219226
],
220227
11: [
221228
{
@@ -232,6 +239,13 @@ export const ArbOwnerABIs = {
232239
name: 'onlyOnArbOS11',
233240
outputs: [{ name: '', internalType: 'address[]', type: 'address[]' }],
234241
},
242+
{
243+
stateMutability: 'nonpayable',
244+
type: 'function',
245+
inputs: [{ name: 'recipient', internalType: 'uint64', type: 'uint64' }],
246+
name: 'setL1PricingRewardRecipient',
247+
outputs: [],
248+
},
235249
],
236250
20: arbOwnerConfig.abi,
237251
} as const;

src/decorators/arbOwnerPrepareTransactionRequest.unit.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
1414
const client = createPublicClient({
1515
chain: nitroTestnodeL2,
1616
transport: http(),
17-
}).extend(arbOwnerPublicActions);
17+
}).extend(arbOwnerPublicActions({ arbOsVersion: 20 }));
1818
const randomAccount = privateKeyToAccount(generatePrivateKey());
1919

2020
it('Infer parameters based on function name', async () => {

src/decorators/arbOwnerPublicActions.integration.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const randomAccount = privateKeyToAccount(generatePrivateKey());
1515
const client = createPublicClient({
1616
chain: nitroTestnodeL2,
1717
transport: http(),
18-
}).extend(arbOwnerPublicActions({ arbOSVersion: 20 }));
18+
}).extend(arbOwnerPublicActions({ arbOsVersion: 20 }));
1919

2020
it('successfully fetches network fee receiver', async () => {
2121
const result = await client.arbOwnerReadContract({

src/decorators/arbOwnerPublicActions.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
} from '../arbOwnerReadContract';
99
import {
1010
arbOwnerPrepareTransactionRequest,
11-
ArbOwnerPrepareTransactionRequestFunctionName,
1211
ArbOwnerPrepareTransactionRequestParameters,
1312
} from '../arbOwnerPrepareTransactionRequest';
1413
import { ArbOSVersions } from '../contracts';
@@ -22,25 +21,25 @@ export type ArbOwnerPublicActions<
2221
) => Promise<ArbOwnerReadContractReturnType<TArbOsVersion, TFunctionName>>;
2322

2423
arbOwnerPrepareTransactionRequest: <
25-
TFunctionName extends ArbOwnerPrepareTransactionRequestFunctionName,
24+
TFunctionName extends ArbOwnerPublicFunctionName<TArbOsVersion>,
2625
>(
27-
args: ArbOwnerPrepareTransactionRequestParameters<TFunctionName>,
26+
args: ArbOwnerPrepareTransactionRequestParameters<TArbOsVersion, TFunctionName>,
2827
) => Promise<PrepareTransactionRequestReturnType<TChain> & { chainId: number }>;
2928
};
3029

3130
export function arbOwnerPublicActions<
3231
TArbOsVersion extends ArbOSVersions,
3332
TTransport extends Transport = Transport,
3433
TChain extends Chain | undefined = Chain | undefined,
35-
>({ arbOSVersion }: { arbOSVersion: TArbOsVersion }) {
34+
>({ arbOsVersion }: { arbOsVersion: TArbOsVersion }) {
3635
return (
3736
client: PublicClient<TTransport, TChain>,
3837
): ArbOwnerPublicActions<TArbOsVersion, TChain> => {
3938
return {
40-
arbOwnerReadContract: (args) => arbOwnerReadContract(client, { ...args, arbOSVersion }),
39+
arbOwnerReadContract: (args) => arbOwnerReadContract(client, { ...args, arbOsVersion }),
4140

4241
arbOwnerPrepareTransactionRequest: (args) =>
43-
arbOwnerPrepareTransactionRequest(client, { ...args, arbOSVersion }),
42+
arbOwnerPrepareTransactionRequest(client, { ...args, arbOsVersion }),
4443
};
4544
};
4645
}
Lines changed: 87 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,112 @@
1-
import { it, expect, expectTypeOf } from 'vitest';
1+
import { describe, it, expect, expectTypeOf } from 'vitest';
22

33
import { AbiFunctionNotFoundError, createPublicClient, http } from 'viem';
44
import { nitroTestnodeL2 } from '../chains';
55
import { arbOwnerPublicActions } from './arbOwnerPublicActions';
6+
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
67

78
const client10 = createPublicClient({
89
chain: nitroTestnodeL2,
910
transport: http(),
10-
}).extend(arbOwnerPublicActions({ arbOSVersion: 10 }));
11+
}).extend(arbOwnerPublicActions({ arbOsVersion: 10 }));
1112
const client11 = createPublicClient({
1213
chain: nitroTestnodeL2,
1314
transport: http(),
14-
}).extend(arbOwnerPublicActions({ arbOSVersion: 11 }));
15+
}).extend(arbOwnerPublicActions({ arbOsVersion: 11 }));
1516
const client20 = createPublicClient({
1617
chain: nitroTestnodeL2,
1718
transport: http(),
18-
}).extend(arbOwnerPublicActions({ arbOSVersion: 20 }));
19+
}).extend(arbOwnerPublicActions({ arbOsVersion: 20 }));
20+
const randomAccount = privateKeyToAccount(generatePrivateKey());
21+
const upgradeExecutorAddress = '0x24198F8A339cd3C47AEa3A764A20d2dDaB4D1b5b';
1922

20-
it('Accept function name based on arbOSVersion', async () => {
21-
// Version 10
22-
client10.arbOwnerReadContract({
23-
functionName: 'onlyOnArbOS10',
24-
});
23+
describe('Accept function name based on arbOSVersion', async () => {
24+
it('Version 10', () => {
25+
expectTypeOf<typeof client10.arbOwnerReadContract<'onlyOnArbOS10'>>().toBeCallableWith({
26+
functionName: 'onlyOnArbOS10'
27+
})
2528

26-
expect(
27-
client10.arbOwnerReadContract({
28-
// @ts-expect-error Not available for version 10
29-
functionName: 'onlyOnArbOS20',
30-
}),
31-
).rejects.toThrowError(AbiFunctionNotFoundError);
29+
expectTypeOf<typeof client10.arbOwnerPrepareTransactionRequest<'setL1PricingRewardRecipient'>>().toBeCallableWith({
30+
functionName: 'setL1PricingRewardRecipient',
31+
account: randomAccount.address,
32+
upgradeExecutor: upgradeExecutorAddress,
33+
args: [[randomAccount.address, randomAccount.address]]
34+
})
3235

33-
// Version 11
34-
client11.arbOwnerReadContract({
35-
functionName: 'onlyOnArbOS11',
36-
});
36+
expect(
37+
client10.arbOwnerReadContract({
38+
// @ts-expect-error Not available for version 10
39+
functionName: 'onlyOnArbOS20',
40+
}),
41+
).rejects.toThrowError(AbiFunctionNotFoundError);
3742

38-
expect(
39-
client11.arbOwnerReadContract({
40-
// @ts-expect-error Not available for version 11
41-
functionName: 'onlyOnArbOS20',
42-
}),
43-
).rejects.toThrowError(AbiFunctionNotFoundError);
4443

45-
// Version 20
46-
client20.arbOwnerReadContract({
47-
functionName: 'getInfraFeeAccount',
48-
});
44+
})
4945

50-
expect(
51-
client20.arbOwnerReadContract({
52-
// @ts-expect-error Not available for version 20
53-
functionName: 'onlyOnArbOS10',
54-
}),
55-
).rejects.toThrowError(AbiFunctionNotFoundError);
46+
it('Version 11', () => {
47+
expectTypeOf<typeof client11.arbOwnerReadContract<'onlyOnArbOS11'>>().toBeCallableWith({
48+
functionName: 'onlyOnArbOS11'
49+
})
50+
51+
expectTypeOf<typeof client11.arbOwnerPrepareTransactionRequest<'setL1PricingRewardRecipient'>>().toBeCallableWith({
52+
functionName: 'setL1PricingRewardRecipient',
53+
account: randomAccount.address,
54+
upgradeExecutor: upgradeExecutorAddress,
55+
args: [100n]
56+
})
57+
58+
expect(
59+
client11.arbOwnerReadContract({
60+
// @ts-expect-error Not available for version 11
61+
functionName: 'onlyOnArbOS20',
62+
}),
63+
).rejects.toThrowError(AbiFunctionNotFoundError);
64+
})
65+
66+
it('Version 20', () => {
67+
expectTypeOf<typeof client20.arbOwnerReadContract<'getInfraFeeAccount'>>().toBeCallableWith({
68+
functionName: 'getInfraFeeAccount'
69+
})
70+
71+
expectTypeOf<typeof client20.arbOwnerPrepareTransactionRequest<'setL1PricingRewardRecipient'>>().toBeCallableWith({
72+
functionName: 'setL1PricingRewardRecipient',
73+
account: randomAccount.address,
74+
upgradeExecutor: upgradeExecutorAddress,
75+
args: [randomAccount.address]
76+
})
77+
78+
expect(
79+
client20.arbOwnerReadContract({
80+
// @ts-expect-error Not available for version 20
81+
functionName: 'onlyOnArbOS10',
82+
}),
83+
).rejects.toThrowError(AbiFunctionNotFoundError);
84+
})
5685
});
5786

5887
// Those tests won't fail if the return type is wrong
5988
// But they will display an error in the IDE
60-
it('Type return values for function in multiple versions', () => {
61-
// Version 10
62-
expectTypeOf(
63-
client10.arbOwnerReadContract({
64-
functionName: 'getAllChainOwners',
65-
}),
66-
).resolves.toEqualTypeOf<`0x${string}`>();
67-
68-
// Version 11
69-
expectTypeOf(
70-
client11.arbOwnerReadContract({
71-
functionName: 'getAllChainOwners',
72-
}),
73-
).resolves.toEqualTypeOf<bigint>();
89+
describe('Type return values for function in multiple versions', () => {
90+
it('Version 10', () => {
91+
expectTypeOf(
92+
client10.arbOwnerReadContract({
93+
functionName: 'getAllChainOwners',
94+
}),
95+
).resolves.toEqualTypeOf<`0x${string}`>();
96+
})
7497

75-
// Version 20
76-
expectTypeOf(
77-
client20.arbOwnerReadContract({
78-
functionName: 'getAllChainOwners',
79-
}),
80-
).resolves.toEqualTypeOf<readonly `0x${string}`[]>();
81-
});
98+
it('Version 11', () => {
99+
expectTypeOf(
100+
client11.arbOwnerReadContract({
101+
functionName: 'getAllChainOwners',
102+
}),
103+
).resolves.toEqualTypeOf<bigint>();
104+
})
105+
it('Version 11', () => {
106+
expectTypeOf(
107+
client20.arbOwnerReadContract({
108+
functionName: 'getAllChainOwners',
109+
}),
110+
).resolves.toEqualTypeOf<readonly `0x${string}`[]>();
111+
})
112+
});

0 commit comments

Comments
 (0)