Candy machine nft как пользоваться
Перейти к содержимому

Candy machine nft как пользоваться

  • автор:

Три всадника апокалипсиса: создание NFT коллекций на Aptos, Sui и Solana

В этой статье мы создадим простые NFT коллекции на Aptos, Sui и Solana. Но стоит понимать, что первые два блокчейна ещё активно разрабатываются и следовательно этот туториал интересен только для ознакомления, т. к. некоторые вещи могут в любой момент поменяться.

Навигация по статье:

1. Aptos

2. Sui

3. Solana

1. Aptos

1.1. Подготовка

Убедитесь, что у вас установлен Node.js (>=16.10) и включен Corepack.

corepack enable
yarn add aptos dotenv && yarn add ts-node typescript @types/node -D

1.2. Инициализация клиентов

На первом этапе в примере инициализируются API и faucet (кран) клиенты.

  • Клиент API взаимодействует с REST API
  • Клиент faucet взаимодействует с сервисом devnet Faucet для создания и пополнения аккаунтов.

Создайте файл index.ts и добавьте импорты:

import dotenv from 'dotenv'; import < AptosClient, AptosAccount, FaucetClient, TokenClient, >from 'aptos'; import < NODE_URL, FAUCET_URL >from './common'; dotenv.config();
(async () => < const client = new AptosClient(NODE_URL); const faucetClient = new FaucetClient(NODE_URL, FAUCET_URL); const tokenClient = new TokenClient(client);

Используя клиент API, мы можем создать TokenClient , который мы используем для общих операций с токенами, таких как создание коллекций и токенов, их передача, получение и т. д.

const alice = new AptosAccount(); const bob = new AptosAccount();

В common.ts инициализируйте значения URL:

export const NODE_URL = process.env.APTOS_NODE_URL || 'https://fullnode.devnet.aptoslabs.com'; export const FAUCET_URL = process.env.APTOS_FAUCET_URL || 'https://faucet.devnet.aptoslabs.com';

По умолчанию URL-адреса обеих служб указывают на службы Aptos devnet. Однако их можно настроить с помощью следующих переменных окружения: APTOS_NODE_URL , APTOS_FAUCET_URL .

1.3. Создание локальных аккаунтов

Следующим шагом будет создание двух аккаунтов локально. Аккаунты представляют собой как on-chain, так и off-chain состояние. Оффчейн состояние состоит из адреса и пары открытого и закрытого ключей, используемых для аутентификации владельца. Этот шаг демонстрирует, как создать это оффчейн состояние (продолжаем в index.ts ).

const alice = new AptosAccount(); const bob = new AptosAccount();

1.4. Создание блокчейн аккаунтов

В Aptos каждый аккаунт должен иметь ончейн представление, чтобы поддерживать получение токенов и монет, а также взаимодействие с другими dApps. Аккаунт представляет собой средство для хранения активов, поэтому он должен быть явно создан. В данном примере кран используется для создания аккаунтов Алисы и Боба. Финансируется только Алиса:

await faucetClient.fundAccount(alice.address(), 20_000); await faucetClient.fundAccount(bob.address(), 20_000);

1.5. Создание коллекции

Теперь начинается процесс создания токенов. Во-первых, создатель должен создать коллекцию для хранения токенов. Коллекция может содержать ноль, один или много различных токенов. Коллекция не ограничивает атрибуты токенов, так как это всего лишь контейнер.

Ваше приложение будет вызывать createCollection :

const collectionName = "Alice's"; const tokenName = "Alice's first token"; const tokenPropertyVersion = 0; const txnHash1 = await tokenClient.createCollection( alice, collectionName, "Alice's simple collection", 'https://alice.com', ); await client.waitForTransaction(txnHash1, < checkSuccess: true >);

Сигнатура метода createCollection . Он возвращает хэш транзакции:

async createCollection( account: AptosAccount, name: string, description: string, uri: string, maxAmount: BCS.AnyNumber = MAX_U64_BIG_INT, ): Promise 

1.6. Создание токена

Ваше приложение будет вызывать createToken :

const txnHash2 = await tokenClient.createToken( alice, collectionName, tokenName, "Alice's simple token", 1, 'https://aptos.dev/img/nyan.jpeg', ); await client.waitForTransaction(txnHash2, < checkSuccess: true >);

Сигнатура метода createToken . Он возвращает хэш транзакции:

async createToken( account: AptosAccount, collectionName: string, name: string, description: string, supply: number, uri: string, max: BCS.AnyNumber = MAX_U64_BIG_INT, royalty_payee_address: MaybeHexString = account.address(), royalty_points_denominator: number = 0, royalty_points_numerator: number = 0, property_keys: Array = [], property_values: Array = [], property_types: Array = [], ): Promise 

1.7. Чтение метаданных токена и коллекции

Метаданные коллекции и токена хранятся на аккаунте создателя в его Collections в таблице. SDKs предоставляют удобные обертки для запросов к этим конкретным таблицам.

Чтобы прочитать метаданные коллекции:

const collectionData = await tokenClient.getCollectionData(alice.address(), collectionName); console.log(`Alice's collection: $`);

Чтобы прочитать метаданные токена:

const tokenData = await tokenClient.getTokenData(alice.address(), collectionName, tokenName); console.log(`Alice's token data: $`);

Вот как getTokenData запрашивает метаданные токена:

async getTokenData( creator: MaybeHexString, collectionName: string, tokenName: string, ): Promise  < const creatorHex = creator instanceof HexString ? creator.hex() : creator; const collection: < type: Gen.MoveStructTag; data: any >= await this.aptosClient.getAccountResource( creatorHex, "0x3::token::Collections", ); const < handle >= collection.data.token_data; const tokenDataId = < creator: creatorHex, collection: collectionName, name: tokenName, >; const getTokenTableItemRequest: Gen.TableItemRequest = < key_type: "0x3::token::TokenDataId", value_type: "0x3::token::TokenData", key: tokenDataId, >; // Мы знаем, что ответом будет структура, содержащая TokenData, отсюда и неявное приведение. return this.aptosClient.getTableItem(handle, getTokenTableItemRequest); >

1.8. Чтение баланса токенов

Каждый токен в Aptos является отдельным активом, активы, принадлежащие пользователю, хранятся в его TokenStore . Чтобы получить баланс:

const aliceBalance1 = await tokenClient.getToken( alice.address(), collectionName, tokenName, `$`, ); console.log(`Alice's token balance: $`);

1.9. Предложение и получение токена

Многие пользователи получили нежелательные токены, которые могут вызвать как минимальный дискомфорт, так и серьезные последствия. Aptos дает право каждому владельцу аккаунта решать, принимать или не принимать односторонние переводы. По умолчанию односторонние переводы не поддерживаются. Таким образом, Aptos обеспечивает основу для предложения и клейма токенов.

Чтобы предложить (отправить) токен:

const txnHash3 = await tokenClient.offerToken( alice, bob.address(), alice.address(), collectionName, tokenName, 1, tokenPropertyVersion, ); await client.waitForTransaction(txnHash3, < checkSuccess: true >);

Чтобы получить токен:

const txnHash4 = await tokenClient.claimToken( bob, alice.address(), alice.address(), collectionName, tokenName, tokenPropertyVersion, ); await client.waitForTransaction(txnHash4, < checkSuccess: true >);

1.10. Безопасная односторонняя передача токена

Чтобы обеспечить безопасную одностороннюю передачу токена, отправитель может сначала попросить получателя подтвердить оффчейн о предстоящей передаче. Это происходит в форме запроса мультиагентной транзакции. Мультиагентные транзакции содержат несколько подписей, по одной для каждого ончейн аккаунта. Затем Move может использовать это для предоставления разрешений на уровне подписи всем подписантам. Для передачи токенов это гарантирует, что принимающая сторона действительно желает получить этот токен, не требуя использования описанной выше структуры передачи токенов.

const txnHash5 = await tokenClient.directTransferToken( bob, alice, alice.address(), collectionName, tokenName, 1, tokenPropertyVersion, ); await client.waitForTransaction(txnHash5, < checkSuccess: true >); >)();

