WEB3DEV

Cover image for Chamando um Contrato Inteligente - Ledger
Banana Labs
Banana Labs

Posted on • Atualizado em

Chamando um Contrato Inteligente - Ledger

Introdução

Nesta seção, orientamos você na criação de uma aplicação que chamará um contrato inteligente para leitura e escrita.

Pré-requisitos

Antes de começar, certifique-se de ter cumprido os pré-requisitos.

Envie o token Ether para sua conta Ethereum da Ledger Nano

Para enviar alguns ethers na rede Ropsten, acesse um dos sites do ropsten faucet:

A rede Ropsten não é visível na Ledger Live, então você pode verificar a transação passada em ropsten.etherscan.io.

Se os Ropsten faucets e Dimension não funcionarem ou a fila for muito longa, use outro faucet de sua escolha para receber o testnet Ether.

Rede Ropsten Ethereum

Vá para o site Ropsten Ethereum Faucet, coloque sua chave pública da carteira na entrada e clique em “Envie-me teste Ether”.

Fig. 1: Ropsten Ethereum Faucet Fig. 1: Ropsten Ethereum Faucet

Rede Dimensions

Acesse o site da Rede Dimensions coloque sua Chave Pública da Carteira na entrada, faça o captcha e clique em “Send me test Ether

Fig. 2: Ropsten Ethereum Faucet Fig. 2: Ropsten Ethereum Faucet

Aplicativo Web Bluetooth (somente Nano X)

A Ledger Nano S e S Plus não possuem a funcionalidade Bluetooth. Este tutorial funcionará apenas com uma Ledger Nano X.

Esteja ciente de que a implementação do Bluetooth é suportada apenas por alguns navegadores. Você pode verificar o suporte do navegador para o transporte Web Bluetooth.

Inicialização do Projeto

O aplicativo é construído com React, que é um framework Javascript para o frontend.

Primeiro, abra um terminal e crie um novo projeto. Para este tutorial, o projeto será nomeado “e2e-tutorial-contract”. Execute:

npx create-react-app e2e-tutorial-contract
cd e2e-tutorial-contract
Enter fullscreen mode Exit fullscreen mode

Abra a pasta em um editor. A inicialização do aplicativo React cria uma pasta “src” onde você encontrará todo o código.

Execute:

touch ./src/ConnectLedger.js
touch ./src/SmartContract.js
touch ./src/ethereum.js
touch ./src/polyfill.js
Enter fullscreen mode Exit fullscreen mode

Seu diretório deve ficar assim.

Fig. 1: Diretório da Aplicação<br>
Fig. 1: Diretório da Aplicação

Para implementar a conexão da Ledger, você só modificará “App.js”, “index.js”, “ConnectLedger.js”,”SmartContract.js” e ethereum.js”

Implementação do Código

App.js

Em App.js, copie e cole o seguinte código:

import React, { useState } from 'react';
import ConnectLedger from './ConnectLedger.js';
import SmartContract from './SmartContract.js';

