Flutter y Blockchain – Hello World Dapp

Flutter and Blockchain

Flutter y string de bloques

Este tutorial lo guiará a través del proceso de creación de su primera dapp móvil: ¡Hello World Dapp!

Este tutorial está destinado a aquellos con un conocimiento básico de Ethereum y contratos inteligentes, que tienen algún conocimiento del marco Flutter pero son nuevos en las dapps móviles.

En este tutorial cubriremos:

  1. Configuración del entorno de desarrollo
  2. Creación de un proyecto de trufa
  3. Escribiendo tu primer contrato inteligente
  4. Compilación y migración del contrato inteligente
  5. Probando el contrato inteligente
  6. Vinculación de contrato con Flutter
  7. Creación de una interfaz de usuario para interactuar con el contrato inteligente
  8. Interactuando con el Dapp completo

la

Truffle es el marco de desarrollo más popular para Ethereum con la misión de hacer su vida mucho más fácil. Pero antes de instalar truffle, asegúrese de instalar node .

Una vez que tenemos el Node instalado, solo necesitamos un comando para instalar Truffle:

npm install -g truffle

También usaremos Ganache , una string de bloques personal para el desarrollo de Ethereum que puede usar para implementar contratos inteligentes, desarrollar aplicaciones y ejecutar pruebas. Puede descargar Ganache navegando a http://truffleframework.com/ganache y haciendo clic en el botón «Descargar».

  1. Cree un proyecto básico de Flutter en su IDE favorito
  2. Inicialice Truffle en el directorio del proyecto flutter ejecutando
truffle init

  • contract/ : Contiene archivo de contrato de solidez.
  • migraciones/ : contiene archivos de script de migración (Truffle usa un sistema de migración para manejar la implementación del contrato).
  • test/ : contiene archivos de script de prueba.
  • truffle-config.js : contiene información de configuraciones de implementación de truffle.

Escribiendo tu primer contrato inteligente

El contrato inteligente en realidad actúa como lógica de back-end y almacenamiento para nuestra Dapp.

  1. Cree un nuevo archivo llamado HelloWorld.sol en el directorio contracts/ .
  2. Agregue el siguiente contenido al archivo:

Solidity

pragma solidity ^0.5.9;
  
contract HelloWorld {
  
}
  • La versión mínima de Solidity requerida se indica en la parte superior del contrato: pragma solidity ^0.5.9; .
  • Las declaraciones se terminan con punto y coma.

