> For the complete documentation index, see [llms.txt](https://blockchain-journal-hope-mabuza.gitbook.io/blockchain-journal-hope-mabuza-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blockchain-journal-hope-mabuza.gitbook.io/blockchain-journal-hope-mabuza-docs/smart-contracts/week-10-aa-erc-4337-and-smart-wallets-bundler.md).

# Week 10 : AA, ERC-4337 and Smart Wallets (Bundler)

### Monday - 06 April

This script is basically me implementing ERC-4337 account abstraction.

Instead of sending a normal Ethereum transaction, I’m building a **UserOperation** (UserOp), signing it, and sending it to a **bundler (Alchemy)**. The bundler is the one that actually turns it into a real on-chain transaction.

So the flow is different from normal txs.

Key pieces involved:

* **EntryPoint** → the main contract that handles everything (validation + execution)
* **Smart Contract Account (SCA)** → the wallet (not an EOA)
* **Bundler (Alchemy)** → sits off-chain, takes UserOps, batches them, and submits them00

<figure><img src="/files/sUNmKUggyBrSjNAcartf" alt=""><figcaption></figcaption></figure>

#### Signers + EntryPoint

I get my signer (user1 = owner of the smart account), then connect to EntryPoint.

Important part:

* I’m not deploying EntryPoint, I’m attaching to an existing one
* This is the contract that will later verify and execute the UserOp

#### Deploy AccountFactory

I deploy a factory contract.

Main idea:

* Factory uses **CREATE2**
* That means I can know the SCA address *before it exists*

<figure><img src="/files/Tp4Rg2FQXAwjoJwKKpJT" alt=""><figcaption></figcaption></figure>

#### Predict SCA Address (no deployment)

I use `.staticCall()` to simulate deployment.

So:

* No transaction happens
* I still get the exact address

The actual deployment happens later inside the UserOp.

#### Build `initCode`

This tells EntryPoint how to deploy the account *if it doesn’t exist*.

Structure:

* factory address
* encoded function call (`createAccount`)

If the account already existed → this would just be `"0x"`.

#### Fund the Account (EntryPoint deposit)

I deposit ETH into EntryPoint for the SCA.

Important shift in thinking:

* Gas is NOT paid directly from my wallet
* The SCA has a **deposit inside EntryPoint**
* Gas gets deducted from there

So this is basically prepaying gas.

#### Build `callData`

This is what the account will execute.

Right now:

* just calling `execute()`

But this could be anything:

* send ETH
* interact with DeFi
* mint NFT

The SCA becomes the `msg.sender` for whatever I encode.

<figure><img src="/files/PxJdoZCEqhtpU5eKl3lf" alt=""><figcaption></figcaption></figure>

#### Build the UserOperation

This is the core object.

It’s basically a “transaction”, but not really.

Fields that mattered most to me:

* `sender` → the SCA (even if not deployed yet)
* `nonce` → from EntryPoint (not from EOA)
* `initCode` → deploy logic
* `callData` → what to execute
* gas fields → initially empty
* `signature` → dummy for now

At this stage, it’s incomplete.

<figure><img src="/files/nb6lUwyZbvWyexcGfxvw" alt=""><figcaption></figcaption></figure>

#### Gas Estimation (Alchemy)

This is where Alchemy becomes necessary.

I call:

* `eth_estimateUserOperationGas`

Key realization:

> This is NOT a normal RPC method.\
> Hardhat / Infura won’t understand it.

Only bundlers support this.

Also:

* the dummy signature is required so simulation doesn’t break

#### Gas Prices

I fetch EIP-1559 values.

* `maxFeePerGas` → from network
* `maxPriorityFeePerGas` → I hardcode a small tip

Bundlers need that incentive to include my UserOp.

#### Hash the UserOp

I call `getUserOpHash()` on EntryPoint.

Important:

* I don’t sign the raw object
* I sign the hash

Also includes chain ID → prevents replay across chains.

#### Sign

I sign using `signMessage`.

This is EIP-191 style.

Important detail:

* I convert hash → bytes first
* otherwise it would get double-prefixed

My account contract must verify using the same logic.

#### Send to Bundler

I call:

* `eth_sendUserOperation`

Again:

* not a normal RPC call

What happens:

1. Bundler validates it
2. Adds it to **alt mempool**
3. Batches with other UserOps
4. Sends a real tx → `handleOps()`

Return value:

* `UserOpHash` (used for tracking)

#### Poll for Result

I try to fetch:

* `eth_getUserOperationByHash`
* `eth_getUserOperationReceipt`

I used `setTimeout`, but this is kinda unreliable.

### Why I Used Alchemy

Standard nodes don’t support ERC-4337.

Alchemy gives me:

* `eth_estimateUserOperationGas`
* `eth_sendUserOperation`
* `eth_getUserOperationByHash`
* `eth_getUserOperationReceipt`

Without a bundler, none of this works.

<figure><img src="/files/urZZDGuJ9OgmPDyP104v" alt=""><figcaption></figcaption></figure>

#### Where to actually see it

Alchemy dashboard:

* shows UserOp status
* shows when it gets included
* links it to the actual transaction
