Estimativa de gas do ERC-4337 para L2s e agregadores de assinatura
Autores: Dan Coombs, David Philipson
Em ERC-4337 Gas Estimation discutimos como o gas funciona no ERC-4337 e nosso método para estimativa de gas. Na parte 2, Dummy Signatures and Gas Token Transfers, descobrimos que estimar gas nem sempre é simples, e precisamos considerar casos extremos. Este post vai se aprofundar em mais alguns desses casos extremos que encontramos.
O problema do L2
Parte da definição de um Ethereum Layer 2 rollup é: ele "deixa a layer 1 cuidar da segurança, disponibilidade de dados e descentralização, enquanto as layer 2s cuidam do scaling."
Para atingir isso, as L2s vão "agrupar" muitas transações em um único batch e então postá-las na blockchain layer 1. Esse custo de transação não é gratuito, já que as L2s precisam pagar pelos custos de calldata incorridos ao postar um grande batch de dados na chain L1.
As L2s precisam de uma forma de cobrar dos seus usuários esses custos de calldata da L1 incorridos. Frameworks de rollup conseguem isso de formas diferentes.
Este artigo foca nos dois maiores rollups EVM: Arbitrum e Optimism.
Como o Arbitrum calcula o custo para cobrir as taxas de gas da L1?
No Arbitrum, a cobrança de gas da L2 para cobrir o custo de gas da L1 é calculado usando a seguinte fórmula, onde o tamanho dos dados é seu tamanho em bytes após a compressão Brotli:
💡 Custo L1 (L1C) = Preço L1 por byte de dado (L1P) * Tamanho do dado a ser postado em bytes (L1S)
💡 Gas (G) = Custo L1 (L1C) / Preço de Gas L2 (P)
Esse gas é cobrado antes do início da execução da transação e conta para o gasLimit da transação. Portanto, deve ser considerado durante a estimativa de gas da transação.
Como o Optimism calcula o custo para cobrir as taxas de gas da L1?
No Optimism, o custo de gas da L1 é calculado de forma similar, onde o tamanho em bytes após a compressão é multiplicado por uma taxa L1. Em vez de converter esse valor em gas L2 como o Arbitrum, o Optimism deduz o ETH necessário diretamente da conta do remetente.
Remetentes não precisam considerar esse valor durante a estimativa de gas, mas não têm a capacidade de definir um limite para seus gastos. O Optimism toma cuidado para garantir que essa taxa não dispare.
Como um bundler nas L2s pode cobrar pelas taxas da L1?
Em ambos os casos, um bundler que envia uma transação de bundle em uma L2 é cobrado pelas taxas da L1. O bundler precisa de uma forma de cobrar das user operations agrupadas por essa taxa, aumentando o gas da L2.
O impacto efetivo no gas da L2 pode ser determinado por:
L2\_gas = L1\_gas \* L1\_fee / L2\_fee
verificationGasLimit e callGasLimit são medidos pelo entry point e, portanto, não podem ser usados pelos bundlers para cobrar por esse gas extra. Os bundlers precisam recorrer a outros métodos.
Tentativa 1: definir uma priority fee mais alta
Exigir um maxPriorityFeePerGas mais alto poderia permitir que o bundler recuperasse essas taxas perdidas.
O cálculo ficaria assim:
- Estimar a taxa L1 e converter em gas L2 a. Assumir um bundle de tamanho 1 user operation e estimar gas usando métodos fornecidos pela rede, tipicamente expostos como chamadas de contrato especiais. b. Isso requer assumir tanto uma base fee L1 quanto uma base fee L2 para converter a taxa em valores de gas L2.
- Estimar
verificationGasLimita. Como esse gas limit está sob regras estritas de simulação, é altamente provável que o valor estimado fique muito próximo do valor real, ao contrário docallGasLimit. - Definir
maxPriorityFeePerGasBuffer=L1\_fee / verificationGasLimit - Adicionar esse buffer a qualquer priority fee necessária
Isso poderia funcionar, mas tem uma UX terrível.
Para se proteger, o bundler deve assumir que a quantidade de call gas usada será 0 e cobrar o usuário como se o verification gas fosse o único componente. O usuário então pagará a mais pelo componente de buffer priority fee multiplicado por qualquer call gas usado. Isso não é bom para o usuário.
Tentativa 2: manipular o preVerificationGas
Isso deixa o preVerificationGas como o único campo razoável para manipular. Isso se encaixa bem na definição fornecida acima de que o preVerificationGas é "o campo de gas usado para capturar qualquer uso de gas que o entry point não consegue medir." Como esse é gas que o entry point não mede, esperaríamos poder usar esse campo para cobrar do usuário.
O cálculo ficaria assim:
- Estimar a taxa L1 e converter em gas L2, definindo como
preVerificationGas. a. Assumir um bundle de tamanho 1 user operation e estimar gas usando métodos fornecidos pela rede, tipicamente expostos como chamadas de contrato especiais. b. Isso requer assumirmos tanto uma base fee L1 quanto uma base fee L2 para converter a taxa em valores de gas L2. - Calcular o gas não medido da L2 e adicionar isso ao valor calculado acima.
a. Esse é o mesmo método descrito na nossa seção de cálculo de PreVerificationGas para um cálculo normal de
preVerificationGas. - Durante
eth\_sendUserOperation, também executar (1) e (2), e rejeitar quaisquer operações que não tenham umpreVerificationGassuficientemente alto como parte do estágio de "pre-check". - Durante o bundling, executar (1) e (2) novamente logo antes do envio.
a. Rejeitar quaisquer operações que não tenham um
preVerificationGassuficientemente alto.
Embora esse mecanismo funcione, ele tem um problema de UX muito significativo.
Durante (2) o bundler precisa assumir valores de base fee L1 e L2 para realizar o cálculo de gas. Como as base fees são dinâmicas, se entre a etapa de estimativa de gas e a etapa de submissão/bundling a proporção de L1\_fee / L2\_fee aumentar, um preVerificationGas mais alto será necessário, e user operations calculadas com uma proporção menor serão rejeitadas.
O melhor que o usuário pode fazer para melhorar isso é assumir que a proporção vai aumentar entre a estimativa e o bundling e fornecer uma margem no seu preVerificationGas para melhorar suas chances.
Como o preVerificationGas é sempre cobrado integralmente (ou seja, não é um campo de limite), o usuário fica preso pagando por essa margem independentemente do que acontece com o preço. O usuário fica preso tendo que escolher entre potencialmente pagar a mais ou ter suas operações rejeitadas.
💡 O Rundler implementa o cálculo de preVerificationGas acima. Recomendamos que usuários dessas L2s adicionem uma margem de 25% ao preVerificationGas retornado por eth\_estimateUserOperationGas para melhorar a chance de que a operação não seja rejeitada.
Caso extremo do Optimism
As base fees do Optimism são incrivelmente baixas, frequentemente bem abaixo de 100 wei (sim, wei). O preVerificationGas necessário para cobrar a taxa de gas da L1 é inversamente relacionado à taxa de gas da L2, exigindo assim que o preVerificationGas seja extremamente alto (na casa dos milhões).
A priority fee do Optimism é frequentemente ordens de magnitude maior que sua base fee. Portanto, um usuário deve ser muito cuidadoso para não enviar uma priority fee proporcional à priority fee da rede, já que o entry point exige pagamento por preVerificationGas \(very high\) \* priority fee \(normal\) , causando pagamento excessivo massivo. Por esse motivo, o Rundler exige que a priority fee seja uma porcentagem estática da base fee para incentivar o bundling no Optimism.
O problema do signature aggregator
Signature aggregation é um recurso muito comentado do ERC-4337 por sua capacidade de:
- Reduzir custos de calldata nas L2s via compressão de assinatura, levando a economias significativas.
- Amortizar o custo de gas de uma verificação de validação agregada em um bundle de operações. a. Essa verificação de validação pode ser tão simples quanto uma assinatura BLS, ou tão complicada quanto uma prova ZK agregada.
Na versão atual do entry point, a chamada para a função validate dos signature aggregators não é medida. Isso significa que o bundler precisa encontrar uma forma de cobrar das user operations agregadas por esse gas, de forma similar ao problema da L2 acima.
Assim como no problema da L2, a única forma razoável de fazer isso é aumentar o preVerificationGas.
Uma forma de fazer isso é:
- O bundler assume um tamanho de bundle
target - O bundler chama
validateUserOpem cada operação que recebe antes da estimativa para extrair um endereço de aggregator, se usado. - Quando uma user operation agregada é recebida, o bundler precisa estimar a quantidade de gas usada pelo signature aggregator, por operação, nesse tamanho de bundle alvo.
a. Uma forma seria replicar a user operation recebida
targetvezes em um bundle e então usareth\_estimateGasemaggregator.validateSignaturesb. Outra forma seria manter uma whitelist de signature aggregators com medições de gas pré-populadas (com um valor estático e um valor dinâmico por operação). - Adicionar o gas estimado ao cálculo de
preVerificationGasacima e retornar esse valor.
Existem alguns problemas com essa abordagem:
- O bundler está assumindo um risco ao supor um tamanho de bundle
target. Ou: a. O bundler espera até realmente poder fazer bundle das operações alvo, prejudicando a UX via latência b. O bundler faz bundle de menos que o alvo, e arca com o custo - Usuários não podem "dar lance" a mais ou a menos dependendo de quão rápido querem ser incluídos.
a. Em uma abordagem baseada em limite, se um usuário quer garantir uma mineração rápida, ele pode superestimar o custo. Se o custo acabar sendo menor, ele não é cobrado a mais. Nessa abordagem, devido ao
preVerificationGasestático, os usuários sempre precisam pagar todo o seu lance. - Na rede P2P, os bundlers podem ter tamanhos de bundle alvo diferentes.
a. Isso significa que o bundler usado para a estimativa pode superestimar/subestimar o
preVerificationGasexigido por outro bundler no mempool. b. Essas suposições off-chain prejudicam a interoperabilidade do mempool.
O Rundler atualmente não tem suporte para signature aggregators devido a essas complicações. É provável que adicionemos suporte para o método acima e assumamos algum tamanho de bundle (pequeno, começando em 1), o que tornará o uso de signature aggregators muito caro.
Possíveis mudanças no entry point
Os problemas acima se devem à falta de medição no contrato do entry point para o uso significativo de gas pela user operation. Depender do preVerificationGas para cobrar esse uso de gas tem o problema significativo de UX de exigir que os usuários paguem mais do que realmente usam para aumentar a chance de sua UO ser incluída onchain rapidamente.
Uma solução para esses problemas poderia ser modificar o contrato do entry point para medir esse uso extra de gas e atribuí-lo a campos de gas baseados em limite.
Medição de gas de calldata L2-L1
💡 Este é um esboço bem inicial de uma solução para um problema difícil. Adoraríamos ouvir ideias da comunidade!
O custo de gas de calldata da L1 pode ser medido onchain e as user operations podem ser cobradas apenas pelo custo exato que incorrem, e não pela sobrecarga. Um campo baseado em limite deveria ser usado.
Uma possível solução é introduzir um novo campo, daCallDataGasLimit (da de Data Availability, nome provisório). Esse campo seria nativo de uma versão L2+ do entry point e usado em chains onde o calldata da transação é postado em um sistema diferente e, portanto, deve ser cobrado de forma separada.
A lógica do entry point seria a seguinte:
- No deployment, o entry point é associado a um contrato auxiliar
daGasMeterque tem uma única funçãomeasureUserOperationDaGas\(UserOperation userOp\)a. Essa função recebe uma user operation e mede exatamente quanto gas de DA foi usado. b. Por exemplo, no Arbitrum o medidor pode fazer uma chamada paragasEstimateL1Componentcom uma user operation em memória para determinar quase exatamente quanto gas da L1 ela usou (não é possível considerar compressão extra devido a um bundle com múltiplas ops). - O entry point vai chamar essa função para cada user operation antes da validação e pode atribuir esse gas ao
daCalldataGasLimit. - Para evitar reverts, em vez de reverter se o gas de DA usado for maior que o
daCalldataGasLimit, o entry point apenas vai limitar ali e o bundler fica responsável por pagar qualquer gas acima desse limite. Isso pode ser considerado off-chain pelos bundlers garantindo que qualquer operação agrupada tenha uma margem suficientemente alta em seu campo de limite antes do bundling.
Há algumas desvantagens bastante significativas nessa abordagem:
- Os contratos de entry point em chains diferentes terão endereços diferentes.
- Utilização de gas durante a medição. a. Isso é menos problemático já que em L2+'s o custo de gas de execução geralmente é muito menor que o custo de gas de dados.
Medição de gas do signature aggregator
O contrato do entry point pode ser modificado para medir a quantidade de gas usada durante sua chamada para aggregator.validateSignatures, dividir isso pela quantidade de user operations agregadas, e atribuir o uso de gas de forma equilibrada deduzindo do verificationGasLimit.
Cada signature aggregator na whitelist deveria ser associado a um valor estático, o custo base para validar a assinatura agregada, e um valor dinâmico, o aumento de custo por operação agregada. Por exemplo, um signature aggregator BLS poderia ter seu valor estático como o custo único de verificação de assinatura e o valor dinâmico como o custo das operações de hashing por op. Bundlers podem aumentar o verificationGasLimit durante eth\_estimateUserOperationGas pelo valor estático dividido por um tamanho de bundle alvo mais o valor dinâmico.
Como definimos o tamanho de bundle alvo?
Uma possível solução aqui é complementar os argumentos de eth\_estimateUserOperationGas com um minimumBundleSize correspondente ao menor tamanho de bundle (portanto o gas mais alto) que o usuário quer que seja incluído. Usuários dispostos a pagar mais podem diminuir seu tamanho mínimo de bundle e melhorar seu tempo de inclusão.
Os bundlers então precisam de lógica para garantir que incluam uma UO em um bundle que seja pelo menos tão grande quanto o tamanho mínimo de bundle dessa UO. Esse tamanho mínimo de bundle pode ser calculado durante a simulação, rastreando a quantidade de gas usada pela etapa de validação de conta, subtraindo isso de verificationGasLimit , e então calculando o tamanho mínimo a partir do que sobrou. Bundlers podem armazenar esse valor junto com a UO em seu mempool e usá-lo como dica para a construção de bundles.
💡 Uma desvantagem dessa abordagem é que ela assume que o uso de gas por um signature aggregator é uniforme por operação. Se não for o caso, a medição poderia ser transferida para o contrato do aggregator e retornada por sua função de verificação. Bundlers precisariam de uma forma de calcular esses valores não uniformes off-chain também.
O que isso significa para desenvolvedores de signature aggregators?
Signature aggregators provavelmente precisarão ser diretamente colocados em whitelist pelos bundlers, fornecendo a eles métodos para calcular assinaturas off-chain e seus componentes de custo de gas estático/dinâmico. O problema de cold-start vai ser difícil, especialmente dada a impossibilidade de um usuário "dar lance" para acelerar sua operação.
O que isso significa para desenvolvedores de account clients?
É importante entender as distinções de L2 descritas acima, especialmente na hora de estimar taxas de gas. No Optimism, se você usar a priority fee fornecida pela rede, pode acabar pagando muito a mais por uma user operation, já que essa priority fee agora também se aplica aos custos da L1. Se estiver usando o endpoint de bundler da Alchemy, consulte nossa documentação para dicas sobre como estimar taxas.
🦀
Continue lendo
O próximo artigo desta análise detalhada sobre estimativa de gas do ERC-4337 fornece um passo a passo do processo de estimativa de taxa da user operation. Se você perdeu a parte um ou dois, aprenda como funcionam a estimativa de gas do ERC-4337, os valores dummy e o problema da transferência de token.
Newsletter da Alchemy
Seja o primeiro a saber sobre lançamentos
Assine nossa newsletter
Receba as últimas atualizações de produtos e recursos da Alchemy
Ao inserir seu endereço de e-mail, você concorda em receber nossas comunicações de marketing e atualizações de produtos. Você reconhece que a Alchemy processa as informações que recebemos de acordo com nosso Aviso de Privacidade. Você pode cancelar a inscrição a qualquer momento.
Artigos relacionados

Glamsterdam: o guia completo para desenvolvedores de Ethereum
Glamsterdam já está na Sepolia. O guia completo sobre o que isso significa para desenvolvedores e como a Alchemy se preparou para a atualização da rede.

Por que equipes de trading escolhem a Alchemy para RPC de baixa latência
Equipes de trading escolhem a Alchemy por leituras e escritas de baixa latência quando o mercado se move, e por um registro confiável quando o dinheiro liquida, mesmo no pico de volume.

Em qual provedor de RPC você deve construir em Tóquio?
Comparamos cinco dos provedores de RPC que atendem Tóquio em cinco chains. Veja como eles se comparam e onde as diferenças importam para equipes sensíveis à latência.