Flow blockchain ticket NFT development practice [including source code]

Brain in new VAT 2021-11-24 15:17:21 阅读数:944

flow blockchain ticket nft development

since 2017 in ERC-721 After standardization , General Certificate of heterogeneity (NFT) It has developed from the experimental platform of virtual pet trading to large-scale adoption by mainstream industries . In this tutorial , We use tickets as a kind of NFT assets , utilize FLow Block chaining Cadence Smart contract to solve the main pain points of the ticketing market , For example, anti-counterfeiting 、 Intermediary fee 、 Problems such as confusion in the secondary market .

 Insert picture description here

Blockchain development tutorial link : The etheric fang | The currency | EOS | Tendermint | Hyperledger Fabric | Omni/USDT | Ripple | Tron

NBA Top Shot Have been told 80 Million users sold more than 3 $ NFT, Sotheby just 1700 A digital artwork for $million . When you buy one NBA Top Shot Collection time , You don't have the only business power , You can't even enjoy its power . Actually, that one 1700 Million dollars of art , You can watch it for free .

But let's explore NFT Value brought : The assets have the ownership verifiable by cryptography algorithm and the ability to sell or transfer given by contract .

Many types of assets can benefit from cryptographically verifiable ownership : school report 、 certificate 、 Intellectual property, etc . Imagine using blockchain instead of USPTO… You can skip the lawyer and submit your application directly , First come, first serve .

It was a friend's suggestion that I consider taking tickets as a kind of NFT assets , It makes sense . What is the biggest problem in the ticket market ? Here are some :

  • Anti-counterfeiting
  • A lot of transaction fees . We all know that when you see 50 A $ticket costs 72.50 Dollars to cover ticket sales The cost of intermediary when feeling
  • Unregulated secondary market

If we use smart contracts to manage assets , These problems will disappear . determine NFT The authenticity of is a piece of cake , transaction
The handling fee can also be greatly reduced through the adoption of blockchain .

To me, , The most exciting thing is that ticket issuers can set secondary market terms . You can make your assets non transferable , Make sure you can only sell below the list price , Even help performers cut costs in any secondary sales .

In this decentralized system , Everyone can get a more fair and transparent experience . Okay , Let's start the development of this system .

1、 tickets NFT Blockchain platform selection : The etheric fang vs. Flow

The first decision we need to make , Is to choose which blockchain platform to use .

We can use Ethereum , But the transaction fee is a little high , Although in the future ETH 2.0 After the upgrade, the handling fee may be significantly reduced .

Flow It is a developer friendly new blockchain ecosystem , The handling charge is minimal , Sounds like a good choice .

actually Dapper Lab Of NBA Top Shot Is the use of Flow Intelligent contract , It's not much different from the contract we're going to deploy next .

At a higher level , Here is a basic but usable ticket Mart we need to construct , We didn't achieve a complete buy / Selling function , But this may be the subject of the next tutorial .

  1. In our Flow The non transferable terms of the ticket defined in the smart contract
  2. Create virtual accounts so that publishers and participants can access NFT
  3. Use transactions to safely demonstrate common functions , Such as casting and ticket transfer
  4. Use React.js Implement a simple front end web Interface

2、Flow Blockchain development environment settings

I use Flow The tutorial in the document to familiarize yourself with its smart contract programming language Cadence And its standard NFT Templates . If you intend to follow this learning path , You need to install Flow CLI.

Of course we can be in Flow Main network or test network deployment contract , But we're talking about using FLow Simulator for rapid local development . Start the emulator with the following command :

flow emulator start

3、Flow Blockchain tickets NFT Smart contract development

Our non homogenous ticket smart contract needs to be defined NFT Characteristics and casting 、 Storage 、 Transfer function . Some of these functions need to be publicly available , For example, storing or obtaining metadata , Other functions, such as extraction and casting , You need certain permissions to execute .

I also want to confirm that our tickets are non transferable , Therefore, we need to set the necessary inspection conditions to prohibit multiple deposits . Let's take a look at our Cadence Intelligent contract .