Configuración de variables

  1. Agregue la siguiente variable en la siguiente línea después del contrato HelloWorld { 

Solidity

string public yourName ;

Acabamos de definir una sola variable yourName de tipo string , también yourName es un modificador público , lo que significa que podemos acceder a él desde fuera del contrato inteligente.

Constructor

  1. Agregue el siguiente constructor en la siguiente línea después de la string public yourName ;

Solidity

constructor() public {
        yourName = "Unknown" ;
}

Constructor en solidez ejecutado solo una vez, cuando se crea un contrato y se usa para inicializar el estado del contrato. Aquí solo estamos configurando el valor inicial de la variable yourName en «Desconocido».

Función

  1. Agregue la siguiente función al contrato inteligente después de la declaración del constructor que configuramos anteriormente.

Solidity

function setName(string memory nm) public{
        yourName = nm ;
}
  • En la función anterior, tomaremos un nm ( string ) y le configuraremos la variable yourName .
  • La memoria es la ubicación de los datos.

Compilar y Migrar 

Compilacion

  1. En una terminal, asegúrese de estar en la raíz del directorio que contiene el proyecto flutter and truffle, ejecute el siguiente comando:
truffle compile

Debería ver un resultado similar al siguiente:

compilación de trufas

Migración

Verá un archivo JavaScript que ya está en el directoriomigrations / : 1_initial_migration.js . Esto maneja la implementación del contrato de Migraciones.sol para observar las migraciones posteriores de contratos inteligentes y garantiza que no migremos dos veces los contratos sin cambios en el futuro.

Vamos a crear nuestro propio script de migración:

  1. Cree un nuevo archivo llamado 2_deploy_contracts.js en el directoriomigrations / .
  2. Agregue el siguiente contenido al archivo 2_deploy_contracts.js :

Javascript

const HelloWorld = artifacts.require("HelloWorld");
  
module.exports = function (deployer) {
  deployer.deploy(HelloWorld);
};
  • Antes de que podamos migrar nuestro contrato a la string de bloques, debemos tener una string de bloques en ejecución. Para este artículo, vamos a usar Ganache , una string de bloques personal para el desarrollo de Ethereum que puede usar para implementar contratos, desarrollar aplicaciones y ejecutar pruebas. Si aún no lo ha hecho, descargue Ganache y haga doble clic en el icono para iniciar la aplicación. Esto generará una string de bloques que se ejecuta localmente en el puerto 7545.

ganache

  • Agregue el siguiente contenido al archivo truffle-config.js :

Javascript

module.exports = {
  networks: {
     development: {
      host: "127.0.0.1",     // Localhost (default: none)
      port: 7545,            // Standard Ethereum port (default: none)
      network_id: "*",       // Any network (default: none)
     },
  },
    contracts_build_directory: "./src/artifacts/",
      
  // Configure your compilers
  compilers: {
    solc: {    
      
       // See the solidity docs for advice
       // about optimization and evmVersion
        optimizer: {
          enabled: false,
          runs: 200
        },
        evmVersion: "byzantium"
    }
  }
};
  • Migrando el contrato a blockchain, ejecuta:
truffle migrate

Debería ver un resultado similar al siguiente:

la trufa migra

  • Eche un vistazo a la Ganache, la primera cuenta originalmente tenía 100 ether, ahora es más baja, debido a los costos de transacción de la migración.

Probando el contrato inteligente

En Truffle, podemos escribir pruebas en JavaScript o Solidity. En este artículo, escribiremos nuestras pruebas en Javascript usando las bibliotecas Chai y Mocha.

  1. Cree un nuevo archivo llamado helloWorld.js en el directorio test/ .
  2. Agregue el siguiente contenido al archivo helloWorld.js :

Javascript

const HelloWorld = artifacts.require("HelloWorld") ;
  
contract("HelloWorld" , () => {
    it("Hello World Testing" , async () => {
       const helloWorld = await HelloWorld.deployed() ;
       await helloWorld.setName("User Name") ;
       const result = await helloWorld.yourName() ;
       assert(result === "User Name") ;
    });
});
  • HelloWorld : el contrato inteligente que queremos probar. Comenzamos nuestra prueba importando nuestro contrato HelloWorld usando artefactos.require .
  • Para probar la función setName , recuerde que acepta un nombre (string) como argumento.
  • Además, la variable yourName en nuestro contrato usa un modificador público , que podemos usar como captador desde la función externa.
  • Truffle importa Chai para que podamos usar la función de afirmación. Pasamos el valor real y el valor esperado, para comprobar que el nombre está configurado correctamente o no, assert(result === “Nombre de usuario”); .

Ejecutando las pruebas

  • Ejecutando la prueba como:
truffle test
  • Si todas las pruebas pasan, verá la salida de la consola similar a esta:

prueba de trufa

Vinculación de contrato con Flutter

  • En el archivo pubspec.yaml importa los siguientes paquetes:
provider: ^4.3.3
web3dart: ^1.2.3
http: ^0.12.2
web_socket_channel: ^1.2.0
  • Además, agregue el activo src/artifacts/HelloWorld.json al archivo pubspec.yaml que genera truffle-config.js mientras migramos nuestro contrato.
assets:
    - src/artifacts/HelloWorld.json
  1. Cree un nuevo archivo llamado contract_linking.dart en el directorio lib/ .
  2. Agregue el siguiente contenido al archivo:

Dart

import 'package:flutter/material.dart';
  
class ContractLinking extends ChangeNotifier {
    
}
  • Solo una clase simple con ChangeNotifier para la gestión del estado.

Variables

  • Agregue la siguiente variable en la siguiente línea después de la clase ContractLinking extends ChangeNotifier { .

Dart

final String _rpcUrl = "http://10.0.2.2:7545";
final String _wsUrl = "ws://10.0.2.2:7545/";
final String _privateKey = "Enter Private Key";

La biblioteca web3dart no enviará transacciones firmadas a los mineros. En su lugar, se basa en un cliente RPC para hacerlo. Para la URL de WebSocket, simplemente modifique la URL de RPC. Puede obtener la URL de RPC del ganache:

Ganache – RPC url

  • Obtenga la clave privada de ganache:

Ganache – Clave privada

  • Declare las siguientes variables a continuación:

Dart

Web3Client _client;
bool isLoading = true;
  
String _abiCode;
EthereumAddress _contractAddress;
  
Credentials _credentials;
  
DeployedContract _contract;
ContractFunction _yourName;
ContractFunction _setName;
  
String deployedName;
  1. La variable _client se utilizará para establecer una conexión con el Node ethereum rpc con la ayuda de WebSocket.
  2. La variable isLoading se utilizará para comprobar el estado del contrato.
  3. La variable _abiCode se utilizará para leer el contrato abi.
  4. La variable _contractAddress se utilizará para almacenar la dirección del contrato del contrato inteligente implementado.
  5. La variable _credentials almacenará las credenciales del implementador de contratos inteligentes.
  6. La variable _contract se usará para decirle a Web3dart dónde se declara nuestro contrato.
  7. Las variables _yourName y _setName se utilizarán para almacenar las funciones declaradas en nuestro contrato inteligente HelloWorld.sol.
  8. deploymentName contendrá el nombre del contrato inteligente.

Funciones

  • Después de declarar las variables anteriores, declare las siguientes funciones debajo:

Dart

ContractLinking() {
    initialSetup();
  }
  
  initialSetup() async {
      
    // establish a connection to the ethereum rpc node. The socketConnector
    // property allows more efficient event streams over websocket instead of
    // http-polls. However, the socketConnector property is experimental.
    _client = Web3Client(_rpcUrl, Client(), socketConnector: () {
      return IOWebSocketChannel.connect(_wsUrl).cast<String>();
    });
  
    await getAbi();
    await getCredentials();
    await getDeployedContract();
  }
  
  Future<void> getAbi() async {
      
    // Reading the contract abi
    String abiStringFile =
        await rootBundle.loadString("src/artifacts/HelloWorld.json");
    var jsonAbi = jsonDecode(abiStringFile);
    _abiCode = jsonEncode(jsonAbi["abi"]);
  
    _contractAddress =
        EthereumAddress.fromHex(jsonAbi["networks"]["5777"]["address"]);
  }
  
  Future<void> getCredentials() async {
    _credentials = await _client.credentialsFromPrivateKey(_privateKey);
  }
  
  Future<void> getDeployedContract() async {
      
    // Telling Web3dart where our contract is declared.
    _contract = DeployedContract(
        ContractAbi.fromJson(_abiCode, "HelloWorld"), _contractAddress);
  
    // Extracting the functions, declared in contract.
    _yourName = _contract.function("yourName");
    _setName = _contract.function("setName");
    getName();
  }
  
  getName() async {
      
    // Getting the current name declared in the smart contract.
    var currentName = await _client
        .call(contract: _contract, function: _yourName, params: []);
    deployedName = currentName[0];
    isLoading = false;
    notifyListeners();
  }
  
  setName(String nameToSet) async {
      
    // Setting the name to nameToSet(name defined by user)
    isLoading = true;
    notifyListeners();
    await _client.sendTransaction(
        _credentials,
        Transaction.callContract(
            contract: _contract, function: _setName, parameters: [nameToSet]));
    getName();
  }

Creación de una interfaz de usuario para interactuar con el contrato inteligente

  1. Cree un nuevo archivo llamado helloUI.dart en el directorio lib/ .
  2. Agregue el siguiente contenido al archivo:

Dart

import 'package:flutter/material.dart';
import 'package:hello_world/contract_linking.dart';
import 'package:provider/provider.dart';
  
class HelloUI extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
      
    // Getting the value and object or contract_linking
    var contractLink = Provider.of<ContractLinking>(context);
  
    TextEditingController yourNameController = TextEditingController();
  
    return Scaffold(
      appBar: AppBar(
        title: Text("Hello World !"),
        centerTitle: true,
      ),
      body: Container(
        padding: EdgeInsets.symmetric(horizontal: 20),
        child: Center(
          child: contractLink.isLoading
              ? CircularProgressIndicator()
              : SingleChildScrollView(
            child: Form(
              child: Column(
                children: [
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(
                        "Hello ",
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 52),
                      ),
                      Text(
                        contractLink.deployedName,
                        style: TextStyle(
                            fontWeight: FontWeight.bold,
                            fontSize: 52,
                            color: Colors.tealAccent),
                      ),
                    ],
                  ),
                  Padding(
                    padding: EdgeInsets.only(top: 29),
                    child: TextFormField(
                      controller: yourNameController,
                      decoration: InputDecoration(
                          border: OutlineInputBorder(),
                          labelText: "Your Name",
                          hintText: "What is your name ?",
                          icon: Icon(Icons.drive_file_rename_outline)),
                    ),
                  ),
                  Padding(
                    padding: EdgeInsets.only(top: 30),
                    child: ElevatedButton(
                      child: Text(
                        'Set Name',
                        style: TextStyle(fontSize: 30),
                      ),
                      style: ElevatedButton.styleFrom(
                        primary: Colors.green,
                      ),
                      onPressed: () {
                        contractLink.setName(yourNameController.text);
                        yourNameController.clear();
                      },
                    ),
                  )
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
  • Actualice main.dart como:

Dart

import 'package:flutter/material.dart';
import 'package:hello_world/contract_linking.dart';
import 'package:hello_world/helloUI.dart';
import 'package:provider/provider.dart';
  
void main() {
  runApp(MyApp());
}
  
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
      
    // Inserting Provider as a parent of HelloUI()
    return ChangeNotifierProvider<ContractLinking>(
      create: (_) => ContractLinking(),
      child: MaterialApp(
        title: "Hello World",
        theme: ThemeData(
            brightness: Brightness.dark,
            primaryColor: Colors.cyan[400],
            accentColor: Colors.deepOrange[200]),
        home: HelloUI(),
      ),
    );
  }
}

Interactuando con el Dapp completo

  • ¡Ahora estamos listos para usar nuestro dapp!
  • Simplemente EJECUTE el Proyecto Flutter.

Hola mundo Dapp

Como puede ver, Hello Unknown , en la interfaz de usuario en realidad proviene del contrato inteligente, variable yourName .

Cuando escribe su nombre en TextFormField y presiona `Set Name` ElevatedButton , invocará la función setName de contract_linking.dart que invocará directamente la función setName de nuestro contrato inteligente (HelloWorld.sol).

Hola mundo Dapp

Hello World Flutter Dapp

Hola mundo Dapp

Hello World Flutter Dapp

Hola mundo Dapp

¡Felicidades! Ha dado un gran paso para convertirse en un desarrollador de dapp móvil de pleno derecho. Para desarrollar localmente, tiene todas las herramientas que necesita para comenzar a crear dapps más avanzados.

Si se quedó atascado en algún lugar, consulte el repositorio de GitHub para obtener el código completo.

Publicación traducida automáticamente

Artículo escrito por aniketambore y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *