|
1 | 1 | import { join } from "node:path"; |
2 | 2 | import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; |
3 | | -import { type EthCallRequest, EthCallSpy } from "@gearbox-protocol/sdk/dev"; |
| 3 | +import { |
| 4 | + type DetectedCall, |
| 5 | + type EthCallRequest, |
| 6 | + EthCallSpy, |
| 7 | +} from "@gearbox-protocol/sdk/dev"; |
| 8 | +import { |
| 9 | + decodeFunctionResult, |
| 10 | + multicall3Abi, |
| 11 | + parseAbi, |
| 12 | + type RequiredBy, |
| 13 | +} from "viem"; |
4 | 14 | import type { Config } from "./config/index.js"; |
5 | 15 | import { DI } from "./di.js"; |
6 | | -import { type ILogger, Logger } from "./log/index.js"; |
| 16 | +import type { ILogger } from "./log/index.js"; |
| 17 | + |
| 18 | +const multicallTimestampAbi = parseAbi([ |
| 19 | + "function getCurrentBlockTimestamp() public view returns (uint256 timestamp)", |
| 20 | + "function getBlockNumber() public view returns (uint256 blockNumber)", |
| 21 | +]); |
| 22 | + |
| 23 | +interface SpiedCall extends DetectedCall { |
| 24 | + multicall: { |
| 25 | + blockNumber: string; |
| 26 | + timestamp: string; |
| 27 | + }; |
| 28 | +} |
7 | 29 |
|
8 | 30 | /** |
9 | 31 | * This is temporary solution to diagnose bug where compressor occasionally returns many accounts with HF = 0 |
10 | 32 | */ |
11 | 33 | @DI.Injectable(DI.MulticallSpy) |
12 | | -export default class MulticallSpy { |
13 | | - @Logger("MulticallSpy") |
14 | | - log!: ILogger; |
15 | | - |
16 | | - @DI.Inject(DI.Config) |
17 | | - config!: Config; |
18 | | - |
19 | | - public readonly spy: EthCallSpy; |
| 34 | +export default class MulticallSpy extends EthCallSpy<SpiedCall> { |
20 | 35 | #client = new S3Client({}); |
| 36 | + #log: ILogger; |
| 37 | + #config: Config; |
21 | 38 |
|
22 | 39 | constructor() { |
23 | | - this.spy = new EthCallSpy( |
| 40 | + const log = DI.create(DI.Logger, "MulticallSpy"); |
| 41 | + const config = DI.get(DI.Config); |
| 42 | + super( |
24 | 43 | isGetCreditAccountsMulticall, |
25 | | - this.log, |
26 | | - this.config.debugScanner && !this.config.optimistic, |
| 44 | + log, |
| 45 | + config.debugScanner && !config.optimistic, |
27 | 46 | ); |
| 47 | + this.#log = log; |
| 48 | + this.#config = config; |
28 | 49 | } |
29 | 50 |
|
30 | 51 | public async dumpCalls(): Promise<void> { |
31 | | - if (!this.config.outS3Bucket) { |
32 | | - this.log.error("outS3Bucket is not set"); |
| 52 | + if (!this.#config.outS3Bucket) { |
| 53 | + this.#log.error("outS3Bucket is not set"); |
33 | 54 | return; |
34 | 55 | } |
35 | 56 | const key = join( |
36 | | - this.config.outS3Prefix, |
37 | | - `getCreditAccounts_${this.spy.detectedBlock}.json`, |
| 57 | + this.#config.outS3Prefix, |
| 58 | + this.#config.network, |
| 59 | + `getCreditAccounts_${this.detectedBlock}.json`, |
38 | 60 | ); |
39 | | - const s3Url = `s3://${this.config.outS3Bucket}/${key}`; |
| 61 | + const s3Url = `s3://${this.#config.outS3Bucket}/${key}`; |
40 | 62 | try { |
41 | | - this.log.debug(`uploading to ${s3Url}`); |
| 63 | + this.#log.debug(`uploading to ${s3Url}`); |
42 | 64 | await this.#client.send( |
43 | 65 | new PutObjectCommand({ |
44 | | - Bucket: this.config.outS3Bucket, |
| 66 | + Bucket: this.#config.outS3Bucket, |
45 | 67 | Key: key, |
46 | 68 | ContentType: "application/json", |
47 | | - Body: JSON.stringify(this.spy.detectedCalls), |
| 69 | + Body: JSON.stringify(this.detectedCalls), |
48 | 70 | }), |
49 | 71 | ); |
50 | | - this.log.debug(`uploaded to ${s3Url}`); |
| 72 | + this.#log.debug(`uploaded to ${s3Url}`); |
51 | 73 | } catch (e) { |
52 | | - this.log.error(e, `failed to upload to ${s3Url}`); |
| 74 | + this.#log.error(e, `failed to upload to ${s3Url}`); |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + protected override storeResponse( |
| 79 | + call: RequiredBy<SpiedCall, "response" | "responseHeaders">, |
| 80 | + ): void | Promise<void> { |
| 81 | + super.storeResponse(call); |
| 82 | + const result = call.response.result; |
| 83 | + if (result) { |
| 84 | + try { |
| 85 | + const res = decodeFunctionResult({ |
| 86 | + abi: multicall3Abi, |
| 87 | + data: result, |
| 88 | + functionName: "aggregate3", |
| 89 | + }); |
| 90 | + const [timestampEnc, blockNumberEnc] = res; |
| 91 | + const timestamp = decodeFunctionResult({ |
| 92 | + abi: multicallTimestampAbi, |
| 93 | + data: timestampEnc.returnData, |
| 94 | + functionName: "getCurrentBlockTimestamp", |
| 95 | + }); |
| 96 | + const blockNumber = decodeFunctionResult({ |
| 97 | + abi: multicallTimestampAbi, |
| 98 | + data: blockNumberEnc.returnData, |
| 99 | + functionName: "getBlockNumber", |
| 100 | + }); |
| 101 | + call.multicall = { |
| 102 | + blockNumber: blockNumber.toString(), |
| 103 | + timestamp: timestamp.toString(), |
| 104 | + }; |
| 105 | + } catch (e) { |
| 106 | + this.#log.error(`failed to parse multicall response: ${e}`); |
| 107 | + } |
53 | 108 | } |
54 | 109 | } |
55 | 110 | } |
|
0 commit comments