Menu
Coddy logo textTech

Шпаргалка по 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Целое со знаком (допускаются отрицательные)
booltrue или false
address20-байтовый адрес аккаунта или контракта
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.valueWei, отправленные с вызовом (нужен 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.
Coddy programming languages illustration

Изучайте Solidity с Coddy

НАЧАТЬ