Skip to content

Commit 5d8e008

Browse files
feat: contract based binary search for call gas limit estimate (#214) (#217)
Co-authored-by: nikhilkumar1612 <[email protected]>
1 parent 44f7ef7 commit 5d8e008

File tree

21 files changed

+711
-64
lines changed

21 files changed

+711
-64
lines changed

lerna.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"packages/*"
44
],
55
"npmClient": "yarn",
6-
"version": "2.0.6",
6+
"version": "2.0.7",
77
"stream": "true",
88
"command": {
99
"version": {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "root",
33
"private": true,
4-
"version": "2.0.6",
4+
"version": "2.0.7",
55
"engines": {
66
"node": ">=18.0.0"
77
},

packages/api/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"publishConfig": {
55
"access": "public"
66
},
7-
"version": "2.0.6",
7+
"version": "2.0.7",
88
"description": "The API module of Etherspot bundler client",
99
"author": "Etherspot",
1010
"homepage": "https://https://github.com/etherspot/skandha#readme",
@@ -34,10 +34,10 @@
3434
"dependencies": {
3535
"@fastify/cors": "9.0.1",
3636
"@fastify/websocket": "10.0.1",
37-
"@skandha/executor": "^2.0.6",
38-
"@skandha/monitoring": "^2.0.6",
39-
"@skandha/types": "^2.0.6",
40-
"@skandha/utils": "^2.0.6",
37+
"@skandha/executor": "^2.0.7",
38+
"@skandha/monitoring": "^2.0.7",
39+
"@skandha/types": "^2.0.7",
40+
"@skandha/utils": "^2.0.7",
4141
"class-transformer": "0.5.1",
4242
"class-validator": "0.14.1",
4343
"ethers": "5.7.2",

packages/cli/package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"publishConfig": {
55
"access": "public"
66
},
7-
"version": "2.0.6",
7+
"version": "2.0.7",
88
"description": "> TODO: description",
99
"author": "zincoshine <[email protected]>",
1010
"homepage": "https://https://github.com/etherspot/skandha#readme",
@@ -40,12 +40,12 @@
4040
"@libp2p/peer-id-factory": "2.0.1",
4141
"@libp2p/prometheus-metrics": "1.1.3",
4242
"@multiformats/multiaddr": "12.1.3",
43-
"@skandha/api": "^2.0.6",
44-
"@skandha/db": "^2.0.6",
45-
"@skandha/executor": "^2.0.6",
46-
"@skandha/monitoring": "^2.0.6",
47-
"@skandha/node": "^2.0.6",
48-
"@skandha/types": "^2.0.6",
43+
"@skandha/api": "^2.0.7",
44+
"@skandha/db": "^2.0.7",
45+
"@skandha/executor": "^2.0.7",
46+
"@skandha/monitoring": "^2.0.7",
47+
"@skandha/node": "^2.0.7",
48+
"@skandha/types": "^2.0.7",
4949
"find-up": "5.0.0",
5050
"got": "12.5.3",
5151
"js-yaml": "4.1.0",

packages/db/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"publishConfig": {
55
"access": "public"
66
},
7-
"version": "2.0.6",
7+
"version": "2.0.7",
88
"description": "The DB module of Etherspot bundler client",
99
"author": "Etherspot",
1010
"homepage": "https://github.com/etherspot/etherspot-bundler#readme",
@@ -34,7 +34,7 @@
3434
"dependencies": {
3535
"@chainsafe/ssz": "0.10.1",
3636
"@farcaster/rocksdb": "5.5.0",
37-
"@skandha/types": "^2.0.6"
37+
"@skandha/types": "^2.0.7"
3838
},
3939
"devDependencies": {
4040
"@types/rocksdb": "3.0.1",

packages/executor/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"publishConfig": {
55
"access": "public"
66
},
7-
"version": "2.0.6",
7+
"version": "2.0.7",
88
"description": "The Relayer module of Etherspot bundler client",
99
"author": "Etherspot",
1010
"homepage": "https://https://github.com/etherspot/skandha#readme",
@@ -35,10 +35,10 @@
3535
},
3636
"dependencies": {
3737
"@flashbots/ethers-provider-bundle": "0.6.2",
38-
"@skandha/monitoring": "^2.0.6",
39-
"@skandha/params": "^2.0.6",
40-
"@skandha/types": "^2.0.6",
41-
"@skandha/utils": "^2.0.6",
38+
"@skandha/monitoring": "^2.0.7",
39+
"@skandha/params": "^2.0.7",
40+
"@skandha/types": "^2.0.7",
41+
"@skandha/utils": "^2.0.7",
4242
"async-mutex": "0.4.0",
4343
"ethers": "5.7.2",
4444
"strict-event-emitter-types": "2.0.0",

packages/executor/src/interfaces.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,8 @@ export interface KnownEntities {
253253
accounts: string[];
254254
otherEntities: string[];
255255
}
256+
257+
export interface ExecutionResultAndCallGasLimit {
258+
returnInfo: ExecutionResult;
259+
callGasLimit: BigNumber;
260+
}

packages/executor/src/modules/eth.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,15 @@ export class Eth {
177177
userOp.signature = ECDSA_DUMMY_SIGNATURE;
178178
}
179179

180-
const returnInfo = await this.userOpValidationService.validateForEstimation(
181-
userOp,
182-
entryPoint
183-
);
180+
// eslint-disable-next-line prefer-const
181+
let { returnInfo, callGasLimit } =
182+
await this.userOpValidationService.validateForEstimation(
183+
userOp,
184+
entryPoint
185+
);
184186

185187
// eslint-disable-next-line prefer-const
186-
let { preOpGas, validAfter, validUntil, paid } = returnInfo;
188+
let { preOpGas, validAfter, validUntil } = returnInfo;
187189

188190
const verificationGasLimit = BigNumber.from(preOpGas)
189191
.sub(userOp.preVerificationGas)
@@ -194,9 +196,7 @@ export class Eth {
194196

195197
// calculate callGasLimit based on paid fee
196198
const { cglMarkup } = this.config;
197-
const totalGas: BigNumber = BigNumber.from(paid).div(userOp.maxFeePerGas);
198-
let callGasLimit = totalGas
199-
.sub(preOpGas)
199+
callGasLimit = callGasLimit
200200
.mul(10000 + this.config.cglMarkupPercent)
201201
.div(10000) // % markup
202202
.add(cglMarkup || 0);

packages/executor/src/services/EntryPointService/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ export const DefaultGasOverheads = {
77
bundleSize: 1,
88
sigSize: 65,
99
};
10+
11+
export const IMPLEMENTATION_ADDRESS_MARKER = "0xA13dB4eCfbce0586E57D1AeE224FbE64706E8cd3";

packages/executor/src/services/EntryPointService/utils/decodeRevertReason.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,23 @@ export function decodeRevertReason(
6363
}
6464
}
6565

66+
export function decodeTargetData(data: string) {
67+
try {
68+
const methodSig = data.slice(0, 10);
69+
const dataParams = "0x" + data.slice(10);
70+
if(methodSig === "0x8c83589a") {
71+
const res = ethers.utils.defaultAbiCoder.decode(
72+
["uint256", "uint256"],
73+
dataParams
74+
);
75+
return res;
76+
}
77+
throw Error("Error decoding target data");
78+
} catch (error) {
79+
throw error;
80+
}
81+
}
82+
6683
// not sure why ethers fail to decode revert reasons, not even "Error()" (and obviously, not custom errors)
6784
export function rethrowWithRevertReason(e: Error): never {
6885
throw new Error(decodeRevertReason(e, false) as any);

packages/executor/src/services/EntryPointService/versions/0.0.7.ts

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ import {
2323
UserOperationByHashResponse,
2424
} from "@skandha/types/lib/api/interfaces";
2525
import { deepHexlify } from "@skandha/utils/lib/hexlify";
26+
import {
27+
CallGasEstimationProxy__factory,
28+
_deployedBytecode as _callGasEstimationProxyDeployedBytecode,
29+
} from "@skandha/types/lib/contracts/EPv7/factories/core/CallGasEstimationProxy__factory";
30+
import { CallGasEstimationProxy } from "@skandha/types/lib/contracts/EPv7/core/CallGasEstimationProxy";
2631
import {
2732
encodeUserOp,
2833
mergeValidationDataValues,
@@ -35,13 +40,20 @@ import {
3540
StakeInfo,
3641
UserOpValidationResult,
3742
} from "../../../interfaces";
38-
import { DefaultGasOverheads } from "../constants";
43+
import {
44+
DefaultGasOverheads,
45+
IMPLEMENTATION_ADDRESS_MARKER,
46+
} from "../constants";
3947
import { StateOverrides } from "../interfaces";
40-
import { decodeRevertReason } from "../utils/decodeRevertReason";
48+
import {
49+
decodeRevertReason,
50+
decodeTargetData,
51+
} from "../utils/decodeRevertReason";
4152
import { getUserOpGasLimit } from "../../BundlingService/utils";
4253
import { IEntryPointService } from "./base";
4354

4455
const entryPointSimulations = IEntryPointSimulations__factory.createInterface();
56+
const callGasEstimateProxy = CallGasEstimationProxy__factory.createInterface();
4557

4658
export class EntryPointV7Service implements IEntryPointService {
4759
contract: EntryPoint;
@@ -71,10 +83,21 @@ export class EntryPointV7Service implements IEntryPointService {
7183
)
7284
: undefined;
7385

74-
const [data, stateOverrides] = this.encodeSimulateHandleOp(
86+
const estimateCallGasArgs: CallGasEstimationProxy.EstimateCallGasArgsStruct =
87+
{
88+
userOp: packUserOp(userOp),
89+
isContinuation: true,
90+
maxGas: "20000000",
91+
minGas: "21000",
92+
rounding: "500",
93+
};
94+
95+
const [data] = this.encodeSimulateHandleOp(
7596
userOp,
76-
AddressZero,
77-
BytesZero
97+
this.address,
98+
callGasEstimateProxy.encodeFunctionData("estimateCallGas", [
99+
estimateCallGasArgs,
100+
])
78101
);
79102

80103
const tx: providers.TransactionRequest = {
@@ -83,6 +106,15 @@ export class EntryPointV7Service implements IEntryPointService {
83106
gasLimit,
84107
};
85108

109+
const stateOverrides: StateOverrides = {
110+
[this.address]: {
111+
code: _callGasEstimationProxyDeployedBytecode,
112+
},
113+
[IMPLEMENTATION_ADDRESS_MARKER]: {
114+
code: _deployedBytecode,
115+
},
116+
};
117+
86118
try {
87119
const simulationResult = await this.provider.send("eth_call", [
88120
tx,
@@ -93,7 +125,8 @@ export class EntryPointV7Service implements IEntryPointService {
93125
"simulateHandleOp",
94126
simulationResult
95127
);
96-
return res[0];
128+
const [callGasLimit] = decodeTargetData(res[0].targetResult);
129+
return { returnInfo: res[0], callGasLimit: callGasLimit };
97130
} catch (error: any) {
98131
console.log(error);
99132
const err = decodeRevertReason(error);

packages/executor/src/services/UserOpValidation/service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { UserOperation } from "@skandha/types/lib/contracts/UserOperation";
66
import { Config } from "../../config";
77
import {
88
ExecutionResult,
9+
ExecutionResultAndCallGasLimit,
910
NetworkConfig,
1011
UserOpValidationResult,
1112
} from "../../interfaces";
@@ -62,7 +63,7 @@ export class UserOpValidationService {
6263
async validateForEstimation(
6364
userOp: UserOperation,
6465
entryPoint: string
65-
): Promise<ExecutionResult> {
66+
): Promise<ExecutionResultAndCallGasLimit> {
6667
return await this.estimationService.estimateUserOp(userOp, entryPoint);
6768
}
6869

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { providers } from "ethers";
22
import { Logger } from "@skandha/types/lib";
33
import { UserOperation } from "@skandha/types/lib/contracts/UserOperation";
4-
import { ExecutionResult } from "../../../interfaces";
4+
import { ExecutionResultAndCallGasLimit } from "../../../interfaces";
55
import { EntryPointService } from "../../EntryPointService";
66
import { mergeValidationDataValues } from "../../EntryPointService/utils";
77

@@ -15,22 +15,23 @@ export class EstimationService {
1515
async estimateUserOp(
1616
userOp: UserOperation,
1717
entryPoint: string
18-
): Promise<ExecutionResult> {
19-
const returnInfo = await this.entryPointService.simulateHandleOp(
20-
entryPoint,
21-
userOp
22-
);
18+
): Promise<ExecutionResultAndCallGasLimit> {
19+
const { returnInfo, callGasLimit } =
20+
await this.entryPointService.simulateHandleOp(entryPoint, userOp);
2321
const { validAfter, validUntil } = mergeValidationDataValues(
2422
returnInfo.accountValidationData,
2523
returnInfo.paymasterValidationData
2624
);
2725
return {
28-
preOpGas: returnInfo.preOpGas,
29-
paid: returnInfo.paid,
30-
validAfter: validAfter,
31-
validUntil: validUntil,
32-
targetSuccess: returnInfo.targetSuccess,
33-
targetResult: returnInfo.targetResult,
26+
returnInfo: {
27+
preOpGas: returnInfo.preOpGas,
28+
paid: returnInfo.paid,
29+
validAfter: validAfter,
30+
validUntil: validUntil,
31+
targetSuccess: returnInfo.targetSuccess,
32+
targetResult: returnInfo.targetResult,
33+
},
34+
callGasLimit,
3435
};
3536
}
3637
}

packages/monitoring/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"publishConfig": {
55
"access": "public"
66
},
7-
"version": "2.0.6",
7+
"version": "2.0.7",
88
"description": "The Monitoring module of Etherspot bundler client",
99
"author": "Etherspot",
1010
"homepage": "https://github.com/etherspot/etherspot-bundler#readme",
@@ -32,7 +32,7 @@
3232
"check-readme": "typescript-docs-verifier"
3333
},
3434
"dependencies": {
35-
"@skandha/types": "^2.0.6",
35+
"@skandha/types": "^2.0.7",
3636
"prom-client": "15.1.0"
3737
}
3838
}

packages/node/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"publishConfig": {
55
"access": "public"
66
},
7-
"version": "2.0.6",
7+
"version": "2.0.7",
88
"description": "The bundler node module of Etherspot bundler client",
99
"author": "Etherspot",
1010
"homepage": "https://https://github.com/etherspot/skandha#readme",
@@ -56,13 +56,13 @@
5656
"@libp2p/prometheus-metrics": "1.1.3",
5757
"@libp2p/tcp": "6.1.0",
5858
"@multiformats/multiaddr": "11.4.0",
59-
"@skandha/api": "^2.0.6",
60-
"@skandha/db": "^2.0.6",
61-
"@skandha/executor": "^2.0.6",
62-
"@skandha/monitoring": "^2.0.6",
63-
"@skandha/params": "^2.0.6",
64-
"@skandha/types": "^2.0.6",
65-
"@skandha/utils": "^2.0.6",
59+
"@skandha/api": "^2.0.7",
60+
"@skandha/db": "^2.0.7",
61+
"@skandha/executor": "^2.0.7",
62+
"@skandha/monitoring": "^2.0.7",
63+
"@skandha/params": "^2.0.7",
64+
"@skandha/types": "^2.0.7",
65+
"@skandha/utils": "^2.0.7",
6666
"abstract-leveldown": "7.2.0",
6767
"datastore-core": "8.0.1",
6868
"ethers": "5.7.2",

packages/params/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"publishConfig": {
55
"access": "public"
66
},
7-
"version": "2.0.6",
7+
"version": "2.0.7",
88
"description": "Various bundler parameters",
99
"author": "Etherspot",
1010
"homepage": "https://github.com/etherspot/skandha#readme",
@@ -28,8 +28,8 @@
2828
"@arbitrum/sdk": "3.1.4",
2929
"@chainsafe/ssz": "0.10.1",
3030
"@mantleio/sdk": "0.2.1",
31-
"@skandha/types": "^2.0.6",
32-
"@skandha/utils": "^2.0.6",
31+
"@skandha/types": "^2.0.7",
32+
"@skandha/utils": "^2.0.7",
3333
"ethers": "5.7.2"
3434
},
3535
"scripts": {

0 commit comments

Comments
 (0)