en , se desplegó una cuenta inteligente y la primera UserOperation se ejecutó con éxito a través de EntryPoint. En ese momento, todo funcionó, pero una parte crítica del sistema permaneció en su mayoría invisible: el paquete. Parte 1 Los bundlers son el puente entre la abstracción de la cuenta y la capa de ejecución de Ethereum. Toman las operaciones de usuario de un mempool separado, pagan los costos del gas de antemano y se reembolsan a través del protocolo.Entender cómo funcionan -las reglas de validación, el sistema de reputación y los incentivos económicos- es esencial para deshacer problemas y construir aplicaciones fiables. El ciclo de vida del usuario Una operación de usuario es la unidad en la que operan los paquetes de trabajo. Incapsula todo lo necesario para ejecutar una acción en nombre de una cuenta inteligente: autorización, restricciones de gas, datos de llamada de ejecución y lógica opcional de paymaster. En EntryPoint v0.8, las operaciones de usuario se manejan en cadena en un formato empacado y optimizado por gas. Cuando se trabaja con SDKs como permissionless.js, se representan como una estructura explícita y no empacada: 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 } En cadena, el EntryPoint utiliza un formato empacado para la eficiencia del gas (combinando campos como El SDK maneja este paquete automáticamente, no tienes que preocuparte por ello. accountGasLimits = verificationGasLimit | callGasLimit El ciclo de vida de una operación de usuario se ve así: Creación: El usuario construye el UserOp con su SDK de cuenta inteligente (como permissionless.js) Firma: el usuario firma el hash de UserOp, lo que demuestra que autorizó la acción Envío: UserOp se envía a un paquete a través de eth_sendUserOperation Validación: Bundler simula el UserOp para comprobar si será exitoso Mempool: Si es válido, el UserOp entra en el mempool del bundler : Bundler packages multiple UserOps into a single call Bundling handleOps Ejecución: El contrato de EntryPoint valida cada UserOp en cadena, luego los ejecuta Pago: EntryPoint cobra los costos de gas de cada cuenta (o de su paymaster). El punto de vista clave es que la validación ocurre dos veces: una vez fuera de la cadena por el agrupador (para decidir si aceptar el UserOp), y una vez en la cadena por el EntryPoint (antes de ejecutar realmente). Si estas dos validaciones producen resultados diferentes, el agrupador pierde dinero - pagando por gas en una transacción que finalmente falla. Cada regla de validación existe para eliminar una clase de ataque donde un UserOp pasa la simulación pero falla en la cadena. Validación: Por qué los Bundlers Son Paranoicos Si una operación de usuario falla en cadena después de ser incluida en un paquete, la pérdida es suya. That single fact defines the entire bundler threat model. Entre la simulación y la inclusión, el estado de Ethereum no es estático. Los parámetros del bloque cambian, los saldos cambian y las transacciones adversarias pueden aterrizar entre ellos.Un UserOperation cuidadosamente diseñado puede pasar por la simulación de la cadena y todavía fallar durante la validación en cadena - convirtiendo el bundler en un sink de gas. ERC-4337 responde con una fuerte restricción de lo que el código de validación está permitido hacer. El EntryPoint impone una estricta separación de preocupaciones: : La función validateUserOp de la cuenta se ejecuta para verificar la firma y autorizar la operación.Esta fase tiene restricciones estrictas sobre qué opcodes y almacenamiento el código puede acceder. Validation Phase : La función de ejecución de la cuenta ejecuta la operación real. No hay restricciones aquí: capacidades EVM completas. Execution Phase Banned Opcodes Ciertos códigos opcionales están prohibidos durante la validación porque sus valores pueden cambiar entre la simulación y la ejecución: , , , : Block-dependent values. An account could check if (block.timestamp > deadline) revert, pass simulation, then fail when the bundle lands in a later block. TIMESTAMP NUMBER COINBASE PREVRANDAO BLOCKHASH: Devuelve valores diferentes para bloques diferentes. GASPRICE, BASEFEE: Cambio basado en las condiciones de la red. , : Only allowed from staked entities (see Staking below) per ERC-7562 [OP-080]. BALANCE SELFBALANCE GASLIMIT, ORIGEN: Puede variar entre el entorno de simulación y la ejecución real. , : EIP-4844 blob-related opcodes that vary per block. BLOBHASH BLOBBASEFEE SELFDESTRUCT, INVALIDO: Los opcodes destructivos no están permitidos durante la validación. : Only allowed when immediately followed by a instruction— , , , or (for gas forwarding to other contracts). GAS *CALL CALL DELEGATECALL STATICCALL CALLCODE CREATE: Generalmente prohibido porque crea contratos en direcciones impredecibles. sin embargo, CREATE está permitido para el contrato del remitente cuando se utiliza una fábrica sin fronteras. CREATE2 está permitido exactamente una vez durante la implementación para el contrato del remitente. Here's what happens when your account uses a banned opcode: // 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 } The bundler runs a trace during simulation (using con un rastreador compatible con ERC-7562) y rechaza cualquier UserOp cuya validación toca opcodes prohibidos. los paquetes modernos pueden utilizar un rastreador JavaScript o la implementación nativa Go introducida con EntryPoint v0.8. debug_traceCall Reglas de acceso al almacenamiento Más allá de los códigos opcionales, los bundlers restringen qué códigos de validación de ranuras de almacenamiento pueden leer y escribir. Sólo se puede acceder: Unstaked entities Su propio almacenamiento (el almacenamiento de la cuenta) Slots de almacenamiento que están "asociados" con la dirección de la cuenta A, definido como: el valor de la ranura es igual a A, O se calculó como keccak256(A Átha Cliath x) + n donde x es bytes32 y n está en el rango de 0 a 128 En la práctica, esto significa que su cuenta puede leer / escribir en mapas donde la dirección de la cuenta es la clave. por ejemplo, un token ERC-20 almacena saldos en un mapeo como . The actual storage slot is Si su dirección de cuenta es la clave, esa ranura está "asociada" con usted. 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 (cuentas, pagadores o fábricas que hayan depositado una participación en el EntryPoint) obtienen más libertad: Staked entities Puede acceder a cualquier ranura en su propio almacenamiento (STO-031) Puede acceder al almacenamiento asociado de cualquier entidad en el UserOp (STO-032) Puede tener acceso únicamente a la lectura al almacenamiento en contratos sin entidad (STO-033) Ver las reglas completas de acceso al almacenamiento en . ERC 7562 ¿Por qué existen estas reglas? considere dos operaciones de usuario que se leen desde la misma ranura de almacenamiento durante la validación. Si la primera operación muta esa ranura, las suposiciones de validación de la segunda operación pueden dejar de ser válidas. Al restringir el acceso al almacenamiento durante la validación, los paquetes pueden incluir de forma segura múltiples operaciones de usuario en el mismo paquete sin riesgo de interferencia interoperatoria o fallas no deterministas. El sistema de reputación Incluso con las reglas de validación, las entidades pueden comportarse mal. Una cuenta puede presentar consistentemente UserOps que pasan la simulación pero fallan en la cadena debido a cambios de estado sutiles.Un administrador de pagos puede aprobar UserOps durante la simulación pero declinar el pago en la cadena. Bundlers sigue estas entidades con una Para cada entidad (adreza de cuenta, dirección de paymaster, dirección de fábrica), el bundler rastrea: reputation system opsSeen: Cuántos UserOps que involucran esta entidad ha visto el bundler opsIncluded: Cuántos de ellos realmente se incluyeron en la cadena El estado de la reputación se determina por los umbrales basados en el slack (definidos en ): ERC 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 Los valores "slack" son buffers de tolerancia que impiden falsos positivos de la varianza normal de funcionamiento. Esto significa que una entidad puede tener hasta 10 más inclusiones esperadas que inclusiones reales antes de ser reemplazada. Este diseño reconoce que algunas opciones de usuario fallan legítimamente (condiciones de red, condiciones de carrera) sin indicar comportamiento malicioso. THROTTLING_SLACK = 10 BAN_SLACK = 50 When an entity is , el bundler limita cuántas UserOps de esa entidad pueden estar en el mempool. , todas las Opciones de Usuario que involucren a esa entidad se rechazan inmediatamente. throttled banned La huelga Las entidades pueden mejorar su posición al apostar ETH en el contrato EntryPoint: entryPoint.addStake{ value: 1 ether }(unstakeDelaySec); La apuesta no se corta, sólo se bloquea, pero demuestra compromiso y subvenciones: Reglas de acceso al almacenamiento relajado (como se describe anteriormente) Límites más altos de mempool Términos de reputación más ligeros Para los paymasters y las fábricas, en particular, la apuesta es casi obligatoria para el uso de la producción. Sin ella, un único UserOp fallido puede rápidamente hacer que la entidad se torce. El mempool canónico requiere (especifica de la cadena, típicamente 1 ETH o equivalente) y of 86400 seconds (1 day). The exact stake amount varies by chain and is defined in the mempool metadata—check the bundler documentation for your target network. MIN_STAKE_VALUE MIN_UNSTAKE_DELAY Gas Economics Se pagan los costos del gas para enviar los paquetes y se reembolsan de los UserOps que incluyen.La economía funciona de esta manera: La perspectiva del Bundler Revenue = Σ (each UserOp's payment to beneficiary) Cost = Gas used × Gas price paid for handleOps tx Profit = Revenue - Cost Each UserOp pays based on its gas usage and the gas prices it specified: Payment = (actualGasUsed + preVerificationGas) × min(maxFeePerGas, baseFee + maxPriorityFeePerGas) El bando establece el La dirección en la solicitud para recibir estos pagos. beneficiary handleOps PreverificaciónGas explicado 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: Costos fijos por llamada de handleOps que se amortizan a través de UserOps : On L2s like Optimism or Arbitrum, posting calldata to L1 has additional costs L2 data fees Al estimar el gas, los agrupadores calculan preVerificationGas basado en el tamaño de 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; Los valores superiores varían según el bundle. Para referencia, Alto utiliza , de , Usar siempre En lugar de codificar. transactionGasStipend: 21000 fixedGasOverhead: 9830 perUserOp: 7260 eth_estimateUserOperationGas La sanción del gas no utilizado Para evitar que los usuarios paguen demasiado por el gas (que desperdicia espacio en bloques), EntryPoint impone una sanción sobre el gas de ejecución no utilizado. (para la ejecución de la cuenta) y (for paymaster post-operations): callGasLimit paymasterPostOpGasLimit Si el gas no utilizado en cualquiera de los campos supera el valor de PENALTY_GAS_THRESHOLD (40.000), la cuenta paga el 10% (UNUSED_GAS_PENALTY_PERCENT) del importe no utilizado (NO se aplica a verificaciónGasLimit o preVerificationGas) Esto desalenta el establecimiento de límites de ejecución absurdamente altos "sólo para ser seguro" Cuando vea errores en la estimación del gas, compruebe si sus límites son razonables. El punto final proporciona defectos razonables. eth_estimateUserOperationGas Errores comunes y debugging Cuando una operación de usuario es rechazada, el error RPC es la única señal que recibe.Bundlers devuelve códigos de error estructurados que explican exactamente por qué la operación falló, pero sólo si sabe cómo leerlos. AA1x: Factory Errors Esto ocurre cuando se implementa una nueva cuenta a través de la fábrica. En EntryPoint v0.8, especifica and as separate fields (the EntryPoint packs them into internally): factory factoryData initCode AA10: "enviador ya construido" - La dirección del remitente ya tiene código desplegado. AA13: "initCode falló o OOG" - La llamada de la fábrica de crearAccount falló o no funcionó. : "initCode must return sender" - The factory returned a different address than expected. AA14 AA15: "initCode debe crear el remitente" - La llamada de fábrica se completó pero no implementó el código a la dirección del remitente. Compruebe que la fábrica de su La función devuelve la dirección esperada. Verificar que la fábrica está desplegada y financiada. Debugging createAccount AA2x: Errores de validación de cuentas The most common category: : "account not deployed" - The sender address has no code and no was provided. AA20 initCode : "didn't pay prefund" - The account doesn't have enough ETH to cover the maximum possible gas cost. Fund the account or use a paymaster. AA21 : "expired or not due" - The UserOp has a timestamp that has passed, or a timestamp that hasn't arrived yet. AA22 validUntil validAfter AA23: "revertido" - La función validateUserOp de la cuenta revertida. Compruebe su lógica de validación de firma. AA24: "error de firma" - Los datos de validación devueltos indican una firma inválida. : "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 Usando la clave noce incorrecta Otro UserOp con el mismo remitente está pendiente en el mempool AA26: "sobre verificaciónGasLimit" - la validación de la cuenta utilizó más gas de lo asignado. AA3x: Errores de Paymaster : "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); AA32: "Paymaster expiró o no se venció" - Similar a AA22, pero para los datos de validación del paymaster. : "paymaster reverted" - The paymaster's function reverted. AA33 validatePaymasterUserOp : "paymaster signature error" - Bad signature in the paymaster data. AA34 AA36: "sobre paymasterVerificationGasLimit" - la validación de Paymaster utilizó más gas de lo asignado. Working with Bundlers Métodos 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, ... } : Buscar un UserOp por su hash eth_getUserOperationByHash const userOp = await bundler.request({ method: 'eth_getUserOperationByHash', params: [userOpHash] }); : Obtener el recibo después de la inclusión 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 Originally, each bundler maintained its own private mempool. This created problems: Riesgo de censura: un único paquete podría negarse a incluir ciertas opciones de usuario Fragmentación: los usuarios tenían que saber a qué paquetes enviar : If your bundler went down, your UserOps were stuck Single points of failure La solución es la , a P2P network where bundlers gossip UserOps to each other. It works similarly to how Ethereum nodes gossip transactions: ERC-4337 shared mempool User submits UserOp to any participating bundler Bundler valida y añade al mempool local Bundler broadcasts to connected peers 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. Temas avanzados Agregadores Signature verification is expensive on-chain. The ecrecover precompile costs 3,000 gas per call, but smart account signature verification typically costs more due to additional validation logic—often 6,000-10,000 gas total. For 100 UserOps in a bundle, that's 600,000+ gas just for signatures. Aggregators enable batch signature verification—verify all 100 signatures in a single operation for a fraction of the cost. 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: Validación de la cuentaUserOp devuelve una dirección de agregador en sus datos de validación Bundler agrupa todas las opciones de usuario usando el mismo agregador Bundler llama agregator.validateSignatures(userOps, agregatedSignature) una vez para el grupo If verification passes, all UserOps in that group are considered valid : The return value from Empaque tres piezas de información en un único valor de 256 bits: 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 (bits 160-207): Timestamp después de que este UserOp expire (0 = no expira) validAfter (bits 208-255): Timestamp antes del cual este UserOp no es válido (0 = inmediatamente válido) This encoding lets accounts specify both signature verification delegation and time-bounded validity in a single return value. Los Paymasters Paymasters abstrae el pago de gas de los usuarios. En lugar de pagar la cuenta por gas, un paymaster puede: : Pay on behalf of users (gasless UX) Sponsor transactions Aceptar tokens ERC-20: Deje que los usuarios paguen en stablecoins u otros tokens Implementar lógica personalizada: Limitación de tarifas, modelos de suscripción, etc. El flujo de validación del paymaster se ejecuta durante la fase de validación: 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; 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 Técnicamente funciona con operaciones básicas, la apuesta es prácticamente necesaria para cualquier implementación seria de paymaster. Puede Testing Locally This section assumes you have Anvil running with EntryPoint v0.8 deployed. We'll use , Pimlico's TypeScript bundler, and , a viem-based library for ERC-4337 interactions. Alto permissionless.js Factoría Simple En la Parte 1 construimos una cuenta inteligente mínima. pero ¿cómo lo implementan los usuarios? no pueden enviar una transacción regular —no tienen ETH para gas todavía. ERC-4337 resuelve esto con contratos de fábrica. For , the reference implementation includes Desplácelo junto al EntryPoint antes de ejecutar los ejemplos de abajo. SimpleAccount Factoría Simple Account Deployment via UserOp Cuando EntryPoint recibe un UserOp con los campos de fábrica y fábricaData: 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 Correr en 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: --executor-private-keys: clave para enviar paquetes (debe tener ETH) : Anvil lacks the JavaScript tracer for full ERC-7562 validation --safe-mode false --api-version v1,v2: Acepta ambos formatos de UserOp (v1 para 0.6, v2 para 0.7/0.8) Sending UserOperations with permissionless.js Install dependencies: npm install viem permissionless Step 1: Set up clients Necesitamos tres clientes: uno para el estado de la cadena de lectura, uno para los RPCs específicos del bundler y uno para el propietario de la cuenta inteligente. 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) El 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) Esto calcula la dirección contrafactual utilizando la dirección de la fábrica. La cuenta aún no existe, pero sabemos exactamente dónde se desplegará. 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") }) The ETH sits at that address. When the account is deployed, it can access those funds immediately. 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 handles UserOp construction, nonce management, gas estimation, and signing. The Callback recoge los precios actuales del gas del 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 y fields. The EntryPoint deploys the account, then executes the transfer—all in one transaction. factory factoryData Lo que hemos aprendido Los bundlers son la capa de ejecución de ERC-4337.Son lo que convierte la Abstracción de Cuentas de una especificación en un mecanismo listo para la producción. Comprender sus restricciones -reglas de validación, economía de gases y mecánica de reputación- es crucial cuando se diseñan cuentas inteligentes confiables. ERC-4337 desplaza la complejidad fuera del protocolo y en la infraestructura.Cuanto antes los desarrolladores empiecen a pensar en términos de empacadores en lugar de transacciones, más resilientes serán sus sistemas en la producción.