Creación y despliegue de contrato inteligente NFT

En esta sección aprenderá a crear y desplegar un contrato inteligente de NFT necesario para configurar NFT Marketplace.

Utilice el creador de aplicaciones de cadena de bloques para generar un contrato inteligente con el fin de gestionar la creación, la propiedad y la transferencia de NFT. El elemento clave de esta solución es la capacidad de combinar y transferir NFT mediante Oracle Blockchain Platform.

En primer lugar, cree un archivo de especificación NFT y, a continuación, despliegue el contrato inteligente en una instancia de Oracle Blockchain Platform. A continuación, puede probar el contrato inteligente.

Instalar creador de aplicaciones de cadena de bloques

Después de aprovisionar una instancia de Oracle Blockchain Platform, realice los siguientes pasos:

  1. En la consola de Oracle Blockchain Platform, abra el separador Herramientas para desarrolladores y, a continuación, seleccione el panel Creador de aplicaciones de cadena de bloques.
  2. En la sección Descargar, descargue el archivo de herramientas de la interfaz de línea de comandos (CLI) o la extensión de código de Visual Studio (VS) y, a continuación, configúrelo localmente.

Personalizar el archivo de especificación de NFT de muestra

Se incluye un archivo de especificación NFT de ejemplo con Blockchain App Builder. Puede utilizarlo y adaptarlo a sus necesidades, como se muestra en el siguiente ejemplo:


 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

Puede agregar propiedades y métodos personalizados para ampliar esta especificación para el código de cadena NFT. Los códigos de cadenas de NFT generados por Blockchain App Builder se basan en el estándar ERC-721.

Para generar el código de cadena (contrato inteligente) mediante la extensión Visual Studio Code, realice los siguientes pasos:

  1. En la sección Códigos de dominio, haga clic en el icono +. Se abre el panel Detalles de código de dominio.
  2. Rellene los campos necesarios para generar el proyecto de código de cadena:
    • Introduzca un nombre para el proyecto de código de cadena.
    • Seleccione TypeScript o Go como el idioma en el que desea generar los métodos de código de cadenas.
    • Seleccione el archivo de especificación de entrada que creó anteriormente.
    • Introduzca la ubicación en la que desea generar el proyecto.
  3. Haga clic en Crear.

En la siguiente captura de pantalla de la interfaz de usuario se muestra la ventana Crear código de cadena.

A continuación se muestra la descripción de blockchain_chaincode_details.png
Descripción de la ilustración Blockchain_chaincode_details.png
Una vez generado el código de cadena, puede revisar la implantación del modelo y el controlador mediante la inspección de los archivos en el directorio src de la jerarquía del proyecto.
  • El archivo de modelo contiene todas las estructuras de datos generadas que representan el token, las cuentas, etc.
  • El archivo de controlador contiene todos los métodos de ciclo de vida de NFT generados y las funciones de soporte con la lógica de validación necesaria basada en la especificación.
El archivo de controlador también tiene plantillas de funciones para métodos personalizados, donde puede agregar su lógica de negocio basada en las funciones de SDK generadas.

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

Despliegue del contrato inteligente

Después de crear un proyecto de código de cadenas, puede desplegarlo localmente.

En el panel Detalles de código de dominio, seleccione Desplegar para abrir el asistente de despliegue. Blockchain App Builder incluye una red de cadenas de bloques local, que se ejecuta en contenedores de Docker, que puede utilizar con fines de prueba.

También puede desplegar el código de cadena en una instancia de Oracle Blockchain Platform seleccionando el perfil de conexión de la lista para el entorno de destino. También debe completar y guardar los parámetros de inicialización, porque el código de cadena NFT generado requiere los parámetros orgId y userId para la inicialización. Los parámetros orgId y userId se utilizan para especificar qué usuarios tienen privilegios de administrador de token.

Prueba del contrato inteligente

