NFT Smart Contract erstellen und bereitstellen

In diesem Abschnitt erfahren Sie, wie Sie einen Smart Contract für NFT erstellen und bereitstellen, der zum Einrichten des NFT Marketplace erforderlich ist.

Mit Blockchain App Builder können Sie einen Smart Contract zum Verwalten von Minzen, Eigentümern und Transfer von NFTs erstellen. Der Kernfaktor dieser Lösung ist die Möglichkeit, NFTs mit Oracle Blockchain Platform zu mintieren und zu übertragen.

Zuerst erstellen Sie eine NFT-Spezifikationsdatei und stellen dann den Smart Contract in einer Oracle Blockchain Platform-Instanz bereit. Anschließend können Sie den Smart Contract testen.

Blockchain App Builder installieren

Nachdem Sie eine Oracle Blockchain Platform-Instanz bereitgestellt haben, führen Sie die folgenden Schritte aus:

  1. Öffnen Sie in der Oracle Blockchain Platform-Konsole die Registerkarte Entwicklertools, und wählen Sie dann den Bereich Blockchain App Builder aus.
  2. Laden Sie im Abschnitt Herunterladen das Befehlszeilenschnittstellenarchiv (CLI) oder die Visual Studio-(VS-)Codeerweiterung herunter, und richten Sie es dann lokal ein.

Anpassen der NFT-Beispielspezifikationsdatei

Eine NFT-Beispielspezifikationsdatei ist in Blockchain App Builder enthalten. Sie können es verwenden und an Ihre Bedürfnisse anpassen, wie im folgenden Beispiel dargestellt:


 assets:
    - name: ArtCollection
      type: token
      symbol: ART      #mandatory
      standard: erc721+   
      anatomy:
        type: nonfungible
        unit: whole
      behavior:
        - indivisible      # mandatory
        - singleton        # mandatory
        - mintable:        # mandatory
            max_min_quantity: 20000
        - transferable
        - burnable
        - roles:
            minter_role_name: minter
      properties:
        - name: price
          type: number
        - name: on_sale_flag
          type: boolean
      metadata:
        - name: painting_name
          type: string
        - name: description
          type: string
        - name: image
          type: string
        - name: painter_name
          type: string
 customMethods:
    - executeQuery
    - "createAccountByConsumers(org_id: string, user_id: string, token_type: string)" # Create accounts for consumers while signing up
    - "sell(token_id: string, selling_price: number)" # Post the token for selling in the marketplace
    - "buyWithTokens(from_org_id: string, from_user_id: string, to_org_id: string, to_user_id: string, nonfungible_token_id: string, fungible_token_id: string, amount_paid: number)"  # Buy the NFT after paying the using FT Tokens 
    - "buyWithDirectPayment(from_org_id: string, from_user_id: string, to_org_id: string, to_user_id: string, nonfungible_token_id: string, amount_paid: number)"  # Buy the NFT after paying the amount using payment gateway

Sie können benutzerdefinierte Eigenschaften und Methoden hinzufügen, um diese Spezifikation für NFT-Chaincode zu erweitern. Von Blockchain App Builder generierte NFT-Chaincodes basieren auf dem Standard ERC-721.

Führen Sie die folgenden Schritte aus, um den Chaincode (Smart Contract) mit der Visual Studio Code-Erweiterung zu generieren:

  1. Klicken Sie im Abschnitt Chaincodes auf das Symbol +. Der Bereich Chaincode-Details wird geöffnet.
  2. Füllen Sie die Felder aus, die zum Generieren des Chaincode-Projekts erforderlich sind:
    • Geben Sie einen Namen für das Chaincode-Projekt ein.
    • Wählen Sie TypeScript oder Go als Sprache aus, in der die Chaincode-Methoden generiert werden sollen.
    • Wählen Sie die Eingabespezifikationsdatei aus, die Sie zuvor erstellt haben.
    • Geben Sie den Standort ein, an dem das Projekt generiert werden soll.
  3. Klicken Sie auf Erstellen.

Im folgenden Screenshot der Benutzeroberfläche wird das Fenster Chaincode erstellen angezeigt.

Beschreibung von Blockchain_chaincode_details.png folgt
Beschreibung der Abbildung Blockchain_chaincode_details.png
Nachdem der Chaincode generiert wurde, können Sie die Modell- und Controllerimplementierung prüfen, indem Sie die Dateien im Verzeichnis src in der Projekthierarchie prüfen.
  • Die Modelldatei enthält alle generierten Datenstrukturen, die das Token, Accounts usw. darstellen.
  • Die Controllerdatei enthält alle generierten NFT-Lebenszyklusmethoden und unterstützenden Funktionen mit erforderlicher Validierungslogik basierend auf der Spezifikation.
