Gas Fees na EVM: Como Estimar e Reduzir Custos
O que são gas fees e por que existem
Gas é a unidade que a EVM (Ethereum Virtual Machine) usa para medir o custo computacional de cada operação executada em um smart contract. Cada opcode — soma, escrita em storage, chamada de contrato — tem um custo fixo de gas, definido na especificação da máquina virtual. Essa tabela de custos existe desde o Yellow Paper original do Ethereum e é mantida como parte do protocolo em cada EIP (Ethereum Improvement Proposal) que altera o comportamento da EVM.
O gas fee é o valor final que o usuário paga por uma transação. Ele é o produto entre a quantidade de gas consumida e o preço pago por unidade de gas. Três variáveis entram nessa conta: o gas limit (quanto gas o remetente está disposto a gastar), o gas price (quanto ele paga por unidade) e, desde a EIP-1559, a base fee (um piso de preço definido algoritmicamente pela própria rede a cada bloco, conforme a demanda).
A base fee sobe ou desce automaticamente dependendo de quão cheio estava o bloco anterior. Ela é queimada — não vai para o minerador ou validador. O que o validador recebe é a priority fee (ou tip), um valor adicional que o usuário oferece para ter prioridade de inclusão no bloco.
É importante não confundir gas fee com o campo value de uma transação. O value é a quantidade de ETH (ou moeda nativa da rede) transferida entre contas. O gas fee é pago independentemente de haver transferência de valor — mesmo uma chamada que só lê ou escreve estado consome gas e gera custo.
Solidity é a linguagem mais usada para escrever a lógica que roda dentro dessa máquina, e boa parte do gas consumido em produção vem diretamente de decisões tomadas no código Solidity, não da rede em si. Isso fica claro mais adiante, na seção de otimização.
Para quem ainda não tem os conceitos básicos de contratos inteligentes consolidados, vale revisar o Guia Definitivo de Smart Contracts para Devs antes de seguir com otimização de gas — o assunto pressupõe familiaridade com storage, opcodes e o modelo de execução da EVM.
Como estimar o custo de uma transação antes de enviar
Antes de assinar e enviar uma transação, é possível — e recomendado — simular a execução para descobrir quanto gas ela vai consumir. O método padrão do JSON-RPC do Ethereum para isso é o eth_estimateGas, que executa a chamada localmente em um nó (sem gastar gas real) e retorna uma estimativa do gas limit necessário.
Bibliotecas como ethers.js e viem expõem essa chamada de forma direta:
import { createPublicClient, http, parseEther } from "viem";
import { mainnet } from "viem/chains";
const client = createPublicClient({
chain: mainnet,
transport: http(),
});
const gasEstimate = await client.estimateGas({
account: "0xSeuEnderecoAqui",
to: "0xEnderecoDoContrato",
value: parseEther("0.01"),
});
console.log(gasEstimate);
Essa estimativa cobre o gas limit, mas não o preço por unidade. O preço final depende da base fee do bloco em que a transação for incluída, somada à priority fee que o remetente escolher oferecer. Em momentos de congestão de rede, a base fee sobe rapidamente entre blocos, e a priority fee necessária para entrar no próximo bloco também aumenta — é a competição por espaço limitado de bloco (cada bloco tem um gas limit máximo definido pela rede).
Suponha, apenas como exercício de cálculo, uma transação que consome 21.000 unidades de gas (o custo mínimo de uma transferência simples de ETH), com base fee de 20 gwei e priority fee de 2 gwei. O custo total seria:
custo = gas usado × (base fee + priority fee)
custo = 21.000 × 22 gwei
custo = 462.000 gwei = 0,000462 ETH
Esse número é hipotético — a base fee real varia bloco a bloco e depende inteiramente da demanda da rede no momento. Ferramentas de estimativa de gas são úteis para prever o gasto, mas não eliminam a incerteza: entre o momento da simulação e o momento em que a transação é minerada, a base fee pode ter mudado.
Técnicas de otimização de gas em Solidity
A maior parte do custo de gas em contratos complexos vem de leitura e escrita em storage, não de lógica aritmética. Cada slot de storage escrito custa significativamente mais gas do que uma operação em memória, conforme documentado na especificação de opcodes da EVM.
Algumas práticas reduzem esse custo de forma consistente:
Packing de storage. A EVM organiza storage em slots de 32 bytes. Se você declarar múltiplas variáveis menores (uint128, uint64, bool) em sequência, o compilador Solidity pode empacotá-las no mesmo slot, economizando escritas.
// Ineficiente: cada variável ocupa um slot inteiro
struct Ineficiente {
uint256 a;
bool b;
uint256 c;
}
// Eficiente: b é empacotado junto com a
struct Eficiente {
uint128 a;
uint128 b;
uint256 c;
}
Evitar loops não limitados sobre arrays de tamanho variável. Um loop que itera sobre um array que cresce com o tempo pode eventualmente exceder o gas limit do bloco e travar a função permanentemente. Prefira estruturas que permitam paginação ou processamento incremental.
Evitar leituras repetidas de storage. Ler uma variável de storage dentro de um loop custa gas a cada iteração. Copiar o valor para uma variável local (memory) uma única vez antes do loop é mais barato.
Preferir calldata a memory em parâmetros de funções externas. Quando um array ou struct é passado como parâmetro em uma função external e não precisa ser modificado, declarar o parâmetro como calldata evita a cópia para memória.
function processar(uint256[] calldata dados) external {
// calldata é mais barato que memory aqui,
// porque não há cópia do array
}
Erros customizados em vez de strings de revert. Desde o Solidity 0.8.4, é possível declarar erros customizados, que custam menos gas de deploy e de execução do que strings de mensagem em require.
error SaldoInsuficiente(uint256 disponivel, uint256 solicitado);
function sacar(uint256 valor) external {
if (valor > saldo) {
revert SaldoInsuficiente(saldo, valor);
}
}
Cada uma dessas técnicas tem um custo de legibilidade. Packing agressivo de storage torna structs mais difíceis de ler e mais propensas a erro de tipo. Erros customizados exigem decodificação no frontend. Vale medir o ganho real com uma ferramenta de profiling de gas antes de sacrificar clareza por economia marginal.
Estratégias de arquitetura para reduzir custo agregado
Otimizar opcode por opcode tem limite. Em algum ponto, a redução de custo real vem de decisões de arquitetura, não de microotimização de código.
Batching de transações. Agrupar múltiplas operações em uma única chamada de contrato reduz o custo fixo por transação (os 21.000 gas base de cada transação, mais o overhead de assinatura e nonce) que seria pago repetidamente se cada operação fosse enviada isoladamente.
Layer 2 e rollups. Redes como as construídas sobre rollups otimistas ou de validade processam transações fora da cadeia principal e publicam apenas um resumo compactado (ou prova) na L1. Isso reduz o custo por transação porque o custo de disponibilizar dados na L1 é diluído entre milhares de transações da L2.
O trade-off aqui é real: L2s geralmente concentram a construção de blocos em um sequenciador único ou em um conjunto pequeno de operadores, o que reduz a descentralização em troca de custo menor e finalização mais rápida. Antes de migrar um contrato para uma L2, vale entender esse modelo de confiança — ele muda o perfil de risco da aplicação, não só o custo.
Mover lógica para off-chain. Nem toda computação precisa acontecer on-chain. Cálculos que não exigem consenso distribuído — validação de assinatura fora da cadeia com verificação posterior, agregação de dados antes de enviar ao contrato — podem ser feitos off-chain e apenas o resultado final é registrado na EVM. Isso reduz gas, mas introduz um ponto de confiança no processo off-chain que precisa ser auditado com o mesmo rigor que o contrato.
Se sua equipe está avaliando entre otimizar o contrato atual ou migrar parte da lógica para L2, vale uma conversa técnica antes de comprometer a arquitetura — fale com o time de desenvolvimento Web3 da Hack Tech Farm pelo formulário de contato.
Gas fees em diferentes redes EVM
Nem toda rede compatível com a EVM segue exatamente o mesmo mecanismo de fee. A tabela abaixo resume as diferenças relevantes para quem porta contratos entre redes.
| Rede | Mecanismo de fee | Moeda de gas | Observação |
|---|---|---|---|
| Ethereum Mainnet | EIP-1559 (base fee + priority fee) | ETH | Base fee ajusta a cada bloco conforme ocupação |
| Polygon PoS | EIP-1559 adaptado | POL (ex-MATIC) | Custo por transação tende a ser menor que na L1 do Ethereum |
| Arbitrum One | Rollup otimista, fee L2 + custo de dados na L1 | ETH | Custo composto: execução na L2 + publicação de dados |
| Optimism | Rollup otimista, fee L2 + custo de dados na L1 | ETH | Modelo similar ao Arbitrum, sequenciador próprio |
| BNB Smart Chain | Gas price fixo por bloco, sem EIP-1559 nativo | BNB | Mecanismo de precificação diferente do padrão EIP-1559 |
Antes de confiar nessa tabela como fonte definitiva, consulte a documentação oficial de cada rede — o comportamento de fee é parte do protocolo e pode mudar com hard forks e upgrades. Para Ethereum, a referência é a própria especificação da EIP-1559; para as demais redes, a documentação oficial de cada uma.
Um cuidado prático ao portar contratos: código otimizado para o comportamento de gas de uma rede pode não ser eficiente em outra. Um contrato que assume que SLOAD é caro e evita leituras repetidas continua se beneficiando em qualquer rede EVM, porque isso é parte da especificação da máquina virtual. Mas premissas sobre o custo relativo de calldata versus storage podem variar entre L2s com modelos de compressão de dados diferentes.
Erros comuns que aumentam o gas sem necessidade
Alguns problemas de gas não vêm de falta de conhecimento técnico, mas de descuido em revisão.
Ordem de operações mal planejada. Colocar validações baratas (comparações simples) depois de operações caras (chamadas externas, escritas em storage) desperdiça gas quando a transação acaba revertendo de qualquer forma. A prática recomendada é validar tudo o que for barato primeiro (padrão checks-effects-interactions), e só então executar as partes caras.
Emissão excessiva de eventos. Eventos são mais baratos que storage, mas não são gratuitos. Emitir eventos redundantes, ou emitir dados que já podem ser derivados de outros eventos, é gas jogado fora sem ganho de observabilidade real.
Falta de auditoria de gas antes do deploy. Ferramentas como o gas reporter do Hardhat ou o profiler do Foundry mostram o consumo de gas função por função antes de o contrato ir para produção. Rodar esse relatório é barato e evita descobrir, depois do deploy, que uma função crítica custa caro demais para ser usada em produção — e contratos deployados não podem ser corrigidos sem migração completa.
Uma checklist de segurança também deve incluir uma passagem de gas. O checklist prático de auditoria de DApps cobre pontos de segurança que frequentemente se cruzam com otimização de gas — por exemplo, loops não limitados são tanto um risco de segurança (denial of service) quanto um problema de custo.
Na NeuroArt DApp estavamos em dúvida entre POL e BASE, ambas L2... optamos por BASE, pela facilidade de aarquitetura e redução do gas fee.
Perguntas Frequentes
O que acontece se o gas limit definido for menor que o necessário?
A transação falha com erro de "out of gas" antes de completar a execução. O estado é revertido, mas o gas já consumido até o ponto da falha não é devolvido ao remetente.
Gas fee alto significa transação mais rápida?
Não diretamente o gas fee total, mas a priority fee (tip) oferecida ao validador. Uma priority fee mais alta aumenta a chance de inclusão em blocos mais próximos, já que validadores priorizam transações mais lucrativas.
É possível recuperar gas fee de uma transação revertida?
Não. Gas consumido até o ponto da reversão é cobrado normalmente, mesmo que o estado seja revertido. Por isso validar condições baratas antes de operações caras reduz o custo de falhas previsíveis.
Como o EIP-1559 mudou o cálculo de gas fees?
Antes da EIP-1559, todo o pagamento ia para o minerador via leilão de gas price simples. Depois, uma base fee é calculada algoritmicamente por bloco e queimada, e o usuário paga separadamente uma priority fee ao validador.
Ferramentas de estimativa de gas são sempre precisas?
Não. eth_estimateGas e simulações de bibliotecas como ethers.js e viem refletem o estado no momento da chamada, mas a base fee e o resultado da execução podem mudar até a transação ser efetivamente incluída em um bloco.