Теперь пробуем запустить:

npx ts-node index
Alice's collection: < "description": "Alice's simple collection", "maximum": "18446744073709551615", "mutability_config": < "description": false, "maximum": false, "uri": false >, "name": "Alice's", "supply": "1", "uri": "https://alice.com" > Alice's token data: < "default_properties": < "map": < "data": [] >>, "description": "Alice's simple token", "largest_property_version": "0", "maximum": "18446744073709551615", "mutability_config": < "description": false, "maximum": false, "properties": false, "royalty": false, "uri": false >, "name": "Alice's first token", "royalty": < "payee_address": "0x3bb244826f49ac293aff101564c462c8e2046912dc8f581db655e2dbb5bffee6", "royalty_points_denominator": "0", "royalty_points_numerator": "0" >, "supply": "1", "uri": "https://aptos.dev/img/nyan.jpeg" > Alice's token balance: 1

Готово! Достаточно просто. Полный код примера можно найти на GitHub . А тут можно увидеть оригинал туториала.

2. Sui

В Sui всё представляет из себя NFT — объекты уникальны, не взаимозаменяемы и принадлежат друг другу. Так что технически достаточно простой публикации. Я решил разобрать два способа создания NFT: простой с помощью Sui CLI и более гибкий с помощью смарт-контракта на языке Move.

2.1. Подготовка

2.2. Реализация с помощью Sui CLI

Вы можете создать NFT-подобный объект на Sui, используя следующую команду:

sui client create-example-nft

Вы увидите вывод, похожий на:

Successfully created an ExampleNFT: ----- Move Object (0x524f9fae3ca4554e01354415daf58a05e5bf26ac[1]) ----- Owner: Account Address ( 0xb02b5e57fe3572f94ad5ac2a17392bfb3261f7a0 ) Version: 1 Storage Rebate: 25 Previous Transaction: 98HbDxEwEUknQiJzyWM8AiYIM479BEKuGwxrZOGtAwk= ----- Data ----- type: 0x2::devnet_nft::DevNetNFT description: An NFT created by the Sui Command Line Tool id: 0x524f9fae3ca4554e01354415daf58a05e5bf26ac[1] name: Example NFT url: ipfs://bafkreibngqhl3gaa7daob4i2vccziay2jjlp435cf66vhono7nrvww53ty

