Creating a Web3 Charity Application

Sohum Padhye
10 min readJun 26, 2022

In my previous article, I went over how I created a GIF portal on the Solana blockchain using a tutorial on Buildspace. Over the past few months, I have been spending time learning how to create Web3 applications and program smart contracts on the Ethereum and Solana blockchains. Now, I wanted to put my knowledge to the test and create my own Web3 application that is simple enough for me to do on my own but still uses all the elements of a Web3 application.

I have searched several smart contract use cases and eventually decided to go with creating a charity application. In this article, I am going to talk about how I created this over the past few weeks, the challenges I faced along the way, as well as my overall experience and takeaways.

Overview

  • Functionality/Requirements
  • Design of my Application
  • Smart Contract/Backend Development
  • Frontend Development
  • Challenges
  • Project Walkthrough
  • Demo
  • Next Steps
  • Final Thoughts

Functionality/Requirements

For this charity application to be successful, I wanted it to work the following way:

  • The user must connect their Metamask wallet to the website before they can donate.
  • The user should be able to select a charity of their choice from the list of available charities.
  • For any selected charity, the user should be able to view the charity address and the total amount donated through the website.
  • The user should be able to donate any amount of ETH they would like, as long as they have enough funds.
  • The button to donate should be disabled initially. The button should enable only if the charity to donate is selected along with a donation amount that is greater than zero, and less than the user’s ETH balance.
  • Once the donation is successful, the user should receive a message saying that their donation was successful and show that the donated amount to the charity increased.

Design of my Application

Once I decided how my application should work, I thought about how I should design the backend and frontend.

Backend

For the backend, I chose to write a smart contract using Solidity with the Ethereum blockchain. I felt that I had the most experience with Solidity and Ethereum over other options like Rust and Solana. Also, Ethereum is the most widely-used blockchain for building smart contracts.

Frontend

For the frontend development, I decided to keep it simple and use React and Hardhat. I wanted to have a list of charities, and I had a couple of options on how to do that. I have explored multiple options such as using radio buttons, creating a dropdown list, or allowing the user to enter the charity name themselves. After weighing the pros and cons associated with all of these options from a design perspective, I decided to go with the dropdown. This is a dropdown list of pre-selected charities that would be built into my application.

For the amount to donate, it was a simple decision to make an input field in which the user could enter any amounts they wished to donate.

I would also need a “donate” button that would enable and disable dynamically based on the user’s inputs.

Once I thought about the look and feel of the frontend, then I needed to think about the structural design of the application that would lay out what React components I would need. This would allow me to go into development in a systematic way.

Smart Contract/Backend Development

In my smart contract on the backend, I had looked at several ways to transfer funds to another account, but I went with what I thought was the simplest way.

When a user calls a function (transferFunds), they have to send funds along with the call. The amount of these funds is determined by what the user puts in the input field for the amount to donate to the charity. Essentially, this step of the user sending funds with the function automatically happens, so I didn’t need to write a line of code on the smart contract for that.

You can think of it like the smart contract has its own wallet. When the function gets executed, funds are first sent to the smart contract, then from there, we need to write a line of code to send the funds from the smart contract to.transfer(msg.value)to the receiver, which in this case is the charity that the user wanted to donate to.

Frontend Development

I found the frontend development to be quite hard, especially because I also had to connect it to the smart contract ABI and address. However, by using Remix I was able to get the full ABI for the smart contract, as well as its address on the Rinkeby testnet.

React

For the frontend I decided to use React because it would help me dynamically render various things I needed in this application. For example, it helped me program the enabling and disabling of the donate button based on the inputs of different fields, and it also helped me show a success message when the transaction went through.

I used React with hooks/functional components, not class components because it provides an easier developer experience and makes the code look cleaner. Read more here.

Challenges

Connecting to the Metamask Wallet

I was having a bit of trouble programming the logic for checking whether a wallet is connected and if it’s not, request Metamask to connect. Eventually, I found a solution online on how to do this.

Here, I’m using a function called ethereum.request(). This function sends a request to check the current Ethereum accounts connected to the site.

Here, I check if the list of accounts has anything in it, and if it doesn’t, then I call the function to connect to the Metamask wallet. However, if there is a list of accounts returned, but the current account that is in use is not the first one on the list, then it switches the current account to the first account in the list.

