dalam , akaun pintar dilancarkan dan Operasi Pengguna pertama berjaya dijalankan melalui EntryPoint. Pada masa itu, segala-galanya berfungsi - tetapi sebahagian kritikal sistem kekal kebanyakan tidak kelihatan: bundler. Bahagian 1 Bundler adalah jambatan antara penyelesaian akaun dan lapisan pelaksanaan Ethereum. Mereka mengambil Operasi Pengguna dari mempool yang berasingan, membayar kos gas terlebih dahulu, dan dikembalikan melalui protokol. Memahami bagaimana mereka berfungsi - peraturan pengesahan, sistem reputasi, dan insentif ekonomi - adalah penting untuk memecahkan isu-isu dan membina aplikasi yang boleh dipercayai. Siklus Kehidupan Pengguna A UserOperation ialah unit bundler kerja yang beroperasi di dalamnya. ia merangkumi segala-galanya yang diperlukan untuk melaksanakan tindakan bagi pihak akaun pintar – pengesahan, sekatan gas, data panggilan eksekusi, dan logik paymaster opsional. Dalam EntryPoint v0.8, UserOperations dikendalikan dalam rantaian dalam format yang dioptimalkan oleh gas yang dikemas. Apabila bekerja dengan SDK seperti permissionless.js, mereka diwakili sebagai struktur yang jelas dan 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 rantaian, EntryPoint menggunakan format yang dikemas untuk kecekapan gas (menggabungkan medan seperti SDK menangani pembungkusan ini secara automatik – anda tidak perlu risau. accountGasLimits = verificationGasLimit | callGasLimit Siklus hidup Operasi Pengguna kelihatan seperti ini: Penciptaan: Pengguna membina UserOp dengan SDK akaun pintar mereka (seperti permissionless.js) Tanda tangan: Pengguna menandatangani hash UserOp, membuktikan bahawa mereka telah membenarkan tindakan : UserOp is sent to a bundler via Submission eth_sendUserOperation Pengesahan: Bundler mensimulasikan UserOp untuk memeriksa sama ada ia akan berjaya Mempool: Jika sah, UserOp memasuki mempool bundler Bundling: Bundler melengkapkan beberapa UserOps ke dalam panggilan HandOps tunggal Eksekusi: Kontrak EntryPoint mengesahkan setiap UserOp dalam rantaian, kemudian melaksanakan mereka : EntryPoint collects gas costs from each account (or their paymaster). Payment Pemahaman utama adalah bahawa pengesahan berlaku dua kali: sekali di luar rantaian oleh pembungkusan (untuk memutuskan sama ada untuk menerima UserOp), dan sekali di rantaian oleh EntryPoint (sebelum sebenarnya melaksanakan).Jika kedua-dua pengesahan ini menghasilkan hasil yang berbeza, pembungkusan kehilangan wang - membayar gas pada transaksi yang akhirnya gagal. Setiap peraturan pengesahan wujud untuk menghilangkan kelas serangan di mana UserOp lulus simulasi tetapi gagal pada rantaian. Pengesahan: Mengapa Bundlers Paranoid Bundler membayar kos gas terlebih dahulu.Jika Operasi Pengguna gagal pada rantaian selepas dimasukkan ke dalam bundle, kerugian adalah milik mereka.Tiada bayaran balik, tiada retries. Fakta tunggal ini mendefinisikan keseluruhan model ancaman bundler. Between simulation and inclusion, Ethereum state is not static. Block parameters shift, balances change, and adversarial transactions can land in between. A carefully crafted UserOperation can pass off-chain simulation and still fail during on-chain validation — turning the bundler into a gas sink. ERC-4337 bertindak balas dengan mengehadkan dengan tajam apa kod pengesahan dibenarkan untuk dilakukan. EntryPoint menguatkuasakan pemisahan ketat keprihatinan: : Fungsi validateUserOp akaun berjalan untuk mengesahkan tanda tangan dan membenarkan operasi. Tahap ini mempunyai sekatan yang ketat pada apa opcodes dan penyimpanan kod boleh diakses. Validation Phase : Fungsi eksekusi akaun menjalankan operasi sebenar. Tiada sekatan di sini – keupayaan EVM penuh. Execution Phase Kod yang dilarang Sesetengah opcode dilarang semasa pengesahan kerana nilai mereka boleh berubah antara simulasi dan pelaksanaan: TIMESTAMP, NUMBER, COINBASE, PREVRANDAO: Nilai bergantung kepada blok. Akaun boleh memeriksa jika (block.timestamp > deadline) kembali, lulus simulasi, kemudian gagal apabila bundel mendarat dalam blok kemudian. BLOCKHASH: Mengembalikan nilai yang berbeza untuk blok yang berbeza. vektor serangan yang sama. GASPRICE, BASEFEE: Perubahan berdasarkan keadaan rangkaian. BALANCE, SELFBALANCE: Hanya dibenarkan daripada entiti berkepentingan (lihat Staking di bawah) per ERC-7562 [OP-080]. GASLIMIT, ORIGIN: Boleh berbeza antara persekitaran simulasi dan pelaksanaan sebenar. BLOBHASH, BLOBBASEFEE: EIP-4844 opcodes yang berkaitan dengan blob yang berbeza per blok. SELFDESTRUCT, INVALID: Kod opsi yang merosakkan tidak dibenarkan semasa pengesahan. GAS: Hanya dibenarkan apabila segera diikuti oleh perintah *CALL—CALL, DELEGATECALL, STATICCALL, atau CALLCODE (untuk penghantaran gas kepada kontrak lain). CREATE: Biasanya dilarang kerana ia mencipta kontrak di alamat yang tidak dapat diramalkan. Walau bagaimanapun, CREATE dibenarkan untuk kontrak penghantar apabila menggunakan kilang yang tidak tertakluk. CREATE2 dibenarkan tepat sekali semasa penyebaran untuk kontrak penghantar. Berikut ialah apa yang berlaku apabila akaun 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 satu jejak semasa simulasi (menggunakan dengan tracer yang mematuhi ERC-7562) dan menolak apa-apa UserOp yang pengesahan menyentuh opcode yang dilarang. bundler moden boleh menggunakan baik tracer JavaScript atau pelaksanaan Go asli yang diperkenalkan dengan EntryPoint v0.8. debug_traceCall Peraturan Akses Penyimpanan Di luar opcodes, bundlers mengehadkan mana-mana kod pengesahan slot storage boleh dibaca dan ditulis. peraturan (dari ERC-7562) adalah kira-kira: Hanya boleh diakses: Unstaked entities Penyimpanan mereka sendiri (penyimpanan akaun) Slot penyimpanan yang "terkait" dengan alamat akaun A, ditakrifkan sebagai: nilai slot sama dengan A, OR dihitung sebagai keccak256(A Átha Cliath x) + n di mana x ialah bytes32 dan n berada dalam julat 0 hingga 128 Dalam amalan, ini bermakna akaun anda boleh membaca / menulis ke peta di mana alamat akaun adalah kunci. Penyimpanan sebenar ialah . If your account address is the key, that slot is "associated" with you. The offset (0-128) allows access to struct members stored after the mapping entry—useful when the mapping value is a struct. mapping(address => uint256) balances keccak256(address || slot_of_mapping) +n (akaun, paymaster, atau kilang yang mempunyai bahagian yang disetorkan dalam EntryPoint) mendapat lebih banyak kebebasan: Staked entities Can access any slot in their own storage (STO-031) Boleh mengakses penyimpanan yang berkaitan dengan mana-mana entiti dalam UserOp (STO-032) Boleh mempunyai akses hanya membaca kepada penyimpanan dalam kontrak bukan entiti (STO-033) Lihat peraturan akses penyimpanan penuh dalam . Sijil 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. Dengan mengehadkan capaian penyimpanan semasa pengesahan, bundler boleh dengan selamat memasukkan beberapa Operasi Pengguna dalam bundle yang sama tanpa risiko gangguan lintas-operasi atau kegagalan non-deterministik. The Reputation System Walaupun dengan peraturan pengesahan, entiti boleh bertindak buruk. akaun mungkin secara konsisten menghantar UserOps yang lulus simulasi tetapi gagal pada rantaian kerana perubahan keadaan halus. seorang paymaster mungkin mengesahkan UserOps semasa simulasi tetapi menolak pembayaran pada rantaian. Bundlers track these entities with a . For each entity (account address, paymaster address, factory address), the bundler tracks: reputation system opsSeen: Berapa banyak UserOps yang melibatkan entiti ini telah dilihat oleh bundler : How many of those actually got included on-chain opsIncluded Status reputasi ditentukan oleh sempadan berasaskan slack (ditakrifkan dalam ) : Sijil 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 The "slack" values are tolerance buffers that prevent false positives from normal operational variance. entiti boleh mempunyai sehingga 10 lebih termasuk yang dijangka daripada termasuk yang sebenar sebelum dijatuhkan. Reka bentuk ini mengakui bahawa sesetengah UserOps secara sah gagal (kondisi rangkaian, keadaan perlumbaan) tanpa menunjukkan tingkah laku berbahaya. THROTTLING_SLACK = 10 BAN_SLACK = 50 When an entity is , bundler mengehadkan berapa banyak UserOps daripada entiti itu boleh berada dalam mempool. , all UserOps involving that entity are rejected immediately. throttled banned Staking Entiti boleh meningkatkan kedudukan mereka dengan memasukkan ETH dalam kontrak EntryPoint: entryPoint.addStake{ value: 1 ether }(unstakeDelaySec); Taruhan tidak dipotong - ia hanya dikunci. tetapi ia menunjukkan komitmen dan sumbangan: Relaxed storage access rules (as described above) Mempool yang lebih tinggi Kadar reputasi yang lebih rendah Bagi paymasters dan kilang, terutamanya, staking adalah hampir wajib untuk penggunaan pengeluaran. Tanpa itu, satu kegagalan UserOp boleh dengan cepat mendapatkan entiti throttled. (chain-specific, typically 1 ETH or equivalent) and Jumlah saham yang tepat berbeza mengikut rantaian dan ditakrifkan dalam metadata mempool – semak dokumen bundler untuk rangkaian sasaran anda. MIN_STAKE_VALUE MIN_UNSTAKE_DELAY Ekonomi Gas Mereka membayar kos gas untuk menghantar bundel dan dikembalikan daripada UserOps mereka termasuk. ekonomi bekerja seperti ini: 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 dinyatakan: Payment = (actualGasUsed + preVerificationGas) × min(maxFeePerGas, baseFee + maxPriorityFeePerGas) The bundler sets the address in the memanggil untuk menerima pembayaran ini. beneficiary handleOps preVerificationGas Explained The 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: Kos tetap per panggilan handleOps yang diamputasi di seluruh UserOps Caj data L2: Pada L2 seperti Optimism atau Arbitrum, menghantar data panggilan kepada L1 mempunyai kos tambahan When estimating gas, bundlers calculate preVerificationGas based on the UserOp's size: // 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 berbeza mengikut bundler. Untuk rujukan, Alto menggunakan daripada , Sentiasa gunakan rather than hardcoding. transactionGasStipend: 21000 fixedGasOverhead: 9830 perUserOp: 7260 eth_estimateUserOperationGas The Unused Gas Penalty 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 pelaksanaan akaun) dan (for paymaster post-operations): callGasLimit paymasterPostOpGasLimit Jika gas yang tidak digunakan dalam kedua-dua medan melebihi PENALTY_GAS_THRESHOLD (40,000), akaun membayar 10% (UNUSED_GAS_PENALTY_PERCENT) daripada jumlah yang tidak digunakan (TIDAK terpakai kepada verificationGasLimit atau preVerificationGas) Ini menghalang penetapan had eksekusi yang sangat tinggi "hanya untuk selamat" Apabila anda melihat kesilapan dalam pertimbangan gas, semak jika had anda munasabah. endpoint provides sensible defaults. eth_estimateUserOperationGas Common Errors and Debugging When a UserOperation is rejected, the RPC error is the only signal you get. Bundlers return structured error codes that explain exactly why the operation failed — but only if you know how to read them. AA1x: Factory Errors These occur when deploying a new account via the factory. In EntryPoint v0.8, you specify and as separate fields (the EntryPoint packs them into internally): factory factoryData initCode AA10: "penghantar telah dibina" - Alamat penghantar telah mempunyai kod yang digunakan. AA13: "initCode gagal atau OOG" - Panggilan CreateAccount kilang gagal atau tamat gas. : "initCode must return sender" - The factory returned a different address than expected. AA14 AA15: "initCode mesti mencipta penghantar" - Panggilan kilang telah diselesaikan tetapi tidak menyebarkan kod kepada alamat penghantar. : Check that your factory's fungsi mengembalikan alamat yang dijangka. mengesahkan kilang telah digunakan dan dibiayai. Debugging createAccount AA2x: Kesilapan Pengesahan Akaun Kategori yang paling biasa: AA20: "akun tidak digunakan" - Alamat penghantar tidak mempunyai kod dan tiada initCode yang disediakan. AA21: "tidak membayar prefund" - Akaun tidak mempunyai cukup ETH untuk menutupi kos gas maksimum yang mungkin. : "expired or not due" - The UserOp has a timestamp that has passed, or a timestamp that hasn't arrived yet. AA22 validUntil validAfter : "reverted" - The account's function reverted. Check your signature validation logic. AA23 validateUserOp AA24: "kesalahan tanda tangan" - Data pengesahan yang dikembalikan menunjukkan tanda tangan yang tidak sah. : "invalid account nonce" - The nonce doesn't match. The nonce in ERC-4337 is a 256-bit value with two parts: . The (upper 192 bits) identifies the "lane"—you can have multiple parallel UserOps with different keys. The (lower 64 bits) must increment sequentially within each lane. Common causes: AA25 nonce = (key << 64) | sequence key sequence Reusing a nonce that was already included Using the wrong nonce key Another UserOp with the same sender is pending in the mempool : "over verificationGasLimit" - Account validation used more gas than allocated. Increase . AA26 verificationGasLimit 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 entryPoint.depositTo{ value: 1 ether }(paymasterAddress); : "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 AA36: "Over paymasterVerificationGasLimit" - Pengesahan Paymaster menggunakan lebih banyak gas daripada yang diberikan. Working with Bundlers Kaedah RPC Every ERC-4337 bundler implements these standard methods: : Submit a UserOp for inclusion eth_sendUserOperation const userOpHash = await bundler.request({ method: 'eth_sendUserOperation', params: [userOp, entryPointAddress] }); : Get gas limit estimates 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] }); : Dapatkan penerimaan selepas penyertaan eth_getUserOperationReceipt const receipt = await bundler.request({ method: 'eth_getUserOperationReceipt', params: [userOpHash] }); // Returns: { success, actualGasUsed, receipt: { transactionHash, ... } } : Menemukan versi EntryPoint yang disokong oleh bundler eth_supportedEntryPoints const entryPoints = await bundler.request({ method: 'eth_supportedEntryPoints', params: [] }); // Returns: ['0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108'] The Shared Mempool Pada mulanya, setiap bundler mengekalkan mempool peribadi mereka sendiri. : A single bundler could refuse to include certain UserOps Censorship risk : Users had to know which bundlers to submit to Fragmentation Satu titik kegagalan: Jika bundler anda jatuh, UserOps anda terjejas The solution is the , a P2P network where bundlers gossip UserOps to each other. It works similarly to how Ethereum nodes gossip transactions: ERC-4337 shared mempool Pengguna menghantar UserOp kepada mana-mana bundler yang mengambil bahagian Bundler validates and adds to the local mempool Bundler broadcasts to connected peers Any bundler on the network can include the UserOp. Protokol ini menggunakan libp2p untuk rangkaian. Bundlers mengiklankan mempools mana yang mereka menyokong (diidentifikasi oleh IPFS CID yang merujuk fail metadata mempool), dan hanya menyebarkan UserOps yang lulus pengesahan. chainId: '1' entryPointContract: '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108' description: Canonical ERC-4337 mempool for Ethereum Mainnet minimumStake: '1000000000000000000' IPFS CID fail ini menjadi pengenal mempool yang digunakan dalam nama topik P2P. Metadata mempool menentukan peraturan pengesahan: opcode mana yang dilarang, corak akses penyimpanan, had gas, dan ambang reputasi. Apabila sebuah bundler menerima UserOp melalui gosip P2P, ia mengesahkan semula terhadap peraturan sendiri sebelum menambah kepada mempool tempatan. Advanced Topics Aggregators Pengesahan tanda tangan adalah mahal pada rantaian. pengkompilasian awal ecrecover kos 3,000 gas per panggilan, tetapi pengesahan tanda tangan akaun pintar biasanya kos lebih banyak kerana logik pengesahan tambahan—seringkali sebanyak 6,000-10,000 gas. Untuk 100 UserOps dalam bundle, ia adalah 600,000+ gas hanya untuk tanda tangan. agregator membolehkan pengesahan tanda tangan batch—melakukan pengesahan semua 100 tanda tangan dalam satu operasi untuk sebahagian daripada kos. 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: Pengesahan akaunUserOp mengembalikan alamat agregator dalam data pengesahan Bundler groups all UserOps using the same aggregator Bundler calls once for the group aggregator.validateSignatures(userOps, aggregatedSignature) Jika pengesahan berlalu, semua UserOps dalam kumpulan itu dianggap sah : The return value from Mengumpulkan tiga bahagian maklumat ke dalam 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 agregator (bit 0-159): Alamat kontrak agregator, atau nilai khas: 0 = tanda tangan sah, 1 = tanda tangan tidak sah validUntil (bit 160-207): Timestamp selepas yang UserOp ini tamat tempoh (0 = tiada tamat tempoh) validAfter (bit 208-255): Timestamp sebelum yang UserOp ini tidak sah (0 = segera sah) This encoding lets accounts specify both signature verification delegation and time-bounded validity in a single return value. Paymasters Paymasters abstract gas payment from users. Instead of the account paying for gas, a paymaster can: Transaksi Sponsor: Bayar bagi pihak pengguna (UX tanpa gas) : Let users pay in stablecoins or other tokens Accept ERC-20 tokens Melaksanakan logik tersuai: batasan kadar, model langganan, dan lain-lain. The paymaster's validation flow runs during the validation phase: function validatePaymasterUserOp( PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost ) external returns (bytes memory context, uint256 validationData); yang Kembali ke sini telah berlalu 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; Paymasters should be staked for production use. Staking provides relaxed storage access rules and better reputation—unstaked paymasters face strict limitations and can be quickly throttled by bundlers. While unstaked paymasters technically function with basic operations, staking is practically required for any serious paymaster implementation. can Ujian tempatan This section assumes you have Anvil running with EntryPoint v0.8 deployed. We'll use , Pimlico's TypeScript bundler, and , perpustakaan berasaskan viem untuk interaksi ERC-4337 tinggi Perkhidmatan.js SimpleAccountFactory Dalam Bahagian 1, kami telah membina akaun pintar minimum. tetapi bagaimana pengguna mengimplementasikannya? Mereka tidak boleh menghantar transaksi biasa - mereka belum mempunyai ETH untuk gas. ERC-4337 menyelesaikan ini dengan kontrak kilang. For , the reference implementation includes . Deploy it alongside the EntryPoint before running the examples below. SimpleAccount SimpleAccountFactory Account Deployment via UserOp Apabila EntryPoint menerima UserOp dengan medan Factory dan FactoryData: Checks if has code—if yes, skip deployment sender Calls via the factory.createAccount(owner, salt) factoryData Verifies the deployed address matches sender Continues with validation on the newly-deployed account 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 Key flags: : Key for submitting bundles (must have ETH) --executor-private-keys --safe-mode false: Anvil tidak mempunyai penjejakan JavaScript untuk pengesahan ERC-7562 penuh --api-version v1,v2: Menerima kedua-dua format UserOp (v1 untuk 0.6, v2 untuk 0.7/0.8) Menghantar Operasi Pengguna dengan permissionless.js Pembentukan ketergantungan : npm install viem permissionless Step 1: Set up clients We need three clients: one for reading chain state, one for bundler-specific RPCs, and one for the smart account owner. 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 connects to Alto's RPC and provides gas estimation via . 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 mengira alamat counterfactual menggunakan alamat kilang Akaun ini belum wujud—tetapi kita tahu persis di mana ia akan digunakan. getAddress Step 3: Fund the account The smart account needs ETH to pay for gas (or use a paymaster). We can send ETH to the counterfactual address: const walletClient = createWalletClient({ account: owner, chain: foundry, transport: http("http://localhost:8545") }) await walletClient.sendTransaction({ to: accountAddress, value: parseEther("1") }) ETH terletak di alamat itu.Selepas akaun dilancarkan, ia boleh mengakses dana itu dengan 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 pembinaan UserOp, pengurusan nonce, penilaian gas, dan penandatanganan. callback mengambil harga gas semasa daripada 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 menyebarkan akaun, kemudian melaksanakan pemindahan—semua dalam satu transaksi. factory factoryData What We've Learned Bundler adalah lapisan eksekusi ERC-4337.Mereka adalah apa yang mengubah Account Abstraction daripada spesifikasi kepada mekanisme yang bersedia untuk pengeluaran. Memahami sekatan mereka - peraturan pengesahan, ekonomi gas, dan mekanik reputasi - adalah penting apabila merancang akaun pintar yang boleh dipercayai. kesilapan di sini tidak muncul dalam kod Solidity, tetapi dalam tingkah laku mempool, simulasi, dan ekonomi pelaksanaan. ERC-4337 memindahkan kerumitan daripada protokol dan ke dalam infrastruktur. Semakin awal pengembang mula berfikir dalam hal bundler bukannya transaksi, sistem mereka akan lebih tahan lama dalam pengeluaran.