Cuando se despliega el código de cadenas, Oracle Blockchain Platform expone automáticamente las API de REST para la inicialización de tokens, la gestión de cuentas y roles, y los métodos de ciclo de vida de NFT (crear, transferir, grabar).

Puede realizar la prueba seleccionando Ejecutar en el panel Detalles de código de dominio en el creador de aplicaciones de cadena de bloques o utilizando un cliente de API de REST como Postman.

En la siguiente captura de pantalla de la interfaz de usuario se muestra el separador Ejecutar de la ventana Crear código de cadena.

A continuación se muestra la descripción de blockchain_chaincode_execute.png
Descripción de la ilustración Blockchain_chaincode_execute.png

Para llamar a métodos de contrato inteligente de Oracle Blockchain Platform mediante la API de REST, utilice el método POST y especifique la URL, que consta de dos partes concatenadas juntas. La primera parte es el punto final de proxy de REST en Oracle Blockchain Platform, que puede obtener del separador Nodos de la consola de Oracle Blockchain Platform.

La segunda parte es el URI específico para llamar a la transacción mediante la API Transaction. Consulte la documentación para enviar una solicitud POST. Las dos partes forman una URL completa similar a la que aparece aquí.

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

Sustituya {channelName} por el nombre del canal especificado al desplegar el código de cadena, como marketplace. Al crear la solicitud de API, realice los siguientes pasos:

  • Defina la autorización para utilizar Basic Auth con el userid and password especificado que está asignado al rol REST_Client. También puede utilizar tokens OAuth2. Consulte Uso de la autenticación basada en token de acceso OAuth 2.0 en la guía de la API de REST para obtener más información.
  • Defina la cabecera Content-Type en application/json.
  • En el cuerpo de la solicitud, incluya los parámetros necesarios para la llamada a la transacción, incluido el nombre del código de cadena y el método create<TokenName>Token junto con los argumentos necesarios.

Según el código de cadena generado a partir de la plantilla yaml, el siguiente texto muestra un cuerpo de solicitud de ejemplo y la respuesta asociada.

Solicitud

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

Respuesta

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

Consulte la sección Explorar más para obtener más información sobre los métodos disponibles para gestionar códigos de cadenas de NFT, incluidos los métodos Golang o TypeScript y Platform REST API.

Puede llamar a las API directamente desde el webhook de Oracle Content Management y la aplicación web creada sobre Visual Builder Cloud Service (VBCS), o bien reasignarlas y encapsularlas con el gateway de API para que las utilice una aplicación web de Marketplace alojada externamente. Tenga en cuenta que al crear (minutos) un NFT, uno de los parámetros que debe proporcionar es token_uri, que puede ser IPFS URI que apunta a un archivo JSON que representa el objeto digital.

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

Los siguientes pasos describen un ejemplo de generación del URI de token mediante IPFS Desktop:

  1. Cargue un archivo de imagen en IPFS y guarde el URI de la imagen.
  2. Cree y cargue el archivo JSON que incluye el URI de imagen junto con los campos de metadatos relevantes.
  3. Comparta y copie el enlace al archivo JSON en ... Lista de más.

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

Utilice el URI que apunta al archivo JSON para el parámetro token_uri.

También puede incluir metadatos relevantes en los atributos que se transfieren al método create<Token-Name>Token, que mantendrá los metadatos en el libro mayor de Oracle Blockchain Platform para una fácil recuperación.

Para los NFT creados mediante Oracle Content Management (OCM), utilice el webhook de OCM para llamar a Oracle Functions mediante un gateway de API y colocar la llamada a la API de REST en Oracle Functions como se muestra en el diagrama de arquitectura. También puede llamar a las API de REST de cadena de bloques directamente desde la aplicación web de Marketplace o utilizando una asignación de gateway de API para soportar contenido generado por el usuario. La funcionalidad de comercio de Marketplace puede invocar los métodos personalizados para manejar el pago y, a continuación, disparar una transferencia de la propiedad de NFT, como los métodos de ejemplo buyWithTokens y buyWithDirectPayment.