Опубликовано:
Обновлено:
Во многих цифровых процессах не хватает простых вещей — четких правил, предсказуемости и доверия. Смарт-контракты решают это кодом. В этой статье разберем, как создаются такие протоколы, и соберем минимальный набор инструментов для дальнейшей работы.
Смарт-контракт — это маленькая программа, которая живет в блокчейне и автоматически выполняет правила: кто и что может делать, когда и на каких условиях. Сильные стороны этой технологии — прозрачность (код видно), предсказуемость (выполняется одинаково для всех) и отсутствие «человеческого фактора» в момент исполнения. На этом строят токены, платежные схемы, игры с предметами, DAO, аукционы — все, где важно доверять правилам, а не людям.
Если вам нужно писать контракты, проверять их или быстро прототипировать идеи, начнем с минимального набора — инструментов и настроек, которые закрывают весь цикл «идея → код → проверка → запуск в песочнице» без лишней установки и рисков. В него входят:
- редактор кода (VS Code / VSCodium) + расширение Solidity (Nomic Foundation);
- удобная среда (Linux/macOS или Windows с WSL);
- фреймворк Foundry;
- автоматические тесты.
С этой связкой вы за вечер сможете:
- развернуть локальную сеть или форк мейннета;
- запустить юнит- и fuzz-тесты;
- добавить базовые инварианты (простые неизменные правила контракта, которые Foundry автоматически проверяет при любых последовательностях действий);
И все это вы сделаете без реальных денег и риска что-либо сломать.
Такой старт уже дает практическую пользу: можно собрать прототип токена или аукциона, воспроизвести баг-репорт, оценить безопасность логики и, главное, говорить с техкомандой на одном языке.
Рабочая среда Foundry: от нуля до первого теста
Здесь мы шаг-за-шагом попробуем создать свой первый смарт-контракт через фреймворк Foundry: инициализируем проект, напишем простые функции, запустим тесты и, при желании, поднимем локальную сеть/форк для экспериментов.
Мы берем Foundry как базовую среду, потому что это самый короткий путь от идеи до проверенного контракта: очень быстрые сборка и тесты, встроенные fuzz и инварианты, газ-репорт из коробки и простые деплой-скрипты — все без лишних Node/Python-зависимостей. Ниже — сравнение с альтернативами, чтобы увидеть контекст выбора.

Какие задачи закрывает Foundry:
- Быстрый цикл «написал → проверил». Сборка и тесты запускаются одной командой — сразу видно «зеленый/красный».
- Автоматические проверки «по краям». Встроенный fuzz гоняет ваши функции на сотнях входов, а инварианты следят за правилами системы при длинных сценариях.
- Безопасные эксперименты. Локальная сеть (Anvil) имитирует блокчейн у вас «под рукой», а форк сети позволяет воспроизводить поведение, как в живой, реальной среде, без риска.
- Измерение стоимости. Газ-репорт показывает, какие функции «дорогие» и где вы теряете эффективность.
- Деплой и скрипты. Простые команды для развертывания и вызовов контрактов — без сложных настроек.
Из чего состоит Foundry?
Стек включает в себя 4 утилиты, которые легко запомнить:
- forge — сборка, тестирование, деплой. «Рабочая лошадка» вашего проекта;
- anvil — локальный узел и форки реальных сетей (Mainnet/Sepolia и т. д.);
- cast — удобные вызовы к контрактам и RPC (чтение состояния, отправка транзакции);
- chisel — интерактивная «песочница» для быстрой проверки кусочков Solidity.
Типичный рабочий процесс с Foundry
- Создаете проект и пишете контракт.
- Пишете тесты: сначала обычные, затем добавляете fuzz и, при необходимости, инварианты.
- Запускаете локальную сеть (или форк) и проигрываете сценарии «как в реальной сети».
- Смотрите отчет по газу, оптимизируете и развертываете (деплоите) туда, где нужно: локально, в тестнет или прод.
Порог входа — низкий. Начать можно без установки на свой компьютер — прямо в браузере, в облачной среде (например, GitHub Codespaces). Там же вы запустите forge test, поднимете anvil, выполните cast call/send. Когда будет удобно — перенесете тот же проект локально.
Мини-словарь
- Fuzz-тест — тест, который автоматически подставляет множество случайных входов, чтобы поймать неожиданные случаи.
- Инвариант — правило, которое всегда должно выполняться при любых последовательностях действий (например: «баланс не уходит в минус», «лимит не превышается»).
- Форк сети — локальная копия состояния выбранной сети «на текущем блоке», где можно безопасно повторять «реальные» сценарии.
Зачем вам это нужно:
- Разработчику на старте: быстрое освоение практики без «боли установки», уверенность за счет тестов и fuzz.
- Исследователю безопасности: воспроизведение баг-репортов на форке, проверка свойств через инварианты.
- Продакту/аналитику: возможность проверить правила «на деле» и говорить с техкомандой на одном языке.
Дальше пойдем по шагам: откроем облачную среду, установим Foundry, напишем простой контракт, добавим тесты, fuzz и инвариант, поднимем anvil (и при желании — форк), затем развернем контракт и вызовем его методы. Все — с понятными ожиданиями «что сделать» и «что получить на выходе».
Развертывание смарт-контракта через Foundry
Чтобы не зависать в теории, начнем с практики в облаке. Проведем короткий эксперимент и соберем «песочницу» для смарт-контрактов прямо в браузере (GitHub Codespaces). К финалу мини-эксперимента у вас будет готовое облачное рабочее место:
- редактор VS Code в браузере, Linux-окружение и установленный Foundry;
- созданный проект, проходящий базовые тесты;
- запущенный локальный узел Anvil или форк основной сети (опционально);
- плюс две автоматические проверки — fuzz-тест (гоняет функцию на разных входах) и простой инвариант (правило, которое всегда должно выполняться).
С таким комплектом вы соберете прототип (токен/ NFT/ аукцион), проверите доступы, смоделируете эскроу и таймлоки, поймаете ошибки до ревью, воспроизведете баг на форке и поймете, что «дорого» по газу. А еще — сможете обсуждать все с командой на языке тестов. Этого хватит, чтобы уверенно двигаться дальше.
Пошаговая инструкция по работе с Foundry
Оптимальный старт — запустить Foundry в облачной среде GitHub Codespaces: работаем прямо в браузере, без локальной установки, и сразу переходим к практике.
0) Подготовьте Codespace
Что сделать
- Переходим на GitHub (https://github.com/features/codespaces) и регистрируемся.
- Создаем репозиторий → Create repository

- Называем репозиторий именем проекта, например, hello-foundry.

- Жмем Create repository

- Переходим во вкладку Code

- В репозитории создаем файл → Creating a new file

- Называем его README.md → добавляем любой текст, например, Commit

Подтверждаем

- Жмем Code → Codespaces → Create codespace on main

- Дождаться открытия VS Code в браузере → Terminal → New Terminal.

Что должно получиться:
- Открылся VS Code в браузере, внизу есть терминал со строкой вида:
codespace@…:/workspaces/hello-foundry$
1. Устанавливаем Foundry
Отправляем в терминал Codespaces:
export PATH=»$HOME/.foundry/bin:$PATH» \
&& curl -L https://foundry.paradigm.xyz | bash \
&& source ~/.bashrc \
&& foundryup
forge —version && anvil —version && cast —version && chisel —version

Что должно получиться:
- Печатаются версии всех утилит (например, forge Version: 1.3.1-stable).

Все инструменты готовы.
2. Создаем проект Foundry
Отправляем в терминал forge init hello — это команда Foundry, которая создает новый проект в папке hello с готовой структурой и шаблонами:
forge init hello
cd hello
forge test

Что должно получиться:
В консоли несколько строк PASS … и итог ok. X passed; 0 failed. Базовые тесты из шаблона прошли.

3. Добавляем контракт Counter
Создаем файл src/Counter.sol автоматически — прямо из терминала Codespaces.
mkdir -p src && cat > src/Counter.sol <<‘SOL’
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
contract Counter {
uint256 public number;
function setNumber(uint256 newNumber) public { number = newNumber; }
function increment() public { number++; }
}
SOL

Что должно получиться:
- Появится файл src/Counter.sol с нужным содержимым.
- Проверка: ls src и forge build (сборка без ошибок).

Вот, что должно отображаться в содержимом файла Counter.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
contract Counter {
uint256 public number;
function setNumber(uint256 newNumber) public { number = newNumber; }
function increment() public { number++; }
}

4. Пишем тесты
Создаем файл test/Counter.t.sol одной командой, которую отправляем в терминал:
mkdir -p test && cat > test/Counter.t.sol <<‘SOL’
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import «forge-std/Test.sol»;
import «../src/Counter.sol»;
contract CounterTest is Test {
Counter counter;
function setUp() public {
counter = new Counter();
}
function test_SetNumber() public {
counter.setNumber(5);
assertEq(counter.number(), 5);
}
function test_Increment() public {
counter.increment();
assertEq(counter.number(), 1);
}
// Fuzz: прогон на множестве входов
function testFuzz_SetNumber(uint256 x) public {
vm.assume(x < 1e18);
counter.setNumber(x);
assertEq(counter.number(), x);
}
}
SOL

Файл Counter.t.sol должен содержать следующие значения:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import «forge-std/Test.sol»;
import «../src/Counter.sol»;
contract CounterTest is Test {
Counter counter;
function setUp() public {
counter = new Counter();
}
function test_SetNumber() public {
counter.setNumber(5);
assertEq(counter.number(), 5);
}
function test_Increment() public {
counter.increment();
assertEq(counter.number(), 1);
}
// Fuzz: прогон на множестве входов
function testFuzz_SetNumber(uint256 x) public {
vm.assume(x < 1e18);
counter.setNumber(x);
assertEq(counter.number(), x);
}
}

Запустите тест:
forge test

Что должно получиться:
- Три PASS (обычные тесты + fuzz), итог ok. 3 passed; 0 failed.

5. Поднимаем локальную сеть (Anvil)
Открываем вторую вкладку терминала.

Запускаем:
source ~/.bashrc
export PATH=»$HOME/.foundry/bin:$PATH»
anvil —version
Что должно получиться:
- Терминал выдаст версию anvil ….

Запускаем в терминале:
anvil

(оставьте это окно открытым; для остановки — Ctrl+C)
Что должно получиться
- В логе видно Listening on 127.0.0.1:8545 и список тестовых аккаунтов с приватными ключами.

- В Codespaces во вкладке Ports появился порт 8545.

Это «песочница»: можно деплоить и вызывать контракты без риска и без реальных средств.
6. Задаем переменные окружения для деплоя: RPC и API-ключ
- RPC_URL — куда отправлять команды (локальный Anvil или форк/тестнет).
- PRIVATE_KEY — нужен для транзакций (деплой, cast send). Для локального Anvil используем любой ключ из его лога — там уже есть тестовый баланс.
Мы будем работать с локальным Anvil (из шага 5). Отправляем в терминал
export RPC_URL=http://127.0.0.1:8545
export PRIVATE_KEY=0xВАШ_КЛЮЧ_ИЗ_ЛОГА_ANVIL
Этот код редактируем в следующем порядке: одну строку оставляем как есть, вторую — заменяем.
- RPC_URL не редактируем для локального Anvil:
export RPC_URL=http://127.0.0.1:8545
- 0xВАШ_КЛЮЧ_ИЗ_ЛОГА_ANVIL заменяем на реальный ключ из вывода Anvil (любая строка “Private Key …” из окна, где запущен anvil):
export PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

Что должно получиться:

Чтобы убедиться, что все работает, отправляем последовательно 2 команды:
- echo $RPC_URL
- echo ${PRIVATE_KEY:0:12}…
В первом случае должно показать http://127.0.0.1:8545, во втором — первые символы ключа.

Если делаете форк реальной сети, то меняете RPC_URL на URL провайдера (регистрируемся на эти сервисах Infura/Alchemy и получаем свой API):
export RPC_URL=https://sepolia.infura.io/v3/<API_KEY>
- PRIVATE_KEY — ваш отдельный тестовый ключ (не из Anvil), с тестовым балансом.
Полезно помнить:
- Переменные действуют только в этой вкладке терминала. Откроете новую — их там нет. Повторите export … или сохраните значения в .env и подгружайте его:
# один раз создаем .env
echo ‘RPC_URL=http://127.0.0.1:8545’ > .env
echo ‘PRIVATE_KEY=0x…’ >> .env
# в каждой новой вкладке
source .env
- Секреты нельзя коммитить. Добавьте .env в .gitignore, чтобы он не попал в репозиторий:
echo ‘.env’ >> .gitignore
- Можно обойтись без переменных. Передавайте значения прямо флагами в команду:
forge create src/Counter.sol:Counter \
—rpc-url http://127.0.0.1:8545 \
—private-key 0x… \
—broadcast
печатает http://127.0.0.1:8545. Теперь forge create / cast send будут использовать эти значения по умолчанию.
- Быстрая проверка, что экспорт сработал (если используете переменные):
echo $RPC_URL
echo ${PRIVATE_KEY:0:12}…
7. Разворачиваем контракт
В рабочей вкладке терминала (не там, где крутится anvil) выполните:
forge create src/Counter.sol:Counter \
—rpc-url $RPC_URL \
—private-key $PRIVATE_KEY \
—broadcast

В выводе появятся строки:
Deployed to: 0x… и Transaction hash: 0x….

Сохраняем адрес:
export COUNTER=0x<адрес_из_вывода>
В строке 0x<адрес_из_вывода> используйте адрес из строки Deployed to: — это адрес развернутого контракта.

Если деплоите на форке: убедитесь, что в отдельной вкладке запущен anvil —fork-url «$RPC_URL».
8. Проверяем контракт вызовами cast
Отправляем в терминал задачу:
- Прочитать значение:
cast call $COUNTER «number()(uint256)» —rpc-url $RPC_URL
- Установить значение и проверить:
cast send $COUNTER «setNumber(uint256)» 7 —rpc-url $RPC_URL —private-key $PRIVATE_KEY
cast call $COUNTER «number()(uint256)» —rpc-url $RPC_URL
Что должно получиться
- До вызова setNumber функция number() возвращает 0.

- После setNumber(7) — возвращает 7.

9. (Опционально) Форк сети и вызов в реальной среде
- Остановите все anvil командой:
pkill anvil.
Проверьте RPC-URL провайдера (Alchemy/Infura/Ankr) — должен быть с реальным ключом; у Infura выключите «Require Project Secret».
Быстрая проверка:
export UPSTREAM_RPC=»https://eth-sepolia.g.alchemy.com/v2/ВАШ_КЛЮЧ»
curl -s -X POST -H «Content-Type: application/json» \
—data ‘{«jsonrpc»:»2.0″,»method»:»eth_blockNumber»,»params»:[],»id»:1}’ \
«$UPSTREAM_RPC»
- Должен прийти JSON с result: «0x…».
Поднимите форк (на отдельном порту, чтобы не конфликтовать):
anvil —fork-url «$UPSTREAM_RPC» -p 8546
- В логе увидите Forking … и Listening on 127.0.0.1:8546
Подключитесь к форку:
export RPC_URL=http://127.0.0.1:8546
cast block-number —rpc-url $RPC_URL
- Большой номер блока → все ок.
Проверьте реальный токен:
Возьмите адрес из соответствующего блок-эксплорера сети и:
cast code 0xАДРЕС —rpc-url $RPC_URL
Например,
cast code 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 (адрес USDC) —rpc-url https://mainnet.infura.io/v3/f39d740f03bb49c3b228b3f1c83df8f6 (ваш API)
- cast call 0xАДРЕС «symbol()(string)» —rpc-url $RPC_URL
Что должно получиться
- cast block-number возвращает большой номер блока (как в сети).

- Вызов symbol() возвращает строку токена (например, USDC) — значит, форк работает.

Короткий чек-лист успеха
Проверяем проделанную работу. Если все пункты выполняются, базовая среда настроена, то можно идти дальше.
- Установлен Foundry в Codespaces, команды печатают версии.
- Проект создан, тесты проходят.
- Контракт Counter собран без ошибок.
- Локальная сеть anvil слушает 127.0.0.1:8545.
- Контракт успешно задеплоен (Deployed to: 0x…).
- Вызовы cast call/send работают (значение меняется).
- (Опция) Форк создан: Forking… в логе и корректные ответы cast.
- (Опция) Деплой в тестнет завершился, адрес виден в обозревателе.
Частые ошибки и быстрые фиксы
Ниже — самые распространенные проблемы при работе с Foundry и короткие решения. Найдите свой симптом — под ним указаны причина и точная команда, чтобы быстро починить.
- bash: anvil: command not found
Во вкладке #2 выполните:
source ~/.bashrc && export PATH=»$HOME/.foundry/bin:$PATH» && anvil —version
Если нужно — foundryup. - Address already in use (os error 98)
Уже запущен другой anvil. Либо используйте его (RPC_URL=http://127.0.0.1:8545), либо остановите pkill anvil и запустите заново, либо запустите второй на другом порту:
anvil -p 8546 и export RPC_URL=http://127.0.0.1:8546. - insufficient funds при деплое/отправке
Возьмите другой PRIVATE_KEY из лога anvil — все они с тестовым балансом. - Ничего не печатает терминал
Возможно, зажали вывод Ctrl+S. Нажмите Ctrl+Q.
Либо вы в вкладке, где крутится anvil. Команды давайте во вкладке #1. - Переменные «пропали»
Они действуют в текущем терминале. В новой вкладке — повторите export … или храните в .env и делайте source .env (и не коммитьте .env).
Заключение
Вы прошли путь от идеи до «живого» результата: собрали рабочую среду, написали и протестировали контракт, запустили локальную сеть, и (по желанию) опробовали форк. Это и есть практический минимум, который позволяет не гадать, а проверять — быстро, безопасно и воспроизводимо.
Смарт-контракты дают прозрачные правила и предсказуемость. Foundry добавляет к этому скорость и контроль: тесты (включая fuzz), инварианты, отчет по газу и деплой — все под рукой и без лишних зависимостей. Такой набор инструментов уже сегодня позволяет прототипировать токены/аукционы, воспроизводить баг-репорты и говорить с командой на языке фактов, а не предположений.
Чтобы прокачать навыки, попробуйте дальше:
- Создать собственный стандартный токен. Реализуйте минимальный ERC-20/721, покройте тестами, сравните газ до/после оптимизаций.
- Проверьте инварианты «как в проде»: задайте правила сохранения сумм/лимитов и запустите stateful-fuzz.
- Вынесите шаги деплоя в script/ и запускайте через forge script —broadcast.
- Опубликуйте исходники/метаданные (верификация) на обозревателе и проверьте, что в карточке контракта видны байткод и ABI.
- Подключите forge test —gas-report в CI и снимайте «снапшоты» forge snapshot — так увидите, как меняется газ на каждом коммите.
- Перенесите проект из Codespaces на локальную машину или разверните его в Sepolia, применяя отдельный тестовый ключ; файл .env не коммитьте (добавьте в .gitignore).
Не забывайте о безопасности:
- Никогда не используйте «боевые» ключи в учебных сценариях и форках.
- Не коммитьте секреты; храните их в .env.
- Прежде чем выходить в основную сеть, убеждайтесь, что тесты зеленые, инварианты держатся, а газ укладывается в бюджет.
Если сохранить нынешнюю «песочницу», вы сможете быстро возвращаться к экспериментам: менять логику, добавлять проверки, смотреть газ — и за вечер превращать идеи в проверенный код.
Добавить комментарий