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
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
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
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
Seu diretório deve ficar assim.
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;
polyfill.js
Em App.js, copie e cole o seguinte código:
global.Buffer = require("buffer").Buffer;
Index.js
No index.js adicione esta linha
import './polyfill'
import 'bootstrap/dist/css/bootstrap.min.css';
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;
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;
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;
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
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"
]
}
}
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
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. 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
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
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
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. 10: Tela de Saldo da Nano
Fig. 11: Tela de Endereço da Nano
Fig. 13: Tela de Max Fees 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.
Aguarde até que o status passe para Sucesso.
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”.
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)