Let players combine existing NFTs to create new ones—a core mechanic for progression and engagement in games.
Why Use Crafting?
Crafting drives collection and trading behaviour. Players actively hunt for ingredients, creating demand across your economy.
Burning inputs removes items from circulation, maintaining scarcity and value in your game economy.
Multi-step recipes create meaningful goals. Players feel invested when they craft rare items.
How It Works
Player Selects Items
Player chooses NFTs to combine from their inventory
Backend Validates
Your server verifies ownership and recipe validity
Burn Inputs
Transfer input NFTs to burn address
Mint Output
Create new NFT for player via Minting API
Recipe System
Define recipes that map inputs to outputs:
const recipes = [
{
id: 'iron_sword',
inputs: [
{ contract: MATERIALS, trait: { type: 'Iron Ore' }, count: 2 },
{ contract: MATERIALS, trait: { type: 'Wood' }, count: 1 },
],
output: {
name: 'Iron Sword',
attributes: [{ trait_type: 'Damage', value: 10 }],
},
},
{
id: 'steel_sword',
inputs: [
{ contract: WEAPONS, trait: { type: 'Iron Sword' }, count: 1 },
{ contract: MATERIALS, trait: { type: 'Steel Ingot' }, count: 2 },
],
output: {
name: 'Steel Sword',
attributes: [{ trait_type: 'Damage', value: 25 }],
},
},
];
Implementation
const BURN_ADDRESS = '0x000000000000000000000000000000000000dEaD';
app.post('/craft', async (req, res) => {
const { recipeId, inputTokenIds, playerAddress } = req.body;
const recipe = recipes.find(r => r.id === recipeId);
if (!recipe) {
return res.status(400).json({ error: 'Invalid recipe' });
}
// Verify ownership of all inputs
for (const tokenId of inputTokenIds) {
const owner = await nftContract.ownerOf(tokenId);
if (owner.toLowerCase() !== playerAddress.toLowerCase()) {
return res.status(403).json({ error: 'Not owner of input' });
}
}
// Verify inputs match recipe requirements
// ... validation logic
// Burn inputs
for (const tokenId of inputTokenIds) {
await nftContract.transferFrom(playerAddress, BURN_ADDRESS, tokenId);
}
// Mint output via Minting API
const outputId = generateTokenId();
await mintNFT(playerAddress, outputId, recipe.output);
res.json({ success: true, outputId });
});
Upgrades
Enhance existing items by burning materials:
async function upgradeItem(tokenId: string, materialsUsed: string[]) {
const nft = await getNFT(tokenId);
const level = nft.attributes.find(a => a.trait_type === 'Level')?.value || 1;
// Burn material NFTs
for (const materialId of materialsUsed) {
await burnNFT(materialId);
}
// Update metadata via Minting API refresh
await refreshMetadata(tokenId, {
...nft.metadata,
attributes: nft.attributes.map(a =>
a.trait_type === 'Level' ? { ...a, value: level + 1 } : a
),
});
}
Design Tips
| Pattern | Description |
|---|
| Deterministic | Same inputs always produce same output |
| Probabilistic | Random chance for rare outcomes |
| Time-gated | Crafting takes time to complete |
| Progressive | Multi-step recipes for advanced items |
Keep crafting server-side to prevent exploitation. Only mint outputs after verifying ownership and burning inputs.