eth-infinitism / bundler Goto Github PK
View Code? Open in Web Editor NEWLicense: GNU General Public License v3.0
License: GNU General Public License v3.0
I used the main code branch, which was successfully deployed on the server, but when using nohub and running in the background, it automatically stopped running within an hour. What is the reason for this?
When trying to execute changing recipient state, UserOperation does not succeed.
How to reproduce:
The index
property on the SimpleAccountApiParams
interface is the salt used by the SimpleAccountFactory
contract when it creates a new account. This is of type uint256
so can be way larger than JS's number
type. I'd suggest changing this type to BigNumberish
.
export interface SimpleAccountApiParams extends BaseApiParams {
owner: Signer
factoryAddress?: string
index?: number
}
The constructor on the SimpleAccountAPI
class would then look like
constructor (params: SimpleAccountApiParams) {
super(params)
this.factoryAddress = params.factoryAddress
this.owner = params.owner
this.index = BigNumber.from(params.index ?? 0)
}
Node v18.15.0
yarn preprocess
yarn run v1.22.19
$ yarn lerna-clear && yarn hardhat-compile && yarn lerna-tsc
$ lerna run clear
lerna notice cli v5.6.2
lerna info Executing command in 3 packages: "yarn run clear"
lerna info run Ran npm script 'clear' in '@account-abstraction/utils' in 0.2s:
$ rm -rf dist artifacts cache src/types
lerna info run Ran npm script 'clear' in '@account-abstraction/sdk' in 0.1s:
$ rm -rf dist artifacts cache
lerna info run Ran npm script 'clear' in '@account-abstraction/bundler' in 0.1s:
$ rm -rf dist artifacts cache src/types
lerna success run Ran npm script 'clear' in 3 packages in 0.5s:
lerna success - @account-abstraction/bundler
lerna success - @account-abstraction/sdk
lerna success - @account-abstraction/utils
$ lerna run hardhat-compile
lerna notice cli v5.6.2
lerna info Executing command in 2 packages: "yarn run hardhat-compile"
lerna info run Ran npm script 'hardhat-compile' in '@account-abstraction/utils' in 1.8s:
$ hardhat compile
Generating typings for: 19 artifacts in dir: src/types for target: ethers-v5
Successfully generated 60 typings!
Compiled 20 Solidity files successfully
lerna info run Ran npm script 'hardhat-compile' in '@account-abstraction/bundler' in 3.8s:
$ hardhat compile
Generating typings for: 39 artifacts in dir: src/types for target: ethers-v5
Successfully generated 112 typings!
Compiled 34 Solidity files successfully
lerna success run Ran npm script 'hardhat-compile' in 2 packages in 5.6s:
lerna success - @account-abstraction/bundler
lerna success - @account-abstraction/utils
$ lerna run tsc --scope @account-abstraction/*
lerna notice cli v5.6.2
lerna notice filter including "@account-abstraction/"
lerna info filter [ '@account-abstraction/' ]
lerna info Executing command in 3 packages: "yarn run tsc"
lerna ERR! yarn run tsc exited 2 in '@account-abstraction/utils'
lerna ERR! yarn run tsc stdout:
$ tsc
../../node_modules/@types/node/globals.d.ts(47,11): error TS2300: Duplicate identifier 'AbortController'.
../../node_modules/@types/node/globals.d.ts(60,11): error TS2300: Duplicate identifier 'AbortSignal'.
../../node_modules/@types/node/globals.d.ts(67,13): error TS2300: Duplicate identifier 'AbortController'.
../../node_modules/@types/node/globals.d.ts(74,13): error TS2300: Duplicate identifier 'AbortSignal'.
../../node_modules/typescript/lib/lib.dom.d.ts(2042,11): error TS2300: Duplicate identifier 'AbortController'.
../../node_modules/typescript/lib/lib.dom.d.ts(2049,13): error TS2300: Duplicate identifier 'AbortController'.
../../node_modules/typescript/lib/lib.dom.d.ts(2059,11): error TS2300: Duplicate identifier 'AbortSignal'.
../../node_modules/typescript/lib/lib.dom.d.ts(2071,13): error TS2300: Duplicate identifier 'AbortSignal'.
../../node_modules/typescript/lib/lib.dom.d.ts(5562,11): error TS2300: Duplicate identifier 'FormData'.
../../node_modules/typescript/lib/lib.dom.d.ts(5572,13): error TS2300: Duplicate identifier 'FormData'.
../../node_modules/typescript/lib/lib.dom.d.ts(14499,11): error TS2300: Duplicate identifier 'URL'.
../../node_modules/typescript/lib/lib.dom.d.ts(14516,13): error TS2300: Duplicate identifier 'URL'.
../../node_modules/typescript/lib/lib.dom.d.ts(14526,11): error TS2300: Duplicate identifier 'URLSearchParams'.
../../node_modules/typescript/lib/lib.dom.d.ts(14545,13): error TS2300: Duplicate identifier 'URLSearchParams'.
../../node_modules/typescript/lib/lib.dom.d.ts(18345,6): error TS2300: Duplicate identifier 'RequestInfo'.
../../node_modules/typescript/lib/lib.dom.d.ts(18505,6): error TS2300: Duplicate identifier 'XMLHttpRequestResponseType'.
../../node_modules/typescript/lib/lib.dom.iterable.d.ts(86,11): error TS2300: Duplicate identifier 'FormData'.
../../node_modules/typescript/lib/lib.dom.iterable.d.ts(263,11): error TS2300: Duplicate identifier 'URLSearchParams'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(69,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'Blob' must be of type '{ new (blobParts?: BlobPart[] | undefined, options?: BlobPropertyBag | undefined): Blob; prototype: Blob; }', but here has type '{ new (blobParts?: (string | Blob)[] | undefined, options?: BlobOptions | undefined): Blob; prototype: Blob; }'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(88,15): error TS2300: Duplicate identifier 'FormData'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(112,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'Headers' must be of type '{ new (init?: HeadersInit | undefined): Headers; prototype: Headers; }', but here has type '{ new (init?: HeadersInit_ | undefined): Headers; prototype: Headers; }'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(146,3): error TS2717: Subsequent property declarations must have the same type. Property 'body' must be of type 'BodyInit | null | undefined', but here has type 'BodyInit_ | undefined'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(148,3): error TS2717: Subsequent property declarations must have the same type. Property 'headers' must be of type 'HeadersInit | undefined', but here has type 'HeadersInit_ | undefined'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(154,3): error TS2717: Subsequent property declarations must have the same type. Property 'window' must be of type 'null | undefined', but here has type 'any'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(155,3): error TS2717: Subsequent property declarations must have the same type. Property 'signal' must be of type 'AbortSignal | null | undefined', but here has type 'AbortSignal | undefined'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(168,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'Request' must be of type '{ new (input: URL | RequestInfo, init?: RequestInit | undefined): Request; prototype: Request; }', but here has type '{ new (input: string | Request, init?: RequestInit | undefined): Request; prototype: Request; }'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(173,14): error TS2300: Duplicate identifier 'RequestInfo'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(176,3): error TS2717: Subsequent property declarations must have the same type. Property 'headers' must be of type 'HeadersInit | undefined', but here has type 'HeadersInit_ | undefined'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(192,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'Response' must be of type '{ new (body?: BodyInit | null | undefined, init?: ResponseInit | undefined): Response; prototype: Response; error(): Response; redirect(url: string | URL, status?: number | undefined): Response; }', but here has type '{ new (body?: BodyInit_ | undefined, init?: ResponseInit | undefined): Response; prototype: Response; error: () => Response; redirect: (url: string, status?: number | undefined) => Response; }'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(282,3): error TS2717: Subsequent property declarations must have the same type. Property 'abort' must be of type 'ProgressEvent', but here has type 'ProgressEvent'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(283,3): error TS2717: Subsequent property declarations must have the same type. Property 'error' must be of type 'ProgressEvent', but here has type 'ProgressEvent'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(284,3): error TS2717: Subsequent property declarations must have the same type. Property 'load' must be of type 'ProgressEvent', but here has type 'ProgressEvent'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(285,3): error TS2717: Subsequent property declarations must have the same type. Property 'loadend' must be of type 'ProgressEvent', but here has type 'ProgressEvent'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(286,3): error TS2717: Subsequent property declarations must have the same type. Property 'loadstart' must be of type 'ProgressEvent', but here has type 'ProgressEvent'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(287,3): error TS2717: Subsequent property declarations must have the same type. Property 'progress' must be of type 'ProgressEvent', but here has type 'ProgressEvent'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(288,3): error TS2717: Subsequent property declarations must have the same type. Property 'timeout' must be of type 'ProgressEvent', but here has type 'ProgressEvent'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(341,14): error TS2300: Duplicate identifier 'XMLHttpRequestResponseType'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(354,15): error TS2300: Duplicate identifier 'URL'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(379,15): error TS2300: Duplicate identifier 'URLSearchParams'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(437,3): error TS2717: Subsequent property declarations must have the same type. Property 'onopen' must be of type '((this: WebSocket, ev: Event) => any) | null', but here has type '(() => void) | null'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(438,3): error TS2717: Subsequent property declarations must have the same type. Property 'onmessage' must be of type '((this: WebSocket, ev: MessageEvent) => any) | null', but here has type '((event: WebSocketMessageEvent) => void) | null'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(439,3): error TS2717: Subsequent property declarations must have the same type. Property 'onerror' must be of type '((this: WebSocket, ev: Event) => any) | null', but here has type '((event: WebSocketErrorEvent) => void) | null'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(440,3): error TS2717: Subsequent property declarations must have the same type. Property 'onclose' must be of type '((this: WebSocket, ev: CloseEvent) => any) | null', but here has type '((event: WebSocketCloseEvent) => void) | null'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(441,3): error TS2717: Subsequent property declarations must have the same type. Property 'addEventListener' must be of type '{ (type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | ... 1 more ... | undefined): void; }', but here has type 'WebsocketEventListener'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(442,3): error TS2717: Subsequent property declarations must have the same type. Property 'removeEventListener' must be of type '{ (type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void; (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | ... 1 more ... | undefined): void; }', but here has type 'WebsocketEventListener'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(445,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'WebSocket' must be of type '{ new (url: string | URL, protocols?: string | string[] | undefined): WebSocket; prototype: WebSocket; readonly CLOSED: number; readonly CLOSING: number; readonly CONNECTING: number; readonly OPEN: number; }', but here has type '{ new (uri: string, protocols?: string | string[] | null | undefined, options?: { [optionName: string]: any; headers: { [headerName: string]: string; }; } | null | undefined): WebSocket; ... 4 more ...; readonly OPEN: number; }'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(469,15): error TS2300: Duplicate identifier 'AbortSignal'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(469,15): error TS2420: Class 'AbortSignal' incorrectly implements interface 'EventTarget'.
Property 'dispatchEvent' is missing in type 'AbortSignal' but required in type 'EventTarget'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(504,15): error TS2300: Duplicate identifier 'AbortController'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(529,12): error TS2717: Subsequent property declarations must have the same type. Property 'error' must be of type 'DOMException | null', but here has type 'Error | null'.
../../../../../node_modules/@types/react-native/modules/globals.d.ts(539,12): error TS2717: Subsequent property declarations must have the same type. Property 'result' must be of type 'string | ArrayBuffer | null', but here has type 'string | ArrayBuffer'.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
lerna ERR! yarn run tsc stderr:
error Command failed with exit code 2.
lerna ERR! yarn run tsc exited 2 in '@account-abstraction/utils'
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
When running the docker-compose in dockers/test, the bundle container fails to run with the error below.
$ ./aabundler-launcher.sh start
Creating network "geth-dev_default" with the default driver
Pulling bundler (accountabstraction/bundler:)...
latest: Pulling from accountabstraction/bundler
5b18dd3a8fc6: Pull complete
a28de039d9b6: Pull complete
a67a939353a3: Pull complete
ddfb18524a5c: Pull complete
b2a0178bf962: Pull complete
64e388ab7361: Pull complete
8eb8d57ab568: Pull complete
d751ba846103: Pull complete
bd0a59e111d6: Pull complete
Digest: sha256:aaa655ac2f486b6fc1ffad6eb2de420786fb086a85fa87a152292b6e394cb451
Status: Downloaded newer image for accountabstraction/bundler:latest
Building geth-dev
[+] Building 2.4s (5/5) FINISHED docker:default
=> [internal] load .dockerignore 0.2s
=> => transferring context: 2B 0.0s
=> [internal] load build definition from Dockerfile 0.2s
=> => transferring dockerfile: 474B 0.0s
=> [internal] load metadata for docker.io/ethereum/client-go:release-1.10 2.0s
=> CACHED [1/1] FROM docker.io/ethereum/client-go:release-1.10@sha256:03604c12f6123fda67f534c9a68a73dbabd35d5c0a13f0c6cfcf735cfd8760c8 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:1a8e603dfe59386bb1a289c4e223e44984ff2b87aaf0e4057f43b91b7e350d16 0.0s
=> => naming to docker.io/library/geth-dev_geth-dev 0.0s
WARNING: Image for service geth-dev was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating geth-dev_bundler_1 ... done
Creating geth-dev_geth-dev_1 ... done
At this point, in other console:
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
029c9231641f geth-dev_geth-dev "/bin/sh -c 'geth โฆ" About a minute ago Up About a minute 8546/tcp, 0.0.0.0:8545->8545/tcp, :::8545->8545/tcp, 30303/tcp, 30303/udp geth-dev_geth-dev_1
d6abd4af1fd2 accountabstraction/bundler "/app/bundler.sh --nโฆ" About a minute ago Exited (1) About a minute ago geth-dev_bundler_1
$ docker logs d6abd4af1fd2
exec /app/bundler.sh: exec format error
In my case I was able to workaround the problem by changing the bundler image, locally building one with this change in file: dockers/bundler/bundler/sh
:
#!/bin/sh
-exec node `dirname $0`/bundler.js "$@"
+node `dirname $0`/bundler.js "$@"
accountabstraction/bundler latest 9841ce9e49d2 5 months ago 194MB
Hi there,
I was testing my custom paymaster with bundler in order to make it compatible with EIP-4337 spec. I found that when the context data (returning from _validatePaymasterUserOp
) encodes more than one field, the bundler would encounter BUFFER_OVERRUN
error.
Here is the minimum paymaster to reproduce this problem:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
import { BasePaymaster } from "@account-abstraction/contracts/core/BasePaymaster.sol";
import { IEntryPoint } from "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import { UserOperation } from "@account-abstraction/contracts/interfaces/UserOperation.sol";
contract Paymaster is BasePaymaster {
constructor(IEntryPoint _entryPoint) BasePaymaster(_entryPoint) {}
function _validatePaymasterUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) internal override returns (bytes memory context, uint256 validationData) {
(userOp, userOpHash, maxCost);
// This is ok
// context = abi.encode(userOp.sender);
// This causes the error
context = abi.encode(userOp.sender, userOp.nonce);
}
function _postOp(
PostOpMode mode,
bytes calldata context,
uint256 actualGasCost
) internal override {
(mode, context, actualGasCost);
}
}
And this paymaster will cause error in bundler side (in safe mode) when simulating validation:
failed: eth_sendUserOperation error: {"message":"data out-of-bounds (length=79, offset=96, code=BUFFER_OVERRUN, version=abi/
5.7.0)","code":"BUFFER_OVERRUN"}
After investigating, I found the problem is due to this line:
The slicing restricts data in the trace step to 1000 in length at most. When paymaster encodes multiple data into the context, it would cause the revert data (revert ValidationResult(...)) length exceed 1000, and bundler would accidentally trim the data to fit that size, finally causing BUFFER_OVERRUN
error when parsing the validation result at this line:
bundler/packages/bundler/src/modules/ValidationManager.ts
Lines 130 to 133 in 6353ca1
After I removed the data slicing in my local bundler, it did fix the problem. I'm wondering if there is any reason to restrict the data length in the trace step? Thanks.
import { ethers } from 'ethers'
import { SimpleAccountAPI,DeterministicDeployer } from '../src'
import { wrapProvider } from '@account-abstraction/sdk'
import { SampleRecipient__factory } from '@account-abstraction/utils'
import {IEntryPoint, SimpleAccountFactory__factory } from '@account-abstraction/contracts'
const abi=require('./abi')
const {HttpRpcClient,sendUserOpToBundler}=require("../src/HttpRpcClient")
const {ExecutionManager}=require('../../bundler/src/modules/ExecutionManager')
const { UserOpMethodHandler } =require('../../bundler/src/UserOpMethodHandler')
const { BundlerReputationParams, ReputationManager } =require( '../../bundler/src/modules/ReputationManager')
const { MempoolManager }= require( '../../bundler/src/modules/MempoolManager')
import { EntryPoint, EntryPoint__factory } from '@account-abstraction/contracts'
const { BundlerConfig } = require('../../bundler/src/BundlerConfig')
import { ValidationManager ,supportsDebugTraceCall} from '@account-abstraction/validation-manager'
const { BundleManager } =require('../../bundler/src/modules/BundleManager')
import {IEntryPoint__factory } from '@account-abstraction/utils'
import { parseEther } from 'ethers/lib/utils'
const { createSigner } =require('../../bundler/test/testUtils')
describe('SimpleAccountAPI', () => {
let provider = new ethers.providers.JsonRpcProvider("https://polygon-mumbai.g.alchemy.com/v2/HncKchA59IsmRnWlOMaNq3YYSCp5DIr0");
const private_key = "7a8daa8561f32e139966ac8d35359af89be277c8707aa630ce71f24bfa8c2fee"
const signer = new ethers.Wallet(private_key, provider)
let op:any;
const entryPointAddress = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"
let factoryAddress:any;
let recipient:any;
let entryPoint:IEntryPoint
let config:any;
it('deploying', async () => {
recipient = await new SampleRecipient__factory(signer).deploy()
console.log("rec", recipient.address);
DeterministicDeployer.init(provider)
factoryAddress = await DeterministicDeployer.deploy(new SimpleAccountFactory__factory(), 0, [entryPointAddress])
console.log(factoryAddress)
entryPoint = IEntryPoint__factory.connect(entryPointAddress, provider)
})
it("userop creation",async function(){
const api = new SimpleAccountAPI({
provider,
entryPointAddress,
owner: signer,
factoryAddress
})
op = await api.createSignedUserOp({
target: recipient.address,
data: recipient.interface.encodeFunctionData('something', ['hello']),
gasLimit: 1e6
})
console.log(op)
})
it('send to bundler',async function(){
const config = {
chainId: await provider.getNetwork().then(net => net.chainId),
entryPointAddress,
bundlerUrl: 'http://localhost:3000/rpc'
}
const httpRpcClient = new HttpRpcClient(config.bundlerUrl, config.entryPointAddress, config.chainId)
const resp= await httpRpcClient.sendUserOpToBundler(op);
console.log("response",resp)
})
it ("send userop to mempool or attempt to bundle",async function() {
config = {
beneficiary: await signer.getAddress(),
entryPoint: entryPointAddress,
gasFactor: '0.2',
minBalance: '0',
mnemonic: '',
network: '',
port: '3000',
unsafe: !await supportsDebugTraceCall(provider as any),
autoBundleInterval: 0,
autoBundleMempoolSize: 0,
maxBundleGas: 5e6,
// minstake zero, since we don't fund deployer.
minStake: '0',
minUnstakeDelay: 0
}
// const unsafe =!await supportsDebugTraceCall(provider as any)
const repMgr = new ReputationManager(provider, BundlerReputationParams, parseEther(config.minStake), config.minUnstakeDelay)
const mempoolMgr = new MempoolManager(repMgr)
const validMgr = new ValidationManager(entryPoint ,config.unsafe)
const Bundlemngr = new BundleManager(entryPointAddress, mempoolMgr, validMgr, repMgr, config.beneficiary, parseEther(config.minBalance), config.maxBundleGas)
// console.log("bu",Bundlemngr);
const executionmanager=new ExecutionManager(mempoolMgr,Bundlemngr,validMgr);
// const bundlerSigner = await createSigner()
const _entryPoint = entryPoint.connect(signer)
const methodHandler = new UserOpMethodHandler(
executionmanager,
provider,
signer,
config,
_entryPoint
)
const a= await methodHandler.sendUserOperation(op, entryPointAddress)
console.log("send userop", a)
})
// })
when running const a= await methodHandler.sendUserOperation(op, entryPointAddress) this error occured: TypeError: Cannot read properties of undefined (reading 'validateInputParameters')
Im trying to run yarn run runop --deployFactory --network http://localhost:8545/ --entryPoint 0x0000000071727De22E5E9d8BAf0edAc6f37da032
using hardhat node, Im already running the bundler with yarn run bundler --unsafe
, with a successful response:
command-line arguments: {
config: './localconfig/bundler.config.json',
auto: false,
unsafe: true
}
Merged configuration: {"port":"3000","entryPoint":"0x0000000071727De22E5E9d8BAf0edAc6f37da032","unsafe":true,"conditionalRpc":false,"minStake":"1","minUnstakeDelay":0,"gasFactor":"1","network":"http://127.0.0.1:8545","beneficiary":"0xd21934eD8eAf27a67f0A70042Af50A1D6d195E81","minBalance":"1","mnemonic":"./localconfig/mnemonic.txt","maxBundleGas":5000000,"autoBundleInterval":3,"autoBundleMempoolSize":10}
url= http://127.0.0.1:8545
== debugrpc was undefined
deployed EntryPoint at 0x0000000071727De22E5E9d8BAf0edAc6f37da032
url= http://127.0.0.1:8545
signer 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 balance 9999.599134268547385368
Bundle interval (seconds) 3
connected to network { name: 'unknown', chainId: 31337 }
running on http://localhost:3000/rpc
but when I try running yarn run runop --deployFactory --network http://localhost:8545/ --entryPoint 0x0000000071727De22E5E9d8BAf0edAc6f37da032
I get:
url= http://localhost:8545/
using account index= 1709766455411
account address 0x31268cc0Dac36f67e28D7712e9bAD40c32D532Ee deployed= false bal= 0.0
funding account to 5268632172000000
data= 0xb0d691fe
Error: processing response error (body="{\"jsonrpc\":\"2.0\",\"id\":43,\"error\":{\"message\":\"data.slice is not a function\"}}", error={}, requestBody="{\"method\":\"eth_sendUserOperation\",\"params\":[{\"sender\":\"0x31268cc0Dac36f67e28D7712e9bAD40c32D532Ee\",\"nonce\":\"0x0\",\"factory\":\"0x12a4F339F74c08F23D8033dF4457eC253DC9AdC0\",\"factoryData\":\"0x5fbfb9cf000000000000000000000000ae72a48c1a36bd18af168541c53037965d26e4a80000000000000000000000000000000000000000000000000000018e1605b073\",\"callData\":\"0xb61d27f600000000000000000000000031268cc0dac36f67e28d7712e9bad40c32d532ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004b0d691fe00000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"0x5601\",\"verificationGasLimit\":\"0x42dc1\",\"maxFeePerGas\":\"0x7f371436\",\"maxPriorityFeePerGas\":\"0x59682f00\",\"preVerificationGas\":\"0xaf54\",\"signature\":\"0x3fa5bb68da08729b8c67a5651d2b514e1093ed97c194edf8060bd811475a37677706df5ba898072d75c1540d5e1e4bb2e71d6e9bec77a192759033c294369bd91b\"},\"0x0000000071727De22E5E9d8BAf0edAc6f37da032\"],\"id\":43,\"jsonrpc\":\"2.0\"}", requestMethod="POST", url="http://localhost:3000/rpc", code=SERVER_ERROR, version=web/5.7.1)
at Logger.makeError (/home/santiago/projects/erc4337/bundler/node_modules/@ethersproject/logger/src.ts/index.ts:269:28)
at Logger.throwError (/home/santiago/projects/erc4337/bundler/node_modules/@ethersproject/logger/src.ts/index.ts:281:20)
at /home/santiago/projects/erc4337/bundler/node_modules/@ethersproject/web/src.ts/index.ts:341:28
at step (/home/santiago/projects/erc4337/bundler/node_modules/@ethersproject/web/lib/index.js:33:23)
at Object.next (/home/santiago/projects/erc4337/bundler/node_modules/@ethersproject/web/lib/index.js:14:53)
at fulfilled (/home/santiago/projects/erc4337/bundler/node_modules/@ethersproject/web/lib/index.js:5:58)
at processTicksAndRejections (node:internal/process/task_queues:95:5) {
reason: 'processing response error',
code: 'SERVER_ERROR',
body: '{"jsonrpc":"2.0","id":43,"error":{"message":"data.slice is not a function"}}',
error: Error: data.slice is not a function
at getResult (/home/santiago/projects/erc4337/bundler/node_modules/@ethersproject/providers/src.ts/json-rpc-provider.ts:142:28)
at processJsonFunc (/home/santiago/projects/erc4337/bundler/node_modules/@ethersproject/web/src.ts/index.ts:383:22)
at /home/santiago/projects/erc4337/bundler/node_modules/@ethersproject/web/src.ts/index.ts:320:42
at step (/home/santiago/projects/erc4337/bundler/node_modules/@ethersproject/web/lib/index.js:33:23)
at Object.next (/home/santiago/projects/erc4337/bundler/node_modules/@ethersproject/web/lib/index.js:14:53)
at fulfilled (/home/santiago/projects/erc4337/bundler/node_modules/@ethersproject/web/lib/index.js:5:58)
at processTicksAndRejections (node:internal/process/task_queues:95:5) {
code: undefined,
data: undefined
},
requestBody: '{"method":"eth_sendUserOperation","params":[{"sender":"0x31268cc0Dac36f67e28D7712e9bAD40c32D532Ee","nonce":"0x0","factory":"0x12a4F339F74c08F23D8033dF4457eC253DC9AdC0","factoryData":"0x5fbfb9cf000000000000000000000000ae72a48c1a36bd18af168541c53037965d26e4a80000000000000000000000000000000000000000000000000000018e1605b073","callData":"0xb61d27f600000000000000000000000031268cc0dac36f67e28d7712e9bad40c32d532ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004b0d691fe00000000000000000000000000000000000000000000000000000000","callGasLimit":"0x5601","verificationGasLimit":"0x42dc1","maxFeePerGas":"0x7f371436","maxPriorityFeePerGas":"0x59682f00","preVerificationGas":"0xaf54","signature":"0x3fa5bb68da08729b8c67a5651d2b514e1093ed97c194edf8060bd811475a37677706df5ba898072d75c1540d5e1e4bb2e71d6e9bec77a192759033c294369bd91b"},"0x0000000071727De22E5E9d8BAf0edAc6f37da032"],"id":43,"jsonrpc":"2.0"}',
requestMethod: 'POST',
url: 'http://localhost:3000/rpc'
}
Im getting this issue as trying to run yarn preprocess
I believe the issue is when calling yarn submodule-update
this is the error log:
yarn run v1.22.19
$ git submodule update --remote --init --recursive
fatal: Needed a single revision
fatal: Unable to find current origin/fix-deployment revision in submodule path 'submodules/account-abstraction'
error Command failed with exit code 1.
I tried to use the current sdk with paymaster. And there are always an error.
return !!(value.toHexString);
^
TypeError: Cannot read properties of undefined (reading 'toHexString')
I found that the problem is in this call chain:
paymasterAndData is undefine.
We can change to this:
const partialUserOp: any = {
sender: this.getWalletAddress(),
nonce: this.getNonce(),
initCode,
callData,
callGasLimit,
verificationGasLimit,
maxFeePerGas,
maxPriorityFeePerGas,
paymasterAndData:'0x' // ADD this line!!!!!!!!!!!!!!!!!!
}
console.log("==aa==")
let paymasterAndData: string | undefined
if (this.paymasterAPI != null) {
// fill (partial) preVerificationGas (all except the cost of the generated paymasterAndData)
console.log("==bb==")
const userOpForPm = {
...partialUserOp,
preVerificationGas: await this.getPreVerificationGas(partialUserOp)
}
paymasterAndData = await this.paymasterAPI.getPaymasterAndData(userOpForPm)
}
partialUserOp.paymasterAndData = paymasterAndData ?? '0x'
// partialUserOp.paymasterAndData = '0x0165878A594ca255338adfa4d48449f69242Eb8F'
console.log("==cc==")
Hi,
TL;DR - Calculation of preVerificationGas
is incorrect, takes 32 bytes of the packed transaction and considers it as a single word, each word is 4 bytes. This is incorrect after using stackup
's bundler since they multiple each byte by 4 instead of each word. Regardless, a word is 2 bytes, not 32, so computation seems off there as well (unless i am missing something).
I've been using this SDK along with stackup's bundler and my uos have been failing because the bundler's preVerificationGas
check - here - returns a larger value and results in te uos being failed since we're not providing sufficient value.
Upon checking it further, I think that the issue is within the calcPreVerificationGas.ts
file.
You take the length of packed
, which is the length in bytes, add 31, and then split it by 32. The result is then multiplied by ov.perUserOpWord
.
I might be missing some part of it, but a word is 2 bytes, so generally you'd need to at words add 1 and divide by 2 instead of 32.
Regardless of that, stackup's bundler takes the number of bytes and multiplies it by 4 gas per byte, while with the current code in this sdk, it takes the size of the packed tx in bytes and multiplies it by 4 gas per 32 bytes, which causes txs sent to stackup's bundler to fail since we didn't specify enough gas.
I think that either the code here should be fixed to use the number of bytes in packed
instead of the number divide by 32 and multiply that by 4.
Alternatively, divide it for words (2bytes) and then multiply that size by 8 (instead of 4).
The whole change would be in this line, simply remove the addition and division.
Not sure if this is something you're wanting to do since I didn't find a page explaining if there's a uniform interface for the bundler and how to perform the serialization cost computation described in EIP-4337.
Thanks.
I'm running my own Geth node on Goerli with the following command:
./go-ethereum/build/bin/geth --goerli --datadir /server2/weihan/ethereum/execution/datadir --http --http.api personal,eth,net,web3,debug --http.vhosts '*, localhost, host.docker.internal' --http.addr "0.0.0.0" --allow-insecure-unlock --rpc.allow-unprotected-txs --authrpc.jwtsecret=/opt/jwtsecret
I tried to run a bundler on Goerli using the following command:
yarn run bundler --network goerli --mnemonic mnemonic.txt
but got the following error:
command-line arguments: {
config: './localconfig/bundler.config.json',
auto: false,
network: 'goerli',
mnemonic: 'mnemonic.txt'
}
Merged configuration: {"port":"3000","entryPoint":"0x0576a174D229E3cFA37253523E645A78A0C91B57","unsafe":false,"conditionalRpc":false,"gasFactor":"1","network":"goerli","beneficiary":"0xd21934eD8eAf27a67f0A70042Af50A1D6d195E81","minBalance":"1","mnemonic":"mnemonic.txt","maxBundleGas":5000000,"minStake":"1","minUnstakeDelay":0,"autoBundleInterval":3,"autoBundleMempoolSize":10}
Aborted: Cannot read properties of undefined (reading '_clientVersion')
Any idea how to tackle this issue?
Well. I tried to use sdk here and encountered a problem.
If I run runop.ts
for two times. The second round will fail.
Error: call revert exception; VM Exception while processing transaction: reverted with reason string "initCode failed" ...
reason: 'initCode failed',
code: 'CALL_EXCEPTION',
The problem is that:
Run runop.ts
for the first time, and the wallet contract is deployed.
Run it again. BasicWalletAPI call entryPointView.getSenderAddress(initCode)
which causes the error as the wallet contract is already deployed.
async getCounterFactualAddress (): Promise<string> {
const initCode = this.getWalletInitCode()...
return await this.entryPointView.callStatic.getSenderAddress(initCode)
}
The logic in the API seems to be ok, so maybe some changes are needed in the entry point contract? Or shall we calculate the account locally instead of using getSenderAddress
?
/**
* helper: make a "view" call to calculate the sender address.
* must be called from zero-address.
*/
function getSenderAddress(bytes calldata initCode) public returns (address sender) {
require(msg.sender == address(0), "must be called off-chain with from=zero-addr");
return _createSender(initCode);
}
yarn run v1.22.18
$ lerna run hardhat-deploy --stream --no-prefix -- --network localhost --show-stack-traces
lerna notice cli v5.6.2
lerna info Executing command in 1 package: "yarn run hardhat-deploy --network localhost --show-stack-traces"
$ hardhat deploy --network localhost --show-stack-traces
Nothing to compile
No need to generate any newer typings.
An unexpected error occurred:
Error: ERROR processing /bundler/packages/bundler/deploy/2-deploy-entrypoint.ts:
Error: raw TX didn't deploy deployer!
at DeterministicDeployer.deployFactory (/bundler/packages/sdk/dist/src/DeterministicDeployer.js:44:19)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at async DeterministicDeployer.getDeployTransaction (/bundler/packages/sdk/dist/src/DeterministicDeployer.js:48:9)
at async DeterministicDeployer.deterministicDeploy (/bundler/packages/sdk/dist/src/DeterministicDeployer.js:88:42)
at async Object.deployEP [as func] (/bundler/packages/bundler/deploy/2-deploy-entrypoint.ts:22:3)
at async DeploymentsManager.executeDeployScripts (/bundler/node_modules/hardhat-deploy/src/DeploymentsManager.ts:1226:22)
at async DeploymentsManager.runDeploy (/bundler/node_modules/hardhat-deploy/src/DeploymentsManager.ts:1059:5)
at async SimpleTaskDefinition.action (/bundler/node_modules/hardhat-deploy/src/index.ts:438:5)
at async Environment._runTaskDefinition (/bundler/node_modules/hardhat/src/internal/core/runtime-environment.ts:333:14)
at async Environment.run (/bundler/node_modules/hardhat/src/internal/core/runtime-environment.ts:166:14)
at DeploymentsManager.executeDeployScripts (/bundler/node_modules/hardhat-deploy/src/DeploymentsManager.ts:1229:19)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at async DeploymentsManager.runDeploy (/bundler/node_modules/hardhat-deploy/src/DeploymentsManager.ts:1059:5)
at async SimpleTaskDefinition.action (/bundler/node_modules/hardhat-deploy/src/index.ts:438:5)
at async Environment._runTaskDefinition (/bundler/node_modules/hardhat/src/internal/core/runtime-environment.ts:333:14)
at async Environment.run (/bundler/node_modules/hardhat/src/internal/core/runtime-environment.ts:166:14)
at async SimpleTaskDefinition.action (/bundler/node_modules/hardhat-deploy/src/index.ts:584:32)
at async Environment._runTaskDefinition (/bundler/node_modules/hardhat/src/internal/core/runtime-environment.ts:333:14)
at async Environment.run (/bundler/node_modules/hardhat/src/internal/core/runtime-environment.ts:166:14)
at async SimpleTaskDefinition.action (/bundler/node_modules/hardhat-deploy/src/index.ts:669:5)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
lerna ERR! yarn run hardhat-deploy --network localhost --show-stack-traces exited 1 in '@account-abstraction/bundler'
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
when working on any packages downstream, i often format the file so long lines can automatically wrap. however, there don't appear to be any prettier rules in this repository and when i format a file, the whole file changes.
this makes it difficult when working downstream because when merging from upstream, there are lots of conflicts.
it would be nice if this repository could provide a .prettierrc or similar, and format all existing code to make downstream development easier.
While trying to set up the whole infrastructure on my local environment (hardhat node, bundler, trampoline), it has come to my attention that HttpRpcClient.estimateUserOpGas
return parameter name is incorrect on the sdk
node module.
The node module exports verificationGas
parameter, while the implementation uses verificationGasLimit
This breaks trampoline, which uses verificationGas
. Since this value is never returned by the bundler, it is undefined
and crashes the extension when passed onto ethers.BigNumber.from
.
What does the following code in runop.ts
mean?
const data = keccak256(Buffer.from('nonce()')).slice(0, 10)
This is the only data that gets used to create a user operation or anything else gets used at some point?
When using VerifyingPaymaster.sol, preVerificationGas
is packed in userOpHash
.
Thus we have to calculate signature in VerifyingPaymaster(gasless verifyingSigner).
However we use @account-abstraction/sdk, after calculating the paymasterAndData
, we will change preVerificationGas
This will lead to failure when using VerifyingPaymaster, see code:
// BaseAccountAPI.ts
async createUnsignedUserOp (info: TransactionDetailsForUserOp): Promise<UserOperationStruct> {
partialUserOp.paymasterAndData = paymasterAndData ?? '0x'
return {
...partialUserOp,
preVerificationGas: this.getPreVerificationGas(partialUserOp),
signature: ''
}
To solve this is either
preVerificationGas
field in VerifyingPaymaster.solpreVerificationGas
with exact number of words in calcPreVerificationGas
or resersve some words in calcPreVerificationGas
I prefer the first solution, which will modify the contract.
The getTransactionReceipt
function hangs (and eventually times out) since the filter is only applied to the latest block. for now i'm working around by changing "latest"
to -1000
which still should not be acceptable.
The ethers interface for BaseProvider may need to change to accept a blockFrom
and blockTo
parameter, or another scenario: the getTransactionReceipt
could scan all blocks moving backwards in chunks of N blocks (expensive).
https://github.com/eth-infinitism/bundler/blob/main/packages/bundler/src/modules/MempoolManager.ts#L159
The clearState()
function empties MempoolManager.mempool
, but does not clear MempoolManager.entryCount
.
userop with too high verificationgaslimit can make bundler to resend reverted tx all the times until all gas of operator used up. we need to check it when creating bundle to prevent it.
Environment: Windows 10, cygwin 3.5.0-1.x86_64, yarn version v1.22.19, npm version 9.6.4, node version 20.11.0
Issue 1:
Running 'yarn && yarn preprocess' failed with the following:
src/ValidationManager.ts(297,17): error TS2365: Operator '>=' cannot be applied to types 'BigNumberish' and 'number'
so cast 'calcPreVerificationGas1' as BigNumberish on line 297 of ValidationManager.ts
Issue 2:
Ran up Geth using 'geth --http --http.api personal,eth,net,web3,debug --dev --dev.period 13 --rpc.allow-unprotected-txs --allow-insecure-unlock'
Deployed an Entrypoint contract through our own tool and updated the bundler.config.json file with the address.
Calling 'yarn run bundler' fails with the following:
command-line arguments: { config: './localconfig/bundler.config.json', auto: false }
Merged configuration: {"port":"3000","entryPoint":"0x9decd0823a4d84fac1f400c316781cb5b047d95c","unsafe":false,"conditionalRpc":false,"minStake":
"1","minUnstakeDelay":0,"gasFactor":"1","network":"http://127.0.0.1:8545","beneficiary":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266","minBalance
":"1","mnemonic":"./localconfig/mnemonic.txt","maxBundleGas":9000000000,"autoBundleInterval":3,"autoBundleMempoolSize":10}
url= http://127.0.0.1:8545
== debugrpc was undefined
Aborted: processing response error (body="{"jsonrpc":"2.0","id":56,"error":{"code":-32000,"message":"insufficient funds for gas * p
rice + value: balance 0, tx cost 10000000000000000, overshot 10000000000000000"}}\n", error={"code":-32000}, requestBody="{"method":"eth_sen
dRawTransaction","params":["0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba022222222222222222222222222222222222222222222222222
22222222222222a02222222222222222222222222222222222222222222222222222222222222222"],"id":56,"jsonrpc":"2.0"}", requestMethod="POST", url="
http://127.0.0.1:8545", code=SERVER_ERROR, version=web/5.7.1)
error Command failed with exit code 1.
Geth console shows the following:
INFO [02-27|16:17:24.569] Submitted transaction hash=0xbbd5610f4fe8dfa4f358ff401aec669fc061ba0e6dcc287611e248384bbc64d5 from=0x7b32ac604407bF0BA97a74d86e2461633472Ae83 nonce=1 recipient=0x3fAB184622Dc19b6109349B94811493BF2a45362 value=10,000,000,000,000,000
WARN [02-27|16:17:24.583] Served eth_sendRawTransaction conn=127.0.0.1:51622 reqid=56 duration="545.2ยตs" err="insufficient funds for gas * price + value: balance 0, tx cost 10000000000000000, overshot 10000000000000000"
0x7b32ac604407bF0BA97a74d86e2461633472Ae83 is the developer account and has all the funds. Through our own tool we can successfully carry out the transfer to 0x3fAB184622Dc19b6109349B94811493BF2a45362
Why is this a problem for the Bundler submitted transaction?
From what I understand, currently the main
branch uses ethers v5 while there is a separate branch, namely support-ethers-v6
which incorporates some changes to the bundler to facilitate the v6 upgrade. Our goal is to have a version of the bundler that is both ethers v6 compatible and also incorporate these changes which essentially allow the bundler to use a hardhat signer. We have that in a private repo which was forked from the support-ethers-v6
branch and now we are trying to merge it in main. The problem is that we are running to lots of conflicts regarding ethers v5-v6 differences. Our approach was to start by migrating each package for example contract-types
(which worked out of the box), then utils
, sdk
and so on solving ethers v6 issues one package at a time. My questions are the following:
I have successfully ran a Geth node using the docker command provided as well as successfully running the bundler following the instruction stated in the README file. When I attempt to run yarn run runop --deployFactory --network localhost
, I get the following error:
Error: unsupported getDefaultProvider network (operation="getDefaultProvider", network="localhost", code=NETWORK_ERROR, version=providers/5.7.2)
at Logger.makeError (/Users/weihan/Documents/Codes/bundler/node_modules/@ethersproject/logger/src.ts/index.ts:269:28)
at Logger.throwError (/Users/weihan/Documents/Codes/bundler/node_modules/@ethersproject/logger/src.ts/index.ts:281:20)
at getDefaultProvider (/Users/weihan/Documents/Codes/bundler/node_modules/@ethersproject/providers/src.ts/index.ts:70:16)
at main (/Users/weihan/Documents/Codes/bundler/packages/bundler/src/runner/runop.ts:112:38)
at Object.<anonymous> (/Users/weihan/Documents/Codes/bundler/packages/bundler/src/runner/runop.ts:194:6)
at Module._compile (node:internal/modules/cjs/loader:1254:14)
at Module.m._compile (/Users/weihan/Documents/Codes/bundler/packages/bundler/node_modules/ts-node/src/index.ts:1618:23)
at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
at Object.require.extensions.<computed> [as .ts] (/Users/weihan/Documents/Codes/bundler/packages/bundler/node_modules/ts-node/src/index.ts:1621:12)
at Module.load (node:internal/modules/cjs/loader:1117:32) {
reason: 'unsupported getDefaultProvider network',
code: 'NETWORK_ERROR',
operation: 'getDefaultProvider',
network: 'localhost'
}
May I ask for help on this?
Ubuntu: 22.04.2 (Also seeing in OSX)
NodeJS: 18.16.0
Firefox: 112.0.2 (64-bit) (Also seeing in Brave)
[email protected]
account-abtraction/[email protected]
In browser
Uncaught (in promise) TypeError: class constructors must be invoked with 'new'
SimpleAccountFactory__factory SimpleAccountFactory__factory.js:111
wrapProvider Provider.js:24
getAaProvider page.tsx:29
Home page.tsx:40
commitHookEffectListMount react-dom.development.js:19974
commitHookPassiveMountEffects react-dom.development.js:22022
commitPassiveMountOnFiber react-dom.development.js:22127
This should also reproduce (in browser):
import { wrapProvider } from "@account-abstraction/sdk";
import { providers, Wallet } from "ethers";
const privateKey = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; // or other, well known key
const entryPointAddress = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789";
const bundlerUrl = "http://localhost:3000/rpc";
const rpcUrl = "http://localhost:8545";
const provider = new providers.JsonRpcProvider(
rpcUrl,
{
name: 'localhost',
chainId: 31337,
},
);
const signer = new Wallet(privateKey, provider);
const main = async () => {
const aaProvider = await wrapProvider(
provider as any,
{
entryPointAddress,
bundlerUrl,
},
signer as any,
)
console.log(aaProvider);
};
main()
.catch((err) => { console.error(err) });
getwax/eth-global-lisbon-hackathon@8e75fad
This appears to be due to how ethers.js & typechain is transpiled in @account-abstraction/contracts
targeting an older es
format. It may be desirable to target a newer es version (es6
, esnext
) and allow project transpilers to target their desired es version.
constructor(IEntryPoint entryPoint, UserOperation[] memory userOps) {
revert UserOpHashesResult(
getUserOpHashes(entryPoint, userOps));
}
this contract has revert in the constructor, where is this contract being used if not needed can this be removed?
Please correct me if i missed any.
Recently, we have integrated eth-infinitism bundler into our Smart Account repo , so in our test cases we can send userOps to EP via bundler.
When trying to send a deployment userOp (initcode not empty) via Bundler, I'm getting a factory accesses un-deployed contract
error.
I believe this error is being thrown here.
After this error, it lists the addresses and the codesize. So I checked addresses and found out the address with 0 codesize is actually an EOA (signer created by the hardhat test env).
After a research, I realised, that the reason is the following:
deployCounterFactualAccount
of factory calls SmartAccount.init()
method which at some point calls the following code
assembly {
size := extcodesize(owner)
}
It is the check, which is performed during setting the owner of Smart Account to make sure owner is not smart contract. As in this case Smart Account will be inaccessible since smart account will user ecrecover
, not eip-1271 to validate the owner's signature.
We don't want to check if the expected signer is smart contract at the validation stage (and select ecrecover/isValidSignature accordingly) as it will add a gas overhead for every userOp validation. We want to allow EOA's only instead by making only one check at the initialization.
So, because of extcodesize
opcode applied to EOA owner address, it is considered as smart contract by bundler. And since it's codesize is 0, the above error is thrown for an EOA, not an un-deployed smart contract.
Looking forward to hearing your thoughts on it.
I was trying to get the bundler connected to hosted nodes which are apparently Erigon nodes. I am trying to run the bundler on the Polygon network.
The initial traceCall from supportsDebugTraceCall
errors out and returns then false, leading to a wrongful error FATAL: full validation requires a node with debug_traceCall. for local UNSAFE mode: use --unsafe
. Apparently the debug_traceCall endpoint is fine, it seems to me the message from Erigon is different than the message from geth if the gas price isn't set correctly.
I think its connected to this one: erigontech/erigon#3494
The exact error coming back from the API is this one:
at processTicksAndRejections (node:internal/process/task_queues:95:5) {
reason: 'processing response error',
code: 'SERVER_ERROR',
body: '{"jsonrpc":"2.0","result":null,"error":{"message":"tracing failed: fee cap less than block base fee: address 0x0000000000000000000000000000000000000000, gasFeeCap: 0 baseFee: 31790422898","code":-32000},"id":45}',
error: Error: tracing failed: fee cap less than block base fee: address 0x0000000000000000000000000000000000000000, gasFeeCap: 0 baseFee: 31790422898
at getResult (/Users/thomas/Projects/Morpher/bundler/node_modules/@ethersproject/providers/src.ts/json-rpc-provider.ts:142:28)
at processJsonFunc (/Users/thomas/Projects/Morpher/bundler/node_modules/@ethersproject/web/src.ts/index.ts:383:22)
at /Users/thomas/Projects/Morpher/bundler/node_modules/@ethersproject/web/src.ts/index.ts:320:42
at step (/Users/thomas/Projects/Morpher/bundler/node_modules/@ethersproject/web/lib/index.js:33:23)
at Object.next (/Users/thomas/Projects/Morpher/bundler/node_modules/@ethersproject/web/lib/index.js:14:53)
at fulfilled (/Users/thomas/Projects/Morpher/bundler/node_modules/@ethersproject/web/lib/index.js:5:58)
at processTicksAndRejections (node:internal/process/task_queues:95:5) {
code: -32000,
data: undefined
},
requestBody: '{"method":"debug_traceCall","params":[{"from":"0x0000000000000000000000000000000000000000","to":"0x0000000000000000000000000000000000000000","data":"0x"},"latest",{"tracer"...
I am using chainnodes nodes for this one which offer a small free tier.
yarn && yarn preprocess
dockers/bundler
and run ./dbuild.sh
The webpack
command will throw an error as below:
โจ Done in 17.00s.
version=0.4.0
../../packages/bundler/src//types/hardhat.d.ts
../../packages/bundler/src//types/contracts/BundlerHelper.ts
webpacking..
ERROR in ../../packages/bundler/dist/src/UserOpMethodHandler.js 188:31-65
Module not found: Error: Can't resolve '../package.json' in '/Users/<user>/Documents/projects/eth-infinitism/bundler/packages/bundler/dist/src'
@ ../../packages/bundler/dist/src/runBundler.js 14:30-62
@ ../../packages/bundler/dist/src/exec.js 3:21-44
Checking file UserOpMethodHandler.ts, the implementation of clientVersion()
depends on the module's package.json
, however, after been compiled to UserOpMethodHandler.js
, there is no package.json
anymore at its parent folder.
clientVersion (): string {
// eslint-disable-next-line
return 'aa-bundler/' + require('../package.json').version
}`
Maybe we should just hard code the version
in clientVersion()?
When a bundler is started and a bundle is sent for the first time (https://github.com/eth-infinitism/bundler/blob/v0.5.0/packages/bundler/src/modules/BundleManager.ts#L55), all past events of entrypoint are scanned (https://github.com/eth-infinitism/bundler/blob/v0.5.0/packages/bundler/src/modules/EventsManager.ts#L37). This may fail because the response from RPC server's eth_getLogs
exceeds the size limit.
Part of the error logs:
reason: 'processing response error',
code: 'SERVER_ERROR',
body: '{"jsonrpc":"2.0","id":55,"error":{"code":-32602,"message":"Log response size exceeded. You can make eth_getLogs requests with up to a 2K block range and no limit on the response size, or you can request any block range with a cap of 10K logs in the response. Based
on your parameters and the response size limit, this block range should work: [0x0, 0x2014fd1]"}}',
error: Error: Log response size exceeded. You can make eth_getLogs requests with up to a 2K block range and no limit on the response size, or you can request any block range with a cap of 10K logs in the response. Based on your parameters and the response size limit, this
block range should work: [0x0, 0x2014fd1]
at getResult (webpack:///../../node_modules/@ethersproject/providers/lib.esm/json-rpc-provider.js?:148:23)
at processJsonFunc (webpack:///../../node_modules/@ethersproject/web/lib.esm/index.js?:312:22)
at eval (webpack:///../../node_modules/@ethersproject/web/lib.esm/index.js?:255:46)
at Generator.next (<anonymous>)
at fulfilled (webpack:///../../node_modules/@ethersproject/web/lib.esm/index.js?:18:58)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
code: -32602,
data: undefined
},
requestBody: '{"method":"eth_getLogs","params":[{"fromBlock":"0x0","toBlock":"latest","address":"0x0576a174d229e3cfa37253523e645a78a0c91b57"}],"id":55,"jsonrpc":"2.0"}',
requestMethod: 'POST',
url: 'https://polygon-mumbai.g.alchemy.com/v2/...'
The check for unstake delay in the reference bundler implementation
only checks if unstake delay is greater than 1 second.
It should be rather
BigNumber.from(config.minunstakedelay).lt(entStakes.unstakeDelaySec)
Only the reputationmanager reads from config.minunstakedelay. The validationmanager (which handles simulatecall) is currently not passed this config parameter. May be one should?
This explains why the bundler spec test passes even with a unstake delay of 2 seconds although it shouldn't
Similarly, the current enforcement of minimum stake value (specified in the minStake bundler configuration field) is missing. Currently, it suffices for stake to be greater than 1 wei
`const transaction = {
to:"0x082364c4E413ea19855426e11c8B3D767104B91d",
value: amount,
gasLimit: 1e6,
};`
I want to send some fund from accountwallet to this 'to' account. But sendTransaction is not supported for accountwallet.
The how we send fund from accountwallet?
import { ethers } from 'ethers'
import { wrapProvider } from '@account-abstraction/sdk'
// import { wrapProvider } from '@account-abstraction/sdk'
import { DeterministicDeployer, SimpleAccountAPI} from '../src'
import { SampleRecipient__factory } from '@account-abstraction/utils'
import { SimpleAccountFactory__factory } from '@account-abstraction/contracts';
const abi=require('./abi')
describe('SimpleAccountAPI', () => {
let provider = new ethers.providers.JsonRpcProvider("http://127.0.0.1:8545");
const signer = provider.getSigner();
it('init', async () => {
const entryPointAddress = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"
const recipient = await new SampleRecipient__factory(signer).deploy()
console.log("rec", recipient.address);
DeterministicDeployer.init(provider)
const factoryAddress = await DeterministicDeployer.deploy(new SimpleAccountFactory__factory(), 0, [entryPointAddress])
// console.log(factoryAddress)
const api = new SimpleAccountAPI({
provider,
entryPointAddress,
owner: signer,
factoryAddress
})
const op = await api.createSignedUserOp({
target: recipient.address,
data: recipient.interface.encodeFunctionData('something', ['hello']),
gasLimit: 1e6
})
console.log(op)
})
it("next phase", async function () {
const entryPointAddress="0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789";
const aaSigner = signer
const config = {
chainId: await provider.getNetwork().then(net => net.chainId),
entryPointAddress,
bundlerUrl: 'http://localhost:3000/rpc'
}
const aaProvider = await wrapProvider(provider, config, aaSigner)
const walletAddress = await aaProvider.getSigner().getAddress()
// console.log("wallwt",aaProvider);
// send some eth to the wallet Address: wallet should have some balance to pay for its own creation, and for calling methods.
// console.log(abi)
const myContract = new ethers.Contract(abi, aaProvider)
// this method will get called from the wallet address, through account-abstraction EntryPoint
await myContract.something("hey")
})
})
when running this test it failed with an error message that abi.map( ) is not a function
It would be valuable to be able to configure the timeout used by the Geth JS tracer used during validation simulation (via debug_traceCall
) to allow for longer/shorter timeouts.
Geth version: v1.13.5
Bundler version v0.6.2
When running one of our integration tests against newer versions of this bundler & geth on our local machines, we have been consistently encountering this error:
Error: could not coalesce error (error={ "code": "SERVER_ERROR", "message": "processing response error (body=\"{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"id\\\":245,\\\"error\\\":{\\\"code\\\":-32000,\\\"message\\\":\\\"execution timeout at parseStringValue (bigInt:1:25261(161)) at step (\\\\u003ceval\\\\u003e:64:31(40)) in server-side tracer function 'step'\\\"}}\\n\", error={\"code\":-32000}, requestBody=\"{\\\"method\\\":\\\"debug_traceCall\\\",\\\"params\\\":[{\\\"from\\\":\\\"0x0000000000000000000000000000000000000000\\\",\\\"to\\\":\\\"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789\\\",\\\"data\\\":\\\"0xee2194230000000000000000000000000000000000000000000000000000000000000020000000000000000000000000d5139e80c58d3b2a91996e7b5eb91a451d6e2aab0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000561800000000000000000000000000000000000000000000000000000000000b83b0000000000000000000000000000000000000000000000000000000000000d3df0000000000000000000000000000000000000000000000000000001160565202000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000238e619ebe8ec922d5cc2197eebe6e8bf5c257f3e471688f0b9000000000000000000000000dac3ef1edc18f3022c380e5737df50283085186a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000490000000000000000000000000000000000000000000000000000000000000184b63e800d00000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a51c1fc2f0d1a1b8494ed1fe312d7c3a78ed91c00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000a51c1fc2f0d1a1b8494ed1fe312d7c3a78ed91c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000004a798b2b10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4ab4ed83e00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000012001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000180353a3ed5a0441919f1c639a46931de872ac3357de2ce5aa2d68c2639df54189d0000000000000000000000000000000000000000000000000000000000000024655c9a457615aac594d92fb6d842f0e910e5ee6677cddbcddaea624f3203f0e77b71a302b06c91a52b9c4ba5a7fb85226738b02c144e8ee177d034022a79c946fdf8bce27f54e06f3aee3b6a542db1ab1f2418d7370a78b150d06965f942b14a470cdee69ab50e610c39b840681bf816b030f4a0a5d5af02ce27dcce6bede89f0000000000000000000000000000000000000000000000000000000000000025f8e4b678e1c62f7355266eaa4dc1148573440937063a46d848da1e25babbd20b010000004d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000897b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a224e546f2d3161424547526e78786a6d6b61544865687972444e5833697a6c7169316f776d4f643955474a30222c226f726967696e223a2268747470733a2f2f66726573682e6c65646765722e636f6d222c2263726f73734f726967696e223a66616c73657d0000000000000000000000000000000000000000000000\\\",\\\"gasLimit\\\":{\\\"type\\\":\\\"BigNumber\\\",\\\"hex\\\":\\\"0x0c578f\\\"}},\\\"latest\\\",{\\\"tracer\\\":\\\"{\\\\n callsFromEntryPoint: [],\\\\n currentLevel: null,\\\\n keccak: [],\\\\n calls: [],\\\\n logs: [],\\\\n debug: [],\\\\n lastOp: '',\\\\n lastThreeOpcodes: [],\\\\n // event sent after all validations are done: keccak(\\\\\\\"BeforeExecution()\\\\\\\")\\\\n stopCollectingTopic: 'bb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f972',\\\\n stopCollecting: false,\\\\n topLevelCallCounter: 0,\\\\n fault(log, db) {\\\\n this.debug.push('fault depth=', log.getDepth(), ' gas=', log.getGas(), ' cost=', log.getCost(), ' err=', log.getError());\\\\n },\\\\n result(ctx, db) {\\\\n return {\\\\n callsFromEntryPoint: this.callsFromEntryPoint,\\\\n keccak: this.keccak,\\\\n logs: this.logs,\\\\n calls: this.calls,\\\\n debug: this.debug // for internal debugging.\\\\n };\\\\n },\\\\n enter(frame) {\\\\n if (this.stopCollecting) {\\\\n return;\\\\n }\\\\n // this.debug.push('enter gas=', frame.getGas(), ' type=', frame.getType(), ' to=', toHex(frame.getTo()), ' in=', toHex(frame.getInput()).slice(0, 500))\\\\n this.calls.push({\\\\n type: frame.getType(),\\\\n from: toHex(frame.getFrom()),\\\\n to: toHex(frame.getTo()),\\\\n method: toHex(frame.getInput()).slice(0, 10),\\\\n gas: frame.getGas(),\\\\n value: frame.getValue()\\\\n });\\\\n },\\\\n exit(frame) {\\\\n if (this.stopCollecting) {\\\\n return;\\\\n }\\\\n this.calls.push({\\\\n type: frame.getError() != null ? 'REVERT' : 'RETURN',\\\\n gasUsed: frame.getGasUsed(),\\\\n data: toHex(frame.getOutput()).slice(0, 4000)\\\\n });\\\\n },\\\\n // increment the \\\\\\\"key\\\\\\\" in the list. if the key is not defined yet, then set it to \\\\\\\"1\\\\\\\"\\\\n countSlot(list, key) {\\\\n var _a;\\\\n list[key] = ((_a = list[key]) !== null && _a !== void 0 ? _a : 0) + 1;\\\\n },\\\\n step(log, db) {\\\\n var _a;\\\\n if (this.stopCollecting) {\\\\n return;\\\\n }\\\\n opcode = log.op.toString();\\\\n stackSize = log.stack.length();\\\\n stackTop3 = [];\\\\n for ( i = 0; i < 3 && i < stackSize; i++) {\\\\n stackTop3.push(log.stack.peek(i));\\\\n }\\\\n this.lastThreeOpcodes.push({ opcode, stackTop3 });\\\\n if (this.lastThreeOpcodes.length > 3) {\\\\n this.lastThreeOpcodes.shift();\\\\n }\\\\n // this.debug.push(this.lastOp + '-' + opcode + '-' + log.getDepth() + '-' + log.getGas() + '-' + log.getCost())\\\\n if (log.getGas() < log.getCost() || (\\\\n // special rule for SSTORE with gas metering\\\\n opcode === 'SSTORE' && log.getGas() < 2300)) {\\\\n this.currentLevel.oog = true;\\\\n }\\\\n if (opcode === 'REVERT' || opcode === 'RETURN') {\\\\n if (log.getDepth() === 1) {\\\\n // exit() is not called on top-level return/revent, so we reconstruct it\\\\n // from opcode\\\\n ofs = parseInt(log.stack.peek(0).toString());\\\\n len = parseInt(log.stack.peek(1).toString());\\\\n data = toHex(log.memory.slice(ofs, ofs + len)).slice(0, 4000);\\\\n // this.debug.push(opcode + ' ' + data)\\\\n this.calls.push({\\\\n type: opcode,\\\\n gasUsed: 0,\\\\n data\\\\n });\\\\n }\\\\n // NOTE: flushing all history after RETURN\\\\n this.lastThreeOpcodes = [];\\\\n }\\\\n if (log.getDepth() === 1) {\\\\n if (opcode === 'CALL' || opcode === 'STATICCALL') {\\\\n // stack.peek(0) - gas\\\\n addr = toAddress(log.stack.peek(1).toString(16));\\\\n topLevelTargetAddress = toHex(addr);\\\\n // stack.peek(2) - value\\\\n ofs = parseInt(log.stack.peek(3).toString());\\\\n // stack.peek(4) - len\\\\n topLevelMethodSig = toHex(log.memory.slice(ofs, ofs + 4));\\\\n this.currentLevel = this.callsFromEntryPoint[this.topLevelCallCounter] = {\\\\n topLevelMethodSig,\\\\n topLevelTargetAddress,\\\\n access: {},\\\\n opcodes: {},\\\\n extCodeAccessInfo: {},\\\\n contractSize: {}\\\\n };\\\\n this.topLevelCallCounter++;\\\\n }\\\\n else if (opcode === 'LOG1') {\\\\n // ignore log data ofs, len\\\\n topic = log.stack.peek(2).toString(16);\\\\n if (topic === this.stopCollectingTopic) {\\\\n this.stopCollecting = true;\\\\n }\\\\n }\\\\n this.lastOp = '';\\\\n return;\\\\n }\\\\n lastOpInfo = this.lastThreeOpcodes[this.lastThreeOpcodes.length - 2];\\\\n // store all addresses touched by EXTCODE* opcodes\\\\n if (((_a = lastOpInfo === null || lastOpInfo === void 0 ? void 0 : lastOpInfo.opcode) === null || _a === void 0 ? void 0 : _a.match(/^(EXT.*)$/)) != null) {\\\\n addr = toAddress(lastOpInfo.stackTop3[0].toString(16));\\\\n addrHex = toHex(addr);\\\\n last3opcodesString = this.lastThreeOpcodes.map(x => x.opcode).join(' ');\\\\n // only store the last EXTCODE* opcode per address - could even be a boolean for our current use-case\\\\n if (last3opcodesString.match(/^(\\\\\\\\w+) EXTCODESIZE ISZERO$/) == null) {\\\\n this.currentLevel.extCodeAccessInfo[addrHex] = opcode;\\\\n // this.debug.push(`potentially illegal EXTCODESIZE without ISZERO for ${addrHex}`)\\\\n }\\\\n else {\\\\n // this.debug.push(`safe EXTCODESIZE with ISZERO for ${addrHex}`)\\\\n }\\\\n }\\\\n // not using 'isPrecompiled' to only allow the ones defined by the ERC-4337 as stateless precompiles\\\\n isAllowedPrecompiled = (address) => {\\\\n addrHex = toHex(address);\\\\n addressInt = parseInt(addrHex);\\\\n // this.debug.push(`isPrecompiled address=${addrHex} addressInt=${addressInt}`)\\\\n return addressInt > 0 && addressInt < 10;\\\\n };\\\\n if (opcode.match(/^(EXT.*|CALL|CALLCODE|DELEGATECALL|STATICCALL)$/) != null) {\\\\n idx = opcode.startsWith('EXT') ? 0 : 1;\\\\n addr = toAddress(log.stack.peek(idx).toString(16));\\\\n addrHex = toHex(addr);\\\\n // this.debug.push('op=' + opcode + ' last=' + this.lastOp + ' stacksize=' + log.stack.length() + ' addr=' + addrHex)\\\\n if (this.currentLevel.contractSize[addrHex] == null && !isAllowedPrecompiled(addr)) {\\\\n this.currentLevel.contractSize[addrHex] = {\\\\n contractSize: db.getCode(addr).length,\\\\n opcode\\\\n };\\\\n }\\\\n }\\\\n if (this.lastOp === 'GAS' && !opcode.includes('CALL')) {\\\\n // count \\\\\\\"GAS\\\\\\\" opcode only if not followed by \\\\\\\"CALL\\\\\\\"\\\\n this.countSlot(this.currentLevel.opcodes, 'GAS');\\\\n }\\\\n if (opcode !== 'GAS') {\\\\n // ignore \\\\\\\"unimportant\\\\\\\" opcodes:\\\\n if (opcode.match(/^(DUP\\\\\\\\d+|PUSH\\\\\\\\d+|SWAP\\\\\\\\d+|POP|ADD|SUB|MUL|DIV|EQ|LTE?|S?GTE?|SLT|SH[LR]|AND|OR|NOT|ISZERO)$/) == null) {\\\\n this.countSlot(this.currentLevel.opcodes, opcode);\\\\n }\\\\n }\\\\n this.lastOp = opcode;\\\\n if (opcode === 'SLOAD' || opcode === 'SSTORE') {\\\\n slot = toWord(log.stack.peek(0).toString(16));\\\\n slotHex = toHex(slot);\\\\n addr = log.contract.getAddress();\\\\n addrHex = toHex(addr);\\\\n access = this.currentLevel.access[addrHex];\\\\n if (access == null) {\\\\n access = {\\\\n reads: {},\\\\n writes: {}\\\\n };\\\\n this.currentLevel.access[addrHex] = access;\\\\n }\\\\n if (opcode === 'SLOAD') {\\\\n // read slot values before this UserOp was created\\\\n // (so saving it if it was written before the first read)\\\\n if (access.reads[slotHex] == null && access.writes[slotHex] == null) {\\\\n access.reads[slotHex] = toHex(db.getState(addr, slot));\\\\n }\\\\n }\\\\n else {\\\\n this.countSlot(access.writes, slotHex);\\\\n }\\\\n }\\\\n if (opcode === 'KECCAK256') {\\\\n // collect keccak on 64-byte blocks\\\\n ofs = parseInt(log.stack.peek(0).toString());\\\\n len = parseInt(log.stack.peek(1).toString());\\\\n // currently, solidity uses only 2-word (6-byte) for a key. this might change..\\\\n // still, no need to return too much\\\\n if (len > 20 && len < 512) {\\\\n // if (len === 64) {\\\\n this.keccak.push(toHex(log.memory.slice(ofs, ofs + len)));\\\\n }\\\\n }\\\\n else if (opcode.startsWith('LOG')) {\\\\n count = parseInt(opcode.substring(3));\\\\n ofs = parseInt(log.stack.peek(0).toString());\\\\n len = parseInt(log.stack.peek(1).toString());\\\\n topics = [];\\\\n for ( i = 0; i < count; i++) {\\\\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\\\\n topics.push('0x' + log.stack.peek(2 + i).toString(16));\\\\n }\\\\n data = toHex(log.memory.slice(ofs, ofs + len));\\\\n this.logs.push({\\\\n topics,\\\\n data\\\\n });\\\\n }\\\\n }\\\\n }\\\"}],\\\"id\\\":245,\\\"jsonrpc\\\":\\\"2.0\\\"}\", requestMethod=\"POST\", url=\"http://geth21153:8545\", code=SERVER_ERROR, version=web/5.7.1)" }, payload={ "id": 4, "jsonrpc": "2.0", "method": "eth_sendUserOperation", "params": [ { "callData": "0xab4ed83e00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", "callGasLimit": "0x5618", "initCode": "0xe619ebe8ec922d5cc2197eebe6e8bf5c257f3e471688f0b9000000000000000000000000dac3ef1edc18f3022c380e5737df50283085186a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000490000000000000000000000000000000000000000000000000000000000000184b63e800d00000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a51c1fc2f0d1a1b8494ed1fe312d7c3a78ed91c00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000a51c1fc2f0d1a1b8494ed1fe312d7c3a78ed91c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000004a798b2b10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "maxFeePerGas": "0x1160565202", "maxPriorityFeePerGas": "0x1000000000", "nonce": "0x0", "paymasterAndData": "0x", "preVerificationGas": "0xd3df", "sender": "0xd5139e80c58d3B2A91996E7b5Eb91A451D6E2Aab", "signature": "0x000000000000000000000000000000000000000000000000000000000000012001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000180353a3ed5a0441919f1c639a46931de872ac3357de2ce5aa2d68c2639df54189d0000000000000000000000000000000000000000000000000000000000000024655c9a457615aac594d92fb6d842f0e910e5ee6677cddbcddaea624f3203f0e77b71a302b06c91a52b9c4ba5a7fb85226738b02c144e8ee177d034022a79c946fdf8bce27f54e06f3aee3b6a542db1ab1f2418d7370a78b150d06965f942b14a470cdee69ab50e610c39b840681bf816b030f4a0a5d5af02ce27dcce6bede89f0000000000000000000000000000000000000000000000000000000000000025f8e4b678e1c62f7355266eaa4dc1148573440937063a46d848da1e25babbd20b010000004d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000897b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a224e546f2d3161424547526e78786a6d6b61544865687972444e5833697a6c7169316f776d4f643955474a30222c226f726967696e223a2268747470733a2f2f66726573682e6c65646765722e636f6d222c2263726f73734f726967696e223a66616c73657d0000000000000000000000000000000000000000000000", "verificationGasLimit": "0x0b83b0" }, "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" ] }, code=UNKNOWN_ERROR, version=6.6.7)
In geth stdout/err:
WARN [11-28|10:58:03.431] Served debug_traceCall conn=172.18.0.3:33728 reqid=245 duration=5.010217559s err="execution timeout at parseStringValue (bigInt:1:25261(161)) at step (<eval>:64:31(40)) in server-side tracer function 'step'"
The key error message in here is execution timeout at parseStringValue..."method\\\":\\\"debug_traceCall
. By default, Geth debug tracers have a timeout of 5 seconds, and simulation of our plugin is exceeding that (duration=5.010217559s
)
The bundler's TraceConfig
looks like it supports a custom timeout, but there is no way to pass configuration down to that from the top level.
It may be worth considering having a (optional?) golang/native geth tracer plugin rather than the injected one in JS to improve performance during UserOp simulation
use getblock rpc, send req to https://matic.getblock.io/${GETBLOCK_ID}/testnet/
{
"method": "debug_traceCall",
"params": [
{
"from": "0x0000000000000000000000000000000000000000",
"to": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
"data": "0xee21942300000000000000000000000000000000000000000000000000000000000000200000000000000000000000009996e688f6f345651c278611ca070c40e085e6de0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000005600000000000000000000000000000000000000000000000000000000000005fb93000000000000000000000000000000000000000000000000000000000000affc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000589406cc6185a346906296840746125a0e449764545fbfb9cf000000000000000000000000ae72a48c1a36bd18af168541c53037965d26e4a8000000000000000000000000000000000000000000000000000001881e34e3d4000000000000000000000000000000000000000000000000000000000000000000000000000000a4b61d27f60000000000000000000000009996e688f6f345651c278611ca070c40e085e6de000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004b0d691fe000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041d33d715561d2488d95afc4a6c29699e62d43b20928271bb611945c86c1aee37816e0a386df3f7070aca1c4b2a362e29ade912b0c02505f310e950203848561051b00000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x06ab8f"
},
"latest",
{
"tracer": "{\n numberLevels: [],\n currentLevel: null,\n keccak: [],\n calls: [],\n logs: [],\n debug: [],\n lastOp: '',\n numberCounter: 0,\n fault(log, db) {\n this.debug.push('fault depth=', log.getDepth(), ' gas=', log.getGas(), ' cost=', log.getCost(), ' err=', log.getError());\n },\n result(ctx, db) {\n return {\n numberLevels: this.numberLevels,\n keccak: this.keccak,\n logs: this.logs,\n calls: this.calls,\n debug: this.debug // for internal debugging.\n };\n },\n enter(frame) {\n // this.debug.push('enter gas=', frame.getGas(), ' type=', frame.getType(), ' to=', toHex(frame.getTo()), ' in=', toHex(frame.getInput()).slice(0, 500))\n this.calls.push({\n type: frame.getType(),\n from: toHex(frame.getFrom()),\n to: toHex(frame.getTo()),\n method: toHex(frame.getInput()).slice(0, 10),\n gas: frame.getGas(),\n value: frame.getValue()\n });\n },\n exit(frame) {\n this.calls.push({\n type: frame.getError() != null ? 'REVERT' : 'RETURN',\n gasUsed: frame.getGasUsed(),\n data: toHex(frame.getOutput()).slice(0, 4000)\n });\n },\n // increment the \"key\" in the list. if the key is not defined yet, then set it to \"1\"\n countSlot(list, key) {\n var _a;\n list[key] = ((_a = list[key]) !== null && _a !== void 0 ? _a : 0) + 1;\n },\n step(log, db) {\n var _a;\n opcode = log.op.toString();\n // this.debug.push(this.lastOp + '-' + opcode + '-' + log.getDepth() + '-' + log.getGas() + '-' + log.getCost())\n if (log.getGas() < log.getCost()) {\n this.currentLevel.oog = true;\n }\n if (opcode === 'REVERT' || opcode === 'RETURN') {\n if (log.getDepth() === 1) {\n // exit() is not called on top-level return/revent, so we reconstruct it\n // from opcode\n ofs = parseInt(log.stack.peek(0).toString());\n len = parseInt(log.stack.peek(1).toString());\n data = toHex(log.memory.slice(ofs, ofs + len)).slice(0, 4000);\n // this.debug.push(opcode + ' ' + data)\n this.calls.push({\n type: opcode,\n gasUsed: 0,\n data\n });\n }\n }\n if (opcode.match(/^(EXT.*|CALL|CALLCODE|DELEGATECALL|STATICCALL)$/) != null) {\n // this.debug.push('op=' + opcode + ' last=' + this.lastOp + ' stacksize=' + log.stack.length())\n idx = opcode.startsWith('EXT') ? 0 : 1;\n addr = toAddress(log.stack.peek(idx).toString(16));\n addrHex = toHex(addr);\n if (((_a = this.currentLevel.contractSize[addrHex]) !== null && _a !== void 0 ? _a : 0) === 0 && !isPrecompiled(addr)) {\n this.currentLevel.contractSize[addrHex] = db.getCode(addr).length;\n }\n }\n if (log.getDepth() === 1) {\n // NUMBER opcode at top level split levels\n if (opcode === 'NUMBER')\n this.numberCounter++;\n if (this.numberLevels[this.numberCounter] == null) {\n this.currentLevel = this.numberLevels[this.numberCounter] = {\n access: {},\n opcodes: {},\n contractSize: {}\n };\n }\n this.lastOp = '';\n return;\n }\n if (this.lastOp === 'GAS' && !opcode.includes('CALL')) {\n // count \"GAS\" opcode only if not followed by \"CALL\"\n this.countSlot(this.currentLevel.opcodes, 'GAS');\n }\n if (opcode !== 'GAS') {\n // ignore \"unimportant\" opcodes:\n if (opcode.match(/^(DUP\\\\d+|PUSH\\\\d+|SWAP\\\\d+|POP|ADD|SUB|MUL|DIV|EQ|LTE?|S?GTE?|SLT|SH[LR]|AND|OR|NOT|ISZERO)$/) == null) {\n this.countSlot(this.currentLevel.opcodes, opcode);\n }\n }\n this.lastOp = opcode;\n if (opcode === 'SLOAD' || opcode === 'SSTORE') {\n slot = toWord(log.stack.peek(0).toString(16));\n slotHex = toHex(slot);\n addr = log.contract.getAddress();\n addrHex = toHex(addr);\n access = this.currentLevel.access[addrHex];\n if (access == null) {\n access = {\n reads: {},\n writes: {}\n };\n this.currentLevel.access[addrHex] = access;\n }\n if (opcode === 'SLOAD') {\n // read slot values before this UserOp was created\n // (so saving it if it was written before the first read)\n if (access.reads[slotHex] == null && access.writes[slotHex] == null) {\n access.reads[slotHex] = toHex(db.getState(addr, slot));\n }\n }\n else {\n this.countSlot(access.writes, slotHex);\n }\n }\n if (opcode === 'KECCAK256') {\n // collect keccak on 64-byte blocks\n ofs = parseInt(log.stack.peek(0).toString());\n len = parseInt(log.stack.peek(1).toString());\n // currently, solidity uses only 2-word (6-byte) for a key. this might change..\n // still, no need to return too much\n if (len > 20 && len < 512) {\n // if (len === 64) {\n this.keccak.push(toHex(log.memory.slice(ofs, ofs + len)));\n }\n }\n else if (opcode.startsWith('LOG')) {\n count = parseInt(opcode.substring(3));\n ofs = parseInt(log.stack.peek(0).toString());\n len = parseInt(log.stack.peek(1).toString());\n topics = [];\n for ( i = 0; i < count; i++) {\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\n topics.push('0x' + log.stack.peek(2 + i).toString(16));\n }\n data = toHex(log.memory.slice(ofs, ofs + len));\n this.logs.push({\n topics,\n data\n });\n }\n }\n }"
}
],
"id": 6297,
"jsonrpc": "2.0"
}
the resp is:
{
"jsonrpc": "2.0",
"id": 6297,
"result": {
"numberLevels": [
{
"access": {
"0x9996e688f6f345651c278611ca070c40e085e6de": {
"reads": {
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
"writes": {
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": 1,
"0x0000000000000000000000000000000000000000000000000000000000000000": 4
}
}
},
"opcodes": {
"PUSH1": 288,
"MSTORE": 123,
"CALLDATASIZE": 13,
"PUSH2": 326,
"JUMPI": 163,
"JUMPDEST": 200,
"CALLDATALOAD": 15,
"DUP1": 66,
"PUSH4": 19,
"JUMP": 148,
"CALLVALUE": 4,
"PUSH32": 24,
"PUSH8": 5,
"DUP2": 309,
"SWAP1": 78,
"DUP5": 32,
"SWAP2": 44,
"DUP3": 119,
"DUP4": 206,
"DUP7": 4,
"SWAP6": 4,
"PUSH20": 11,
"DUP6": 14,
"SWAP3": 25,
"MLOAD": 115,
"REVERT": 1,
"SWAP4": 14,
"DUP8": 8,
"SWAP5": 6,
"SWAP7": 2,
"DUP9": 5,
"CALLDATACOPY": 1,
"CALL": 1,
"CODECOPY": 5,
"PUSH28": 2,
"KECCAK256": 2,
"ADDRESS": 1,
"MSTORE8": 1,
"EXTCODESIZE": 3,
"CREATE2": 1,
"CODESIZE": 1,
"SLOAD": 7,
"SSTORE": 5,
"LOG2": 1,
"DELEGATECALL": 1,
"PUSH3": 1,
"LOG3": 1,
"LOG1": 1,
"STOP": 1,
"RETURNDATASIZE": 1,
"RETURN": 3
},
"contractSize": {
"0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789": 23689,
"0x9996e688f6f345651c278611ca070c40e085e6de": 845,
"0x7fc98430eaedbb6070b35b39d798725049088348": 528,
"0x9406cc6185a346906296840746125a0e44976454": 3238,
"0x8abb13360b87be5eeb1b98647a016add927a136c": 9247
},
"oog": true
},
{
"access": {
"0x9996e688f6f345651c278611ca070c40e085e6de": {
"reads": {
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000000000000000000000008abb13360b87be5eeb1b98647a016add927a136c",
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000ae72a48c1a36bd18af168541c53037965d26e4a80001"
},
"writes": {}
}
},
"opcodes": {
"PUSH1": 68,
"MSTORE": 16,
"CALLDATASIZE": 7,
"PUSH2": 56,
"JUMPI": 24,
"JUMPDEST": 47,
"JUMP": 28,
"PUSH32": 6,
"SLOAD": 2,
"PUSH20": 4,
"SWAP1": 31,
"DUP1": 31,
"CALLDATACOPY": 2,
"DUP5": 10,
"DELEGATECALL": 1,
"CALLDATALOAD": 6,
"PUSH4": 5,
"CALLVALUE": 1,
"DUP7": 4,
"DUP4": 9,
"PUSH8": 2,
"DUP2": 19,
"DUP8": 2,
"SWAP6": 2,
"DUP6": 9,
"SWAP5": 5,
"SWAP4": 5,
"SWAP3": 15,
"CALLER": 1,
"MLOAD": 14,
"DUP3": 11,
"KECCAK256": 1,
"SWAP2": 15,
"BYTE": 1,
"DUP10": 1,
"DUP9": 1,
"STATICCALL": 1,
"PUSH3": 1,
"RETURN": 2,
"RETURNDATASIZE": 2,
"RETURNDATACOPY": 1
},
"contractSize": {
"0x9996e688f6f345651c278611ca070c40e085e6de": 845,
"0x8abb13360b87be5eeb1b98647a016add927a136c": 9247
}
},
{
"access": {},
"opcodes": {},
"contractSize": {}
}
],
"keccak": [
"0xff9406cc6185a346906296840746125a0e44976454000000000000000000000000000000000000000000000000000001881e34e3d42a38ad9cddab72264721d9296e05bc0c03dea82c497160f8e68a159319f7f18b",
"0x19457468657265756d205369676e6564204d6573736167653a0a33326f6f706c33d0885dfe2608b436cbef56b6f159a423d883548d75d87f9821d058"
],
"logs": [
{
"topics": [
"0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b",
"0x8abb13360b87be5eeb1b98647a016add927a136c"
],
"data": "0x"
},
{
"topics": [
"0x47e55c76e7a6f1fd8996a1da8008c1ea29699cca35e7bcd057f2dec313b6e5de",
"0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789",
"0xae72a48c1a36bd18af168541c53037965d26e4a8"
],
"data": "0x"
},
{
"topics": [
"0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498"
],
"data": "0x0000000000000000000000000000000000000000000000000000000000000001"
}
],
"calls": [
{
"type": "STATICCALL",
"from": "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789",
"to": "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789",
"method": "0x957122ab",
"gas": 4294938809
},
{
"type": "REVERT",
"gasUsed": 967,
"data": "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"
},
{
"type": "CALL",
"from": "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789",
"to": "0x7fc98430eaedbb6070b35b39d798725049088348",
"method": "0x570e1a36",
"gas": 392083,
"value": "0"
},
{
"type": "CALL",
"from": "0x7fc98430eaedbb6070b35b39d798725049088348",
"to": "0x9406cc6185a346906296840746125a0e44976454",
"method": "0x5fbfb9cf",
"gas": 382834,
"value": "0"
},
{
"type": "CREATE2",
"from": "0x9406cc6185a346906296840746125a0e44976454",
"to": "0x9996e688f6f345651c278611ca070c40e085e6de",
"method": "0x60806040",
"gas": 336735,
"value": "0"
},
{
"type": "DELEGATECALL",
"from": "0x9996e688f6f345651c278611ca070c40e085e6de",
"to": "0x8abb13360b87be5eeb1b98647a016add927a136c",
"method": "0xc4d66de8",
"gas": 304319
},
{
"type": "RETURN",
"gasUsed": 26114,
"data": "0x"
},
{
"type": "RETURN",
"gasUsed": 223217,
"data": "0x60806040523661001357610011610017565b005b6100115b610027610022610074565b6100b9565b565b606061004e83836040518060600160405280602781526020016102f1602791396100dd565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b90565b60006100b47f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b905090565b3660008037600080366000845af43d6000803e8080156100d8573d6000f35b3d6000fd5b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516101079190610283565b600060405180830381855af49150503d8060008114610142576040519150601f19603f3d011682016040523d82523d6000602084013e610147565b606091505b509150915061015886838387610162565b9695505050505050565b606083156101fd5782516000036101f65773ffffffffffffffffffffffffffffffffffffffff85163b6101f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b5081610207565b610207838361020f565b949350505050565b81511561021f5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ed919061029f565b60005b8381101561026e578181015183820152602001610256565b8381111561027d576000848401525b50505050565b60008251610295818460208701610253565b9190910192915050565b60208152600082518060208401526102be816040850160208701610253565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212201cd78ab6a31213989661cff2d7d05fc9b9c38b1a848e8249e2e398659a9eb7e364736f6c634300080f0033"
},
{
"type": "RETURN",
"gasUsed": 264082,
"data": "0x0000000000000000000000009996e688f6f345651c278611ca070c40e085e6de"
},
{
"type": "RETURN",
"gasUsed": 267352,
"data": "0x0000000000000000000000009996e688f6f345651c278611ca070c40e085e6de"
},
{
"type": "CALL",
"from": "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789",
"to": "0x9996e688f6f345651c278611ca070c40e085e6de",
"method": "0x3a871cdd",
"gas": 392083,
"value": "0"
},
{
"type": "DELEGATECALL",
"from": "0x9996e688f6f345651c278611ca070c40e085e6de",
"to": "0x8abb13360b87be5eeb1b98647a016add927a136c",
"method": "0x3a871cdd",
"gas": 385448
},
{
"type": "STATICCALL",
"from": "0x9996e688f6f345651c278611ca070c40e085e6de",
"to": "0x0000000000000000000000000000000000000001",
"method": "0x0c190955",
"gas": 377981
},
{
"type": "RETURN",
"gasUsed": 3000,
"data": "0x00000000000000000000000043fa03fc9f25656063afa87f3cd5f2650459634e"
},
{
"type": "RETURN",
"gasUsed": 5055,
"data": "0x0000000000000000000000000000000000000000000000000000000000000001"
},
{
"type": "RETURN",
"gasUsed": 5613,
"data": "0x0000000000000000000000000000000000000000000000000000000000000001"
},
{
"type": "REVERT",
"gasUsed": 0,
"data": "0xe0cff05f00000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000570b50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffff00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000"
}
],
"debug": [
"fault depth=",
2,
" gas=",
4294937842,
" cost=",
0,
" err=",
"execution reverted",
"fault depth=",
1,
" gas=",
4294611117,
" cost=",
0,
" err=",
"execution reverted"
]
}
}
I am having trouble starting the bundler service after successfully deploying the EntryPoint contract.
The error is "FATAL: Invalid entryPoint contract at xxx. wrong version?"
1)Modify the JSON_RPC in scripts/test.sh as shown in the figure below
Execute ./scripts/test.sh
and an error is reported as follows.
{"jsonrpc":"2.0","id":1,"error":{"code":-32000,"message":"gas price too high: 100000000000 wei, use at most tx.gasPrice = 1 wei"}}
Our mantle testnet transactions are all set to 1wei, so modify the gasPrice
in scripts/compile.ts
to 1wei, as shown in the figure below
Execute npm run build to generate the output/deployment.json file, then execute ./scripts/test.sh to deploy the contract to Mantle.
{
"gasPrice": 1,
"gasLimit": 100000,
"signerAddress": "67318b895775b2aaa9e5330981b620af942b8c73",
"transaction": "f8a08001830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222",
"address": "47416ea33cd1e6026e199d88ae2719f5be3d321d"
}
Add the mantleTestnet
network and deterministicDeployment
configuration to hardhat.config.ts
in the account-abstraction
project.
mantleTestnet: {
accounts: {
mnemonic: mnemonic,
},
chainId: 5001,
url: 'https://rpc.testnet.mantle.xyz',
allowUnlimitedContractSize: true
}
deterministicDeployment: {
"5001": {
factory: "0x47416ea33cd1e6026e199d88ae2719f5be3d321d",
deployer: "0x67318b895775b2aaa9e5330981b620af942b8c73",
funding: "100000",
signedTx: "0xf8a08001830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222",
}
}
Execute yarn run deploy --network mantleTestnet
command to deploy EntryPoint
contract and SimpleAccountFactory
contract, the results are as follows
yarn run v1.22.15
$ ./scripts/hh-wrapper deploy --network mantleTestnet
Nothing to compile
No need to generate any newer typings.
==entrypoint addr= 0x968223e76cD2117a677EB00dC8D299213EC6F155
==SimpleAccountFactory addr= 0x6cf2E0056Bbf79eBa22ad73d2949206911c8eAc9
โจ Done in 7.37s.
According to the content deployed in the third step, modify the network
, EntryPoint
and beneficiary
in the packages/bundler/localconfig/bundler.config.json
configuration in the bundler project
{
"gasFactor": "1",
"port": "3000",
"network": "https://rpc.testnet.mantle.xyz",
"entryPoint": "0x968223e76cD2117a677EB00dC8D299213EC6F155",
"beneficiary": "0x83165f86c10898dD4a7f33bDe8e5C0e4cC90E424",
"minBalance": "1",
"mnemonic": "./localconfig/mnemonic.txt",
"maxBundleGas": 5e6,
"minStake": "1" ,
"minUnstakeDelay": 0 ,
"autoBundleInterval": 3,
"autoBundleMempoolSize": 10
}
Execute the following command to start bundler
yarn run bundler --network https://rpc.testnet.mantle.xyz --mnemonic ./localconfig/mnemonic.txt --unsafe
and then report an error
Error: missing revert data in call exception; Transaction reverted without a reason string [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (data="0x", transaction={"to":"0x968223e76cD2117a677EB00dC8D299213EC6F155","data":"0xee219423000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","accessList":null}, error={"reason":"processing response error","code":"SERVER_ERROR","body":"{\"jsonrpc\":\"2.0\",\"id\":65,\"error\":{\"code\":-32000,\"message\":\"execution reverted\"}}\n","error":{"code":-32000},"requestBody":"{\"method\":\"eth_call\",\"params\":[{\"to\":\"0x968223e76cd2117a677eb00dc8d299213ec6f155\",\"data\":\"0xee219423000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"},\"latest\"],\"id\":65,\"jsonrpc\":\"2.0\"}","requestMethod":"POST","url":"https://rpc.testnet.mantle.xyz"}, code=CALL_EXCEPTION, version=providers/5.7.2)
at Logger.makeError (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/logger/src.ts/index.ts:269:28)
at Logger.throwError (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/logger/src.ts/index.ts:281:20)
at checkError (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/providers/src.ts/json-rpc-provider.ts:66:16)
at JsonRpcProvider.<anonymous> (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/providers/src.ts/json-rpc-provider.ts:642:20)
at step (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/providers/lib/json-rpc-provider.js:48:23)
at Object.throw (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/providers/lib/json-rpc-provider.js:29:53)
at rejected (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/providers/lib/json-rpc-provider.js:21:65)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
reason: 'missing revert data in call exception; Transaction reverted without a reason string',
code: 'CALL_EXCEPTION',
data: '0x',
transaction: {
to: '0x968223e76cD2117a677EB00dC8D299213EC6F155',
data: '0xee219423000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
accessList: null
},
error: Error: processing response error (body="{\"jsonrpc\":\"2.0\",\"id\":65,\"error\":{\"code\":-32000,\"message\":\"execution reverted\"}}\n", error={"code":-32000}, requestBody="{\"method\":\"eth_call\",\"params\":[{\"to\":\"0x968223e76cd2117a677eb00dc8d299213ec6f155\",\"data\":\"0xee219423000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"},\"latest\"],\"id\":65,\"jsonrpc\":\"2.0\"}", requestMethod="POST", url="https://rpc.testnet.mantle.xyz", code=SERVER_ERROR, version=web/5.7.1)
at Logger.makeError (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/logger/src.ts/index.ts:269:28)
at Logger.throwError (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/logger/src.ts/index.ts:281:20)
at /Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/web/src.ts/index.ts:341:28
at step (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/web/lib/index.js:33:23)
at Object.next (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/web/lib/index.js:14:53)
at fulfilled (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/web/lib/index.js:5:58)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
reason: 'processing response error',
code: 'SERVER_ERROR',
body: '{"jsonrpc":"2.0","id":65,"error":{"code":-32000,"message":"execution reverted"}}\n',
error: Error: execution reverted
at getResult (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/providers/src.ts/json-rpc-provider.ts:142:28)
at processJsonFunc (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/web/src.ts/index.ts:383:22)
at /Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/web/src.ts/index.ts:320:42
at step (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/web/lib/index.js:33:23)
at Object.next (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/web/lib/index.js:14:53)
at fulfilled (/Users/dl00028ml/workspace/eip4337-bundler/node_modules/@ethersproject/web/lib/index.js:5:58)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
code: -32000,
data: undefined
},
requestBody: '{"method":"eth_call","params":[{"to":"0x968223e76cd2117a677eb00dc8d299213ec6f155","data":"0xee219423000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"latest"],"id":65,"jsonrpc":"2.0"}',
requestMethod: 'POST',
url: 'https://rpc.testnet.mantle.xyz'
}
}
FATAL: Invalid entryPoint contract at 0x968223e76cD2117a677EB00dC8D299213EC6F155. wrong version?
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Currently, 0x0576a174d229e3cfa37253523e645a78a0c91b57
is mentioned as entrypoint address
However, after deploying, 0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789
is the entrypoint address.
Let's change the address.
I am encountering a discrepancy in the behavior of associative storage while adhering to the ERC-4337 standard, particularly when deploying an Account contract via initCode
and subsequently executing a transaction.
Here's a breakdown of my setup:
mapping(address => bool) internal _reentrancyStatus
and is situated at slot 1 of my owner contract.I observed the following:
unstaked factory accessed 0x4e74b605bdaba2651fdd49d6751303a67e33b7c7 slot 0x9eb25a85dff830d4fc0f95d6af192b91783569f7c4eb4c68c5db9d950d5e061c".
Upon analyzing the error:
The mentioned slot 0x9eb25a85dff830d4fc0f95d6af192b91783569f7c4eb4c68c5db9d950d5e061c
aligns with the expected value calculated with account 0x1375Ca41d29BA02f264bB9dcF66a6cbB8B9734B4
and a mapping situated at slot 1
of the owner contract (0x4e74b605bdaba2651fdd49d6751303a67e33b7c7
).
This raises a question:
Is this behavior expected per the ERC-4337 standard? If so, why is associative storage accessible when the Account contract is deployed prior to the ERC-4337 transaction, but not when deployed via initCode
?
I am keen to understand why there's a disparity in behavior and how to mitigate this issue. Any insights or clarification on the ERC-4337 standard concerning this scenario would be highly appreciated.
Not sure if this is intended, but the function calcPreVerificationGas
is ignoring the signature field in the following function:
bundler/packages/sdk/src/calcPreVerificationGas.ts
Lines 55 to 73 in 5d24112
Should const packed = arrayify(packUserOp(p))
be changed to const packed = arrayify(packUserOp(p, false))
in order to take signature value into account? Otherwise calcPreVerificationGas
returns a lower gas value.
(+latest updated)
#87 (comment)
for an issue readers,
I made an error in my estimation of the issue and stand corrected.
UserOp users do not need to explicitly call deposit.
When the Entrypoint handles the UserOp, it will try to make the deposit directly from the user's balance as the prefund is insufficient.
https://github.com/eth-infinitism/account-abstraction/blob/9b5f2e4bb30a81aa30761749d9e2e43fee64c768/contracts/core/EntryPoint.sol#L408
However, the reason you're still getting an AA21 error in runop.ts is because of an asynchronization issue with sendTransaction.
By waiting for balance funding as follows, the problem no longer occurs.
const fundTx = await signer.sendTransaction({ to: addr, value: requiredBalance.sub(bal) }) await fundTx.wait()
I ran the following simple test procedure from the readme.
Usage:
run yarn && yarn preprocess
deploy contracts with yarn hardhat-deploy --network localhost
run yarn run bundler (or yarn run bundler --unsafe, if working with "hardhat node")
Now your bundler is active on local url http://localhost:3000/rpcTo run a simple test, do yarn run runop --deployFactory --network http://localhost:8545/ --entryPoint 0x0576a174d229e3cfa37253523e645a78a0c91b57
However, I ran into an AA21
error in the process. because that the AA user did not prefund.
So I checked the code of runop
task, it seems that it only initializes the balance of the CA, and is missing the staking to the entrypoint
.
bundler/packages/bundler/src/runner/runop.ts
Line 176 in ef0751c
const bal = await getBalance(addr)
console.log('account address', addr, 'deployed=', await isDeployed(addr), 'bal=', formatEther(bal))
// TODO: actual required val
const requiredBalance = parseEther('0.1')
if (bal.lt(requiredBalance.div(2))) {
console.log('funding account to', requiredBalance)
await signer.sendTransaction({
to: addr,
value: requiredBalance.sub(bal)
})
} else {
console.log('not funding account. balance is enough')
}
const dest = addr
const data = keccak256(Buffer.from('nonce()')).slice(0, 10)
console.log('data=', data)
await client.runUserOp(dest, data)
I replaced it with a W/A code that does a depositTo
instead of sendTransaction above, like this, and I was able to run the UserOp
normally.
await (await entrypoint.depositTo(addr, {value: requiredBalance})).wait()
Looking at the implementation of simpleAccount
, it looks like it will only be a deposit if explicitly use addDeposit
, could you please review?
Hey guys,
I'm trying to give the implementation a try but i'm facing an issue with the imports.
I ran yarn install, @account-abstraction/utils dependency appears on node_modules but I still get the error of Cannot find module. Any ideas?
We are trying to run the bundler on our Spark test net (network id: 123) which is running on Nethermind RPC node and getting this error:
{ "reason": "missing revert data in call exception; Transaction reverted without a reason string", "code": "CALL_EXCEPTION", "data": "0x", "transaction": { "to": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", "data": "0xee219423000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "accessList": null }, "error": { "reason": "processing response error", "code": "SERVER_ERROR", "body": "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32015,\"message\":\"VM execution error.\",\"data\":\"Reverted 0x\"},\"id\":50}", "error": { "code": -32015, "data": "Reverted 0x" }, "requestBody": "{\"method\":\"eth_call\",\"params\":[{\"to\":\"0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789\",\"data\":\"0xee219423000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"},\"latest\"],\"id\":50,\"jsonrpc\":\"2.0\"}", "requestMethod": "POST", "url": "https://rpc.fusespark.io/" } }
While running with a Geth local node as an example returns the following which is the expected result:
{ "reason": null, "code": "CALL_EXCEPTION", "method": "simulateValidation((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes))", "data": "0x220266b600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001b4141313320696e6974436f6465206661696c6564206f72204f4f470000000000", "errorArgs": [ { "type": "BigNumber", "hex": "0x00" }, "AA13 initCode failed or OOG" ], "errorName": "FailedOp", "errorSignature": "FailedOp(uint256,string)", "address": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", "args": [ { "sender": "0x0000000000000000000000000000000000000000", "callData": "0x", "initCode": "0x0000000000000000000000000000000000000000", "paymasterAndData": "0x", "nonce": 0, "preVerificationGas": 0, "verificationGasLimit": 100000, "callGasLimit": 0, "maxFeePerGas": 0, "maxPriorityFeePerGas": 0, "signature": "0x" } ], "transaction": { "data": "0xee219423000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "to": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" } }
We believe that the issue is somehow related to our nodes, but not sure if it is due to something that is not supported at all by Nethermind nodes, or something that should be enabled.
I already deployed EntryPoint in localhost ganacge using
yarn hardhat-deploy --network localhost
and got output like
yarn run v1.22.19
$ lerna run hardhat-deploy --stream --no-prefix -- --network localhost
lerna notice cli v5.6.2
lerna info Executing command in 1 package: "yarn run hardhat-deploy --network localhost"
$ hardhat deploy --network localhost
Nothing to compile
No need to generate any newer typings.
EntryPoint already deployed at 0x0576a174d229e3cfa37253523e645a78a0c91b57
lerna success run Ran npm script 'hardhat-deploy' in 1 package in 1.7s:
lerna success - @account-abstraction/bundler
Done in 1.95s.
After that I tried to run
yarn run bundler --unsafe
and got error saying
yarn run v1.22.19
$ yarn --cwd packages/bundler bundler --unsafe
$ ts-node ./src/exec.ts --config ./localconfig/bundler.config.json --unsafe
command-line arguments: {
config: './localconfig/bundler.config.json',
auto: false,
unsafe: true
}
Merged configuration: {"port":"3000","entryPoint":"0x0576a174D229E3cFA37253523E645A78A0C91B57","unsafe":true,"conditionalRpc":false,"gasFactor":"1","network":"http://localhost:8545","beneficiary":"0x5392E4A5Ed9E756D814a2aB903BF365beF12FCED","minBalance":"1","mnemonic":"./localconfig/mnemonic.txt","maxBundleGas":5000000,"minStake":"1","minUnstakeDelay":0,"autoBundleInterval":3,"autoBundleMempoolSize":10}
FATAL: Invalid entryPoint contract at 0x0576a174D229E3cFA37253523E645A78A0C91B57. wrong version?
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Even though this is not the ethers.js
terminology, doing this rename is more consistent with the notion of Account Abstraction as in:
Try to use the ERC4337EthersProvider
and ERC4337EthersSigner
in the sdk. And I have a suggestion for the sdk.
Currently, they are intertwingled with the SimpleWallet implementation.
SimpleWallet
contract & SimpleWalletDeployer
SimpleWalletAPI
wrapProvider()
in Provider.ts
As for a showcase, it is ok.
But as a developer who is trying to use this SDK, I would like to:
MyWalletContract
, MyWalletDeployer
BaseWalletAPI
: MyWalletAPI
MyWalletAPI
I have tried this and it can work. Code snippets of mywrapProvider
:
export async function mywrapProvider (
originalProvider: JsonRpcProvider,
config: ClientConfig,
originalSigner: Signer = originalProvider.getSigner(),
walletFacotryAddress: string,
walletIndex: number = 0
): Promise<ERC4337EthersProvider> {
const entryPoint = EntryPoint__factory.connect(config.entryPointAddress, originalProvider)
const smartWalletAPI: BaseWalletAPI = new MySimpleWalletAPI({
provider: originalProvider,
entryPointAddress: config.entryPointAddress,
owner: originalSigner,
factoryAddress: walletFacotryAddress,
paymasterAPI: config.paymasterAPI,
index: walletIndex,
walletAddress:config.walletAddres
})
...
}
So maybe we can separate sdk from SimpleWallet implementation so that developers can import sdk and use it directly. Thanks for consideration.
Just a reminder folks, don't do as I did and start debugging nonsense ๐ .
Closed.
getting execution reverted error on geth console when trying to run test yarn run runop --deployFactory --network localhost
steps to reproduce this error :
`
attaching logs of geth,bundler and test console for your reference
Hey folks, I was just reading the code of the bundler's ReputationManager
module, and noticed what seems to be a small oversight.
In the getStatus
function, the code appears to be miscalculating the minimum amount of ops to be included (stored in minExpectedIncluded
local var).
According to the spec it must be:
min_expected_included = opsSeen[paymaster] // MIN_INCLUSION_RATE_DENOMINATOR
which as far as I my newbie typescript goes, should translate to:
const minExpectedIncluded = Math.floor(entry.opsSeen / this.params.minInclusionDenominator)
const minExpectedIncluded = Math.min(entry.opsSeen / this.params.minInclusionDenominator)
Hope I'm following this correctly. I'm not that familiar with the bundler's codebase yet.
import {
SimpleAccountFactory__factory,
EntryPoint__factory,
DepositPaymaster__factory,
DepositPaymaster,
EntryPoint,
} from "@account-abstraction/contracts";
const { abi1 } = require("./abi1")
import { DeterministicDeployer, HttpRpcClient, SimpleAccountAPI } from "@account-abstraction/sdk";
import { BytesLike, ethers, } from "ethers";
import { abi, bytecode } from '../artifacts/contracts/TestToken.sol/TestToken.json'
import { abi as oracleabi, bytecode as oracleBytecode } from '../artifacts/contracts/TestOracle.sol/TestOracle.json'
import { DepositPaymasterAPI } from "./DepositPaymasterApi";
import { resolveProperties } from "@ethersproject/properties";
describe('paymaster', function () {
let provider = new ethers.providers.JsonRpcProvider("https://polygon-mumbai.g.alchemy.com/v2/HncKchA59IsmRnWlOMaNq3YYSCp5DIr0");
const private_key = "7a8daa8561f32e139966ac8d35359af89be277c8707aa630ce71f24bfa8c2fee"
const signer = new ethers.Wallet(private_key, provider)
let entryPointAddress = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789";
let api: SimpleAccountAPI;
let paymaster: DepositPaymaster;
let testToken: ethers.Contract;
let factoryAddress: string;
let ownerAA: string
let entryPoint: EntryPoint;
let api2:SimpleAccountAPI
let bundlerProvider: HttpRpcClient
const age_address = "0xa7C90b6C4ab446B4C193fc65771eFAf06f52105d";
const payAddress="0x3d62238e6EBEE2631b9E7593CaC3E5F55C6e6fb6"
it("paymaster deploy", async function () {
DeterministicDeployer.init(provider)
factoryAddress = await DeterministicDeployer.deploy(new SimpleAccountFactory__factory(), 0, [entryPointAddress])
entryPoint = await new EntryPoint__factory(signer).attach(entryPointAddress);
// paymaster = await new DepositPaymaster__factory(signer).deploy(entryPoint.address)
paymaster = await new DepositPaymaster__factory(signer).attach(payAddress)
console.log(paymaster.address);
// await paymaster.deployed();
// paymaster should stake at entry point
await paymaster.addStake(1000000, { value: ethers.utils.parseEther('1'), gasLimit: 1e6 })
await entryPoint.depositTo(paymaster.address, { value: ethers.utils.parseEther('1'), gasLimit: 1e6 })
})
it("deploy token and oracle", async function () {
const tokenName = "USDT test";
const tokenSymbol = "USDT";
const price = 1; // 1 ETH = 1 USDT
const TestToken = new ethers.ContractFactory(abi, bytecode, signer);
testToken = await TestToken.deploy(tokenName, tokenSymbol);
const oracleAddr = "0xF4eF2BF0F10f7A931840c9d6E61448D492bd0667"
const testOracle = new ethers.Contract(oracleAddr, oracleabi, signer)
console.log("testToken: %s, testOracle: %s", testToken.address, testOracle.address);
// const depositPaymaster = await DepositPaymaster__factory.connect(paymaster.address, signer);
await paymaster.addToken(testToken.address, testOracle.address);
})
it("next phase", async function () {
const approve = await testToken.allowance(signer.address, paymaster.address)
const tx = await testToken.approve(paymaster.address, ethers.utils.parseEther('1000000'))
console.log('owner approve USDT to deposit paymaster, ', tx.hash);
await tx.wait()
})
it("api and op", async function () {
api = new SimpleAccountAPI({
provider,
entryPointAddress:entryPoint.address,
owner: signer,
factoryAddress,
})
ownerAA = await api.getAccountAddress()
console.log('ownerAA', ownerAA);
const ownerAAUSDTBalance = await testToken.balanceOf(ownerAA)
if (ownerAAUSDTBalance.lt(ethers.utils.parseEther('10'))) {
const tx = await testToken.transfer(ownerAA, ethers.utils.parseEther('100000'))
console.log('owner transfer 100000000 USDT to ownerAA, ', tx.hash);
await tx.wait()
}
const ownerDepositInfo = await paymaster.depositInfo(testToken.address, ownerAA);
console.log("deposit",ownerDepositInfo);
if (ethers.utils.parseEther('10').gt(ownerDepositInfo.amount)) { // prepare deposit
const tx = await paymaster.addDepositFor(testToken.address, ownerAA, ethers.utils.parseEther('10000'));
console.log('owner deposit 10000 USDT, ', tx.hash);
await tx.wait();
}
})
it("allowance and send bundler", async function () {
const bundlerUrl = "http://localhost:3000/rpc"
bundlerProvider = new HttpRpcClient(bundlerUrl, entryPoint.address, provider.network.chainId)
const allowance = await testToken.allowance(ownerAA, paymaster.address)
console.log('allowance of ownerAA to depositMaster, ', ethers.utils.formatEther(allowance));
})
it('send oue op', async function () {
const paymasterAPI = new DepositPaymasterAPI(paymaster.address, testToken.address);
const gasPrice = await provider.getGasPrice();
api2 = new SimpleAccountAPI({
provider: provider,
entryPointAddress:entryPoint.address,
owner: signer,
factoryAddress,
paymasterAPI
})
const age_interface = new ethers.utils.Interface(abi1)
const unsignedTransferOP = await resolveProperties(await api2.createUnsignedUserOp({
target: age_address,
data: age_interface.encodeFunctionData('setId', ['7']),
maxFeePerGas: gasPrice, maxPriorityFeePerGas: gasPrice
}))
// unsignedTransferOP.paymasterAndData="0x"
// console.log("recepient addr",receiptAddress)
// const userOpHash = await api2.getUserOpHash(unsignedTransferOP)
// const signature = await api2.signUserOpHash(userOpHash)
// unsignedTransferOP.signature = signature
const be="0x416908b6618B72fBEa9F08F0a4F49b634f14F471"
// const {signedOp,signature} =await resolveProperties( await api2.signUserOp(unsignedTransferOP));
// console.log("use", signature);
// await bundlerProvider.sendUserOpToBundler(unsignedTransferOP)
const op = await api2.signUserOp(unsignedTransferOP);
console.log("op", op)
await entryPoint.handleOps([op],be);
})
})
this code works with no paymaster and data. but after adding paymaster and data all the test is passedd.But the the setId function is not called .HandleOps reverted
async getPaymasterAndData(userOp: Partial): Promise<string | undefined> {
return this.addr + this.token.substring(2);
}
this is paymasterAndData .
Is there any solution for this?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.