From 2288d73152e24e60cacc7feb6fe2ca61b4810ad2 Mon Sep 17 00:00:00 2001 From: marie-fourier Date: Thu, 19 Sep 2024 14:08:16 +0500 Subject: [PATCH 1/2] feat: blockscout integration --- packages/executor/src/config.ts | 17 +++ packages/executor/src/interfaces.ts | 2 + packages/executor/src/modules/eth.ts | 16 +++ packages/executor/src/modules/skandha.ts | 2 + packages/types/src/api/interfaces.ts | 2 + packages/utils/src/index.ts | 1 + packages/utils/src/third-party/blockscout.ts | 136 +++++++++++++++++++ packages/utils/src/third-party/index.ts | 1 + 8 files changed, 177 insertions(+) create mode 100644 packages/utils/src/third-party/blockscout.ts create mode 100644 packages/utils/src/third-party/index.ts diff --git a/packages/executor/src/config.ts b/packages/executor/src/config.ts index b39cbfef..73286547 100644 --- a/packages/executor/src/config.ts +++ b/packages/executor/src/config.ts @@ -329,6 +329,21 @@ export class Config { ) ); + config.blockscoutUrl = String( + fromEnvVar( + "BLOCKSCOUT_URL", + config.blockscoutUrl || bundlerDefaultConfigs.blockscoutUrl + ) + ); + + config.blockscoutApiKeys = fromEnvVar( + "BLOCKSCOUT_API_KEYS", + config.blockscoutApiKeys != undefined + ? config.blockscoutApiKeys + : bundlerDefaultConfigs.blockscoutApiKeys, + true + ) as string[]; + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (!config.whitelistedEntities) { config.whitelistedEntities = bundlerDefaultConfigs.whitelistedEntities; @@ -401,6 +416,8 @@ const bundlerDefaultConfigs: BundlerConfig = { echoAuthKey: "", archiveDuration: 24 * 3600, fastlaneValidators: [], + blockscoutUrl: "", + blockscoutApiKeys: [], }; function getEnvVar(envVar: string, fallback: T): T | string { diff --git a/packages/executor/src/interfaces.ts b/packages/executor/src/interfaces.ts index 1ae4b3fd..71916287 100644 --- a/packages/executor/src/interfaces.ts +++ b/packages/executor/src/interfaces.ts @@ -174,6 +174,8 @@ export interface NetworkConfig { // default: 24 hours archiveDuration: number; fastlaneValidators: string[]; + blockscoutUrl: string; + blockscoutApiKeys: string[]; } export type BundlerConfig = Omit< diff --git a/packages/executor/src/modules/eth.ts b/packages/executor/src/modules/eth.ts index 3e63d993..9785ab6c 100644 --- a/packages/executor/src/modules/eth.ts +++ b/packages/executor/src/modules/eth.ts @@ -24,6 +24,7 @@ import { import { Logger } from "@skandha/types/lib"; import { PerChainMetrics } from "@skandha/monitoring/lib"; import { deepHexlify } from "@skandha/utils/lib/hexlify"; +import { BlockscoutAPI } from "@skandha/utils/lib/third-party"; import { packUserOp } from "../utils"; import { UserOpValidationService, MempoolService } from "../services"; import { GetNodeAPI, Log, NetworkConfig } from "../interfaces"; @@ -36,6 +37,7 @@ import { Skandha } from "./skandha"; export class Eth { private pvgEstimator: IPVGEstimator | null = null; + private blockscoutApi: BlockscoutAPI | null = null; constructor( private chainId: number, @@ -62,6 +64,15 @@ export class Eth { if ([5000, 5001, 5003].includes(this.chainId)) { this.pvgEstimator = estimateMantlePVG(this.provider); } + + if (this.config.blockscoutUrl) { + this.blockscoutApi = new BlockscoutAPI( + this.provider, + this.logger, + this.config.blockscoutUrl, + this.config.blockscoutApiKeys + ); + } } /** @@ -340,6 +351,8 @@ export class Eth { } const [entryPoint, event] = await this.getUserOperationEvent(hash); if (!entryPoint || !event) { + if (this.blockscoutApi) + return await this.blockscoutApi.getUserOperationByHash(hash); return null; } const tx = await event.getTransaction(); @@ -405,6 +418,8 @@ export class Eth { ): Promise { const [entryPoint, event] = await this.getUserOperationEvent(hash); if (!event || !entryPoint) { + if (this.blockscoutApi) + return await this.blockscoutApi.getUserOperationReceipt(hash); return null; } const receipt = await event.getTransactionReceipt(); @@ -531,6 +546,7 @@ export class Eth { ); } } + return [null, null]; } diff --git a/packages/executor/src/modules/skandha.ts b/packages/executor/src/modules/skandha.ts index 4b8b7f78..f123b6e6 100644 --- a/packages/executor/src/modules/skandha.ts +++ b/packages/executor/src/modules/skandha.ts @@ -168,6 +168,8 @@ export class Skandha { pvgMarkupPercent: this.networkConfig.pvgMarkupPercent, cglMarkupPercent: this.networkConfig.cglMarkupPercent, vglMarkupPercent: this.networkConfig.vglMarkupPercent, + blockscoutUrl: this.networkConfig.blockscoutUrl, + blockscoutApiKeys: this.networkConfig.blockscoutApiKeys.length, }; } diff --git a/packages/types/src/api/interfaces.ts b/packages/types/src/api/interfaces.ts index 662837ca..8cbb132d 100644 --- a/packages/types/src/api/interfaces.ts +++ b/packages/types/src/api/interfaces.ts @@ -99,6 +99,8 @@ export type GetConfigResponse = { pvgMarkupPercent: number; cglMarkupPercent: number; vglMarkupPercent: number; + blockscoutUrl: string; + blockscoutApiKeys: number; }; export type SupportedEntryPoints = string[]; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 8526b2e9..0a53dacd 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -7,3 +7,4 @@ export * from "./errors"; export * from "./shuffle"; export * from "./sortBy"; export * from "./timeout"; +export * from "./third-party"; diff --git a/packages/utils/src/third-party/blockscout.ts b/packages/utils/src/third-party/blockscout.ts new file mode 100644 index 00000000..d0bb6a34 --- /dev/null +++ b/packages/utils/src/third-party/blockscout.ts @@ -0,0 +1,136 @@ +import { providers } from "ethers"; +import { + UserOperationByHashResponse, + UserOperationReceipt, +} from "@skandha/types/lib/api/interfaces"; +import { Logger } from "@skandha/types/lib"; +import { deepHexlify } from "../hexlify"; + +export class BlockscoutAPI { + private currentKeyIndex: number; + + constructor( + private provider: providers.JsonRpcProvider, + private logger: Logger, + private baseUrl: string, + private apiKeys: string[] + ) { + this.currentKeyIndex = 0; + } + + private getNextApiKey(): string { + if (this.apiKeys.length === 0) { + return ""; + } + this.currentKeyIndex = (this.currentKeyIndex + 1) % this.apiKeys.length; + return this.apiKeys[this.currentKeyIndex]; + } + + private async fetchUserOpByHash( + hash: string + ): Promise { + const apiKey = this.getNextApiKey(); + let url = `${this.baseUrl}/api/v2/proxy/account-abstraction/operations/${hash}`; + if (apiKey) { + url += `?apikey=${apiKey}`; + } + try { + const response = await fetch(url); + const data: UserOperationResponse = await response.json(); + + // userop not found + if (!data.entry_point_version) return null; + + return data; + } catch (err) { + return null; + } + } + + async getUserOperationReceipt( + hash: string + ): Promise { + this.logger.debug("Blockscout: getUserOperationReceipt"); + const data = await this.fetchUserOpByHash(hash); + if (!data) { + return null; + } + const receipt = await this.provider.getTransactionReceipt( + data.transaction_hash + ); + return deepHexlify({ + userOpHash: hash, + sender: data.raw.sender, + nonce: data.raw.nonce, + actualGasCost: data.fee, + actualGasUsed: data.gas_used, + success: data.revert_reason == null, + logs: receipt.logs, + receipt, + }); + } + + async getUserOperationByHash( + hash: string + ): Promise { + this.logger.debug("Blockscout: getUserOperationByHash"); + const data = await this.fetchUserOpByHash(hash); + if (!data) { + return null; + } + const { + raw, + transaction_hash: transactionHash, + entry_point: { hash: entryPoint }, + block_number: blockNumber, + block_hash: blockHash, + } = data; + + return deepHexlify({ + userOperation: { + sender: raw.sender, + nonce: raw.nonce, + initCode: raw.init_code, + callData: raw.call_data, + callGasLimit: raw.call_gas_limit, + verificationGasLimit: raw.verification_gas_limit, + preVerificationGas: raw.pre_verification_gas, + maxFeePerGas: raw.max_fee_per_gas, + maxPriorityFeePerGas: raw.max_priority_fee_per_gas, + paymasterAndData: raw.paymaster_and_data, + signature: raw.signature, + }, + entryPoint, + transactionHash, + blockHash, + blockNumber, + }); + } +} + +type UserOperationResponse = { + entry_point_version: string; + transaction_hash: string; + hash: string; + block_number: string; + block_hash: string; + raw: { + call_data: string; + call_gas_limit: string; + init_code: string; + max_fee_per_gas: string; + max_priority_fee_per_gas: string; + nonce: string; + paymaster_and_data: string; + pre_verification_gas: string; + sender: string; + signature: string; + verification_gas_limit: string; + }; + entry_point: { + hash: string; + }; + fee: string; // actualGasCost + gas_used: string; // actualGasUsed + revert_reason: string | null; +}; diff --git a/packages/utils/src/third-party/index.ts b/packages/utils/src/third-party/index.ts new file mode 100644 index 00000000..20a4c1cf --- /dev/null +++ b/packages/utils/src/third-party/index.ts @@ -0,0 +1 @@ +export * from "./blockscout"; From c84bd227355000d0607959b97793b301c5e03f04 Mon Sep 17 00:00:00 2001 From: marie-fourier Date: Thu, 19 Sep 2024 14:08:35 +0500 Subject: [PATCH 2/2] chore(release): v1.5.25 --- lerna.json | 2 +- package.json | 2 +- packages/api/package.json | 10 +++++----- packages/cli/package.json | 14 +++++++------- packages/contracts/package.json | 2 +- packages/db/package.json | 4 ++-- packages/executor/package.json | 10 +++++----- packages/monitoring/package.json | 4 ++-- packages/node/package.json | 16 ++++++++-------- packages/params/package.json | 6 +++--- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- 12 files changed, 38 insertions(+), 38 deletions(-) diff --git a/lerna.json b/lerna.json index 91d192e2..2eeb1e88 100644 --- a/lerna.json +++ b/lerna.json @@ -3,7 +3,7 @@ "packages/*" ], "npmClient": "yarn", - "version": "1.5.24", + "version": "1.5.25", "stream": "true", "command": { "version": { diff --git a/package.json b/package.json index 8149ade1..aec533aa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "root", "private": true, - "version": "1.5.24", + "version": "1.5.25", "engines": { "node": ">=18.0.0" }, diff --git a/packages/api/package.json b/packages/api/package.json index c97fc348..7d51d0d4 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -4,7 +4,7 @@ "publishConfig": { "access": "public" }, - "version": "1.5.24", + "version": "1.5.25", "description": "The API module of Etherspot bundler client", "author": "Etherspot", "homepage": "https://https://github.com/etherspot/skandha#readme", @@ -34,10 +34,10 @@ "dependencies": { "@fastify/cors": "9.0.1", "@fastify/websocket": "10.0.1", - "@skandha/executor": "^1.5.24", - "@skandha/monitoring": "^1.5.24", - "@skandha/types": "^1.5.24", - "@skandha/utils": "^1.5.24", + "@skandha/executor": "^1.5.25", + "@skandha/monitoring": "^1.5.25", + "@skandha/types": "^1.5.25", + "@skandha/utils": "^1.5.25", "class-transformer": "0.5.1", "class-validator": "0.14.1", "ethers": "5.7.2", diff --git a/packages/cli/package.json b/packages/cli/package.json index b24008d8..00cf008b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -4,7 +4,7 @@ "publishConfig": { "access": "public" }, - "version": "1.5.24", + "version": "1.5.25", "description": "> TODO: description", "author": "zincoshine ", "homepage": "https://https://github.com/etherspot/skandha#readme", @@ -40,12 +40,12 @@ "@libp2p/peer-id-factory": "2.0.1", "@libp2p/prometheus-metrics": "1.1.3", "@multiformats/multiaddr": "12.1.3", - "@skandha/api": "^1.5.24", - "@skandha/db": "^1.5.24", - "@skandha/executor": "^1.5.24", - "@skandha/monitoring": "^1.5.24", - "@skandha/node": "^1.5.24", - "@skandha/types": "^1.5.24", + "@skandha/api": "^1.5.25", + "@skandha/db": "^1.5.25", + "@skandha/executor": "^1.5.25", + "@skandha/monitoring": "^1.5.25", + "@skandha/node": "^1.5.25", + "@skandha/types": "^1.5.25", "find-up": "5.0.0", "got": "12.5.3", "js-yaml": "4.1.0", diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 2dec069d..84c638b5 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -4,7 +4,7 @@ "publishConfig": { "access": "public" }, - "version": "1.5.24", + "version": "1.5.25", "description": "Smart contracts of Etherspot bundler client", "author": "Etherspot", "homepage": "https://https://github.com/etherspot/skandha#readme", diff --git a/packages/db/package.json b/packages/db/package.json index 599694b6..dccd3f68 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -4,7 +4,7 @@ "publishConfig": { "access": "public" }, - "version": "1.5.24", + "version": "1.5.25", "description": "The DB module of Etherspot bundler client", "author": "Etherspot", "homepage": "https://github.com/etherspot/etherspot-bundler#readme", @@ -34,7 +34,7 @@ "dependencies": { "@chainsafe/ssz": "0.10.1", "@farcaster/rocksdb": "5.5.0", - "@skandha/types": "^1.5.24" + "@skandha/types": "^1.5.25" }, "devDependencies": { "@types/rocksdb": "3.0.1", diff --git a/packages/executor/package.json b/packages/executor/package.json index 92b9b156..38d4de78 100644 --- a/packages/executor/package.json +++ b/packages/executor/package.json @@ -4,7 +4,7 @@ "publishConfig": { "access": "public" }, - "version": "1.5.24", + "version": "1.5.25", "description": "The Relayer module of Etherspot bundler client", "author": "Etherspot", "homepage": "https://https://github.com/etherspot/skandha#readme", @@ -35,10 +35,10 @@ }, "dependencies": { "@flashbots/ethers-provider-bundle": "0.6.2", - "@skandha/monitoring": "^1.5.24", - "@skandha/params": "^1.5.24", - "@skandha/types": "^1.5.24", - "@skandha/utils": "^1.5.24", + "@skandha/monitoring": "^1.5.25", + "@skandha/params": "^1.5.25", + "@skandha/types": "^1.5.25", + "@skandha/utils": "^1.5.25", "async-mutex": "0.4.0", "ethers": "5.7.2", "strict-event-emitter-types": "2.0.0", diff --git a/packages/monitoring/package.json b/packages/monitoring/package.json index bd4b8446..617b413d 100644 --- a/packages/monitoring/package.json +++ b/packages/monitoring/package.json @@ -4,7 +4,7 @@ "publishConfig": { "access": "public" }, - "version": "1.5.24", + "version": "1.5.25", "description": "The Monitoring module of Etherspot bundler client", "author": "Etherspot", "homepage": "https://github.com/etherspot/etherspot-bundler#readme", @@ -32,7 +32,7 @@ "check-readme": "typescript-docs-verifier" }, "dependencies": { - "@skandha/types": "^1.5.24", + "@skandha/types": "^1.5.25", "prom-client": "^14.2.0" } } diff --git a/packages/node/package.json b/packages/node/package.json index 679d30ea..5ca244aa 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -4,7 +4,7 @@ "publishConfig": { "access": "public" }, - "version": "1.5.24", + "version": "1.5.25", "description": "The bundler node module of Etherspot bundler client", "author": "Etherspot", "homepage": "https://https://github.com/etherspot/skandha#readme", @@ -56,13 +56,13 @@ "@libp2p/prometheus-metrics": "1.1.3", "@libp2p/tcp": "6.1.0", "@multiformats/multiaddr": "11.4.0", - "@skandha/api": "^1.5.24", - "@skandha/db": "^1.5.24", - "@skandha/executor": "^1.5.24", - "@skandha/monitoring": "^1.5.24", - "@skandha/params": "^1.5.24", - "@skandha/types": "^1.5.24", - "@skandha/utils": "^1.5.24", + "@skandha/api": "^1.5.25", + "@skandha/db": "^1.5.25", + "@skandha/executor": "^1.5.25", + "@skandha/monitoring": "^1.5.25", + "@skandha/params": "^1.5.25", + "@skandha/types": "^1.5.25", + "@skandha/utils": "^1.5.25", "@types/varint": "6.0.1", "abstract-leveldown": "7.2.0", "datastore-core": "8.0.1", diff --git a/packages/params/package.json b/packages/params/package.json index 94d8e363..0156fc18 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -4,7 +4,7 @@ "publishConfig": { "access": "public" }, - "version": "1.5.24", + "version": "1.5.25", "description": "Various bundler parameters", "author": "Etherspot", "homepage": "https://github.com/etherspot/skandha#readme", @@ -28,8 +28,8 @@ "@arbitrum/sdk": "3.1.4", "@chainsafe/ssz": "0.10.1", "@mantleio/sdk": "0.2.1", - "@skandha/types": "^1.5.24", - "@skandha/utils": "^1.5.24", + "@skandha/types": "^1.5.25", + "@skandha/utils": "^1.5.25", "ethers": "5.7.2" }, "scripts": { diff --git a/packages/types/package.json b/packages/types/package.json index 7ccb2828..65d7733e 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -4,7 +4,7 @@ "publishConfig": { "access": "public" }, - "version": "1.5.24", + "version": "1.5.25", "description": "The types of Etherspot bundler client", "author": "Etherspot", "homepage": "https://https://github.com/etherspot/skandha#readme", diff --git a/packages/utils/package.json b/packages/utils/package.json index 7ff42c8c..5c0fe301 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -4,7 +4,7 @@ "publishConfig": { "access": "public" }, - "version": "1.5.24", + "version": "1.5.25", "description": "utils of Etherspot bundler client", "author": "Etherspot", "homepage": "https://https://github.com/etherspot/skandha#readme", @@ -33,7 +33,7 @@ }, "dependencies": { "@chainsafe/as-sha256": "0.3.1", - "@skandha/types": "^1.5.24", + "@skandha/types": "^1.5.25", "any-signal": "3.0.1", "bigint-buffer": "1.1.5", "case": "^1.6.3",