13  Prática sobre Ferramentas de Desenvolvimento e Frameworks Ethereum: Implementação de Aplicações

Implementação de Aplicações

Resumo
A proposta desta aula prática é implementarmos alguns exemplos de aplicações web que interajam com contratos implantados.

13.1 Introdução

A interação com smart contracts como parte de uma DApps é normalmente feito usando uma interface web desenvolvida utilizando HTML/JS/CSS. Algumas bibliotecas e frameworks como React, Redux, e Drizzle, podem também ser usadas. A Figura 13.I apresenta um esquema de interação com uma rede blockchain via aplicação web utilizando biblioteca web3.

Figure 13.I: Interação com Aplicações Web

13.2 Biblioteca javascript Web3.js 

Se ainda não instalou a biblioteca web3.js, pode instalá-la via npm com o comando:

$ npm install web3@1.10.0

A biblioteca web3.js também pode ser instalada via download direto de https://github.com/ethereum/web3.js.

A biblioteca web.js disponibiliza alguns módulos, sendo eles:

  • web3-eth: Ethereum blockchain e smart contracts.

  • web3-shh: Protocolo Whisper (Comunicação e broadcast P2P).

  • web3-bzz: Protocolo Swarm, que fornece armazenamento descentralizado.

  • web3-utils: Fornece funções úteis para o desenvolvimento de DApps.

13.3 Servidor HTTP

Para executarmos uma aplicação web precisaremos de um servidor de aplicações http. O pacote http-server do node pode ser usado para suporte a um servidor http e pode ser instalado com o comando:

$ npm install --global http-server

added 44 packages in 5s

14 packages are looking for funding
  run `npm fund` for details

Após a instalação o servidor pode ser executando na porta \(8000\), por exemplo, com o comando:

[app]$ http-server -p 8000
Starting up http-server, serving ./

http-server version: 14.1.1

http-server settings: 
CORS: disabled
Cache: 3600 seconds
Connection Timeout: 120 seconds
Directory Listings: visible
AutoIndex: visible
Serve GZIP Files: false
Serve Brotli Files: false
Default File Extension: none

Available on:
  http://127.0.0.1:8000
  http://172.18.11.178:8000
Hit CTRL-C to stop the server

[2023-11-07T23:40:28.835Z]  "GET /" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0"
(node:156213) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated
(Use `node --trace-deprecation ...` to show where the warning was created)
[2023-11-07T23:40:28.999Z]  "GET /app.js" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0"
[2023-11-07T23:40:29.797Z]  "GET /favicon.ico" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 F

Uma alternativa pode ser criarmos o servidor http utilizando os recursos do Python.

# Python 3.x
[app]$ python3 -m http.server 8000
# If Python version returned above is 2.X
[app]$ python -m SimpleHTTPServer 8000

Tanto o servidor do http do node quanto do Python deve ser executado dentro do diretório app do projeto.

13.4 Projeto projeto-helloworld-truffle

Considerando o projeto projeto-helloworld-truffle, vamos executar o teste em uma rede padrão do truffle para verificar o funcionamento, vamos utilizar o comando truffle test:

[projeto-helloworld-truffle]$ truffle test
Using network 'test'.


Compiling your contracts...
===========================
> Compiling ./contracts/Greeter.sol
> Compiling openzeppelin-solidity/contracts/access/Ownable.sol
> Compiling openzeppelin-solidity/contracts/utils/Context.sol
> Artifacts written to /tmp/test--15169-EOpeI8e5cvxQ
> Compiled successfully using:
   - solc: 0.8.21+commit.d9974bed.Emscripten.clang

  Contract: Greeter
    [ok] has been deployed successfully
    greet()
      [ok] returns 'Hello, World!'
    Contract: Greeter: update greeting
      setGreeting(string)
        [ok] sets greeting to passed in string (73ms)
    Contract: owner()
      [ok] returns the address of the owner
      [ok] matches the address that originally deployed the contract
    Contract: Greeter: update greeting
      setGreeting(string)
        when message is sent by the owner
          [ok] sets greeting to passed in string (65ms)
      when message is sent by another account
        [ok] does not set the greeting (267ms)


  7 passing (579ms)

[projeto-helloworld-truffle]$

Para executarmos o teste em uma rede das que vimos no decorrer das aulas é necessário que a rede esteja em execução. Para testar o deploy na rede ganache-cli é necessário subirmos a rede conforme o comando:

$ ganache-cli --chain.chainId 1337 --chain.networkId 2525
ganache v7.9.1 (@ganache/cli: 0.10.1, @ganache/core: 0.10.1)
Starting RPC server

Available Accounts
==================
(0) 0x2161FB1A0b754eb1cfb48D214926602beB8cE370 (1000 ETH)
(1) 0x26e969A727cC64b1412eF49E1cAd92271B27Eb7E (1000 ETH)
(2) 0xF17058AD8929C9d4DA7D3A1AD08a7D28f5fF604C (1000 ETH)
(3) 0x302a2dAdb79ca2512341759BCd4829C2F5123cB3 (1000 ETH)
(4) 0xED2D8e4B4c516A52086A2Eda58DC0ED5f7Add815 (1000 ETH)
(5) 0x0d9C5bfdBC93521a709b91816AEb486272555a3E (1000 ETH)
(6) 0xbc618f9C71DD794fcb613e0fF0E8c7C8b326603E (1000 ETH)
(7) 0x770d75FCE798831A1b7C3d762B13bD44DB779590 (1000 ETH)
(8) 0x14DB77A215869EC40a51Ecd7d895bBb23e7D30Dd (1000 ETH)
(9) 0xd7049C7Bd0bB3Cda500aaDA677abD8C2B94cc36C (1000 ETH)

Private Keys
==================
(0) 0x60dfe80d1691cda7766b9bbab139d40bcf94ea57551c60479fbec8d93e1e995d
(1) 0xd1f073fd8952521ae85499600d9843631b267ac3498597d28aca3c70d166d45c
(2) 0x93bc50a9cf546f876459002430e0ef91b6f7764eeb6c64921db1fa283d0be84a
(3) 0x8cce8c5e603a017075ed0c3abe9e5999237e6a597121d4c5522d075c3650c40d
(4) 0x0346a1465ae017627fc3538370ef90a21037870edeabb7af9bedf8dca2875f69
(5) 0x94b914e5bb391cbc6aaf5bfef73496240d45fbaec5bd8df3116952a100b71aae
(6) 0x75868abce85cb593dbebe9caa9b19fcb5a363dedf7ad5f42a56acd164bc603a1
(7) 0x048f88d531bd3201f7dd41f35dc8e534958338da77b90efb3b979690dc1aa03a
(8) 0xa5513eb14f5d83a215ed0f7877ae23d82abd126740a6937edc9cd87190c203ca
(9) 0xe4ce4e28d579fe8e9ea0793eed48da9f3e9ffa4a03b3d00b7cff1c9568d10555

HD Wallet
==================
Mnemonic:      alert notice holiday spawn wasp host uncle coin skin scrub zero trial
Base HD Path:  m/44'/60'/0'/0/{account_index}

Default Gas Price
==================
2000000000

BlockGas Limit
==================
30000000

Call Gas Limit
==================
50000000

Chain
==================
Hardfork: shanghai
Id:       1337

RPC Listening on 127.0.0.1:8545

Para executar o teste com a rede ganache-cli é necessário configurar o IP e a porta 8545 no arquivo de configuração do truffle.

[projeto-helloworld-truffle]$ truffle test --network ganachecli
Using network 'ganachecli'.


Compiling your contracts...
===========================
> Compiling ./contracts/Greeter.sol
> Compiling openzeppelin-solidity/contracts/access/Ownable.sol
> Compiling openzeppelin-solidity/contracts/utils/Context.sol
> Artifacts written to /tmp/test--18491-0eHv1cQ5PRGi
> Compiled successfully using:
   - solc: 0.8.21+commit.d9974bed.Emscripten.clang


  Contract: Greeter
    [ok] has been deployed successfully
    greet()
      [ok] returns 'Hello, World!'
    Contract: Greeter: update greeting
      setGreeting(string)
        [ok] sets greeting to passed in string (50ms)
    Contract: owner()
      [ok] returns the address of the owner
      [ok] matches the address that originally deployed the contract
    Contract: Greeter: update greeting
      setGreeting(string)
        when message is sent by the owner
          [ok] sets greeting to passed in string (62ms)
      when message is sent by another account
        [ok] does not set the greeting (175ms)


  7 passing (452ms)

[projeto-helloworld-truffle]$ 

A execução dos testes irá gerar algumas mensagens do terminal onde a rede está sendo executada.

RPC Listening on 127.0.0.1:8545
eth_blockNumber
net_version
eth_accounts
eth_blockNumber
net_version
eth_accounts
eth_getBlockByNumber
eth_accounts
eth_getBlockByNumber
eth_getBlockByNumber
eth_getBlockByNumber
eth_estimateGas
eth_getBlockByNumber
eth_blockNumber
eth_estimateGas
eth_getBlockByNumber
eth_gasPrice
eth_sendTransaction

  Transaction: 0x7a3c6ce5355a541852564148aee7f07fb4197a0e833fa1581bf6c2e23473496d
  Contract created: 0x8389f668c138ab559bb3152df4735ae0bd2056b5
  Gas usage: 750889
  Block number: 1
  Block time: Thu Nov 14 2024 15:27:33 GMT-0300 (Horário Padrão de Brasília)

eth_getTransactionReceipt
eth_getCode
evm_snapshot
Saved snapshot #1
net_version
eth_blockNumber
eth_getBlockByNumber
eth_blockNumber
eth_getBlockByNumber
eth_call
evm_revert
Reverting to snapshot #1
evm_snapshot
Saved snapshot #1
net_version
eth_blockNumber
eth_blockNumber
eth_getBlockByNumber
eth_getBlockByNumber
eth_estimateGas
eth_getBlockByNumber
eth_gasPrice
eth_sendTransaction

  Transaction: 0x49932947db1d68ec42b3387ed40a2143c042e5d903790171dc9a00e300a9c68f
  Gas usage: 29938
  Block number: 2
  Block time: Thu Nov 14 2024 15:27:33 GMT-0300 (Horário Padrão de Brasília)

eth_getTransactionReceipt
eth_call
evm_revert
Reverting to snapshot #1
evm_snapshot
Saved snapshot #1
net_version
eth_blockNumber
eth_blockNumber
eth_getBlockByNumber
eth_call
eth_blockNumber
eth_blockNumber
eth_getBlockByNumber
eth_call
evm_revert
Reverting to snapshot #1
evm_snapshot
Saved snapshot #1
net_version
eth_blockNumber
eth_blockNumber
eth_getBlockByNumber
eth_getBlockByNumber
eth_estimateGas
eth_getBlockByNumber
eth_gasPrice
eth_sendTransaction

  Transaction: 0x64c7b015cff99f0c4a86a17ca53fe39cd343f32ca9c9d36cbec4a307e8b6060a
  Gas usage: 30178
  Block number: 2
  Block time: Thu Nov 14 2024 15:27:33 GMT-0300 (Horário Padrão de Brasília)

eth_getTransactionReceipt
eth_call
eth_blockNumber
eth_blockNumber
eth_getBlockByNumber
eth_call
eth_getBlockByNumber
eth_estimateGas

13.5 Projeto projeto-valuechecker-truffle

O outro exemplo de contrato do projeto-valuechecker-truffle pode ser testado da mesma forma utilizando qualquer uma das redes que executamos, seja simulado ou rede privada local.

[projeto-valuechecker-truffle]$ truffle test --network ganachecli
Using network 'ganachecli'.


Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


  Contract: ValueChecker
    [ok] has been deployed successfully
    greet()
      [ok] returns 'ValueChecker!'


  2 passing (48ms)

[projeto-valuechecker-truffle]$ 

Fazendo o teste, as mensagens aparecem no console onde o ganache-cli foi iniciado:

eth_blockNumber
net_version
eth_accounts
eth_blockNumber
net_version
eth_accounts
eth_getBlockByNumber
eth_accounts
eth_getBlockByNumber
eth_getBlockByNumber
eth_getBlockByNumber
eth_estimateGas
eth_getBlockByNumber
eth_blockNumber
eth_estimateGas
eth_getBlockByNumber
eth_gasPrice
eth_sendTransaction

  Transaction: 0xd753c86db4cf9af7b43ec70dcfff2afeceffc66d2a1552a8bb27b74af5299530
  Contract created: 0x2d17533cdc2f706020d383c550977b050d677fae
  Gas usage: 295447
  Block number: 3
  Block time: Thu Nov 14 2024 21:33:56 GMT-0300 (Horário Padrão de Brasília)

eth_getTransactionReceipt
eth_getCode
evm_snapshot
Saved snapshot #2
net_version
eth_blockNumber
eth_getBlockByNumber
eth_blockNumber
eth_getBlockByNumber
eth_call

Executando o deploy para o ganache-cli:

[projeto-valuechecker-truffle]$ truffle migrate --network ganachecli

Compiling your contracts...
===========================
> Compiling ./contracts/ValueChecker.sol

> Artifacts written to /run/media/rogerio/DADOS/repositorios/Dropbox/dados/rogerio/UTFPR/docencia/disciplinas/2024/DLT-PPGCC17/2024-2/aulas/md/aula-15-pratica-implementacao-patentidea-app/src/projeto-valuechecker-truffle/build/contracts
> Compiled successfully using:
   - solc: 0.8.21+commit.d9974bed.Emscripten.clang

Starting migrations...
======================
> Network name:    'ganachecli'
> Network id:      2525
> Block gas limit: 30000000 (0x1c9c380)


2_deploy_valuechecker.js
========================

   Replacing 'ValueChecker'
   ------------------------
   > transaction hash:    0x2f4fa80aa5e9afced43866c3aff9a4ca9b67a62b101654da5aeea30649c6265e
   > Blocks: 0            Seconds: 0
   > contract address:    0xE5764329De8c1FFC6D12246D49C8d537ab8bFa70
   > block number:        4
   > block timestamp:     1731630948
   > account:             0x4869c5C3CfAc7Ab1bE63e6C9C18878dA4057e71F
   > balance:             999.99551543504778316
   > gas used:            295447 (0x48217)
   > gas price:           3.092204955 gwei
   > value sent:          0 ETH
   > total cost:          0.000913582677339885 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost:     0.000913582677339885 ETH

Summary
=======
> Total deployments:   1
> Final cost:          0.000913582677339885 ETH

[projeto-valuechecker-truffle]$ 

No console do ganache-cli:

eth_blockNumber
net_version
eth_accounts
eth_getBlockByNumber
eth_accounts
eth_getBlockByNumber
eth_getBlockByNumber
eth_getBlockByNumber
eth_estimateGas
eth_getBlockByNumber
eth_blockNumber
eth_estimateGas
eth_getBlockByNumber
eth_gasPrice
eth_sendTransaction

  Transaction: 0x2f4fa80aa5e9afced43866c3aff9a4ca9b67a62b101654da5aeea30649c6265e
  Contract created: 0xe5764329de8c1ffc6d12246d49c8d537ab8bfa70
  Gas usage: 295447
  Block number: 4
  Block time: Thu Nov 14 2024 21:35:48 GMT-0300 (Horário Padrão de Brasília)

eth_getTransactionReceipt
eth_getCode
eth_getTransactionByHash
eth_getBlockByNumber
eth_getBalance

No console do truffle podemos nos certificar que o contrato ValueChecker foi implantando, podemos inclusive recuperar o endereço que ele recebeu na blockchain.

[projeto-valuechecker-truffle]$ truffle console --network ganachecli
truffle(ganachecli)> ValueChecker.address
ValueChecker.address

truffle(ganachecli)> ValueChecker.address
'0xE5764329De8c1FFC6D12246D49C8d537ab8bFa70'
truffle(ganachecli)> 

Recuperando a ABI do contrato no arquivo projeto-valuechecker-truffle/build/contracts/ValueChecker.json:

"abi": [
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "bool",
          "name": "returnValue",
          "type": "bool"
        }
      ],
      "name": "valueEvent",
      "type": "event"
    },
    {
      "inputs": [
        {
          "internalType": "uint8",
          "name": "x",
          "type": "uint8"
        }
      ],
      "name": "Matcher",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "greet",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    }
  ]

Recuperando a primeira conta.

[projeto-valuechecker-truffle]$ truffle console --network ganachecli
truffle(ganachecli)> accounts
[
  '0x4869c5C3CfAc7Ab1bE63e6C9C18878dA4057e71F',
  '0x714fB43b7d1a20dF30E0a2276794216f522BF51C',
  '0xBA705bE7120cCECa4e6bCe1Ac7A8c8194cf86374',
  '0xcd8A7026aA533f998d6Cf509F9fB2C658e13980d',
  '0x6E6323b1a2155007bEd68480Da5C38B5798289Cd',
  '0xAb74aEFee3b5256dE4878409567fcd02c0e87d5E',
  '0x0A1e0C35318dC12c05Bd84702C59f45cCc64fA81',
  '0x81f7d97Bb1757Ca601c4FC2d076c699E70BBEdB6',
  '0x8E5643A75860A9395cf5C0EA3A3CFd0b70E05D00',
  '0x8f471618c5b55e4F418AA7ADfAafe4C1694a0EAe'
]
truffle(ganachecli)> accounts[0]
'0x4869c5C3CfAc7Ab1bE63e6C9C18878dA4057e71F'
truffle(ganachecli)> 

13.6 Executando uma aplicação básica

A interação com um nó do geth em execução com uma aplicação javascript pode ser feita conforme o exemplo no [Código xxx]. Inicie o ganache-cli em um terminal conforme Código 13.I.

Listing 13.I: Comando de Inicialização do Ganache
$ ganache-cli --chain.chainId 1337 --chain.networkId 2525
ganache v7.9.2 (@ganache/cli: 0.10.2, @ganache/core: 0.10.2)
Starting RPC server

Available Accounts
==================
(0) 0x5A9c1A5146F3e0869290A4b1B19Ce5a3f3cC6350 (1000 ETH)
(1) 0x4cB5784fdAB3E1De349883b8818B14Aa80B4260e (1000 ETH)
(2) 0xcfAb598C0C4076FfCF5c3f6F50590F6BF826c21B (1000 ETH)
(3) 0x9Dac9743ffF9b96207b578866727EC45dFc33029 (1000 ETH)
(4) 0x9387B696Ef768ebf042eC22cbF74a4E32aEca425 (1000 ETH)
(5) 0xDf46317878fb8f90B30489D7e739DdE657Cd5668 (1000 ETH)
(6) 0x319382Ad36f2395a2967A7B2d12B5422914F8091 (1000 ETH)
(7) 0xaEa319FAE6e1744Ada140A1eaB043CB5343a438b (1000 ETH)
(8) 0x5a4cdacdE151e14763aC57eA369740e3f7383aBf (1000 ETH)
(9) 0xA5599C9c22a28c6bee8CEBbdb1DF382a753F7558 (1000 ETH)

Private Keys
==================
(0) 0xdc4188b9a7105ae4df2d838399d5f9c4858f7d52e8b8e3c7b4148544b49df552
(1) 0xb3c2b6852e868f6bc5fc642e1bb4c269e3bc3756574e5d183e769388d3a1667b
(2) 0x0bd4933d6c356c24019823de955da1b6be0f0be58be19b2ca88cf56f25c8a2a1
(3) 0x8ef2817984f02f05f39b086e00dd16bd408e82457caf824238001b1a2e6dd2bd
(4) 0x15314a35f581b7f4ddc69edcb49ec37f204acd1caf19efc8731b3f18192b347d
(5) 0xc2509a7ba81eedae0a3f9f5aeb765d66889bd0375de1c354d282aa224da8a7e1
(6) 0xd835de1dc4655d984ec69d4eb96cf6463ef95e13718540ce23fbd162ef8e8718
(7) 0x3dff71bb95078dc8e18e700d7f8828a792f662bbb513ecde7d389ef3ecbb2956
(8) 0xade7af341bafc32a43612bf6125fc79bf74febe8fda3e84455018956801192ad
(9) 0xf79754a16f282aeee1f0ec3f7dc09e36ed122a05dc2e4f90309142c3a58e8a1f

HD Wallet
==================
Mnemonic:      harsh card adapt sea loud squirrel moon carry total ladder improve eager
Base HD Path:  m/44'/60'/0'/0/{account_index}

Default Gas Price
==================
2000000000

BlockGas Limit
==================
30000000

Call Gas Limit
==================
50000000

Chain
==================
Hardfork: shanghai
Id:       1337

RPC Listening on 127.0.0.1:8545

13.6.1 Cliente Python

Em um outro terminal crie o arquivo crie o diretório de sua app exemplo e dentro crie o arquivo app.js com seguinte conteúdo:

mkdir python_projeto_web3
cd python_projeto_web3
python -m venv venv
source venv/bin/activate

Crie um arquivo app.py:

from web3 import Web3, AsyncWeb3
w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))


