Crea e distribuisci contratto smart NFT

In questa sezione imparerai come creare e distribuire un contratto smart NFT necessario per configurare il Marketplace NFT.

Utilizzare Blockchain App Builder per generare uno smart contract per gestire la mentazione, la proprietà e il trasferimento di NFT. L'enabler di base di questa soluzione è la possibilità di creare e trasferire NFT utilizzando Oracle Blockchain Platform.

In primo luogo, creare un file di specifica NFT, quindi distribuire lo smart contract a un'istanza di Oracle Blockchain Platform. È quindi possibile testare lo smart contract.

Installa App Builder Blockchain

Dopo aver eseguito il provisioning di un'istanza di Oracle Blockchain Platform, attenersi alla procedura riportata di seguito.

  1. Nella console di Oracle Blockchain Platform aprire la scheda Strumenti per sviluppatori e selezionare il riquadro Builder delle applicazioni blockchain.
  2. Nella sezione Download scaricare l'archivio degli strumenti dell'interfaccia a riga di comando (CLI) o l'estensione del codice Visual Studio (VS) e impostarla localmente.

Personalizzare il file di specifica NFT di esempio

Un file di specifica NFT di esempio è incluso in Blockchain App Builder. È possibile utilizzarlo e adattarlo alle proprie esigenze, come mostrato nell'esempio riportato di seguito.


 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

È possibile aggiungere proprietà e metodi personalizzati per estendere questa specifica per il codice concatenato NFT. I codici concatenati NFT generati da Blockchain App Builder si basano sullo standard ERC-721.

Per generare il codice concatenato (contratto intelligente) utilizzando l'estensione Codice di Visual Studio, attenersi alla procedura riportata di seguito.

  1. Nella sezione Chaincodes, fare clic sull'icona +. Viene visualizzato il riquadro Dettagli codice fiscale.
  2. Completare i campi necessari per generare il progetto con codice concatenato.
    • Immettere un nome per il progetto codice concatenato.
    • Selezionare TypeScript o Go come lingua in cui generare i metodi del codice concatenato.
    • Selezionare il file della specifica di input creato in precedenza.
    • Inserire l'ubicazione in cui si desidera generare il progetto.
  3. Fare clic su Crea.

L'immagine seguente dell'interfaccia utente mostra la finestra Crea codice concatenato.

Segue la descrizione di blockchain_chaincode_details.png
Descrizione dell'immagine blockchain_chaincode_details.png
Dopo la generazione del codice concatenato, è possibile rivedere l'implementazione del modello e del controller ispezionando i file nella directory src nella gerarchia di progetti.
  • Il file modello contiene tutte le strutture dati generate che rappresentano il token, i conti e così via.
  • Il file controller contiene tutti i metodi del ciclo di vita NFT generati e le funzioni di supporto con la logica di convalida richiesta in base alla specifica.
Il file controller dispone anche di modelli di funzione per metodi personalizzati, in cui è possibile aggiungere la propria business logic in base alle funzioni SDK generate.

