Como você pode construir um aplicativo de transação Ethereum com React e Solidity: Half 2

Escrito por Otávio Vieira em

Introdução

Seguindo a metade deste tutorial, podemos estar construindo a faceta front-end desta missão. Se você ainda não viu a PARTE UM , recomendo que o faça para entender esta parte dois.

Se você estiver preparado, vamos esmagar este aplicativo…

Configuração do empreendimento

Certifique-se de que você já instalou o NodeJs em sua máquina, se você não tiver, siga o link abaixo para fazer isso.

Vá para a lista de tarefas e crie uma nova pasta chamada “dalto”. Você pode intitular o que quiser, mas por uma questão de uniformidade, aconselho você a se mover comigo sobre os nomes.

Dentro desta listagem dalto , crie duas pastas extras denominadas consumer e smart_contract , nosso código ethereum residirá na pasta smart_contract, enquanto o aplicativo react residirá na listagem do consumidor. Por fim, abra esta missão em seu editor de código, escolho VS Code . Se você fez tudo isso corretamente, a construção de sua missão deve ser assim.

Empreendendo a construção
Os códigos precisam ser estruturados da seguinte maneira.

A configuração sensata do contrato

Salte para o terminal, transfira (cd) para a listagem smart_contract e execute o comando abaixo.

npm init -y

Ele criará um arquivo npm na raiz da pasta smart_contract . Para especificar os pacotes a serem usados ​​para construir o contrato sensato, vamos executar o trecho de código abaixo.

yarn add @nomiclabs/hardhat-ethers @nomiclabs/hardhat-waffle chai ethereum-waffle ethers hardhat --dev
# or
npm set up -D @nomiclabs/hardhat-ethers @nomiclabs/hardhat-waffle chai ethereum-waffle ethers hardhat

Observe que esses pacotes são listados apenas na atmosfera de melhoria.
Após a conclusão da configuração, você deve ter uma consequência muito parecida com a minha.

 

Pacote smart_contract.json

 

Agora você pode querer executar o código abaixo para organizar o capacete dentro da pasta smart_contract atual.

yarn hardhat
# or
npm hardhat

Você pode ser solicitado com algumas perguntas, é melhor escolher as próximas opções.

  • Crie uma missão de padrão fundamental quando solicitado o que você precisa fazer.
  • Especifique a listagem atual quando solicitado para a pasta de fundação, esta seleção é pré-preenchida no terminal para você.
  • Digite ‘y’ quando solicitado se desejar adicionar um .gitIgnore e pressione Enter no teclado.

Quando você especificar as opções acima corretamente, o capacete irá gerar rotineiramente a construção da missão para você.

Processando o contrato sensato
Em seguida, vá para a lista smart_contract >> contratos e renomeie o arquivo Greeter.sol para Transactions.sol . Depois cole os códigos abaixo nele, salve e transfira comigo.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Transactions {
    tackle personal proprietor;
    uint256 transactionCounts;
    mapping (tackle => uint) balanceOf;

    occasion Switch(tackle listed sender, tackle listed receiver, uint256 quantity, string comment, uint256 timestamp);

    struct TransferStruct {
        tackle sender;
        tackle receiver;
        uint256 quantity;
        string comment;
        uint256 timestamp;
    }
    
    TransferStruct[] transactions;

    constructor() {
        proprietor = msg.sender;
        balanceOf[tx.origin] = msg.sender.steadiness;
    }

    perform getOwner() public view returns (tackle) {
        return proprietor;
    }

    perform sendMoney(tackle payable receiver, uint256 quantity, string reminiscence comment) public returns(bool success) {
        if (balanceOf[owner] < quantity) return false;
        balanceOf[owner] -= quantity;
        balanceOf[receiver] += quantity;

        transactionCounts += 1;
        transactions.push(
            TransferStruct(
                proprietor,
                receiver,
                quantity,
                comment,
                block.timestamp
            )
        );

        emit Switch(msg.sender, receiver, quantity, comment, block.timestamp);
        return true;
    }

    perform getBalance(tackle addr) public view returns(uint) {
        return balanceOf[addr];
    }

    perform getAllTransactions() public view returns(TransferStruct[] reminiscence) {
        return transactions;
    }

    perform getTransactionsCount() public view returns(uint256) {
        return transactionCounts;
    }
}

Organising the Deployment Script
Head to smart_contract listing >> scripts and renaming the sample-script.js file to deploy.js. Afterward, substitute the codes beneath in it. The code snippet beneath specifies the place our sensible contract will reside on the internet.

const hre = require('hardhat')
const important = async () => {
  const Transactions = await hre.ethers.getContractFactory('Transactions')
  const transactions = await Transactions.deploy()
  await transactions.deployed()
  console.log('Transactions deployed to:', transactions.tackle)
}
const runMain = async () => {
  strive {
    await important()
    course of.exit(0)
  } catch (error) {
    console.error(error)
    course of.exit(1)
  }
}
runMain()

Unbelievable work, presently it is best to have already got your Rinkeby take a look at community funded and prepared to be used, for those who haven’t, please return to the PART-ONE of this tutorial, you can see the instruction there.

Now it is time to learn about alchemy…

Deploying to Alchemy

 

Alchemy Blockchain Improvement and Deployment

 

Atualmente, nosso contrato inteligente pode ser executado apenas em nosso laptop e terceiros não podem se conectar a ele. Para torná-lo acessível a todos gratuitamente, vamos usar a alquimia para isso.

Prossiga inscrevendo-se com eles ou LOG ​​IN se você já tiver uma conta.

Assim que você estiver conectado, você verá a página do painel que fornece acesso para criar um novo utilitário blockchain.

Criando um aplicativo Alchemy
Clique no botão CRIAR APLICATIVO e preencha os detalhes que você precisa, conforme a imagem abaixo, certifique- se de especificar a comunidade de teste Rinkeby .

Depois de criar o aplicativo, clique no título do aplicativo ou visualize o botão de letras pequenas para ver os dados do aplicativo.

Clique no botão VIEW KEY e copie o URL HTTP como visto na imagem abaixo.

Incrível, agora siga as etapas mostradas nas fotos abaixo para obter sua conta Rinkeby. Observe que não estamos usando o endereço de conta comum, mas a chave pessoal dessa conta.

Bom , agora volte ao código VS >> smart_contract >> hardhat.config.js e substitua seu conteúdo pelos códigos abaixo. Use seu URL individual em vez do atual no arquivo.

require('@nomiclabs/hardhat-waffle')
module.exports = {
  solidity: '0.8.0',
  networks: {
    rinkeby: {
      url: '<YOUR_ALCHEMY_APP_URL_GOES_HERE>',
      accounts: [
        '<YOUR_RINKEBY_ACCOUNT_PRIVATE_KEY_GOES_HERE>',
      ],
    },
  },
}

Se você tivesse feito tudo isso corretamente, basta fazer outra coisa antes de transferir para o front-end parte desta missão. Vamos implantar este contrato sensato no Alchemy, execute o código abaixo, certifique-se de que seu terminal esteja na listagem smart_contract .

yarn hardhat run scripts/deploy.js --network rinkeby
or
npx hardhat run scripts/deploy.js --network rinkeby

Depois que o contrato sensato for implantado com sucesso na Alquimia, você deve ter o endereço do contrato sensato que verá destacado na imagem abaixo.

Copie e salve esse endereço, ele deve ser usado posteriormente na lista de consumidores >> utils >> arquivo constants.js .

Parabéns, você acabou de realizar a implantação sensata do contrato, agora vamos usá-lo em nosso utilitário de front-end.

A configuração do front-end

 

Utilizando o Vite React no Frontend

 

Abra o terminal, entre na lista do consumidor e siga as próximas instruções. Para o front-end, vamos usar o Vite para criar nosso utilitário de reação, o Vite é um conjunto de ferramentas superior que facilita o método de tornar seu utilitário de front-end.

Para esta construção, podemos até usar o Yarn como nosso principal supervisor de pacotes, é simplesmente muito melhor colocar pacotes npm. Observe, todas as instruções de fio podem ser simplesmente executadas com npm também. Você simplesmente deve fazer um pequeno ajuste. Agora vamos configurar o Vite quando você não tiver.

yarn create vite
# or
npm init [email protected]

