Як ми реалізуємо виведення токенів (Withdraw) з мобільної GameFi-гри
Гравець накопичив 500 GOLD-токенів і хоче вивести їх на зовнішній гаманець. За цією кнопкою ховається: верифікація ігрового балансу, підписання транзакції мінту або переказу, захист від чит-клієнтів та ботів, газ на мобільному пристрої. Ми спроєктували систему виведення, яка виключає втрати та шахрайство. Наш досвід — понад 10 інтеграцій у GameFi-проєктах з DAU від 5 000 до 50 000. Гарантуємо, що кожне виведення пройде без подвоєнь та втрат.
Чому виведення ламається найчастіше?
Головний ризик — подвійне списання. Гравець ініціював виведення, транзакція зависла в mempool через низький газ, гравець повторив запит. Серверний баланс уже зменшений при першому запиті, але токени на гаманець не прийшли жодного разу. Або навпаки — прийшли двічі, тому що idempotency не реалізована.
Рішення: nonce-система на рівні додатку. Кожен запит на виведення отримує унікальний withdrawalId (UUID). Бекенд приймає виведення лише один раз для кожного withdrawalId. Статус: pending → submitted → confirmed / failed. Поки статус pending — повторний запит з тим же ID повертає поточний статус, не створює новий вивід.
// Android: стани виведення через sealed class sealed class WithdrawalState { object Idle : WithdrawalState() data class Pending(val withdrawalId: String) : WithdrawalState() data class Submitted(val txHash: String) : WithdrawalState() data class Confirmed(val txHash: String, val amount: BigDecimal) : WithdrawalState() data class Failed(val reason: String) : WithdrawalState() } class WithdrawViewModel(private val repository: WithdrawRepository) : ViewModel() { private val _state = MutableStateFlow<WithdrawalState>(WithdrawalState.Idle) val state: StateFlow<WithdrawalState> = _state fun initiateWithdraw(amount: BigDecimal, toAddress: String) { viewModelScope.launch { val withdrawalId = UUID.randomUUID().toString() _state.emit(WithdrawalState.Pending(withdrawalId)) try { val result = repository.createWithdrawal(withdrawalId, amount, toAddress) _state.emit(WithdrawalState.Submitted(result.txHash)) pollConfirmation(result.txHash) } catch (e: Exception) { _state.emit(WithdrawalState.Failed(e.message ?: "Unknown error")) } } } } Серверна верифікація ігрового балансу
Мобільний клієнт ніколи не є джерелом правди про баланс. Баланс зберігається на сервері, вся ігрова логіка — серверна. Запит на виведення містить amount, сервер верифікує: чи достатньо токенів, чи немає активного cooldown (наприклад, 24 години між виведеннями), чи не забанений акаунт.
Після успішної верифікації — сервер або мінтить токени на гаманець гравця (якщо це централізований мінт), або підписує withdrawal voucher, який гравець пред'являє смарт-контракту.
Патерн Withdrawal Voucher
// Гравець пред'являє підписаний сервером ваучер contract GameTokenBridge { address public signer; // backend сервер function withdraw( uint256 amount, uint256 nonce, bytes memory signature ) external { bytes32 hash = keccak256(abi.encodePacked(msg.sender, amount, nonce)); bytes32 ethHash = hash.toEthSignedMessageHash(); require(ethHash.recover(signature) == signer, "Invalid signature"); require(!usedNonces[nonce], "Nonce already used"); usedNonces[nonce] = true; _mint(msg.sender, amount); } } Сервер підписує ваучер своїм приватним ключем (signer). Контракт перевіряє підпис. Це означає: без підпису сервера ніхто не може вивести токени — захист від експлойтів на смарт-контракті, що в 10 разів безпечніше за прямий серверний переказ.
Як вибрати відповідний метод виведення?
Вибір між прямим серверним мінтом, voucher-схемою або Account Abstraction залежить від рівня довіри та зручності для користувача. У таблиці нижче — порівняння підходів.
| Метод | Безпека | Зручність для гравця | Децентралізація | Швидкість інтеграції |
|---|---|---|---|---|
| Прямий серверний мінт | Середня (залежить від сервера) | Низька (потрібен гаманець) | Низька | 1-2 тижні |
| Voucher-схема | Висока (криптографічний підпис) | Низька (потрібен гаманець) | Висока | 2-3 тижні |
| Account Abstraction | Висока (smart account) | Висока (Face ID, без seed) | Середня (через paymaster) | 3-4 тижні |
Для масової аудиторії рекомендуємо Account Abstraction — він знижує поріг входу на 60% порівняно зі звичайним гаманцем.
Як ми захищаємо виведення від ботів?
Cooldown між виведеннями, ліміти на суму на добу/тиждень, перевірка акаунта на підозрілу активність (забагато токенів за короткий час — ознака чита). Fingerprinting пристрою через DeviceCheck (iOS) або Play Integrity API (Android) — верифікуємо, що запит іде з реального пристрою, а не з емулятора/скрипта.
| Опція | Захист | Додаткова складність |
|---|---|---|
| Cooldown 24 год | Блокує часті виведення | Низька |
| Добовий ліміт | Обмежує сумарний вивід | Середня |
| DeviceCheck / Play Integrity | Відсікає емулятори | Висока |
Гаманець і підпис транзакції на мобільному
Для GameFi з масовою аудиторією — Account Abstraction (ERC-4337). Гравець не керує seed-фразою; додаток створює smart account через Biconomy SDK або ZeroDev. Підпис транзакції — через Face ID / Touch ID, а не seed-фразу. Gas спонсорується Paymaster'ом — економія до 40% на газі для типових транзакцій.
Для просунутих користувачів — підтримка зовнішніх гаманців через WalletConnect v2: Deep Link відкриває MetaMask/Trust Wallet на телефоні, користувач підтверджує транзакцію там.
Комісії та газ
Показуємо користувачеві:
- Скільки токенів отримає (amount - fee)
- Поточну вартість газу в USD (конвертуємо через API)
- Очікуваний час підтвердження (0.5–5 хв)
Мінімальний поріг виведення — обов'язковий параметр. Виведення 0.01 GOLD при газі $0.50 безглузде. Показуємо попередження, якщо комісія > 10% від суми виведення.
Що входить в роботу
- Документація архітектури виведення (voucher-схема, статусна модель)
- Вихідний код на Kotlin/Swift з інтеграцією бекенду
- Налаштування idempotency та nonce-системи
- Інтеграція DeviceCheck / Play Integrity
- Тестовий вивід у тестнеті
- Пост-релізна підтримка 2 тижні
Приклад оцінки на проєкті
Для гри з 10 тис. DAU і ERC-20 токеном: 3 тижні, включаючи Account Abstraction і Paymaster.Строки
2–3 тижні для реалізації виведення з voucher-патерном, idempotency та UI. З Account Abstraction і Paymaster — плюс тиждень. Вартість розраховується індивідуально після аналізу вимог. ERC-4337 specification — основа для Account Abstraction.
Отримайте консультацію з інтеграції виведення токенів під ключ. Оцінимо ваш проєкт за 1 день. Наші інженери сертифіковані з iOS та Android — зв'яжіться для обговорення архітектури та реалізації.