А вот так выглядит контракт DevNetNFT:

module sui::devnet_nft < use sui::url::; use std::string; use sui::object::; use sui::event; use sui::transfer; use sui::tx_context::; /// Example NFT, который может заминтить кто угодно struct DevNetNFT has key, store < id: UID, /// Имя токена name: string::String, /// Описание токена description: string::String, /// URL токена url: Url, // Можно добавить кастомные аттрибуты >struct MintNFTEvent has copy, drop < // Идентификатор объекта NFT object_id: ID, // Создатель NFT creator: address, // Название NFT name: string::String, >/// Создать новый devnet_nft public entry fun mint( name: vector, description: vector, url: vector, ctx: &mut TxContext ) < let nft = DevNetNFT < id: object::new(ctx), name: string::utf8(name), description: string::utf8(description), url: url::new_unsafe_from_bytes(url) >; let sender = tx_context::sender(ctx); event::emit(MintNFTEvent < object_id: object::uid_to_inner(&nft.id), creator: sender, name: nft.name, >); transfer::transfer(nft, sender); > /// Обновить `description` у `nft` на `new_description` public entry fun update_description( nft: &mut DevNetNFT, new_description: vector, _: &mut TxContext ) < nft.description = string::utf8(new_description) >/// Навсегда удалить `nft` public entry fun burn(nft: DevNetNFT, _: &mut TxContext) < let DevNetNFT < id, name: _, description: _, url: _ >= nft; object::delete(id) > /// Получить NFT's `name` public fun name(nft: &DevNetNFT): &string::String < &nft.name >/// Получить NFT's `description` public fun description(nft: &DevNetNFT): &string::String < &nft.description >/// Получить NFT's `url` public fun url(nft: &DevNetNFT): &Url < &nft.url >>

2.3. Реализация с помощью смарт-контракта

Теперь же создадим простую и очень проблемную коллекцию. За основу я взял контракт DevNetNFT и пример коллекции . Также упомяну, что мои знания в языке Move нулевые, спасало только то, что это Rust-подобный язык.

Сначала создайте пустой пакет Move:

sui move new my_nfts

Клонируйте репозиторий Sui:

git clone https://github.com/MystenLabs/sui.git

Обновите [dependencies] в файле Move.toml вот так:

[package] name = "my_nfts" version = "0.0.1" [dependencies] Sui = < local = "../sui/crates/sui-framework" >[addresses] my_nfts = "0x0"

А теперь создайте файл collection.move :

touch my_nfts/sources/collection.move

И обновите его (комментарии на русском языке не поддерживаются, позже их нужно будет удалить):