/**
*      
* 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);
         }
      }
}

Distribuire il contratto smart

Dopo aver creato un progetto con codice concatenato, puoi distribuirlo localmente.

Nel riquadro Dettagli codice fiscale selezionare Distribuisci per aprire la distribuzione guidata. Blockchain App Builder include una rete di blockchain locale, che viene eseguita nei container Docker, che è possibile utilizzare per finalità di test.

È anche possibile distribuire il codice concatenato in un'istanza di Oracle Blockchain Platform selezionando il profilo di connessione dalla lista per l'ambiente di destinazione. È inoltre necessario completare e salvare i parametri di inizializzazione, poiché il codice concatenato NFT generato richiede i parametri orgId e userId per l'inizializzazione. I parametri orgId e userId vengono utilizzati per specificare gli utenti con privilegi di amministratore token.

Test del contratto smart

Quando il codice concatenato viene distribuito, Oracle Blockchain Platform espone automaticamente le API REST per l'inizializzazione dei token, la gestione di account e ruoli e i metodi del ciclo di vita NFT (creazione, trasferimento, masterizzazione).

È possibile eseguire il test selezionando Esegui nel riquadro Dettagli codice tariffa in Blockchain App Builder oppure utilizzando un client API REST, ad esempio Postman.

L'immagine seguente dell'interfaccia utente mostra la scheda Esegui della finestra Crea codice concatenato.

Segue la descrizione di blockchain_chaincode_execute.png
Descrizione dell'immagine blockchain_chaincode_execute.png

Per richiamare i metodi di smart contract di Oracle Blockchain Platform mediante l'API REST, utilizzare il metodo POST e specificare l'URL, composto da due parti concatenate insieme. La prima parte è l'endpoint proxy REST di Oracle Blockchain Platform, che è possibile ottenere dalla scheda Nodi della console di Oracle Blockchain Platform.

La seconda parte è l'URI specifico per richiamare la transazione utilizzando l'API Transaction. Consulta la documentazione per inviare una richiesta POST. Le due parti formano un URL completo simile a quello qui.

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

Sostituire {channelName} con il nome del canale specificato durante la distribuzione del codice concatenato, ad esempio marketplace. Durante la creazione della richiesta API, attenersi alla procedura riportata di seguito.

  • Impostare l'autorizzazione per utilizzare Basic Auth con il valore userid and password specificato mappato al ruolo REST_Client. È inoltre possibile utilizzare i token OAuth2. Per ulteriori informazioni, vedere Usare OAuth 2.0 Access Token Based Authentication nella guida delle API REST.
  • Impostare l'intestazione Content-Type su application/json.
  • Nel corpo della richiesta, includere i parametri necessari per il richiamo della transazione, inclusi il nome del codice concatenato e il metodo create<TokenName>Token insieme agli argomenti richiesti.

In base al codice concatenato generato dal modello yaml, il testo seguente mostra un corpo della richiesta campione e la risposta associata.

Richiesta

{
    "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
}

Risposta

{
    "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
        },

Per ulteriori informazioni sui metodi disponibili per la gestione dei codici concatenati NFT, inclusi i metodi Golang o TypeScript e Platform REST API, vedere la sezione Esplora altro.

È possibile richiamare le API direttamente dal webhook Oracle Content Management e dall'applicazione Web creata su Visual Builder Cloud Service (VBCS) oppure rimapparle con il gateway API per l'uso da parte di un'applicazione Web del marketplace ospitato esternamente. Tenere presente che quando si crea (suggerimento) un NFT, uno dei parametri da fornire è token_uri, che può essere un IPFS URI che punta a un file JSON che rappresenta l'oggetto digitale.

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

I passi seguenti descrivono un esempio di generazione dell'URI del token mediante IPFS Desktop:

  1. Caricare un file immagine su IPFS e salvare l'URI dell'immagine.
  2. Creare e caricare il file JSON che include l'URI dell'immagine insieme ai campi di metadati pertinenti.
  3. Condividere e copiare il collegamento nel file JSON sotto ... Altro elenco.

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

Utilizzare l'URI che punta al file JSON per il parametro token_uri.

È inoltre possibile includere metadati pertinenti negli attributi passati al metodo create<Token-Name>Token, che gestiranno i metadati nel libro contabile di Oracle Blockchain Platform per un facile recupero.

Per i NFT creati utilizzando Oracle Content Management (OCM), utilizzare il webhook OCM per chiamare Oracle Functions mediante un gateway API e collocare il richiamo dell'API REST in Oracle Functions come mostrato nel diagramma dell'architettura. Puoi anche richiamare le API REST della blockchain direttamente dall'applicazione Web del marketplace o utilizzando un mapping del gateway API per supportare i contenuti generati dagli utenti. La funzionalità di trading di Marketplace può richiamare i metodi personalizzati per gestire il pagamento e quindi attivare un trasferimento della proprietà NFT, ad esempio i metodi di esempio buyWithTokens e buyWithDirectPayment.