How to Create an NFT Marketplace with Filebase + Flow

# Prerequisites

💡 Using React
React.js is the most widely-used UI library that arguably takes away the tediousness of setting up a JavaScript app. You are welcome to work with another library/framework if you are happy to take on the additional work of taking the road less travelled (opens new window) approach.

Обзор L1-платформы для NFT и GameFi

Что такое блокчейн и криптовалюта Flow?

NFT и метавселенные

Что такое блокчейн и криптовалюта Flow?

NFT и метавселенные

# Next steps

Because NFTs have assets that need to be stored off-chain permanently, using NFT.Storage to store them on the Filecoin network is a natural way to go as the first step to launch your NFT app on Flow quickly.

Last but not least, this tutorial is not perfect, and it can be improved with your help. Do not hesitate to create a pull request. No contribution is too small!

What is an NFT Marketplace?

NFT marketplaces are gaining traction in industries such as gaming, art, social networking, and music, nearly capturing every market that deals with digital assets. With the influx of Metaverse projects, NFT marketplaces have grown into prominence and relevance even further.

With time, the features of NFT marketplaces are upgrading, and limitations like lack of NFT interoperability are getting addressed. Cross-chain bridging, niche-specific NFTs, NFT swapping, and compatibility with multiple metaverse projects are some of the advanced features of contemporary NFT marketplaces.

Какую проблему решает Flow

Многие проекты выпускают NFT в сети Ethereum, однако в периоды большой загрузки транзакционные издержки превышают десятки долларов. Блокчейн Flow решает проблему масштабирования и высоких комиссий без шардинга.

Блокчейн Flow предназначен для работы с NFT, игровыми проектами и другими приложениями. Он оптимален для пользователей, не знакомых с блокчейн-технологиями: адреса в сети короткие, а ее участники могут обойтись без приватных ключей.

Платформа ориентирована на работу крупных децентрализованных приложений, в которых используются NFT — в основном это проекты в сфере GameFi.

У Flow есть нативная криптовалюта, которая торгуется под тикером FLOW, а также официальный кошелек для ее хранения — Dapper Wallet. Dapper Labs реализуют на платформе собственные проекты, однако протокол Flow открыт для сторонних программистов и компаний.

Требования к ноде и стейкинг криптовалюты Flow

Поскольку Flow использует алгоритм PoS, всем его нодам для работы необходимо внести определенное количество FLOW в стейкинг. Минимальная сумма зависит от выбранного типа узла:

  • исполнение — 1,25 млн FLOW;
  • консенсус — 500 000 FLOW;
  • сбор — 250 000 FLOW;
  • верификация — 135 000 FLOW.

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

Крупнейшие проекты на блокчейне Flow

Flow является одной из самых успешных и популярных сетей для сферы NFT. Этого удалось достичь благодаря привлечению Dapper Labs в проект крупных партнеров, таких как Национальная баскетбольная ассоциация (NBA) и Ultimate Fighting Championship (UFC).

После запуска сети, разработчики создали первые NFT-проекты, в частности платформа NBA Top Shot, созданная в сотрудничестве с НБА. Она позволяет выпускать NFT-коллекции, связанные с крупнейшими баскетбольными командами американской лиги и проходящими между ними состязаниями. Контент токенов NBA Top Shot обычно представляет собой изображение игрока или интересный видеофрагмент матча.

Пример контента NFT на NBA Top Shot
Пример контента NFT на платформе NBA Top Shot. Данные: NBA Top Shot

NBA Top Shot стала хорошей рекламой для Dapper Labs, которая привлекла внимание к блокчейну Flow со стороны других крупных брендов. Платформа уже давно возглавляет рейтинг наиболее популярных продуктов для коллекционирования цифровых предметов от Dapp Radar. Успех NBA Top Shot также позволил Dapper Labs провести крупный инвестраунд весной 2021 года.