module my_nfts::collection < use sui::url::; use std::string; use sui::object::; use sui::event; use sui::transfer; use sui::typed_id::; use sui::tx_context::; use sui::vec_set::; /// Example NFT, который может заминтить кто угодно struct MyNFT has key, store < id: UID, /// Имя токена name: string::String, /// Описание токена description: string::String, /// URL токена url: Url, >// ===== События ===== struct MintNFTEvent has copy, drop < // Идентификатор объекта NFT object_id: ID, // Создатель NFT creator: address, // Название NFT name: string::String, >// ===== Public view функции ===== /// Получить NFT's `name` public fun name(nft: &MyNFT): &string::String < &nft.name >/// Получить NFT's `description` public fun description(nft: &MyNFT): &string::String < &nft.description >/// Получить NFT's `url` public fun url(nft: &MyNFT): &Url < &nft.url >// ===== Entrypoints (точки входа) ===== /// Создать новый my_nft (этот ентри метод необязателен) public entry fun mint_to_sender( name: vector, description: vector, url: vector, ctx: &mut TxContext ) < let nft = MyNFT < id: object::new(ctx), name: string::utf8(name), description: string::utf8(description), url: url::new_unsafe_from_bytes(url) >; let sender = tx_context::sender(ctx); event::emit(MintNFTEvent < object_id: object::uid_to_inner(&nft.id), creator: sender, name: nft.name, >); transfer::transfer(nft, sender); > /// Перевести `nft` `получателю` public entry fun transfer( nft: MyNFT, recipient: address, _: &mut TxContext ) < transfer::transfer(nft, recipient) >/// Обновить `description` у `nft` на `new_description` public entry fun update_description( nft: &mut MyNFT, new_description: vector, _: &mut TxContext ) < nft.description = string::utf8(new_description) >/// Навсегда удалить `nft` public entry fun burn(nft: MyNFT, _: &mut TxContext) < let MyNFT < id, name: _, description: _, url: _ >= nft; object::delete(id) > // ===== Коллекция ===== // Коды ошибок /// Максимальная емкость, установленная для коллекции, не может превышать жесткого ограничения, /// которое равно DEFAULT_MAX_CAPACITY. const EInvalidMaxCapacity: u64 = 0; /// Попытка добавить объект в коллекцию, когда коллекция /// уже заполнена до предела. const EMaxCapacityExceeded: u64 = 1; const DEFAULT_MAX_CAPACITY: u64 = 0x10000; struct Collection has key < id: UID, objects: VecSet, max_capacity: u64, > /// Создать новую коллекцию и вернуть ее. public fun new(ctx: &mut TxContext): Collection  < new_with_max_capacity(ctx, DEFAULT_MAX_CAPACITY) >/// Создать новую коллекцию с настраиваемым ограничением размера и вернуть ее. public fun new_with_max_capacity( ctx: &mut TxContext, max_capacity: u64, ): Collection  < assert!(max_capacity 0, EInvalidMaxCapacity); let c = Collection < id: object::new(ctx), objects: vec_set::empty(), max_capacity, >; // Минтим 2 MyNFT и добавляем в коллекцию mint_and_add_nft(b"MyNFT #1", b"This is MyNFT #1", b"ipfs://bafkreibngqhl3gaa7daob4i2vccziay2jjlp435cf66vhono7nrvww53ty", &mut c, ctx); mint_and_add_nft(b"MyNFT #2", b"This is MyNFT #2", b"ipfs://bafkreibngqhl3gaa7daob4i2vccziay2jjlp435cf66vhono7nrvww53ty", &mut c, ctx); c > /// Создать новую коллекцию и передать ее подписавшему. public entry fun create(ctx: &mut TxContext) < transfer::transfer(new(ctx), tx_context::sender(ctx)) > /// Вернуть размер коллекции. public fun size(c: &Collection): u64 < vec_set::size(&c.objects) >/// Заминтить MyNFT объект и добавить в коллекцию. public fun mint_and_add_nft( name: vector, description: vector, url: vector, c: &mut Collection, ctx: &mut TxContext, ): TypedID < assert!(size(c) + 1 ; let sender = tx_context::sender(ctx); event::emit(MintNFTEvent < object_id: object::uid_to_inner(&nft.id), creator: sender, name: nft.name, >); vec_set::insert(&mut c.objects, object::uid_to_inner(&nft.id)); let nft_id = typed_id::new(&nft); transfer::transfer_to_object(nft, c); nft_id > /// Проверить, содержит ли коллекция определенный объект, /// идентифицируемый идентификатором объекта в байтах. public fun contains(c: &Collection, id: &ID): bool < vec_set::contains(&c.objects, id) >/// Удалить и вернуть объект из коллекции. /// Прервать, если объект не найден. public fun remove(c: &mut Collection, nft: MyNFT): MyNFT < vec_set::remove(&mut c.objects, object::uid_as_inner(&nft.id)); nft >/// Удалить объект из коллекции, а затем передать его подписавшему. public entry fun remove_and_take( c: &mut Collection, nft: MyNFT, ctx: &mut TxContext, ) < let object = remove(c, nft); transfer::transfer(object, tx_context::sender(ctx)); >public fun transfer_to_object_id( obj: Collection, owner_id: &mut UID, ) < transfer::transfer_to_object_id(obj, owner_id) >>

Этот контракт — сплошной эксперимент, т. к. в итоге у него есть ряд проблем: создатель MyNFT считается коллекция, а если MyNFT вытащить из коллекции, принадлежность к ней исчезнет. В общем, нет функции минта 🙂

А ещё, как видите, я закомментировал методы remove и remove_and_take , которые как раз таки вытаскивали NFT из коллекции, потому что пока не смог исправить ошибку в методе remove (edit 20.09: исправил ошибку).

Но всё же пример получился интересным на мой взгляд. Тестируем.

sui client publish --path my_nfts --gas-budget 30000

Вы увидите вывод, похожий на:

----- Certificate ---- Transaction Hash: Mpa5fQD++ej/RlNFaBK181iDsyfAwzAn2p6tYs89Ppk= Transaction Signature: AA==@8uR5Yl+9yT3fvScztVN1+9oTXrYpEbO8HDWc/gCxXpW+Qa3Dl6Wsqa7VR9QhgradYqxW1o9H5afbuiNcf87DAg==@7izXcEge0JZjZ1Ifhjit3s1A/NcFQ7SbezzQY2+xxeM= Signed Authorities Bitmap: RoaringBitmap <[1, 2, 3]>Transaction Kind : Publish ----- Transaction Effects ---- Status : Success Created Objects: - ID: 0x585677ee8152c2365b64e218a0a90842d6b9ba45 , Owner: Immutable Mutated Objects: - ID: 0x3f9594a043ff74d79f423f989d445f1317005050 , Owner: Account Address ( 0x8f624561d9659c623cf55153df227133fe409482 ) ----- Publish Results ---- The newly published package object ID: 0x585677ee8152c2365b64e218a0a90842d6b9ba45 Updated Gas : Coin

Вызываем метод create (создаём коллекцию):

sui client call --function create --module collection --package --type-args ::collection::MyNFT --gas-budget 30000

