Шпаргалка по Solidity
Структура контракта
Каждый файл начинается с лицензии и pragma; контракт - единица деплоя.
| Синтаксис | Значение |
|---|---|
// SPDX-License-Identifier: MIT | Комментарий с лицензией, который компилятор ожидает в строке 1 |
pragma solidity ^0.8.0; | Версия компилятора, для которой написан файл |
contract Counter { ... } | Объявить контракт (состояние + функции) |
constructor(uint start) { count = start; } | Выполняется один раз, при деплое |
import "./Token.sol"; | Импортировать другой файл |
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | Импортировать пакет библиотеки |
interface IToken { function balanceOf(address a) external view returns (uint); } | Объявить интерфейс (без тел функций) |
library Math { function min(uint a, uint b) internal pure returns (uint) { ... } } | Библиотека переиспользуемых функций |
Типы значений
У целых чисел фиксированный размер и нет дробной части; 0.8 откатывает транзакцию при переполнении.
| Тип | Что хранит |
|---|---|
uint256 / uint | Целое без знака, от 0 до 2^256 - 1 (uint - это uint256) |
uint8, uint16, ... uint128 | Целые без знака меньшего размера, с шагом 8 бит |
int256 / int | Целое со знаком (допускаются отрицательные) |
bool | true или false |
address | 20-байтовый адрес аккаунта или контракта |
address payable | Адрес, который может получать Ether через transfer/send |
bytes32, bytes1... | Байтовые массивы фиксированного размера |
enum Status { Open, Closed } | Именованный набор констант, хранится как uint8 |
1 ether, 1 gwei, 1 wei | Единицы Ether: 1 ether = 10^18 wei |
1 days, 2 hours, 30 minutes | Единицы времени, в секундах |
Ссылочные типы и расположение данных
Массивы, строки, bytes, struct и mapping живут в storage, memory или calldata.
| Синтаксис | Значение |
|---|---|
string memory name | Динамическая строка UTF-8 (временная копия) |
bytes memory data | Динамический байтовый массив |
uint[] public scores; | Динамический массив в storage |
uint[3] fixed; | Массив фиксированного размера из 3 элементов |
uint[] memory tmp = new uint[](5); | Выделить массив в memory |
scores.push(42); | Добавить элемент в конец массива в storage |
scores.pop(); | Удалить последний элемент |
scores.length | Количество элементов |
storage | Постоянное, on-chain, дорогое для записи |
memory | Временное, живёт в течение одного вызова |
calldata | Входные данные внешней функции только для чтения, самый дешёвый вариант |
Mapping и struct
Mapping - хеш-таблица без длины и без итерации; struct группирует поля.
| Синтаксис | Значение |
|---|---|
mapping(address => uint) public balances; | Хранилище ключ-значение, любой ключ существует (по умолчанию 0) |
balances[msg.sender] += 1; | Чтение/запись по ключу |
mapping(address => mapping(address => uint)) allowance; | Вложенный mapping |
struct User { string name; uint age; bool active; } | Определить struct |
User memory u = User("Ada", 36, true); | Создать struct в memory |
User memory u = User({name: "Ada", age: 36, active: true}); | Создание с именованными полями |
users[msg.sender] = u; | Сохранить struct в mapping |
users[msg.sender].age = 37; | Обновить одно поле в storage |
delete users[msg.sender]; | Сбросить к значениям по умолчанию |
Функции и видимость
Каждая функция указывает, кто может её вызвать и читает ли она состояние или пишет в него.
| Синтаксис | Значение |
|---|---|
function add(uint a, uint b) public pure returns (uint) { return a + b; } | Функция с параметрами и возвращаемым значением |
public | Вызывается откуда угодно (внутри и снаружи) |
external | Вызывается только извне контракта |
internal | Этот контракт и контракты, которые его наследуют |
private | Только этот контракт |
view | Читает состояние, никогда не пишет |
pure | Вообще не читает состояние |
payable | Может получать Ether вместе с вызовом |
returns (uint sum, bool ok) | Несколько именованных возвращаемых значений |
(uint s, bool ok) = f(); | Деструктурировать несколько возвращаемых значений |
uint public count; | Публичная переменная состояния получает автоматический геттер count() |
Модификаторы, константы и наследование
Переиспользуйте проверки через модификаторы; фиксируйте значения через constant и immutable.
| Синтаксис | Значение |
|---|---|
modifier onlyOwner() { require(msg.sender == owner, "Not owner"); _; } | Определить модификатор (_ = выполнить тело функции) |
function withdraw() public onlyOwner { ... } | Применить модификатор |
uint public constant MAX = 100; | Константа времени компиляции |
address public immutable owner; | Задаётся один раз в конструкторе, затем не меняется |
contract Token is ERC20, Ownable { ... } | Наследовать от других контрактов |
function f() public virtual { ... } | Разрешить переопределение |
function f() public override { ... } | Переопределить функцию родителя |
super.f(); | Вызвать реализацию родителя |
abstract contract Base { function f() public virtual; } | Контракт с нереализованными функциями |
Управление потоком
Обычные конструкции семейства C; нет switch, а циклы стоят газа на каждой итерации.
| Синтаксис | Значение |
|---|---|
if (x > 5) { ... } else if (x > 2) { ... } else { ... } | Условные ветви |
for (uint i = 0; i < n; i++) { ... } | Цикл со счётчиком |
while (x < 10) { x++; } | Цикл, пока выполняется условие |
do { ... } while (cond); | Выполняется хотя бы один раз |
break; / continue; | Выйти из цикла / перейти к следующей итерации |
x > 0 ? a : b | Тернарное выражение |
a / b | Целочисленное деление (отбрасывает остаток) |
a % b | Остаток |
a ** 2 | Возведение в степень |
unchecked { x++; } | Пропустить проверки переполнения (экономит газ, использовать осторожно) |
Ошибки: require, revert, assert
Неудавшаяся проверка откатывает всю транзакцию и возвращает неиспользованный газ.
| Синтаксис | Значение |
|---|---|
require(amount > 0, "Amount must be positive"); | Проверить ввод или состояние; откатить с сообщением |
revert("Not allowed"); | Прервать безусловно |
error Insufficient(uint available, uint requested); | Объявить пользовательскую ошибку (дешевле строк) |
revert Insufficient(balance, amount); | Откатить с пользовательской ошибкой |
assert(total == a + b); | Проверить инвариант, который никогда не должен нарушаться |
try token.transfer(to, amt) returns (bool ok) { ... } catch { ... } | Обработать неудавшийся внешний вызов |
События
События записывают логи, на которые могут подписываться off-chain приложения; из контрактов они не читаются.
| Синтаксис | Значение |
|---|---|
event Transfer(address indexed from, address indexed to, uint value); | Объявить событие |
emit Transfer(msg.sender, to, amount); | Сгенерировать его |
indexed | Фильтруемый параметр (до 3 на событие) |
event Log(string message); | Логировать можно любой тип ABI |
Ether, адреса и глобальные переменные
Контекст транзакции берётся из msg, block и tx.
| Синтаксис | Значение |
|---|---|
msg.sender | Адрес, вызвавший эту функцию |
msg.value | Wei, отправленные с вызовом (нужен payable) |
block.timestamp | Время текущего блока (секунды с начала эпохи) |
block.number | Высота текущего блока |
tx.origin | Внешний аккаунт (EOA), инициировавший транзакцию (не используйте для авторизации) |
address(this).balance | Баланс Ether этого контракта |
payable(to).transfer(1 ether); | Отправить Ether, откат при неудаче |
(bool ok, ) = to.call{value: amt}(""); | Низкоуровневая отправка, возвращает флаг успеха |
receive() external payable {} | Выполняется при простом переводе Ether |
fallback() external payable {} | Выполняется, когда ни одна функция не подошла |
keccak256(abi.encodePacked(a, b)) | Хешировать значения |
abi.encode(x), abi.decode(data, (uint)) | Кодировать / декодировать данные ABI |
Весь синтаксис Solidity, который вам нужен, на одной странице. Эта шпаргалка по Solidity - краткий справочник по языку смарт-контрактов Ethereum и всех EVM-сетей: как объявить контракт, выбрать типы, хранить данные в mapping и struct, писать функции с правильной видимостью и изменяемостью и защищать их с помощью require, модификаторов и событий.
Здесь используется синтаксис Solidity 0.8, который по умолчанию проверяет арифметическое переполнение и работает с Remix, Hardhat и Foundry. Копируйте нужное или попробуйте вживую в плейграунде Solidity - напишите контракт, скомпилируйте его и запустите на EVM в браузере.
Solidity cheat sheet FAQ
Is this Solidity cheat sheet free?
Yes. This cheat sheet is free to use, with no sign-up required. Bookmark it and come back any time you need a quick reference.
Is this cheat sheet good for beginners?
Yes. It is organized by topic so you can find what you need at any level, and each entry links back to Coddy's free interactive Solidity course when you want to go deeper.