Build a Web3 app with Solidity
Tags: blockchain, react, web3, programming
Published: 2022-06-30 18:15:16

In this tutorial, I'm going to show you how to build an Ethereum Decentralized application or Dapp with React.js. If you are an absolute beginner, I suggest that you go over to the [Ethereum docs](https://ethereum.org/en/developers/docs/) for a proper introduction. 

## What we will be building

We'll be building a Dapp I call SendFunds, you can call it whatever you like. It will be a place where anybody can send ether(Ethereum's native currency) to any address and display the transaction on the front end. 

We'll be writing and deploying a smart contract that will let people connect their wallets and interact with our smart contract. We will be deploying our Dapp to the Göerli testnet. 


![Demo of SendFunds](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s2udezahyeibxnnuv25x.PNG)

## Installing dependencies 


### Node js
First we need to install the node package manager. To do this, head over to this website [Node.js website](https://nodejs.org/en/).
You can see if you already have node installed by going to your terminal and typing: 

```
node -v
```


### Metamask wallet
We need metamask in order to interact with the ethereum blockchain. [Visit this link](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn?hl=en) to install metamask chrome plugin in your chrome browser. 


### Create-react-app
Next, we will need to install [create-react-app](https://reactjs.org/) which allows us to create and run a react application very easily without too much configuration. You can install it using the following commands:

```
npm install create-react-app

```
### Sample project
Let's create our react app. Type in the following command in your terminal window. 

```
npx create-react-app send-funds
cd send-funds
npm start
```

Your browser should open automatically. If it doesn't, head over to your browser and type `http://localhost:3000`. You should see a webpage like this:

![React webpage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4h5g4vl341yxi8rhz0hh.PNG)

### Hardhat
[Hardhat](https://hardhat.org/getting-started) is a tool that lets us compile our smart contract code quickly and test them locally. It creates a local Ethereum network for us that mimics the actual Ethereum mainnet. How cool is that!
Install Hardhat with the following commands:

```
npm install --save-dev hardhat

```
Make sure you are inside the `send-funds` directory!

### Sample project
Let's get a sample project running.
Run:

```
npx hardhat
```
Your terminal should look like this:

![npx hardhat](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gwpz5thc5uhyhhigoaa3.PNG)

Choose the option to “Create a basic sample project”. Say yes to everything. In case you get a conflict error, delete the `README.md` file in your root directory. 

We need a few other dependencies. Let's install them.

```
npm install --save-dev @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers moment dotenv 
```

## Writing our smart contract code
Inside of your `send-funds` folder, navigate to your `contracts` folder and create a new file called `SendFunds.sol`. You can go ahead and delete `Greeter.sol` as we will not be needing it. 

I will paste the code we will be needing below and explain what each line does. 

```
//SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

import "hardhat/console.sol";

contract SendFunds {
    constructor() payable {
        console.log("hello");
    }

    event NewTxn(address indexed to, uint256 amount, uint256 timestamp);

    struct SentTransaction {
        address reciever;
        uint256 amount;
        uint256 timestamp;
    }

    SentTransaction[] allTxn;

    function sendFunds(address payable _to, uint256 amount) public payable {
        require(amount <= address(this).balance, "not enough funds");
        (bool success, ) = _to.call{value: amount}("");
        require(success, "Unable to send Ether");
        allTxn.push(SentTransaction(_to, amount, block.timestamp));
        emit NewTxn(_to, amount, block.timestamp);
    }

    function getAllTxn() public view returns (SentTransaction[] memory) {
        return allTxn;
    }
}

```
```
//SPDX-License-Identifier: MIT
```
Every smart contract must begin with an `// SPDX-License-Identifier`. If you do not do this, an error will occur. 


```
pragma solidity ^0.8.13;
```

A version of solidity must be indicated next. We do this to tell the compiler to use version 0.8.13. To know more about license identifiers and compiler versions, check [this](https://docs.soliditylang.org/en/v0.6.8/layout-of-source-files.html) out.


```
import "hardhat/console.sol";
```

Hardhat gives us a way to `console.log` statements to our teminal.


```
contract SendFunds {
    constructor() payable {
        console.log("hello");
    }
```

Smart contracts looks like a `class` in other programming languages. The `constructor` will run once when the contract is initialized for the first time and print what is in the `console.log()`. We are making the constructor `payable` because we want the smart contract to be able to receive ether. 


```
event NewTxn(address indexed to, uint256 amount, uint256 timestamp);
```

Next is our `event`. We need to display the transaction on our front end, we need an `event` to be able to communicate to our front end that some state has changed!


```
SentTransaction[] allTxn;
```

`struct` is used to group related data together. When sending a transaction, we need to store the `receiver`, the `amount` and the `timestamp`.  


```
function sendFunds(address payable _to, uint256 amount) public payable {
```

Next is our sendFunds function which takes in an `address payable _to` meaning the address can accept payment. A `uint256 amount` which takes in the amount to send to `_to` and the function is `payable`. 



```
require(amount <= address(this).balance, "not enough funds");
```

The `require` keyword returns a true or false. If the first half of it is true, it continues code execution. If false, it throws an error. Here, we are checking if the amount we want to send to the receiver is less than or equal to what the sender has in their wallet.  


```
(bool success, ) = _to.call{value: amount}("");

```
Above is the magic line that actually sends ether to the receiver. Then we have another `require` block to check if the transaction was a success. 


```
allTxn.push(SentTransaction(_to, amount, block.timestamp));
emit NewTxn(_to, amount, block.timestamp);
```

Here, we are pushing `_to`, `amount` and `block.timestamp` to our `struct` instance and emitting it to the front end. 


```
function getAllTxn() public view returns (SentTransaction[] memory) {
        return allTxn;
    }
```
For the final block of code, this function above returns all the transactions. 


## Testing out our smart contract
Before we begin, head over to your `hardhat.config.js` file and change your version of solidity to `0.8.13` so it would match what you have in your `SendFunds.sol` file. 

In your `scripts` folder, delete `sample-script.js` and create two new files. `run.js` is the first file to create. Here, we would play around with testing different aspects of our code and the next file to create is `deploy.js`, here is the file we use to deploy our smart contract to your testnet. 

The code below should be inside the `run.js` file.
```
const hre = require("hardhat");

const main = async () => {
  const sendFundsContractFactory = await hre.ethers.getContractFactory(
    "SendFunds"
  );
  const sendFundsContract = await sendFundsContractFactory.deploy({
    value: hre.ethers.utils.parseEther("4"),
  });

  await sendFundsContract.deployed();

  console.log("contract address: ", sendFundsContract.address);
  let contractBalance = await hre.ethers.provider.getBalance(
    sendFundsContract.address
  );
  console.log(
    "Contract balance:",
    hre.ethers.utils.formatEther(contractBalance)
  );

  const [owner, randomPerson] = await hre.ethers.getSigners();
  const sendFunds = await sendFundsContract
    .connect(randomPerson)
    .sendFunds(randomPerson.address, 2);
  await sendFunds.wait();

  const allTxn = await sendFundsContract.getAllTxn();
  console.log(allTxn);
};

const runMain = async () => {
  try {
    await main();
    process.exit(0);
  } catch (error) {
    console.log(error);
    process.exit(1);
  }
};

runMain();

```

Let's go over this line by line. 

```
const hre = require("hardhat");
```
We are requiring hardhat here because we will be needing it later.


```
const sendFundsContractFactory = await hre.ethers.getContractFactory(
    "SendFunds"
  );
```
This will compile our smart contract and generate the necessary files we need to work with our contract under the `artifacts` folder. 


```
const sendFundsContract = await sendFundsContractFactory.deploy({
    value: hre.ethers.utils.parseEther("4")
  });

```
Hardhat will create a local Ethereum network for us. Then, after the script completes it'll destroy that local network and we are giving the contract 4 ether. 

```
  await sendFundsContract.deployed();

```
Here, we are waiting for the contract to be deployed. 


```
console.log("contract address: ", sendFundsContract.address);
  let contractBalance = await hre.ethers.provider.getBalance(
    sendFundsContract.address
  );
  console.log(
    "Contract balance:",
    hre.ethers.utils.formatEther(contractBalance)
  );
```
Next, we are console.logging the contract's address and the contract's balance. 

```
const [owner, randomPerson] = await hre.ethers.getSigners();
  const sendFunds = await sendFundsContract
    .connect(randomPerson)
    .sendFunds(randomPerson.address, 2);
  await sendFunds.wait();
```
What is going on here is we are getting a random user to send some ether to and we are calling the `sendFunds` function passing in the random user's address and amount and waiting for the transaction to be completed. 

```
const allTxn = await sendFundsContract.getAllTxn();
  console.log(allTxn);

```
For the final bit of testing, we are calling the `getAllTxn` function to get all of our transactions. 

Run the following command in your terminal: `npx hardhat run scripts/run.js`. Your terminal should be outputing the following:


![test terminal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ud19gotgvyhbr661rx3h.PNG)

Let's write our deploy script. It will be very similar to our `run.js` file. 

Input the following in your `deploy.js` file.

```
const hre = require("hardhat");

const main = async () => {
    const [deployer] = await hre.ethers.getSigners();
    const accountBalance = await deployer.getBalance();
    
    console.log("deploying contracts with account ", deployer.address);
    console.log("account balance ", accountBalance.toString());
    
    const sendFundsContractFactory = await hre.ethers.getContractFactory("SendFunds");
    const sendFundsContract = await sendFundsContractFactory.deploy();
    
    await sendFundsContract.deployed();
    
    console.log("Funds contract address: ", sendFundsContract.address)
    
    }
    
    const runMain = async () => {
        try {
            await main();
            process.exit(0)
        } catch (error) {
            console.log(error);
            process.exit(1)
        }
    }
    
    runMain();
```


## Deploy to the Göerli testnet with Alchemy

We are going to be deploying to a testnet because deploying to the Ethereum Mainnet costs real money. I'll show you how to deploy to a testnet using [Alchemy](https://www.alchemy.com/).

After logging in to Alchemy, on the top right corner, there is a create app button. Click on it


![Alchemy dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6bktei9yk3y5gjv3y27w.png)

A pop up should appear next. Give your app a name, the chain should be Ethereum and network should be changed to Göerli. Finally click on create app button. 


![testnet](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/la3r0gd1z63v806h8nlr.PNG)

Next, click on your newly created project, it should take you to your project's dashboard. You will be needing the API url. 


![View key](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hoa0oeivvby9x4l7yl3u.png)


![API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ch4t79oe4v89nrwxrjt7.png)

Next, create a `.env` file in your root directory. We would be adding some things we don't want to public to get access to like your private key and API url. Don't forget to add your `.env` file to your `gitignore` file.

Head over to your `hardhat.config.js` file. Input the following:

```
require("@nomiclabs/hardhat-waffle");
require('dotenv').config();

module.exports = {
  solidity: "0.8.13",
  networks: {
    goerli: {
      url: process.env.ALCHEMY_URL,
      accounts: [process.env.WALLET_PRIVATE_KEY],
    },
  }
};

```
Let's go over this. 

```
require('dotenv').config();
```
First, we are requiring `dotenv`


```
module.exports = {
  solidity: "0.8.13",
  networks: {
    goerli: {
      url: process.env.ALCHEMY_URL,
      accounts: [process.env.WALLET_PRIVATE_KEY],
    },
  }
};
```
Next, we are filling in the url and accounts with our alchemy API url and our private key. To get your wallet's private key, head over [here](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key). 
Please keep your private key safe to avoid loss of funds. 

Before we deploy to the testnet, we need test Göerli. Head over to [Göerli faucet](https://goerlifaucet.com/). Login with Alchemy and paste in your wallet address. You should receive your test Göerli in a couple of seconds. 

In your terminal, run the following commands to deploy your contract to the Göerli testnet: `npx hardhat run scripts/deploy.js --network goerli`

Your terminal should output the following:


![Deployed successfully](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/99v0jloe2edghbnwi00b.PNG)

Copy your contract's address. We are going to need it in the front end. 

<img width="100%" style="width:100%" src="https://media.giphy.com/media/l3q2NdI5m0jrtwFpu/giphy.gif">

You've come a long way. Now let's connect our front end. 


## Setting up the front end
Let's start by deleting some unwanted code in your `App.js` file under your `src` folder. It should look like this:

```
import './App.css';

function App() {
  return (
    <div>
      hello
    </div>
  );
}

export default App;

```
Next, we are going to be creating some new folders. Under your `src` folder, create two new folders: `components` and `utils`. 
Inside your `components` folder, create two new files: `Home.js` and `Home.css`.

Inside of your `Home.js` file. Input the following code:

```
import React, { useEffect, useState } from "react";

function Home() {
  const [currentAccount, setCurrentAccount] = useState("");

  const checkIfWalletIsConnected = async () => {
    try {
      const { ethereum } = window;
      if (!ethereum) {
        console.log("you need to install metamask");
      } else {
        console.log("found one", ethereum);
      }
      /*
       * Check if we're authorized to access the user's wallet
       */

      const accounts = await ethereum.request({ method: "eth_accounts" });
      if (accounts.length !== 0) {
        const account = accounts[0];
        console.log("account ", account);
        setCurrentAccount(account);
      } else {
        console.log("no authorized account found");
      }
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() => {
    checkIfWalletIsConnected();
  }, []);

  return <div>Home</div>;
}

export default Home;

```

What is going on here is that we are basically checking to see if the special `window.ethereum` object is injected in our browser. If not, you get a `console.log` telling you to install Metamask. If the object is found, we use a special method called `eth_accounts` to see if we're authorized to access any of the accounts in the user's wallet and since a user can have multiple accounts, we are taking the first one. Finally we are using the `useEffect` hook to run the function immediately the page loads. 

## Connecting our wallet

Connecting our wallet is very easy to do. Your `Home.js` file should look like the following:

```
import React, { useEffect, useState } from "react";
import "./Home.css";

function Home() {
  const [currentAccount, setCurrentAccount] = useState("");

  const checkIfWalletIsConnected = async () => {
    try {
      const { ethereum } = window;
      if (!ethereum) {
        console.log("you need to install metamask");
      } else {
        console.log("found one", ethereum);
      }
      /*
       * Check if we're authorized to access the user's wallet
       */

      const accounts = await ethereum.request({ method: "eth_accounts" });
      if (accounts.length !== 0) {
        const account = accounts[0];
        console.log("account ", account);
        setCurrentAccount(account);
      } else {
        console.log("no authorized account found");
      }
    } catch (error) {
      console.log(error);
    }
  };

  //connect wallet with button click
  const connectWallet = async () => {
    try {
      const { ethereum } = window;
      if (!ethereum) {
        console.log("you need to install metamask");
        return;
      }
      const accounts = await ethereum.request({
        method: "eth_requestAccounts",
      });

      console.log("Connected", accounts[0]);
      setCurrentAccount(accounts[0]);
    } catch (error) {
      console.log(error);
    }
  };
  useEffect(() => {
    checkIfWalletIsConnected();
  }, []);

  //truncate wallet address
  function truncate(input) {
    return input.substring(0, 5) + "..." + input.substring(38);
  }

  return (
    <div className="App">
      {currentAccount.length === 0 ? (
        <div>
          <div className="nav">
            <h1>SendFunds</h1>
          </div>
          <div className="content">
            <div>
              <p className="description">
                Send <i className="fa-brands fa-ethereum"></i> to your friends
                and family.
              </p>
              <button className="connect-btn" onClick={() => connectWallet()}>
                Connect Wallet
              </button>
            </div>
          </div>
        </div>
      ) : (
        <div>
          <div className="nav flex">
            <h1>SendFunds</h1>
            <p className="wallet-address">{truncate(currentAccount)}</p>
          </div>
          <div className="content connected-wallet">
            <p className="description">
              Send <i className="fa-brands fa-ethereum"></i> to your friends and
              family.
            </p>
          </div>
        </div>
      )}
    </div>
  );
}

export default Home;

```

Let's go over the `connectWallet` and `truncate` functions.

```
const connectWallet = async () => {
    try {
      const { ethereum } = window;
      if (!ethereum) {
        console.log("you need to install metamask");
        return;
      }
      const accounts = await ethereum.request({
        method: "eth_requestAccounts",
      });

      console.log("Connected", accounts[0]);
      setCurrentAccount(accounts[0]);
    } catch (error) {
      console.log(error);
    }
  };
```
Here, we are checking if `window.ethereum` is present. If it is, we call `eth_requestAccounts` to ask Metamask to give us access to the user's wallet. Then we are setting `setCurrentAccount` to the first account. 

```
 function truncate(input) {
    return input.substring(0, 5) + "..." + input.substring(38);
  }

```
Since, wallet addresses are too long, we are truncating it.

Finally, we are doing some conditional rendering. If `currentAccount.length === 0`, the user needs to connect their wallet, else display a welcome text. 

The styling for the `Home.css` page:

```
body{
    background: rgb(100,0,123);
    background: radial-gradient(circle, rgba(100,0,123,1) 0%, rgba(62,20,86,1) 100%);
    color: #fff;
    margin: 2px 40px;
    font-family: 'Bellota', cursive;
  }

  .content {
    text-align: center;
    margin: 160px auto 40px;
  }

  .description {
    font-size: 30px;
    font-weight: bold;
  }

  .connect-btn {
  color: white;
  padding: 10px 30px;
  font-size: 1.3em;
  background: transparent;
  border-radius: 50px;
  border: 1px solid white;
  margin: 10px auto 0;
  cursor: pointer;
  opacity: 0.7;
  font-family: 'Bellota', cursive;
  font-weight: bold;
  }

.nav {
  border-bottom: 1px solid #fff;
}

.nav h1 {
  margin-bottom: 0;
  text-align: left;
}

.flex {
  display: flex;
  align-items: center;
  justify-content: space-between;
  place-items: flex-end;
}

.nav p {
  margin: 3px 0;
}

.connected-wallet {
  margin: 70px auto 40px;

}

.wallet-address {
  border: 1px solid #fff;
  padding: 2px 15px;
  border-radius: 50px;
}
```
I got my icon from [font awesome](https://fontawesome.com/) and added the [cdn](https://cdnjs.com/libraries/font-awesome) to my `index.html` file. For the font, I used [Bellota](https://fonts.google.com/specimen/Bellota?query=bellota) from [google fonts](https://fonts.google.com/) and also added the link to my `index.html` file.

Import `Home.js` in your `App.js` file.

```
import './App.css';
import Home from './components/Home';


function App() {
  return (
    <div>
      <Home />
    </div>
  );
}

export default App;

```

Run `npm start` to check out your Dapp.

Your Home page should be looking like this:

![Home page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j9nw0aoxgsvaw5s5ayq0.PNG)

## Form implementation

Let's dive into our form creation. Under the `utils` folder, create a new file called `SendFunds.json`. This will house the artifacts gotten when you deployed your contract. 
Under `artifacts/contracts/SendFunds.sol`, you will find a `SendFunds.json` file. Copy everything and paste in inside your `utils/SendFunds.json`.

You also need to create two new files under your `components`: `Form.js` and `Form.css`. 

Let's create a custom form inside your `Form.js` file:

```
import React, {useState} from 'react';
import './Form.css';


const Form = () => {
    const [walletAddress, setWalletAddress] = useState('')
    const [amount, setAmount] = useState('')
  

  return (
    <div className="form">
      <form>
        <p>
          <input
            type="text"
            name=""
            id=""
            placeholder="Enter Wallet Address"
            required
            value={walletAddress}
            onChange={(e) => setWalletAddress(e.target.value)}
          />
        </p>
        <p>
          <input
            type="number"
            name=""
            id=""
            placeholder="Enter Amount"
            required
            value={amount}
            onChange={(e) => setAmount(e.target.value)}
            step='any'
            min='0'
          />
        </p>
        <button type="submit">
          Send
        </button>
      </form>

    </div>
  );
};

export default Form;
```
The code above is pretty straight forward. Two `input` fields. One a `number` and the other a `text` type. Then, I am saving the values in state. 

_Note:_ Don't forget to include your `Form.js` file at the bottom of your `Home.js` file. 

Now, let's call our `sendFunds` function from our smart contract.
```
import React, { useState } from "react";
import { ethers } from "ethers";
import abi from "../utils/SendFunds.json";
import { parseEther } from "ethers/lib/utils";

const Form = () => {
  const [walletAddress, setWalletAddress] = useState("");
  const [amount, setAmount] = useState("");

  const contractAddress = "0x0FB172Db7Ab332f3ea5189C4A3659720124880Bc";
  const contractABI = abi.abi;
  const sendFunds = async () => {
    try {
      const { ethereum } = window;
      if (ethereum) {
        const provider = new ethers.providers.Web3Provider(ethereum);
        const signer = provider.getSigner();
        const sendFundsContract = new ethers.Contract(
          contractAddress,
          contractABI,
          signer
        );
        const sendFundsTxn = await sendFundsContract.sendFunds(
          walletAddress,
          ethers.utils.parseEther(amount),
          { gasLimit: 300000, value: parseEther(amount) }
        );
        await sendFundsTxn.wait();
        setWalletAddress('')
        setAmount('')
      } else {
        console.log("ethereum object does not exist!");
      }
    } catch (error) {
      console.log(error);
    }
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    sendFunds();
  };

  return (
    <div className="form">
      <form onSubmit={handleSubmit}>
        <p>
          <input
            type="text"
            name=""
            id=""
            placeholder="Enter Wallet Address"
            required
            value={walletAddress}
            onChange={(e) => setWalletAddress(e.target.value)}
          />
        </p>
        <p>
          <input
            type="number"
            name=""
            id=""
            placeholder="Enter Amount"
            required
            value={amount}
            onChange={(e) => setAmount(e.target.value)}
            step="any"
            min="0"
          />
        </p>
        <button type="submit">Send</button>
      </form>
    </div>
  );
};

export default Form;

```
We have a lot going on here, so let's break it down. 

```
import { ethers } from "ethers";
```
We are importing `ethers` because we will need it in order to interact with our smart contract. 

```
import abi from "../utils/SendFunds.json";
```
Next, we are importing our abi. You can read more about it [here](https://www.quicknode.com/guides/solidity/what-is-an-abi).

```
import { parseEther } from "ethers/lib/utils";
```
We use `parseEther` when we want to convert a value from ETH to WEI which is the value we want to send to the contract when calling a payable method.

```
const contractAddress = "0x0FB172Db7Ab332f3ea5189C4A3659720124880Bc";
```
The contract address gotten when we deployed our smart contract. Incase you didn't save yours, run `npx hardhat run scripts/deploy.js --network goerli`.

```
  const contractABI = abi.abi;
```
The abi gotten from our `SendFunds.json` file. 

```
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
```
A Provider is what we use to actually talk to Ethereum nodes. A signer is used to sign transactions and send the signed transactions to the Ethereum network. Read more abour signers [here](https://docs.ethers.io/v5/api/signer/).

```
const sendFundsTxn = await sendFundsContract.sendFunds(
          walletAddress,
          ethers.utils.parseEther(amount),
          { gasLimit: 300000, value: parseEther(amount) }
        );
        await sendFundsTxn.wait();

```
We are calling the function we wrote in our smart contract and passing in the necessary arguments and waiting for the transaction to execute. 

Next is the function to get all of our transactions:

```
import React, { useEffect, useState } from "react";
import { ethers } from "ethers";
import abi from "../utils/SendFunds.json";
import { parseEther } from "ethers/lib/utils";
import Transaction from "./Transactions";
import "./Form.css";

const Form = () => {
  const [walletAddress, setWalletAddress] = useState("");
  const [amount, setAmount] = useState("");
  const [allTxns, setAllTxns] = useState([]);
  const [isTxn, setIsTxn] = useState(false);

  const contractAddress = "0x0FB172Db7Ab332f3ea5189C4A3659720124880Bc";
  const contractABI = abi.abi;
  const sendFunds = async () => {
    try {
      const { ethereum } = window;
      if (ethereum) {
        const provider = new ethers.providers.Web3Provider(ethereum);
        const signer = provider.getSigner();
        const sendFundsContract = new ethers.Contract(
          contractAddress,
          contractABI,
          signer
        );
        const sendFundsTxn = await sendFundsContract.sendFunds(
          walletAddress,
          ethers.utils.parseEther(amount),
          { gasLimit: 300000, value: parseEther(amount) }
        );
        await sendFundsTxn.wait();
      } else {
        console.log("ethereum object does not exist!");
      }
    } catch (error) {
      console.log(error);
    }
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    sendFunds();
  };

  const getAllTransactions = async () => {
    try {
      const { ethereum } = window;
      if (ethereum) {
        const provider = new ethers.providers.Web3Provider(ethereum);
        const signer = provider.getSigner();
        const sendFundsContract = new ethers.Contract(
          contractAddress,
          contractABI,
          signer
        );
        let getAllTxn = await sendFundsContract.getAllTxn();
        setIsTxn(true);

        let txns = [];
        getAllTxn.forEach((txn) => {
          txns.push({
            address: txn.reciever,
            amount: txn.amount,
            timestamp: new Date(txn.timestamp * 1000),
          });
        });
        setAllTxns(txns);
      } else {
        console.log("ethereum object does not exist!");
      }
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() => {
    getAllTransactions();
  }, []);

 useEffect(() => {
    let sendFundsContract;
  
    const onNewTransaction = (to, amount, timestamp) => {
      console.log("New transaction", to, amount, timestamp);
      setAllTxns(prevState => [
        ...prevState,
        {
          address: to,
          amount: amount,
          timestamp: new Date(timestamp * 1000)
        },
      ]);
    };
  
    if (window.ethereum) {
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const signer = provider.getSigner();
      sendFundsContract = new ethers.Contract(contractAddress, contractABI, signer);
      sendFundsContract.on("NewTxn", onNewTransaction);
    }
  
    return () => {
      if (sendFundsContract) {
        sendFundsContract.off("NewTxn", onNewTransaction);
      }
    };
  }, []);

  return (
    <div className="form">
          {/* don't forget to add the input fields, i removed them to make the code shorter */}

      <div>
        {isTxn === false ? (
          <div></div>
        ) : (
          <div>
            <Transaction allTxns={allTxns} />
          </div>
        )}
      </div>
    </div>
  );
};

export default Form;

```
We are calling the `getAllTxn` function and pushing it into an array that we store with `useState` and sending the array to the `Transaction` component. You can go ahead and create a `Transaction.js` and `Transaction.css` files inside your `components` folder. 
I am also catching the event I created on the smart contract so I don't have to refresh the page whenever I send in a new transaction. 

The styling I used for the form. Add it to your `Form.css` file:

```
* {
  font-family: 'Bellota', cursive;

}

button {
  color: white;
  padding: 10px 30px;
  font-size: 1.3em;
  background: transparent;
  border-radius: 50px;
  border: 1px solid white;
  margin: 10px auto 0;
  cursor: pointer;
  opacity: 0.7;
  font-weight: bold;
}

.form {
    text-align: center;
    margin: 60px auto 40px;
}

input {
    border: 1px solid #fff;
    padding: 8px 13px;
    border-radius: 50px;
    width: 30%;
    margin-bottom: 20px;
    font-weight: bold;
    font-size: 18px;
}
```

For the final bit of this tutorial, let us display our transactions on the front end. 

In your `Transaction.js` file, input the following code:

```
import React from 'react';
import './Transaction.css'
import moment from 'moment'
import {ethers} from 'ethers'

const Transaction = ({allTxns}) => {
  console.log(allTxns)
  return (
    <div className='transaction-container'>
    <h2>All Transactions:</h2>
     {allTxns.length === 0 ? <div>
       
       </div>: <div className='grid-container'>
       
          {allTxns.map((txn, index) => {
            return (
              <div key={index} className='transactions'>
                <p>Reciever: {txn.address}</p>
                <p>Amount: {ethers.utils.formatUnits(txn.amount.toString(), 'ether')} eth</p>
                <p>Date:  {moment(txn.timestamp.toString()).format('MM/DD/YYYY')}</p>
                </div>
            )
          })}
         </div>}
    </div>
  );
};

export default Transaction;
```
What is going on here is very clear. We are getting the `allTxns` prop from the `Form.js` file and we are displaying the data. Changing WEI to ETH using `ethers.utils.formatUnits` and changing the `txn.timestamp` to something more readable using `moment`. 

Styling for `Transaction.css` file:
```
.transaction-container {
    text-align: left;
    margin-top: 20px;
}

.grid-container {
    display: grid;
    grid-template-columns: auto auto auto;
    grid-gap: 10px;
}

.transactions{
    background-color: #ffffff;
    color: black;
    padding: 0 10px;
    border-radius: 10px;
    width: 60%;

}

```

Run `npm start` in your terminal. Send some transactions. Your web page should be looking like this:


![Final result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ymcdb3iiggjoydaekmeh.PNG)

## Further learning

- [Solidity by example](https://solidity-by-example.org/)
- [buildspace] (https://buildspace.so/)
- [cryptozombies] (https://cryptozombies.io/)

Connect with me on: [Twitter](https://twitter.com/devv_chi) || [LinkedIn] (https://www.linkedin.com/in/chidera-johnson-7018ba22a/)