Как раздать NFT Solana через Airdrop Minting API от Crossmint
Обзор
Доставка NFT еще никогда не была такой простой. Независимо от того, являетесь ли вы компанией Web2, желающей начать работу с NFT, или у вас есть сообщество Web3, которое вы хотели бы вознаградить с помощью NFT, Mint API Crossmint позволяет вам создавать NFT для ваших пользователей с помощью одного запроса POST. NFT API Crossmint доступен непосредственно через QuickNode Marketplace, поэтому начать работу еще проще. В этом руководстве вы создадите простой скрипт, который позволит вам создавать и доставлять NFT напрямую списку клиентов (через адрес кошелька или адрес электронной почты 👀).
Что вы будете делать
В этом руководстве мы:
- Создайте конечную точку QuickNode с надстройкой Crossmint API.
- Создать метаданные NFT
- Airdrop NFT в объединенный список кошельков и адресов электронной почты Solana с использованием API Crossmint (с использованием TypeScript)
- Убедитесь, что раздача прошла успешно
- Записывать данные об аирдропе в файл
.json
Что вам понадобится
Чтобы следовать этому руководству, вам потребуется следующее:
- Базовые знания языков программирования JavaScript/TypeScript
- Установлен Nodejs (версия 16.15 и выше)
- установлен npm или yarn (мы будем использовать yarn для инициализации нашего проекта и установки необходимых пакетов. Не стесняйтесь использовать npm вместо этого, если это ваш предпочтительный менеджер пакетов)
- Опыт работы с TypeScript и установленный ts-node
Настройте свой проект
Создайте новый каталог проекта в своем терминале со следующим:
mkdir crossmint-drop cd crossmint-drop
Создайте файл для своего приложения app.ts
:
echo > app.ts
Инициализируйте свой проект с флагом «да», чтобы использовать значения по умолчанию для вашего нового пакета:
yarn init --yes #or npm init --yes
Создайте tsconfig.json
с включенным импортом .json:
tsc -init --resolveJsonModule true --target es2020
Создайте папку results
, которую мы будем использовать для сохранения вывода наших аирдропов:
mkdir results
Установите зависимость Solana Web3
Хотя это и не требуется для этого упражнения, мы будем использовать библиотеку Solana-Web3 для проверки адресов кошельков перед вызовом API Crossmint. Мы также будем использовать Axios для выполнения наших HTTP-запросов к Crossmint. В терминале введите:
yarn add @solana/web3.js axios #or npm install @solana/web3.js axios
Нам понадобится несколько компонентов из этих библиотек и fs для записи наших результатов в файл. Откройте папку crossmint-drop
в выбранной IDE (мы будем использовать VSCode) и добавьте следующие операторы импорта в app.ts
в строке 1:
import { PublicKey } from '@solana/web3.js'; import axios from 'axios'; import fs from 'fs';
Подключитесь к кластеру Solana с помощью конечной точки QuickNode
Чтобы получить быстрый доступ к Crossmint API, который позволяет создавать и отправлять NFT своим пользователям с помощью одной строки кода, даже если у них нет криптокошелька, вам необходимо создать конечную точку QuickNode с надстройкой Crossmint. на. Зарегистрируйте бесплатный аккаунт здесь. Создайте новую конечную точку Solana Devnet и обязательно настройте ее с помощью Crossmint NFT Mint API:
Скопируйте ссылку поставщика HTTP:
Внутри app.ts
под вашими операторами импорта объявите свой RPC (это понадобится нам при запуске нашего скрипта):
const QUICKNODE_RPC = 'https://example.solana-devnet.quiknode.pro/0123456/';
Ваше окружение должно выглядеть так.
У вас все настроено. Давайте создадим наше приложение!
Объявить типы
Мы будем использовать TypeScript для нашего сценария, поэтому мы определим несколько типов и интерфейсов, чтобы наш код оставался чистым и точным. Если вы разработчик JavaScript или предпочитаете не использовать TypeScript, это нормально.
Создайте раздел в своем коде // Types
и добавьте следующий код вверху вашего приложения под вашим импортом:
// TYPES type Email = string; type StringPubKey = string; type Destination = Email | StringPubKey; interface NftMetadata { name: string, image: string, description: string attributes: {trait_type: string, value: string}[], properties: { files: {uri: string, type: string}[], category: string } } interface MintNftProps { destination: Destination, qnEndpoint: string, collectionId: string, nftInfo: NftMetadata } interface FetchMintProps { qnEndpoint: string, collectionId: string, crossmintId: string } interface MintResult { destination: string, crossmintId: string, mint: string }
Немного о каждом объявлении:
- Во-первых, мы объявляем наш Destination как Email или StringPubKey (это будет то место, куда мы хотим, чтобы NFT наших пользователей направлялись).
- Затем мы определяем наши NftMetadata, которые принимают основную информацию о нашем NFT, включая массив признаков.
- MintNftProps определяет входные данные, которые мы будем использовать для нашей функции монетного двора. Нам понадобится пункт назначения, конечная точка QuickNode, идентификатор коллекции и метаданные создаваемого NFT.
- FetchNftProps определяет входные данные, которые мы будем использовать для проверки состояния нашего монетного двора.
- MintResult описывает, как мы будем регистрировать наши результаты (включая пункт назначения, уникальный идентификатор от CrossMint и адрес монетного двора — уникальный открытый ключ в блокчейне Solana).
Определить ключевые константы
Давайте определим несколько ключевых констант для нашего проекта. Под вашими типами добавьте:
// CONSTANTS const QUICKNODE_RPC = 'https://example.solana-devnet.quiknode.pro/0123456/'; const COLLECTION_ID = 'default-solana'; const DROP_LIST: Destination[] = [ '[email protected]', 'CTrLzkrcnqgqSTmzJ146ZTRkLAvwcjnxGSZBvqC5BH3w', '[email protected]', 'DemoKMZWkk483hX4mUrcJoo3zVvsKhm8XXs28TuwZw9H' ]; const DELAY = 1000;
- Сначала мы переместили
QUICKNODE_RPC
вместе с остальными константами. - Затем мы устанавливаем
COLLECTION_ID
вdefault-solana
. Это значение по умолчанию для монетных дворов Crossmint NFT на Solana. Если вы планируете запустить коллекцию NFT, возможно, имеет смысл создать собственную коллекцию. Сделать это можно с помощью методаcm_createCollection
(docs). Мы будем использовать значение по умолчанию для этого примера. - Список адресов электронной почты и адресов кошелька Solana, на которые мы хотим отправить NFT (мы настроим наше приложение, чтобы иметь возможность обрабатывать оба). Mint API от Crossmint создает кошельки для новых пользователей, позволяя вам отправлять NFT на их адреса электронной почты и легко добавлять новых пользователей.
- Мы добавим простую задержку между каждым запросом монетного двора в Crossmint, чтобы предотвратить превышение каких-либо ограничений скорости. Мы рекомендуем ознакомиться с лучшими практиками Crossmint, если вы планируете запустить какой-либо крупный выпуск NFT. Мы установим
DELAY
на 1 секунду (1000 мс).
Давайте добавим еще одну служебную константу, функцию wait
. Мы будем использовать это для создания задержки между вызовами API:
async function wait(ms: number):Promise<void> { return new Promise<void>((resolve) => { setTimeout(() => { resolve(); }, ms); }); }
Хорошо! Давайте перейдем к API Crossmint.
Создать функцию монетного двора
Давайте создадим наш HTTP-запрос к Crossmint, чтобы отчеканить наш NFT. Функция будет делать три вещи:
- Подтвердите наш пункт назначения как действительный адрес электронной почты или открытый ключ Solana.
- Собрать почтовый запрос
- Отправить почтовый запрос и обработать ответ
В app.ts
добавьте функцию requestCrossMintNft
:
const requestCrossMintNft = async ({ destination, qnEndpoint, collectionId, nftInfo }: MintNftProps) => { // Regular expression to validate an email address const emailRegex: RegExp = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; // Validate & define recipient (as either email address or Solana wallet else throw an error) let recipient: string; if (emailRegex.test(destination)) { recipient = `email:${destination}:sol`; } else if (new PublicKey(destination)) { recipient = `solana:${destination}`; } else { throw new Error('Invalid destination address (must be a valid email address or a Solana Wallet address).'); } // Assemble POST Request const metadata = { "name": nftInfo.name, "image": nftInfo.image, "description": nftInfo.description }; const data = { jsonrpc: "2.0", id: 1, method: "cm_mintNFT", params: [collectionId, recipient, metadata], // https://docs.crossmint.com/docs/cm-mintnft }; const config = { headers: { "Content-Type": "application/json", }, }; // Send Post Request return new Promise<string>(async (resolve, reject) => { try { let response = await axios.post(qnEndpoint, data, config); resolve(response.data.result.id as string); } catch (error) { reject("Error sending request to CrossMint. Check your inputs."); } }); }
Вот что мы делаем:
- Во-первых, мы используем регулярное выражение JavaScript (RegExp) и класс Solana PublicKey, чтобы проверить, что предоставленный адрес является допустимым пунктом назначения. Не стесняйтесь изменять это в зависимости от вашего списка рассылки (например, если вы отправляете только на адреса электронной почты, вам не нужна проверка Solana PublicKey и наоборот). Если недействительно, мы выдаем ошибку.
ОБЫЧНЫЕ ВЫРАЖЕНИЯ
Если вы никогда раньше не использовали регулярное выражение, шаблон emailRegex
проверяет, что входная строка начинается с одного или нескольких символов из набора a-z
, A-Z
, 0-9
, .!#$%&'*+/=?^_{|}~-
, за которым следует символ @
, а затем один или несколько символов из набора a-z
. , A-Z
, 0-9
и дефис -
, максимум 61 символ и возможность добавления точки .
, за которой следуют дополнительные символы, максимум 61 символ, из набора a-z
, A-Z
, 0-9
и дефис -
.
- Затем мы собираем наш POST-запрос на основе документации Crossmint. Обратите внимание, что наш
metadata
скомпилирован с использованием нашего параметраnftInfo
. Это означает, что мы можем создавать собственные атрибуты для каждого NFT, который мы чеканим!
2. Наконец, мы возвращаем обещание POST метода cm_mintNFT
. Если получен успешный ответ, обещание возвращает идентификатор Crossmint (уникальный идентификатор транзакции).
Создать функцию Fetch Mint
После того, как мы отправили запрос на чеканку в Crossmint, нам понадобится способ убедиться, что наша чеканка прошла успешно (до сих пор все, что мы знаем, это то, что Crossmint успешно получил наш запрос, а не то, что Солана подтвердила чеканку NFT). Для этого мы можем выполнить проверку состояния с помощью Crossmint, используя идентификатор, возвращенный на предыдущем шаге.
Создайте новую функцию fetchMintAddress
:
const fetchMintAddress = async ({ collectionId, qnEndpoint, crossmintId }: FetchMintProps) => { // Assemble POST Request const data = { jsonrpc: "2.0", id: 1, method: "cm_getNFTMintStatus", params: [collectionId,crossmintId], //https://docs.crossmint.com/docs/cm-getnftmintstatus }; const config = { headers: { "Content-Type": "application/json", }, }; // Send POST Request return new Promise<string>(async (resolve, _reject) => { try { let response = await axios.post(qnEndpoint, data, config); resolve(response.data.result.onChain.mintHash as string); } catch (error) { //reject("Error fetching mint address."); } }); }
Структурно это очень похоже на наш предыдущий шаг:
- Мы собираем запрос POST (на этот раз вызывая
cm_getNFTMintStatus
и передаваяcrossmintId
, возвращенный с предыдущего шага). - Отправьте запрос POST и, в случае успеха, верните уникальный хэш монетного двора в сети отчеканенного NFT.
Вместе вы можете запустить эти две функции, чтобы создать один NFT, но мы хотим немного повеселиться — давайте раздадим кучу 👇
Создать функцию массовой раздачи
У нас есть все инструменты для чеканки и подтверждения NFT с помощью Crossmint API — нам нужен способ массового сброса с некоторой возможностью настройки каждого NFT. Нам нужно создать функцию dropNfts
, которая будет:
- Используйте
.map
, чтобы создать обещание для каждого Destination в нашемdropList
. - Определите наши метаданные на основе какой-либо уникальной характеристики (в этом случае мы будем использовать индекс
i
, чтобы дать уникальное имя и характеристику каждому NFT. Не стесняйтесь обновлять метаданные так, чтобы они соответствовали вашему стилю! - Создайте обещание, что:
- Просит Crossmint отчеканить NFT, используя
requestCrossMintNft
- Ожидает 1 минуту, пока произойдет чеканка, позвонив. Примечание. Это простой метод для нашей демонстрации. В зависимости от ваших потребностей вы можете настроить некоторую логику запроса/повторения).
- Проверяет успешность монетного двора с помощью
fetchMintAddress
- Возвращает информацию о сброшенном NFT
- Выполнить все обещания, используя
Promise.allSettled()
- Создайте журнал наших результатов в каталоге
results
Эта следующая функция немного длинная, но мы уже сделали всю тяжелую работу в наших предыдущих шагах! В app.ts
создайте функцию dropNfts
, которая принимает список Destination, вашу конечную точку QuickNode и идентификатор вашей коллекции:
const dropNfts = async (dropList: Destination[], qnEndpoint: string, collectionId: string) => { console.log('Generating promises...'); let promises = dropList.map((drop, i) => { // 1-Define Custom Metadata const nftNumber = (i+1).toString(); const nftInfo = { name: `Demo Airdrop # ${nftNumber}`, image: 'https://arweave.net/UTFFfaVA3HoFcxwoMHEcvBLq19HrW6FuzpyygXqxduk', description: 'Demo airdrop NFT using Crossmint Mint API via the Quicknode add-on', attributes: [ { trait_type: "background", value: "blue" }, { trait_type: "type", value: "pixel" }, { trait_type: "id", value: nftNumber } ], properties: { files: [ { "uri": "https://arweave.net/UTFFfaVA3HoFcxwoMHEcvBLq19HrW6FuzpyygXqxduk", "type": "image/png" } ], category: "image" } }; // 2-Create Promise return new Promise< MintResult >(async (resolve, reject)=>{ setTimeout(async ()=>{ try { let crossmintId = await requestCrossMintNft({ destination: drop, qnEndpoint, collectionId, nftInfo }); if (!crossmintId) throw new Error('No CrossMint ID received.'); await wait(60000); // wait 1 min let mint = await fetchMintAddress({ collectionId, qnEndpoint, crossmintId }); resolve({ destination: drop, crossmintId: crossmintId, mint: mint ?? '' }); } catch (error) { reject('Unknown Error sending request to CrossMint.'); } },i * DELAY); }) }); // 3-Execute Promises console.log('Executing promises...(this will take 1min +)'); let results = await Promise.allSettled(promises); // 4-Save Results console.log('Writing results to ./results/results.json'); let data = JSON.stringify(results); fs.writeFileSync('./results/results.json',data); }
Эпично! Давайте зажжем его.
Бросьте свои NFT 🪂
В конце app.ts
вызовите функцию dropNfts
:
dropNfts(DROP_LIST, QUICKNODE_RPC, COLLECTION_ID);
Внутри вашего терминала введите следующее:
ts-node app
Примерно через минуту вы должны увидеть новый сгенерированный results.json
, который содержит массив результатов вашего монетного двора:
[ { "status": "fulfilled", "value": { "destination": "[email protected]", "crossmintId": "60f33f72-a8d8-41ce-b28a-bc899aa7b929", "mint": "AbJjT4j9MYQTya9aZ9qmCd36dspwoMnhfsEpZL91sFwG" } }, { "status": "fulfilled", "value": { "destination": "DemoKMZWkk483hX4mUrcJoo3zVvsKhm8XXs28TuwZw9H", "crossmintId": "0c4836cb-26dc-48a2-a55f-5d3ca40699da", "mint": "5RRDSrq6ME5Yz9qXcKRvSQeGD1F2AEnURnjfCs7BTEvN" } }, // etc. ]
Хорошая работа!
Подпишитесь на нашу рассылку новостей, чтобы получать больше статей и руководств по Ethereum. Если у вас есть какие-либо отзывы, не стесняйтесь обращаться к нам через Twitter. Вы всегда можете пообщаться с нами на нашем сервере сообщества Discord, где представлены одни из самых крутых разработчиков, которых вы когда-либо встречали :)