Вместо — id пакета (контракта), в моём случае это 0x585677ee8152c2365b64e218a0a90842d6b9ba45 .

Получаем примерно такой вывод:

----- Certificate ---- Transaction Hash: 2N4LFMjqEbrV1tDEXcYzIA+pzewCtN4n+FAv4Ar4f3c= Transaction Signature: AA==@+BGpI+WaXhzLl5Zynql2X44px8Q7+PI0ihxQUl5s/LpwvO2XvN508zRZm82rGv1Y7oKHefdY4VjWcKLXbSv7Cw==@7izXcEge0JZjZ1Ifhjit3s1A/NcFQ7SbezzQY2+xxeM= Signed Authorities Bitmap: RoaringBitmap <[0, 1, 3]>Transaction Kind : Call Package ID : 0x585677ee8152c2365b64e218a0a90842d6b9ba45 Module : collection Function : create Arguments : [] Type Arguments : ["0x585677ee8152c2365b64e218a0a90842d6b9ba45::collection::MyNFT"] ----- Transaction Effects ---- Status : Success Created Objects: - ID: 0x28a887795de98bd02aad3922b5d48fa444b005cb , Owner: Object ID: ( 0xceaad4a58eb097a0ecfd4412006abfcdd55b1928 ) - ID: 0x4f0f93e8480bc73bbbcf51800e14bad5c85deeee , Owner: Object ID: ( 0xceaad4a58eb097a0ecfd4412006abfcdd55b1928 ) - ID: 0xceaad4a58eb097a0ecfd4412006abfcdd55b1928 , Owner: Account Address ( 0x8f624561d9659c623cf55153df227133fe409482 ) Mutated Objects: - ID: 0x7478f82dc5fcc49b00d97c93179b43c347a8ea83 , Owner: Account Address ( 0x8f624561d9659c623cf55153df227133fe409482 )

А теперь давайте посмотрим как выглядит эта коллекция в эксплорере: сама коллекция , MyNFT #1 , MyNFT #2 .

Настройка Solana NFT

Имеется NFT коллекция на Solana. Нужна помощь нашему программисту доделать все. Деплой делали с помощью Candy Machine V3, коллекция уже выгружена в блокчейн. Нужна помощь с настройками:

-сделать 3 минт стадии OG, WL, Public

-подключить контракт к сайту. Скачали рабочий UI с гитхаб, но не можем его запустить. Правки и изменения мы уже будем вносить сами

-минимальная консультация нашего программиста

Для знающего человека работы на 10 минут.

Результаты работы

× Просмотр вложений доступен только зарегистрированным пользователям.

Отзыв заказчика о сотрудничестве с Николаем Семенютой

Настройка Solana NFT
Профессионализм
Контактность

Николай через удаленный рабочий стол помог нам настроить уже готовый NFT контракт, подвязать его к фронт-енду и выложить все на Vercel. Предоставил качественную консультацию и подсказал нам тонкости о которых мы даже не представляли. Благодаря Николаю приняли решение не экономить, купить выделенный RPC и это спасло наш минт (изначально нам насоветовали использовать api.mainnet-beta.solana.com).
Это самый грамотный специалист в сфере блокчейна, которого я встречал. За час общения узнал про солану больше, чем за год в сфере нфт флипов

От идеи создания NFT до опустошения Candy Machine

Давным давно в 2020 г. когда я только познавал мир крипты и параллельно торговал на фондовом рынке, я состоял в открытой группе где сидели как и трейдера с стажем, так и такие новички как и я.

В данной группе мне сказали что создавай своё комьюнити, или хотя-бы найди пару человек что-бы иметь больше информации, распределять обязанности. В тот момент я видел свое комьюнити так:

Два-три человека сидят, отбирают стаки для торговли внутри дня, каждому отведено определенной сектор или же, по своим скринерам.

За пару часов до начала торговой сессии все созваниваются и обсуждают какие стаки торговать, а какие нет.

Ну и ходил я с этой идеей очень долго. Потом, когда я уже погрузился с головой в крипту понял что без команды ты никто (Только если ты не торгуешь внутри дня), ведь когда ты понимаешь что хочешь зарабатывать в крипте то ты должен как минимум знать «все» , и захватывать все сферы

Ну а далее время шло и я все продумывал как же организовать это всё

И когда я уже более менее стал стоять на своих двух я понял что лучшего времени не будет, и без каких либо уменний в рисовании и знаний программирования (Хотя я уже изучал Python, и HTML но до конца я так и не дошёл — поэтому базовые знания были) я приступил к реализации проекта…

Как пришла идея к созданию своей коллекции?

Зима 2021 — 2022 г.

Возможно вы застали то время, когда стреляли почти-что все коллекции НФТ, многие тогда фармили WL и после чего лутали десятки иксов, и многие коллекции предлагали держателем доступ в DAO, но это было сложно назвать DAO ведь в большинстве случаев вы получали неликвидную НФТ, и грустное комьюнити которое пришло флипануть данную коллекцию, и не более. (Но есть и те кто реализовал все на высшем уровне — их можно пересчитать на пальцах)

