Ви створили колекцію 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).