Here, I use the ethereum.request() function again, but instead of trying to call the list of accounts, it tries to request more accounts. After that, it checks again if there is an account in the account list. If Metamask is not in the browser, then it checks for other wallets, but if there are no Ethereum wallets in the browser/browser extensions, an alert will be shown to the user.

Finally, I call the checkIfWalletIsConnected() function as the page loads.

If an Ethereum address is connected to the website, it will render the CharityApp.

Displaying Updated Charity Recipient Balance

After the donations were successful, I wanted to find a way to update the balance of the charity without refreshing the page. The problem was that the logic of knowing when the transaction went through was in the DonateButton.jsx component. So, I needed to write code that would retrieve the new value of the balance from Metamask and update it in Recipient.jsx , but the problem was the files weren’t directly related. Instead, they both had a parent file of CharityApp.jsx .

So, I had to pass the new balance from DonateButton.jsx , to CharityApp.jsx , to Recipient.jsx . Here’s how I overcame this problem.

Upon getting a successful transaction message, I request the new balance for the current recipient address. Then, I call a function that passes this balance with props and sends the value to the parent component.

As you can see, in updateRecipientBalance, I’m calling a function in the CharityApp.jsx file.

Then, I update a state called recipient . I keep the same values, except for the last field, where I pass the new balance of the address.

Next, I pass this state as props into my recipient.jsx file.

Finally, I convert the number into base 10, because ethereum.request({ "eth_getBalance" }) returns a hexadecimal value.

Automatic Enabling/Disabling of the Donate Button

Initially, I set the donate button to be disabled, and I would enable it only if the below conditions were met.

These conditions are:

  • A valid charity is chosen (the address is not equal to null)
  • The amount the user wants to donate must be greater than 0
  • The amount the user wants to donate must be less than the user’s balance

The challenge in this section was to make sure all the logic was put in the right place, and all possible scenarios were included.

Project Walkthrough

High-level Folder Structure

Here is the main folder structure for my project:

  • Theartifacts folder contains all of the metadata, functions that can be called, and ABI of the smart contract.
  • The cache folder contains a list of all the compiled Solidity smart contracts so that they can be easily accessed when run.
  • The contracts folder contains all of the smart contracts that are used in the application, which in this case is only one.
  • The node_modules folder contains all of the dependencies that are needed for the project.
  • The public folder contains an HTML file that is rendered by default.
  • The scripts folder contains script files that can be used to call functions directly from the smart contract.
  • The src folder contains all of the source files, which include the React components as well as the CSS module files for some components.
  • The test folder contains test files to make sure the smart contract runs as expected.
  • The hardhat.config.js file contains some command-line statements for the easy use of Hardhat.
  • The package-lock.json and package.json files contain details for all of the dependencies that are being used for the project. However, the package-lock.json file is more specific.

Here is a more detailed look into the src folder:

  • The components folder contains all of the React components.
  • The styles folder contains all of the CSS module files.
  • The index.js file is where the entire React render starts from. It, along with App.jsx, are the only JSX files that are rendered by default in the project.

Demo

Next Steps

Although I have completed the basic functionality for the application, there are still a few things that I can work on, such as:

  • Converting using the fromWei() function: Currently, I convert from Wei to Ether by dividing by 10¹⁸. This was because I was having trouble importing the function from the Web3 module.
  • Predict gas needed for the transaction: Currently, I assume that the total gas required for executing the transaction is 0.0001 ETH. Instead, I would like to use a number which factors the exact required gas for executing the transaction, into the if statement which checks all of the fields to enable the donate button.
  • Show total donated amount: Currently, my code looks for the balance of the recipient address to show how much has been donated. However, there is a flaw because if the charity decides to convert all of the ETH that was donated to them into USD, then the balance resets to 0. Instead, what I can do is program a mapping on the smart contract side that updates with every transaction to show the actual total donated amount.
  • Fetch transaction history for a user or charity: What I would like to do is to let the user see all of the donations they made to charities through my website, and I would also like to display all of the donations made to a particular charity by all users.
  • Page styling: Currently my page uses basic styling, and is not very visually appealing to the user.

Final Thoughts

I have developed this application fully on my own. It gave me a significant learning experience in using Solidity for making a smart contract, with React and Hardhat for making the frontend. Although the end product is simple, it gave me a great appreciation of the kind of effort that is involved in building a fully-functional Web3 application. Creating it by myself gave me a huge sense of accomplishment and satisfaction, and motivates me to develop with Web3 more.

If you made it this far, thank you for reading and I’ll see you in the next article!

--

--