Разработка системы крафтинга NFT

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы крафтинга NFT
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1258
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1170
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    873
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1092
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    563
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    830

Разработка системы крафтинга NFT

NFT крафтинг — механика, при которой несколько NFT или ресурсов объединяются для создания нового NFT. Это одновременно sink-механизм (сжигает или потребляет NFT/токены) и источник новых ценных предметов. Правильно реализованная система крафтинга создаёт экономический цикл и удерживает игроков.

Типы крафтинга

Fusion (слияние): N токенов одного типа → 1 токен более высокого tier. Классический пример: 3 Common меча → 1 Rare меч. Упрощает инвентарь, создаёт demand на низкотировые NFT.

Recipe крафтинг: конкретные комбинации материалов → конкретный результат. Поваренная книга алхимика: 1 Iron Ore + 2 Coal + 1 Fire Essence → Steel Ingot.

Random crafting: материалы + randomness → результат из диапазона возможных. Риск/награда: можно получить legendary, можно получить common.

Upgrade (прокачка): существующий NFT + материалы → тот же NFT с улучшенными атрибутами.

Smart contract реализация

// 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 система (прокачка атрибутов)

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 необходим — игрок должен быть уверен что казино не может манипулировать шансом.

Crafting UI паттерны

Drag-and-drop слоты для материалов, preview результата до крафтинга, вероятности для random recipes, анимация крафтинга (прогресс бар или particle effect).

Разработка базовой системы крафтинга (рецепты + fusion + детерминированный output) — 3-4 недели. С VRF random crafting и upgrade системой — 5-7 недель.