Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Coding Dojo] - Introducao a Smart contracts com Solidity #21

Open
tolstenko opened this issue May 11, 2023 · 0 comments
Open

[Coding Dojo] - Introducao a Smart contracts com Solidity #21

tolstenko opened this issue May 11, 2023 · 0 comments
Labels
Coding Dojo Coding Dojo Session

Comments

@tolstenko
Copy link
Contributor

tolstenko commented May 11, 2023

Introducao a SmartContracts com Solidity

Tema: aplicação frontend consumindo um smartcontract
Pitch: Desenvolvimento de Aplicações Descentralizadas

Sumario

  • Criar projeto Solidity com hardhat
  • Testes automatizados de Solitidy com hardhat
  • Deploy em testnet mumbai
  • Integracao com frontent react

Atividade:

Seguir documentacao https://hardhat.org/tutorial/creating-a-new-hardhat-project

mkdir smartocntracts-tuto
cd smartocntracts-tuto
npm init # setup the way you prefer
npx hardhat # select create typescript project

Seguir documentacao https://www.npmjs.com/package/@typechain/hardhat

npm install --save-dev typechain @typechain/hardhat @typechain/ethers-v5

Adicione no arquivo hardhat.config.ts

import '@typechain/hardhat'
import '@nomiclabs/hardhat-ethers'

Delete Lock.sol na pasta contracts e tbm Lock.ts da pasta testes. Crie um contrato simples de greet.ts na pasta contracts:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

contract Greeter {
    constructor() {}

    function greet() public pure returns (string memory) {
        return "Hello, World!";
    }
}

bash:

npx hardhat compile

Agora vamos integrar ao front!
O melhor caminho eh criar testes automatizados via typescript. Depois de criar as funcionalidades ja testadas, basta copiar o fluxo testado pro front e acoplar em algum botao.

Crie um arquivo na pasta test como greeter.ts

import { expect } from "chai";
import { ethers } from "hardhat";
import {Greeter__factory} from "../typechain-types";
import {Greeter} from "../typechain-types";

describe("Greeter", function () {
    let greeter: Greeter;

    async function deployGreeter() {
        const Greeter: Greeter__factory = await ethers.getContractFactory("Greeter") as Greeter__factory;
        const [owner, otherAccount] = await ethers.getSigners();
        greeter = await Greeter.deploy();
        return ;
    }

    beforeEach(async function () {
        await deployGreeter();
    });

    describe("Hello Test", function () {
        it("Should print \"Hello World!\"", async function () {
            let response = await greeter.greet();
            await expect(response).equal( "Hello, World!");
        });
    });
});

Rode os testes:

hardhat test

Se tudo tiver certo, faca deploy do contrato, recomendo testnet polygon. Edite o orquivo deploy.ts da pasta scripts. Para efetivamente fazer deploy do contrato.

import { ethers } from "hardhat";
import { Greeter__factory } from "../typechain-types";
import { Greeter } from "../typechain-types";

