Full stack web3 - fundraising decentralized app

SHARE

Topics

  • Introduction
  • New react app
  • Truffle
  • Smart contracts
  • Fundraiser setup
  • Material UI
  • React routing
  • Finishing up

Set up a fundraising campaign, donate ETH, generate a receipt, and withdraw the amount

photo credit: Shubham Dhage

We’re going to use React Truffle Box to generate frontend code for our Web3 application to get it running quickly and interact with Web3. Let’s start by making a new directory for our fundraiser application and creating a fresh Truffle React Box application inside it.

The first thing we will need to do is create a new empty repository for our Fundraiser application. Next, we’ll change into that directory and unbox the React Truffle Box:

mdkir fundraiser cd fundraiser truffle unbox react

Excluding the node_modules directory, our directory structure should now look like the following:

Remove contracts/SimpleStorage.sol, migrations/2_deploy_contracts.js and empty test folder:

rm contracts/SimpleStorage.sol **\** migrations/2_deploy_contracts.js \ test/*

Next, you’ll need to create new files for our contracts and the migration. First, create all the empty files for our contracts and our migration:

touch contracts/FundraiserFactory.sol touch contracts/Fundraiser.sol touch migrations/2_factory_contract_migrations.js

We’ll also need to install OpenZeppelin because we are using the Ownable contract:

npm install @openzeppelin/contracts

And in the Fundraiser.sol file, change the import statement to use the node_module we just installed from OpenZeppelin:

import '../client/node_modules/@openzeppelin/contracts/ownership/Ownable.sol';

The code for the Fundraiser.sol is given below: https://gist.github.com/ac12644/98b2e9b2fba5cedf0b388a6e106b07b0#file-fundraiser-sol

The code for the FundraiserFactory.sol is here: https://gist.github.com/ac12644/bf381a0fbccb76d0b9bd5b01716d848f#file-fundraiserfactory-sol

After we’ve added the contracts, let’s get our Truffle development environment up and running again.

In the fundraiser repository, let’s run the commands to compile and migrate our Fundraiser contracts so we can interact with them from our frontend application:

truffle develop

After that command has finished running, we’ll run the compile and migrate in that same terminal window:

compile  
migrate

If you ever run into migration issues and get stuck on the solution, try running migrate — reset.

If your contracts have migrated successfully, they should look like this output:

Starting migrations...

Network name: 'develop'
Network id: 5777
Block gas limit: 0x6691b71_initial_migration.js
======================Replacing 'Migrations'


transaction hash: 0xf04ee2a0c62330e7a051148d4660de...
Blocks: 0 Seconds: 0
contract address: 0x6Af651D4c6E9f32a627381B...
block number: 1
block timestamp: 1566526994
account: 0xb94454C83ff541c82391b...
balance: 99.99477342
gas used: 261329
gas price: 20 gwei
value sent: 0 ETH
total cost: 0.00522658 ETH> Saving migration to chain.
Saving artifacts


Total cost: 0.00522658 ETH2_factory_contract_migrations.js
================================Replacing 'Factory'


transaction hash: 0xebc5a26bbe12f52b809d9144...
Blocks: 0 Seconds: 0
contract address: 0xB7780C9AD3ef38bb4C8B48fab37...
block number: 3
block timestamp: 1566526995
account: 0xb94454C83ff541c82391b4...
balance: 99.95063086
gas used: 2165105
gas price: 20 gwei
value sent: 0 ETH
total cost: 0.0433021 ETH> Saving migration to chain.
Saving artifacts


Total cost: 0.0433021 ETH
Summary
=======> Total deployments: 2
Final cost: 0.04852868 ETH

Fundraiser Setup

Let’s work on getting our React Truffle Box up and running so we can interact with our application.

We’ll first need to cd into the src file of our React application and install all of the dependencies that the React Truffle Box provided for us.

After that, we’ll need to start up the frontend of our application just like we did in the previous chapter:

cd client  
npm i

After the modules have finished installing, start up the server:

npm start

If everything has been installed properly and started successfully, we can now navigate to localhost:3000 to see our Web3 application. See

Oops! We forgot to switch our network to match our new application. We’ll need to be on the same network so our app can run properly.

Let’s first go into MetaMask and switch the network at the top to be Localhost 8545.

Localhost 8545 should be in the default list. If not, you can refer back to the previous chapter and add it.

When we ran truffle develop, we saw this: Truffle Develop started at http://127.0.0.1:9545/

Copy http://127.0.0.1:9545/ to your clipboard. Next, we need to open MetaMask and import that network. Open the MetaMask extension and select Main Ethereum Network. We’ll need to select Custom RPC and enter http://127.0.0.1:9545 where it says New RPC URL.”

metamask

Go to My Accounts > Import Account

Paste the private key generated after truffle develop in the MetaMask import and select Import.

Now, refresh the screen and you should see the simple storage UI we saw before. Verify that your page looks like

With our app running, let’s start in our App.js file and rip out some of the boilerplate code to prepare our frontend to interact with the fundraiser.

First, navigate to the [client/src](https://github.com/ac12644/fundraiser_dapp/tree/master/client/src) directory and open the App.js file. We’ll need to remove the old React code and replace it with our own React code: https://gist.github.com/ac12644/4ae75f9dcbb21819490cc70551be7b51#file-app-js

React Routing

We’ll need to set up routes in our React application. We’ll use react-router-dom to let a user see different pages, depending on what they’ve selected from the navbar.

We’ll start by installing the npm package for react-router-dom:

npm install — save react-router-dom

After you’ve installed the npm package and restarted your frontend server, import the necessary files from react-router-dom in your App.js file, as shown here:

import { BrowserRouter as Router, Route, NavLink } from "react-router-dom"

We’ll also need to import our two new components for the home page and the new fundraiser to use in our routes:

import NewFundraiser from './NewFundraiser'  
import Home from './Home'

Next, let’s replace the render function with the following code. This will enable us to use the navbar provided from Material UI to navigate to different pages throughout our app: https://gist.github.com/ac12644/7123d8390d5937a6eeb404ca8a5d3968#file-app-js

Create two new files: Home.js and NewFundraiser.js.

We’ll use the home page component as our main landing page for our application and the New Fundraiser page to create a new fundraiser in our application:

touch Home.js  
touch NewFundraiser.js

Let’s work on creating the Home view. Inside your [Home.js](https://github.com/ac12644/fundraiser_dapp/blob/master/client/src/Home.js) file, use the following placeholder code and save that file: https://gist.github.com/ac12644/249f05f5e1a7470caeb218f07605752e#file-home-js

Similarly, in the NewFundraiser.js file, add this code: https://gist.github.com/ac12644/034a5ebeadf6d48aec51d19e47b83403#file-newfundraiser-js

We’ll need to do is modify the code in our index.js file so we can render routes properly.

We’ll use BrowserRouter from react-router-dom to wrap our application in a Router: https://gist.github.com/ac12644/98767afe42ebb9d12bfcb7c8f5941483#file-index-js

React and Material UI

Let’s begin by installing Material UI into our application.

Run the install command in your client directory to install react-bootstrap in our fundraiser application as follows:

npm install @material-ui/core --save

From the Material UI site, let’s look at the app bar page here.
Let’s start with the simple app bar.

First, we’ll need to add all the imports to the top of our App.js file. This will allow us to use the Material UI components we need:

import { makeStyles } from '@material-ui/core/styles';  
import AppBar from '@material-ui/core/AppBar';  
import Toolbar from '@material-ui/core/Toolbar';  
import Typography from '@material-ui/core/Typography';

Now that we have the imports, we need to add in the styles so our fundraiser app looks good.

You’ll need to add in these styles after your useEffect function:

const useStyles = makeStyles({  
      root: {  
        flexGrow: 1,  
      },  
});  
const classes = useStyles();

After you’ve imported the correct files and added the style preceding code, let’s replace the actual render code so we can see our new navbar:

Let’s quickly add a little styling to the NavLink component so it looks more professional.

In your App.css file, add these to the file:

Creating Our New Fundraiser Page View

We’ll start by using Material UI’s text field component. Add an import statement to your NewFundraiser.js file right after your latest import statement. Now, let’s move on to getting Web3 so we can access our Factory contract [line 42].

In our NewFundraiser.js file, update the useEffect function to use the Web3 code. The following code will create a new instance of our contract and set the state of Web3, our contract, and our current account.

Next, we need to import our contract and point to our contract that has been deployed locally in our NewFundraiser.js file [line 6–7]. https://gist.github.com/ac12644/7a365977d7ce51e3eecf196c65bd21a4#file-newfundraiser-js

Now that we’ve received the data from our contract, we’ll work on the front end to display each Fundraiser card to the user.

The first thing we’ll need to do is create a new component that we’ll use to display our Card component. Create a new file FundraiserCard.js. https://gist.github.com/ac12644/58936e3d9acbdf8a296773b5b1738b76#file-fundraisercard-js

If you navigate to localhost:3000, you’ll see that it’s blank for now. Let’s create a render function to go through each fundraiser and display them on a card.

Now, switch to [Home.js](https://github.com/ac12644/fundraiser_dapp/blob/master/client/src/Home.js) file, we’ll iterate through the list of fundraisers and display the Card component for each one:

const displayFundraisers = () => {  
      return funds.map((fundraiser) => {   
        return (  
          <FundraiserCard fundraiser={fundraiser} />  
       ) })  
}

fundraiser

Finishing Up

Adding Detailed Information About Each Fundraiser

The next item on our agenda is to display more information about each fundraiser to our users. Copy the following code and add it to FundraiserCard.js: https://gist.github.com/ac12644/3c38f7d7594f91f9d42a55d3c9905139#file-fundraisercard-js

The code for the App.js is given below: https://gist.github.com/ac12644/9af208636a6c7cbf186fd76c2a4e4ace#file-app-js

The code for the Receipts.js is given below: https://gist.github.com/ac12644/9faec855f937b70d29077b5947a11f5c#file-receipts-js