Розробка GameFi проекту
GameFi — це перетин двох дуже різних інженерних дисциплін: розробки ігор з вимогами до реального часу, низької затримки та високої частоти подій, та розробки на блокчейні з його фіналітетом, вартістю газу та незмінністю. Спроба просто «додати блокчейн до гри» майже завжди провалюється — або гра стає неграбельною через трансакції, або блокчейн-частина є декоративною та нічого не дає користувачам. Правильна архітектура GameFi — це чітка межа між тим, що повинно бути на ланцюгу, та тим, що повинно залишатися позаланцюговим.
Фундаментальне питання: що йде на ланцюг
Не все у грі повинно бути на блокчейні. Блокчейн — це дорогий, повільний, але безпечний та постійний зберіганням. Використовуйте його саме там, де потрібні ці властивості.
Повинно бути на ланцюгу:
- Власність активами (NFT персонажі, предмети, землі)
- Фінансові операції (покупка, продаж, стейкинг, нагороди)
- Критичні результати, що впливають на економіку (перемога турніру, падіння рідкісного дропу)
- Рішення управління (якщо застосовуються)
Повинно бути позаланцюговим (ігрові сервери):
- Ігрова механіка в реальному часі
- Позиції гравців, зіткнення, фізика
- Більшість ігрових подій
- Соціальні функції (чат, гільдії)
- Аналітика та логування
Добра модель: ігровий сервер — джерело правди для гейплею, блокчейн — джерело правди для власності та економіки. Синхронізація відбувається в певних контрольних точках.
Архітектура: сервери, контракти, клієнт
Ігровий бекенд
Ігровий клієнт (Unity/Unreal/Web)
↓
Ігровий сервер (авторитетний)
└── База даних ігрового стану (Redis для реального часу, PostgreSQL для постійності)
↓ (при значних подіях)
Сервіс синхронізації блокчейна
↓
Смарт-контракти (активи, економіка, нагороди)
↓
The Graph (індексування для UI/лідербордів)
Модель авторитетного сервера — клієнт ніколи не приймає остаточних рішень. Клієнт відправляє введення (рух вліво, атака), сервер перевіряє та застосовує. Це запобігає читингу без будь-якого блокчейна.
Сервіс синхронізації блокчейна — окремий сервіс, який слухає ігрові події та переводить значущі з них у на-ланцюгові трансакції. Працює асинхронно, не блокує гейплей.
NFT активи: стандарти та метадані
ERC-721 для унікальних предметів, ERC-1155 для складуваних предметів (ресурси, витратники) — GameFi майже завжди поєднує обидва.
Метадані ігрових NFT — окрема проблема. Метадані на ланцюгу (повністю у контракті) — максимальна постійність, але дорого та обмежено за обсягом. IPFS — компроміс: адресований вмістом, але вимагає закріплення. Централізований сервер — швидко, дешево, але залежить від вас.
contract GameItem is ERC1155 {
struct ItemType {
string name;
uint8 rarity; // 1=Common, 2=Rare, 3=Epic, 4=Legendary
uint16 baseAttack;
uint16 baseDefense;
bool tradeable;
}
mapping(uint256 => ItemType) public itemTypes;
mapping(uint256 => uint256) public itemMaxSupply;
mapping(uint256 => uint256) public itemCurrentSupply;
// Тільки ігровий сервер може чеканити предмети
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
function mintItem(
address to,
uint256 itemTypeId,
uint256 amount,
bytes memory data
) external onlyRole(MINTER_ROLE) {
require(
itemCurrentSupply[itemTypeId] + amount <= itemMaxSupply[itemTypeId],
"Перевищено максимальну пропозицію"
);
itemCurrentSupply[itemTypeId] += amount;
_mint(to, itemTypeId, amount, data);
}
// Не-передаючи soulbound предмети
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal override {
for (uint i = 0; i < ids.length; i++) {
if (from != address(0) && to != address(0)) { // не чеканирь/спалюй
require(itemTypes[ids[i]].tradeable, "Предмет прив'язаний");
}
}
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
}
}
Ігровий токен: токеноміка
Більшість невдалих GameFi проектів провалилися через погану токеноміку, а не через погану гру. Головні помилки:
Інфляційна спіраль — токен видається як нагорода за гейплей без достатнього сінка. Більше гравців → більше пропозиції → нижча ціна → менше стимулу грати. Це вбило Axie Infinity у 2022.
Модель з двома токенами — спроба розділити «токен управління» (дефляційний) та «утилітарний токен» (інфляційний) часто створює ірраціональний peg між ними та ще складніші режими збою.
Правильний підхід — балансувати випромінювання та сінк:
contract GameEconomy {
// Випромінювання: тільки через ігрові досягнення, перевірені сервером
function claimDailyReward(
address player,
uint256 amount,
uint256 nonce,
bytes memory serverSignature
) external {
// Перевіряємо підпис сервера
bytes32 message = keccak256(abi.encodePacked(player, amount, nonce));
require(
ECDSA.recover(message.toEthSignedMessageHash(), serverSignature) == GAME_SERVER,
"Недійсна підпис сервера"
);
require(!usedNonces[nonce], "Nonce вже використаний");
usedNonces[nonce] = true;
// Ліміт щоденного дропу
require(dailyClaimed[player][today()] + amount <= MAX_DAILY_REWARD, "Щоденний ліміт");
dailyClaimed[player][today()] += amount;
gameToken.mint(player, amount);
}
// Сінк: крафт, апгрейд, комісія, спалювання
function craftItem(uint256 recipeId) external {
Recipe memory recipe = recipes[recipeId];
gameToken.burnFrom(msg.sender, recipe.tokenCost);
// чеканимо NFT предмет
}
}
Паттерн підпису ігрового сервера
Це критичний паттерн для GameFi: ігровий сервер є довіреним джерелом правди, і його рішення перевіряються на-ланцюгово через перевірку підпису.
Користувач не може просто вызвати claimReward — він повинен отримати підписаний сервером ваучер. Це запобігає:
- Фабрикуванню результатів через прямий вызов контракту
- Подвійній витраті одного результату (nonce)
- Читингу через атаки повторення
// Сторона ігрового сервера (Node.js)
import { ethers } from "ethers";
const serverWallet = new ethers.Wallet(process.env.SERVER_PRIVATE_KEY);
async function generateRewardVoucher(
playerAddress: string,
rewardAmount: bigint,
gameSessionId: string
): Promise<{ nonce: string; signature: string; amount: string }> {
const nonce = ethers.hexlify(ethers.randomBytes(32));
const message = ethers.solidityPackedKeccak256(
["address", "uint256", "bytes32"],
[playerAddress, rewardAmount, nonce]
);
const signature = await serverWallet.signMessage(ethers.getBytes(message));
return { nonce, signature, amount: rewardAmount.toString() };
}
Маркетплейс: P2P торгівля активами
contract GameMarketplace {
struct Listing {
address seller;
address nftContract;
uint256 tokenId;
uint256 amount; // для ERC-1155
uint256 price; // в ERC-20 токені або рідному
uint256 expiresAt;
}
mapping(bytes32 => Listing) public listings;
uint256 public feePercent = 250; // 2.5%
function buyItem(bytes32 listingId) external {
Listing memory listing = listings[listingId];
require(block.timestamp < listing.expiresAt, "Список закінчився");
require(listing.seller != address(0), "Список не знайдено");
uint256 fee = (listing.price * feePercent) / 10_000;
uint256 sellerAmount = listing.price - fee;
// Передача токена
paymentToken.transferFrom(msg.sender, listing.seller, sellerAmount);
paymentToken.transferFrom(msg.sender, treasury, fee);
// Передача NFT
IERC1155(listing.nftContract).safeTransferFrom(
address(this), msg.sender, listing.tokenId, listing.amount, ""
);
delete listings[listingId];
}
}
Античід на рівні блокчейна
Верифікація результатів на-ланцюгово можлива кількома механізмами:
Commit-reveal для випадковості — гра не може знати результат наперед, але блокчейн не повинен бути маніпульований:
- Гравець фіксує hash(seed) перед стартом
- Після гри розкриває seed
- Блокчейн перевіряє: random = hash(seed, block.hash) — не можна передбачити наперед
Chainlink VRF v2 — для на-ланцюгової випадковості (дроп лутів, матчмейкинг):
import { VRFConsumerBaseV2 } from "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
contract LootBox is VRFConsumerBaseV2 {
mapping(uint256 => address) public requestToPlayer;
function openLootBox() external returns (uint256 requestId) {
requestId = vrfCoordinator.requestRandomWords(
keyHash, subscriptionId, 3, 100_000, 3 // 3 випадкових слова
);
requestToPlayer[requestId] = msg.sender;
}
function fulfillRandomWords(uint256 requestId, uint256[] memory words) internal override {
address player = requestToPlayer[requestId];
// Визначаємо дроп на основі верифікованої випадковості
uint256 itemTier = words[0] % 1000; // 0-999
_mintReward(player, itemTier);
}
}
Технічний стек для GameFi
Ігровий движок: Unity (WebGL + рідна мобільна) або Phaser 3 (спочатку браузер). Unity з WebGL — стандарт для випадкової GameFi.
Web3 інтеграція в Unity: Nethereum для EVM, Solana.Unity-SDK для Solana. Для браузера — MetaMask SDK через JSLib bridge.
Бекенд: Go або Node.js для ігрового сервера (затримка критична), окремий сервіс TypeScript для взаємодій блокчейна.
Індексування: The Graph для лідербордів, збірок NFT, історії трансакцій. Власна PostgreSQL для ігрової аналітики.
Мережі: Polygon PoS або Arbitrum Nova (ультра-низький газ для частих трансакцій), Ethereum mainnet для цінних активів.
Фази та графік
| Фаза | Вміст | Графік |
|---|---|---|
| Дизайн гри та токеноміка | Механіка, модель економіки, білий папір | 4–6 тижнів |
| Смарт-контракти (активи, економіка) | ERC-1155, маркетплейс, стейкинг | 4–8 тижнів |
| Ігровий сервер | Авторитетна логіка, сервіс підпису | 4–8 тижнів |
| Ігровий клієнт | Unity/Phaser + інтеграція гаманця | 6–12 тижнів |
| Аудит смарт-контракту | — | 4–6 тижнів |
| Testnet та балансування | Тестування економіки, античід | 4–6 тижнів |
| Запуск | Розгортування mainnet, моніторинг | 2 тижні |
Мінімальний бюджет для повного GameFi MVP — $200k–400k. Проекти з меншим бюджетом зазвичай жертвують якістю гри або якістю смарт-контракту — обидва вибори ведуть до невдачі.