Você pode ser solicitado a inserir o título da sua missão, simplesmente use “ ./ ”. Ele instruirá o Vite a obter os códigos na lista atual (consumidor) . Em seguida, você será solicitado a fornecer o título da missão, basta digitar “ Dalto ” e, em seguida, escolher reagir na lista de verificação de estruturas disponíveis. Veja a imagem abaixo para direção.

Após as execuções acima serem realizadas no terminal, execute o comando abaixo para colocar os módulos npm para uso em nossa missão.

yarn set up
# or
npm set up

Colocando em Dependências de Empreendimento

Depois que o método for concluído no terminal, mais uma vez você deve inserir os próximos pacotes dos quais nosso utilitário depende.

yarn add @heroicons/react ethers @faker-js/faker identicon.js react-hooks-global-state
# or
npm set up @heroicons/react ethers @faker-js/faker identicon.js react-hooks-global-state

Depois de inserir esses pacotes, você pode ser ótimo, vamos prosseguir para inserir o CSS de cauda do qual nosso utilitário também depende.

Colocando no Tailwind CSS

Use as instruções abaixo para tentar isso.

yarn add tailwindcss postcss autoprefixer --dev
yarn tailwindcss init
# or
npm set up -D tailwindcss postcss autoprefixer
npx tailwindcss init

Você precisa ter duas informações na raiz da pasta do consumidor . tailwind.config.js e postcss.config.js , no entanto, para aqueles que não, você pode criá-los você mesmo.

A seguir, substitua o conteúdo das 2 informações pelos próximos códigos.

# postcss.config.js
const tailwindcss = require('tailwindcss')
module.exports = {
  plugins: [tailwindcss('./tailwind.config.js'), require('autoprefixer')],
}


# tailwind.config.js
module.exports = {
  content material: [
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    prolong: {},
  },
  plugins: [],
}

Agora, substitua o conteúdo do arquivo index.css na lista de clientes >> src pelos códigos abaixo.

@tailwind base;
@tailwind parts;
@tailwind utilities;

Very effectively, let’s take a look at the app to see if the whole lot is working proper by operating the code beneath.

# Working the appliance
yarn dev
# or
npm run dev

Should you did the whole lot proper, it is best to have the identical consequence as mine.

Epic work to date, let’s begin coding. We are going to proceed by coding up the parts.

Coding the Elements

We’ve got 4 parts and we are going to start with the Header part. Earlier than we do this, go to the consumer listing >> src and create a folder referred to as parts. That is the place all our parts will reside.

Header Element

Crie uma parte denominada Header.jsx . Esta parte compreende o botão enviar que é usado para iniciar o modal addTransactionCard para entrar em novas transações. Veja o bloco de código abaixo.

import ethLogo from '../belongings/ethlogo.png'
import { setGlobalState } from '../retailer'

const Header = () => {
  return (
    <header className="flex flex-row items-center justify-between drop-shadow-md py-2 px-5 bg-white">
      <div className="flex flex-row justify-center items-center cursor-pointer">
        <img
          className="w-6 h-6 object-contain cursor-pointer"
          src={ethLogo}
          alt="Etherium Emblem"
        />
        <span>Dalto</span>
      </div>
      <nav className="flex flex-row justify-center items-center list-none">
        <li className="cursor-pointer mr-3 hover:text-blue-500">Pricing</li>
        <li className="cursor-pointer mr-3 hover:text-blue-500">Docs</li>
        <li className="cursor-pointer mr-3">
          <button
            onClick={() => setGlobalState('modal', 'scale-100')}
            className="text-white bg-blue-500 py-2 px-5 rounded-xl drop-shadow-xl border border-transparent hover:bg-transparent hover:text-blue-500 hover:border hover:border-blue-500 focus:outline-none focus:ring"
          >
            Ship
          </button>
        </li>
      </nav>
    </header>
  )
}

export default Header

Excelente, vamos criar a parte AddTransactionCard .

Elemento AddTransactionCard

No entanto, na lista de peças, crie outra parte chamada AddTransactionCard.jsx , depois cole os códigos abaixo nela e salve. Vamos usar esta parte modal para criar novas transações. Um consumidor pode iniciá-lo sempre que o botão enviar na parte do cabeçalho for clicado.

