Реализация продажи NFT в мобильном приложении
Чтобы выставить NFT на продажу, нужно выполнить две операции: разрешить маркетплейсу управлять токеном (approve или setApprovalForAll) и создать листинг. Это две транзакции — значит, два расхода на газ и два подтверждения пользователя. UX должен провести через это без боли.
setApprovalForAll vs approve
setApprovalForAll(marketplaceAddress, true) — одно разрешение для всех токенов коллекции. Пользователь делает это один раз, потом может листить любые NFT из этой коллекции без повторного approve.
approve(marketplaceAddress, tokenId) — разрешение для конкретного токена. Безопаснее, но каждый листинг требует отдельной транзакции.
Рекомендуемый UX: при первом листинге из коллекции — предлагать setApprovalForAll с объяснением «Разрешите один раз для всей коллекции, чтобы не платить газ при каждой продаже». Пользователь должен понимать последствия.
// iOS — проверка одобрения перед листингом
func checkApproval(nftContract: EthereumAddress, owner: EthereumAddress) async -> Bool {
let erc721 = ERC721(web3: web3, provider: web3.provider, address: nftContract)
return (try? await erc721.getApproved(tokenId: tokenId) == marketplaceAddress)
?? (try? await erc721.isApprovedForAll(owner: owner, operator: marketplaceAddress))
?? false
}
Форма листинга
Минимум полей: цена (в ETH или ERC-20 токене), опциональный дедлайн листинга. Показывай прямо в форме расчётную сумму, которую получит продавец с учётом комиссий: netAmount = price * (1 - platformFee - royalty).
// Android — расчёт чистой суммы продавца
data class ListingFeeBreakdown(
val grossPrice: BigDecimal,
val platformFeePercent: BigDecimal,
val royaltyPercent: BigDecimal
) {
val platformFeeAmount get() = grossPrice * platformFeePercent / BigDecimal(100)
val royaltyAmount get() = grossPrice * royaltyPercent / BigDecimal(100)
val sellerReceives get() = grossPrice - platformFeeAmount - royaltyAmount
}
Роялти берётся из ERC2981.royaltyInfo(tokenId, price). Показывай строку «Роялти создателю: X%» — это важно для прозрачности.
Flow создания листинга
- Проверить одобрение → если нет, отправить
approve/setApprovalForAll - Подождать подтверждения approve
- Отправить
listItem(nftAddress, tokenId, price, deadline) - После подтверждения — NFT появляется в каталоге
Каждый шаг с прогресс-индикатором. Если пользователь закрыл приложение после шага 1 — при следующем открытии проверить одобрение (уже выдано) и предложить продолжить с шага 3.
Изменение цены и снятие с продажи
updateListing(nftAddress, tokenId, newPrice) — одна транзакция без повторного approve.
cancelListing(nftAddress, tokenId) — снятие листинга. После подтверждения — NFT исчезает из каталога. Важно: отображать кнопку «Снять с продажи» только тогда, когда листинг действительно активен (проверка on-chain или через индексатор).
Сроки: 3–5 дней: форма листинга с разбивкой комиссий, flow approve + list с checkpoints, изменение и отмена листинга.







