Code Monkey home page Code Monkey logo

bundler's People

Contributors

0xbigboss avatar 0xsulpiride avatar alex-miao avatar andreas-papageorgiou avatar ankurdubey521 avatar arc0035 avatar delaaxe avatar derekchiang avatar drortirosh avatar forshtat avatar gooong avatar hazim-j avatar jayden-sudo avatar kristofgazso avatar leekt avatar maksimfedin avatar naddison36 avatar plusminushalf avatar ququzone avatar rachosuar avatar shahafn avatar skyh24 avatar skypigr avatar tconnolly11 avatar tinchoabbate avatar weiihann avatar zihaoccc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bundler's Issues

Error using `yarn preprocess`

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.

No waiting status update after sending transaction

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.

Facing Issue saying "wrong version?"

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.

`preVerificationGas` calculation seems incorrect

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.

Problems with run Bundler: FATAL: Invalid entryPoint contract at xxx. wrong version?

Description

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?"

Environment

  • Network๏ผšMantle testnet(eip1559 is not supported)
  • bundler version: v0.5.0
  • account abstraction version: v0.5.0

Steps to Reproduce

1. Deterministic-deployment-proxy deployment on Mantle testnet

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"
}

2. Deploy the EntryPoint contract to Mantle testnet

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.

3. Run the bundler service

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.

Question on user operation creation

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?

clientVersion breaks webpack

How to reprodcue

  1. sync to v0.4.0
  2. at repo root, run yarn && yarn preprocess
  3. go to 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

Root Cause: Path Resolution

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
  }`

Solution

Maybe we should just hard code the version in clientVersion()?

`preVerificationGas` cannot be changed when using `VerifyingPaymaster`

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

  1. The simplest way is to omit preVerificationGas field in VerifyingPaymaster.sol
    or
  2. The other solution is to pre-calculate preVerificationGas with exact number of words in calcPreVerificationGas or resersve some words in calcPreVerificationGas

I prefer the first solution, which will modify the contract.

Facing Revert Error on geth logs

getting execution reverted error on geth console when trying to run test yarn run runop --deployFactory --network localhost

steps to reproduce this error :
`

  1. docker run --rm -ti --name geth -p 8545:8545 ethereum/client-go:v1.10.26
    --miner.gaslimit 12000000
    --http --http.api personal,eth,net,web3,debug
    --http.vhosts '*,localhost,host.docker.internal' --http.addr "0.0.0.0"
    --ignore-legacy-receipts --allow-insecure-unlock --rpc.allow-unprotected-txs
    --dev
    --verbosity 2
    --nodiscover --maxpeers 0 --mine --miner.threads 1
    --networkid 1337
  2. yarn && yarn preprocess
    3.yarn hardhat-deploy --network localhost
    4.yarn run bundler
    5.yarn run runop --deployFactory --network http://localhost:8545/ --entryPoint 0x0576a174d229e3cfa37253523e645a78a0c91b57`

attaching logs of geth,bundler and test console for your reference
Screenshot from 2023-03-28 17-12-21
Screenshot from 2023-03-28 17-09-56
Screenshot from 2023-03-28 17-09-46

Minor miscalculation of minimum amount of ops to be included while calculating status.

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)

But the code is now doing:

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.

Failed at running `yarn preprocess`

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.

Can current sdk work with paymaster?

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:

  • createUnsignedUserOp
  • calcPreVerificationGas
  • packUserOp(p)

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==")

`BundleManager.handlePastEvents` may exceed JSON RPC response size limit

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/...'

Runop seems does not make a deposit to the entrypoint

(+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/rpc

To 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.

await signer.sendTransaction({

  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?

HandleOps reverted with paymasterAndData

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?

Update EntryPoint address in README

Currently, 0x0576a174d229e3cfa37253523e645a78a0c91b57 is mentioned as entrypoint address

However, after deploying, 0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789 is the entrypoint address.

Let's change the address.

Cannot find module even with dependencies installed

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?

Tracing failed: fee cap less than block base fee: address 0x000000000000000000000000000000000000000 (Erigon?)

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: ledgerwatch/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.

Test docker fails to run

When running the docker-compose in dockers/test, the bundle container fails to run with the error below.

Launch:

$ ./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 "$@"

Environment with the problem:

  • docker image ls:
accountabstraction/bundler      latest        9841ce9e49d2   5 months ago    194MB

Bundler fails to start

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?

TypeError: Cannot read properties of undefined (reading 'validateInputParameters')

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')

Aborted: Cannot read properties of undefined (reading '_clientVersion')

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?

Change the type of index on the SimpleAccountApiParams interface to BigNumberish

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)
  }

Trying to deployFactory getting data,slice is not a function

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'
}