import { useGlobalState, setGlobalState } from '../retailer'
import { useState } from 'react'
import { sendMoney } from '../shared/Transaction'

const AddTransactionCard = () => {
  const [modal] = useGlobalState('modal')
  const [connectedAccount] = useGlobalState('connectedAccount')
  const [address, setAddress] = useState('')
  const [amount, setAmount] = useState('')
  const [remark, setRemark] = useState('')
  const [loading, setLoading] = useState(false)

  const handleSubmit = () => {
    if (!tackle || !quantity || !comment) return
    setLoading(true)

    sendMoney({ connectedAccount, tackle, quantity, comment })
      .then(() => {
        setGlobalState('transaction', { tackle, quantity, comment })
        setLoading(false)
        setGlobalState('modal', '')
        resetForm()
      })
      .catch((error) => {
        setLoading(false)
        console.log(error)
      })
  }

  const resetForm = () => {
    setAddress('')
    setAmount('')
    setRemark('')
  }

  return (
    <div
      className={`fastened top-0 left-0 w-screen h-screen flex items-center justify-center bg-black bg-opacity-50 rework scale-0 transition-transform duration-300 ${modal}`}
    >
      <div className="bg-white rounded-xl w-1/3 h-7/12 p-6">
        <div className="flex flex-col">
          <div className="flex flex-row justify-between items-center">
            <p className="font-semibold text-gray-800">Add a step</p>
            <button
              onClick={() => setGlobalState('modal', '')}
              className="border-0 bg-transparent focus:outline-none"
            >
              <svg
                className="w-6 h-6"
                fill="none"
                stroke="currentColor"
                viewBox="0 0 24 24"
                xmlns="http://www.w3.org/2000/svg"
              >
                <path
                  strokeLinecap="spherical"
                  strokeLinejoin="spherical"
                  strokeWidth="2"
                  d="M6 18L18 6M6 6l12 12"
                ></path>
              </svg>
            </button>
          </div>

          <div className="flex flex-row justify-between items-center bg-gray-100 rounded-xl p-3 mt-5">
            <enter
              className="bg-transparent focus:outline-none w-full"
              sort="textual content"
              title="tackle"
              placeholder="Handle To"
              onChange={(e) => setAddress(e.goal.worth)}
              worth={tackle}
            />
          </div>

          <div className="flex flex-row justify-between items-center bg-gray-100 rounded-xl p-3 mt-5">
            <enter
              className="bg-transparent focus:outline-none w-full"
              sort="quantity"
              step={0.0001}
              title="quantity"
              placeholder="Quantity (Eth)"
              onChange={(e) => setAmount(e.goal.worth)}
              worth={quantity}
            />
          </div>

          <div className="flex flex-row justify-between items-center bg-gray-100 rounded-xl p-3 mt-5">
            <enter
              className="bg-transparent focus:outline-none w-full"
              sort="textual content"
              title="comment"
              placeholder="Comment"
              onChange={(e) => setRemark(e.goal.worth)}
              worth={comment}
            />
          </div>

          <div className="flex flex-row justify-between items-centerrounded-xl mt-5">
            {!loading ? (
              <button
                sort="submit"
                onClick={handleSubmit}
                className="flex flex-row justify-center items-center w-full text-white text-lg bg-blue-500 py-2 px-5 rounded-xl drop-shadow-xl border border-transparent hover:bg-transparent hover:text-blue-500 hover:border hover:border-blue-500 focus:outline-none focus:ring"
              >
                Ship Cash
              </button>
            ) : (
              <button
                className="flex flex-row justify-center items-center w-full text-white text-lg bg-blue-300 py-2 px-5 rounded-xl drop-shadow-xl border border-transparent focus:outline-none focus:ring"
                disabled
              >
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  width="30px"
                  peak="30px"
                  viewBox="0 0 100 100"
                  preserveAspectRatio="xMidYMid"
                >
                  <path
                    d="M10 50A40 40 0 0 0 90 50A40 42 0 0 1 10 50"
                    fill="white"
                    stroke="none"
                  >
                    <animateTransform
                      attributeName="rework"
                      sort="rotate"
                      dur="1s"
                      repeatCount="indefinite"
                      keyTimes="0;1"
                      values="0 50 51;360 50 51"
                    ></animateTransform>
                  </path>
                </svg>
                Sending...
              </button>
            )}
          </div>
        </div>
      </div>
    </div>
  )
}