function App() {
  const [transport, setTransport] = useState(undefined);
  const [eth, setEth] = useState(undefined);
  const [address, setAddress] = useState(undefined);

  const saveInfo = (info) => {
    setAddress(info.address);
    setEth(info.eth);
    setTransport(info.transport);
  }

  return (
    <div className='container'>
      {
      !transport ?
      <ConnectLedger onTransport={(info) => saveInfo(info)}></ConnectLedger> :
      <SmartContract address={address} eth={eth}></SmartContract>
      }
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

polyfill.js

Em App.js, copie e cole o seguinte código:

global.Buffer = require("buffer").Buffer;
Enter fullscreen mode Exit fullscreen mode

Index.js

No index.js adicione esta linha

import './polyfill'
import 'bootstrap/dist/css/bootstrap.min.css';
Enter fullscreen mode Exit fullscreen mode

ConnectLedger.js

Em ConnectLedger.js, copie e cole o seguinte código:

import React from 'react';

import TransportWebBLE from "@ledgerhq/hw-transport-web-ble";
import Eth from "@ledgerhq/hw-app-eth";


function ConnectLedger({onTransport}) {

  const connectLedger = async() => {
    const transport = await TransportWebBLE.create();
    const eth = new Eth(transport);
    const {address} = await eth.getAddress("44'/60'/0'/0/0", false);
    onTransport({address,eth,transport})
  }


  return (
    <div className='container'>
      <div className='row'>
        <div className='col-sm-4 mt-5 mx-auto'>
          <button onClick={connectLedger}>Connect Your Ledger</button>
        </div>
      </div>
    </div>
  );
}

export default ConnectLedger;
Enter fullscreen mode Exit fullscreen mode

SmartContract.js

Em “SmartContract.js”, copie e cole o seguinte código:

import React, { useState } from 'react';
import getBlockchain from './ethereum.js';
import { ethers } from 'ethers';

function SmartContract({eth,address}) {
  const [simpleStorage, setSimpleStorage] = useState(undefined);
  const [data, setData] = useState(undefined);
  const [provider, setProvider] = useState(undefined);
  const [url, setUrl] = useState(undefined);

  const smartContractRead = async() => {
    const provider = new ethers.providers.JsonRpcProvider('https://ropsten.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161');
    const { simpleStorage } = await getBlockchain(provider);
    console.log(simpleStorage);
    const data = await simpleStorage.readData();
    setProvider(provider);
    setSimpleStorage(simpleStorage);
    setData(data);
  };

  const updateData = async e => {
    e.preventDefault();
    const dataInput = e.target.elements[0].value;
    console.log(simpleStorage);
    const { data } = await simpleStorage.populateTransaction['updateData(uint256)'](dataInput);

    const unsignedTx = {
      to: simpleStorage.address,
      gasPrice: (await provider.getGasPrice())._hex,
      gasLimit: ethers.utils.hexlify(100000),
      nonce: await provider.getTransactionCount(address, "latest"),
      chainId: 3,
      data: data,
    }
    console.log(unsignedTx);
    const serializedTx = ethers.utils.serializeTransaction(unsignedTx).slice(2);

    console.log(serializedTx);
    const signature = await eth.signTransaction(
      "44'/60'/0'/0/0",
      serializedTx
    );

    console.log(signature);
    //Parse the signature
    signature.r = "0x"+signature.r;
    signature.s = "0x"+signature.s;
    signature.v = parseInt("0x"+signature.v);
    signature.from = address;
    console.log(signature);

    //Serialize the same transaction as before, but adding the signature on it
    const signedTx = ethers.utils.serializeTransaction(unsignedTx, signature);
    console.log(signedTx);

    const hash = (await provider.sendTransaction(signedTx)).hash;
    console.log(hash);
    setUrl("https://ropsten.etherscan.io/tx/" + hash);
  };


  return (
    <div className='container'>
      <div className='row'>
        <div className='col-sm-4'>
          <h2>Data:</h2>
          <p>{data ? data.toString() : "..." }</p>
          <button onClick={() => smartContractRead()}>Get Data</button>
        </div>

        <div className='col-sm-4'>
          <h2>Change data</h2>
          <form className="form-inline" onSubmit={e => updateData(e)}>
            <input 
              type="text" 
              className="form-control" 
              placeholder="data"
            />
            <button 
              type="submit" 
              className="btn btn-primary"
            >
              Submit
            </button>
          </form>
        </div>
        <div className="mt-5 mx-auto d-flex flex-column">
          <p>
            Ropsten Etherscan :
          </p>
          <p><a href={url} target="_blank" rel="noreferrer">{url}</a></p>
        </div>
      </div>
    </div>
  );
}

export default SmartContract;
Enter fullscreen mode Exit fullscreen mode

Ethereum.js

Em “ethereum.js”, copie e cole o seguinte código:

import { Contract } from 'ethers';

const getBlockchain = (provider) =>
  new Promise( async (resolve, reject) => {
    if(provider) {
      const simpleStorage = new Contract(
        "0x989c810f64ac577683d49a318adfd98b8d482472",
        [
          {
            "inputs": [],
            "name": "data",
            "outputs": [
              {
                "internalType": "uint256",
                "name": "",
                "type": "uint256"
              }
            ],
            "stateMutability": "view",
            "type": "function"
          },
          {
            "inputs": [],
            "name": "readData",
            "outputs": [
              {
                "internalType": "uint256",
                "name": "",
                "type": "uint256"
              }
            ],
            "stateMutability": "view",
            "type": "function"
          },
          {
            "inputs": [
              {
                "internalType": "uint256",
                "name": "_data",
                "type": "uint256"
              }
            ],
            "name": "updateData",
            "outputs": [],
            "stateMutability": "nonpayable",
            "type": "function"
          }
        ],
        provider
      );
      resolve({simpleStorage});
      return;
    }
    reject('Provider not recognized');
  });

export default getBlockchain;
Enter fullscreen mode Exit fullscreen mode

Instalação de dependências

Execute:

npm install --save bootstrap
npm install --save ethers
npm install --save @ledgerhq/hw-app-eth
npm install --save @ledgerhq/hw-transport-web-ble
npm install --save buffer
Enter fullscreen mode Exit fullscreen mode
Pacote O que ele faz?
bootstrap Ele permite que você use o framework CSS Bootstrap.
ethers Ele fornece todos os métodos para interagir com a blockchain Ethereum
@ledgerhq/hw-app-eth Isso ajudará você a pedir à sua Nano para acessar o endereço ethereum.
@ledgerhq/hw-transport-web-ble Ele fornece todos os métodos para interagir com sua Ledger Nano X usando uma conexão Bluetooth.
buffer O objetivo é fornecer uma API 100% idêntica à API de buffer do nó.

Dependências do Package.json

Agora que as dependências estão instaladas, você pode encontrá-las no “package.js”. É assim que seu “package.json” deve ficar:

{
  "name": "e2e-tutorial",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@ledgerhq/hw-app-eth": "^6.26.0",
    "@ledgerhq/hw-transport-web-ble": "^6.24.0",
    "@testing-library/jest-dom": "^5.16.2",
    "@testing-library/react": "^12.1.3",
    "@testing-library/user-event": "^13.5.0",
    "bootstrap": "^5.1.3",
    "buffer": "^6.0.3",
    "ethers": "^5.5.4",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "5.0.0",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Web App Test

Inicie o Servidor de Desenvolvimento

Execute:

npm run start

⚠ Aviso
Todos os navegadores não suportam o Bluetooth, consulte o suporte do navegador.

Agora a aplicação está funcionando. Abra o navegador e vá para localhost:3000
ele irá exibir:

Fig. 2: Aplicação rodando no navegador<br>
Fig. 2: Aplicação rodando no navegador

Não clique no botão ainda.

Inicie a aplicação Ethereum

Antes de clicar no botão, desbloqueie sua Nano X e execute a aplicação Ethereum. As etapas são descritas abaixo.

Fig. 3: Digite o código PIN da Ledger Fig. 3: Digite o código PIN da Ledger

Fig. 4: Aplicação Ledger Fig. 4: Aplicação Ledger

Fig. 5: Execução da Aplicação Ledger Fig. 5: Execução da Aplicação Ledger

Conecte sua Nano à aplicação

Agora você pode clicar no botão e uma janela pop-up será aberta. Escolha sua Ledger Nano X e clique em conexão

Fig. 6: Conecte a Ledger com Bluetooth Fig. 6: Conecte a Ledger com Bluetooth

Leia os Dados de um Contrato Inteligente

Agora você pode clicar no botão “Obter dados” para ler os dados do contrato inteligente. Em seguida, os dados serão exibidos na tela.

Fig. 7: Obter dados de um contrato inteligente Fig. 7: Obter dados de um contrato inteligente

Atualize os Dados de um Contrato Inteligente

Agora, em vez de ler os dados, sobrescrevemos os dados chamando uma função do contrato inteligente que é “UpdateData”.

Fig. 8: Alterar dados de um contrato inteligente Fig. 8: Alterar dados de um contrato inteligente

Verifique o Endereço na sua Nano

Por motivos de segurança, o endereço também será exibido na sua Ledger Nano X para verificar e confirmar o endereço.

Fig. 9: Tela de Revisão da Nano Fig. 9: Tela de Revisão da Nano

Fig. 10: Tela de Saldo da Nano Fig. 10: Tela de Saldo da Nano

Fig. 11: Tela de Endereço da Nano Fig. 11: Tela de Endereço da Nano

Fig. 12: Tela de Rede da Nano Fig. 12: Tela de Rede da Nano

Fig. 13: Tela de Max Fees da Nano Fig. 13: Tela de Max Fees da Nano

Fig. 14: Tela de Aceitar e Enviar da Nano Fig. 14: Tela de Aceitar e Enviar da Nano

⚠ Aviso
Para a chamada de contrato inteligente, você precisa permitir o blind signing porque o contrato inteligente chamado no tutorial ainda não foi verificado e revisado pela Ledger. Mas se o contrato inteligente que você está chamando for aceito pela Ledger, não habilite o blind signing. Além disso, não recomendamos habilitar o blind signing em outras situações, pois o objetivo principal de assinar com a Ledger é o sistema 'Assine o que você vê'. E ao habilitar o blind signing, ele não pode garantir que o que você vê seja o que você obtém.

Revise a Transação no Ropsten Etherscan

Ao atualizar os dados, uma transação é criada para alterar esses dados, ela pode ser verificada no Ropsten Etherscan.

Fig. 15: Ropsten Etherscan<br>
Fig. 15: Ropsten Etherscan

Aguarde até que o status passe para Sucesso.

Fig. 16: Ropsten Etherscan<br>
Fig. 16: Ropsten Etherscan

Verifique a atualização dos dados

Por fim, para verificar se os dados foram atualizados, abra a aplicação web e clique em “Obter dados”.

Fig. 17: Verifique os dados Fig. 17: Verifique os dados

Fig. 18: Verifique os dados Fig. 18: Verifique os dados

Parabéns, você construiu com sucesso seu primeiro aplicativo conectado à Ledger!


Esse artigo é uma tradução de Ledger Developer Portal feita por @bananlabs. Você pode encontrar o artigo original aqui

Latest comments (0)