Suggestion: separating sdk from SimpleWallet implementation

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:

  • write my wallet contract: MyWalletContract, MyWalletDeployer
  • implement my wallet API extending BaseWalletAPI: MyWalletAPI
  • my own wrapProvider which uses my own 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.

Allow configuration of timeout on Geth JS tracer

Summary

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.

Versions used

Geth version: v1.13.5
Bundler version v0.6.2

Details

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.

Future improvements

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

Upgrading main branch to Ethers V6

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:

  1. Is there a plan to upgrade main to ethers v6 in the future, if so is there any timeline?
  2. Do you have any recommendation as to our approach?

Send ether from account wallet

`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?

`BUFFER_OVERRUN` while simulating validation

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:

const data = toHex(log.memory.slice(ofs, ofs + len)).slice(0, 1000)

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:

const {
name: errorName,
args: errorArgs
} = this.entryPoint.interface.parseError(data)

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.

runop: getDefaultProvider error

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?

@account-abstraction/sdk TypeError: class constructors must be invoked with 'new'

env

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]

error

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

code

https://github.com/web3well/eth-global-lisbon-hackathon/blob/1d53cb7aa4f6d00d904156e88bd06f7b1841f5b1/frontend/src/app/page.tsx#L28

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) });

workaround

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.

no formatting rules provided

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.

Missing revert data in call exception instead of expected FailedOp

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.

Simulate validation does not enforce MIN_STAKE and MIN_UNSTAKE_DELAY configuration parameters

The check for unstake delay in the reference bundler implementation

https://github.com/eth-infinitism/bundler/blob/a1cab449a45c991215648fe77b10148cc6466d62/packages/bundler/src/parseScannerResult.ts#L322C19-L323

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?

const validationManager = new ValidationManager(entryPoint, reputationManager, config.unsafe)

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

`getTransactionReceipt` only works if you call it within the timespan of current block

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).

const res = await this.entryPoint.queryFilter(filter, 'latest')

Bundler considers EOA is an un-deployed SA

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.

too high verificationgaslimit

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.

Should calcPreVerificationGas ignore signature field when calculating callDataCost?

Not sure if this is intended, but the function calcPreVerificationGas is ignoring the signature field in the following function:

export function calcPreVerificationGas (userOp: Partial<NotPromise<UserOperationStruct>>, overheads?: Partial<GasOverheads>): number {
const ov = { ...DefaultGasOverheads, ...(overheads ?? {}) }
const p: NotPromise<UserOperationStruct> = {
// dummy values, in case the UserOp is incomplete.
preVerificationGas: 21000, // dummy value, just for calldata cost
signature: hexlify(Buffer.alloc(65, 1)), // dummy signature
...userOp
} as any
const packed = arrayify(packUserOp(p))
const callDataCost = packed.map(x => x === 0 ? ov.zeroByte : ov.nonZeroByte).reduce((sum, x) => sum + x)
const ret = Math.round(
callDataCost +
ov.fixed / ov.bundleSize +
ov.perUserOp +
ov.perUserOpWord * packed.length
)
return ret
}

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.

Incorrect return parameter name from `HttpRpcClient.estimateUserOpGas` function on `@account-abstraction/sdk` node module

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

screenshot-2023-08-06-12-20-53

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.

polygon/mumbai always returns `OOG` when debug_traceCall_SimulateValidation

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"
        ]
    }
}

run `runop.ts` several times and get an error

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);
    }

abi.map is not a function

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

Rename `Wallet` instances to `Account`

Even though this is not the ethers.js terminology, doing this rename is more consistent with the notion of Account Abstraction as in:

  • Wallet: UI / client software that manages accounts
  • Account: on-chain object that holds funds

stop with one hour

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?

Issue with Associative Storage Accessibility During Account Deployment

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:

  • I have an owner contract that manages the reentrancy status of my Account contract.
  • The reentrancy guard is defined as mapping(address => bool) internal _reentrancyStatus and is situated at slot 1 of my owner contract.
  • The key for this mapping is the address of my Account contract.

I observed the following:

  • When the Account contract is already deployed, the associative storage functions as expected.
  • However, when deploying the Account contract through initCode first, followed by executing a transaction, I encounter an error:
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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.