// NonFungibleTicket.cdc
// contract to manage unique tradeable tickets (based on Flow NFT standard)
// see: https://docs.onflow.org/cadence/tutorial/04-non-fungible-tokens/
pub contract NonFungibleTicket {
// set up a couple events for key deposits/withdrawals
pub event Withdraw(id: UInt64, from: Address?)
pub event Deposit(id: UInt64, to: Address?)
// our NFT (Non-Fungible-Ticket) is simply defined by an id. metadata coming later
pub resource NFT {
pub let id: UInt64
// we want to make our ticket non-transferrable, so let's keep track of how many times it has changed hands
pub var numTransfers : UInt64
init(initID: UInt64) {
self.id = initID
self.numTransfers = 0
// we will need a function to iterate the number of transfers each time
pub fun transfer() {
self.numTransfers = self.numTransfers + 1 as UInt64
// receiver interface allows others to interact w certain functions via public access
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}
// obviously, we don't allow public access to withdraw/minting functions
// defining a Collection resource for all our tickets
pub resource Collection: NFTReceiver {
pub var ownedNFTs: @{UInt64: NFT}
pub var metadataObjs: {UInt64: { String : String }}
init () {
self.ownedNFTs <- {}
self.metadataObjs = {}
// withdraw forced to be non-nil. function throws error if NFT with withdrawID doesn't exist
pub fun withdraw(withdrawID: UInt64): @NFT {
let token <- self.ownedNFTs.remove(key: withdrawID)!
emit Withdraw(id: token.id, from: self.owner?.address)
return <- token
// the deposit function is a bit more complex. first of all, this is where the metadata comes in:
pub fun deposit(token: @NFT, metadata: {String : String}) {
// our token can be transferred no more than once (from admin to attendee)
if token.numTransfers > (1 as UInt64) {
panic("Ticket is non-transferrable!")
self.metadataObjs[token.id] = metadata
emit Deposit(id: token.id, to: self.owner?.address)
// log the transfer (increases numTransfers by 1)
self.ownedNFTs[token.id] <-! token
// rest of these are pretty straightforward
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
// will need to create an empty collection for any account that wants our NFT
pub fun createEmptyCollection(): @Collection {
return <- create Collection()
// can explicitly share NFTMinter resource with another admin so that they can mint tickets
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
// launching the contract does 3 things:
init() {
// 1) save a fresh collection to the admin's storage
self.account.save(<-self.createEmptyCollection(), to: /storage/NFTCollection)
// 2) allow public access to NFTReceiver functions through this reference
self.account.link<&{NFTReceiver}>(/public/NFTReceiver, target: /storage/NFTCollection)
// 3) save NFTMinter resource to private storage
self.account.save(<-create NFTMinter(), to: /storage/NFTMinter)

About Cadence,Flow The official documents are clearer than I introduced , But on a higher level ,Cadence Use Resources( resources ) and Capabilities( Ability ) To define who (Who) What can I visit (What) function .

for example , Let's talk about NFTCollection and NFTMinter Resources are stored in the deployment account /storage/ route , This means that these resources are private . But we are /public/ Publish a path pointing to NFTReceiver Links to capabilities . Another thing to note , our NFT Just simply use its integer ID Definition , And use a numTransfers Counter to record NFT Number of deposits .

In this example , If someone tries to transfer our tickets again , The deal will fail . Deposit the contract under the name cadence/contracts/ The catalog of .

Before we deploy the contract , We need to create flow.json Document to specify who (Who) Where is the (Where) What to deploy (What). Initialize this file by executing the following command in the project directory :

flow init

This will give us a startup account and the corresponding private key . We'll look at... Later flow.json file , But first we need to create an account for the participants . Run the following code to generate the key pair :

flow keys generate

Save the key pair generated by the above command , And then run :

flow accounts create ATTENDEE_PUB_KEY

take ATTENDEE_PUB_KEY Replace with the public key you just generated .

recorded 0x The address at the beginning . Now we have flow.json All the information needed .

"emulators": {
"default": {
"port": 3569,
"serviceAccount": "emulator-account"
"contracts": {
"NonFungibleTicket": "./cadence/contracts/NonFungibleTicket.cdc"
"networks": {
"emulator": "",
"mainnet": "access.mainnet.nodes.onflow.org:9000",
"testnet": "access.devnet.nodes.onflow.org:9000"
"accounts": {
"emulator-account": {
"address": "f8d6e0586b0a20c7",
"keys": "e61fd9cbcf7d7d0918c5d02f79c9be08717ca82b5e7bd8c151e009eeb384bb78"
"attendee-account": {
"address": "01cf0e2f2f715450",
"deployments": {
"emulator": {
"emulator-account": ["NonFungibleTicket"]

Be careful : Never share your private key .

You will see us in NonFungibleTicket A pointer is added to the contract (Pointer), Our new participant account and emulator account ( Identify our ticket issuer ) Contract deployment . Now we can deploy the contract with the following command :

flow project deploy

If all goes well , You will see the following output :

Deploying 1 contracts for accounts: emulator-account
NonFungibleTicket -> 0xf8d6e0586b0a20c7
All contracts deployed successfully

4、 Casting Flow Blockchain tickets NFT

Now it's time to create our first NFT 了 . We will use Cadence, But we will use transactions instead of defining a contract . Trading is the way we use the functions defined in the smart contract , Transaction execution will lead to changes in blockchain status .

import NonFungibleTicket from 0xf8d6e0586b0a20c7
// This transaction allows the Minter account to mint an NFT
// and deposit it into its collection.
transaction {
// The reference to the collection that will be receiving the NFT
let receiverRef: &{NonFungibleTicket.NFTReceiver}
// The reference to the Minter resource stored in account storage
let minterRef: &NonFungibleTicket.NFTMinter
prepare(acct: AuthAccount) {
// Get the owner's collection capability and borrow a reference
self.receiverRef = acct.getCapability<&{NonFungibleTicket.NFTReceiver}>(/public/NFTReceiver)
?? panic("Could not borrow receiver reference")
// Borrow a capability for the NFTMinter in storage
self.minterRef = acct.borrow<&NonFungibleTicket.NFTMinter>(from: /storage/NFTMinter)
?? panic("Could not borrow minter reference")
execute {
// Use the minter reference to mint an NFT, which deposits
// the NFT into the collection that is sent as a parameter.
let newNFT <- self.minterRef.mintNFT()
let metadata : {String : String} = {
"event": "FLOW LIVE in Concert!",
"section": "200",
"row": "3",
"seat": "1",
"uri": "https://flow-ticket-exchange.s3.amazonaws.com/ticket.png"
self.receiverRef.deposit(token: <-newNFT, metadata: metadata)
log("Ticket minted and deposited into admin account")

To me, , The interesting part is NFT Metadata . I created a ticket with several properties for demonstration , For example, area and row , And a pointer to the ticket image URI link .

This caused me to think , I don't know if it's lightweight NFT Users understand how it works .

The blockchain is tracking NFT And its associated metadata . However , A more common implementation of digital assets is to use external storage to store the actual content of these assets .

As S3 bucket Users of the service , Nothing can prevent me from deleting or updating these files !

Imagine , You spend 3 Ten thousand dollars for Steph Curry Of 3 Divide the ball , However Dapper Lab Quietly replace it with Alex Caruso My free throw ! Hope like IIPFS Such a decentralized storage solution can solve this kind of problem .

Our ticket issuing account deployment contract , Therefore, the account is saved in its private storage NFTMinter resources . This account must be used to sign the following transactions :

flow transactions ./cadence/transactions/MintTicket.cdc send --signer emulator-account

If we try to sign with a participant account , The deal will fail . Next, let's use a Cadence Script to check the balance of our ticket issuing account .

import NonFungibleTicket from 0xf8d6e0586b0a20c7
pub fun main() : [UInt64] {
let acct1 = getAccount(0xf8d6e0586b0a20c7)
let capability1 = acct1.getCapability<&{NonFungibleTicket.NFTReceiver}>(/public/NFTReceiver)
let receiverRef1 = capability1.borrow()
?? panic("Could not borrow the receiver reference")
return receiverRef1.getIDs()

Run the script with the following command :

flow scripts execute ./cadence/scripts/CheckTicketBalance.cdc

Then you will see an inclusion that holds NFT Of ID Array of :

Result: [1]

This means that the issuing account currently holds our newly cast NFT!

5、 Use Cadence Script transfer tickets NFT

Now we will transfer the tickets to a eagerly waiting music fan . First, we will create a... In the participant's storage NFTCollection resources .

This gives us a chance to understand FLow A useful aspect of Architecture .

In Ethereum , If you send ether to an invalid wallet address , These etheric coins are gone . However, in FLow in , Resources cannot be sent without a clear destination address , Or roll back the entire transaction . We won't lose tickets because we mistakenly send them to an invalid address .

import NonFungibleTicket from 0xf8d6e0586b0a20c7
// This transaction configures a user's account
// to use the NFT contract by creating a new empty collection,
// storing it in their account storage, and publishing a capability
transaction {
prepare(acct: AuthAccount) {
// Create a new empty collection
let collection <- NonFungibleTicket.createEmptyCollection()
// store the empty NFT Collection in account storage
acct.save<@NonFungibleTicket.Collection>(<-collection, to: /storage/NFTCollection)
log("Collection created for account 2")
// create a public capability for the Collection
acct.link<&{NonFungibleTicket.NFTReceiver}>(/public/NFTReceiver, target: /storage/NFTCollection)
log("Capability created")

Use the above transaction to run the following command :

flow transactions send .\cadence\transactions\SetupEmptyCollection.cdc --signer attendee-account

Now our participants are ready to receive tickets . We will use Cadence Trade to complete this operation , In this transaction, issue an account and take out its NFT Then put it into the participant's collection storage .

Don't forget that every time you deposit , Contracts will increase stored in NFT Medium numTransfers The value of the parameter . After this deal ,numTransfers = 1.
The following is the content of the contract :

import NonFungibleTicket from 0xf8d6e0586b0a20c7
// This transaction transfers an NFT from one user's collection
// to another user's collection.
transaction {
// The field that will hold the NFT as it is being
// transferred to the other account
let transferToken: @NonFungibleTicket.NFT
let metadata: { String : String }
prepare(acct: AuthAccount) {
// Borrow a reference from the stored collection
let collectionRef = acct.borrow<&NonFungibleTicket.Collection>(from: /storage/NFTCollection)
?? panic("Could not borrow a reference to the owner's collection")
self.metadata = collectionRef.getMetadata(id: 1)
// Call the withdraw function on the sender's Collection
// to move the NFT out of the collection
self.transferToken <- collectionRef.withdraw(withdrawID: 1)
execute {
// Get the recipient's public account object
let recipient = getAccount(0x01cf0e2f2f715450)
// Get the Collection reference for the receiver
// getting the public capability and borrowing a reference from it
let receiverRef = recipient.getCapability<&{NonFungibleTicket.NFTReceiver}>(/public/NFTReceiver)
?? panic("Could not borrow receiver reference")
// Deposit the NFT in the receivers collection
receiverRef.deposit(token: <-self.transferToken, metadata: self.metadata)
log("NFT ID 1 transferred from account 2 to account 1")

Use the following command to transfer tickets :

flow transactions send ./cadence/transactions/TransferTicket.cdc --signer emulator-account

You can run with two accounts CheckTicketBalance Script , To validate the getIDs() Returns an empty array when using the distribution account , When using the participant account, it returns [1]! Next, let's see what happens if we try to transfer tickets back to the issuing account .

 Transaction Error
execution error code 100: Execution failed:
error: panic: Ticket is non-transferrable!
--> f8d6e0586b0a20c7.NonFungibleTicket:59:16
59 | panic("Ticket is non-transferrable!")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Our smart contract correctly prevents this from happening . Our tickets can't be sold again in the secondary market !

6、 tickets NFT Applied React The front-end implementation

We won't go into the details of the front-end application , It mainly uses FLow JS Library access to our Cadence contract . In this simple example program , We read NFT Metadata , But you can do anything in the same way Cadence Code .

import React, { useState, useEffect } from "react";
import * as fcl from "@onflow/fcl";
import { Address } from "@onflow/types";
import * as t from "@onflow/types"
const TokenData = () => {
const [user, setUser] = useState({loggedIn: null})
useEffect(() => fcl.currentUser().subscribe(setUser), [])
const [nftInfo, setNftInfo] = useState(null)
const fetchTokenData = async () => {
const encoded = await fcl
import NonFungibleTicket from 0xf8d6e0586b0a20c7
pub fun main() : {String : String} {
let nftOwner = getAccount(0xf8d6e0586b0a20c7)
let capability = nftOwner.getCapability<&{NonFungibleTicket.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)
return (
<div className="listing">
<div className="center">
<button className="btn-primary" onClick={fetchTokenData}>Fetch Token Data</button>
nftInfo &&
<div className="center">
<p>Event: {nftInfo["event"]}</p>
<p>Section: {nftInfo["section"]}</p>
<p>Row: {nftInfo["row"]}</p>
<p>Seat: {nftInfo["seat"]}</p>
<div className="center image">
<img src={nftInfo["uri"]} alt="My NFT!" width="90%"/>
<button onClick={() => setNftInfo(null)} className="btn-secondary">Clear Token Info</button>
const OwnerData = (account) => {
const [ownerInfo, setOwnerInfo] = useState(null)
const fetchOwnerData = async () => {
const encoded = await fcl
fcl.arg(account, t.Address)
import NonFungibleTicket from 0xf8d6e0586b0a20c7
pub fun main() : [UInt64] {
let acct1 = getAccount(account)
let capability1 = acct1.getCapability<&{NonFungibleTicket.NFTReceiver}>(/public/NFTReceiver)
let receiverRef1 = capability1.borrow()
?? panic("Could not borrow the receiver reference")
return receiverRef1.getIDs()
const decoded = await fcl.decode(encoded)
return (
<p>Account: {account}</p>
<p>Owned NFT's: {ownerInfo}</p>
export default TokenData;

Start our front-end application with the following command :

npm run start

Here is our simple but powerful decentralized ticket viewing page :
 Insert picture description here

The complete code can be obtained from here download .

Link to the original text :Flow Blockchain tickets NFT Development practice and source code — Huizhi. Com

版权声明:本文为[Brain in new VAT]所创,转载请带上原文链接,感谢。 https://netfreeman.com/2021/11/20211108231833886a.html