Gas — как считается и кто платит
Как Ethereum считает комиссию транзакции: gas limit, gas used, base fee, priority fee и кто платит за выполнение.
Gas — как считается и кто платит
Gas — это единица стоимости вычислений в Ethereum.
Любая запись в State требует работы EVM: проверить подпись, изменить баланс, выполнить код контракта, записать логи. За эту работу платит отправитель транзакции.
Формула комиссии
Комиссия = gasUsed × effectiveGasPricegasUsed — сколько gas реально потратила транзакция.
effectiveGasPrice — фактическая цена одного gas в wei.
Если транзакция потратила 21 000 gas, а цена gas была 20 gwei, комиссия будет:
21 000 × 20 gwei = 420 000 gwei = 0.00042 ETHСчитаем комиссию реальной транзакции
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("https://ethereum.publicnode.com");
const block = await provider.getBlock("latest");
if (!block || block.transactions.length === 0) {
throw new Error("В последнем блоке нет транзакций");
}
const txHash = block.transactions[0];
const tx = await provider.getTransaction(txHash);
const receipt = await provider.getTransactionReceipt(txHash);
if (!tx || !receipt) {
throw new Error("Транзакция ещё не доступна через RPC");
}
const minedBlock = await provider.getBlock(receipt.blockNumber);
const baseFeePerGas = minedBlock?.baseFeePerGas ?? 0n;
const effectiveGasPrice = receipt.gasPrice;
const totalFee = receipt.gasUsed * effectiveGasPrice;
const priorityFeePerGas = effectiveGasPrice > baseFeePerGas
? effectiveGasPrice - baseFeePerGas
: 0n;
console.log("Hash:", tx.hash);
console.log("From:", tx.from);
console.log("Gas limit:", tx.gasLimit.toString());
console.log("Gas used:", receipt.gasUsed.toString());
console.log("Base fee:", ethers.formatUnits(baseFeePerGas, "gwei"), "gwei");
console.log("Priority fee:", ethers.formatUnits(priorityFeePerGas, "gwei"), "gwei");
console.log("Effective gas price:", ethers.formatUnits(effectiveGasPrice, "gwei"), "gwei");
console.log("Total fee:", ethers.formatEther(totalFee), "ETH");Этот код берёт транзакцию из последнего блока mainnet и считает, сколько ETH она реально стоила отправителю.
Как это работает
tx.gasLimit — максимум gas, который отправитель разрешил потратить.
receipt.gasUsed — сколько gas транзакция потратила после выполнения в EVM.
receipt.gasPrice — фактическая цена gas для уже включённой транзакции.
baseFeePerGas — обязательная часть комиссии. Она сжигается протоколом и не достаётся валидатору.
priorityFeePerGas — чаевые валидатору за включение транзакции в блок.
receipt.gasUsed * receipt.gasPrice — итоговая комиссия, списанная с отправителя.
Gas limit vs gas used
gasLimit — это лимит, а не точная цена.
gasLimit = 100 000
gasUsed = 63 421
Платите только за 63 421 gasНеиспользованный gas возвращается отправителю. Если gas закончился во время выполнения, транзакция падает, изменения State откатываются, но потраченный gas не возвращается.
Кто платит
Платит всегда EOA, который подписал транзакцию.
Если вы вызываете контракт, комиссию платит ваш кошелёк. Если контракт внутри своей логики вызывает другой контракт, комиссию всё равно платит исходный отправитель транзакции.
EOA отправил транзакцию
↓
Контракт A выполнил код
↓
Контракт A вызвал Контракт B
↓
Gas платит EOAКонтракт может компенсировать пользователю расходы отдельной логикой, но на уровне протокола gas списывается с отправителя транзакции.
Почему чтение бесплатно
eth_call не меняет State. RPC-нода локально симулирует выполнение и возвращает результат.
Поэтому balanceOf(), name(), decimals() и другие view функции можно читать бесплатно. Но если та же функция вызывается внутри транзакции, её выполнение уже потребляет gas.
Частые ошибки
Путать gas и ETH → gas измеряет работу EVM, ETH оплачивает эту работу.
Думать, что gasLimit всегда списывается полностью → списывается только gasUsed × effectiveGasPrice, неиспользованный gas возвращается.
Считать failed-транзакцию бесплатной → если транзакция попала в блок и упала, gas за выполненные операции всё равно списывается.
Что дальше
- Как работает транзакция изнутри — где gas находится в жизненном цикле транзакции
- Провайдер vs Сайнер — кто читает данные и кто оплачивает запись
- Что такое ABI — как вызов функции превращается в calldata