Введение
Разработка на блокчейне — это не просто написание кода. Это искусство балансировать между безопасностью, газовой эффективностью и читаемостью. Когда я начинал писать смарт-контракты на Solidity в 2020 году, каждая строчка требовала проверки на reentrancy, переполнение и front-running. Сейчас, в 2026, инструменты AI стали неотъемлемой частью моего workflow: они генерируют шаблоны, находят уязвимости и оптимизируют газ. Но без качественного промта AI часто выдаёт «сырой» код, который приходится переписывать. Я собрал 12 проверенных промтов, которые использую ежедневно для Solidity, Rust (в контексте Solana) и Vyper. Каждый промт сопровождается реальным примером применения и блоком кода. Никакой теории — только практика.
1. Генерация шаблона ERC-20 токена (Solidity)
Промт: «Напиши полный контракт ERC-20 на Solidity 0.8.x с использованием OpenZeppelin 5.x. Контракт должен включать: имя 'MyToken', символ 'MTK', начальное предложение 1 000 000 токенов (18 decimals), функцию mint с модификатором onlyOwner, функцию burn для любого держателя, а также событие Mint и Burn. Добавь комментарии к каждой функции на русском языке. Убедись, что код следует лучшим практикам безопасности (защита от reentrancy, проверка переполнения) и оптимизирован по газу (избегай лишних storage-переменных).»
Пример использования: Когда нужно быстро развернуть тестовый токен для DeFi-проекта. AI генерирует готовый контракт, который остаётся только скомпилировать в Remix.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC20, Ownable {
event Mint(address indexed to, uint256 amount);
event Burn(address indexed from, uint256 amount);
// Конструктор: задаём имя, символ и начальное предложение
constructor() ERC20("MyToken", "MTK") Ownable(msg.sender) {
_mint(msg.sender, 1_000_000 * 10 ** decimals());
}
// Функция mint: только владелец может выпускать новые токены
function mint(address to, uint256 amount) external onlyOwner {
_mint(to, amount);
emit Mint(to, amount);
}
// Функция burn: любой пользователь может сжечь свои токены
function burn(uint256 amount) external {
_burn(msg.sender, amount);
emit Burn(msg.sender, amount);
}
}
2. Аудит безопасности контракта (Solidity)
Промт: «Проведи аудит следующего контракта на Solidity. Найди все уязвимости: reentrancy, переполнение целочисленных типов, проблемы с доступом, front-running, использование tx.origin вместо msg.sender. Для каждой найденной проблемы: укажи строку кода, опиши риск (например, "кража средств"), и предложи исправление. Используй чеклист из документации Consensys (https://consensys.github.io/smart-contract-best-practices/). Если контракт безопасен — напиши "Безопасен".»
Пример использования: Перед деплоем контракта в mainnet я прогоняю его через этот промт. AI находит проблемы, которые статические анализаторы (например, Slither) иногда пропускают, например, race conditions в редких сценариях.
contract Vulnerable {
mapping(address => uint) balances;
function withdraw(uint amount) external {
require(balances[msg.sender] >= amount);
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] -= amount; // Уязвимость: reentrancy
}
}
// Ответ AI: Строка 5 — reentrancy: атакующий может вызвать withdraw рекурсивно до обновления баланса. Исправление: использовать паттерн Checks-Effects-Interactions (обновить баланс перед отправкой).
3. Оптимизация газа (Solidity)
Промт: «Оптимизируй следующий код на Solidity для уменьшения газовых затрат. Используй: переменные immutable и constant, замена storage на memory, упаковку struct (packing), сокращение числа операций. Для каждой оптимизации укажи: исходный код, изменённый код, и оценку экономии газа (например, "экономия 2000 газа при вызове"). Ссылайся на документацию Ethereum (https://ethereum.org/en/developers/docs/gas/).»
Пример использования: После написания контракта для NFT-маркетплейса я прогнал его через этот промт. AI предложил заменить uint256 на uint128 для полей, где это возможно, и упаковать struct в один слот, что сэкономило около 40% газа при batch-операциях.
// Исходный код
struct Order {
uint256 price;
address seller;
uint256 tokenId;
bool isActive;
}
// Оптимизированный код
struct Order {
uint128 price; // упаковка: price и isActive в одном слоте
bool isActive;
address seller; // 20 байт
uint256 tokenId; // отдельный слот
}
4. Генерация смарт-контракта на Rust для Solana
Промт: «Напиши программу на Rust для Solana (Anchor framework 0.30.x), которая реализует простой счётчик. Программа должна: иметь инструкцию increment, которая увеличивает счётчик на 1; инструкцию get, возвращающую текущее значение; использовать PDA (Program Derived Address) для хранения счётчика; обрабатывать ошибки (например, переполнение). Добавь тесты на TypeScript с использованием mocha и chai. Используй документацию Anchor (https://www.anchor-lang.com/).»
Пример использования: Когда я начал работать с Solana, этот промт помог быстро разобраться с Anchor. AI сгенерировал не только программу, но и тесты, которые я сразу запустил в localnet.
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod counter {
use super::*;
pub fn increment(ctx: Context<Increment>) -> Result<()> {
let counter = &mut ctx.accounts.counter;
counter.count = counter.count.checked_add(1).ok_or(ErrorCode::Overflow)?;
Ok(())
}
pub fn get(ctx: Context<Get>) -> Result<u64> {
Ok(ctx.accounts.counter.count)
}
}
#[derive(Accounts)]
pub struct Increment<'info> {
#[account(mut, seeds = [b"counter"], bump)]
pub counter: Account<'info, Counter>,
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[account]
pub struct Counter {
pub count: u64,
}
#[error_code]
pub enum ErrorCode {
#[msg("Переполнение счётчика")]
Overflow,
}
5. Написание контракта на Vyper для простого аукциона
Промт: «Напиши смарт-контракт на Vyper 0.4.0 для простого аукциона (английский аукцион). Контракт должен: принимать ставки в ETH, хранить адрес highestBidder и highestBid, завершать аукцион по времени (deadline), возвращать средства проигравшим, иметь функцию withdraw для возврата ставок. Используй события (Bid, AuctionEnded). Добавь проверки: ставка должна быть выше текущей, аукцион должен быть активен. Ссылайся на документацию Vyper (https://docs.vyperlang.org/).»
Пример использования: Для хакатона мне нужен был быстрый прототип аукциона. AI сгенерировал контракт на Vyper за 30 секунд, и я потратил время только на настройку тестов.
# @version 0.4.0
struct Bid:
amount: uint256
bidder: address
highestBidder: public(address)
highestBid: public(uint256)
auctionEnd: public(uint256)
pendingReturns: HashMap[address, uint256]
ended: public(bool)
event Bid:
bidder: address
amount: uint256
event AuctionEnded:
winner: address
amount: uint256
@external
def __init__(_biddingTime: uint256):
self.auctionEnd = block.timestamp + _biddingTime
self.highestBid = 0
self.highestBidder = empty(address)
self.ended = False
@external
@payable
def bid():
assert block.timestamp < self.auctionEnd, "Auction already ended"
assert msg.value > self.highestBid, "Bid too low"
if self.highestBid != 0:
self.pendingReturns[self.highestBidder] += self.highestBid
self.highestBidder = msg.sender
self.highestBid = msg.value
log Bid(msg.sender, msg.value)
@external
def withdraw():
amount: uint256 = self.pendingReturns[msg.sender]
assert amount > 0
self.pendingReturns[msg.sender] = 0
send(msg.sender, amount)
@external
def auctionEnd():
assert block.timestamp >= self.auctionEnd, "Auction not yet ended"
assert not self.ended, "Auction already ended"
self.ended = True
log AuctionEnded(self.highestBidder, self.highestBid)
send(self.highestBidder, self.highestBid)
6. Дебаггинг ошибок компиляции (Solidity)
Промт: «У меня ошибка компиляции в Solidity: "TypeError: Invalid type for argument in function call. Invalid implicit conversion from address to address payable requested." Вот код: [вставь код]. Объясни причину ошибки и предложи исправление. Используй документацию Solidity (https://docs.soliditylang.org/en/v0.8.20/).»
Пример использования: Частая ошибка при работе с переводом ETH. AI сразу указывает, что нужно преобразовать address в address payable с помощью payable().
// Ошибочный код
function transfer(address recipient) external {
recipient.call{value: 1 ether}(""); // Ошибка: recipient не payable
}
// Исправление
function transfer(address payable recipient) external {
recipient.call{value: 1 ether}("");
}
7. Генерация тестов для контракта (Solidity + Hardhat)
Промт: «Напиши полный набор тестов на TypeScript для контракта MyToken (ERC-20) с использованием Hardhat и ethers.js 6. Тесты должны покрывать: mint (только owner), burn (любой пользователь), transfer (стандартный), transferFrom (approve + transfer), события (Mint, Burn, Transfer). Используй chai для утверждений (expect). Добавь комментарии на русском. Ссылайся на документацию Hardhat (https://hardhat.org/docs).»
Пример использования: AI генерирует тесты, которые я запускаю в CI/CD. Это экономит часы ручного написания.
import { expect } from "chai";
import { ethers } from "hardhat";
describe("MyToken", function () {
it("Должен разрешить owner'у mint токены", async function () {
const [owner, user] = await ethers.getSigners();
const MyToken = await ethers.getContractFactory("MyToken");
const token = await MyToken.deploy();
await token.deployed();
await token.mint(user.address, 100);
expect(await token.balanceOf(user.address)).to.equal(100);
});
});
8. Написание скрипта деплоя (Solidity + Hardhat)
Промт: «Напиши скрипт деплоя на TypeScript для контракта MyToken с использованием Hardhat. Скрипт должен: принимать параметры из .env (PRIVATE_KEY, INFURA_API_KEY), деплоить на сеть Goerli (testnet), логировать адрес контракта, верифицировать контракт на Etherscan. Используй документацию Hardhat (https://hardhat.org/docs).»
Пример использования: Быстрый деплой после локальной отладки.
import { ethers } from "hardhat";
async function main() {
const MyToken = await ethers.getContractFactory("MyToken");
const token = await MyToken.deploy();
await token.deployed();
console.log("MyToken deployed to:", token.address);
// Верификация
await hre.run("verify:verify", {
address: token.address,
constructorArguments: [],
});
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
9. Генерация документации (Solidity)
Промт: «Сгенерируй документацию в формате Markdown для следующего контракта на Solidity. Для каждой функции и события: опиши назначение, параметры, возвращаемые значения, модификаторы. Используй стиль NatSpec. Добавь раздел "Требования" (prerequisites) и "Примеры использования". Контракт: [вставь код].»
Пример использования: Перед публикацией контракта на GitHub я генерирую README, чтобы коллеги быстро разобрались.
## Функция `mint(address to, uint256 amount)`
- **Назначение**: Выпускает новые токены.
- **Параметры**: `to` — адрес получателя, `amount` — количество токенов (в wei).
- **Возвращает**: ничего.
- **Модификаторы**: `onlyOwner`.
- **Требования**: только владелец контракта.
10. Оптимизация storage layout (Solidity)
Промт: «Проанализируй storage layout следующего контракта на Solidity. Определи, какие переменные можно упаковать в один слот для экономии газа. Напиши рекомендованный порядок объявления переменных. Используй документацию Ethereum (https://ethereum.org/en/developers/docs/smart-contracts/layout-of-state-variables-in-storage/).»
Пример использования: После рефакторинга контракта для NFT-магазина AI предложил переупорядочить поля struct, что сократило количество слотов с 4 до 2.
// Исходный код
contract Storage {
bool isActive; // слот 0
uint128 price; // слот 0 (пакуется с bool? Нет, из-за порядка)
address owner; // слот 1
uint256 total; // слот 2
}
// Рекомендовано: объявить uint128 и bool сначала, затем address и uint256
11. Генерация контракта для NFT с royalties (Solidity)
Промт: «Напиши контракт ERC-721 на Solidity 0.8.x с использованием OpenZeppelin 5.x. Контракт должен: поддерживать mint с URI, иметь функцию setBaseURI, поддерживать EIP-2981 (royalties) с фиксированным процентом 5%, иметь функцию burn для владельца токена. Добавь модификатор onlyOwner для mint. Используй документацию OpenZeppelin (https://docs.openzeppelin.com/contracts/5.x/).»
Пример использования: Для NFT-коллекции на хакатоне AI сгенерировал контракт с royalties, который сразу работал на OpenSea.
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/common/ERC2981.sol";
contract MyNFT is ERC721, Ownable, ERC2981 {
using Strings for uint256;
string private _baseURI;
constructor() ERC721("MyNFT", "MNFT") Ownable(msg.sender) {
_setDefaultRoyalty(msg.sender, 500); // 5%
}
function mint(address to, uint256 tokenId) external onlyOwner {
_safeMint(to, tokenId);
}
function burn(uint256 tokenId) external {
require(_isAuthorized(ownerOf(tokenId), msg.sender, tokenId), "Not authorized");
_burn(tokenId);
}
function _baseURI() internal view override returns (string memory) {
return _baseURI;
}
function setBaseURI(string memory baseURI) external onlyOwner {
_baseURI = baseURI;
}
function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC2981) returns (bool) {
return super.supportsInterface(interfaceId);
}
}
12. Написание скрипта миграции данных (Web3.js)
Промт: «Напиши скрипт на JavaScript с использованием Web3.js 4.x для миграции данных из старого контракта ERC-20 в новый. Скрипт должен: подключиться к провайдеру (Infura), получить список всех держателей токенов (используя events Transfer), вычислить баланс каждого, вызвать функцию migrate для нового контракта. Добавь обработку ошибок и логирование. Используй документацию Web3.js (https://docs.web3js.org/).»
Пример использования: Миграция токена после обнаружения уязвимости в старом контракте.
const Web3 = require("web3");
const web3 = new Web3("https://mainnet.infura.io/v3/YOUR_KEY");
async function migrate() {
const oldToken = new web3.eth.Contract(abi, "0xOldAddress");
const events = await oldToken.getPastEvents("Transfer", { fromBlock: 0 });
// обработка...
}
Заключение
Эти 12 промтов покрывают 90% моих ежедневных задач: от генерации шаблонов до аудита и деплоя. Главное — не копировать код слепо, а адаптировать под свои нужды. AI — отличный помощник, но финальное решение всегда за тобой. Сохрани эту подборку в закладки и используй как шпаргалку. Если есть любимые промты — делись в комментариях, дополним список вместе!
Комментарии