В таких DAO люди не получали право голоса где всех просто ставили в известность постфактум

И тогда уже зародилась идея создание своей коллекции, конечно хотелось заскамить кого-то но я понимал что лучше сделать все правильно и красиво, и не залутать десятки тысяч вечно зеленых, а собрать комьюнити. На тот момент в паблике было всего-лишь 150-500 человек и я понимал что если сейчас это все делать то

  • Не наберу свою аудиторию
  • Выпаду из рынка на месяц, и пропущу всю активность с НФТ

Поэтому я стал просто искать инфу как создать свою коллекцию, и готовится к создание коллекции.

Данная НФТ дает доступ в наше закрытое DAO

В апреле 2022 года — я уже начал делать исходники для коллекции

  • Это были бейджи, которые я перерисовывал в Photoshop неделями, но так и не зашло мне это
  • Потом я вспомнил про коллекцию Portals — их коллекция в виде банковской карты, и начал кидать исходники, но тоже понял что это не то что я хотел увидеть
  • Персонажи, сначала начал с идеи персонажа, первые на ум пришли нинзя, но они за один день отвалились, и тут я увидел его странное сушество, немного посидев в Photoshop я отрисовал первого Гуманоида

Сложность была в моих кривых руках, и все что я не рисовал выходило мягко сказать говном, и в один прекрасный день родился мой первый Гуманоид

Конечно в первом варианте он был убожеством, но уже с отрисованным телом, если у него оно вообще есть)

И далее на основе этого тела я отрисовал

Humanoid — 11 разных гуманоидов, 7 из них похожие по форме, 4 залитых градиентом, и эксклюзив 9 отрисованные полностью с нуля — т.е без генерации

Background — 17 фонов скаченных из интернета с бесплатной лицензией, но не все фоны были скачаны, многие это просто градиент, и один это первая сгенерированная коллекция в размытом виде

Eyes — 5 обычных глаз, и одни в виде Thug очков

Teeth — 6 видов зубов, которые в день генерации нфт в основную сеть были перерисованными ибо они не попадали под гуманоида

Вот так и появились исходники для генерации моей первой НФТ коллекции

Как создавалась данная коллекция?

Выше вы уже узнали что данная коллекция рисовалась в Photoshop

Все исходники были в формате 2000х2000

Сначала сохранял гуманоидов, а после каждый отдельный атрибут, и далее стал вопрос о генерации нфт с метаданными

Прочитав документации по Ethereum и Solana выбор пал на Solana.

Узнал что все можно сделать без каких-либо знаний, я приступил к генерации нфт.

В данном случае я использовал Hashlips Art Engine — это открытый исходник для генерации нфт

Прочитав их инструкцию я сделал все по шагам, и первая коллекция сгенерирована!

Что мне для этого понадобилось?

  • Linux — но не обязательно, можно все сделать и в Windows
  • Visual Studio Code — для удобного редактирования кода

И библиотеки для генерации колекции

Видео гайды есть на этом youtube канале

Почему Solana?

Ну тут все просто

  • Быстрота блокчейна
  • Дешевые комиссии
  • Не требуется создавать Смарт контракты как в Ethereum

Как деплоил нфт?

Деплой коллекции происходил через Metaplex

Что мне для этого понадобилось?

  • Solana-cli — Для создания кошелька
  • Metaplex — Основной инструмент деплоя нфт коллекции

Тут все так-же было по детальной инструкции

Да на заметку, опустошать Candy Machine надо после того как: Все НФТ были отчеканены, и не раньше!

Выход на паблик

Первый анонс своей коллекции был сделан 03.06.2022 в данном посте , т.е от создания первого гуманоида — 16.05 прошло 17 дней!

И уже 03.06 был создан сайт для минта — исходник лежит на github

Сайт был создан очень быстро, был взят исходник, сделал сверху удобное меню, добавил кривой блок с информацией, и в тот же день были отчеканены первые WL НФТ

Далее, я протестировал сайт, он работал нормально, только вот столкнулся с проблемой в виде минта для WL, я создал обычный токен, и данный сайт все не как не хотел брать 1 токен, а брал 0.000000001, перерыв все я понял что проблема была в сайте.

Решил я данную проблему созданием нового WL токена только уже в виде НФТ, и о чудо он берёт 1 нфт и соляну для минта

Определился с датой минта — 07.06.2022, я отправил свою коллекцию в НФТ календари, по итогу только один календарь разместил мою коллекцию.

NFTCALENDAR, а условия разрешения были очень простыми — поставить их баннер у себя на сайте, и сделать превью для своей коллекции

День минта

Я сразу ожидал что будет отчеканено не более 5-10 шт.

— Но вы спросите зачем такая большая коллекция?

А ответ будет простым — просто захотел, ибо дальше данная NFT возможно будет сжигаться, для разного рода наград.

В первый час отчеканили почти все кто хотел, далее я просто ждал окончания минта — 08.06.2022.

В день окончания также были отчеканены 1-2 НФТ.

