Введение
Web3-разработка требует не только понимания блокчейна, но и умения быстро создавать безопасный и эффективный код смарт-контрактов. Промты — это не просто шаблоны, а рабочие инструменты, которые экономят часы на написание boilerplate, поиск уязвимостей и оптимизацию газа. В этой подборке — 10 проверенных промтов для Solidity, Rust (Anchor) и Vyper. Каждый сопровождается примером кода из реальной практики.
Базовые промты
1. Генерация ERC-20 токена на Solidity
Задача: Быстро создать минимальный контракт токена стандарта ERC-20 с базовыми функциями.
Промт: “Сгенерируй Solidity контракт ERC-20 с именем MyToken, символом MTK, начальным supply 1 000 000, используя OpenZeppelin v5. Добавь функцию mint с onlyOwner.”
Пример результата:
// 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 {
constructor() ERC20("MyToken", "MTK") {
_mint(msg.sender, 1_000_000 * 10 ** decimals());
}
function mint(address to, uint256 amount) external onlyOwner {
_mint(to, amount);
}
}
2. Создание NFT (ERC-721) с метаданными
Задача: Развернуть коллекцию NFT с URI метаданных.
Промт: “Напиши контракт ERC-721 с использованием OpenZeppelin. Включи counter для tokenId, функцию mint (payable) и _baseURI, который возвращает ipfs://.”
Пример результата:
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract MyNFT is ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
string private _baseTokenURI = "ipfs://QmHash/";
constructor() ERC721("MyNFT", "MNFT") {}
function mint() public payable {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(msg.sender, tokenId);
}
function _baseURI() internal view override returns (string memory) {
return _baseTokenURI;
}
}
3. Базовый депозитный контракт на Vyper
Задача: Написать контракт приёмника средств с выводом владельцем.
Промт: “Реализуй на Vyper 0.4.0 контракт Vault с функциями deposit (payable) и withdraw (только owner).”
Пример результата:
# @version 0.4.0
owner: public(address)
@deploy
def __init__():
self.owner = msg.sender
@payable
def deposit():
pass
def withdraw(amount: uint256):
assert msg.sender == self.owner
send(self.owner, amount)
Продвинутые промты
4. Оптимизация газа в Solidity: storage → memory
Задача: Уменьшить стоимость вызова функции со сложным struct.
Промт: “Рефактори этот код так, чтобы избежать многократного чтения storage. Используй memory для временных переменных и pack для uint.”
Пример результата (до и после):
// Было: читаем storage каждый раз
function getBalance(address user) external view returns (uint) {
return balances[user];
}
// Стало: кеширование в memory
function process(address[] calldata users) external {
for (uint i = 0; i < users.length; i++) {
uint bal = balances[users[i]]; // одно чтение
// ... работа с bal
}
}
5. Контракт лендинг-пула на Rust (Solana с Anchor)
Задача: Простой пул ликвидности под проценты.
Промт: “Напиши программу на Anchor 0.30 для депозита токенов SPL и начисления процентов каждый эпоху. Используй PDA для хранения пула.”
Пример результата (фрагмент):
use anchor_lang::prelude::*;
#[account]
pub struct Pool {
pub total_deposits: u64,
pub interest_rate: u64, // basis points
}
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(mut, seeds = [b"pool"], bump)]
pub pool: Account<'info, Pool>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
let pool = &mut ctx.accounts.pool;
pool.total_deposits = pool.total_deposits.checked_add(amount).unwrap();
Ok(())
}
6. Исправление типовой ошибки reentrancy
Задача: Защитить контракт от повторного входа.
Промт: “Покажи уязвимый код с reentrancy и исправь его через Checks-Effects-Interactions и OpenZeppelin ReentrancyGuard.”
Пример результата:
// Уязвимый
function withdraw(uint amount) external {
require(balances[msg.sender] >= amount);
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] -= amount;
}
// Защищённый
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
function withdraw(uint amount) external nonReentrant {
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount;
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
7. Интеграция Chainlink Price Feed
Задача: Получить актуальную цену ETH/USD в контракте.
Промт: “Напиши контракт, который использует AggregatorV3Interface для получения цены с 18 десятичными знаками.”
Пример результата:
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract PriceConsumer {
AggregatorV3Interface internal priceFeed;
constructor() {
// Sepolia ETH/USD
priceFeed = AggregatorV3Interface(0x694AA1769357215De4FAC081bf1f309aDC325306);
}
function getLatestPrice() public view returns (int) {
(
, int price, , ,
) = priceFeed.latestRoundData();
return price; // 8 decimals
}
}
Экспертные промты
8. Upgradeable контракт через UUPS Proxy
Задача: Развернуть прокси-контракт с возможностью обновления логики.
Промт: “Сгенерируй Solidity контракт для UUPS паттерна с OpenZeppelin. Включи функцию _authorizeUpgrade.”
Пример результата:
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
contract MyContractV1 is Initializable, UUPSUpgradeable, OwnableUpgradeable {
uint public value;
function initialize() initializer public {
__Ownable_init();
__UUPSUpgradeable_init();
}
function setValue(uint _value) external onlyOwner {
value = _value;
}
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}
9. Написание inline assembly (Yul) для оптимизации
Задача: Ускорить сложную математическую операцию.
Промт: “Реализуй функцию pow в Yul для uint256 – возведение в степень по модулю 2256. Сравни газ с Solidity loop.”
Пример результата:**
function power(uint base, uint exp) public pure returns (uint result) {
assembly {
result := 1
let b := base
let e := exp
for { } gt(e, 0) { } {
if and(e, 1) {
result := mul(result, b)
}
e := shr(1, e)
b := mul(b, b)
}
}
}
10. Генерация фаззинг-тестов для Foundry
Задача: Протестировать контракт на случайные входные данные.
Промт: “Напиши тест на Foundry для контракта Vault: проверь, что после множества депозитов и выводов баланс сходится. Используй fuzzing.”
Пример результата:
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../src/Vault.sol";
contract VaultTest is Test {
Vault vault;
function setUp() public {
vault = new Vault();
}
function testFuzz_DepositWithdraw(uint amount) public {
vm.assume(amount > 0 && amount < 1e30);
vault.deposit{value: amount}();
uint before = address(vault).balance;
vault.withdraw(amount);
assertEq(address(vault).balance, before - amount);
}
}
Заключение
Эти 10 промтов покрывают 90% типовых задач Web3-разработчика: от токенов до оракулов и апгрейда. Используйте их как стартовую точку — адаптируйте под свой проект, тестируйте и не забывайте про аудит. Для более глубокого изучения рекомендую официальную документацию OpenZeppelin, Anchor Book и Solidity by Example. Попробуйте применить любой из промтов уже сегодня — это сэкономит вам часы работы.
Комментарии