Die Controllerdatei verfügt auch über Funktionsvorlagen für benutzerdefinierte Methoden, mit denen Sie Ihre Geschäftslogik basierend auf den generierten SDK-Funktionen hinzufügen können.

/**
*      
* BDB sql rich queries can be executed in OBP CS/EE.
* This method can be invoked only when connected to remote OBP CS/EE network.
*    
*/
@Validator(yup.string())
    public async executeQuery(query: string) {
        const result = await this.query(query);
        return result;
    }
@Validator(yup.string(), yup.string(), yup.string())
          public async createAccountByConsumers(org_id: string, user_id: string, token_type: string) {       
          //await this.Ctx.ERC721Auth.checkAuthorization('ERC721ACCOUNT.createAccount', 'TOKEN');
          return await this.Ctx.ERC721Account.createAccount(org_id, user_id, token_type);   
    }
@Validator(yup.string(), yup.number())
public async sell (token_id: string, selling_price: number) {       
          try {  
            const token = await this.Ctx.ERC721Token.get(token_id);
            const t = new ArtCollection(token)
            t.price =  selling_price;
            t.on_sale_flag = true;
            //console.log(token);           
            await this.Ctx.ERC721Token.update(t);
            return `Token ID : '${token_id}' has been posted for selling in the marketplace'`;           
          } catch(error) {
                throw new Error(error.message);
        }
}
@Validator(yup.string(), yup.string(), yup.string(), yup.string(), yup.string(), yup.string(), yup.number())
public async buyWithTokens(from_org_id: string, from_user_id: string, to_org_id: string, to_user_id: string, nonfungible_token_id: string, fungible_token_id: string, amount_paid: number) {
        try {  
            const token = await this.Ctx.ERC721Token.get(nonfungible_token_id);
            const t = new ArtCollection(token);
            const oChainUtil = new OChainUtils(this.Ctx.Stub);
            var msg = `Token ID : '${nonfungible_token_id}' had not been transferred'`;
            if (t.on_sale_flag==true) {
                if(t.price == amount_paid) {                   
                     // @ts-ignore
                    await oChainUtil.invokeChaincode("LoyaltyToken7", "transferTokens", [fungible_token_id, from_org_id, from_user_id, amount_paid], "marketplace");
                    const from_account_id = await this.Ctx.ERC721Account.generateAccountId(from_org_id, from_user_id);                   
                    const to_account_id = await this.Ctx.ERC721Account.generateAccountId(to_org_id, to_user_id);         
                    await this.Ctx.ERC721Token.transferFrom(from_account_id, to_account_id, t);
     
                    msg = `Token ID : '${nonfungible_token_id}' has been successfully transferred to UserID : '${to_user_id}'`;           
              }           
            }
            else {
                msg = `Token ID : '${nonfungible_token_id}' has not been transferred to UserID : '${to_user_id}' as the amount was not fully paid'`;
            }
            return msg;
       } catch(error)
          {
            throw new Error(error.message);
         }
}
@Validator(yup.string(), yup.string(), yup.string(), yup.string(), yup.string(), yup.number())
    public async buyWithDirectPayment(from_org_id: string, from_user_id: string, to_org_id: string, to_user_id: string, nonfungible_token_id: string, amount_paid: number) {
         try {  
             const token = await this.Ctx.ERC721Token.get(nonfungible_token_id);
             const t = new ArtCollection(token);
             var msg = `Token ID : '${nonfungible_token_id}' had not been transferred'`;           
           if (t.on_sale_flag==true) {
                 if(t.price == amount_paid) {                   
                 const from_account_id = await this.Ctx.ERC721Account.generateAccountId(from_org_id, from_user_id);         
                 const to_account_id = await this.Ctx.ERC721Account.generateAccountId(to_org_id, to_user_id);                   
                 await this.Ctx.ERC721Token.transferFrom(from_account_id, to_account_id, t);
                   
                 msg = `Token ID : '${nonfungible_token_id}' has been successfully transferred to UserID : '${to_user_id}'`;
                 }
             }
             else {
                 msg = `Token ID : '${nonfungible_token_id}' has not been transferred to UserID : '${to_user_id}' as the amount was not fully paid'`;
             }
             return msg;
         } catch(error) {         
             throw new Error(error.message);
         }
      }
}

Smart Contract bereitstellen