После окончания минта, я сминтил остальные нфт, и принялся за финальные действия…

Опустошение Candy Machine и выход на маркетплейс

Коллекция сминчена на 100%, иду подписывать все нфт, и столкнулся с проблемой соль в тот момент не очень быстро работала, и две подряд транзакции у меня идут с фейл, хотя если бы я сразу все чекнул в Exploler то я бы не потратил много времени на эту ошибку

Далее я выдохнув, что это не ошибка и пошёл листится на все маркетплейсы

OpenSea — самый лучший маркетплейс, листинг моментальный

Magic Eden — тут возникла проблема, хотя я так и нечего не понял — Команда отклонила ваш листинг) — но в конце концов коллекция на Magic Eden

Ну и далее я опустошаю Candy Machine на которой лежало 0.2 SOL, и всё данная коллекция была официально запушена

Вот такая получилась статья, возможно она вам поможет!

How to Mint an NFT on Solana Using Candy Machine

This guide will give you an in-depth walkthrough of how to mint an NFT on Solana using Candy Machine through a series of technical steps. If you’d like to accomplish this task quicker and leave the heavy lifting to us, we recommend the Crossmint NFT Mint API [mainnet] add-on. By using the Crossmint NFT Mint API [mainnet] , you can avoid having to create a Candy Machine. Use the NFT Mint API to create collections and reduce up-front costs and mint NFTs easily!

This guide is based off of the V1 of Candy Machine. V1 has been deprecated. You can catch an up-to-date guide on V2 here.

Overview​

Hello reader! We have had a lot of requests for another Solana NFT guide where we show you how to Mint a 1-of-1 token, or NFT on Solana. In the previous guide we did not quite get to where the juicy stuff is. That is the actual linking of the picture/metadata to the token. In order to do this we will use a program called Candy Machine. Candy Machine is a tool that allows you set up your own Solana NFT shop in your own little corner of the internet. In this guide we will walkthrough how to setup this one-stop-shop for Solana NFT minting.

NOTE: this guide is meant to show you the workflow and process for how to create and mint your own NFTs on Solana. Not teach you the underlying technologies.

There is much to learn about in the Solana ecosystem, and if you intend to do more than this happy path that we provide, you will need to dig in and learn these individual pieces! Cheers 🙂

These prerequisites will need to be installed before going forward, and we will be linking to the installation docs/guides for each one, as they will do a better job explaining how to install it than we would.

Prerequisites:

  • Nodejs (version 14.17.6)
  • Docker
  • Yarn
  • Solana CLI
  • Metaplex CLI
  • Phantom Wallet
  • Deep familiarity with CLI tools

Candy Machine Overview​

Candy Machine is a tool that utilizes the Metaplex CLI to generate an NFT, link a picture and relevant metadata to the NFT token, and setup a "fair auction." A "fair auction" really consists of two separate pieces. The first of which is that it starts at the same time for everyone. No pre-sales! The second component is that it will not send the transaction if there are no more NFTs to be minted.

No more throwing your SOL into the void, unsure if there are any more editions to be minted. While there is a LOT that you can dig into here as far as the internals go, the best way to learn is by building!

Forking the Repository​

There are two different repositories that you can use. One of which is built by the candy-machine maintainers and another one that a community member built on top of to abstract a few things and create easier workflows. We will be using the latter in this tutorial. If you need to deviate from the happy path however, you will need the underlying knowledge of how Metaplex works.

To fork the repo you want to go to the community member's repo and fork it by clicking the fork button at the top

after you have it forked you will want to clone the repository:

git clone https://github.com//solana-candy-factory 

With the projects successfully forked you can now begin the project setup.

Project Setup​

With all of the code pulled down to your local machine, you should open the solana-candy-factory folder in your code editor of choice.

Installing dependencies​

With that done we now need to begin setting the project up for development.

The first thing to do will be to install the dependencies for the project by running the command:

yarn 

Spinning up the database​

After installing your dependencies, you will want to start the postgres database in docker that will hold your nfts before they are deployed on the network.

yarn start-nft-manager-db 

This will spin up your database and allow Strapi, which is a headless CMS that will hold all of our NFT information, to connect to the docker container.

NFT Manager​

This is the real beauty of this repository. You are able to use a headless CMS to upload and manage all of your NFTs before blasting them online to be minted. To get this setup you will run the following command:

yarn nft-manager 

You can then navigate yourself to http://localhost:1337/admin. You first need to create a free Strapi account and log in. Then, you need to create a "user"; to do so, click on the appropriate tab as shown below.

Your user will need to have the following fields:

  • Username: admin
  • Password: Admin123
  • Email: yourEmail@website.com
  • Confirmed: On

Role: Authenticated (This is super important!)

All that is left is to save your newly created User. Having done that, we can now move on to creating a collection.

A collection has a one-to-many relationship with NFTs. One collection will have many NFTs pointing to it. The process is very similar to creating a User. Go to the "Collections" tab to create a new collection. There are only two fields here. "Name" and "Family" are the only fields that relate to "collections", because the fields we are filling out in Strappi need to match the json attributes defined in the Solana NFT Metadata Standard.

