Реалізація покупки NFT в мобільному додатку
Купити NFT — це значить викликати функцію смарт-контракту маркетплейса, передав потрібну суму ETH або ERC-20. Звучить просто, але між натисканням «Купити» та підтвердженою транзакцією — кілька кроків, де все може пойти не так: газ скінчився, NFT вже куплені, гаманець не підключений. UX повинен обробляти кожен випадок.
Перевірка доступності листингу перед покупкою
Перед показом кнопки «Купити» — перевіріте актуальний статус листингу. NFT мог бути проданий секунду назад, а кешований екран цього не знає.
// iOS — перевірка активності листингу перед покупкою
func checkListingActive(contractAddress: String, tokenId: BigUInt) async throws -> Bool {
let listing = try await marketplaceContract.getListing(
nftAddress: EthereumAddress(contractAddress)!,
tokenId: tokenId
)
return listing.price > 0 && listing.seller != EthereumAddress.zero
}
Якщо неактивний — кнопка змінюється на «Не в продажу», без діалогу покупки.
Approve + Buy: одна або дві транзакції
При покупці за ETH — одна транзакція: buyItem(nftContract, tokenId, { value: price }).
При покупці за ERC-20 (наприклад, USDC) — дві:
-
usdc.approve(marketplaceAddress, price)— дозволити маркетплейсу витрачати токени -
marketplace.buyItem(nftContract, tokenId)— безпосередньо покупка
Показувати це як єдиний потік: «Крок 1 з 2: Дозволити списання USDC» → «Крок 2 з 2: Підтвердити покупку». Прогресс-індикатор, пояснення кожного кроку.
Оптимізація: використовувати permit (EIP-2612) якщо токен підтримує. Це об'єднує approve та buy в одну транзакцію через off-chain підпис.
Очікування підтвердження
Після відправки транзакції — не блокуй екран. Показуй:
- TransactionHash як посилання на Explorer (Etherscan, Polygonscan)
- Індикатор «Очікування підтвердження» з можливістю піти
- Push при отриманні N підтверджень (зазвичай 1–3)
// Android — очікування підтвердження з таймаутом
suspend fun waitForReceipt(txHash: String, timeoutMs: Long = 120_000): TransactionReceipt? {
val deadline = System.currentTimeMillis() + timeoutMs
while (System.currentTimeMillis() < deadline) {
val receipt = web3j.ethGetTransactionReceipt(txHash).send().transactionReceipt
if (receipt.isPresent) return receipt.get()
delay(3_000)
}
return null
}
Якщо receipt.status == "0x0" — транзакція завершилась з ошибкою (revert). Потрібно декодувати причину через debug_traceTransaction або перевіріти відомі помилки смарт-контракту.
Типові помилки та їх обробка
| Помилка | Причина | Рішення UI |
|---|---|---|
execution reverted: Not listed |
NFT знят з продажу | «NFT більше не продається» |
execution reverted: Price mismatch |
Ціна змінилась | Показати актуальну ціну, запропонувати оновити |
insufficient funds |
Не хватає ETH на газ | «Поповніть гаманець для оплати комісії» |
| Transaction timeout | Congestion мережі | Запропонувати прискорити транзакцію (increase gas price) |
Часовий графік: 3–5 днів: перевірка листингу, flow approve+buy, очікування підтвердження з push, обробка reverts.







