Uploading to IPFS with NFT.storage
В этом руководстве мы выбираем IPFS, децентрализованный поставщик хранилища, чтобы разместить выбранное фото и объект метаданных.
Мы также будем использовать NFT.storage для загрузки напрямую в IPFS через их HTTP API. Вы можете зарегистрироваться и получить бесплатный API-ключ на их сайте.
Выбор фотографии
Вам нужно выбрать существующее фото из нашей галереи. Чтобы представить интерфейс выбора и получить путь к файлу, используйте launchImageLibrary
из библиотеки react-native-image-picker
.
В примере приложения это делается в компоненте NftMinter
, где handleSelectImage
вызывается при нажатии кнопки.
Мы сохраняем путь к изображению как состояние, чтобы использовать его на следующем шаге.
import {launchImageLibrary} from 'react-native-image-picker';
const photo = await launchImageLibrary({
selectionLimit: 1,
mediaType: 'photo',
});
const selectedPhoto = photo?.assets?.[0];
if (!selectedPhoto?.uri) {
console.warn('Selected photo not found');
return;
}
const imagePath = selectedPhoto.uri;
Загрузка фото
Теперь, когда у нас есть путь к изображению, нам нужно загрузить сырые байты файла в IPFS, используя конечную точку NFT.storage /upload
.
Шаги:
- Используйте библиотеку
rn-fetch-blob
, чтобы прочитать изображение в строку Base 64. - Преобразуйте в сырые байты, декодируя строку Base64 с помощью
Buffer
. - Используйте
fetch
, чтобы отправить запрос, содержащий байты изображения, на конечную точку загрузки.
На этом шаге вам потребуется предоставить свой собственный API-ключ от NFT.storage. В примере приложения значение NFT_STORAGE_API_KEY
устанавливается через конфигурацию переменных окружения с использованием библиотеки react-native-config
.
// Read the image file and get the base64 string.
const imageBytesInBase64: string = await RNFetchBlob.fs.readFile(
imagePath,
'base64',
);
// Convert base64 into raw bytes.
const bytes = Buffer.from(imageBytesInBase64, 'base64');
// Upload the image to IPFS by sending a POST request to the NFT.storage upload endpoint.
const headers = {
Accept: 'application/json',
Authorization: `Bearer ${Config.NFT_STORAGE_API_KEY}`,
};
const imageUpload = await fetch('https://api.nft.storage/upload', {
method: 'POST',
headers: {
...headers,
'Content-Type': 'image/jpg',
},
body: bytes,
});
const imageData = await imageUpload.json();
console.log(imageData.value.cid);
Если успешно, imageData.value.cid
будет содержать действующий CID (Content Identifier). Это строка, которая уникально идентифицирует ваш загруженный ресурс.
Вы можете просмотреть свой загруженный ресурс на IPFS gateway, передав CID в URL (например, https://ipfs.io/ipfs/<cid>
).
Загрузка метаданных
Далее нам нужно составить объект метаданных, соответствующий стандарту Metaplex NFT, затем загрузить его на ту же конечную точку /upload
.
В примере приложения шаг загрузки метаданных также обрабатывается в функции uploadToIPFS
, которая вызывается позже в рамках более крупной mintNft
функции.
Следует отметить небольшое отличие. Поле изображения использует предварительно вычисленный CID для фотографии, а не ожидает завершения загрузки фотографии. Это оптимизация, которая объясняется в следующем разделе.
// Construct the metadata fields.
const metadata = JSON.stringify({
name,
description,
image: `https://ipfs.io/ipfs/${imageData.value.cid}`,
});
// Upload to IPFS
const metadataUpload = await fetch('https://api.nft.storage/upload', {
method: 'POST',
headers: {
...headers,
'Content-Type': 'application/json',
},
body: metadata,
});
const metadataData = await metadataUpload.json();
console.log(metadataData.value.cid);
Если успешно, metadataData.value.cid
теперь будет содержать CID, указывающий на JSON-объект, представляющий метаданные NFT.
Подытожив, у нас теперь есть два CID, которые можно просмотреть в IPFS. Первый — CID нашей загруженной фотографии, и второй — CID JSON Metadata (который имеет ссылку на CID фотографии в поле image
).
Предварительное вычисление CID
Вы можете заметить в примере приложения, что во время шага загрузки в uploadToIPFS
мы можем предварительно вычислить CID актива фотографии до его фактической загрузки в IPFS. Это оптимизация, позволяющая нам создавать и загружать объект метаданных без ожидания завершения загрузки фотографии и возврата CID.
// Fire off both uploads aysnc
return Promise.all([
imageUpload.then(response => response.json()),
metadataUpload.then(response => response.json()),
]);
Мы используем это преимущество, загружая как фотографию, так и метаданные асинхронно.
Это стало возможным, потому что CID генерируются детерминированно из двоичных данных любого данного актива. Это означает, что мы можем вычислить CID актива до его загрузки в IPFS.
Чтобы вычислить CID из байтов данного актива, см. функцию getCid
.
import {CID, hasher} from 'multiformats';
const crypto = require('crypto-browserify');
const SHA_256_CODE = 0x12;
const IPLD_RAW_BINARY_CODE = 0x55;
const getCid = async (bytes: Buffer) => {
const sha256 = hasher.from({
// As per multiformats table
// https://github.com/multiformats/multicodec/blob/master/table.csv#L9
name: 'sha2-256',
code: SHA_256_CODE,
encode: input =>
new Uint8Array(crypto.createHash('sha256').update(input).digest()),
});
const hash = await sha256.digest(bytes);
const cid = await CID.create(1, IPLD_RAW_BINARY_CODE, hash);
return cid;
};
ДимкаРеактнативный 🖋 | katsuhira02 📝 |
Go!