На следующее утро Алекс проснулся с необычным чувством. Его первый контракт уже был развернут в блокчейне — пусть и простой, он был живым. И этот факт не давал покоя:
— «Вчера я просто поздоровался с блокчейном…» — задумчиво тянет он, глядя в потолок. — «Но сегодня я хочу большего. Просто поздороваться — это слишком просто. Хочу, чтобы с моим контрактом можно было взаимодействовать!»
Он начинает изучать документацию Solidity. И вдруг обнаруживает: для этого всего есть инструменты. Переменные. Функции. Всё, как в обычном программировании — только внутри блокчейна.
Алекс проснулся
Термины
Развертывание контракта — процесс публикации смарт-контракта в блокчейне. При развертывании код контракта записывается в блокчейн навсегда, получает уникальный адрес и становится доступным для взаимодействия. После развертывания контракт нельзя изменить, но можно вызывать его функции.
Лицензия — указание на условия использования кода смарт-контракта. Определяет, как можно использовать, модифицировать и распространять код. Обычно указывается в начале файла в формате SPDX.
Версия Solidity — указание на то, какая версия компилятора Solidity должна использоваться для компиляции контракта. Разные версии могут иметь разный синтаксис и возможности.
Импорт — подключение внешних библиотек или контрактов к текущему контракту. Позволяет использовать готовые проверенные решения и не писать код с нуля.
Структура (struct) — пользовательский тип данных, который группирует несколько связанных переменных под одним именем. Например, структура User может содержать имя, возраст и адрес пользователя.
Перечисление (enum) — пользовательский тип данных с ограниченным набором именованных значений. Например, статус заказа может быть только "новый", "обработанный" или "отправленный".
Событие (event) — способ уведомления внешних приложений о том, что в контракте произошло что-то важное. События записываются в логи блокчейна и могут быть отслежены.
Модификатор (modifier) — специальная конструкция, которая позволяет добавить проверки или ограничения к функциям. Используется для контроля доступа и валидации условий.
Конструктор — специальная функция, которая выполняется только один раз при создании контракта. Используется для инициализации переменных состояния и настройки начальных параметров.
Структура смарт-контракта
Смарт-контракт похож на класс в объектно-ориентированном языке программирования. Он представляет из себя набор данных и функций – действий, способных работать с данными. Обычно функции и данные в одном смарт-контракте связаны логически. Например, смарт-контракт может следить за балансом пользователя или управлять счетчиком. Одна задача – один смарт-контракт.
Далее мы рассмотрим каждый элемент структуры смарт-контракта.
Лицензия
Лицензия определяет, как можно использовать смарт-контракт. Например, лицензия MIT позволяет использовать код без ограничений, а лицензия GPL требует, чтобы код, созданный на основе этого кода, также был открытым. Смарт-контракты обычно имеют лицензию MIT.
Solidity
// SPDX-License-Identifier: MIT
Версия Solidity
Версия Solidity определяет, какие возможности и синтаксис будут доступны в коде.
Solidity
pragmasolidity ^0.8.0;
Импорты
Подключение библиотек позволяет использовать готовые функции и структуры, которые уже были протестированы и проверены.
Структуры, перечисления и события определяют типы данных, которые могут использоваться в контракте.
Структуры группируют логически связанные данные в один тип.
Перечисления позволяют создать собственный тип данных с ограниченным набором именованных вариантов. Например, статус пользователя может быть только "активный", "заблокированный" или "удаленный" — никаких других значений быть не может.
События используются для уведомления внешнего мира о произошедших событиях.
Solidity
// SPDX-License-Identifier: MIT
pragmasolidity ^0.8.0;
contractSimpleStorage{
// Структура, хранящая айди пользователя, его имя и статус
structUser {
uint256 id;
string name;
UserStatus status;
}
// Перечисление статусов пользователя
enumUserStatus {
ACTIVE,
INACTIVE,
BANNED
}
// Событие, уведомляющее о том, что пользователь изменил свое имя
eventNameChanged(uint256 id, string name);
...
}
Кастомные модификаторы используются для ограничения доступа к функциям смарт-контракта. Мы можем определить, кто может вызывать функцию, и какие действия можно выполнять с ней.
Solidity
// SPDX-License-Identifier: MIT
pragmasolidity ^0.8.0;
contractSimpleStorage{
...
// Модификатор, ограничивающий доступ к функции только для владельца контракта
modifieronlyOwner() {
require(msg.sender== owner, "Only owner can call this function");
_;
}
// Модификатор, ограничивающий доступ к функции только для активных пользователей
modifieronlyActive() {
require(user.status == UserStatus.ACTIVE, "User is not active");
_;
}
...
}
Кастомные модификаторы можно указать в объявлении функции, чтобы контролировать, кто может её вызывать.
Переменные
Переменные нужны для хранения данных в смарт-контракте. Они могут быть публичными, приватными или внутренними.
В зависимости от типа видимости переменные могут быть доступны для чтения снаружи, внутри контракта или только внутри его функций.
Важно:public переменная не означает, что её можно изменить извне! Это объявление только создает геттер – функцию для чтения переменной извне. Для изменения необходимо присвоить переменной новое значение в функции.
Функции
Функции — это действия, которые может выполнять смарт-контракт. Они могут быть публичными, приватными или внутренними.
В зависимости от типа видимости функции могут быть доступны, либо недоступны для вызова снаружи. Например, private функции доступны для вызова только внутри другой функции текущего смарт-контракта, их невозможно вызвать извне. public функции могут быть вызваны другими смарт-контрактами или пользователелями в транзакции.
Конструктор
Конструктор — это специальная функция, которая вызывается при создании смарт-контракта. Она используется для инициализации переменных.
Solidity
// SPDX-License-Identifier: MIT
pragmasolidity ^0.8.0;
contractSimpleStorage{
addresspublic owner;
...
constructor() {
// Кладем в переменную owner адрес пользователя, который создал контракт
owner =msg.sender;
}
...
}
Практическое задание
Алекс изучил структуру смарт-контракта и решил создать свой контракт для управления пользователями. Но когда он писал код, его младший брат решил "помочь" и перемешал все части контракта! Теперь лицензия находится посередине, функции в начале, а переменные разбросаны по всему файлу.
— «Компилятор не понимает мой код! Нужно расставить все части в правильном порядке!» — в панике воскликнул Алекс.
Помоги Алексу восстановить правильную структуру смарт-контракта.