Реалізація маркетплейса внутриігрових предметів у мобільній GameFi-грі
NFT-маркетплейс всередину мобільної гри — одна з найскладніших завдань у GameFi-розробці. Тут зіштовхуються два світи: звичний мобільний UX (швидко, інтуїтивно, без seed-фраз) та блокчейн-реальність (gas fees, час підтвердження транзакцій, ownership через гаманець). Розв'язати це протиріччя — маркетплейс використовуватимуть. Не розв'язати — велика прийняття не буде.
Архітектура: on-chain vs off-chain listing
Повністю on-chain маркетплейс (як OpenSea v1) — кожен листинг це транзакція. На мобільних пристроях неадекватно: користувач не буде платити $0.50–5 газу за кожне виставлення предмета.
Правильна архітектура для GameFi-мобайла — off-chain листинги з on-chain розрахунками:
- Продавець підписує листинг офчейн (
signTypedData/ EIP-712) — транзакції немає, газу немає - Листинг зберігається у базі додатка
- Покупець натискає "Купити" — тільки тоді on-chain транзакція відбувається
- Смарт-контракт верифікує підпис продавця, переводить NFT покупцю та оплату продавцю атомарно
// Мінімальна структура листингу EIP-712
struct Listing {
address seller;
address nftContract;
uint256 tokenId;
address paymentToken; // USDC, GOLD або нативний токен
uint256 price;
uint256 expiry; // термін дії листингу
uint256 nonce; // захист від replay attack
}
bytes32 public constant LISTING_TYPEHASH = keccak256(
"Listing(address seller,address nftContract,uint256 tokenId,address paymentToken,uint256 price,uint256 expiry,uint256 nonce)"
);
function buyItem(Listing calldata listing, bytes calldata signature) external {
require(block.timestamp < listing.expiry, "Listing expired");
require(!usedNonces[listing.seller][listing.nonce], "Nonce used");
bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(LISTING_TYPEHASH, listing)));
require(ECDSA.recover(digest, signature) == listing.seller, "Invalid signature");
usedNonces[listing.seller][listing.nonce] = true;
IERC20(listing.paymentToken).transferFrom(msg.sender, listing.seller, listing.price);
IERC721(listing.nftContract).safeTransferFrom(listing.seller, msg.sender, listing.tokenId);
}
Цей підхід використовують Seaport (OpenSea v2) та Blur — перевірена схема.
Мобільний UX: відображення предметів
Кожний NFT-предмет — це tokenId + метадані з tokenURI на IPFS або централізованому CDN. Завантаження метаданих напрямки з IPFS на мобільному — повільно та ненадійно. Розв'язання: бекенд індексує метадані у базу та відправляє через REST API. Мобільний клієнт ніколи не звертається до IPFS напрямки.
Зображення предметів — через CDN (CloudFront / Cloudflare), кешування на клієнті через Kingfisher (iOS) або Coil (Android). Lazy loading у списку — LazyColumn з AsyncImage у Compose, LazyVGrid у SwiftUI.
// SwiftUI: грід предметів маркетплейса
struct MarketplaceGridView: View {
@StateObject var viewModel: MarketplaceViewModel
let columns = [GridItem(.adaptive(minimum: 160), spacing: 12)]
var body: some View {
ScrollView {
LazyVGrid(columns: columns, spacing: 12) {
ForEach(viewModel.items) { item in
NFTItemCard(item: item)
.onAppear {
if item == viewModel.items.last {
viewModel.loadNextPage()
}
}
}
}
.padding()
}
}
}
Фільтрація та пошук
Фільтри: редкість (Rare/Epic/Legendary), тип предмета (зброя/броня/питомець), ціновий діапазон, актив оплати. Сортування: по ціні, даті листингу, редкості. Полнотекстовий пошук по імені предмета — через PostgreSQL tsvector або Elasticsearch на бекенді.
Атрибути NFT-предметів індексуються у реляційну таблицю при мінті — не парсяться з IPFS JSON при кожному запиті.
Процес покупки на мобільному
Головна проблема — як користувач підписує транзакцію покупки без seed-фрази у додатку.
Варіант 1: Account Abstraction. Smart account користувача підписує UserOperation через біометрію (Face ID / Touch ID). Paymaster спонсирує газ — користувач платить тільки в ігровому токені. Найкращий UX, складніше в реалізації.
Варіант 2: WalletConnect. Deep Link на MetaMask або Phantom, користувач підтверджує транзакцію в зовнішньому гаманці та повертається у гру. Знайомо крипто-користувачам, непривичне для гейминг-аудиторії.
Варіант 3: Кастодіальний гаманець. Додаток управляє ключами (через Fireblocks MPC або Privy). Транзакції підписуються server-side або через Shamir's Secret Sharing. Найпростіший UX, жорсткі вимоги до безпеки.
Для GameFi з мільйонною аудиторією — Account Abstraction через Privy або Dynamic з embedded wallet. Користувач входить через Google/Apple — отримує smart account автоматично.
Роялті для розробника гри
При кожній P2P-продажі на вторинному ринку — автоматичне відчислення роялті (2–5%) у гаманець студії. ERC-2981 (NFT Royalty Standard) задає royaltyInfo(tokenId, salePrice) — смарт-контракт маркетплейса викликає перед розрахунком та утримує комісію.
Модерація та блокування предметів
Система скарг на підозрілі листинги (чит-предмети, дубікати). Адміністративний endpoint POST /listings/{id}/delist — видаляє з бази. On-chain ніщо не мінюється (транзакції не було), предмет просто перестає відображатися.
Блокування крадених токенів (якщо аккаунт взламано) — blacklist на рівні смарт-контракту: blockedTokens[tokenId] = true з перевіркою у buyItem.
Етапи та сроки
| Етап | Терміни |
|---|---|
| Смарт-контракт маркетплейса + аудит | 2 тижні |
| Бекенд: індексування, листинги, пошук | 2 тижні |
| Мобільний клієнт: грід, карточка, покупка | 2–3 тижні |
| Гаманець (WalletConnect або Account Abstraction) | 1 тиждень |
| Фільтри, сортування, історія сделок | 1 тиждень |
Всього: 8–10 тижнів. Вартість розраховується індивідуально після аналізу вимог.