В январе 2022 года начала работу NFT-платформа UFC Strike — официальный проект Dapper Strike и знаменитой организации по смешанным единоборствам, в котором использовали многие механики NBA Top Shot.

В августе того же года в сети Flow заработало приложение NFL All Day, разработанное Dapper Labs в партнерстве с Национальной футбольной лигой США (NFL). К концу сентября объем продаж на платформе превысил показатель NBA Top Shot.По данным обозревателя блоков, на 25 сентября 2022 года в сети Flow создано уже более 15 млн аккаунтов и развернуто свыше 1700 смарт-контрактов. Экосистема включает несколько десятков активных NFT-проектов и превосходит по числу транзакций с невзаимозаменяемыми токенами Ethereum.

Главное

  • Flow — это блокчейн-платформа, предназначенная для выпуска NFT и реализации игровых приложений. Проект позволяет создавать dapps, цифровые объекты коллекционирования и метавселенные.
  • Архитектура Flow основана на принципе разделения задач: каждая нода выполняет отдельную функцию. Такой принцип позволяет на порядок повысить производительность сети. Поддержка языка программирования Cadence при написании смарт-контрактов упрощает выпуск невзаимозаменямых токенов (NFT).
  • Создателем платформы является компания Dapper Labs, автор первой популярной блокчейн-игры CryptoKitties. На блокчейне Flow построена экосистема, поддерживаемая ведущими спортивными объединениями, включая NBA, UFC и NFL. Компания Meta интегрировала NFT, выпущенные во Flow, в Instagram и Facebook.

Блокчейн Flow — проект компании Dapper Labs, которая стала известна благодаря блокчейн-игре CryptoKitties. Ее геймплей предполагал «воспитание» и поединки между персонажами, привязанными к невзаимозаменяемым токенам (NFT) в сети Ethereum. CryptoKitties стала первой популярной блокчейн-игрой и в конце 2017 года привела к сильным перегрузкам Ethereum и, как следствие, общему росту комиссий в сети.

В итоге в Dapper Labs решили создать собственный, более масштабируемый блокчейн, «заточенный» под операции с NFT. Основную сеть Flow запустили в 2020 году. Основателем проекта является Дитер Ширли, а генеральным директором — Рохам Гарегозлоу. Ширли известен как создатель стандарта ERC-721, а Гарегозлоу ранее возглавлял один из первых венчурных фондов для криптопроектов под названием Axiom Zen.

В сентябре 2020 года в результате публичной продажи монет FLOW разработчики получили $19,5 млн. В мае 2022 года Dapper Labs привлек $725 млн в фонд развития экосистемы. Среди его участников — Andreessen Horowitz, Coatue, Greenfield One, Liberty City Ventures и другие. Фонд предоставляет гранты и прямые инвестиции в криптовалюте FLOW. Организация развивает игровые и инфраструктурные проекты, а также помогает создателям контента.

Токен FLOW

Если Flow – новая цифровая инфраструктура, то токен FLOW – топливо следующего поколения, которое питает ее. Токен необходим для работы сети и всех приложений на ней. FLOW разработан как способ оплаты, а также как долгосрочный резервный актив для всей экономики, построенной на блокчейне Flow. Модель Proof-of-Stake, используемая протоколом, требует, чтобы все валидаторы стейкали FLOW, чтобы участвовать в сети. Он также используется для оплаты и будущего управления протоколом.

Про NFT:  Освоение методов оптимизации размера NFT в Opensia: подробное руководство

Нативный токен Flow был первоначально предложен публике в октябре 2020 года, но недоступен в США и Канаде. Токены, проданные посредством первичного предложения, были заблокированы как минимум на год, что означает, что они не могут быть распространены, пока не будут разблокированы.

Однако, например, FLOW, заработанный валидаторами, можно свободно переводить и продавать, поэтому существует некоторая сумма, циркулирующая на рынках через различные биржи. CoinMarketCap сообщает, что текущее предложение составляет чуть менее 34 миллионов, а рыночная капитализация занимает 109 место и составляет 872 миллиона долларов.

В общем, Flow уже выиграл от бума NFT, который мы наблюдали в последние несколько месяцев, и протокол настроен на то, чтобы улавливать еще больше всплесков интереса в интерактивных и коллекционных опытах. И если они действительно смогут удовлетворить открытые миры крупномасштабных криптовалютных игр, мы услышим гораздо больше о Flow в ближайшие годы.

Токеномика криптовалюты FLOW

FLOW — это нативная криптовалюта одноименного блокчейна. Монеты необходимы для оплаты комиссий, выполнения смарт-контрактов и работы алгоритма консенсуса. Также FLOW применяют в качестве обеспечения выпускаемых токенов.

Изначально криптовалюту Flow распределили между инвесторами путем публичного токенсейла, проведенного в конце 2020 года на платформе CoinList. Всего Dapper Labs продали 100 млн FLOW. Еще 25 млн распределили 6 октября 2020 года. Реализованные монеты заблокировали на один год, что препятствовало их свободной продаже.

На момент написания в обращении находится более 1 млрд FLOW, а максимальная эмиссия составляет 1,39 млрд. Крупнейшим держателем этой криптовалюты является Flow Foundation. В его распоряжении находятся 250 млн FLOW, зарезервированные для долгосрочного развития проекта.

Отслеживать транзакции в сети можно при помощи блокчейн-обозревателя Flow. На ресурсе представлена аналитическая информация, включая число заблокированных активов, количество нод различных типов и параметры стейкинга. Также там находятся актуальные данные о наградах. Доходность стейкинга по состояния на 22 сентября, согласно данным Staking Rewards, составляет  8,3% годовых.

Система управления и развитие экосистемы Flow

Осенью 2021 года Flow интегрировал решение для децентрализованного облачного хранения файлов от блокчейн-платформы Filecoin. В то же время Dapper Labs заключила соглашение  о долгосрочном сотрудничестве с Google Cloud, которое должно способствовать масштабированию Flow.

Одним из приобретений Dapper Labs стал стартап Brud, решения которого призваны добавить в экосистему Flow инструменты для быстрого создания децентрализованных автономных организаций (ДАО). В Flow действует баунти-программа для данного направления. Сейчас принятие и внедрение предложений происходит офчейн.

Еще в 2020 году в Dapper Labs заявляли о планах перевести CryptoKitties с Ethereum на Flow. Это позволит реализовать новые игровые функции и применять токены в других приложениях. Однако точные сроки миграции пока не известны.

Нашли ошибку в тексте? Выделите ее и нажмите CTRL+ENTER

How to develop an NFT marketplace using IPFS and Flow?

Let’s start with the creation of the contract and token minting.

Setting Up Tools 

Install Flow CLI on your system. There are different commands for installing CLI based on different operating systems.

For example, to install Flow CLI on macOS, use the command:

brew install flow-cli
iex “& { $(irm ‘https://storage.googleapis.com/flow-cli/install.ps1‘) }”
sh -ci “$(curl -fsSL https://storage.googleapis.com/flow-cli/install.sh)”

Asset files will be stored on IPFS. In this example, we are going to use Pinata for storing files. You can sign up for a free account and get an API key here.

It is also essential to install a NodeJS and a text editor to highlight Flow smart contract code.

The second step is to create a directory for the project using the command:

mkdir pinata-party

Initialize a new flow project and change it into that directory:

cd pinata-party

Now, open the project in your code editor and let’s start working. First, create a folder named cadence. Add another folder called contracts within that folder. Finally, create a file within the contracts folder named PinataPartyContract.cdc.

We need to update the contract’s object in flow.json using the code:

“contracts”: {
“PinataPartyContract”: “./cadence/contracts/PinataPartyContract.cdc”
}

Update the deployments object in that file using the below code:

“deployments”: {
“emulator”: {
“emulator-account”: [“PinataPartyContract”]
}
}

It will enable the Flow CLI to use the emulator for deploying our contract. This code is also referencing the account and the contract that we are going to write soon.

Contracts

We need to create contracts for minting NFT, associating metadata to the NFT and ensuring that metadata points to the underlying assets stored on IPFS.

pub contract PinataPartyContract {
pub resource NFT {
pub let id: UInt64
init(initID: UInt64) {
self.id = initID
}
}
}

Then, a resource interface is created to define what capabilities are made available to others.

pub resource interface NFTReceiver {
pub fun deposit(token: @NFT, metadata: {String : String})
pub fun getIDs(): [UInt64]
pub fun idExists(id: UInt64): Bool
pub fun getMetadata(id: UInt64) : {String : String}
}
  • getIDs
  • idExists
  • deposit
  • getMetadata
pub resource Collection: NFTReceiver {
pub var ownedNFTs: @{UInt64: NFT}
pub var metadataObjs: {UInt64: { String : String }}
init () {
self.ownedNFTs <- {}
self.metadataObjs = {}
}
pub fun withdraw(withdrawID: UInt64): @NFT {
let token <- self.ownedNFTs.remove(key: withdrawID)!
return <-token
}
pub fun deposit(token: @NFT, metadata: {String : String}) {
self.metadataObjs[token.id] = metadata
self.ownedNFTs[token.id] <-! token
}
pub fun idExists(id: UInt64): Bool {
return self.ownedNFTs[id] != nil
}
pub fun getIDs(): [UInt64] {
return self.ownedNFTs.keys
}
pub fun updateMetadata(id: UInt64, metadata: {String: String}) {
self.metadataObjs[id] = metadata
}
pub fun getMetadata(id: UInt64): {String : String} {
return self.metadataObjs[id]!
}
destroy() {
destroy self.ownedNFTs
}
}
pub fun createEmptyCollection(): @Collection {
return <- create Collection()
}
pub resource NFTMinter {
pub var idCount: UInt64
init() {
self.idCount = 1
}
pub fun mintNFT(): @NFT {
var newNFT <- create NFT(initID: self.idCount)
self.idCount = self.idCount + 1 as UInt64
return <-newNFT
}
}

We will create one more resource after that. We cannot mint tokens without it. The NFTMinter comprises an idCount that is increased every time to ensure we don’t have duplicate ids for NFTs. It also contains a function for creating NFTs.

Add the main contract initializer below the NFTMinter resource:

init() {
self.account.save(<-self.createEmptyCollection(),to: /storage/NFTCollection)
self.account.link<&{NFTReceiver}>(/public/NFTReceiver,target:/storage/NFTCollection)
self.account.save(<-create NFTMinter(), to: /storage/NFTMinter)
}

The initializer function is called only when deploying the contract. It performs three things:

  • Create an empty collection for the collection deployer so that the owner contract can create and own NFTs from the contract.
  • The NFTMinter resource is stored in account storage for the contract creator. It means only the contract creator can mint tokens.
  • The Collection resource is published in a public location with reference to the NFTReceiver interface created at the beginning. That is how we tell the contract that anyone can call functions defined on the NFTReceiver.

Once we have a contract ready to go, let’s deploy it. Before deploying it:

  1. Test it on the Flow Playground.
  2. Go to Flow Playground and click on the first account in the left sidebar.
  3. Replace all the code with the contract code and click Deploy.
Про NFT:  В Петербурге открывается крупнейшая NFT-выставка

If everything goes well, you should view a log at the bottom of the screen:

16:48:55 Deployment Deployed Contract To: 0x01

flow project start-emulator

With the emulator running and configured flow.json file, a contract can be deployed with the below command:

flow project Deploy

If everything goes well, you should view an output like this:

Deploying 1 contract for accounts: emulator-account
PinataPartyContract → 0xf8d6e0586b0a20c7

Now, we shall move to the minting of NFTs.

Minting NFTs

Create a new directory within the root of our pinata-party project and call them “transactions.” Once a folder is created, create a new file within it called as MintPinataParty.cdc.

We should have a file to reference in the metadata we offer to the NFT. A file is uploaded to IPFS via Pinata. In this tutorial, NFTs are focused on tradable videos of Pinata being smashed at parties. In this demo, we will upload a kid’s video hitting a pinata at a  birthday party. You can upload any media file you want and associate it with the NFT.

import PinataPartyContract from 0xf8d6e0586b0a20c7
transaction {
let receiverRef: &{PinataPartyContract.NFTReceiver}
let minterRef: &PinataPartyContract.NFTMinter
prepare(acct: AuthAccount) {
self.receiverRef=acct.getCapability<&{PinataPartyContract.NFTReceiver}>(/public/NFTReceiver)
.borrow()
?? panic(“Could not borrow receiver reference”)
self.minterRef = acct.borrow<&PinataPartyContract.NFTMinter>(from: /storage/NFTMinter)
?? panic(“could not borrow minter reference”)
}
execute {
let metadata : {String : String} = {
“name”: “The Big Swing”,
“swing_velocity”: “29”,
“swing_angle”: “45”,
“rating”: “5”,
“uri”: “ipfs://QmRZdc3mAMXpv6Akz9Ekp1y4vDSjazTx2dCQRkxVy1yUj6”
}
let newNFT <- self.minterRef.mintNFT()
self.receiverRef.deposit(token: <-newNFT, metadata: metadata)
log(“NFT Minted and deposited to Account 2’s Collection”)
}
}

Firstly, we have defined two reference variables, minterRef and receiverRef. In this scenario, we are both the receiver and minter of the NFT. These variables reference resources that are created in the contract. The transaction gets failed if the person executing it does not have access to the resource.

The above contract will mint and deposit NFTs. Now, we will send the transaction and mint the NFT. But before that, we need to prepare the account. Create a private key for signing from the command line within the project’s root folder.

Run the below command:

flow keys generate

It will provide you with public and private keys. Make sure to protect your private key.

You will need the private key for signing the transaction that needs to be pasted into our flow.json file. It is also essential to specify the signing algorithm and here is what your accounts object in the flow.json file should look like:

“accounts”: {
“emulator-account”: {
“address”: “YOUR ACCOUNT ADDRESS”,
“privateKey”: “YOUR PRIVATE KEY”,
“chain”: “flow-emulator”,
“sigAlgorithm”: “ECDSA_P256”,
“hashAlgorithm”: “SHA3_256”
}
}

If you want to store any of this project on a remote git repository or Github, you should not include the private key. You may need to .gitignore the entire flow.json. Though we are only using a local emulator, it is good to keep keys protected.

The last thing that we need to do is to verify that the token is in our account and fetch the metadata. To verify it, we need to write a simple script and call it from the command line.

import PinataPartyContract from 0xf8d6e0586b0a20c7
pub fun main() : {String : String} {
let nftOwner = getAccount(0xf8d6e0586b0a20c7) // log(“NFT Owner”)
let capability = nftOwner.getCapability<&{PinataPartyContract.NFTReceiver}>(/public/NFTReceiver)
let receiverRef = capability.borrow()
?? panic(“Could not borrow the receiver reference”)
return
receiverRef.getMetadata(id: 1)
}

We are importing the contract from the deployed address in this script. We define the main function and define three variables inside it:

  • nftOwner
    This account owns the NFT.
  • capability
    Capabilities are access-controlled. If a capability is not available to the address attempting to borrow it, the script gets failed. In this example, we borrow capabilities from the NFTReceiver resource.
  • receiverRef
    The variable takes our capability and states the script to borrow from the deployed contract.

We want to ensure the address in the question has received the NFT we minted and then we want to view the metadata associated with the token.

flow scripts execute ./scripts/CheckTokenMetadata.cdc

You will get an output like this:

{"name": "The Big Swing", "swing_velocity": "29", "swing_angle": "45", "rating": "5", "uri": "ipfs://QmRZdc3mAMXpv6Akz9Ekp1y4vDSjazTx2dCQRkxVy1yUj6 "}

We will then build a front-end React app that allows you to display the NFT by fetching the metadata.

Displaying NFT Collectibles

Setup React and Dependencies

Create React app within the parent directory pinata-party. Run the below command to create a React app:

npx create-react-app pinata-party-frontend 

When you are done with installing, you will see a new directory called pinata-party-frontend. Switch to that directory and install dependencies. For the first part of the frontend setup, run:

npm i @onflow/fcl @onflow/types

We will store some values as global variables for our app and use environment variables. In react, it means creating a .env file and setting key-value pairs where you need to prefix it with REACT_APP.

import {config} from “@onflow/fcl”
config()
.put(“access node.API”, process.env.REACT_APP_ACCESS_NODE)
.put(“challenge.handshake”, process.env.REACT_APP_WALLET_DISCOVERY)
.put(“0xProfile”, process.env.REACT_APP_CONTRACT_PROFILE)
import "./config"
import React, {useState, useEffect} from ‘react’
import * as fcl from “@onflow/fcl”
const AuthCluster = () => {
const [user, setUser] = useState({loggedIn: null})
useEffect(() => fcl.currentUser().subscribe(setUser), [])
if (user.loggedIn) {
return (

export default AuthCluster

import ‘./App.css’;
import AuthCluster from ‘./AuthCluster’;function App() {
return (

}export default App;

After adding the above code, you will see a page with a login sign-up button on starting the app. Now, it’s time to build the ability to fetch NFTs for an account and display them.

Fetching NFTs from Flow

import React, { useState } from “react”;
import * as fcl from “@onflow/fcl”;
const TokenData = () => {
const [nftInfo, setNftInfo] = useState(null)
const fetchTokenData = async () => {
const encoded = await fcl
.send([
fcl.script`
import PinataPartyContract from 0xf8d6e0586b0a20c7
pub fun main() : {String : String} {
let nftOwner = getAccount(0xf8d6e0586b0a20c7)
let capability = nftOwner.getCapability<&{PinataPartyContract.NFTReceiver}>(/public/NFTReceiver)
let receiverRef = capability.borrow()
?? panic(“Could not borrow the receiver reference”)
return receiverRef.getMetadata(id: 1)
}
`
])
const decoded = await fcl.decode(encoded)
setNftInfo(decoded)
};
return (

export default TokenData;

In this file, we are creating a component with a button to fetch token data. We have also created a button to clear token data. On clicking the fetch button, a function fetchTokenData is called. The function uses the Flow JS SDK to run the script we executed from the command line. Taking results of the execution and setting results to a state variable, nftInfo. If the variable exists, key-value pairs are rendered from the NFT metadata on screen and a button to clear the data.

Getting Media from IPFS

As we have already signed up on the Pinata account and added the video file to IPFS via the Pinata upload interface, you are navigated to the Pinata IPFS gateway where IPFS content is displayed when you click on a hash in the Pin Explorer.

In the TokenData.js file, add a way to display the video file retrieved from IPFS. Update the file to look like this:

import React, { useState } from “react”;
import * as fcl from “@onflow/fcl”;
const TokenData = () => {
const [nftInfo, setNftInfo] = useState(null)
const fetchTokenData = async () => {
const encoded = await fcl
.send([
fcl.script`
import PinataPartyContract from 0xf8d6e0586b0a20c7
pub fun main() : {String : String} {
let nftOwner = getAccount(0xf8d6e0586b0a20c7)
let capability = nftOwner.getCapability<&{PinataPartyContract.NFTReceiver}>(/public/NFTReceiver)
let receiverRef = capability.borrow()
?? panic(“Could not borrow the receiver reference”)
return receiverRef.getMetadata(id: 1)
}
`
])
const decoded = await fcl.decode(encoded)
setNftInfo(decoded)
};
return (

); }; export default TokenData;

Про NFT:  Nft в сети solana

We made it like this because the IPFS desktop client allows clicking on and opening links.

Now, we will enable the transfer of NFTs.

Transferring NFTs

First of all, we need to create contracts for setting up a marketplace. Contracts will be created for:

  • Payment mechanism for fungible tokens
  • Token supply settings
  • Token transfer capabilities

Let’s create a fungible token contract used for payments when purchasing NFTs.

We will create a fungible token contract by defining the empty contract:

pub contract PinnieToken {}

Token pub variables associated with token and provider resources need to be added to the contract.

pub var totalSupply: UFix64
pub var tokenName: String
pub resource interface Provider {
pub fun withdraw(amount: UFix64): @Vault {
post {
result.balance == UFix64(amount):
"Withdrawal amount must be the same as the balance of the withdrawn Vault."
}
}
}

Add the above contract within the empty contract.

The resource interface called Provider defines a public function, but the account owner can only call it. Then, we will define two more public resource interfaces:

pub resource interface Receiver {
pub fun deposit(from @Vault)
}
pub resource interface Balance {
pub var balance: UFix64
}

The above interfaces go directly below the Provider resource interface. The Receiver interface involves a function that anyone can execute. It ensures that deposits into an account can be performed as long as the recipient initializes a vault to handle tokens created via the contract. The Balance resource returns a balance of the new token for any provided account.

pub resource Vault: Provider, Receiver, Balance {
pub var balance: UFix64
init(balance: UFix64) {
self.balance = balance
}
pub fun withdraw(amount: UFix64): @Vault {
self.balance = self.balance – amount
return <-create Vault(balance: amount)
}
pub fun deposit(from: @Vault) {
self.balance = self.balance + from.balance
destroy from
}
}

Add the below function under the vault interface:

pub fun createEmptyVault(): @Vault {
return <-create Vault(balance: 0.0)
}

As the name implies, the function creates an empty Vault resource for an account. The balance is 0.

pub resource VaultMinter {
pub fun mintTokens(amount: UFix64, recipient: Capability<&AnyResource{Receiver}>)
{
let recipientRef = recipient.borrow()
?? panic(“Could not borrow a receiver reference to the vault”)
PinnieToken.totalSupply = PinnieToken.totalSupply + UFix64(amount)
recipientRef.deposit(from: <-create Vault(balance: amount))
}
}

The VaultMinter resource is public, but it is only available to the contract account owner.

The VaultMinter resource only includes one function: mintTokens that needs an amount to mint and a recipient. The newly minted tokens can be deposited into that account as long as the recipient will have the Vault resource stored.

The totalSupply variable needs to be updated when tokens are minted. Therefore, the minted amount is added to the previous supply for getting the new supply.

Now, we need to initialize the contract and add the below code after VaultMinter resource:

init() {
self.totalSupply = 30.0
self.tokenName = “Pinnie”
let vault <- create Vault(balance: self.totalSupply)
self.account.save(<-vault, to: /storage/MainVault)
self.account.save(<-create VaultMinter(), to: /storage/MainMinter)
self.account.link<&VaultMinter>(/private/Minter, target: /storage/MainMinter)
}

It is essential to set a total supply when initializing the contract. In this example, we have initialized the contract with a supply of 30 and set the token name as “Pinnie.”

Deploying and Minting Tokens

Update the flow.json file in the project to deploy the new contract. Ensure that the flow.json file references the new contract and has the emulator-account key reference:

{
“emulators”: {
“default”: {
“port”: 3569,
“serviceAccount”: “emulator-account”
}
},
“contracts”: {
“PinataPartyContract”: “./cadence/contracts/PinataPartyContract.cdc”,
“PinnieToken”: “./cadence/contracts/PinnieToken.cdc”
},
“networks”: {
“emulator”: {
“host”: “127.0.0.1:3569”,
“chain”: “flow-emulator”
}
},
“accounts”: {
“emulator-account”: {
“address”: “f8d6e0586b0a20c7”,
“keys”: “e5ca2b0946358223f0555206144fe4d74e65cbd58b0933c5232ce195b9058cdd”
}
},
“deployments”: {
“emulator”: {
“emulator-account”: [“PinataPartyContract”, “PinnieToken”]
}
}
}

In another terminal window within your pinata-party project directory, run flow project deploy. Now, let’s test the minting function. We will create a transaction that allows us to create Pinnie tokens. But first, we need to update the flow.json file.

Change json under the emulator-account:

“emulator-account”: {
“address”: “f8d6e0586b0a20c7”,
“privateKey”: “e5ca2b0946358223f0555206144fe4d74e65cbd58b0933c5232ce195b9058cdd”,
"sigAlgorithm": "ECDSA_P256",
"hashAlgorithm": "SHA3_256",
"chain": "flow-emulator"
}

The key field becomes the privateKey field and we add properties, including sigAlgorithm, chain and hashAlgorithm.

Developing an NFT marketplace

Before working on the marketplace’s front end, we should have a contract to handle the marketplace creation and management.

In cadence/contracts folder, create a new file called MarketplaceContract.cdc.

import PinataPartyContract from 0xf8d6e0586b0a20c7
import PinnieToken from 0xf8d6e0586b0a20c7
pub contract MarketplaceContract {
pub event ForSale(id: UInt64, price: UFix64)
pub event PriceChanged(id: UInt64, newPrice: UFix64)
pub event TokenPurchased(id: UInt64, price: UFix64)
pub event SaleWithdrawn(id: UInt64)
pub resource interface SalePublic {
pub fun purchase(tokenID: UInt64, recipient: &AnyResource{PinataPartyContract.NFTReceiver}, buyTokens: @PinnieToken.Vault)
pub fun idPrice(tokenID: UInt64): UFix64?
pub fun getIDs(): [UInt64]
}
}

We need to import both the NFT contract and the fungible token contract. We have defined four events inside the contract definition:

  • ForSale: NFTs for sale
  • PriceChanged: Change in the price for NFTs
  • TokenPurchased: When NFTs are purchased
  • SaleWithdrawn: When NFTs are removed from the marketplace

We have added a resource interface called SalePublic below event emitters. The interface should be public to everyone, not only the contract owner.

We need to add a SaleCollection resource below the SalePublic interface. We have defined a few variables within this resource. For example, mapping of tokens for sale, mapping prices for each token for sale and a protected variable that is only accessible by the contract owner called ownerVault.

We need to initialize variables when defining them on a resource. It is done in the init function and is initialized with the owner’s vault resource and empty values.

Then, it is important to define functions to control the actions of an NFT Marketplace. Functions are:

  • listForSale
  • changePrice
  • withdraw
  • idPrice
  • purchase
  • destroy
  • getIDs

As mentioned above, three of these functions are available publicly, it implies that listForSale, withdraw, destroy and changePrice are only available to the NFT owners being listed. For example, changePrice is not available publicly because we don’t want anyone to change the price of NFTs. The last part of the marketplace contract is the CreateSaleCollection function.

flow project Deploy

It will finally deploy the marketplace contract and allow us to use it within the frontend application.

Once it is done, we need to work on the frontend and connect these contracts using the Flow CLI tool.

If you are looking to build a custom NFT marketplace, consult our NFT development experts who will help you from consulting to the marketplace platform’s development and launch. 

Smart Contracts and Account State on Flow

Developers use the Flow Playground to write and deploy smart contracts. The Flow Developer Playground comprises an in-browser editor and an emulator for developers to experiment with on Flow. Before setting up your NFT marketplace on Flow, the Flow Playground comes with several features that make it easier for developers to create and execute smart contracts along with familiarizing them with Cadence on the Playground. It is important for developers to first get accustomed to the Flow Playground to understand the deployment of Cadence smart contracts without errors.

Оцените статью
NFT Эксперт