async function main() {
  const Greeter: Greeter__factory = await ethers.getContractFactory("Greeter") as Greeter__factory;
  const [owner, otherAccount] = await ethers.getSigners();
  let greeter: Greeter = await Greeter.deploy();
  await greeter.deployed();

  console.log(`Greeter deployed to ${greeter.address}`);
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Pra que o contrato seja deployado em alguma chain, digamos polygon testnet, vc precisara das credenciais da wallet.

Pra isso crie um arquivo .env coloque ele no .gitignore e adicione o seu mnemonic phrase la. Se voce nao tiver uma wallet, recomendo criar uma apenas para este fim agora e salvar no arquivo .env. Como vamos usar .env nao esqueca de instalar o pacote dotenv com npm install --save-dev dotenv.

Para usar o contrato no navegador a forma mais simple eh adicionar a extensao metamask. Apos isto, importe suas chaves na metamask(criado no passo anterior) ou crie uma por la.

Use esse hardhat.config.ts que ele ja esta configurado para usar testnet da polygon e outras chains.

import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import '@typechain/hardhat'
import '@nomiclabs/hardhat-ethers'
import * as dotenv from "dotenv";
import { resolve } from "path";
import { Wallet } from "ethers";
import * as fs from 'fs';

dotenv.config({ path: resolve(__dirname, "./.env") });

let mnemonic = process.env.MNEMONIC || "";
let wallet:Wallet;
if(mnemonic)
  wallet = Wallet.fromMnemonic(mnemonic);
else {
  mnemonic = Wallet.createRandom().mnemonic.phrase;
  wallet = Wallet.fromMnemonic(mnemonic);
  console.warn("RANDOM MNEMONIC used: " + mnemonic);
  console.warn("PRIVATE KEY used: " + wallet.privateKey);
  console.warn("WALLET ADDR used: " + wallet.address);
  fs.writeFileSync(resolve(__dirname, "./.env"), `MNEMONIC="${mnemonic}"\nPRIVATEKEY="${wallet.privateKey}"\nWALLETADDRESS="${wallet.address}"\n`);
}

const config: HardhatUserConfig = {
  solidity: {
    compilers: [
      {
        version: "0.8.18",
        settings: {
          metadata: {
            bytecodeHash: "none",
          },
          optimizer: {
            enabled: true,
            runs: 800,
          },
        },
      }
    ],
  },
  networks: {
    local: {
      url: "http://localhost:8545",
      accounts: { mnemonic },
    },
    bsctest: {
      url: "https://data-seed-prebsc-1-s1.binance.org:8545",
      chainId: 97,
      accounts: { mnemonic },
    },
    bsc: {
      url: "https://bsc-dataseed.binance.org/",
      chainId: 56,
      accounts: { mnemonic },
    },
    mumbai: {
      url: "https://polygon-mumbai.blockpi.network/v1/rpc/public",
      chainId: 80001,
      accounts: { mnemonic },
    },
    hardhat: {
      accounts: { mnemonic },
    },
  },
  gasReporter: {
    enabled: process.env.REPORT_GAS !== undefined,
    currency: "USD",
  },
  typechain: {
    outDir: "typechain-types",
    target: "ethers-v5",
  },
  paths: {
    artifacts: "./artifacts",
    cache: "./cache",
    sources: "./contracts",
    tests: "./test",
  },
};

export default config;

Adicione a mumbai a sua wallet aqui https://chainlist.org/chain/80001

Se voce nao tiver tokens na wallet que vc estiver usando, precisamos adicionar fundos, no caso da polygon mumbai, adicione fundos aqui. https://faucet.polygon.technology/

Para deployar para a polygon testnet basta rodar agora com tudo configurado:

hardhat run --network mumbai scripts/deploy.ts

Guarde o endereco do contrato pois vamos usar ele na integracao com o front. No meu caso o endereco do contrato gerado foi: "0xe720699f67778FBF021B3a5C6C5092ea4e5c3087"

Agora vamos integrar o contrato ao front.

Crie o projeto com a stack typescript que melhor lhe convir. Recomendo react. Copie toda a pasta typechain-types para o seu sources pois vamos usar ele.

Se voce estiver na pasta do smartcontracts-tuto acima, volte um nivel com cd ...

Para criar um esqueleto com react, vc pode usar:

npx create-react-app react-demo --template typescript

Agora copie o typechain-types da sua pasta smartcontracts-tuto para a nova pasta do react-demo recem criada dentro da subpasta src.

Na pasta do react-demo, instale @nomicfoundation/hardhat-toolbox via npm install --save @nomicfoundation/hardhat-toolbox.

Altere o App.tsx para chamar o greeter.

import React from 'react';
import logo from './logo.svg';
import './App.css';
import {Greeter, Greeter__factory} from './typechain-types';
import {ethers, Wallet} from 'ethers';

async function connect() {
  console.log('clicked');
  (window as any).ethereum.request({ method: 'eth_requestAccounts' });
}

async function callGreet(){
  const provider = new ethers.providers.Web3Provider((window as any).ethereum);
  const contract = Greeter__factory.connect('0xe720699f67778FBF021B3a5C6C5092ea4e5c3087', provider);
  let ret = await contract.greet();
  console.log(ret);
  alert(ret);
}

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
        <button onClick={() => connect()}>Connect to Metamask</button>
        <button onClick={() => callGreet()}>Call Greet</button>
      </header>
    </div>
  );
}

export default App;

E pronto basta voce editar seu contrato e usar ele como achar melhor no seu frontend.

image image
@tolstenko tolstenko added the Coding Dojo Coding Dojo Session label May 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Coding Dojo Coding Dojo Session
Projects
None yet
Development

No branches or pull requests

1 participant