Dalam , sebuah akun pintar didistribusikan dan UserOperation pertama berhasil dijalankan melalui EntryPoint. Pada saat itu, semuanya berhasil — tetapi bagian penting dari sistem sebagian besar tetap tidak terlihat: bundler. Bagian 1 Bundler adalah jembatan antara abstraksi akun dan lapisan eksekusi Ethereum. Mereka mengambil UserOperations dari mempool terpisah, membayar biaya gas terlebih dahulu, dan dikembalikan melalui protokol. Memahami bagaimana mereka bekerja - aturan validasi, sistem reputasi, dan insentif ekonomi - sangat penting untuk memecahkan masalah dan membangun aplikasi yang dapat diandalkan. Siklus Kehidupan Operasi UserOperation adalah unit dari paket kerja yang beroperasi, yang mencakup semua yang diperlukan untuk melakukan tindakan atas nama akun pintar – otorisasi, pembatasan gas, data panggilan eksekusi, dan logika paymaster opsional. Dalam EntryPoint v0.8, UserOperations diproses dalam rantai dalam format yang dikemas, dioptimalkan gas. Ketika bekerja dengan SDK seperti permissionless.js, mereka diwakili sebagai struktur eksplisit, tidak dikemas: type UserOperation = { sender: Address nonce: bigint factory?: Address // Account factory (for first-time deployment) factoryData?: Hex // Factory calldata callData: Hex callGasLimit: bigint verificationGasLimit: bigint preVerificationGas: bigint maxFeePerGas: bigint maxPriorityFeePerGas: bigint paymaster?: Address paymasterVerificationGasLimit?: bigint paymasterPostOpGasLimit?: bigint paymasterData?: Hex signature: Hex } Pada rantai, EntryPoint menggunakan format yang dikemas untuk efisiensi gas (menggabungkan bidang seperti SDK menangani kemasan ini secara otomatis – Anda tidak perlu khawatir tentang hal itu. accountGasLimits = verificationGasLimit | callGasLimit Siklus hidup UserOperation terlihat seperti ini: Pengguna membangun UserOp dengan SDK akun cerdas mereka (seperti permissionless.js) Menandatangani: Pengguna menandatangani UserOp hash, membuktikan bahwa mereka mengautorisasi tindakan Submission: UserOp dikirim ke bundler melalui eth_sendUserOperation Validasi: Bundler mensimulasikan UserOp untuk memeriksa apakah itu akan berhasil Mempool: Jika valid, UserOp memasuki mempool bundler Bundling: Bundler mengumpulkan beberapa UserOps ke dalam satu panggilan handleOps Eksekusi: Kontrak EntryPoint memvalidasi setiap UserOp pada rantai, kemudian mengeksekusi mereka : EntryPoint collects gas costs from each account (or their paymaster). Payment Key insight adalah bahwa validasi terjadi dua kali: sekali off-chain oleh bundler (untuk memutuskan apakah untuk menerima UserOp), dan sekali on-chain oleh EntryPoint (sebelum benar-benar melakukan). Setiap aturan validasi ada untuk menghilangkan kelas serangan di mana UserOp melewati simulasi tetapi gagal pada rantai. Validasi: Mengapa Bundlers Paranoid Bundler membayar biaya gas terlebih dahulu.Jika Operasi Pengguna gagal pada rantai setelah dimasukkan ke dalam paket, kerugian adalah milik mereka.Tidak ada pengembalian dana, tidak ada pengembalian dana. Fakta tunggal ini mendefinisikan seluruh model ancaman bundler. Antara simulasi dan inklusi, keadaan Ethereum tidak statis. parameter blok bergeser, keseimbangan berubah, dan transaksi lawan dapat mendarat di antara. UserOperation yang dirancang dengan hati-hati dapat melewati simulasi rantai dan masih gagal selama validasi rantai - mengubah bundler menjadi sumur gas. ERC-4337 menanggapi dengan sangat membatasi apa yang diperbolehkan kode validasi untuk dilakukan. EntryPoint menegakkan pemisahan kekhawatiran yang ketat: : Validasi akunFungsi UserOp berjalan untuk memverifikasi tanda tangan dan mengautorisasi operasi.Fase ini memiliki batasan ketat pada apa opcodes dan penyimpanan kode dapat diakses. Validation Phase : Fungsi eksekusi akun menjalankan operasi sebenarnya. tidak ada batasan di sini — kemampuan EVM penuh. Execution Phase larangan kode Kode opsi tertentu dilarang selama validasi karena nilai mereka dapat berubah antara simulasi dan eksekusi: TIMESTAMP, NUMBER, COINBASE, PREVRANDAO: Nilai tergantung blok. Akun dapat memeriksa jika (block.timestamp > deadline) kembali, melewati simulasi, kemudian gagal ketika bundel mendarat di blok berikutnya. BLOCKHASH: Mengembalikan nilai yang berbeda untuk blok yang berbeda. GASPRICE, BASEFEE: Perubahan berdasarkan kondisi jaringan. BALANCE, SELFBALANCE: Hanya diizinkan dari entitas yang berkepentingan (lihat Staking di bawah) per ERC-7562 [OP-080]. GASLIMIT, ORIGIN: Dapat bervariasi antara lingkungan simulasi dan eksekusi sebenarnya. BLOBHASH, BLOBBASEFEE: EIP-4844 blob terkait opkode yang bervariasi per blok. SELFDESTRUCT, INVALID: kode opsi destruktif tidak diizinkan selama validasi. GAS: Hanya diperbolehkan jika segera diikuti oleh instruksi *CALL—CALL, DELEGATECALL, STATICCALL, atau CALLCODE (untuk pengiriman gas ke kontrak lain). CREATE: Secara umum dilarang karena membuat kontrak di alamat yang tidak dapat diprediksi. Namun, CREATE diizinkan untuk kontrak pengirim ketika menggunakan pabrik yang tidak terikat. CREATE2 diizinkan tepat sekali selama pengembangan untuk kontrak pengirim. Berikut ini yang terjadi ketika akun Anda menggunakan opcode yang dilarang: // This validateUserOp will be rejected by bundlers function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds) external returns (uint256 validationData) { // BANNED: block.timestamp can change require(block.timestamp < deadline, "Expired"); // ... rest of validation } bundler menjalankan jejak selama simulasi (menggunakan dengan tracer yang sesuai dengan ERC-7562) dan menolak UserOp yang validasi menyentuh opcode yang dilarang. bundler modern dapat menggunakan baik tracer JavaScript atau implementasi Go asli yang diperkenalkan dengan EntryPoint v0.8. debug_traceCall Aturan Akses Penyimpanan Selain kode opsi, bundler membatasi kode validasi slot penyimpanan yang dapat dibaca dan ditulis. aturan (dari ERC-7562) adalah: Hanya dapat diakses: Unstaked entities Penyimpanan sendiri (penyimpanan akun) Slot penyimpanan yang "terhubung" dengan alamat akun A, didefinisikan sebagai: nilai slot sama dengan A, OR dihitung sebagai keccak256(A Átha Cliath x) + n di mana x adalah bytes32 dan n berada di kisaran 0 hingga 128 Dalam prakteknya, ini berarti akun Anda dapat membaca / menulis ke mapping di mana alamat akun adalah kunci. Penyimpanan yang sebenarnya adalah Jika alamat akun Anda adalah kunci, slot itu "terhubung" dengan Anda. offset (0-128) memungkinkan akses ke struktur anggota yang disimpan setelah entri mapping – berguna ketika nilai mapping adalah struktur. mapping(address => uint256) balances keccak256(address || slot_of_mapping) +n (akun, paymaster, atau pabrik yang telah menyetorkan saham di EntryPoint) mendapatkan lebih banyak kebebasan: Staked entities Dapat mengakses setiap slot di penyimpanan mereka sendiri (STO-031) Dapat mengakses penyimpanan terkait dari setiap entitas di UserOp (STO-032) Dapat memiliki akses hanya membaca ke penyimpanan dalam kontrak non-entitas (STO-033) See the full storage access rules in . KPK 7562 Why do these rules exist? Consider two UserOperations that read from the same storage slot during validation. If the first operation mutates that slot, the second operation’s validation assumptions may no longer hold. By restricting storage access during validation, bundlers can safely include multiple UserOperations in the same bundle without risking cross-operation interference or non-deterministic failures. Sistem Reputasi Bahkan dengan aturan validasi, entitas dapat berperilaku buruk. akun dapat secara konsisten mengirimkan UserOps yang melewati simulasi tetapi gagal pada rantai karena perubahan status halus. seorang paymaster mungkin menyetujui UserOps selama simulasi tetapi menolak pembayaran pada rantai. Bundlers track these entities with a Untuk setiap entitas (alamat akun, alamat paymaster, alamat pabrik), bundler melacak: reputation system : How many UserOps involving this entity has the bundler seen opsSeen : How many of those actually got included on-chain opsIncluded Status reputasi ditentukan oleh ambang batas berbasis slack (definisikan dalam ): KPK 7562 maxSeen = opsSeen / MIN_INCLUSION_RATE_DENOMINATOR (10 for bundlers) status = BANNED if maxSeen > opsIncluded + BAN_SLACK (50) status = THROTTLED if maxSeen > opsIncluded + THROTTLING_SLACK (10) status = OK otherwise Nilai "slack" adalah toleransi buffer yang mencegah positif palsu dari varians operasi normal. Ini berarti bahwa suatu entitas dapat memiliki hingga 10 lebih banyak inklusi yang diharapkan daripada inklusi yang sebenarnya sebelum ditransfer. Desain ini mengakui bahwa beberapa UserOps secara sah gagal (kondisi jaringan, kondisi ras) tanpa menunjukkan perilaku berbahaya. THROTTLING_SLACK = 10 BAN_SLACK = 50 Ketika suatu entitas adalah , bundler membatasi berapa banyak UserOps dari entitas itu dapat berada di mempool. , semua UserOps yang melibatkan entitas tersebut segera ditolak. throttled banned mogok Entities can improve their standing by staking ETH in the EntryPoint contract: entryPoint.addStake{ value: 1 ether }(unstakeDelaySec); Taruhan tidak dipotong - itu hanya terkunci. tetapi itu menunjukkan komitmen dan hibah: Aturan akses penyimpanan yang santai (seperti yang dijelaskan di atas) Higher mempool limits Batasan reputasi yang lebih rendah Untuk paymasters dan pabrik, terutama, staking hampir wajib untuk penggunaan produksi. Tanpa itu, satu UserOp gagal dapat dengan cepat mendapatkan entitas throttled. (chain-specific, typically 1 ETH or equivalent) and Jumlah taruhan yang tepat bervariasi berdasarkan rantai dan didefinisikan dalam metadata mempool – periksa dokumentasi bundler untuk jaringan target Anda. MIN_STAKE_VALUE MIN_UNSTAKE_DELAY Ekonomi Gas Bundlers are businesses. They pay gas costs to submit bundles and get reimbursed from the UserOps they include. The economics work like this: The Bundler's Perspective Revenue = Σ (each UserOp's payment to beneficiary) Cost = Gas used × Gas price paid for handleOps tx Profit = Revenue - Cost Setiap UserOp membayar berdasarkan penggunaan gas dan harga gas yang ditentukan: Payment = (actualGasUsed + preVerificationGas) × min(maxFeePerGas, baseFee + maxPriorityFeePerGas) Bundle yang menetapkan address in the memanggil untuk menerima pembayaran tersebut. beneficiary handleOps PreverifikasiGas dijelaskan yang field covers costs that can't be directly metered: preVerificationGas : 16 gas per non-zero byte, 4 gas per zero byte Calldata cost Bundle overhead: Biaya tetap per panggilan handleOps yang diamputasi di UserOps Biaya data L2: Pada L2 seperti Optimism atau Arbitrum, mengirimkan data panggilan ke L1 memiliki biaya tambahan Ketika memperkirakan gas, bundler menghitung preVerificationGas berdasarkan ukuran UserOp: // Simplified preVerificationGas calculation const calldataCost = userOpBytes.reduce((sum, byte) => sum + (byte === 0 ? 4n : 16n), 0n ); const overhead = 38000n; // ~21000 tx base + ~10000 bundle overhead + ~7000 per-op preVerificationGas = calldataCost + overhead + l2DataFee; Nilai overhead bervariasi menurut bundler. untuk referensi, Alto menggunakan , yang , yang Selalu Gunakan bukannya hardcoding. transactionGasStipend: 21000 fixedGasOverhead: 9830 perUserOp: 7260 eth_estimateUserOperationGas Hukuman Gas yang Tidak Digunakan To prevent users from overpaying for gas (which wastes blockspace), the EntryPoint imposes a penalty on unused execution gas. Specifically, the penalty applies to (untuk eksekusi akun) dan (untuk transaksi pasca-transaksi dari paymaster): callGasLimit paymasterPostOpGasLimit Jika gas yang tidak digunakan di kedua bidang melebihi PENALTY_GAS_THRESHOLD (40.000), akun membayar 10% (UNUSED_GAS_PENALTY_PERCENT) dari jumlah yang tidak digunakan (TIDAK berlaku untuk verificationGasLimit atau preVerificationGas) This discourages setting absurdly high execution limits "just to be safe" When you see gas estimation errors, check if your limits are reasonable. The bundler's Endpoint memberikan defisit yang masuk akal. eth_estimateUserOperationGas Kesalahan Umum dan Debugging Ketika UserOperation ditolak, kesalahan RPC adalah satu-satunya sinyal yang Anda dapatkan. Bundlers mengembalikan kode kesalahan terstruktur yang menjelaskan persis mengapa operasi gagal - tetapi hanya jika Anda tahu cara membacanya. AA1x: kesalahan pabrik Ini terjadi ketika Anda mendistribusikan akun baru melalui pabrik. dalam EntryPoint v0.8, Anda menentukan dan sebagai bidang terpisah (EntryPoint membungkus mereka ke dalam Secara internal : factory factoryData initCode : "sender already constructed" - The sender address already has code deployed. AA10 AA13: "initCode gagal atau OOG" - Panggilan CreateAccount pabrik gagal atau habis gas. : "initCode must return sender" - The factory returned a different address than expected. AA14 AA15: "initCode harus membuat pengirim" - Panggilan pabrik selesai tetapi tidak mengimplementasikan kode ke alamat pengirim. Periksa apakah pabrik Anda fungsi mengembalikan alamat yang diharapkan. memverifikasi pabrik diluncurkan dan didanai. Debugging createAccount AA2x: Account Validation Errors Kategori yang paling umum: : "account not deployed" - The sender address has no code and no was provided. AA20 initCode AA21: "tidak membayar prefund" - Akun tidak memiliki cukup ETH untuk menutupi biaya gas maksimum yang mungkin. AA22: "Tanggal atau tidak berakhir" - UserOp memiliki timestamp validUntil yang telah berlalu, atau timestamp validAfter yang belum tiba. : "reverted" - The account's function reverted. Check your signature validation logic. AA23 validateUserOp : "signature error" - The returned validation data indicates an invalid signature. AA24 AA25: "invalid account nonce" - nonce tidak cocok. nonce dalam ERC-4337 adalah nilai 256-bit dengan dua bagian: nonce = (keyword << 64) Iain urutan. Kunci (atas 192 bit) mengidentifikasi "lane" - Anda dapat memiliki beberapa UserOps paralel dengan kunci yang berbeda. urutan (kurang dari 64 bit) harus bertambah berturut-turut dalam setiap lane. penyebab umum: Menggunakan nonce yang sudah dimasukkan Menggunakan kunci nonce yang salah UserOp lain dengan pengirim yang sama sedang menunggu di mempool AA26: "over verificationGasLimit" - validasi akun menggunakan lebih banyak gas daripada yang ditugaskan. AA3x: Paymaster Errors : "paymaster not deployed" - The paymaster address has no code deployed. AA30 : "paymaster deposit too low" - The paymaster's deposit in the EntryPoint can't cover the gas cost. Top it up: AA31 Pendaftaran Pendaftaran Pendaftaran Pendaftaran Pendaftaran Pendaftaran Pendaftaran : "paymaster expired or not due" - Similar to AA22, but for the paymaster's validation data. AA32 : "paymaster reverted" - The paymaster's function reverted. AA33 validatePaymasterUserOp : "paymaster signature error" - Bad signature in the paymaster data. AA34 : "over paymasterVerificationGasLimit" - Paymaster validation used more gas than allocated. Increase . AA36 paymasterVerificationGasLimit Working with Bundlers Metode RPC Setiap bundler ERC-4337 menerapkan metode standar ini: : Submit a UserOp for inclusion eth_sendUserOperation const userOpHash = await bundler.request({ method: 'eth_sendUserOperation', params: [userOp, entryPointAddress] }); : Dapatkan estimasi batas gas eth_estimateUserOperationGas const gasEstimate = await bundler.request({ method: 'eth_estimateUserOperationGas', params: [userOp, entryPointAddress] }); // Returns: { preVerificationGas, verificationGasLimit, callGasLimit, ... } : Look up a UserOp by its hash eth_getUserOperationByHash const userOp = await bundler.request({ method: 'eth_getUserOperationByHash', params: [userOpHash] }); : Get the receipt after inclusion eth_getUserOperationReceipt const receipt = await bundler.request({ method: 'eth_getUserOperationReceipt', params: [userOpHash] }); // Returns: { success, actualGasUsed, receipt: { transactionHash, ... } } : Discover which EntryPoint versions the bundler supports eth_supportedEntryPoints const entryPoints = await bundler.request({ method: 'eth_supportedEntryPoints', params: [] }); // Returns: ['0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108'] The Shared Mempool Awalnya, setiap bundler mempertahankan mempool pribadinya sendiri. Risiko Censorship: Sebuah paket tunggal dapat menolak untuk memasukkan UserOps tertentu Fragmentasi: Pengguna harus tahu paket mana yang harus diajukan ke : If your bundler went down, your UserOps were stuck Single points of failure The solution is the , sebuah jaringan P2P di mana bundlers gosip UserOps satu sama lain. Ini bekerja mirip dengan bagaimana Ethereum nodes gosip transaksi: ERC-4337 shared mempool Pengguna mengirimkan UserOp ke setiap bundler yang berpartisipasi Bundler memvalidasi dan menambahkan ke mempool lokal Bundler Broadcasts untuk peer-connected Any bundler on the network can include the UserOp. The protocol uses libp2p for networking. Bundlers advertise which mempools they support (identified by IPFS CIDs that reference mempool metadata files), and only propagate UserOps that pass validation. For example, a mempool metadata file looks like: chainId: '1' entryPointContract: '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108' description: Canonical ERC-4337 mempool for Ethereum Mainnet minimumStake: '1000000000000000000' The IPFS CID of this file becomes the mempool identifier used in P2P topic names. The mempool metadata defines validation rules: which opcodes are banned, storage access patterns, gas limits, and reputation thresholds. When a bundler receives a UserOp via P2P gossip, it re-validates against its own rules before adding to its local mempool. Topik yang maju Aggregators Verifikasi tanda tangan mahal di rantai. precompilasi ecrecover biaya 3.000 gas per panggilan, tetapi verifikasi tanda tangan akun pintar biasanya lebih mahal karena logika validasi tambahan – seringkali 6.000-10.000 gas total. Untuk 100 UserOps dalam bundel, itu 600.000+ gas hanya untuk tanda tangan. agregator memungkinkan verifikasi tanda tangan batch – memverifikasi semua 100 tanda tangan dalam satu operasi untuk sebagian dari biaya. What problem do aggregators solve? Instead of each account verifying its own signature, accounts can delegate to an aggregator contract. The aggregator implements a batch verification algorithm (like BLS signatures, where multiple signatures can be combined into one). How it works: Validasi akunUserOp mengembalikan alamat agregator dalam data validasi Bundler groups all UserOps using the same aggregator Bundler calls once for the group aggregator.validateSignatures(userOps, aggregatedSignature) Jika verifikasi berlalu, semua UserOps dalam kelompok tersebut dianggap valid : The return value from Mengumpulkan tiga informasi menjadi satu nilai 256-bit: The validationData encoding validateUserOp validationData = uint160(aggregator) | // bits 0-159: aggregator address (uint256(validUntil) << 160) | // bits 160-207: expiration timestamp (uint256(validAfter) << 208) // bits 208-255: earliest valid time (bits 0-159): Address of the aggregator contract, or special values: 0 = signature valid, 1 = signature invalid aggregator validUntil (bit 160-207): Timestamp setelah yang UserOp ini berakhir (0 = tidak berakhir) (bits 208-255): Timestamp before which this UserOp is not valid (0 = immediately valid) validAfter This encoding lets accounts specify both signature verification delegation and time-bounded validity in a single return value. Pembayaran Paymasters abstrak pembayaran gas dari pengguna. alih-alih membayar rekening untuk gas, seorang paymaster dapat: Transaksi sponsor: Bayar atas nama pengguna (UX tanpa gas) : Let users pay in stablecoins or other tokens Accept ERC-20 tokens Implementasikan logika kustom: pembatasan tarif, model langganan, dll. Aliran validasi paymaster berjalan selama fase validasi: function validatePaymasterUserOp( PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost ) external returns (bytes memory context, uint256 validationData); The returned here is passed to after execution completes, allowing the paymaster to perform final accounting (like charging an ERC-20 token): context postOp function postOp( PostOpMode mode, bytes calldata context, uint256 actualGasCost, uint256 actualUserOpFeePerGas ) external; Staking memberikan aturan akses penyimpanan yang rileks dan reputasi yang lebih baik - paymasters yang tidak terikat menghadapi batasan yang ketat dan dapat dengan cepat dihancurkan oleh bundler. technically function with basic operations, staking is practically required for any serious paymaster implementation. bisa Testing Locally This section assumes you have Anvil running with EntryPoint v0.8 deployed. We'll use , Pimlico's TypeScript bundler, dan , sebuah perpustakaan berbasis viem untuk interaksi ERC-4337 . Alto permissionless.js SimpleAccountFactory In Part 1 we built a minimal smart account. But how do users deploy it? They can't send a regular transaction—they don't have ETH for gas yet. ERC-4337 solves this with factory contracts. Untuk implementasi referensi termasuk Mengimplementasikannya bersama EntryPoint sebelum menjalankan contoh di bawah ini. SimpleAccount Factory yang sederhana Account Deployment via UserOp Ketika EntryPoint menerima UserOp dengan bidang pabrik dan pabrikData: Checks if has code—if yes, skip deployment sender Telepon factory.createAccount(pemilik, garam) melalui factoryData Memeriksa alamat yang diimplementasikan yang cocok dengan pengirim Terus dengan validasi pada akun yang baru diimplementasikan Running Alto alto \ --rpc-url http://localhost:8545 \ --entrypoints 0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108 \ --executor-private-keys 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d \ --utility-private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ --safe-mode false \ --api-version v1,v2 \ --bundle-mode auto Bendera utama : : Key for submitting bundles (must have ETH) --executor-private-keys : Anvil lacks the JavaScript tracer for full ERC-7562 validation --safe-mode false : Accept both UserOp formats (v1 for 0.6, v2 for 0.7/0.8) --api-version v1,v2 Mengirim UserOperasi dengan permissionless.js Pembentukan ketergantungan : npm install viem permissionless Step 1: Set up clients Kami membutuhkan tiga klien: satu untuk status rantai membaca, satu untuk RPC khusus bundler, dan satu untuk pemilik akun pintar. import { http, createPublicClient, createWalletClient, parseEther } from "viem" import { privateKeyToAccount } from "viem/accounts" import { foundry } from "viem/chains" import { toSimpleSmartAccount } from "permissionless/accounts" import { createSmartAccountClient } from "permissionless/clients" import { createPimlicoClient } from "permissionless/clients/pimlico" const ENTRYPOINT = "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108" const publicClient = createPublicClient({ chain: foundry, transport: http("http://localhost:8545") }) const pimlicoClient = createPimlicoClient({ chain: foundry, transport: http("http://localhost:4337"), entryPoint: { address: ENTRYPOINT, version: "0.8" } }) const owner = privateKeyToAccount(process.env.PRIVATE_KEY) The terhubung ke RPC Alto dan memberikan estimasi gas melalui . pimlicoClient pimlico_getUserOperationGasPrice Step 2: Create the smart account instance const simpleAccount = await toSimpleSmartAccount({ client: publicClient, owner, entryPoint: { address: ENTRYPOINT, version: "0.8" } }) const accountAddress = await simpleAccount.getAddress() console.log("Account:", accountAddress) Ini menghitung alamat counterfactual menggunakan alamat pabrik function. The account doesn't exist yet—but we know exactly where it will be deployed. getAddress Step 3: Fund the account Akun pintar membutuhkan ETH untuk membayar gas (atau menggunakan paymaster). kita dapat mengirim ETH ke alamat counterfactual: const walletClient = createWalletClient({ account: owner, chain: foundry, transport: http("http://localhost:8545") }) await walletClient.sendTransaction({ to: accountAddress, value: parseEther("1") }) ETH berada di alamat itu. ketika akun diluncurkan, ia dapat mengakses dana tersebut segera. Step 4: Create the smart account client const smartAccountClient = createSmartAccountClient({ client: publicClient, account: simpleAccount, bundlerTransport: http("http://localhost:4337"), userOperation: { estimateFeesPerGas: async () => (await pimlicoClient.getUserOperationGasPrice()).fast } }) The menangani konstruksi UserOp, manajemen nonce, estimasi gas, dan penandatanganan. callback mengambil harga gas saat ini dari bundler. smartAccountClient estimateFeesPerGas Step 5: Send a UserOperation const hash = await smartAccountClient.sendUserOperation({ calls: [{ to: "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720", value: parseEther("0.01"), data: "0x" }] }) const receipt = await smartAccountClient.waitForUserOperationReceipt({ hash }) console.log("Success:", receipt.success) For the first UserOp, the SDK automatically includes dan EntryPoint mendistribusikan akun, lalu melakukan transfer—semua dalam satu transaksi. factory factoryData Apa yang telah kita pelajari Bundler adalah lapisan eksekusi ERC-4337. mereka adalah apa yang mengubah Account Abstraction dari spesifikasi menjadi mekanisme yang siap diproduksi. Understanding their constraints — validation rules, gas economics, and reputation mechanics — is critical when designing reliable smart accounts. Mistakes here don’t surface in Solidity code, but in mempool behavior, simulations, and execution economics. ERC-4337 shifts complexity away from the protocol and into infrastructure. The sooner developers start thinking in terms of bundlers rather than transactions, the more resilient their systems will be in production.