Вы создали коллекцию NFT, игроки активно майнят и трейдуют — но что дальше? Без механики, которая потребляет существующие токены и мотивирует на взаимодействие, экономика быстро застаивается. Мы столкнулись с этим в проекте P2E с тысячами невостребованных предметов: игроки просто копили их без цели. Решением стала система крафтинга — возможность объединять несколько NFT или ресурсов для создания нового ценного предмета. Это создаёт экономический цикл: sink-механизм выводит ликвидность, а награда удерживает игроков. В одном проекте мы добились снижения оборота низкоуровневых NFT на 70% за счёт продуманного крафтинга, а средняя стоимость транзакции на Polygon составила всего $0.02 — это примерно в 175 раз дешевле, чем на Ethereum mainnet ($3.50). Экономия газа при грамотной реализации может достигать 40%.
Как работает система крафтинга NFT?
Крафтинг — это не просто вызов safeTransferFrom. Под капотом лежат чёткие паттерны сжигания, чеканки и валидации рецептов. Рассмотрим основные типы:
| Тип | Описание | Пример | Случайность | Примечания |
|---|---|---|---|---|
| Fusion (слияние) | N токенов одного типа → 1 токен более высокого тира | 3 Common меча → 1 Rare меч | Нет | Упрощает инвентарь, создаёт спрос на низкоуровневые NFT |
| Recipe (рецепт) | Конкретные комбинации материалов → конкретный результат | 1 Iron Ore + 2 Coal + 1 Fire Essence → Steel Ingot | Нет | Детерминированный, подходит для крафта ограниченных предметов |
| Random | Материалы + VRF → результат из диапазона | Расходники → случайный предмет из пула (common до legendary) | Да (Chainlink VRF) | Риск / награда; увеличивает спрос на материалы |
| Upgrade (прокачка) | Существующий NFT + материалы → тот же NFT с улучшенными атрибутами | Меч 1 лвл + 10 Essence → Меч 2 лвл | Частично (успех/неудача) | Korean-MMO стиль: можно потерять предмет |
Сравнение эффективности сетей для крафтинга
| Сеть | Средняя стоимость газа за крафт (USD) | Время блока | L2 rollup | Рекомендация |
|---|---|---|---|---|
| Ethereum mainnet | $3.50 | 12 с | Нет | Только для high-value предметов |
| Polygon (zkEVM) | $0.02 | 2 с | Да | Лучший баланс цены и скорости |
| Arbitrum One | $0.15 | 0.25 с | Да | Для быстрых upgrad-циклов |
| BNB Chain | $0.05 | 3 с | Нет | Экономия при частых крафтах |
Пример реализации на Solidity
Для случайных крафтов мы используем Chainlink VRF — каждая операция подтверждается честным random. Ниже фрагмент контракта, поддерживающего как детерминированные рецепты, так и случайный крафтинг. Полный код доступен в нашем репозитории.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/AccessControl.sol";
contract NFTCraftingSystem is AccessControl, VRFConsumerBaseV2Plus {
bytes32 public constant RECIPE_MANAGER = keccak256("RECIPE_MANAGER");
struct CraftingRecipe {
uint256 recipeId;
string name;
// Входящие материалы
address[] inputContracts; // адреса NFT контрактов материалов
uint256[] inputTokenIds; // tokenId (0 = любой из коллекции)
uint256[] inputAmounts; // количество (для ERC-1155)
// Входящие ERC-20 токены
address[] tokenInputs;
uint256[] tokenAmounts;
// Выход
address outputContract;
uint256 outputTokenId; // 0 = random из диапазона
uint256 minOutputId; // для random: минимальный tokenId
uint256 maxOutputId; // для random: максимальный tokenId
bool burnInputs; // сжигать или только потреблять
bool requiresVRF; // нужен ли random
bool isActive;
uint256 cooldown; // секунды между крафтингами одним адресом
}
mapping(uint256 => CraftingRecipe) public recipes;
mapping(address => mapping(uint256 => uint256)) public lastCraftTime; // player → recipeId → timestamp
mapping(uint256 => PendingCraft) public pendingCrafts; // vrfRequestId → craft
struct PendingCraft {
address crafter;
uint256 recipeId;
bool fulfilled;
}
function craft(uint256 recipeId, uint256[][] calldata inputTokenIds)
external returns (uint256 requestId)
{
CraftingRecipe storage recipe = recipes[recipeId];
require(recipe.isActive, "Recipe not active");
// Cooldown check
require(
block.timestamp >= lastCraftTime[msg.sender][recipeId] + recipe.cooldown,
"Crafting cooldown active"
);
lastCraftTime[msg.sender][recipeId] = block.timestamp;
// Валидируем и забираем материалы
_consumeInputMaterials(recipe, inputTokenIds);
_consumeInputTokens(recipe);
if (recipe.requiresVRF) {
// Для рандомного крафтинга — запрашиваем VRF
requestId = _requestRandomWords(1);
pendingCrafts[requestId] = PendingCraft({
crafter: msg.sender,
recipeId: recipeId,
fulfilled: false,
});
emit CraftingInitiated(msg.sender, recipeId, requestId);
} else {
// Детерминированный крафтинг — минтим сразу
_mintCraftingResult(msg.sender, recipe, 0);
}
}
function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords)
internal override
{
PendingCraft storage pending = pendingCrafts[requestId];
require(!pending.fulfilled, "Already fulfilled");
pending.fulfilled = true;
CraftingRecipe storage recipe = recipes[pending.recipeId];
_mintCraftingResult(pending.crafter, recipe, randomWords[0]);
}
function _mintCraftingResult(
address crafter,
CraftingRecipe storage recipe,
uint256 random
) internal {
uint256 outputTokenId;
if (recipe.outputTokenId != 0) {
// Детерминированный output
outputTokenId = recipe.outputTokenId;
} else {
// Random output в диапазоне [minOutputId, maxOutputId]
outputTokenId = recipe.minOutputId + (random % (recipe.maxOutputId - recipe.minOutputId + 1));
}
// Минтим результат
IGameItems(recipe.outputContract).mintCraftingResult(crafter, outputTokenId, 1);
emit CraftingCompleted(crafter, recipe.recipeId, outputTokenId);
}
function _consumeInputMaterials(
CraftingRecipe storage recipe,
uint256[][] calldata inputTokenIds
) internal {
for (uint i = 0; i < recipe.inputContracts.length; i++) {
IERC1155 nft = IERC1155(recipe.inputContracts[i]);
if (recipe.burnInputs) {
// Burn материалы
IERC1155Burnable(recipe.inputContracts[i]).burn(
msg.sender,
inputTokenIds[i][0],
recipe.inputAmounts[i]
);
} else {
// Перевести в контракт (без сжигания)
nft.safeTransferFrom(
msg.sender,
address(this),
inputTokenIds[i][0],
recipe.inputAmounts[i],
""
);
}
}
}
}
Upgrade система (прокачка атрибутов)
Для игр, где предметы нужно улучшать, мы реализуем отдельный контракт с поддержкой уровней, материалов и шанса успеха. Также возможна механика "уничтожение при неудаче" (Korean-MMO стиль) — она драматически увеличивает ценность высокоуровневых предметов.
contract NFTUpgradeSystem {
struct UpgradePath {
uint256 itemTypeId;
uint256 currentLevel;
uint256 maxLevel;
uint256[] materialCosts; // материалы для каждого уровня
uint256[] tokenCosts;
uint256 successRate; // в basis points, 10000 = 100%
bool destroyOnFail; // сжигать при неудаче?
}
// Upgrade с риском уничтожения (Korean-MMO стиль)
function upgradeItem(
uint256 tokenId,
uint256 itemTypeId,
uint256 targetLevel
) external returns (bool success) {
UpgradePath storage path = upgradePaths[itemTypeId][targetLevel];
// Забираем материалы
_burnUpgradeMaterials(path);
// Определяем успех (off-chain random или VRF)
// Для простоты — pseudo-random через block hash
uint256 rand = uint256(keccak256(abi.encodePacked(
blockhash(block.number - 1),
msg.sender,
tokenId,
block.timestamp
))) % 10000;
success = rand < path.successRate;
if (success) {
gameItems.setItemLevel(tokenId, targetLevel);
emit UpgradeSuccess(msg.sender, tokenId, targetLevel);
} else if (path.destroyOnFail) {
gameItems.burn(msg.sender, itemTypeId, 1);
emit UpgradeFailed(msg.sender, tokenId, targetLevel, true);
} else {
// Просто неудача без потери предмета
emit UpgradeFailed(msg.sender, tokenId, targetLevel, false);
}
}
}
Для upgrade с риском уничтожения VRF обязателен — игрок должен быть уверен, что казино не может манипулировать шансом.
Почему важна корректная валидация материалов?
Ошибка в логике consumeInputMaterials — одна из самых частых причин взлома крафтинга. Нужно проверять:
- Соответствие адресов контрактов и разрешённых tokenId.
- Баланс игрока перед переводом, особенно при burn-режиме (перевод сразу сжигает, а не временно холдит).
- Отсутствие reentrancy — используйте OpenZeppelin ReentrancyGuard.
- Правильную обработку ERC-1155 batchTransfer для многокомпонентных рецептов.
Согласно документации OpenZeppelin ReentrancyGuard, он предотвращает повторный вход, что критично для операций с сжиганием и чеканкой.
Что входит в разработку?
Мы предоставляем полный цикл:
- Анализ игровой экономики и проектирование рецептов.
- Смарт-контракты крафтинга (Solidity 0.8.x, модульная архитектура).
- Интеграция с Chainlink VRF для рандома.
- Разработка frontend UI (drag-and-drop слоты, preview результата, анимация).
- Деплой на выбранную сеть (Ethereum, Polygon, Arbitrum, BNB Chain).
- Полная документация (архитектура, интерфейсы, deploy-скрипты).
- Аудит безопасности (Slither, Mythril, Echidna).
- Гарантия на код — 6 месяцев баг-фиксов.
Закажите разработку системы крафтинга NFT и получите консультацию с прототипом на тестнете. Наш опыт: более 20 реализованных проектов, в том числе с интеграцией VRF и upgrad-системами. Мы гарантируем прозрачность кода, своевременную сдачу этапов и пост-релизную поддержку.
Процесс работы
Мы работаем по этапам:
- Аналитика — разбор вашей экономики и токеномики, формирование спецификации.
- Проектирование — архитектура смарт-контрактов, выбор стандартов, оценка газа.
- Разработка — написание контрактов, юнит-тесты (Foundry), интеграция с VRF.
- Аудит — внутренний и внешний код-ревью, исправление уязвимостей.
- Деплой и тестирование — testnet, симуляция нагрузок, коррекция.
Сроки и стоимость
Базовая система крафтинга (рецепты + fusion + детерминированный output) занимает от 3 до 4 недель. С VRF random crafting и upgrade системой — от 5 до 7 недель. Стоимость рассчитывается индивидуально на основе объёма рецептов и необходимой кастомизации. Свяжитесь с нами — мы оценим ваш проект и предложим оптимальное решение.
Crafting UI паттерны: Drag-and-drop слоты для материалов, preview результата до крафтинга, вероятности для random recipes, анимация крафтинга (прогресс бар или particle effect).







