Skip to content

Commit 626657e

Browse files
committed
fix: use getLogsSafe
1 parent c222bef commit 626657e

File tree

4 files changed

+133
-12
lines changed

4 files changed

+133
-12
lines changed

src/services/AddressProviderService.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import type { Address, NetworkType } from "@gearbox-protocol/sdk-gov";
22
import { ADDRESS_PROVIDER } from "@gearbox-protocol/sdk-gov";
33
import { iAddressProviderV3Abi } from "@gearbox-protocol/types/abi";
4-
import { getContract, hexToString, stringToHex } from "viem";
4+
import { getAbiItem, hexToString, stringToHex } from "viem";
55

66
import type { Config } from "../config/index.js";
77
import { DI } from "../di.js";
88
import { type ILogger, Logger } from "../log/index.js";
99
import { TxParser } from "../utils/ethers-6-temp/txparser/index.js";
10+
import { getLogsSafe } from "../utils/getLogsSafe.js";
1011
import type Client from "./Client.js";
1112

1213
const AP_SERVICES = [
@@ -49,19 +50,17 @@ export class AddressProviderService {
4950
? ` (overrides default ${ADDRESS_PROVIDER[this.config.network]})`
5051
: "";
5152

52-
const contract = getContract({
53+
const toBlock = await this.client.pub.getBlockNumber();
54+
55+
const logs = await getLogsSafe(this.client.pub, {
5356
address,
54-
abi: iAddressProviderV3Abi,
55-
client: this.client.pub,
57+
event: getAbiItem({ abi: iAddressProviderV3Abi, name: "SetAddress" }),
58+
args: { key: AP_SERVICES.map(s => stringToHex(s, { size: 32 })) },
59+
fromBlock: AP_BLOCK_BY_NETWORK[this.config.network],
60+
toBlock,
61+
strict: true,
5662
});
5763

58-
const logs = await contract.getEvents.SetAddress(
59-
{
60-
key: AP_SERVICES.map(s => stringToHex(s, { size: 32 })),
61-
},
62-
{ fromBlock: AP_BLOCK_BY_NETWORK[this.config.network], strict: true },
63-
);
64-
6564
for (const { args } of logs) {
6665
const { key, version, value } = args;
6766
const service = hexToString(key!, { size: 32 }) as AddressProviderKey;

src/services/OracleServiceV3.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { DI } from "../di.js";
1414
import type { ILogger } from "../log/index.js";
1515
import { Logger } from "../log/index.js";
1616
import { TxParser } from "../utils/ethers-6-temp/txparser/index.js";
17+
import { getLogsSafe } from "../utils/getLogsSafe.js";
1718
import type { AddressProviderService } from "./AddressProviderService.js";
1819
import type Client from "./Client.js";
1920

@@ -191,7 +192,7 @@ export default class OracleServiceV3 {
191192
return;
192193
}
193194
this.log.debug(`updating price feeds in [${this.#lastBlock}, ${toBlock}]`);
194-
let logs = await this.client.pub.getLogs({
195+
let logs = await getLogsSafe(this.client.pub, {
195196
address: this.oracle,
196197
events: iPriceOracleV3EventsAbi,
197198
fromBlock: BigInt(this.#lastBlock),

src/utils/getLogsSafe.ts

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import type { AbiEvent } from "abitype";
2+
import {
3+
type BlockNumber,
4+
type Chain,
5+
type Client,
6+
type GetLogsParameters,
7+
type GetLogsReturnType,
8+
HttpRequestError,
9+
type Transport,
10+
} from "viem";
11+
import { getLogs } from "viem/actions";
12+
13+
interface BlockRange {
14+
fromBlock: bigint;
15+
toBlock: bigint;
16+
}
17+
18+
export async function getLogsSafe<
19+
chain extends Chain | undefined,
20+
const abiEvent extends AbiEvent | undefined = undefined,
21+
const abiEvents extends
22+
| readonly AbiEvent[]
23+
| readonly unknown[]
24+
| undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,
25+
strict extends boolean | undefined = undefined,
26+
>(
27+
client: Client<Transport, chain>,
28+
params: GetLogsParameters<
29+
abiEvent,
30+
abiEvents,
31+
strict,
32+
BlockNumber,
33+
BlockNumber
34+
> = {},
35+
): Promise<
36+
GetLogsReturnType<abiEvent, abiEvents, strict, BlockNumber, BlockNumber>
37+
> {
38+
try {
39+
const events = await getLogs<
40+
chain,
41+
abiEvent,
42+
abiEvents,
43+
strict,
44+
BlockNumber,
45+
BlockNumber
46+
>(client, params);
47+
return events;
48+
} catch (e) {
49+
const fromBlock = params.fromBlock as bigint;
50+
const toBlock = params.toBlock as bigint;
51+
const bisected = tryBisectBlockRange({ fromBlock, toBlock }, e);
52+
if (!bisected) {
53+
throw e;
54+
}
55+
56+
const [left, right] = await Promise.all([
57+
getLogs(client, { ...params, ...bisected[0] } as any),
58+
getLogs(client, { ...params, ...bisected[1] } as any),
59+
]);
60+
return [...left, ...right] as GetLogsReturnType<
61+
abiEvent,
62+
abiEvents,
63+
strict,
64+
BlockNumber,
65+
BlockNumber
66+
>;
67+
}
68+
}
69+
70+
function tryBisectBlockRange(
71+
{ fromBlock, toBlock }: BlockRange,
72+
e: any,
73+
): [BlockRange, BlockRange] | undefined {
74+
const alchemyMid = checkForAlchemyBlockRange(e);
75+
if (alchemyMid && alchemyMid > fromBlock && alchemyMid < toBlock) {
76+
return [
77+
{ fromBlock, toBlock: alchemyMid },
78+
{ fromBlock: alchemyMid + 1n, toBlock },
79+
];
80+
}
81+
82+
const blockRangeErrors = [
83+
"query exceeds max block",
84+
"range is too large",
85+
"eth_getLogs is limited to",
86+
"eth_getLogs requests with up to",
87+
];
88+
89+
if (
90+
e instanceof Error &&
91+
blockRangeErrors.some(errorText => e.message.includes(errorText))
92+
) {
93+
const middle = (fromBlock + toBlock) / 2n;
94+
return [
95+
{ fromBlock, toBlock: middle },
96+
{ fromBlock: middle + 1n, toBlock },
97+
];
98+
}
99+
return undefined;
100+
}
101+
102+
const ALCHEMY_BLOCK_RANGE_REGEX =
103+
/this block range should work: \[(0x[0-9a-fA-F]+),\s*(0x[0-9a-fA-F]+)\]/;
104+
105+
function checkForAlchemyBlockRange(e: any): bigint | undefined {
106+
if (e instanceof HttpRequestError) {
107+
try {
108+
// exmple of alchemy error:
109+
// Details: {"code":-32600,"message":"You can make eth_getLogs requests with up to a 10000 block range. Based on your parameters, this block range should work: [0x9538b4, 0x955fc3]"}
110+
const err = JSON.parse(e.details);
111+
if (typeof err.message === "string") {
112+
const match = err.message.match(ALCHEMY_BLOCK_RANGE_REGEX);
113+
if (match) {
114+
return BigInt(match[2]);
115+
}
116+
}
117+
} catch {}
118+
}
119+
return undefined;
120+
}

src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from "./bigint-utils.js";
33
export * from "./detect-network.js";
44
export * from "./etherscan.js";
55
export * from "./formatters.js";
6+
export * from "./getLogsSafe.js";
67
export * from "./retry.js";
78
export * from "./simulateMulticall.js";
89
export * from "./types.js";

0 commit comments

Comments
 (0)