Nachdem Sie ein Chaincode-Projekt erstellt haben, können Sie es lokal bereitstellen.

Wählen Sie im Bereich Chaincode-Details die Option Bereitstellen, um den Deployment-Assistenten zu öffnen. Blockchain App Builder umfasst ein lokales Blockchain-Netzwerk, das in den Docker-Containern ausgeführt wird, das Sie zu Testzwecken verwenden können.

Sie können den Chaincode auch in einer Oracle Blockchain Platform-Instanz bereitstellen, indem Sie das Verbindungsprofil aus der Liste für die Zielumgebung auswählen. Sie müssen auch die Init-Parameter abschließen und speichern, da der generierte NFT-Chaincode die Parameter orgId und userId zur Initialisierung erfordert. Mit den Parametern orgId und userId wird angegeben, welche Benutzer über Tokenadministratorberechtigungen verfügen.

Smart Contract testen

Beim Deployment des Chaincodes stellt Oracle Blockchain Platform automatisch die REST-APIs für Tokeninitialisierung, Account- und Rollenverwaltung und NFT-Lebenszyklusmethoden (Erstellen, Transfer, Brennen) bereit.

Sie können den Test durchführen, indem Sie im Bereich Chaincode-Details in Blockchain App Builder die Option Ausführen auswählen oder einen REST-API-Client wie Postman verwenden.

Der folgende Screenshot der Benutzeroberfläche zeigt die Registerkarte Ausführen des Fensters Kettencode erstellen.

Beschreibung von Blockchain_chaincode_execute.png folgt
Beschreibung der Abbildung Blockchain_chaincode_execute.png

Um Oracle Blockchain Platform-Smart Contract-Methoden mit REST-API aufzurufen, verwenden Sie die Methode POST, und geben Sie die URL an, die aus zwei Teilen besteht, die zusammen verkettet sind. Der erste Teil ist der REST-Proxyendpunkt in Oracle Blockchain Platform, den Sie über die Registerkarte Knoten der Oracle Blockchain Platform-Konsole abrufen können.

Der zweite Teil ist die spezifische URI, mit der die Transaktion mit der Transaction-API aufgerufen wird. Informationen zum Senden einer POST-Anforderung finden Sie in der Dokumentation. Die beiden Teile bilden eine vollständige URL ähnlich der hier.

https://oabcs1-iad.blockchain.ocp.oraclecloud.com:7443/restproxy/api/v2/channels/{channelName}/transactions

Ersetzen Sie {channelName} durch den Namen des Kanals, den Sie beim Deployment Ihres Chaincodes angegeben haben, wie marketplace. Führen Sie beim Erstellen der API-Anforderung die folgenden Schritte aus:

  • Legen Sie die Autorisierung so fest, dass Basic Auth mit der angegebenen userid and password verwendet wird, die der Rolle REST_Client zugeordnet ist. Sie können auch OAuth2-Token verwenden. Weitere Informationen finden Sie unter Zugriffstokenbasierte Authentifizierung für OAuth 2.0 verwenden in der REST-API-Dokumentation.
  • Setzen Sie den Content-Type-Header auf application/json.
  • Nehmen Sie im Body der Anforderung die für den Transaktionsaufruf erforderlichen Parameter auf, einschließlich des Chaincode-Namens und der Methode create<TokenName>Token sowie die erforderlichen Argumente.

Basierend auf dem aus der Vorlage yaml generierten Chaincode zeigt der folgende Text einen Musteranforderungsbody und die zugehörige Antwort an.

Anforderung

{
    "chaincode": "{{NFTChaincode}}",
    "args": [
        "createArtCollectionToken",
        "{\"token_id\":\"{{NFTTokenID}}\",\"token_uri\":\"https://ipfs.io/ipfs/QmV68aiT7xw2WX8pmDbeTWpGP2or35NUFan9RagymsLpgV?filename=ArtCollection_NFT1.json\",\"metadata\":{\"painting_name\":\"Oracle - Red Bull Partnership\",\"image\":\"https://ipfs.io/ipfs/QmVap6Gkh3Cp9DiLLWvkvJHpuXpFmYB2GzU1caM57gNcAa?filename=Oracle_RedBull_NFT1.jpeg\",\"painter\":\"Alex\"},\"price\":200,\"on_sale_flag\":false}"
    ],
    "timeout": 0,
    "sync": true
}

Antwort