if w3.is_connected():
    print("Connected to Ethereum node.")
else:
    print("Falha na conexão.")
    exit()

print(w3.eth.accounts)

account_address = "0x0E90dBe2Cdedf31b8219e48941738fDf948dF424"

# Saldo em Wei
balance_wei = w3.eth.get_balance(account_address)

# Converter para Ether
balance_ether = w3.from_wei(balance_wei, "ether")

print(f"The balance of {account_address} is: {balance_ether} ETH")

# Listar o saldo de todas as contas.
accounts =  w3.eth.accounts

for account in accounts:
    balance = w3.from_wei(w3.eth.get_balance(account), "ether")
    print(f"{account}: {balance} ETH")

Executar o código em python:

(venv) $ python app.py 
Connected ao Ethereum node.
['0x0E90dBe2Cdedf31b8219e48941738fDf948dF424', '0x06827CFf67b81b14736dCC5C0d692595968eF380', '0xA60963502A20E35834c499AAee9D9Cd8135c9813', '0xd64213B1F4df57a8cD99903Ab01fcb5AC1766dA0', '0x99f525409820476C5D7Fe20A8369b545cA58Bb69', '0x6F12868219226eCBa8Bb19b75E25E427589D6D6e', '0xe1bC47D65c8C31C8A7dF246Db1f87EaDca456757', '0x3fe3b1E3Df65DFaD779Baffb82064A8895201c40', '0x8BF5B5B867Db3CCB901179091A2ed08F1343D432', '0xdcf01E04a05A839Ca18bD7847FCeF42230A83085']
The balance of 0x0E90dBe2Cdedf31b8219e48941738fDf948dF424 is: 1000 ETH
0x0E90dBe2Cdedf31b8219e48941738fDf948dF424: 1000 ETH
0x06827CFf67b81b14736dCC5C0d692595968eF380: 1000 ETH
0xA60963502A20E35834c499AAee9D9Cd8135c9813: 1000 ETH
0xd64213B1F4df57a8cD99903Ab01fcb5AC1766dA0: 1000 ETH
0x99f525409820476C5D7Fe20A8369b545cA58Bb69: 1000 ETH
0x6F12868219226eCBa8Bb19b75E25E427589D6D6e: 1000 ETH
0xe1bC47D65c8C31C8A7dF246Db1f87EaDca456757: 1000 ETH
0x3fe3b1E3Df65DFaD779Baffb82064A8895201c40: 1000 ETH
0x8BF5B5B867Db3CCB901179091A2ed08F1343D432: 1000 ETH
0xdcf01E04a05A839Ca18bD7847FCeF42230A83085: 1000 ETH
(venv) $ 

13.6.2 Cliente Java

Em um outro terminal verifique se você tem o java e o Maven instalado. Caso não tenha utilize os comandos de instalação:

$ sudo apt install openjdk-25-jdk
$ sudo apt install maven

Verifique as versões instaladas:

``bash $ java –version openjdk 25.0.1 2025-09-16 OpenJDK Runtime Environment (build 25.0.1) OpenJDK 64-Bit Server VM (build 25.0.1, mixed mode, sharing) $ $ mvn –version Apache Maven 3.9.11 (3e54c93a704957b63ee3494413a2b544fd3d825b) Maven home: /usr/share/java/maven Java version: 25.0.1, vendor: Arch Linux, runtime: /usr/lib/jvm/java-25-openjdk Default locale: pt_BR, platform encoding: UTF-8 OS name: “linux”, version: “6.17.3-arch2-1”, arch: “amd64”, family: “unix”


Vamos criar um exemplo de projeto para consultar o saldo das contas do nó `Ethereum` em execução com o `ganache-cli`, forneça na linha de comando o nome do projeto `consulta-saldo-ethereum`.