export default AddTransactionCard

Bom, vamos criar o restante das partes.

Elemento do Herói

Crie outra peça com o título Hero.jsx dentro da pasta parts. Esta parte contém as descrições do que este utilitário faz. Ele não tem nenhum desempenho específico, mas oferece o melhor do design do nosso aplicativo. Cole os códigos abaixo nele e salve.

import { LightningBoltIcon, ScaleIcon } from '@heroicons/react/define'

const Hero = () => {
  const options = [
    {
      name: 'No hidden fees',
      description:
        'Sending money is free of charge, you have no need for a middle man or annoying taxes.',
      icon: ScaleIcon,
    },
    {
      name: 'Transfers are instant',
      description:
        'You do not have to wait for days anymore, you can get you money in seconds within any country in the world',
      icon: LightningBoltIcon,
    },
  ]

  return (
    <div className="py-12 bg-white">
      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div className="lg:text-center">
          <p className="mt-2 text-3xl leading-8 font-extrabold tracking-tight text-gray-900 sm:text-4xl">
            A greater strategy to ship cash
          </p>
          <p className="mt-4 max-w-2xl text-xl text-gray-500 lg:mx-auto">
            Discover the crypto world. Purchase and promote cryptocurrencies simply on
            Dalto.
          </p>
        </div>

        <div className="mt-10">
          <dl className="space-y-10 md:space-y-0 md:grid md:grid-cols-2 md:gap-x-8 md:gap-y-10">
            {options.map((characteristic) => (
              <div key={characteristic.title} className="relative">
                <dt>
                  <div className="drop-shadow-xl absolute flex items-center justify-center h-12 w-12 rounded-md bg-blue-500 text-white">
                    <characteristic.icon className="h-6 w-6" aria-hidden="true" />
                  </div>
                  <p className="ml-16 text-lg leading-6 font-medium text-gray-900">
                    {characteristic.title}
                  </p>
                </dt>
                <dd className="mt-2 ml-16 text-base text-gray-500">
                  {characteristic.description}
                </dd>
              </div>
            ))}
          </dl>
        </div>
      </div>
    </div>
  )
}

export default Hero

Por último, vamos criar a parte Tabular.

elemento tabular

Crie uma peça com o título Tabular.jsx dentro da pasta de peças e cole os códigos abaixo nela. Esta parte é responsável por processar todas as transações registradas em nossa comunidade blockchain. Observe o código abaixo.

import { useEffect, useState } from 'react'
import ethLogo from '../belongings/ethlogo.png'
import Identicon from 'identicon.js'
import faker from '@faker-js/faker'
import { getAllTransactions } from '../shared/Transaction'
import { useGlobalState } from '../retailer'