{
    "returnCode": "Success",
    "error": "",
    "result": {
        "txid": "c999922f04c3011bf25ca43624e4bb23e8900634f8e23a1648170a90274a9733",
        "payload": {
            "metadata": {
                "painter": "Alex",
                "painting_name": "Oracle - Red Bull Partnership",
                "image": "https://ipfs.io/ipfs/QmVap6Gkh3Cp9DiLLWvkvJHpuXpFmYB2GzU1caM57gNcAa?filename=Oracle_RedBull_NFT1.jpeg"
            },
            "assetType": "otoken",
            "created_by": "oaccount~eadf1b0ae857164f8681d1742b6328089a7d33ebec76d8248cb909da7a84f42a",
            "creation_date": "2022-04-28T12:08:38.000Z",
            "owner": "oaccount~eadf1b0ae857164f8681d1742b6328089a7d33ebec76d8248cb909da7a84f42a",
            "uri": "https://ipfs.io/ipfs/QmV68aiT7xw2WX8pmDbeTWpGP2or35NUFan9RagymsLpgV?filename=ArtCollection_NFT1.json",
            "is_burned": false,
            "token_id": "NFT17",
            "token_name": "artcollection",
            "symbol": "ART",
            "token_standard": "erc721+",
            "token_type": "nonfungible",
            "token_unit": "whole",
            "behaviors": [
                "indivisible",
                "singleton",
                "mintable",
                "transferable",
                "burnable",
                "roles"
            ],
            "roles": {
                "minter_role_name": "minter"
            },
            "mintable": {
                "max_mint_quantity": 20000
            },
            "token_uri": "https://ipfs.io/ipfs/QmV68aiT7xw2WX8pmDbeTWpGP2or35NUFan9RagymsLpgV?filename=ArtCollection_NFT1.json",
            "price": 200,
            "on_sale_flag": false
        },

Weitere Informationen zu den Methoden zur Verwaltung von NFT-Chaincodes finden Sie im Abschnitt Weitere Informationen anzeigen, einschließlich der Methoden Golang oder TypeScript und Platform REST API.

Sie können die APIs direkt aus dem Oracle Content Management-Webhook und der auf Visual Builder Cloud Service (VBCS) erstellten Webanwendung aufrufen oder sie erneut mit dem API-Gateway zur Verwendung durch eine extern gehostete Marketplace-Webanwendung mappen und umschließen. Beachten Sie, dass Sie beim Erstellen (Mint) eines NFT einen der Parameter token_uri angeben müssen. Dabei kann es sich um eine IPFS URI handeln, die auf eine JSON-Datei verweist, die das digitale Objekt darstellt.

https://ipfs.io/ipfs/QmV68aiT7xw2WX8pmDbeTWpGP2or35NUFan9RagymsLpgV?filename=ArtCollection_NFT1.json

In den folgenden Schritten wird ein Beispiel zum Generieren der Token-URI mit IPFS-Desktop beschrieben:

  1. Laden Sie eine Bilddatei auf IPFS hoch, und speichern Sie die URI des Images.
  2. Erstellen und laden Sie die Datei JSON hoch, die die Image-URI zusammen mit relevanten Metadatenfeldern enthält.
  3. Teilen und kopieren Sie den Link in die Datei JSON unter ... Liste "Mehr".

{ 
    "painting_name": "Oracle - Red Bull Partnership",
    "description": "Cloud Partnership",
    "image": "https://ipfs.io/ipfs/QmVap6Gkh3Cp9DiLLWvkvJHpuXpFmYB2GzU1caM57gNcAa?filename=Oracle_RedBull.jpeg",
    "painter_name": "Alex"
}

Verwenden Sie die URI, die auf die Datei JSON für den Parameter token_uri verweist.

Sie können auch relevante Metadaten in die Attribute aufnehmen, die an die Methode create<Token-Name>Token übergeben werden. Dadurch werden die Metadaten im Oracle Blockchain Platform-Ledger für einen einfachen Abruf verwaltet.

Verwenden Sie für NFTs, die mit Oracle Content Management (OCM) erstellt wurden, den OCM-Webhook, um Oracle Functions mit einem API-Gateway aufzurufen und den REST-API-Aufruf wie im Architekturdiagramm dargestellt in Oracle Functions zu platzieren. Sie können Blockchain-REST-APIs auch direkt von der Marketplace-Webanwendung aus oder über eine API-Gatewayzuordnung aufrufen, um vom Benutzer generierte Inhalte zu unterstützen. Die Funktion des Marketplace-Handels kann die benutzerdefinierten Methoden zur Verarbeitung der Zahlung aufrufen und dann eine Übertragung des NFT-Eigentums auslösen, wie die Beispielmethoden buyWithTokens und buyWithDirectPayment.