Что такое ABI
ABI в Ethereum: как TypeScript-код понимает функции смарт-контракта, кодирует calldata и читает ответы через RPC.
Что такое ABI
ABI — это описание интерфейса смарт-контракта.
Код контракта в сети хранится как bytecode. ABI объясняет вашему приложению, какие функции есть у контракта, какие аргументы они принимают и как декодировать ответ.
Зачем нужен ABI
Без ABI приложение видит только адрес и байткод:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
0x608060405260043610...С ABI этот же адрес превращается в понятный объект:
weth.name()
weth.symbol()
weth.decimals()
weth.balanceOf(address)Ethereum не хранит имена функций в удобном виде для frontend или backend. ABI добавляет этот слой понимания на стороне вашего кода.
Читаем WETH через ABI
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("https://ethereum.publicnode.com");
const wethAddress = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
const vitalikAddress = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
const wethAbi = [
"function name() view returns (string)",
"function symbol() view returns (string)",
"function decimals() view returns (uint8)",
"function balanceOf(address owner) view returns (uint256)",
];
const weth = new ethers.Contract(wethAddress, wethAbi, provider);
const name = await weth.name();
const symbol = await weth.symbol();
const decimals = await weth.decimals();
const balance = await weth.balanceOf(vitalikAddress);
console.log("Name:", name);
console.log("Symbol:", symbol);
console.log("Decimals:", decimals.toString());
console.log("Balance:", ethers.formatUnits(balance, decimals));Этот код вызывает реальные функции WETH-контракта в Ethereum mainnet. Без ABI ethers не узнал бы, как собрать запрос к balanceOf(address) и как прочитать uint256 из ответа.
Как это работает
wethAbi — минимальный ABI. В нём только те функции, которые нужны скрипту.
new ethers.Contract(wethAddress, wethAbi, provider) — создаёт объект контракта по адресу, ABI и RPC-провайдеру.
weth.balanceOf(vitalikAddress) — ethers берёт описание balanceOf(address), кодирует аргумент и отправляет eth_call.
ethers.formatUnits(balance, decimals) — переводит raw uint256 в читаемое количество токенов с учётом decimals.
ABI превращается в calldata
Когда вы вызываете функцию контракта, Ethereum получает не имя функции, а байты в поле data.
import { ethers } from "ethers";
const vitalikAddress = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
const abi = ["function balanceOf(address owner) view returns (uint256)"];
const iface = new ethers.Interface(abi);
const calldata = iface.encodeFunctionData("balanceOf", [vitalikAddress]);
console.log(calldata);Результат начинается с function selector:
0x70a08231...0x70a08231 — первые 4 байта от хеша сигнатуры balanceOf(address). После них идут закодированные аргументы функции.
Что бывает в ABI
| Элемент | Зачем нужен |
|---|---|
function | вызвать или прочитать функцию контракта |
event | декодировать логи из receipt |
constructor | описать аргументы деплоя |
error | декодировать custom error при revert |
Для чтения баланса ERC-20 не нужен полный ABI токена. Достаточно одной строки balanceOf(address).
Частые ошибки
Передавать неправильный ABI → адрес может быть верным, но вызов сломается, если ABI описывает другую функцию или другой порядок аргументов.
Думать, что ABI хранится в блокчейне → в сети хранится bytecode. ABI обычно берут из исходников, артефактов компиляции или explorer API.
Использовать полный ABI без необходимости → для простого чтения можно передать только нужные функции. Это короче и легче проверять.
Что дальше
- Провайдер vs Сайнер — как читать контракт и как отправлять транзакции
- Чтение данных из контракта — как вызывать
viewфункции через ABI - Events и logs — как ABI помогает декодировать события контракта