"Name" should be the name of the specific project you are launching, whereas "Family" can be part of a larger theme.

I will be naming the fields by their name for the sake of transparency.

Name will be "Collection _ Name", and Family will be "Collection _ Family." You can now save the collection, and move to the "NFTs" tab to create your individual NFTs.

I will show you what mine looks like, and explain what each field means:

Format for the following information --> FieldName: Value --- Explanation.

  • Name: CoolNFTName --- The Name of your NFT
  • Symbol: CNN --- This is the "Ticker" for your NFT, like DAPE for the Degenerate Ape Academy.
  • Description: This is the description of my Super Cool NFT --- The description for the individual NFT.
  • Seller _ fee _ basis _ points: 500 --- This is the % of royalties the creator of the NFT will receive on each purchase. (500 equates to 5%). You don't need to worry about this too much with this framework as we will set this using the CLI, but its always good to verify your data and ensure that this is set to what you would want it to be, regardless of the CLI implementation.
  • Image: Image.png --- Name of the image file. Leave this as Image.png (Regardless of the uploaded photo's name) as this will be dynamically changed. It MUST match the Properties -> Files -> Uri json field below.
  • Animation URL: n/a --- URL to a multi-media attachment of the asset. The supported file formats are MP4 and MOV for video, MP3, FLAC and WAV for audio and GLB for AR/3D assets. You may use the ?ext= query to provide information on the file type.
  • External URL: https://Quicknode.com/ --- This is typically another link to view the asset on a centralized website such as imgur. You can however, leave it blank. (blank == "")
  • Traits:
  "attributes": [   "value": "Solana", "trait_type": "Chain" >,   "value": "QuickNode", "trait_type": "Company" >,   "value": "Tutorial", "trait_type": "Category" >,   "value": "Degen", "trait_type": "Status" > ] > 

This will be the "attributes" of your NFT. You do not have to have these, and they are completely arbitrary. However, if you do set an attribute, it must have both a value, and a trait _ type field. Value can be a string or a number.

  "files": [   "uri": "image.png", "type": "image/png" > ], "category": "image", "creators": [   "share": 100, "address": "7K6XCSwVh3YZAh7GhARZ9pQ7gWkFNuWQ77U5CbV3PcF3" > ] > 

Properties contains much of the information around what exactly is being shown. It will link to the type (see supported types here), point to the uri (uploaded on arweave), and then a link to the creators of the NFT. There can be multiple creators so long as the "share" totals up to 100.

  • Content: This is where you can upload your image. This is the one I chose!

Note: Your image must be in .png format!

After filling out all of this information with the values that suit you personally, you are all ready to mint an NFT!

Deploying the Candy Machine​

With everything in place there are just a few commands to run. Due to the framework we are building on top of this is only a few commands.

First we will want to ensure that all of the funds the NFTs generate are going to go to you! Use the following command:

yarn update-creator-all-rows 

It will then ask you to paste in the correct address. Put your Solana address here. This is the creators address from before!

Then you can put in the % of royalties you should make off of future sales of the artwork. This is the Seller _ fee _ basis _ points field.

With those double-checked, we can now generate the NFT data.

yarn generate-nfts-sources 

It will ask if you want to shuffle. This will randomize the order in which people mint nfts. If you are doing a large drop of 5-10k NFTs, you probably don't want them going in order! This will randomize it for you. For the purposes of this tutorial it does not matter since there is only one.

After running the previous command you should see two files in the nft-manager/nfts-sources folder, 0.json, and 0.png.

If those are there, you are ready to deploy!

Since we are using devnet things will be slightly different than if you were to deploy on mainnet, however the repository's README covers the differences quite nicely. You can run the following command, and accept all of the default values by pressing the "Enter" key without any other input.

yarn setup-dev 

If you would like to learn about the internals of what this command is doing, it is available in the readme for you! Just know that this is setting up the program that is responsible for minting the NFTs you just generated previously.

That is everything for the deployment process!

Minting your NFT​

With the program up, all we need to do is interact with it! To set up the website, run the following command.

yarn dev 

This will spinup a webpage at http://localhost:3000. You can connect your wallet, and click on the "Mint" button as shown below.

You can see on the one in the picture there are no more available as we have already minted the only one. If you try to mint while there are none available, it will ask you to confirm the transaction; then the program denies it as there are none left to give you. This goes back to the "fair auction" that we spoke of earlier.

If everything went accordingly you should now have an NFT in your Phantom wallet. This is what mine looks like!

Conclusion​

Congratulations! You just minted your first NFT on Solana! There is a lot going on under the hood that we didn't go over. If you are trying to do a larger NFT launch on the mainnet I would recommend doing a deep dive on Metaplex to see how each different command works, as things do not always go smoothly, and you want to be able to fix your problem should something go awry. That being said, you still learned a bunch!

Subscribe to our newsletter for more articles and guides on Ethereum. If you have any feedback, feel free to reach out to us via Twitter. You can always chat with us on our Discord community server, featuring some of the coolest developers you'll ever meet 🙂

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *