Skip to content
This repository was archived by the owner on Feb 20, 2025. It is now read-only.

Commit ecaa42d

Browse files
authored
Merge pull request #81 from api3dao/arbitrum-block-number-hot-fix
Fetches block number using dedicated RPC call only for Airbitrum
2 parents dd1c753 + 93863ba commit ecaa42d

File tree

5 files changed

+76
-28
lines changed

5 files changed

+76
-28
lines changed

scripts/fund.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ async function main() {
3333
return;
3434
}
3535

36-
await fundChainRecipients(chainConfig, merkleFunderContract);
36+
await fundChainRecipients(chainId, chainConfig, merkleFunderContract);
3737
}
3838

3939
main()

src/handler.test.ts

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ describe('run', () => {
4545
expect(fundChainRecipients).toHaveBeenCalledTimes(2);
4646
expect(fundChainRecipients).toHaveBeenNthCalledWith(
4747
1,
48+
'31337',
4849
expect.anything(),
4950
expect.objectContaining({
5051
address: merkleFunderContractAddress,
@@ -57,6 +58,7 @@ describe('run', () => {
5758
);
5859
expect(fundChainRecipients).toHaveBeenNthCalledWith(
5960
2,
61+
'31337',
6062
expect.anything(),
6163
expect.objectContaining({
6264
address: merkleFunderContractAddress,

src/handler.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const run: ScheduledHandler = async (_event: ScheduledEvent, _context: Co
3030
console.log(`Funding recipients on chain with ID: ${chainId} using provider: ${providerName}`);
3131

3232
const merkleFunderContract = getMerkleFunderContract(funderMnemonic, provider.url, chainId);
33-
await fundChainRecipients(chainConfig, merkleFunderContract);
33+
await fundChainRecipients(chainId, chainConfig, merkleFunderContract);
3434
})
3535
)
3636
);

src/merkle-funder.test.ts

+50-16
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,11 @@ describe('fundChainRecipients', () => {
117117
// Capture console.log outputs
118118
const consoleLogSpy = jest.spyOn(console, 'log');
119119

120-
await fundChainRecipients({ options, merkleFunderDepositories }, mockContract as unknown as ethers.Contract);
120+
await fundChainRecipients(
121+
'31337',
122+
{ options, merkleFunderDepositories },
123+
mockContract as unknown as ethers.Contract
124+
);
121125

122126
expect(buildMerkleTree).toHaveBeenCalledTimes(1);
123127
expect(buildMerkleTree).toHaveBeenCalledWith(values);
@@ -132,13 +136,18 @@ describe('fundChainRecipients', () => {
132136
[owner, treeRoot, proof2, values[1].recipient, ethers.utils.parseEther('5'), ethers.utils.parseEther('15')]
133137
);
134138
const [, ...multicallCalldata] = staticMulticallCalldata;
135-
expect(consoleLogSpy).toHaveBeenCalledWith('Expected number of calldatas to be sent: ', multicallCalldata.length);
139+
expect(consoleLogSpy).toHaveBeenCalledWith(
140+
'Expected number of calldatas to be sent: ',
141+
multicallCalldata.length,
142+
'31337'
143+
);
136144
expect(mockContractCallStaticTryMulticall).toHaveBeenCalledWith(staticMulticallCalldata);
137145
expect(consoleLogSpy).not.toHaveBeenCalledWith(
138146
`Failed to call merkleFunderContract.callStatic.tryMulticall:`,
139-
expect.any(String)
147+
expect.any(String),
148+
'31337'
140149
);
141-
expect(consoleLogSpy).toHaveBeenCalledWith('Block number:', '10');
150+
expect(consoleLogSpy).toHaveBeenCalledWith('Block number:', '10', '31337');
142151
expect(consoleLogSpy).not.toHaveBeenCalledWith('Failded to fetch block number:', expect.any(String));
143152
expect(consoleLogSpy).not.toHaveBeenCalledWith(
144153
`Calldata #${1} reverted with message:`,
@@ -157,7 +166,8 @@ describe('fundChainRecipients', () => {
157166
expect.any(String)
158167
);
159168
expect(consoleLogSpy).toHaveBeenCalledWith(
160-
`Sent tx with hash ${tryMulticallResult.hash} that will send funds to ${multicallCalldata.length} recipients`
169+
`Sent tx with hash ${tryMulticallResult.hash} that will send funds to ${multicallCalldata.length} recipients`,
170+
'31337'
161171
);
162172
expect(consoleLogSpy).not.toHaveBeenCalledWith('All recipients are already funded');
163173
});
@@ -250,7 +260,11 @@ describe('fundChainRecipients', () => {
250260
// Capture console.log outputs
251261
const consoleLogSpy = jest.spyOn(console, 'log');
252262

253-
await fundChainRecipients({ options, merkleFunderDepositories }, mockContract as unknown as ethers.Contract);
263+
await fundChainRecipients(
264+
'31337',
265+
{ options, merkleFunderDepositories },
266+
mockContract as unknown as ethers.Contract
267+
);
254268

255269
expect(buildMerkleTree).toHaveBeenCalledTimes(1);
256270
expect(buildMerkleTree).toHaveBeenCalledWith(values);
@@ -265,21 +279,31 @@ describe('fundChainRecipients', () => {
265279
[owner, treeRoot, proof2, values[1].recipient, ethers.utils.parseEther('5'), ethers.utils.parseEther('15')]
266280
);
267281
const [, ...multicallCalldata] = staticMulticallCalldata;
268-
expect(consoleLogSpy).toHaveBeenCalledWith('Expected number of calldatas to be sent: ', multicallCalldata.length);
282+
expect(consoleLogSpy).toHaveBeenCalledWith(
283+
'Expected number of calldatas to be sent: ',
284+
multicallCalldata.length,
285+
'31337'
286+
);
269287
expect(mockContractCallStaticTryMulticall).toHaveBeenCalledWith(staticMulticallCalldata);
270-
expect(consoleLogSpy).toHaveBeenCalledWith('Block number:', '10');
271-
expect(consoleLogSpy).not.toHaveBeenCalledWith('Failded to fetch block number:', expect.any(String));
272-
expect(consoleLogSpy).toHaveBeenCalledWith(`Calldata #${1} reverted with message:`, 'mocked-revert-string');
288+
expect(consoleLogSpy).toHaveBeenCalledWith('Block number:', '10', '31337');
289+
expect(consoleLogSpy).not.toHaveBeenCalledWith('Failded to fetch block number:', expect.any(String), '31337');
290+
expect(consoleLogSpy).toHaveBeenCalledWith(
291+
`Calldata #${1} reverted with message:`,
292+
'mocked-revert-string',
293+
'31337'
294+
);
273295
expect(mockGetTransactionCount).toHaveBeenCalledTimes(1);
274296
expect(getGasPriceMock).toHaveBeenCalledTimes(1);
275297
expect(consoleLogSpy).toHaveBeenCalledWith('mocked-get-gas-price-message');
276298
expect(mockContractTryMulticall).toHaveBeenCalledWith([staticMulticallCalldata[2]], expect.anything());
277299
expect(consoleLogSpy).not.toHaveBeenCalledWith(
278300
`Failed to call merkleFunderContract.tryMulticall:`,
279-
expect.any(String)
301+
expect.any(String),
302+
'31337'
280303
);
281304
expect(consoleLogSpy).toHaveBeenCalledWith(
282-
`Sent tx with hash ${tryMulticallResult.hash} that will send funds to 1 recipients`
305+
`Sent tx with hash ${tryMulticallResult.hash} that will send funds to 1 recipients`,
306+
'31337'
283307
);
284308
expect(consoleLogSpy).not.toHaveBeenCalledWith('All recipients are already funded');
285309
});
@@ -357,7 +381,11 @@ describe('fundChainRecipients', () => {
357381
// Capture console.log outputs
358382
const consoleLogSpy = jest.spyOn(console, 'log');
359383

360-
await fundChainRecipients({ options, merkleFunderDepositories }, mockContract as unknown as ethers.Contract);
384+
await fundChainRecipients(
385+
'31337',
386+
{ options, merkleFunderDepositories },
387+
mockContract as unknown as ethers.Contract
388+
);
361389

362390
expect(buildMerkleTree).toHaveBeenCalledTimes(1);
363391
expect(buildMerkleTree).toHaveBeenCalledWith(values);
@@ -367,19 +395,25 @@ describe('fundChainRecipients', () => {
367395
[owner, treeRoot, proof1, values[0].recipient, ethers.utils.parseEther('10'), ethers.utils.parseEther('20')]
368396
);
369397
const [, ...multicallCalldata] = staticMulticallCalldata;
370-
expect(consoleLogSpy).toHaveBeenCalledWith('Expected number of calldatas to be sent: ', multicallCalldata.length);
398+
expect(consoleLogSpy).toHaveBeenCalledWith(
399+
'Expected number of calldatas to be sent: ',
400+
multicallCalldata.length,
401+
'31337'
402+
);
371403
expect(mockContractCallStaticTryMulticall).toHaveBeenCalledWith(staticMulticallCalldata);
372404
expect(consoleLogSpy).not.toHaveBeenCalledWith(
373405
`Failed to call merkleFunderContract.callStatic.tryMulticall:`,
374-
expect.any(String)
406+
expect.any(String),
407+
'31337'
375408
);
376409
expect(mockGetTransactionCount).toHaveBeenCalledTimes(1);
377410
expect(getGasPriceMock).toHaveBeenCalledTimes(1);
378411
expect(consoleLogSpy).toHaveBeenCalledWith('mocked-get-gas-price-message');
379412
expect(mockContractTryMulticall).toHaveBeenCalledWith(multicallCalldata, expect.anything());
380413
expect(consoleLogSpy).toHaveBeenCalledWith(
381414
'Failed to call merkleFunderContract.tryMulticall:',
382-
'mocked-error-message'
415+
'mocked-error-message',
416+
'31337'
383417
);
384418
});
385419
});

src/merkle-funder.ts

+22-10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import buildMerkleTree from './merkle-tree';
66
import { ChainConfig } from './types';
77

88
export const fundChainRecipients = async (
9+
chainId: string,
910
chainConfig: Pick<ChainConfig, 'options' | 'merkleFunderDepositories'>,
1011
merkleFunderContract: ethers.Contract
1112
) => {
@@ -27,15 +28,16 @@ export const fundChainRecipients = async (
2728
ethers.utils.parseUnits(highThreshold.value.toString(), highThreshold.unit),
2829
])
2930
);
30-
console.log('Expected number of calldatas to be sent: ', multicallCalldata.length);
31+
console.log('Expected number of calldatas to be sent: ', multicallCalldata.length, chainId);
3132

3233
const tryStaticMulticallResult = await go(() =>
3334
merkleFunderContract.callStatic.tryMulticall([getBlockNumberCalldata, ...multicallCalldata])
3435
);
3536
if (!tryStaticMulticallResult.success) {
3637
console.log(
3738
'Failed to call merkleFunderContract.callStatic.tryMulticall:',
38-
tryStaticMulticallResult.error.message
39+
tryStaticMulticallResult.error.message,
40+
chainId
3941
);
4042
continue;
4143
}
@@ -47,27 +49,36 @@ export const fundChainRecipients = async (
4749

4850
// Get block number to use as argument when fetching the transaction count
4951
if (!getBlockNumberSuccess) {
50-
console.log('Failded to fetch block number:', decodeRevertString(getBlockNumberReturndata));
52+
console.log('Failded to fetch block number:', decodeRevertString(getBlockNumberReturndata), chainId);
5153
continue;
5254
}
5355
const blockNumber = ethers.BigNumber.from(getBlockNumberReturndata);
54-
console.log('Block number:', blockNumber.toString());
56+
console.log('Block number:', blockNumber.toString(), chainId);
5557

5658
// Filter out calldata that failed to be sent
5759
const successfulMulticallCalldata = (remainingSuccesses as boolean[]).reduce((acc, success, index) => {
5860
if (!success) {
59-
console.log(`Calldata #${index + 1} reverted with message:`, decodeRevertString(remainingRetunrdata[index]));
61+
console.log(
62+
`Calldata #${index + 1} reverted with message:`,
63+
decodeRevertString(remainingRetunrdata[index]),
64+
chainId
65+
);
6066
return acc;
6167
}
6268
return [...acc, multicallCalldata[index]];
6369
}, [] as string[]);
6470

6571
// Try to send the calldatas
6672
// TODO: A potential improvement here is to batch these calls
67-
console.log('Actual number of calldatas to be sent: ', successfulMulticallCalldata.length);
73+
console.log('Actual number of calldatas to be sent: ', successfulMulticallCalldata.length, chainId);
6874
if (successfulMulticallCalldata.length > 0) {
69-
nonce = nonce ?? (await merkleFunderContract.signer.getTransactionCount(blockNumber.toNumber()));
70-
console.log('Nonce:', nonce);
75+
nonce =
76+
nonce ??
77+
(await merkleFunderContract.signer.getTransactionCount(
78+
// HACK: Arbitrum returns the L1 block number so we need to fetch the L2 block number via provider RPC call
79+
chainId === '42161' ? await merkleFunderContract.provider.getBlockNumber() : blockNumber.toNumber()
80+
));
81+
console.log('Nonce:', nonce, chainId);
7182

7283
// Get the latest gas price
7384
const [logs, gasTarget] = await getGasPrice(merkleFunderContract.provider, chainConfig.options);
@@ -78,11 +89,12 @@ export const fundChainRecipients = async (
7889
merkleFunderContract.tryMulticall(successfulMulticallCalldata, { nonce, ...gasTarget })
7990
);
8091
if (!tryMulticallResult.success) {
81-
console.log('Failed to call merkleFunderContract.tryMulticall:', tryMulticallResult.error.message);
92+
console.log('Failed to call merkleFunderContract.tryMulticall:', tryMulticallResult.error.message, chainId);
8293
continue;
8394
}
8495
console.log(
85-
`Sent tx with hash ${tryMulticallResult.data.hash} that will send funds to ${successfulMulticallCalldata.length} recipients`
96+
`Sent tx with hash ${tryMulticallResult.data.hash} that will send funds to ${successfulMulticallCalldata.length} recipients`,
97+
chainId
8698
);
8799
nonce++;
88100
}

0 commit comments

Comments
 (0)