Building SendCrypto: A Web 3.0 Application for Secure Blockchain Transactions
Tags: solidity, react, ethers, smartcontract
Published: 2023-08-15 14:06:16

### Introduction:
The rapid evolution of blockchain technology has paved the way for Web 3.0 and decentralized finance, a new era that is redefining the way we transact, invest, and interact with our money.

This article delves into building **SendCrypto**, a Web 3.0 application that enables users to perform transactions through the blockchain.

### What you will be building:
You will be creating a fully-fledged Web 3.0 application that allows users to send transactions through the blockchain. 

Technologies you will be using for this project include React for the front-end, Hardhat-Ethers for Ethereum integration, and Solidity for the smart contract. 

### Application Demo:
View the application Demo [Here](https://send-crypto.netlify.app/)
![Send crypto](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uk490zh4hmngavm4ikit.PNG)


![Ethereum card](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s9upec2ueicdmhttisun.PNG)

If you do not have a Meta mask setup on your browser, You can do that using this link - https://support.metamask.io/hc/en-us/articles/360015489531-Getting-started-with-MetaMask

Here is the link to the [github repository](https://github.com/jamesoyanna/send-crypto)

### How it works:

 The application allows users to make a transaction through the blockchain.

-Each transaction is paired with an image and it is stored on the blockchain.

When a user clicks on the connect to wallet button, it will immediately trigger a connection to the Metamask wallet, and it will request the account you want to connect to.

**Connection to a meta mask account** - You will automatically see a display of the connected wallet address on the Ethereum card.

You can switch your account to another account you want to send Ethereum to from the Metamask wallet.

Input your wallet address on the transaction area. Specify the amount of Ethereum you want to send, add a keyword you would want to use and a message then click on the Send Now button

Metamask automatically prompts a message describing the amount to be sent.

-Click on confirm then a second notification will appear which is the contract interaction.

Here, we are actually interacting with our Solidity smart contract doing this.

If you scroll down, you will see the recent transactions being stored on the blockchain. Clicking on any transaction will take you to the Etherscan platform, where you will see the actual address and the real transaction.

The focus of this tutorial will be to implement Web 3.0 into our React application, allowing it to send transactions through the blockchain and then store those transactions.

We will be conducting our testing on the goerli faucet test network.

Lets setup our development environment. 

### Setting up the Development Environment:
Now let's configure our development environment. We will start by setting up the frontend of the application using React. 

Before we begin, ensure you have Node.js and npm (Node Package Manager) installed on your machine. You can download them from the official Node.js website: https://nodejs.org/

To verify if Node.js and npm are installed, open your terminal and run the following commands:
`
node -v
npm -v
`

#### Create a New Project:
create the main project folder, name it **Sendcrypto**.

We will be using **vite** to bootstrap our application. Vite is a build tool and development server for modern web development. It helps you set up a modern development environment with minimal configuration. 

To install Vite globally, run the following command:

`npm create vite@latest`
Then follow the instructions to install it.
navigate into your project folder and run this command:

`npm install
npm run dev`
Ensure you you name the react application as client during installation.

Your application should be running on  http://127.0.0.1:5173/ . Enter this address on your browser. If the installation is successful, you should see this on your browser:

![Vite landing page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vyhsz0wjgxfh8z013u3u.PNG)

#### Installing tailwind CSS
use these commands
`npm install -D tailwindcss postcss autoprefixer

npx tailwindcss init -p`

Open your project with VScode editor

copy the code below and paste on your tailwind.config file that was created when you ran the above command.

`module.exports = { content: [ "./src/**/*.{js,jsx,ts,tsx}", ], theme: { extend: {}, }, plugins: [],}
`
**Add these code (directives) below to your index.css file**
@tailwind base;
@tailwind components;
@tailwind utilities;

You can now test your App by adding the code below in your `app.js` file

{% gist https://gist.github.com/jamesoyanna/498d7fe9f6e8b82a72d13499820a0a2a file=App.js%}
to ensure your tailwind style is working.

Now let's create the basic setup for our smart contract. Navigate into the smart_contract directory. and run the command:
`npm init -y`

This will initialize an empty `package.json`. This would be the starting point of our smart contract.

Now let's create our react application that will display our transactions on the frontend.

Navigate to your `client` folder of your react application. Add a folder in the `src` directory. Name it components.

We can start adding our components. Inside the components folder, add the following files `Navbar.jsx` `Footer.jsx`, `Services.jsx`, `Loader.jsx` `Transactions.jsx` `Welcome.jsx`

To allow us to export all these components from a single file, add a file in the components folder. Name it `index.js`

Export all the components you have created in the index.js file. It should now look like this.
{% gist https://gist.github.com/jamesoyanna/ff0afbf3f1d1d35af73b797da61a36de file=index.js%}

Add the following basic contents to the components you have created.

{% gist https://gist.github.com/jamesoyanna/03e8a17b7d0abd348dd709fb47e9113d file=Navbar.jsx%}

{% gist https://gist.github.com/jamesoyanna/e2c75f97107842eb60fdf40a7d9cb178 file=Footer.jsx%}


{% gist https://gist.github.com/jamesoyanna/d9b40570365a75229ceeaffbc3d55459 file=Services.jsx%}

{% gist https://gist.github.com/jamesoyanna/1865496b51abee244aada4e493288ae9 file=Transactions.jsx%}


Now update your `App.jsx` by importing these components into them. 
Your `App.jsx` should now look like this.

{% gist https://gist.github.com/jamesoyanna/fad3b75d20ea025689b51a1b6da4154f file=App.jsx%}

If everything works fine you should now see this on your browser.


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

**Adding style to our App:**
To add style to our application simply copy the style below and add it to your index.css file. 

{% gist https://gist.github.com/jamesoyanna/a9bce3daf78b8074e1487b6519a26bcb file=index.css%}

For the icons we will use throughout the project, install the react icons using this command:
` npm i react-icons`

For the logo, create a folder inside the `src` folder and add add a logo image of your choice to it.

Now let's add the code for the Navbar component:
Open the `Navbar.jsx` file and add the following code:

{% gist https://gist.github.com/jamesoyanna/41eca556b20cfc4890c9cb35830e2894 file=Navbar.jsx%}

Here in this code, we imported the required modules and resources. We imported React from the "react" package, icons like HiMenuAlt4 from the `react-icons/hi` package, and `AiOutlineClose` from the `react-icons/ai` package.

We then added a logo image by importing it from the "../images/logo.png" file

We also define a functional component `NavBarItem`. It takes two props, `title` and `classprops`. 

Inside the component, it returns a list element with the title as its content and applies CSS classes for margin, cursor, and any additional classes provided via `classprops`.

Inside our Navbar component,we sets up a state variable `toggleMenu` and a state updater function `setToggleMenu` using the `useState` hook. The initial state of `toggleMenu` is false.

In our `jsx` we, render a responsive navigation bar component that includes a logo, navigation items, and a mobile menu toggle.

It adapts to both desktop and mobile screen sizes, providing easy navigation through a list of items and a mobile menu toggle.

Your `Navbar` should now look like this on the browser:

![Navbar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ghcbgh8gcayf0u8sabi.PNG)

Now let's add the code for the `Welcome` component.

Open the `Welcome.jsx` file and add the code below:
{% gist https://gist.github.com/jamesoyanna/f6adc12a715d31ce972de0a59b57d077 file=Welcome.jsx%}

Here in this `Welcome` component, we updated it by first we import of several icons from the "react-icons" library.

We define a constant `companyCommonStyles `.This contains a set of CSS classes.

We also define a functional component called `Input`. It takes props like `placeholder, name, type, value, and handleChange`, and renders an input element with various properties and styling.


Inside the `Welcome` component, we declared three functions -  `connectWallet` and `handleSubmit` and an empty `handleChange `function. We will add the logic for these functions later

The return statement of the Welcome component starts by rendering a structure of HTML elements.
The content section includes headings, a description, and a "Connect Wallet" button.

We added a section that includes a grid of information boxes with text like "Reliability", "Security", "Ethereum", etc. These boxes represent features of the platform.

We also added a button to send crypto.

Your application should now look like this.

![Welcome page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9cl5v7w905ymptyt2h0g.PNG)


### Adding the Service Component:
Now inside your client folder, open the Services.jsx file and the following code :
{% gist https://gist.github.com/jamesoyanna/123c171645eff2e683c7499bdb4c3e62 file=Services.jsx%}

Here in this code, we imported several icons from the `react-icons `package.

We then define a functional component `ServiceCard` that takes several props: color, title, icon, and subtitle.

This component represents a card-like structure containing service details.
We use the color prop to determine the background color of the circular icon container.

The icon prop is a React element representing the icon for the service.
The title prop is the title of the service.
The subtitle prop is the description of the service.
The card structure is built using flexbox classes for layout and styling.

We also define another functional component `Services`.
This component wraps the content of the services section, providing a gradient background.

Inside the component, we added a nested div element with various styling classes applied to control layout and spacing.

### Adding Footer Component:
Inside the `Footer.jsx` file we previously created, add the following code:
{% gist https://gist.github.com/jamesoyanna/7fac42ed66e5ceda5f655ee69668e9ad file=Footer.jsx%}

Here in this code above, we define a React functional component called Footer, which serves as a footer section for our application. 

The footer contains various elements such as a logo, navigation links, contact information, and copyright text. 

We also imported the image named `logo.png` from the ../images/ directory to be used for our logo.

### Adding Helper functions:
We will be adding some helper functions and reusable code snippets that we will be using throughout the application.

Inside the `src` folder, create a folder and name it `utils`. create a file inside the `utils` folder, name it `Transactions.json`, and add the following code to it:
{% gist https://gist.github.com/jamesoyanna/292bcf65660c836d4f49323482f85983 file=Transactions.json%}

Here in this code, is a JSON object that describes an `Ethereum `smart contract called "Transactions" written in Solidity. 

It includes information about the contract's name, source file path, ABI (interface for external interaction), compiled bytecode, and deployed bytecode. 

The ABI outlines the contract's functions and events, while the bytecode is the low-level code that runs on the Ethereum network.

This artifact is essential for deploying, interacting with, and understanding our contract programmatically.

Inside the `utils` folder, create another file. Name it `constants.js` and add the following code to it.

{% gist https://gist.github.com/jamesoyanna/679b9001e2cd749e136dbc2b62e1c0fd file=constants.js%}

Here in this code above, we imported the `ABI(interface for external interaction)` of the smart contract from the `Transactions.json` file we created.
We declared a constant variable named `contractAddress`, which contains the `Ethereum` address where the smart contract has been deployed. This address is represented as a hexadecimal string.
`
export const contractABI = abi.abi;`
In this line of code, we declared a constant variable named `contractABI`. It assigns the abi property of the imported abi object to contractABI. 

This `contractABI` represents the ABI of the smart contract and will be used in various parts of the application to interact with the contract's functions and events.

What we have done in this whole code module is to provide a central location for storing the contract's address and ABI, so as to make it easy for us to access and use these details throughout the application.

Inside the utils file, add create another file. Name it `shortenAddress.js` and add the following code:
{% gist https://gist.github.com/jamesoyanna/efed57056f7cfdeb39667a6df6da794e file=shortenAddress.js%}

Here in this code above, we define a function called `shortenAddress`. It takes in an Ethereum address as input and returns a shortened version of that address.

 Ethereum addresses are typically long hexadecimal strings, and this function is intended to make them more visually manageable.

So, when you call the `shortenAddress` function with a full Ethereum address as an argument, it will return a string that shows the first five characters, an ellipsis, and the last four characters of the address.

Let's also add dummy transaction data that would serve as default transactions on the blockchain.
Inside the utils folder create a file. Name it `dummyData.js` and add the following code to it:
{% gist https://gist.github.com/jamesoyanna/80d9b9ac8df6620fc0e07ba480c22e83 file=dummyData.js%}
Here in this code above, we exported an array of objects, each representing a transaction with certain details. 

Each object in the array contains information about the sender's address, receiver's address, amount, timestamp, and a GIF URL. 
This represent a series of transactions in our blockchain application.

Now next we will use the React Context API to manage and share the state and functions relating to Ethereum transactions across our components without the need to pass props explicitly through component nesting.

Inside the `src` folder, create a folder. name it context. Inside the context folder, create a file. Name it `TransactionContext.jsx` and add the following code:
{% gist https://gist.github.com/jamesoyanna/860ca1ded3c299ae9fe4693dd0f3fa90 file=TransactionContext.jsx%}

Here in this code above, we define a React context provider called `TransactionsProvider` that manages interactions with our blockchain contract using the Ethereum blockchain and MetaMask.

Firstly, we imported necessary libraries and modules, including React, useEffect, useState for managing component state, and the ethers library for interacting with the Ethereum blockchain.

We also imported `contractABI` and `contractAddress` from the `constant` module we defined earlier. 

We created a context named `TransactionContext` using React.createContext(). This context will provide the necessary data and functions related to transactions to its consumers.

We define a `createEthereumContract` function. This initializes the Ethereum contract using the `contractAddress` and `contractABI`. It uses the `MetaMask` provider to obtain a signer and interact with the contract.

We define several state variables:
`formData:` Tracks form data such as the recipient's address, amount, keyword, and message.

` currentAccount:` Stores the current Ethereum account's address.

`isLoading:` Indicates whether a transaction is currently being processed.
`transactionCount`: Stores the number of transactions.

`transactions:` Holds an array of structured transaction objects.

For our Data Fetching and Processing, we defined several functions:
`
getAllTransactions:` Uses the contract instance to fetch all transactions from the blockchain, processes the data, and updates the transactions state.

`checkIfWalletIsConnect:` Checks if `MetaMask` is installed, gets the user's Ethereum accounts, and updates the `currentAccount `state. It then calls `getAllTransactions`.

`checkIfTransactionsExists:` Initializes the `transactionCount` using the contract's method to get the count of transactions.

Wallet Connection and Transaction Submission:

`connectWallet:` This function requests user account access from `MetaMask` and updates the `currentAcc`ount`.

`sendT`ransaction:` Constructs and sends an `Ethereum` transaction using MetaMask. 

It also interacts with the smart contract to add the transaction to the blockchain. It updates the `transactionCount` after the transaction is successful.

We use the `useEffect` hook is used to automatically check for wallet connection and existing transactions when the `transactionCount` changes. This helps keep the UI in sync with the blockchain.

The `TransactionsProvider` component wraps its children in the `TransactionContext.Provider`. It exposes various state variables and functions related to transactions to its children.

Since we are using the `ethers` library, you will need to install it for our application to work properly.
Navigate to your client directory, open your command-line and run this command to install `ethers`:

 `npm i ethers`
To start your server again by running the command: `npm run dev` 

We will also wrap our application with a custom context provider. This will provide the context data and functions related to `Ethereum` transactions to all components rendered within it.

Update your `main.jsx` file with the following code:
 {% gist https://gist.github.com/jamesoyanna/3dd5c6a6d366e3441c97e63fd247c510 file=main.jsx%}
Here in this code, we added the `TransactionsProvider` by importing it from the `TransactionContext` in the context folder.

The `TransactionsProvider` is a custom context provider that wraps our main `App` component. It provides the context data and functions for `Ethereum` transactions.

We want to add a custom hook to fetch GIFs images from the `Giphy API`. 
Inside your `src` folder, create a new folder, name it `hooks`. Inside the hooks folder add a file. Name it `useFetch.jsx` and add the following code:
 {% gist https://gist.github.com/jamesoyanna/67c3be6b230171735db1743091baab3f file=useFetch.jsx%}

Here in this code, we define a custom React hook named `useFetch` that is used to fetch `GIFs` from the `Giphy API` based on a provided keyword. 

It uses the `useState` and `useEffect` hooks to manage the state and handle the asynchronous fetching of `GIFs`.


Now we will be adding our `transactions `component logic. Inside the Transactions.jsx file in the components folder, add the following code:
{% gist https://gist.github.com/jamesoyanna/1248dd81528a2dc852d88a3b4cae390e file=Transactions.jsx%}

Here in this code, we define two components: `TransactionsCard` and `Transactions`. We use these components to display a list of transactions with associated information, including `GIFs` fetched based on keywords.

We imported the `useContext` from the "react" library. The TransactionContext is imported from "../context/TransactionContext".

We imported the `useFetch` custom hook from "../hooks/useFetch".

We also imported the `dummyData` and `shortenAddress` functions from their respective paths.

We define `TransactionsCard` functional component which takes various props (addressTo, addressFrom, timestamp, message, keyword, amount, url) to render a transaction card.

We use the `useFetch` hook to fetch GIFs based on the keyword prop.

We define the `Transactions` functional component which displays a list of transaction cards using the `TransactionsCard` component.

It uses the `useContext` hook to access the transactions array and `currentAccount` from the `TransactionContext`.

Depending on whether there is a `currentAccount`, it displays a message suggesting to connect an account or showing the "Latest Transactions" header.

The list of transactions is rendered using the map function, combining the `dummyData` (predefined transactions) and the dynamic transactions from context.

Now let's update our `Welcome` component to add the logic for `connectWallet`, `handleSubmit` and `handleChange` functions we had earlier defined.

Inside the `Welcome.jsx`file in the components folder, update it with the following code:
 {% gist https://gist.github.com/jamesoyanna/bc18666ebe779be55c4567dda2fc8b6c file=Welcome.jsx%}

Here in this code above we updated the `handleSubmit` function in our previous code by using destructuring to extract values from the `formData` object. 

The formData object holds data the users inputed in the form.

The values we extracted are addressTo, amount, keyword, and message, which represent the recipient's address, transaction amount, GIF keyword, and message respectively.

We prevented the default behavior of the form submission event by using `e.preventDefault();`.

`if (!addressTo || !amount || !keyword || !message) return;`

This is a conditional statement that checks whether any of the extracted values (i.e., addressTo, amount, keyword, message) are falsy. 

If any of these values are falsy (empty or not provided), the condition evaluates to true, and the code inside the if-block doesn't run. This effectively stops the function from continuing if any required field is missing.

If all the required fields (addressTo, amount, keyword, message) have valid values, the `sendTransaction` function is invoked.

This function initiates the process of sending a cryptocurrency transaction based on the user's input data.

We will also add the code for the `Loader` component. Inside the `Loader.jsx` file we have created earlier, add the following code:
{% gist https://gist.github.com/jamesoyanna/e40c243ae748ff31b763ed5ac7c66ad3 file=Loader.jsx%}
Here in this code, we define an arrow function component named `Loader`. This is a simple circular loading animation.
 
When this component is rendered in our application, it will display a spinning circle with a red border at the bottom. It's often used to show that some asynchronous operation (like data fetching) is in progress.


### Connecting application to the blockchain

Now let's connect our application to the blockchain. We will be writing a solidity contract that keeps track of all the transactions that went through the blockchain.

Let's add the dependencies for our smart contract. 
Switch to your `smart_contract` folder and from your project in your command-line, run the following command:

`npm i hardhat @nomiclabs/hardhat-waffle @nomiclabs/hardhat-ethers chai ethereum-waffle ethers`

Hardhat is an Ethereum development environment. It enables us to easily deploy contracts, run tests, and debug Solidity code without dealing with live environments. You can read more on their documentation [Hardhat Doc](https://hardhat.org/hardhat-runner/docs/getting-started)

After the dependencies have finished installing, run the command:
`npx hardhat  ` and follow the instructions. Press yes to accept the questions. New files and folders are added to your project directory. You can run an initial test by running the command 
`npx hardhat test`

Also, ensure you install the solidity extension on your Vscode. This would make your writing of solidity code easier.

here is it.

![Solidity Extension](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t538r7y3fzyphqq7wlh9.PNG)

Now, let's write our smart contract for our transactions.
Inside the `contracts` folder in your `smart_contract` directory, add a file called `Transactions.sol`. Inside it add the following code below:

{% gist https://gist.github.com/jamesoyanna/23b9944204eb95c437266f965eb56982 file=Transactions.sol%}

Here in this code, 

```
pragma solidity ^0.8.0;
```
we use the `pragma` directive that specifies the version of the Solidity compiler that should be used. 

The caret (^) symbol means the code is compatible with compiler versions greater than or equal to 0.8.0. 

`contract Transactions {
}`
Then, we define a Solidity smart contract named `Transactions`

`uint256 transactionCount;`

Then we declare a state variable `transactionCount` of type uint256, which will be used to keep track of the number of transactions.

`event Transfer(address from, address receiver, uint amount, string message, uint256 timestamp, string keyword);`

Then we define an event named `Transfer`. Events are simply a way for contracts to communicate that something has happened. 

This event is used to log transaction details, such as sender, receiver, amount, message, timestamp, and keyword.
`
struct TransferStruct {
    address sender;
    address receiver;
    uint amount;
    string message;
    uint256 timestamp;
    string keyword;
}`

Then we define a structure named `TransferStruct` which holds the components of a transaction. It includes the sender's and receiver's addresses, the transaction amount, a message, timestamp, and a keyword associated with the transaction

`TransferStruct[] transactions;`

We then declare a dynamic array named transactions that will store instances of `TransferStruct`, representing the recorded transactions.

```
function addToBlockchain(address payable receiver, uint amount, string memory message, string memory keyword) public {
    transactionCount += 1;
    transactions.push(TransferStruct(msg.sender, receiver, amount, message, block.timestamp, keyword));

    emit Transfer(msg.sender, receiver, amount, message, block.timestamp, keyword);
}
```

Then we added an `addToBlockchain` function. This would allow a user to add a new transaction to the blockchain. 

What it simply does is it increments the `transactionCount`, creates a new instance of `TransferStruct` with the provided parameters, pushes it to the transactions array, and emits the Transfer event to log the transaction details.

```

function getAllTransactions() public view returns (TransferStruct[] memory) {
    return transactions;
}

```
Here, we define a function, `getAllTransactions`, which is a view function that returns the entire array of recorded transactions when called. It doesn't modify the contract's state.

`function getTransactionCount() public view returns (uint256) {
    return transactionCount;
}`

And lastly, we define a function, `getTransactionCount`, which is also a view function that returns the current value of `transactionCount.`


From deploy - When we run the deploy code, we are going to get the address of our smart contract deployed on the blockchain network

For our contract to be deployed, we need to have Ethereum on our own wallet already because everything on the blockchain network requires what we know as gas.

To get a wallet account signup for the Metamask account and use it on your browser as an extension.

Metamask is an extension to accessing Ethereum-enabled distributed applications or Dapps in your browser. You can install it here - https://metamask.io/download/
 
To deploy our smart contract, we will be using Alchemy. Its a platform that would enable us deploy our smart contract. You can signup for an account [Here](https://www.alchemy.com/)

To get a free Ethereum to test our contract, you can get from the ropsen test network or from goerli faucet - https://goerlifaucet.com/

When you have created Alchemy account, it should take you to the dashboard like this:

![Alchemy dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fpm4665xx1dazx8erj03.PNG)

Click on Apps Menus on the Dashboard and click on the create App button to create an App. See below:

![Create App](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nyga05gyvqv313nqpv8x.PNG)

Writing code to deploy your application.