const Tabuler = () => {
  const [transactionsStore] = useGlobalState('transactions')
  const [transactionCount] = useGlobalState('transactionCount')
  const [transactions, setTransaction] = useState([])
  const [start, setStart] = useState(0)
  const [end, setEnd] = useState(6)

  const makeImage = (tackle) => {
    const knowledge = new Identicon(tackle, 400).toString()
    return `knowledge:picture/png;base64,${knowledge}`
  }

  const loadMoreTransactions = () => {
    setTransaction((prevState) => [
      ...prevState,
      ...transactionsStore.slice(start, end),
    ])
    setStart(finish)
    setEnd(finish * 2)
  }

  const shortenAddress = (tackle) =>
    `${tackle.slice(0, 5)}...${tackle.slice(tackle.size - 4)}`

  useEffect(() => {
    getAllTransactions().then((knowledge) => {
      setTransaction([...data.slice(start, end)])
      setStart(finish)
      setEnd(finish * 2)
    })
  }, [])

  return (
    <>
      <part className="antialiased rounded-xl text-gray-600 p-5">
        <div className="flex flex-col justify-center h-full">
          <div className="max-w-full mx-auto px-4 sm:px-6 lg:px-8 bg-white shadow-2xl rounded-xl">
            <header className="px-5 py-4">
              <h2 className="font-semibold text-gray-800 text-center">
                Whole Transactions({transactionCount})
              </h2>
            </header>
            <div className="p-3">
              <div className="overflow-x-auto">
                <desk className="table-auto w-full">
                  <thead className="text-xs font-semibold uppercase text-gray-400 bg-gray-50">
                    <tr>
                      <th className="p-2 whitespace-nowrap">
                        <div className="font-semibold text-left">Title</div>
                      </th>
                      <th className="p-2 whitespace-nowrap">
                        <div className="font-semibold text-left">Sender</div>
                      </th>
                      <th className="p-2 whitespace-nowrap">
                        <div className="font-semibold text-left">Receiver</div>
                      </th>
                      <th className="p-2 whitespace-nowrap">
                        <div className="font-semibold text-left">Quantity</div>
                      </th>
                      <th className="p-2 whitespace-nowrap">
                        <div className="font-semibold text-left">Timestamp</div>
                      </th>
                      <th className="p-2 whitespace-nowrap">
                        <div className="font-semibold text-center">Comment</div>
                      </th>
                    </tr>
                  </thead>
                  <tbody className="text-sm divide-y divide-gray-100">
                    {transactions.map((tx, index) => (
                      <tr key={index + 1}>
                        <td className="p-2 whitespace-nowrap">
                          <div className="flex items-center">
                            <div className="w-10 h-10 flex-shrink-0 mr-2 sm:mr-3">
                              <img
                                className="rounded-full"
                                src={makeImage(tx.sender)}
                                width="40"
                                peak="40"
                                alt="Alex Shatov"
                              />
                            </div>
                            <div className="font-medium text-gray-800">
                              {faker.title.findName()}
                            </div>
                          </div>
                        </td>
                        <td className="p-2 whitespace-nowrap">
                          <div className="text-left">
                            <a
                              href={`https://ropsten.etherscan.io/tackle/${tx.sender}`}
                              goal="_blank"
                              rel="noreferrer"
                              className="hover:text-blue-500"
                            >
                              {shortenAddress(tx.sender)}
                            </a>
                          </div>
                        </td>
                        <td className="p-2 whitespace-nowrap">
                          <div className="text-left">
                            <a
                              href={`https://ropsten.etherscan.io/tackle/${tx.receiver}`}
                              goal="_blank"
                              rel="noreferrer"
                              className="hover:text-blue-500"
                            >
                              {shortenAddress(tx.receiver)}
                            </a>
                          </div>
                        </td>
                        <td className="p-2 whitespace-nowrap">
                          <div className="flex flex-row justify-center items-center text-left font-medium">
                            <img
                              className="w-3 h-3 object-contain cursor-pointer mr-1"
                              src={ethLogo}
                              alt="Etherium Emblem"
                            />
                            <span className="text-green-500">{tx.quantity}</span>
                          </div>
                        </td>
                        <td className="p-2 whitespace-nowrap">
                          <div className="text-sm text-center">
                            {tx.timestamp}
                          </div>
                        </td>
                        <td className="p-2 whitespace-nowrap">
                          <div className="text-sm text-center">{tx.comment}</div>
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </desk>
              </div>
            </div>
          </div>
        </div>
      </part>
      <div className="text-center mt-5 mb-10">
        <button
          onClick={loadMoreTransactions}
          className="text-white bg-blue-500 py-2 px-5 rounded-xl drop-shadow-xl border border-transparent hover:bg-transparent hover:text-blue-500 hover:border hover:border-blue-500 focus:outline-none focus:ring"
        >
          Load extra
        </button>
      </div>
    </>
  )
}

export default Tabuler

Todas essas partes são unificadas por um único varejista de conhecimento, utilizando o pacote react -hooks-global-state npm. Agora vamos transmitir coletivamente as partes acima para a parte App .

O elemento do aplicativo

Os códigos abaixo unem todas as partes e trabalham juntas.

import { useEffect } from 'react'
import AddTransactionCard from './parts/AddTransactionCard'
import Header from './parts/Header'
import Hero from './parts/Hero'
import Tabuler from './parts/Tabuler'
import {
  isWallectConnected,
  checkIfTransactionExist,
  connectWallet,
} from './shared/Transaction'
import { useGlobalState } from './retailer'

const App = () => {
  const [connectedAccount] = useGlobalState('connectedAccount')
  useEffect(() => {
    isWallectConnected()
    checkIfTransactionExist()
  }, [])

  return (
    <div className="flex flex-col min-h-screen">
      <Header />
      <Hero />
      {!connectedAccount ? (
        <div className="text-center mb-10">
          <button
            onClick={connectWallet}
            className="text-white bg-blue-500 py-2 px-5 rounded-xl drop-shadow-xl border border-transparent hover:bg-transparent hover:text-blue-500 hover:border hover:border-blue-500 focus:outline-none focus:ring"
          >
            Join Pockets
          </button>
        </div>
      ) : (
        <>
          <Tabuler />
          <AddTransactionCard />
        </>
      )}
    </div>
  )
}

export default App

Legal, o código acima une todas as nossas partes, mas e quanto ao controle de estado? Como é acoplado coletivamente? Vamos dar uma olhada na configuração do varejista react-hooks-global-state .

O Varejista do Conhecimento

Vá para a lista consumidor >> src e crie uma pasta chamada varejista. Dentro desta pasta do varejista, crie um arquivo chamado index.jsx e cole os códigos abaixo nele.

import { createGlobalState } from 'react-hooks-global-state'
const { setGlobalState, useGlobalState } = createGlobalState({
  modal: '',
  connectedAccount: '',
  transactions: [],
  transaction: {
    tackle: '',
    quantity: '',
    comment: '',
  },
  transactionCount: localStorage.getItem('transactionCount'),
})
export { useGlobalState, setGlobalState }

Ótimo, esse pacote de administração de estado fácil elimina todas as complexidades do Redux ou da API de contexto. Esse é o lugar onde armazenamos todas as nossas transações e mantemos o controle da conta relacionada.

Should you’ve gotten up so far, you deserve a cup of espresso, let’s work on the subsequent half.

The Software Utilities

Head to the consumer folder >> src listing and create a brand new folder referred to as utils. Now, inside this utils folder create two information referred to as constants.js and Transactions.json. The JSON file comprises the Software Binary Interface (ABI) which was generated by hardhat and the js file will put together it for exports.

The ABI is generated by hardhat after compilation, it describes our sensible contract and prepares it in a approach it may be understood by ethers.js.

On the smart_contract listing goto >> artifacts >> contracts >> Transactions.sol >> Transactions.json. You’ll copy all the codes on this file and paste them in consumer >> src >> utils >> Transactions.json.

Subsequent, paste the code beneath into the constants.js file.

import abi from './Transactions.json'
export const contractAbi = abi.abi
export const contractAddress = '<YOUR_DEPLOYED_SMART_CONTRACT_ADDRESS_GOES_HERE>'

Superior, I do know this has been intense, however be cool, we’re virtually ending up.

The Sensible Contract Assets

Este arquivo nos oferece todas as estratégias existentes no arquivo Transactions.sol . Essas estratégias nos ajudarão a interagir com o aplicativo blockchain usando a biblioteca ethers.js e o URL que copiamos do Alchemy.

Crie uma pasta chamada shared dentro da lista de consumidores >> src. Crie um arquivo chamado Transaction.jsx e cole os códigos abaixo nele.

import { ethers } from 'ethers'
import { setGlobalState } from '../retailer'

import { contractAbi, contractAddress } from '../utils/constants'

const { ethereum } = window

const getEtheriumContract = () => {
  const supplier = new ethers.suppliers.Web3Provider(ethereum)
  const signer = supplier.getSigner()
  const transactionContract = new ethers.Contract(
    contractAddress,
    contractAbi,
    signer
  )

  return transactionContract
}

const isWallectConnected = async () => {
  strive {
    if (!ethereum) return alert('Please set up Metamask')
    const accounts = await ethereum.request({ technique: 'eth_accounts' })

    if (accounts.size) {
      setGlobalState('connectedAccount', accounts[0])
    } else {
      console.log('No accounts discovered.')
    }
  } catch (error) {
    console.log(error)
    throw new Error('No ethereum object.')
  }
}

const checkIfTransactionExist = async () => {
  strive {
    const transactionContract = getEtheriumContract()
    const transactionCount = await transactionContract.getTransactionsCount()

    window.localStorage.setItem('transactionCount', transactionCount)
  } catch (error) {
    console.log(error)
    throw new Error('No ethereum object.')
  }
}

const connectWallet = async () => {
  strive {
    if (!ethereum) return alert('Please set up Metamask')
    const accounts = await ethereum.request({ technique: 'eth_requestAccounts' })
    setGlobalState('connectedAccount', accounts[0])
  } catch (error) {
    console.log(error)
    throw new Error('No ethereum object.')
  }
}

const sendMoney = async ({ connectedAccount, tackle, quantity, comment }) => {
  strive {
    if (!ethereum) return alert('Please set up Metamask')
    const transactionContract = getEtheriumContract()
    const parsedAmount = ethers.utils.parseEther(quantity)

    await ethereum.request({
      technique: 'eth_sendTransaction',
      params: [
        {
          from: connectedAccount,
          to: address,
          gas: '0x5208',
          value: parsedAmount._hex,
        },
      ],
    })

    const transactionHash = await transactionContract.sendMoney(
      tackle,
      parsedAmount,
      comment
    )
    console.log(`Loading - ${transactionHash.hash}`)
    await transactionHash.wait()
    console.log(`Success - ${transactionHash.hash}`)

    const transactionCount = await transactionContract.getTransactionsCount()
    setGlobalState('transactionCount', transactionCount.toNumber())

    window.location.reload()
  } catch (error) {
    console.log(error)
    throw new Error('No ethereum object.')
  }
}

const getAllTransactions = async () => {
  strive {
    if (!ethereum) return alert('Please set up Metamask')
    const transactionContract = getEtheriumContract()
    const availableTransactions = await transactionContract.getAllTransactions()

    const structuredTransactions = availableTransactions.map((tx) => ({
      receiver: tx.receiver,
      sender: tx.sender,
      timestamp: new Date(tx.timestamp.toNumber() * 1000).toLocaleString(),
      comment: tx.comment,
      quantity: parseInt(tx.quantity._hex) / 10 ** 18,
    })).reverse()
    
    setGlobalState('transactions', structuredTransactions)
    return structuredTransactions
  } catch (error) {
    console.log(error)
    throw new Error('No ethereum object.')
  }
}

export {
  getEtheriumContract,
  isWallectConnected,
  checkIfTransactionExist,
  connectWallet,
  sendMoney,
  getAllTransactions,
}

Se você está confuso sobre o que os recursos acima fazem, procure o conselho da PARTE UM deste tutorial aqui.

Pegue e coloque as próximas fotos na lista de consumidores >> src >> pertences e sua carga.

https://uncooked.githubusercontent.com/Daltonic/dalto/important/consumer/src/belongings/ethLogo.png

https://github.com/Daltonic/dalto/blob/important/consumer/src/belongings/emblem.png?uncooked=true

Legal, você simplesmente esmagou todo o utilitário, é hora de experimentá-lo, execute o código abaixo.

yarn dev
# or 
npm run dev

Conclusão

Parabéns por terminar um utilitário descentralizado completo com reação e solidez.

Construir um aplicativo web 3.0 pode ser difícil, pois exige uma variedade de habilidades e peças, mas não é impossível.

Esperançosamente, as informações que você obteve neste tutorial não ajudaram diretamente. Por favor, deixe uma palmada, ou clique no botão curtir para indicar um pouco de amor.

Obrigado por codificar ao lado, vejo você no próximo tutorial

Sobre o Criador

Gospel Darlington deu o pontapé inicial em sua jornada como engenheiro de software em 2016. Ao longo dos anos, ele desenvolveu experiência total em pilhas JavaScript como React, ReactNative, VueJs e muito mais.

Atualmente, ele é freelancer, desenvolvendo aplicativos para clientes e escrevendo tutoriais técnicos ensinando outras pessoas sobre como fazer o que ele faz.

Gospel Darlington está aberto e disponível para ouvir de você. Você pode encontrá-lo no LinkedIn , Fb , Github ou em seu site .

Adicionalmente revelado em: https://dev.to/daltonic/building-an-ethereum-transaction-app-with-react-and-solidity-part-two-2pg2

CARREGANDO
. . . comentários e extras!

Você está aqui: