Solidity Playground
Пишите, запускайте и делитесь фрагментами кода - без установки.
Нажмите «Запустить», чтобы увидеть вывод здесь.
Попробуйте Solidity в браузере
Solidity - язык смарт-контрактов Ethereum. Он исполняется на EVM - той же виртуальной машине, которая защищает сотни миллиардов долларов в mainnet и питает большинство L2. Этот playground даёт вам Monaco-редактор, подключённый к sandbox-ной связке solc + geth EVM, так что вы можете написать контракт, нажать Run и увидеть в точности, что произошло бы on-chain: вывод console.log, emit-нутые события и конечное состояние ваших storage-переменных - без деплоя, без оплаты gas и без использования wallet.
У Solidity есть несколько особенностей, которые стоит держать в голове на старте. Storage по умолчанию постоянный - всё, что вы присваиваете state-переменной, сохраняется; всё, что находится внутри функции, исчезает, как только вызов возвращается. События - это то, как контракты разговаривают с внешним миром (вашим фронтендом, индексером, The Graph) - они стоят gas, пишутся в логи транзакции и фильтруются по indexed-параметрам. И каждая external-функция получает входные данные через ABI encoding, а не через stdin - поэтому playground даёт вам типизированную панель Args, которая напрямую подключается к параметрам вашего main(...).
Что этот Solidity playground умеет хорошо
- Настоящее исполнение solc + EVM, не симуляция через транспайлер. console.log идёт через forge-std, а пути emit / storage проходят настоящую семантику EVM - opcodes, gas, всё как есть.
- Вкладка Events показывает каждый
emitиз вашего запуска, сindexed-параметрами, помеченными отдельно, так что вы видите ровно то, что получил бы фронтенд или subgraph. - Вкладка Storage показывает конечное значение каждой state-переменной, к которой обращался контракт, - включая записи в mapping (например,
balances[0xabc...]). Переменные, в которые вы не писали, не появляются. - Типизированная панель Args передаёт значения в параметрический
main(uint256 n, string memory name, ...). Runner ABI-кодирует их по сигнатуре функции, так что42становитсяuint256, а"hello"-string.
Что можно построить в Solidity playground
- Счётчики / increment-decrement-контракты, чтобы прочувствовать, как state-переменные сохраняются между вызовами - запишите в
count, запустите и посмотрите, как значение появляется во вкладке Storage. - Паттерны передачи токенов - emit-ните
Transfer(from indexed, to indexed, value)и увидите, как indexed и не-indexed поля рендерятся по-разному во вкладке Events, ровно так же, как они выглядят в реальных log topics EVM. - Случаи провала с
require/revert- напишите guard, который падает на плохом входе, и увидите сообщение revert в stdout - вместо того чтобы сжечь gas на упавшей транзакции в mainnet.
Частые вопросы о Solidity
Что такое Solidity?
Нужен ли мне wallet или testnet ETH, чтобы это использовать?
main(...) с переданными args и показывает вам stdout, события и storage этого одного вызова. После Run всё выбрасывается.Как передать входные данные в контракт?
main(...) с теми типизированными параметрами, которые вам нужны - function main(uint256 n) external или function main(string memory name, uint256 age, bool active) external view. Затем впишите значения в панель Args под редактором. Runner смотрит на сигнатуру функции и ABI-кодирует ваши строки в нужные типы - точно так же, как это делает cast call в командной строке. Для address пишите 0x...; для bool - true или false; для uint - десятичное значение.В чём разница между вкладками Output, Events и Storage?
console.log(...) из forge-std/console.sol, плюс сообщение об ошибке revert / require, если оно было. Events показывает каждое событие, которое контракт emit-нул во время запуска, по порядку, со значением каждого параметра (и небольшой пометкой "indexed" для indexed-параметров - это те, которые попадают в log topics EVM и могут фильтроваться инструментами вроде The Graph). Storage показывает значение после запуска для каждой state-переменной, в которую была запись, включая отдельные записи mapping - переменные, к которым вы не обращались, в списке не появляются.Почему в некоторых туториалах по Solidity нет main()?
main() как соглашение, чтобы было очевидно, что запускать, и куда класть аргументы. Вне playground ваш контракт обычно выставляет несколько функций (mint, transfer, withdraw, ...), и ваш фронтенд или инструмент вроде cast / ethers / viem выбирает, какую вызвать.