In diesem Tutorial lernen wir, wie man eine Website zum Sammeln digitaler Sammlerstücke (oder NFTs) auf der Blockchain Flow erstellt. Um dies zu ermöglichen, verwenden wir die intelligente Vertragssprache Cadence zusammen mit React. Außerdem erfahren wir mehr über Flow, seine Vorteile und die unterhaltsamen Tools, die wir verwenden können.
Am Ende dieses Artikels verfügen Sie über die Tools und Kenntnisse, die Sie zum Erstellen Ihrer eigenen dezentralen Anwendung auf der Flow-Blockchain benötigen.
Lasst uns gleich eintauchen!
Wir entwickeln eine Anwendung für digitale Sammlerstücke. Jedes Sammlerstück ist ein Non-Fungible Token (NFT).
Damit das alles funktioniert, verwenden wir den NonFungibleToken-Standard von Flow, einen Regelsatz, der uns bei der Verwaltung dieser besonderen digitalen Gegenstände hilft (ähnlich ERC-721 in Ethereum).
Bevor Sie beginnen, stellen Sie sicher, dass Sie die Flow CLI auf Ihrem System installieren. Wenn Sie dies noch nicht getan haben, befolgen Sie diese Installationsanweisungen .
Wenn Sie bereit sind, Ihr Projekt zu starten, geben Sie zunächst das Befehlsfluss-Setup ein.
Dieser Befehl wirkt hinter den Kulissen zauberhaft, um die Grundlage für Ihr Projekt zu schaffen. Es erstellt ein Ordnersystem und richtet eine Datei namens flow.json ein, um Ihr Projekt zu konfigurieren und sicherzustellen, dass alles organisiert und einsatzbereit ist!
Das Projekt enthält einen cadence
Ordner und flow.json
Datei. (Eine flow.json-Datei ist eine Konfigurationsdatei für Ihr Projekt, die automatisch verwaltet wird.)
Der Cadence-Ordner enthält Folgendes:
Befolgen Sie die folgenden Schritte, um Flow NFT Standard zu verwenden.
Gehen Sie zunächst zum Ordner flow-collectibles-portal
und suchen Sie den Ordner cadence
. Öffnen Sie dann den contracts
. Erstellen Sie eine neue Datei und nennen Sie sie NonFungibleToken.cdc
.
Öffnen Sie nun den Link NonFungibleToken , der den NFT-Standard enthält. Kopieren Sie den gesamten Inhalt aus dieser Datei und fügen Sie ihn in die neue Datei ein, die Sie gerade erstellt haben („NonFungibleToken.cdc“).
Das ist es! Sie haben die Standards für Ihr Projekt erfolgreich eingerichtet.
Jetzt schreiben wir etwas Code!
Bevor wir uns jedoch mit dem Codieren befassen, ist es für Entwickler wichtig, ein mentales Modell für die Strukturierung ihres Codes zu entwickeln.
Auf der obersten Ebene besteht unsere Codebasis aus drei Hauptkomponenten:
NFT: Jedes Sammlerstück wird als NFT dargestellt.
Sammlung: Eine Sammlung bezieht sich auf eine Gruppe von NFTs, die einem bestimmten Benutzer gehören.
Globale Funktionen und Variablen: Dies sind Funktionen und Variablen, die auf globaler Ebene für den Smart Contract definiert werden und keiner bestimmten Ressource zugeordnet sind.
Erstellen Sie eine neue Datei mit dem Namen Collectibles.cdc
in cadence/contracts
. Hier werden wir den Code schreiben.
Vertragsstruktur
import NonFungibleToken from "./NonFungibleToken.cdc" pub contract Collectibles: NonFungibleToken{ pub var totalSupply: UInt64 // other code will come here init(){ self.totalSupply = 0 } }
Lassen Sie uns den Code Zeile für Zeile aufschlüsseln:
Zuerst müssen wir standardisieren, dass wir einen NFT erstellen, indem wir das sogenannte „NonFungibleToken“ einbeziehen. Dabei handelt es sich um einen von Flow entwickelten NFT-Standard, der die folgenden Funktionen definiert, die in jedem NFT-Smart-Vertrag enthalten sein müssen.
Nach dem Import erstellen wir unseren Vertrag. Dazu verwenden wir pub contract [contract name]
. Verwenden Sie jedes Mal dieselbe Syntax, wenn Sie einen neuen Vertrag erstellen. Sie können den contract name
mit dem von Ihnen gewünschten Namen für Ihren Vertrag angeben. In unserem Fall nennen wir es Collectibles
.
Als Nächstes möchten wir sicherstellen, dass unser Vertrag bestimmte Funktionen und Regeln von NonFungibleToken einhält. Dazu fügen wir mit Hilfe von „:“ eine NonFungibleToken-Schnittstelle hinzu.
So ( `pub contract Collectibles: NonFungibleToken{}`
)
Jeder einzelne Vertrag MUSS über die Funktion init()
verfügen. Es wird aufgerufen, wenn der Vertrag zum ersten Mal bereitgestellt wird. Dies ähnelt dem, was Solidity als Konstruktor bezeichnet.
Erstellen wir nun eine globale Variable namens totalSupply
mit einem Datentyp UInt64
. Diese Variable verfolgt Ihre gesamten Sammlerstücke.
Initialisieren Sie nun totalSupply
mit dem Wert 0
.
Das ist es! Wir legen den Grundstein für unseren Collectibles
. Jetzt können wir damit beginnen, weitere Features und Funktionalitäten hinzuzufügen, um es noch spannender zu machen.
Bevor Sie fortfahren, schauen Sie sich bitte das Code-Snippet an, um zu verstehen, wie wir Variablen in Cadence definieren:
Fügen Sie Ihrem Smart-Vertrag den folgenden Code hinzu:
import NonFungibleToken from "./NonFungibleToken.cdc" pub contract Collectibles: NonFungibleToken{ // above code… pub resource NFT: NonFungibleToken.INFT{ pub let id: UInt64 pub var name: String pub var image: String init(_id:UInt64, _name:String, _image:String){ self.id = _id self.name = _name self.image = _image } } // init()... }
Wie Sie bereits gesehen haben, implementiert der Vertrag die NFT-Standardschnittstelle, dargestellt durch pub contract Collectibles: NonFungibleToken
. Ebenso können Ressourcen auch verschiedene Ressourcenschnittstellen implementieren.
Fügen wir also der NFT-Ressource die Schnittstelle NonFungibleToken.INFT
hinzu, die die Existenz einer öffentlichen Eigenschaft namens id innerhalb der Ressource vorschreibt.
Hier sind die Variablen, die wir in der NFT-Ressource verwenden werden:
id:
Behält die ID von NFT beiname:
Name des NFT.image:
Bild-URL von NFT.
Stellen Sie nach dem Definieren der Variablen sicher, dass Sie die Variable in der Funktion init()
initialisieren.
Machen wir weiter und erstellen eine weitere Ressource namens Collection Resource
.
Zunächst müssen Sie verstehen, wie Collection Resources
funktionieren.
Was würden Sie tun, wenn Sie eine Musikdatei und mehrere Fotos auf Ihrem Laptop speichern müssten?
Normalerweise navigieren Sie zu einem lokalen Laufwerk (z. B. Ihrem D-Drive) und erstellen einen music
und photos
. Anschließend kopieren Sie die Musik- und Fotodateien und fügen sie in Ihre Zielordner ein.
Genauso funktionieren auch Ihre digitalen Sammlerstücke auf Flow.
Stellen Sie sich Ihren Laptop als Flow Blockchain Account
, Ihr D-Laufwerk als Account Storage
und den Ordner als Collection
vor.
Wenn Sie also mit einem Projekt zum Kauf von NFTs interagieren, erstellt das Projekt seine collection
in Ihrem account storage
, ähnlich wie beim Erstellen eines Ordners auf Ihrem D-Drive. Wenn Sie mit 10 verschiedenen NFT-Projekten interagieren, erhalten Sie 10 verschiedene Sammlungen in Ihrem Konto.
Es ist, als hätten Sie einen persönlichen Raum zum Aufbewahren und Organisieren Ihrer einzigartigen digitalen Schätze!
import NonFungibleToken from "./NonFungibleToken.cdc" pub contract Collectibles: NonFungibleToken{ //Above code NFT Resource… // Collection Resource pub resource Collection{ } // Below code… }
Jede collection
verfügt über eine ownedNFTs
Variable zum Speichern der NFT Resources
.
pub resource Collection { pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} init(){ self.ownedNFTs <- {} } }
Ressourcenschnittstellen
Eine resource
in Flow ähnelt Schnittstellen in anderen Programmiersprachen. Es sitzt über einer Ressource und stellt sicher, dass die Ressource, die es implementiert, über die erforderliche Funktionalität verfügt, wie durch die Schnittstelle definiert.
Es kann auch verwendet werden, um den Zugriff auf die gesamte Ressource einzuschränken und hinsichtlich der Zugriffsmodifikatoren restriktiver zu sein als die Ressource selbst.
Im NonFungibleToken
Standard gibt es mehrere Ressourcenschnittstellen wie INFT
, Provider
, Receiver
und CollectionPublic
.
Jede dieser Schnittstellen verfügt über spezifische Funktionen und Felder, die von der Ressource, die sie verwendet, implementiert werden müssen.
In diesem Vertrag verwenden wir diese drei Schnittstellen von NonFungibleToken: Provider
, Receiver
und CollectionPublic
. Diese Schnittstellen definieren Funktionen wie deposit
, withdraw
, borrowNFT
und getIDs
. Wir werden diese im weiteren Verlauf im Detail erklären.
Wir werden auch einige Ereignisse hinzufügen, die wir von diesen Funktionen ausgeben, und einige Variablen deklarieren, die wir im weiteren Verlauf des Tutorials verwenden werden.
pub contract Collectibles:NonFungibleToken{ // rest of the code… pub event ContractInitialized() pub event Withdraw(id: UInt64, from: Address?) pub event Deposit(id: UInt64, to: Address?) pub let CollectionStoragePath: StoragePath pub let CollectionPublicPath: PublicPath pub resource interface CollectionPublic{ pub fun deposit(token: @NonFungibleToken.NFT) pub fun getIDs(): [UInt64] pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT } pub resource Collection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic{ pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} init(){ self.ownedNFTs <- {} } } }
Zurückziehen
Erstellen wir nun die für die Schnittstelle erforderliche Funktion withdraw()
.
pub resource Collection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic{ // other code pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") emit Withdraw(id: token.id, from: self.owner?.address) return <- token } init()... }
Mit Hilfe dieser Funktion können Sie die NFT-Ressource aus der Sammlung verschieben. Wenn es:
Der Anrufer kann diese Ressource dann nutzen und in seinem Kontospeicher speichern.
Kaution
Jetzt ist es Zeit für die von NonFungibleToken.Receiver
benötigte Funktion deposit()
.
pub resource Collection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic{ // other code pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") emit Withdraw(id: token.id, from: self.owner?.address) return <- token } pub fun deposit(token: @NonFungibleToken.NFT) { let id = token.id let oldToken <- self.ownedNFTs[id] <-token destroy oldToken emit Deposit(id: id, to: self.owner?.address) } init()... }
Ausleihen und GetID
Konzentrieren wir uns nun auf die beiden von NonFungibleToken.CollectionPublic: borrowNFT()
und getID()
.
pub resource Collection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic{ // other code pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") emit Withdraw(id: token.id, from: self.owner?.address) return <- token } pub fun deposit(token: @NonFungibleToken.NFT) { let id = token.id let oldToken <- self.ownedNFTs[id] <-token destroy oldToken emit Deposit(id: id, to: self.owner?.address) } pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { if self.ownedNFTs[id] != nil { return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! } panic("NFT not found in collection.") } pub fun getIDs(): [UInt64]{ return self.ownedNFTs.keys } init()... }
Zerstörer
Das Letzte, was wir für die Sammlungsressource benötigen, ist ein Destruktor.
destroy (){ destroy self.ownedNFTs }
Da die Collection-Ressource andere Ressourcen (NFT-Ressourcen) enthält, müssen wir einen Destruktor angeben. Ein Destruktor wird ausgeführt, wenn das Objekt zerstört wird. Dadurch wird sichergestellt, dass Ressourcen nicht „obdachlos“ bleiben, wenn ihre übergeordnete Ressource zerstört wird. Wir benötigen keinen Destruktor für die NFT-Ressource, da diese keine anderen Ressourcen enthält.
Schauen wir uns den vollständigen Quellcode der Sammlungsressource an:
import NonFungibleToken from "./NonFungibleToken.cdc" pub contract Collectibles: NonFungibleToken{ pub var totalSupply: UInt64 pub resource NFT: NonFungibleToken.INFT{ pub let id: UInt64 pub var name: String pub var image: String init(_id:UInt64, _name:String, _image:String){ self.id = _id self.name = _name self.image = _image } } pub resource interface CollectionPublic{ pub fun deposit(token: @NonFungibleToken.NFT) pub fun getIDs(): [UInt64] pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT } pub event ContractInitialized() pub event Withdraw(id: UInt64, from: Address?) pub event Deposit(id: UInt64, to: Address?) pub let CollectionStoragePath: StoragePath pub let CollectionPublicPath: PublicPath pub resource Collection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic{ pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} init(){ self.ownedNFTs <- {} } destroy (){ destroy self.ownedNFTs } pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") emit Withdraw(id: token.id, from: self.owner?.address) return <- token } pub fun deposit(token: @NonFungibleToken.NFT) { let id = token.id let oldToken <- self.ownedNFTs[id] <-token destroy oldToken emit Deposit(id: id, to: self.owner?.address) } pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { if self.ownedNFTs[id] != nil { return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! } panic("NFT not found in collection.") } pub fun getIDs(): [UInt64]{ return self.ownedNFTs.keys } } init(){ self.CollectionPublicPath = /public/NFTCollection self.CollectionStoragePath = /storage/NFTCollection self.totalSupply = 0 emit ContractInitialized() } }
Jetzt haben wir alle Ressourcen aufgebraucht. Als nächstes schauen wir uns die globale Funktion an.
Globale Funktionen sind Funktionen, die auf der globalen Ebene des Smart Contracts definiert sind, d. h. sie sind nicht Teil einer Ressource. Diese sind für die Öffentlichkeit zugänglich und abrufbar und stellen der Öffentlichkeit die Kernfunktionalität des Smart Contracts zur Verfügung.
createEmptyCollection : Diese Funktion initialisiert eine leere Collectibles.Collection
im Anruferkontospeicher.
checkCollection : Mit dieser praktischen Funktion können Sie herausfinden, ob Ihr Konto bereits über eine collection
verfügt.
mintNFT : Diese Funktion ist super cool, weil sie es jedem ermöglicht, ein NFT zu erstellen.
// pub resource Collection… pub fun createEmptyCollection(): @Collection{ return <- create Collection() } pub fun checkCollection(_addr: Address): Bool{ return getAccount(_addr) .capabilities.get<&{Collectibles.CollectionPublic}> (Collectibles.CollectionPublicPath)! .check() } pub fun mintNFT(name:String, image:String): @NFT{ Collectibles.totalSupply = Collectibles.totalSupply + 1 let nftId = Collectibles.totalSupply var newNFT <- create NFT(_id:nftId, _name:name, _image:image) return <- newNFT } init()...
Und jetzt, ENDLICH, da alles vorbereitet ist, sind wir mit dem Schreiben unseres Smart Contracts fertig. Schauen Sie sich hier den endgültigen Code an.
Schauen wir uns nun an, wie ein Benutzer mit intelligenten Verträgen interagiert, die auf der Flow-Blockchain bereitgestellt werden.
Die Interaktion mit der Flow-Blockchain erfolgt in zwei Schritten:
Transaktionen sind kryptografisch signierte Daten, die eine Reihe von Anweisungen enthalten, die mit dem Smart Contract interagieren, um den Flow-Status zu aktualisieren. Vereinfacht ausgedrückt ist dies wie ein Funktionsaufruf, der die Daten auf der Blockchain ändert. Transaktionen sind in der Regel mit gewissen Kosten verbunden, die je nach Blockchain, auf der Sie sich befinden, variieren können.
Eine Transaktion umfasst mehrere optionale Phasen: prepare
, pre
, execute
und post
.
Weitere Informationen hierzu finden Sie im Cadence-Referenzdokument zu Transaktionen . Jede Phase hat einen Zweck; Die beiden wichtigsten Phasen sind prepare
und execute
.
Prepare Phase
: Diese Phase wird verwendet, um auf Daten und Informationen im Konto des Unterzeichners zuzugreifen (durch den AuthAccount-Typ zulässig).
Execute Phase
: In dieser Phase werden Aktionen ausgeführt.
Lassen Sie uns nun eine Transaktion für unser Projekt erstellen.
Führen Sie die folgenden Schritte aus, um eine Transaktion in Ihrem Projektordner zu erstellen.
Gehen Sie zunächst in den Projektordner und öffnen Sie den cadence
Ordner. Öffnen Sie darin den transaction
und erstellen Sie eine neue Datei mit den Namen Create_Collection.cdc
und mint_nft.cdc
import Collectibles from "../contracts/Collectibles.cdc" transaction { prepare(signer: AuthAccount) { if signer.borrow<&Collectibles.Collection>(from: Collectibles.CollectionStoragePath) == nil { let collection <- Collectibles.createEmptyCollection() signer.save(<-collection, to: Collectibles.CollectionStoragePath) let cap = signer.capabilities.storage.issue<&{Collectibles.CollectionPublic}>(Collectibles.CollectionStoragePath) signer.capabilities.publish( cap, at: Collectibles.CollectionPublicPath) } } }
Lassen Sie uns diesen Code Zeile für Zeile aufschlüsseln:
Diese Transaktion interagiert mit dem Smart-Vertrag Collectibles. Anschließend prüft es, ob der Absender (Unterzeichner) eine Collection-Ressource in seinem Konto gespeichert hat, indem es einen Verweis auf die Collection-Ressource aus dem angegebenen Speicherpfad Collectibles.CollectionStoragePath
entlehnt. Wenn die Referenz Null ist, bedeutet dies, dass der Unterzeichner noch keine Sammlung hat.
Wenn der Unterzeichner keine Sammlung hat, erstellt er eine leere Sammlung, indem er die Funktion createEmptyCollection()
aufruft.
Nachdem Sie die leere Sammlung erstellt haben, platzieren Sie sie im Konto des Unterzeichners unter dem angegebenen Speicherpfad Collectibles.CollectionStoragePath
.
Dadurch wird mithilfe von link()
eine Verknüpfung zwischen dem Konto des Unterzeichners und der neu erstellten Sammlung hergestellt.
import NonFungibleToken from "../contracts/NonFungibleToken.cdc" import Collectibles from "../contracts/Collectibles.cdc" transaction(name:String, image:String){ let receiverCollectionRef: &{NonFungibleToken.CollectionPublic} prepare(signer:AuthAccount){ self.receiverCollectionRef = signer.borrow<&Collectibles.Collection>(from: Collectibles.CollectionStoragePath) ?? panic("could not borrow Collection reference") } execute{ let nft <- Collectibles.mintNFT(name:name, image:image) self.receiverCollectionRef.deposit(token: <-nft) } }
Lassen Sie uns diesen Code Zeile für Zeile aufschlüsseln:
Wir importieren zunächst den NonFungibleToken
und Collectibles contract
.
transaction(name: String, image: String)
Diese Zeile definiert eine neue Transaktion. Es benötigt zwei Argumente, name und image, beide vom Typ String. Diese Argumente werden verwendet, um den Namen und das Bild des zu prägenden NFT zu übergeben.
let receiverCollectionRef: &{NonFungibleToken.CollectionPublic}
Diese Zeile deklariert eine neue Variable receiverCollectionRef.
Es handelt sich um einen Verweis auf eine öffentliche Sammlung von NFTs vom Typ NonFungibleToken.CollectionPublic
. Diese Referenz wird verwendet, um mit der Sammlung zu interagieren, in der wir den neu geprägten NFT hinterlegen.
prepare(signer: AuthAccount)
Diese Zeile startet den Prepare-Block, der vor der Transaktion ausgeführt wird. Es benötigt einen Argumentunterzeichner vom Typ AuthAccount
. AuthAccount
stellt das Konto des Unterzeichners der Transaktion dar.
Es entlehnt einen Verweis auf die Collectibles.Collection
aus dem Speicher des Unterzeichners im Prepare-Block. Mithilfe der Funktion „borgen“ greift es auf den Verweis auf die Sammlung zu und speichert ihn in der Variablen receiverCollectionRef
.
Wenn die Referenz nicht gefunden wird (z. B. wenn die Sammlung nicht im Speicher des Unterzeichners vorhanden ist), wird die Fehlermeldung „Sammlungsreferenz konnte nicht ausgeliehen werden“ ausgegeben.
Der execute
enthält die Hauptausführungslogik für die Transaktion. Der Code in diesem Block wird ausgeführt, nachdem der prepare
erfolgreich abgeschlossen wurde.
nft <- Collectibles.mintNFT(_name: name, image: image)
Innerhalb des execute
ruft diese Zeile die mintNFT
Funktion aus dem Collectibles
Vertrag mit den bereitgestellten Namens- und Bildargumenten auf. Von dieser Funktion wird erwartet, dass sie ein neues NFT mit dem angegebenen Namen und Bild erstellt. Das <-
-Symbol zeigt an, dass der NFT als verschiebbares Objekt (Ressource) empfangen wird.
self.receiverCollectionRef.deposit(token: <-nft)
Diese Zeile hinterlegt den neu geprägten NFT in der angegebenen Sammlung. Es verwendet die Einzahlungsfunktion auf der receiverCollectionRef
, um das Eigentum an der NFT vom ausführenden Konto der Transaktion auf die Sammlung zu übertragen. Das <-
-Symbol weist hier auch darauf hin, dass der NFT während des deposit
als Ressource verschoben wird.
Wir verwenden ein Skript, um Daten aus der Blockchain anzuzeigen oder zu lesen. Skripte sind kostenlos und müssen nicht signiert werden.
Führen Sie die folgenden Schritte aus, um ein Skript in Ihrem Projektordner zu erstellen.
Gehen Sie zunächst in den Projektordner und öffnen Sie den cadence
Ordner. Öffnen Sie darin den script
und erstellen Sie eine neue Datei mit dem Namen view_nft.cdc
.
import NonFungibleToken from "../contracts/NonFungibleToken.cdc" import Collectibles from "../contracts/Collectibles.cdc" pub fun main(user: Address, id: UInt64): &NonFungibleToken.NFT? { let collectionCap= getAccount(user).capabilities .get<&{Collectibles.CollectionPublic}>(/public/NFTCollection) ?? panic("This public capability does not exist.") let collectionRef = collectionCap.borrow()! return collectionRef.borrowNFT(id: id) }
Lassen Sie uns diesen Code Zeile für Zeile aufschlüsseln:
Zuerst importieren wir den NonFungibleToken
und Collectibles
-Vertrag.
pub fun main(acctAddress: Address, id: UInt64): &NonFungibleToken.NFT?
Diese Zeile definiert den Einstiegspunkt des Skripts, bei dem es sich um eine öffentliche Funktion namens main handelt. Die Funktion benötigt zwei Parameter:
acctAddress
: Ein Parameter vom Typ Address
, der die Adresse eines Kontos in der Flow-Blockchain darstellt.
id
: Ein Parameter vom Typ UInt64
, der die eindeutige Kennung des NFT innerhalb der Sammlung darstellt.
Dann verwenden wir getCapability
, um die Collectibles.Collection
Funktion für die angegebene acctAddress
abzurufen. Eine Fähigkeit ist ein Verweis auf eine Ressource, die den Zugriff auf ihre Funktionen und Daten ermöglicht. In diesem Fall wird die Funktion für den Ressourcentyp Collectibles.Collection
abgerufen.
Anschließend leihen wir mithilfe der Funktion borrowNFT
ein NFT aus der collectionRef
aus. Die Funktion borrowNFT
verwendet den Parameter id
, der die eindeutige Kennung des NFT innerhalb der Sammlung darstellt. Die borrow
Funktion einer Fähigkeit ermöglicht das Lesen der Ressourcendaten.
Schließlich geben wir die NFT von der Funktion zurück.
Jetzt ist es an der Zeit, unseren Smart Contract im Flow-Testnetz bereitzustellen.
1. Richten Sie ein Flow-Konto ein.
Führen Sie den folgenden Befehl im Terminal aus, um ein Flow-Konto zu generieren:
flow keys generate
Notieren Sie sich unbedingt Ihren öffentlichen und privaten Schlüssel.
Als nächstes machen wir uns auf den Weg zu
Fügen Sie Ihren öffentlichen Schlüssel in das angegebene Eingabefeld ein.
Behalten Sie die Standardeinstellungen für die Signatur- und Hash-Algorithmen bei.
Füllen Sie das Captcha aus.
Klicken Sie auf Konto erstellen.
Nach dem Einrichten eines Kontos erhalten wir einen Dialog mit unserer neuen Flow-Adresse, der 1.000 Test-Flow-Token enthält. Kopieren Sie die Adresse, damit wir sie künftig verwenden können .
2. Konfigurieren Sie das Projekt.
Jetzt konfigurieren wir unser Projekt. Als wir das Projekt einrichteten, wurde zunächst eine flow.json
Datei erstellt.
Dies ist die Konfigurationsdatei für die Flow CLI und definiert die Konfiguration für Aktionen, die die Flow CLI für Sie ausführen kann. Stellen Sie sich dies als ungefähr gleichbedeutend mit hardhat.config.js
auf Ethereum vor.
Öffnen Sie nun Ihren Code-Editor, kopieren Sie den folgenden Code und fügen Sie ihn in Ihre flow.json
Datei ein.
{ "contracts": { "Collectibles": "./cadence/contracts/Collectibles.cdc", "NonFungibleToken": { "source": "./cadence/contracts/NonFungibleToken.cdc", "aliases": { "testnet": "0x631e88ae7f1d7c20" } } }, "networks": { "testnet": "access.devnet.nodes.onflow.org:9000" }, "accounts": { "testnet-account": { "address": "ENTER YOUR ADDRESS FROM FAUCET HERE", "key": "ENTER YOUR GENERATED PRIVATE KEY HERE" } }, "deployments": { "testnet": { "testnet-account": [ "Collectibles" ] } } }
Fügen Sie Ihren generierten privaten Schlüssel an der Stelle (Schlüssel: „GEBEN SIE IHREN GENERIERTEN PRIVATEN SCHLÜSSEL HIER EIN“) im Code ein.
Führen Sie nun den Code im Testnetz aus. Gehen Sie zum Terminal und führen Sie den folgenden Code aus:
flow project deploy --network testnet
5. Warten Sie auf die Bestätigung.
Nach dem Absenden der Transaktion erhalten Sie eine Transaktions-ID. Warten Sie, bis die Transaktion im Testnetz bestätigt wird, was anzeigt, dass der Smart Contract erfolgreich bereitgestellt wurde.
Überprüfen Sie hier Ihren bereitgestellten Vertrag.
Überprüfen Sie den vollständigen Code auf GitHub .
Glückwunsch! Sie haben jetzt ein Sammlerportal auf der Flow-Blockchain erstellt und es im Testnetz bereitgestellt. Was kommt als nächstes? Jetzt können Sie an der Erstellung des Frontends arbeiten, das wir in Teil 2 dieser Serie behandeln werden.
Ich wünsche Ihnen einen wirklich tollen Tag!
Auch hier veröffentlicht