Реализация создания (минтинга) NFT через мобильное приложение
Минтинг — это вызов функции mint смарт-контракта, которая записывает новый токен в блокчейн и привязывает к нему метаданные. Мобильный flow минтинга сложнее, чем десктопный: нужно выбрать медиафайл, загрузить его в децентрализованное хранилище, сформировать метаданные в формате ERC-721 JSON, затем вызвать контракт. Всё это должно работать с обрывами связи, медленным IPFS и ограниченными ресурсами мобильного устройства.
Загрузка медиа в IPFS
Минтинг начинается с медиафайла: изображение, видео, аудио. Пользователь выбирает из галереи или снимает.
На iOS — PHPickerViewController (iOS 14+) для выбора из Photos. На Android — ActivityResultContracts.PickVisualMedia (Photo Picker, Android 13+) с fallback на GetContent.
Медиафайл загружается в IPFS через Pinata, NFT.Storage или Web3.Storage API:
// iOS — загрузка файла в Pinata IPFS
func pinFileToIPFS(fileURL: URL, fileName: String) async throws -> String {
var request = URLRequest(url: URL(string: "https://api.pinata.cloud/pinning/pinFileToIPFS")!)
request.httpMethod = "POST"
request.setValue("Bearer \(pinataJWT)", forHTTPHeaderField: "Authorization")
let boundary = UUID().uuidString
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var body = Data()
body.append("--\(boundary)\r\nContent-Disposition: form-data; name=\"file\"; filename=\"\(fileName)\"\r\n")
body.append("Content-Type: image/jpeg\r\n\r\n")
body.append(try Data(contentsOf: fileURL))
body.append("\r\n--\(boundary)--\r\n")
request.httpBody = body
let (data, _) = try await URLSession.shared.data(for: request)
let response = try JSONDecoder().decode(PinataResponse.self, from: data)
return "ipfs://\(response.ipfsHash)"
}
IPFS-загрузка крупных видеофайлов (100+ МБ) на мобильном — фоновая задача с прогресс-баром. На iOS — URLSession с background configuration; на Android — WorkManager с setExpedited.
Формирование метаданных ERC-721
После загрузки медиа — формируем JSON метаданных по стандарту OpenSea:
// Android — формирование NFT metadata JSON
data class NftMetadata(
val name: String,
val description: String,
val image: String, // ipfs://QmXxx... (CID загруженного файла)
val externalUrl: String?,
val attributes: List<NftAttribute>
)
data class NftAttribute(
val traitType: String,
val value: String
)
// Пример результата
val metadata = NftMetadata(
name = "My NFT #1",
description = "Created via mobile app",
image = "ipfs://QmImageHash...",
attributes = listOf(
NftAttribute("Background", "Blue"),
NftAttribute("Rarity", "Rare")
)
)
Этот JSON тоже загружается в IPFS — получаем ipfs://QmMetadataHash. Именно этот URI передаётся в mint(to, tokenId, metadataURI).
UI форма минтинга
Минимальные поля: Name, Description, медиафайл, атрибуты (опционально). Атрибуты — динамически добавляемые пары ключ-значение. Preview карточки NFT в реальном времени.
Прогресс загрузки разбить на три шага с индикатором:
- Загрузка медиа в IPFS (долгий шаг)
- Загрузка метаданных в IPFS (быстро)
- Транзакция минтинга
Lazy Minting
Если газ дорог — предложить lazy minting: токен не записывается в блокчейн немедленно. Метаданные хранятся off-chain, а транзакция происходит при первой продаже (покупатель платит газ за минтинг). OpenSea поддерживает этот механизм через ваучеры — подписанные сообщения EIP-712, которые минтятся при покупке.
// iOS — подпись ваучера для lazy minting (EIP-712)
struct NFTVoucher {
let tokenId: BigUInt
let minPrice: BigUInt
let uri: String
let signature: Data // EIP-712 подпись создателя
}
Lazy minting убирает барьер «заплати газ до продажи» — важно для авторов, которые только начинают.
Сроки
5 рабочих дней: выбор медиа, загрузка в IPFS (Pinata/NFT.Storage), формирование ERC-721 metadata, вызов mint, прогресс-бар по шагам, базовая форма атрибутов. Lazy minting через EIP-712 ваучеры — дополнительно 2–3 дня.