```bash
$ mvn archetype:generate -DgroupId=com.exemplo.web3 \
    -DartifactId=consulta-saldo-ethereum \
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -DinteractiveMode=false

Uma estrutura básica de diretórios para o projeto será criada:

$ tree
.
├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── com
    │           └── exemplo
    │               └── web3
    │                   └── App.java
    └── test
        └── java
            └── com
                └── exemplo
                    └── web3
                        └── AppTest.java

12 directories, 3 files

Abra o arquivo pom.xml e adicione dentro da seção <dependencies> a dependência Web3j.

<dependencies>
    <dependency>
        <groupId>org.web3j</groupId>
        <artifactId>core</artifactId>
        <version>4.10.3</version>
    </dependency>
</dependencies>

O arquivo pom.xml final com dependências e plugins ficará como segue:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.exemplo.web3</groupId>
  <artifactId>consulta-saldo-ethereum</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>consulta-saldo-ethereum</name>
  <url>http://maven.apache.org</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.web3j</groupId>
        <artifactId>core</artifactId>
        <version>4.10.3</version>
    </dependency>
  </dependencies>
  <build>
  <plugins>
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>exec-maven-plugin</artifactId>
      <version>3.1.0</version>
      <configuration>
        <mainClass>com.exemplo.web3.App</mainClass>
        <source>19</source>
        <target>19</target>-->
        <release>19</release>
      </configuration>
    </plugin>
  </plugins>
</build>
</project>

Edite o conteúdo do arquivo src/main/java/com/exemplo/web3/App.java para que fique com nosso código de verificação de saldo das contas.

package com.exemplo.web3;

import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
import org.web3j.protocol.core.methods.response.Web3ClientVersion;
import org.web3j.protocol.core.methods.response.EthGetBalance;
import org.web3j.utils.Convert;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthAccounts;

import java.io.IOException;
import java.util.List;
import java.math.BigDecimal;
import java.math.BigInteger;

public class App {
    public static void main(String[] args) throws Exception {
        // String endPointURL = "https://mainnet.infura.io/v3/SEU_PROJECT_ID"; // troque pelo seu
        String endPointURL = "http://localhost:8545"; // troque pelo seu

        Web3j web3 = Web3j.build(new HttpService(endPointURL));

        Web3ClientVersion clientVersion = web3.web3ClientVersion().send();
        System.out.println("Conectado a: " + clientVersion.getWeb3ClientVersion());

        String endereco = "0x0E90dBe2Cdedf31b8219e48941738fDf948dF424";
        EthGetBalance saldoWei = web3.ethGetBalance(endereco, DefaultBlockParameterName.LATEST).send();
        BigDecimal saldoEther = Convert.fromWei(saldoWei.getBalance().toString(), Convert.Unit.ETHER);

        System.out.println("Saldo da carteira " + endereco + ": " + saldoEther + " ETH");

        EthAccounts ethAccounts = web3.ethAccounts().send();

        if (ethAccounts.hasError()) {
            System.err.println("Error getting accounts: " + ethAccounts.getError().getMessage());
        } else {
            List<String> accounts = ethAccounts.getAccounts();
            if (accounts.isEmpty()) {
                System.out.println("No accounts found on the connected node.");
            } else {
                System.out.println("Accounts on the connected node:");
                for (String account : accounts) {
                    saldoWei = web3.ethGetBalance(account, DefaultBlockParameterName.LATEST).send();
                    saldoEther = Convert.fromWei(saldoWei.getBalance().toString(), Convert.Unit.ETHER);
                    System.out.println(account + ": " + saldoEther + "ETH");
                }
            }
        }
    }
}

Para compilar utilizando o Maven utilize o comando:

$ mvn clean compile
$ mvn clean compile
[INFO] Scanning for projects...
[INFO] 
[INFO] --------------< com.exemplo.web3:consulta-saldo-ethereum >--------------
[INFO] Building consulta-saldo-ethereum 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- clean:3.2.0:clean (default-clean) @ consulta-saldo-ethereum ---
[INFO] Deleting ../app-basico-java/consulta-saldo-ethereum/target
[INFO] 
[INFO] --- resources:3.3.1:resources (default-resources) @ consulta-saldo-ethereum ---
[INFO] skip non existing resourceDirectory .../consulta-saldo-ethereum/src/main/resources
[INFO] 
[INFO] --- compiler:3.13.0:compile (default-compile) @ consulta-saldo-ethereum ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug target 1.8] to target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.229 s
[INFO] Finished at: 2025-10-22T09:04:34-03:00
[INFO] ------------------------------------------------------------------------
$

Para executa o exemplo utilize o comando:

$ mvn exec:java
[INFO] Scanning for projects...
[INFO] 
[INFO] --------------< com.exemplo.web3:consulta-saldo-ethereum >--------------
[INFO] Building consulta-saldo-ethereum 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- exec:3.1.0:java (default-cli) @ consulta-saldo-ethereum ---
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Conectado a: Ganache/v7.9.2/EthereumJS TestRPC/v7.9.2/ethereum-js
Saldo da carteira 0x0E90dBe2Cdedf31b8219e48941738fDf948dF424: 1000 ETH
Accounts on the connected node:
0x0e90dbe2cdedf31b8219e48941738fdf948df424: 1000ETH
0x06827cff67b81b14736dcc5c0d692595968ef380: 1000ETH
0xa60963502a20e35834c499aaee9d9cd8135c9813: 1000ETH
0xd64213b1f4df57a8cd99903ab01fcb5ac1766da0: 1000ETH
0x99f525409820476c5d7fe20a8369b545ca58bb69: 1000ETH
0x6f12868219226ecba8bb19b75e25e427589d6d6e: 1000ETH
0xe1bc47d65c8c31c8a7df246db1f87eadca456757: 1000ETH
0x3fe3b1e3df65dfad779baffb82064a8895201c40: 1000ETH
0x8bf5b5b867db3ccb901179091a2ed08f1343d432: 1000ETH
0xdcf01e04a05a839ca18bd7847fcef42230a83085: 1000ETH

Para gerar um arquivo.jar para o projeto adicione ao pom.xml o plugin:

<plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>3.2.4</version> <!-- Use a recent version -->
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>shade</goal>
          </goals>
          <configuration>
            <transformers>
              <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                <mainClass>com.exemplo.web3.App</mainClass>
              </transformer>
            </transformers>
            <filters>
              <filter>
                <artifact>*:*</artifact>
                  <excludes>
                    <exclude>META-INF/*.SF</exclude>
                    <exclude>META-INF/*.DSA</exclude>
                    <exclude>META-INF/*.RSA</exclude>
                  </excludes>
              </filter>
            </filters>
          </configuration>
        </execution>
      </executions>
    </plugin>

Executando o comando mvn clean package o projeto será recompilado e o arquivo consulta-saldo-ethereum 1.0-SNAPSHOT.jar será criado dentro do diretório target:

$ mvn clean package
[INFO] Scanning for projects...
[INFO] 
[INFO] --------------< com.exemplo.web3:consulta-saldo-ethereum >--------------
[INFO] Building consulta-saldo-ethereum 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- clean:3.2.0:clean (default-clean) @ consulta-saldo-ethereum ---
[INFO] Deleting consulta-saldo-ethereum/target
[INFO] 
[INFO] --- resources:3.3.1:resources (default-resources) @ consulta-saldo-ethereum ---
[INFO] skip non existing resourceDirectory consulta-saldo-ethereum/src/main/resources
[INFO] 
[INFO] --- compiler:3.13.0:compile (default-compile) @ consulta-saldo-ethereum ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug target 1.8] to target/classes
[INFO] 
[INFO] --- resources:3.3.1:testResources (default-testResources) @ consulta-saldo-ethereum ---
[INFO] skip non existing resourceDirectory consulta-saldo-ethereum/src/test/resources
[INFO] 
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ consulta-saldo-ethereum ---
[INFO] Recompiling the module because of changed dependency.
[INFO] Compiling 1 source file with javac [debug target 1.8] to target/test-classes
[INFO] 
[INFO] --- surefire:3.2.5:test (default-test) @ consulta-saldo-ethereum ---
[INFO] Using auto detected provider org.apache.maven.surefire.junit.JUnit3Provider
[INFO] 
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.exemplo.web3.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.031 s -- in com.exemplo.web3.AppTest
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] 
[INFO] --- jar:3.4.1:jar (default-jar) @ consulta-saldo-ethereum ---
[INFO] Building jar: consulta-saldo-ethereum/target/consulta-saldo-ethereum-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- shade:3.2.4:shade (default) @ consulta-saldo-ethereum ---
[INFO] Including org.web3j:core:jar:4.10.3 in the shaded jar.
[INFO] Including org.web3j:abi:jar:4.10.3 in the shaded jar.
[INFO] Including org.web3j:utils:jar:4.10.3 in the shaded jar.
[INFO] Including org.bouncycastle:bcprov-jdk18on:jar:1.73 in the shaded jar.
[INFO] Including org.web3j:crypto:jar:4.10.3 in the shaded jar.
[INFO] Including org.web3j:rlp:jar:4.10.3 in the shaded jar.
[INFO] Including org.web3j:tuples:jar:4.10.3 in the shaded jar.
[INFO] Including com.github.jnr:jnr-unixsocket:jar:0.38.17 in the shaded jar.
[INFO] Including com.github.jnr:jnr-ffi:jar:2.2.11 in the shaded jar.
[INFO] Including com.github.jnr:jffi:jar:1.3.9 in the shaded jar.
[INFO] Including com.github.jnr:jffi:jar:native:1.3.9 in the shaded jar.
[INFO] Including org.ow2.asm:asm:jar:9.2 in the shaded jar.
[INFO] Including org.ow2.asm:asm-commons:jar:9.2 in the shaded jar.
[INFO] Including org.ow2.asm:asm-analysis:jar:9.2 in the shaded jar.
[INFO] Including org.ow2.asm:asm-tree:jar:9.2 in the shaded jar.
[INFO] Including org.ow2.asm:asm-util:jar:9.2 in the shaded jar.
[INFO] Including com.github.jnr:jnr-a64asm:jar:1.0.0 in the shaded jar.
[INFO] Including com.github.jnr:jnr-x86asm:jar:1.0.2 in the shaded jar.
[INFO] Including com.github.jnr:jnr-constants:jar:0.10.3 in the shaded jar.
[INFO] Including com.github.jnr:jnr-enxio:jar:0.32.13 in the shaded jar.
[INFO] Including com.github.jnr:jnr-posix:jar:3.1.15 in the shaded jar.
[INFO] Including com.squareup.okhttp3:okhttp:jar:4.9.0 in the shaded jar.
[INFO] Including com.squareup.okio:okio:jar:2.8.0 in the shaded jar.
[INFO] Including org.jetbrains.kotlin:kotlin-stdlib-common:jar:1.4.0 in the shaded jar.
[INFO] Including org.jetbrains.kotlin:kotlin-stdlib:jar:1.4.10 in the shaded jar.
[INFO] Including org.jetbrains:annotations:jar:13.0 in the shaded jar.
[INFO] Including com.squareup.okhttp3:logging-interceptor:jar:4.9.0 in the shaded jar.
[INFO] Including org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.4.10 in the shaded jar.
[INFO] Including org.jetbrains.kotlin:kotlin-stdlib-jdk7:jar:1.4.10 in the shaded jar.
[INFO] Including io.reactivex.rxjava2:rxjava:jar:2.2.2 in the shaded jar.
[INFO] Including org.reactivestreams:reactive-streams:jar:1.0.2 in the shaded jar.
[INFO] Including org.java-websocket:Java-WebSocket:jar:1.5.3 in the shaded jar.
[INFO] Including com.fasterxml.jackson.core:jackson-databind:jar:2.14.2 in the shaded jar.
[INFO] Including com.fasterxml.jackson.core:jackson-annotations:jar:2.14.2 in the shaded jar.
[INFO] Including com.fasterxml.jackson.core:jackson-core:jar:2.14.2 in the shaded jar.
[INFO] Including org.slf4j:slf4j-api:jar:1.7.30 in the shaded jar.
[INFO] Including io.github.adraffy:ens-normalize:jar:0.1.2 in the shaded jar.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
[WARNING] Java-WebSocket-1.5.3.jar, abi-4.10.3.jar, annotations-13.0.jar, asm-9.2.jar, asm-analysis-9.2.jar, asm-commons-9.2.jar, asm-tree-9.2.jar, asm-util-9.2.jar, bcprov-jdk18on-1.73.jar, consulta-saldo-ethereum-1.0-SNAPSHOT.jar, core-4.10.3.jar, crypto-4.10.3.jar, ens-normalize-0.1.2.jar, jackson-annotations-2.14.2.jar, jackson-core-2.14.2.jar, jackson-databind-2.14.2.jar, jffi-1.3.9-native.jar, jffi-1.3.9.jar, jnr-a64asm-1.0.0.jar, jnr-constants-0.10.3.jar, jnr-enxio-0.32.13.jar, jnr-ffi-2.2.11.jar, jnr-posix-3.1.15.jar, jnr-unixsocket-0.38.17.jar, jnr-x86asm-1.0.2.jar, kotlin-stdlib-1.4.10.jar, kotlin-stdlib-common-1.4.0.jar, kotlin-stdlib-jdk7-1.4.10.jar, kotlin-stdlib-jdk8-1.4.10.jar, logging-interceptor-4.9.0.jar, okhttp-4.9.0.jar, okio-2.8.0.jar, reactive-streams-1.0.2.jar, rlp-4.10.3.jar, rxjava-2.2.2.jar, slf4j-api-1.7.30.jar, tuples-4.10.3.jar, utils-4.10.3.jar define 1 overlapping resource: 
[WARNING]   - META-INF/MANIFEST.MF
[WARNING] bcprov-jdk18on-1.73.jar, jackson-core-2.14.2.jar, jackson-databind-2.14.2.jar, kotlin-stdlib-1.4.10.jar, kotlin-stdlib-jdk7-1.4.10.jar, kotlin-stdlib-jdk8-1.4.10.jar define 1 overlapping classes: 
[WARNING]   - META-INF.versions.9.module-info
[WARNING] jackson-annotations-2.14.2.jar, jackson-core-2.14.2.jar, jackson-databind-2.14.2.jar define 2 overlapping resources: 
[WARNING]   - META-INF/LICENSE
[WARNING]   - META-INF/NOTICE
[WARNING] maven-shade-plugin has detected that some class files are
[WARNING] present in two or more JARs. When this happens, only one
[WARNING] single version of the class is copied to the uber jar.
[WARNING] Usually this is not harmful and you can skip these warnings,
[WARNING] otherwise try to manually exclude artifacts based on
[WARNING] mvn dependency:tree -Ddetail=true and the above output.
[WARNING] See http://maven.apache.org/plugins/maven-shade-plugin/
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing consulta-saldo-ethereum/target/consulta-saldo-ethereum-1.0-SNAPSHOT.jar with consulta-saldo-ethereum/target/consulta-saldo-ethereum-1.0-SNAPSHOT-shaded.jar
[INFO] Dependency-reduced POM written at: consulta-saldo-ethereum/dependency-reduced-pom.xml
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.720 s
[INFO] Finished at: 2025-10-22T09:56:55-03:00
[INFO] ------------------------------------------------------------------------

Para executar o código:

$ cd consulta-saldo-ethereum
$ java -jar target/consulta-saldo-ethereum-1.0-SNAPSHOT.jar 
Conectado a: Ganache/v7.9.2/EthereumJS TestRPC/v7.9.2/ethereum-js
Saldo da carteira 0x0E90dBe2Cdedf31b8219e48941738fDf948dF424: 1000 ETH
Accounts on the connected node:
0x0e90dbe2cdedf31b8219e48941738fdf948df424: 1000ETH
0x06827cff67b81b14736dcc5c0d692595968ef380: 1000ETH
0xa60963502a20e35834c499aaee9d9cd8135c9813: 1000ETH
0xd64213b1f4df57a8cd99903ab01fcb5ac1766da0: 1000ETH
0x99f525409820476c5d7fe20a8369b545ca58bb69: 1000ETH
0x6f12868219226ecba8bb19b75e25e427589d6d6e: 1000ETH
0xe1bc47d65c8c31c8a7df246db1f87eadca456757: 1000ETH
0x3fe3b1e3df65dfad779baffb82064a8895201c40: 1000ETH
0x8bf5b5b867db3ccb901179091a2ed08f1343d432: 1000ETH
0xdcf01e04a05a839ca18bd7847fcef42230a83085: 1000ETH
$

As contas serão listadas ao lado de seus saldos.

13.6.3 Cliente JavaScript

Em um outro terminal crie o arquivo crie o diretório de sua app exemplo e dentro crie o arquivo app.js com seguinte conteúdo:

const {Web3} = require('web3')

if (typeof web3 !== 'undefined') {
    web3 = new Web3(web3.currentProvider);
} else {
    // set the provider you want from Web3.providers
    web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}
web3.eth.defaultAccount = web3.eth.accounts[0];


// Comandos básicos de interação com o nói geth.
console.log(web3.eth.defaultAccount);

// console.log("Último bloco:\n")

// web3.eth.getBlock('latest').then(console.log);

const balance = web3.eth.getBalance("0x0E90dBe2Cdedf31b8219e48941738fDf948dF424");

console.log("Saldo da conta eth.accounts[0]:\n");
// web3.eth.getBalance("0x0E90dBe2Cdedf31b8219e48941738fDf948dF424").then(console.log);

const accounts = [
  "0x0E90dBe2Cdedf31b8219e48941738fDf948dF424",
  "0x0E90dBe2Cdedf31b8219e48941738fDf948dF424"
];

for (const account of accounts) {
  web3.eth.getBalance(account).then(console.log);
  // const balanceInEth = web3.utils.fromWei(balanceInWei, 'ether');
  // console.log(`Account: ${account}\nBalance: ${balanceInEth} ETH\n`);
}

Executando o código com node:

[app-basico]$  node app.js 
undefined
Último bloco:

Saldo da conta eth.accounts[0]:

{
  hash: '0xcb359a1349d0ffbd5df460055cdbd2df3d0f34730cd06c1dfe14ed1e8fdc1971',
  parentHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
  sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
  miner: '0x0000000000000000000000000000000000000000',
  stateRoot: '0x02a7d68f19eb68267bbab43e51136f566f459349039d6bda660d2cb38c4924bb',
  transactionsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
  receiptsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
  logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
  difficulty: 0n,
  number: 0n,
  gasLimit: 30000000n,
  gasUsed: 0n,
  timestamp: 1761055212n,
  extraData: '0x',
  mixHash: '0x43a41a8bd61579d01469cd239c0168975e12458b501755ed173a158a626affcd',
  nonce: 0n,
  totalDifficulty: 0n,
  baseFeePerGas: 1000000000n,
  withdrawalsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
  size: 548n,
  uncles: [],
  withdrawals: [],
  transactions: []
}
[
  '0x0E90dBe2Cdedf31b8219e48941738fDf948dF424',
  '0x06827CFf67b81b14736dCC5C0d692595968eF380',
  '0xA60963502A20E35834c499AAee9D9Cd8135c9813',
  '0xd64213B1F4df57a8cD99903Ab01fcb5AC1766dA0',
  '0x99f525409820476C5D7Fe20A8369b545cA58Bb69',
  '0x6F12868219226eCBa8Bb19b75E25E427589D6D6e',
  '0xe1bC47D65c8C31C8A7dF246Db1f87EaDca456757',
  '0x3fe3b1E3Df65DFaD779Baffb82064A8895201c40',
  '0x8BF5B5B867Db3CCB901179091A2ed08F1343D432',
  '0xdcf01E04a05A839Ca18bD7847FCeF42230A83085'
]
1000000000000000000000n
$ 

<!–

Executando o app.js no node:

[projeto-valuechecker-truffle]$ node app/app.js 
Contract {
  setProvider: [Function (anonymous)],
  currentProvider: [Getter/Setter],
  _requestManager: RequestManager {
    provider: HttpProvider {
      withCredentials: undefined,
      timeout: 0,
      headers: undefined,
      agent: undefined,
      forceGlobalFetch: false,
      connected: false,
      host: 'http://localhost:8545',
      httpAgent: [Agent]
    },
    providers: {
      WebsocketProvider: [Function: WebsocketProvider],
      HttpProvider: [Function: HttpProvider],
      IpcProvider: [Function: IpcProvider]
    },
    subscriptions: Map(0) {}
  },
  givenProvider: null,
  providers: {
    WebsocketProvider: [Function: WebsocketProvider],
    HttpProvider: [Function: HttpProvider],
    IpcProvider: [Function: IpcProvider]
  },
  _provider: HttpProvider {
    withCredentials: undefined,
    timeout: 0,
    headers: undefined,
    agent: undefined,
    forceGlobalFetch: false,
    connected: false,
    host: 'http://localhost:8545',
    httpAgent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 80,
      protocol: 'http:',
      options: [Object: null prototype],
      requests: [Object: null prototype] {},
      sockets: [Object: null prototype] {},
      freeSockets: [Object: null prototype] {},
      keepAliveMsecs: 1000,
      keepAlive: true,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'lifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 0,
      [Symbol(kCapture)]: false
    }
  },
  setRequestManager: [Function (anonymous)],
  BatchRequest: [Function: bound Batch],
  extend: [Function: ex] {
    formatters: {
      inputDefaultBlockNumberFormatter: [Function: inputDefaultBlockNumberFormatter],
      inputBlockNumberFormatter: [Function: inputBlockNumberFormatter],
      inputCallFormatter: [Function: inputCallFormatter],
      inputTransactionFormatter: [Function: inputTransactionFormatter],
      inputAddressFormatter: [Function: inputAddressFormatter],
      inputPostFormatter: [Function: inputPostFormatter],
      inputLogFormatter: [Function: inputLogFormatter],
      inputSignFormatter: [Function: inputSignFormatter],
      inputStorageKeysFormatter: [Function: inputStorageKeysFormatter],
      outputProofFormatter: [Function: outputProofFormatter],
      outputBigNumberFormatter: [Function: outputBigNumberFormatter],
      outputTransactionFormatter: [Function: outputTransactionFormatter],
      outputTransactionReceiptFormatter: [Function: outputTransactionReceiptFormatter],
      outputBlockFormatter: [Function: outputBlockFormatter],
      outputLogFormatter: [Function: outputLogFormatter],
      outputPostFormatter: [Function: outputPostFormatter],
      outputSyncingFormatter: [Function: outputSyncingFormatter]
    },
    utils: {
      _fireError: [Function: _fireError],
      _jsonInterfaceMethodToString: [Function: _jsonInterfaceMethodToString],
      _flattenTypes: [Function: _flattenTypes],
      randomHex: [Function: randomHex],
      BN: [Function: BNwrapped],
      isBN: [Function: isBN],
      isBigNumber: [Function: isBigNumber],
      isHex: [Function: isHex],
      isHexStrict: [Function: isHexStrict],
      sha3: [Function],
      sha3Raw: [Function: sha3Raw],
      keccak256: [Function],
      soliditySha3: [Function: soliditySha3],
      soliditySha3Raw: [Function: soliditySha3Raw],
      encodePacked: [Function: encodePacked],
      isAddress: [Function: isAddress],
      checkAddressChecksum: [Function: checkAddressChecksum],
      toChecksumAddress: [Function: toChecksumAddress],
      toHex: [Function: toHex],
      toBN: [Function: toBN],
      bytesToHex: [Function: bytesToHex],
      hexToBytes: [Function: hexToBytes],
      hexToNumberString: [Function: hexToNumberString],
      hexToNumber: [Function: hexToNumber],
      toDecimal: [Function: hexToNumber],
      numberToHex: [Function: numberToHex],
      fromDecimal: [Function: numberToHex],
      hexToUtf8: [Function: hexToUtf8],
      hexToString: [Function: hexToUtf8],
      toUtf8: [Function: hexToUtf8],
      stripHexPrefix: [Function: stripHexPrefix],
      utf8ToHex: [Function: utf8ToHex],
      stringToHex: [Function: utf8ToHex],
      fromUtf8: [Function: utf8ToHex],
      hexToAscii: [Function: hexToAscii],
      toAscii: [Function: hexToAscii],
      asciiToHex: [Function: asciiToHex],
      fromAscii: [Function: asciiToHex],
      unitMap: [Object],
      toWei: [Function: toWei],
      fromWei: [Function: fromWei],
      padLeft: [Function: leftPad],
      leftPad: [Function: leftPad],
      padRight: [Function: rightPad],
      rightPad: [Function: rightPad],
      toTwosComplement: [Function: toTwosComplement],
      isBloom: [Function: isBloom],
      isUserEthereumAddressInBloom: [Function: isUserEthereumAddressInBloom],
      isContractAddressInBloom: [Function: isContractAddressInBloom],
      isTopic: [Function: isTopic],
      isTopicInBloom: [Function: isTopicInBloom],
      isInBloom: [Function: isInBloom],
      compareBlockNumbers: [Function: compareBlockNumbers],
      toNumber: [Function: toNumber]
    },
    Method: [Function: Method]
  },
  clearSubscriptions: [Function (anonymous)],
  options: { address: [Getter/Setter], jsonInterface: [Getter/Setter] },
  handleRevert: [Getter/Setter],
  defaultCommon: [Getter/Setter],
  defaultHardfork: [Getter/Setter],
  defaultChain: [Getter/Setter],
  transactionPollingTimeout: [Getter/Setter],
  transactionPollingInterval: [Getter/Setter],
  transactionConfirmationBlocks: [Getter/Setter],
  transactionBlockTimeout: [Getter/Setter],
  blockHeaderTimeout: [Getter/Setter],
  defaultAccount: [Getter/Setter],
  defaultBlock: [Getter/Setter],
  methods: {
    Matcher: [Function: bound _createTxObject],
    '0xf9d55e21': [Function: bound _createTxObject],
    'Matcher(uint8)': [Function: bound _createTxObject]
  },
  events: {
    valueEvent: [Function: bound ],
    '0x3eb1a229ff7995457774a4bd31ef7b13b6f4491ad1ebb8961af120b8b4b6239c': [Function: bound ],
    'valueEvent(bool)': [Function: bound ],
    allEvents: [Function: bound ]
  },
  _address: '0x82012b7601Fd23669B50Bb7Dd79460970cE386e3',
  _jsonInterface: [
    {
      constant: false,
      inputs: [Array],
      name: 'Matcher',
      outputs: [Array],
      payable: false,
      stateMutability: 'nonpayable',
      type: 'function',
      signature: '0xf9d55e21'
    },
    {
      anonymous: false,
      inputs: [Array],
      name: 'valueEvent',
      type: 'event',
      constant: undefined,
      payable: undefined,
      signature: '0x3eb1a229ff7995457774a4bd31ef7b13b6f4491ad1ebb8961af120b8b4b6239c'
    }
  ]
}
[projeto-valuechecker-truffle]$ 

Deploy na etherprivate:

[projeto-valuechecker-truffle]$ truffle networks

Network: etherprivate (id: 786)
  No contracts deployed.

Network: ganachecli (id: 2525)
  ValueChecker: 0x08f8ee04C5DB0835ceB816230e308A10c07b28f9

Network: ganacheui (id: 5777)
  No contracts deployed.

[projeto-valuechecker-truffle]$ truffle test --network etherprivate
> Something went wrong while attempting to connect to the network at http://127.0.0.1:8559. Check your network configuration.
CONNECTION ERROR: Couldn't connect to node http://127.0.0.1:8559.
Truffle v5.11.5 (core: 5.11.5)
Node v18.16.0
[projeto-valuechecker-truffle]$ truffle test --network etherprivate
> Something went wrong while attempting to connect to the network at http://127.0.0.1:8559. Check your network configuration.
CONNECTION ERROR: Couldn't connect to node http://127.0.0.1:8559.
Truffle v5.11.5 (core: 5.11.5)
Node v18.16.0
[projeto-valuechecker-truffle]$ truffle test --network etherprivate
Using network 'etherprivate'.


Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.

^C[projeto-valuechecker-truffle]$ truffle test --network etherprivate
Using network 'etherprivate'.


Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


  Contract: ValueChecker
    [ok] has been deployed successfully (113ms)
    greet()
      [ok] returns 'ValueChecker!' (218ms)


  2 passing (1s)

[projeto-valuechecker-truffle]$ truffle deploy --network etherprivate

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


Starting migrations...
======================
> Network name:    'etherprivate'
> Network id:      786
> Block gas limit: 30000000 (0x1c9c380)


2_deploy_valuechecker.js
========================

   Deploying 'ValueChecker'
   ------------------------
   > transaction hash:    0x11e52c27965e6ab851dc762f252462b94b074a41dab58710415003f2d1db412f
^C[projeto-valuechecker-truffle]$ truffle migrate --network etherprivate

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


Starting migrations...
======================
> Network name:    'etherprivate'
> Network id:      786
> Block gas limit: 30000000 (0x1c9c380)


2_deploy_valuechecker.js
========================

   Deploying 'ValueChecker'
   ------------------------
   > transaction hash:    0x157f75ff4b5bb4fa8844ec01369849dba7bbfef3f6debfbe30a9a489a625d817
   [x] Blocks: 0            Seconds: 762
 *** Deployment Failed ***

"ValueChecker" -- Transaction was not mined within 750 seconds, please make sure your transaction was properly sent. Be aware that it might still be mined!.


Exiting: Review successful transactions manually by checking the transaction hashes above on Etherscan.


Error:  *** Deployment Failed ***

"ValueChecker" -- Transaction was not mined within 750 seconds, please make sure your transaction was properly sent. Be aware that it might still be mined!.

    at /home/rogerio/.nvm/versions/node/v18.16.0/lib/node_modules/truffle/build/webpack:/packages/deployer/src/deployment.js:330:1
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
Truffle v5.11.5 (core: 5.11.5)
Node v18.16.0
[projeto-valuechecker-truffle]$ truffle migrate --network etherprivate

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


Starting migrations...
======================
> Network name:    'etherprivate'
> Network id:      786
> Block gas limit: 30000000 (0x1c9c380)


2_deploy_valuechecker.js
========================

   Deploying 'ValueChecker'
   ------------------------
   > transaction hash:    0x4601043f490e0e303ff9870e16fe4860ea8b471ce3f06e32955d79915704f079
   [x] Blocks: 0            Seconds: 765
 *** Deployment Failed ***

"ValueChecker" -- Transaction was not mined within 750 seconds, please make sure your transaction was properly sent. Be aware that it might still be mined!.


Exiting: Review successful transactions manually by checking the transaction hashes above on Etherscan.


Error:  *** Deployment Failed ***

"ValueChecker" -- Transaction was not mined within 750 seconds, please make sure your transaction was properly sent. Be aware that it might still be mined!.

    at /home/rogerio/.nvm/versions/node/v18.16.0/lib/node_modules/truffle/build/webpack:/packages/deployer/src/deployment.js:330:1
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
Truffle v5.11.5 (core: 5.11.5)
Node v18.16.0
[projeto-valuechecker-truffle]$ truffle deploy --network etherprivate

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


Starting migrations...
======================
> Network name:    'etherprivate'
> Network id:      786
> Block gas limit: 30000000 (0x1c9c380)


2_deploy_valuechecker.js
========================

   Deploying 'ValueChecker'
   ------------------------
   > transaction hash:    0xd3ca55313812f0d3f7f6a276037611401893994fc7d8361d2504e884c4209f22
   > Blocks: 0            Seconds: 52
   > contract address:    0x7D1783b6E3Af7008A05b9770cE4A1fb7544094D6
   > block number:        12455
   > block timestamp:     1699361906
   > account:             0x2db017E44b03B37755A4b15e14Cd799f83DE4c13
   > balance:             24910.0000000000002999
   > gas used:            295335 (0x481a7)
   > gas price:           1 gwei
   > value sent:          0 ETH
   > total cost:          0.000295335 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost:         0.000295335 ETH

Summary
=======
> Total deployments:   1
> Final cost:          0.000295335 ETH


[projeto-valuechecker-truffle]$ 

–>

Execução Chamadas Básicas

13.7 Desenvolvendo o Projeto PatentIdea

Esse exemplo de projeto é apresentado em um dos livros utilizados como referência na disciplina. Vamos utilizar o Código 13.II e editá-lo no Remix IDE.

Listing 13.II: Código do Contrato
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

contract PatentIdea {
    mapping(bytes32 => bool) private hashes;
    bool alreadyStored;
    bool storedNow;
    int256 tracker = 0;
    event ideahashed(bool);

    function saveHash(bytes32 hash) private {
        hashes[hash] = true;
    }

    function SaveIdeaHash(string memory idea) public returns (bool) {
        bytes32 hashedIdea = HashtheIdea(idea);
        if (alreadyHashed(HashtheIdea(idea))) {
            alreadyStored = true;
            emit ideahashed(false);
            return alreadyStored;
        }
        saveHash(hashedIdea);
        tracker = tracker + 1;
        emit ideahashed(true);
        storedNow = true;
        return storedNow;
    }

    function alreadyHashed(bytes32 hash) private view returns (bool) {
        return hashes[hash];
    }

    function isAlreadyHashed(string memory idea) public view returns (bool) {
        bytes32 hashedIdea = HashtheIdea(idea);
        return alreadyHashed(hashedIdea);
    }

    function HashtheIdea(string memory idea) private pure returns (bytes32) {
        return bytes32(keccak256(abi.encodePacked(idea)));
    }

    function getTracker() public view returns (int256) {
        return tracker;
    }
}

Vamos editar o contrato no Remix conforme a Figura 13.II.

Figure 13.II: Editando o contrato no Remix IDE

A Figura 13.III mostra o processo de deploy pela interface do Remix.

Figure 13.III: Criando o Contrato
[block:5 txIndex:-]from: 0xc01...04bb2to: PatentIdea.(constructor)value: 0 weidata: 0x608...60033logs: 0hash: 0x4f9...19e6b
status  0x1 Transaction mined and execution succeed
transaction hash    0xfded2bb9797d9d06ef3e305857ada3b581e85f3b63840962a81d51930e096044
block hash  0x4f9cdf8df0ef10fbd10338adb982a5e1f594b35292eb49a20f4e887002b19e6b
block number    5
contract address    0xc28d8b9152b5312719476375332c8f5064673915
from    0xc01046fece893706d7d70b4493dfce8b4ac04bb2
to  PatentIdea.(constructor)
gas  gas
transaction cost    373943 gas 
input   0x608...60033
decoded input   {}
decoded output   - 
logs    []

Após fazermos o deploy, as duas funções do contrato estarão disponíveis na interface do Remix IDE para testarmos:

Testando os métodos pela interface do Remix IDE

Testando o contrato com a cadeia "UTFPR", conforme a Figura 13.IV.

Figure 13.IV: Adicionando a cadeia UTFPR

Pedindo para salvar a cadeia “UTFPR”:

transact to PatentIdea.SaveIdeaHash pending ... 
[block:6 txIndex:-]from: 0xc01...04bb2to: PatentIdea.SaveIdeaHash(string) 0xc28...73915value: 0 weidata: 0xe92...00000logs: 1hash: 0x65c...60207
status  0x1 Transaction mined and execution succeed
transaction hash    0xb1abe896ac68ea22849b57cd3da8abea3798e0eb0bda6faf7c9898920bef18ef
block hash  0x65c673a07e331944caabd75bf037124946e338410739efd3ba1bb88042c60207
block number    6
from    0xc01046fece893706d7d70b4493dfce8b4ac04bb2
to  PatentIdea.SaveIdeaHash(string) 0xc28d8b9152b5312719476375332c8f5064673915
gas  gas
transaction cost    92261 gas 
input   0xe92...00000
decoded input   {
    "string idea": "UTFPR"
}
decoded output   - 
logs    [
    {
        "from": "0xc28d8b9152b5312719476375332c8f5064673915",
        "topic": "0x50a0231b714fc7ad51309492c3e5b5c3fb79c5aa6646b65abd90b708f30b92e5",
        "event": "ideahashed",
        "args": {
            "0": true
        }
    }
]

Testando o contrato com a cadeia "UTFPR", conforme a Figura 13.V.

Figure 13.V: Verificando se a cadeia diferente UFTPR está armazenada

Algumas informações são apresentadas no log, tais como:

  • status: Este valor é verdadeiro no exemplo, o que significa que a transação foi minerada e executada com sucesso.
  • transaction hash: Hash da transação.
  • from: Endereço da conta na qual o contrato foi iniciado.
  • to: Este é o endereço do contrato na blockchain.
  • gas: Mostra quanto de gas é enviado.
  • hash: Este é o hash do contrato.
  • input: Código do contrato como entrada mostrado em hexadecimal.
  • decoded input: Campo mostra o input decodificado.
  • decoded output: Mostra a saída decodificada.
  • logs: Mostra os logs da transação com eventos relevantes.
  • value: Mostra o valor em Wei no contrato.

Chamando o método getTracker que devolve quantas cadeia foram salvas.

call to PatentIdea.getTracker
CALL
[call]from: 0xc01046fecE893706d7d70b4493DFCe8b4aC04BB2to: PatentIdea.getTracker()data: 0x911...564e5
from    0xc01046fecE893706d7d70b4493DFCe8b4aC04BB2
to  PatentIdea.getTracker() 0xC28d8b9152B5312719476375332C8F5064673915
input   0x911...564e5
decoded input   {}
decoded output  {
    "0": "int256: 1"
}
logs    []

Verificando se a cadeia "UTFPR" já foi salva na rede, a resposta é sim (true).

call to PatentIdea.isAlreadyHashed
CALL
[call]from: 0xc01046fecE893706d7d70b4493DFCe8b4aC04BB2to: PatentIdea.isAlreadyHashed(string)data: 0xa87...00000
from    0xc01046fecE893706d7d70b4493DFCe8b4aC04BB2
to  PatentIdea.isAlreadyHashed(string) 0xC28d8b9152B5312719476375332C8F5064673915
input   0xa87...00000
decoded input   {
    "string idea": "UTFPR"
}
decoded output  {
    "0": "bool: true"
}
logs    []

Verificando se a cadeia "UFTPR" (errada) já foi salva na rede, a resposta é não (false).

call to PatentIdea.isAlreadyHashed
CALL
[call]from: 0xc01046fecE893706d7d70b4493DFCe8b4aC04BB2to: PatentIdea.isAlreadyHashed(string)data: 0xa87...00000
from    0xc01046fecE893706d7d70b4493DFCe8b4aC04BB2
to  PatentIdea.isAlreadyHashed(string) 0xC28d8b9152B5312719476375332C8F5064673915
input   0xa87...00000
decoded input   {
    "string idea": "UFTPR"
}
decoded output  {
    "0": "bool: false"
}
logs    []

Na interface do Ganache aparecem as transações de criação de contrato e chamada de contrato.

Lista de transações no Ganache

Agora que testamos o contrato na rede simulada do Ganache usando a Remix IDE, podemos fazer o deploy em nossa rede privada.

13.8 Implantando o contrato com o Truffle

Vamos criar o diretório do projeto ideap e inicializar a estrutura de projeto para o truffle:

$ mkdir ideap
$ cd ideap/
[ideap]$ truffle init

Starting init...
================

> Copying project files to aula-13-pratica-implementacao-patentidea-app/src/ideap

Init successful, sweet!

Try our scaffold commands to get started:
  $ truffle create contract YourContractName # scaffold a contract
  $ truffle create test YourTestName         # scaffold a test

http://trufflesuite.com/docs

Criando o contrato PatentIdea:

[ideap]$ truffle create contract PatentIdea
[ideap]$ ls
build  contracts  migrations  test  truffle-config.js
[ideap]$ tree
.
|-- contracts
    |-- PatentIdea.sol
|-- migrations
    |-- 2_deploy_contracts.js
|-- test
|-- truffle-config.js

3 directories, 4 files
[ideap]$ 

Edite o arquivo e atualize com a configuração das redes do truffle como fizemos na aula de introdução ao deploy com truffle:

// Ganache AppImage (ganache-ui).
    ganacheui: {
      host: "127.0.0.1",     // Localhost (default: none)
      port: 7545,            // Standard Ethereum port (default: none)
      network_id: "5777",       // Any network (default: none)
    },
    // RAGEtherPrivate.
    etherprivate: {
      host: "127.0.0.1",     // Localhost (default: none)
      port: 8559,            // Standard Ethereum port (default: none)
      network_id: "786",       // Any network (default: none)
    },
    // ganache ou ganache-cli (console)
    ganachecli: {
      host: "127.0.0.1",
      port: 8545,
      network_id: "2525",
    },

Crie o arquivo migrations/2_deploy_contracts.js:

[migrations]$ nano 2_deploy_contracts.js
[migrations]$ cd ..

Adicione o conteúdo:

var PatentContract = artifacts.require("PatentIdea");

module.exports = function(deployer) {
    deployer.deploy(PatentContract);
};

Compilando o contrato:

[ideap]$ truffle compile

Compiling your contracts...
===========================
> Compiling ./contracts/PatentIdea.sol

ParserError: Source file requires different compiler version (current compiler is 0.8.21+commit.d9974bed.Emscripten.clang) - note that nightly builds are considered to be strictly less than the released version
 --> project:/contracts/PatentIdea.sol:2:1:
  |
2 | pragma solidity ^0.8.22;
  | ^^^^^^^^^^^^^^^^^^^^^^^^


Error: Truffle is currently using solc 0.8.21, but one or more of your contracts specify "pragma solidity ^0.8.22".
Please update your truffle config or pragma statement(s).
(See https://trufflesuite.com/docs/truffle/reference/configuration#compiler-configuration for information on
configuring Truffle to use a specific solc compiler version.)

Compilation failed. See above.
Truffle v5.11.5 (core: 5.11.5)
Node v18.16.0
[ideap]$ truffle compile

Compiling your contracts...
===========================
> Compiling ./contracts/PatentIdea.sol
> Artifacts written to ./ideap/build/contracts
> Compiled successfully using:
   - solc: 0.8.21+commit.d9974bed.Emscripten.clang
[contracts]$ 

Estrutura de diretórios:

[ideap]$ ls
build  contracts  migrations  test  truffle-config.js
[ideap]$ tree
.
|-- build
    |-- contracts
        |-- PatentIdea.json
|-- contracts
    |-- PatentIdea.sol
|-- migrations
    |-- 2_deploy_contracts.js
|-- test
|-- truffle-config.js

6 directories, 4 files
[ideap]$
[ideap]$ truffle networks

Network: etherprivate (id: 786)
  No contracts deployed.

Network: ganachecli (id: 2525)
  No contracts deployed.

Network: ganacheui (id: 5777)
  No contracts deployed.

Criando alguns casos de teste para o contrato:

[ideap]$ truffle create test PatentIdea

Editando o arquivo /ideap/test/patent_idea_test.js:

const PatentIdeaContract = artifacts.require("PatentIdea");

contract("PatentIdea", function (/* accounts */) {
  it("has been deployed successfully", async function () {
    const patentIdea = await PatentIdeaContract.deployed();
    assert(patentIdea, "contract was not deployed");
    return assert.isTrue(true);
  });

   describe("SaveIdeaHash(string)", () => {
        it("sets string to hash and verify", async () => {
          const patentIdea = await PatentIdeaContract.deployed()
          const expected = "UTFPR";
          await patentIdea.SaveIdeaHash(expected);
          const test = await patentIdea.isAlreadyHashed(expected);
          assert.isTrue(test, expected +  " was Hashed.");
        });
    });

   describe("SaveIdeaHash(string)", () => {
        it("verify if other string was hashed", async () => {
          const patentIdea = await PatentIdeaContract.deployed()
          const str = "UFTPR";
          const test = await patentIdea.isAlreadyHashed(str);
          assert.isFalse(test, str +  " was Hashed.");
        });
    });
});

Os testes podem ser executados em uma rede simulada do truffle, com a execução do comando:

[ideap]$ truffle test
Using network 'test'.


Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


  Contract: PatentIdea
    [ok] has been deployed successfully
    SaveIdeaHash(string)
      [ok] sets string to hash and verify (75ms)
    SaveIdeaHash(string)
      [ok] verify if other string was hashed


  3 passing (128ms)

[ideap]$

Para executar o teste em uma rede como a do ganache-cli, é necessário subirmos a rede em um terminal utilizando o comando:

[~]$ ganache-cli --chain.chainId 1337 --chain.networkId 2525
ganache v7.9.1 (@ganache/cli: 0.10.1, @ganache/core: 0.10.1)
Starting RPC server

Available Accounts
==================
(0) 0x188566c9a2bEa3bEe130eec941a88E2F58AD372E (1000 ETH)
(1) 0x7FF306bEC4795773d9CcDAEB3FDABEA89bcb32B3 (1000 ETH)
(2) 0x24B599EA718e9bfa43A00616fb20b89751caf14F (1000 ETH)
(3) 0x871D453bCC42c4485e9178f2D66F7Fbef41Cfa59 (1000 ETH)
(4) 0xD3A5612196f6A0f9863D92e11A59BaeDEb1e1673 (1000 ETH)
(5) 0xF56aBA7c29FA98E4A45Dd637D54f33b2D0e417d5 (1000 ETH)
(6) 0x1faA7792f5595238230eC78b20D982db62B376B6 (1000 ETH)
(7) 0x8B3A660e88D61E056696Bdad3005E47F2DCD2311 (1000 ETH)
(8) 0xd8bed6061C7a82513e6f1573D1f3147CE7b0a5A6 (1000 ETH)
(9) 0x9133671Fa44Ed7D86B416EDEF59506C1060a2D9a (1000 ETH)

Private Keys
==================
(0) 0xa1e024afe0f4d4f65587c86d6ffc2049e2b05125e07459b22bcadf9806f76603
(1) 0xc14d7ece43014e2bf80b7cef4b3cfc1a5e4b9daf234b677ddf752fa0dc45c969
(2) 0x3a59ee6baf3edd330e995fb9b3665c0eba75dba62ca56784b7cfe9c4fe71cf64
(3) 0x30ba75dbe8dd261b087246a3a27d2cfdfb2fb42a4c68ad327be9387f4f4e6c1d
(4) 0xa98a89fd7f458f7639a6fe4e537d47ac50d9c35170c334497b8f0685d592e199
(5) 0x774aaf9b90200084cf24ceadb7918a0cc3568222027d9aa34d4babe34e0c506a
(6) 0x2b7975ae1a0ddd7ac810a37933a7fa1418d0aa1386ff26022b038457e5f555a2
(7) 0x509df6ab9cc9f583d63d3da175081a156609ddd48833fceab50ae75f6a6e4f5b
(8) 0x02902a4f802d5c9edcf14e56767cb7c99c94cfd3a1c77dc23c1a410e457e82b2
(9) 0x1887dce310d40541f2586d81039881b83380a9290d45d82dbf5b089d8eb27ff0

HD Wallet
==================
Mnemonic:      bench nasty milk balcony alpha family horse embark drama pulse situate tortoise
Base HD Path:  m/44'/60'/0'/0/{account_index}

Default Gas Price
==================
2000000000

BlockGas Limit
==================
30000000

Call Gas Limit
==================
50000000

Chain
==================
Hardfork: shanghai
Id:       1337

RPC Listening on 127.0.0.1:8545

O teste para a rede do ganache-cli pode ser executado com o comando, lembre-se de utilizar o mesmo nome dado para rede no arquivo de configuração do truffle:

[ideap]$ truffle test --network ganachecli
Using network 'ganacheui'.


Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


  Contract: PatentIdea
    [ok] has been deployed successfully
    SaveIdeaHash(string)
      [ok] sets string to hash and verify (80ms)
    SaveIdeaHash(string)
      [ok] verify if other string was hashed


  3 passing (159ms)

Fazendo o deploy na rede ganachecli com o truffle:

[ideap]$ truffle migrate --network ganachecli

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


Starting migrations...
======================
> Network name:    'ganachecli'
> Network id:      2525
> Block gas limit: 30000000 (0x1c9c380)


2_deploy_contracts.js
=====================

   Replacing 'PatentIdea'
   ----------------------
   > transaction hash:    0x92ca4da1e5a5908d6d40415b0656dc315026092071e78cf588191034b15f63f3
   > Blocks: 0            Seconds: 0
   > contract address:    0xe9D7f3727866123b0058532F21a54885C4978487
   > block number:        1
   > block timestamp:     1732053848
   > account:             0x188566c9a2bEa3bEe130eec941a88E2F58AD372E
   > balance:             999.998737658875
   > gas used:            374027 (0x5b50b)
   > gas price:           3.375 gwei
   > value sent:          0 ETH
   > total cost:          0.001262341125 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost:      0.001262341125 ETH

Summary
=======
> Total deployments:   1
> Final cost:          0.001262341125 ETH


[ideap]$ 

No terminal no qual estamos executando a rede do ganache-cli irá aparecer as mensagens de criação do contrato:

RPC Listening on 127.0.0.1:8545
eth_blockNumber
net_version
eth_accounts
eth_getBlockByNumber
eth_accounts
eth_getBlockByNumber
eth_getBlockByNumber
eth_getBlockByNumber
eth_estimateGas
eth_getBlockByNumber
eth_blockNumber
eth_estimateGas
eth_getBlockByNumber
eth_gasPrice
eth_sendTransaction

  Transaction: 0x92ca4da1e5a5908d6d40415b0656dc315026092071e78cf588191034b15f63f3
  Contract created: 0xe9d7f3727866123b0058532f21a54885c4978487
  Gas usage: 374027
  Block number: 1
  Block time: Tue Nov 19 2024 19:04:08 GMT-0300 (Horário Padrão de Brasília)

eth_getTransactionReceipt
eth_getCode
eth_getTransactionByHash
eth_getBlockByNumber
eth_getBalance

O funcionamento pode ser verificado pelo console javascript do truffle utilizando o parâmetro --network ganachecli para que o truffle se conecte à rede correta.

[ideap]$ truffle console --network ganachecli
truffle(ganachecli)> Pa
PatentIdea  parseFloat  parseInt    path

Note que o contrato PatentIdea foi criado então recupere uma instância dele.

truffle(ganachecli)> PatentIdea.deployed().then(function(instance){app = instance})
undefined

Salve o hash de alguma mensagem, no exemplo estamos salvando a cadeia "RAG".

truffle(ganachecli)> app.SaveIdeaHash("RAG")
{
  tx: '0x3533e83b69a1b9002c9c44c2c5a99918870c0c0434168751cd43d23f57c9d990',
  receipt: {
    transactionHash: '0x3533e83b69a1b9002c9c44c2c5a99918870c0c0434168751cd43d23f57c9d990',
    transactionIndex: 0,
    blockNumber: 4,
    blockHash: '0x1a5a8bb441b3283475e825b63b62947ddc65199373820d47c3f5d6f25f915e4d',
    from: '0x9ec9164906f175a0dbcc1fdebff9b632f2e14e9e',
    to: '0x68e5b9212ef39886dbd872a8d1531a515ac607f3',
    cumulativeGasUsed: 92237,
    gasUsed: 92237,
    contractAddress: null,
    logs: [ [Object] ],
    logsBloom: '0x00000000000100000000000000000000000000000000000400000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000020020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    status: true,
    effectiveGasPrice: 3090883968,
    type: '0x2',
    rawLogs: [ [Object] ]
  },
  logs: [
    {
      address: '0x68e5b9212EF39886dBD872a8d1531a515aC607f3',
      blockHash: '0x1a5a8bb441b3283475e825b63b62947ddc65199373820d47c3f5d6f25f915e4d',
      blockNumber: 4,
      logIndex: 0,
      removed: false,
      transactionHash: '0x3533e83b69a1b9002c9c44c2c5a99918870c0c0434168751cd43d23f57c9d990',
      transactionIndex: 0,
      id: 'log_243f4248',
      event: 'ideahashed',
      args: [Result]
    }
  ]
}

Verifique se a cadeia salva está na armazenada na blockchain.

truffle(ganache)> app.isAlreadyHashed("RAG");
true
truffle(ganache)> app.isAlreadyHashed("UTFPR");
false
truffle(ganache)> app.getTracker()
BN { negative: 0, words: [ 1, <1 empty item> ], length: 1, red: null }
truffle(ganache)>

Para fazer o deploy em outras redes com a rede ganacheui com o truffle:

[ideap]$ truffle migrate --network ganacheui

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


Starting migrations...
======================
> Network name:    'ganacheui'
> Network id:      5777
> Block gas limit: 6721975 (0x6691b7)


2_deploy_contracts.js
=====================

   Deploying 'PatentIdea'
   ----------------------
   > transaction hash:    0x679bfd44c6be905dbb971642bd777ad9b713f7796f7ebb3f3be1d007b46a929d
   > Blocks: 0            Seconds: 0
   > contract address:    0x58fc7f90febCA940757A46086e9474f9e9f66fdb
   > block number:        7
   > block timestamp:     1699970688
   > account:             0xc01046fecE893706d7d70b4493DFCe8b4aC04BB2
   > balance:             9999999999.991583884035123203
   > gas used:            373931 (0x5b4ab)
   > gas price:           2.932598194 gwei
   > value sent:          0 ETH
   > total cost:          0.001096589375280614 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost:     0.001096589375280614 ETH

Summary
=======
> Total deployments:   1
> Final cost:          0.001096589375280614 ETH

Na Figura 13.VI podemos ver que o contrato foi criado.

Figure 13.VI: Transação de Criação do Contrato

13.9 Criando uma interface web

13.10 Criando uma app react

Vamos criar uma interface para nossa aplicação de interação com o contrato.

[ideap]$ npx create-react-app app
Need to install the following packages:
  create-react-app@5.0.1
Ok to proceed? (y) y
npm WARN deprecated tar@2.2.2: This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.

Creating a new React app in /run/media/rogerio/BK-RAG-HP1TB/repositorios/Dropbox/dados/rogerio/UTFPR/docencia/disciplinas/2023/DLT-PPGCC17/2023-2/aulas/md/aula-16-pratica-implementacao-patentidea-app/src/ideap/app.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts with cra-template...


added 1462 packages in 2m

242 packages are looking for funding
  run `npm fund` for details

Installing template dependencies using npm...

added 69 packages, and changed 1 package in 14s

246 packages are looking for funding
  run `npm fund` for details
Removing template package using npm...


removed 1 package, and audited 1531 packages in 3s

246 packages are looking for funding
  run `npm fund` for details

8 vulnerabilities (2 moderate, 6 high)

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

Success! Created app at /run/media/rogerio/BK-RAG-HP1TB/repositorios/Dropbox/dados/rogerio/UTFPR/docencia/disciplinas/2023/DLT-PPGCC17/2023-2/aulas/md/aula-16-pratica-implementacao-patentidea-app/src/ideap/app
Inside that directory, you can run several commands:

  npm start
    Starts the development server.

  npm run build
    Bundles the app into static files for production.

  npm test
    Starts the test runner.

  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can't go back!

We suggest that you begin by typing:

  cd app
  npm start

Happy hacking!
[ideap]$ cd app
[app]$ npm start

Executando o npm start a aplicação inicial irá executar conforme a Figura XX.

Iniciando o ganache-cli e configurando as duas primeiras contas no Metamask utilizando as chaves privadas geradas:

[~]$ ganache-cli --chain.chainId 1337 --chain.networkId 2525
ganache v7.9.1 (@ganache/cli: 0.10.1, @ganache/core: 0.10.1)
Starting RPC server

Available Accounts
==================
(0) 0x9081faebf708Af86958e16f539D498BB4f6eae1E (1000 ETH)
(1) 0x8D2b059172eAA064c4bbD102Fb0c664CD2f66E2B (1000 ETH)
(2) 0xf084Df49B0e65aF8b1A989Bc5aDf420db21B9063 (1000 ETH)
(3) 0xd507327B956691BA4Fa91e681d3AE439e0B08392 (1000 ETH)
(4) 0x359962bD3279e952B5050717CA36a9E7ee2B3AcA (1000 ETH)
(5) 0x03b7ab650bEc504C3955B63086b65144700a8127 (1000 ETH)
(6) 0xb10e8E461eF41320d8D5Bb834D57bE2B1dF4850D (1000 ETH)
(7) 0x2e455ae05639406966Ed9bbD0FF18b377ee57aa4 (1000 ETH)
(8) 0xe105106c5EC7F0403d9220a69378E3db4442bb37 (1000 ETH)
(9) 0xbbcd8F43491b238f2e539CB3f28162c292B9dbE9 (1000 ETH)

Private Keys
==================
(0) 0xfb29f9cbbd092cac830bf64df1165563d57c1fa6866b2ff57f0341b5becb7da3
(1) 0x5eca3330905a7970e50fb666bc5f8f9adffc7568d4333cca64bd92a38a5b8d48
(2) 0xd52c6e2253613928c5182db95aca3dc9828699f4fbc3b34ce847f2375161882e
(3) 0x5b6ad4cc7cc45ea47b7d08bf97637be68d019fd6cc2b9603f8ffdf06a8336956
(4) 0x60ba3444b5e1fe5b4162ae2ccfc40c191223f6b6503bcf835b2b02515f4b6b48
(5) 0x289e08d4f1419e0342cce9c6ba5891abfcc9050fec73f8027c35287fa044d6c1
(6) 0x35322e9aa2fe9732d20dee21717ee8e79803b0372e9ef3878ad8c85f5f131b7d
(7) 0xed49209f63dfe470198ac6c4dcf4adac87e651fe25529926edc0b059549a543b
(8) 0x3989276caa749e46d47df4727045d5c62f754dae3e8f0903194840c87d79f7fa
(9) 0x34ce56be5d498c2ee0d1ec283480e264214044f7fdfd0c0d0836097568cd18e9

HD Wallet
==================
Mnemonic:      beauty deposit still island search fancy invite differ slab leopard shrimp tiger
Base HD Path:  m/44'/60'/0'/0/{account_index}

Default Gas Price
==================
2000000000

BlockGas Limit
==================
30000000

Call Gas Limit
==================
50000000

Chain
==================
Hardfork: shanghai
Id:       1337

RPC Listening on 127.0.0.1:8545

Teremos nesse exemplo as duas contas para efetuarmos algumas operações de consulta de saldo e transferência. A conta principal 0x9081faebf708Af86958e16f539D498BB4f6eae1E e 0x8D2b059172eAA064c4bbD102Fb0c664CD2f66E2B.

Configuração da Rede do Ganache CLI no Metamask

Configuração da Rede do Ganache CLI no Metamask

Editamos basicamente os arquivos transfer-app/src/MetaMaskService.js e transfer-app/src/App.js.

Criando um serviço de acesso com o Metamask

Código principal do App

13.11 Considerações Finais

Nesta aula vimos alguns exemplos de implantação de contratos e como podemos fazer chamadas a esses contratos.

13.12 Leitura Recomendada

14 Word Cloud

14.1 Referências