Creating a Simple Crowdfunding Dapp with Ethereum Solidity and Vue.js
A lot of us might have been in a situation wherein we had a brilliant idea, may it be of a product or an event, but just didn’t have the funds to bring it to life. This is where crowdfunding comes in.
You might have already heard of Kickstarter, or CAMPFIRE, which are some of the known crowdfunding platforms that currently exist. In this tutorial, we’ll be building something similar, specifically a simple decentralized crowdfunding platform using Ethereum.
What We Are About To Build
In this tutorial, we’ll be building a simple crowdfunding dapp which will have the ‘minimum’ functionalities that you’d expect from a crowdfunding platform. Basically, we should be able to start crowdfunding projects, and fund them, which will look like this:
Function List
- Start Project — we should be able to start a new crowdfunding project, along with setting its details like goal amount, etc.
- View Projects — we should be able to retrieve our existing projects’ details and display it
- Fund Project — we should be able to fund an existing project with Ether
- Retrieve Funds — in the case where a project does not meet its goal amount, and is past its deadline, funders should be able to retrieve their contributed funds (All-or-Nothing setup)
Tools
Aside from that, we will also be using Git later to clone our boilerplate :)
Prerequisites
Before proceeding with this tutorial, you should first read the following articles:
- Getting Started with Metamask
- Compile and Deploy Using Remix IDE
- Introduction to Smart Contracts and Solidity
Why Make a Crowdfunding App?
Great ideas need effort and funding. You can ask for donations or solicitations, but donors would of course prefer giving to projects where they have some sort of certainty that the project is actually going somewhere.
This is where crowdfunding comes in, an ideal setup where you can specify your goal, and a deadline for reaching it. If you miss your goal, the donations are returned, therefore reducing the risk for donors.
The existing platforms are all great, but in every completed project or in every donation sent, the platform takes a certain percent (margin) which could, at times, be too high for the project starters. What’s more, is that we heavily depend on them as the third-party that connects us to the donors. Should they fail, then we’re also in trouble.
With a decentralized setup, we can have a trustless platform and therefore the only fees everyone will pay are just the gas fees.
This is also one of the apps that are good to build early on, because you can definitely learn a lot by doing so.
Making the Project
Workflow
- Creating the Smart Contract
- Building the Web App
Creating the Smart Contract
We’ll be using Solidity, one of the programming languages used for creating smart contracts, specifically for Ethereum-based ones.
In Remix, create a new file named Crowdfunding.sol and add the following code:
We’re creating 2 contracts in one .sol file: Crowdfunding and Project. The Crowdfunding contract acts as a container for all Project contracts that will be initialized. Each crowdfunding project will have a contract of its own.
As for the Project contract, it is instantiated through the Crowdfunding contract, and handles all the methods that can be performed in every crowdfunding project, such as contribute(), getRefund(), etc.
Basically, each project will initially be in the Fundraising state, and will change states through the checkIfFundingCompleteOrExpired() function from there. Every time someone contributes funds towards the project, the state will change depending on certain conditions such has “has the project goal amount been met” or “has the project exceeded set deadline”.
Also, notice how we send funds from our contract in both the payOut() and getRefund() functions. We did not just directly send it, but had some security considerations because this is an area prone to a re-entrancy attack.
And so, compile the Crowdfunding contract (make sure you select compiler version at the right side of Remix, and choose 0.5.4+commit.9549d8ff because we are using Solidity version 0.5.4) and deploy it to the Ropsten Test Network. Make sure you are compiling and deploying the Crowdfunding contract.
To check that our contract was deployed, you should see the following:
Building the Web App
We’re done working on our smart contract. However, it doesn’t seem user-friendly and fun to just use Remix to interact with the contract, so we’ll be making a simple web application.
Setting Up
To get up to speed, let’s clone a boilerplate project (found here) by doing the following in a Terminal (or Command Prompt/Powershell for Windows):
# Cloning the boilerplate from GitHub
git clone -b boilerplate --single-branch https://github.com/openberry-ac/crowdfunding.git# Navigating to the directory and installing packages
cd crowdfunding
npm install# To run the app
npm run serve
In a few minutes, you should see the app running through a browser on http://localhost:8080. Apparently, all we see is a white screen, because there is an error. If we open our console, we can see this:
Thing is, we have not connected our web app with our smart contract instance yet, which causes this error. And so, that is exactly what we’re about to do next.
Connecting to Our Smart Contract Instance
To enable our web app to interact with our smart contract, we will be using web3.js. We already have the package installed, you can see how it is called in the file named web3.js inside the “contracts” folder, where we should put something like this:
It basically loads the web3 instance the MetaMask extension initializes, which we will be needing later to interact with our smart contract.
You might encounter a MetaMask pop-up window that asks for access permission. This is because we have ethereum.enable()
where the app requests for account (or wallet) access. You should just click the ‘Connect’ button right here:
Voila! You should see the app running through a browser on http://localhost:8080 looking like this (though it is not functional yet):
Now, we need our smart contract’s ABI to connect it to our web app. We have 2 contracts, so we need to get both their ABIs. To get it, go back to Remix, go to the Compile tab, and click ABI beside the Details button as shown in the picture (make sure Crowdfunding is selected):
After getting it, open the file named crowdfundInstance.js in the contracts folder, then paste it as the variable abi ’s value. There should be an example in the file, which you can always refer to.
Then, as you can see, we also need the deployed contract’s address, which you can get by going to Remix’s Deploy tab, and clicking the copy icon on your deployed contract, as shown in this picture:
Go back to crowdfundInstance.js in the contracts folder, then paste the address as the variable address ’ value. Save the file, and we’re done setting the contract information for our Crowdfunding contract. For the Project contract, just go back to Remix’s Compile tab, select the Project contract, and get the ABI just like this:
After getting it, open the file named crowdfundProjectInstance.js in the contracts folder, then paste it as the variable abi ’s value. There should be an example in the file, which you can always refer to. We’re all set!
Defining the Methods
As we see in the browser, our user interface is ready, but apparently, nothing is functional yet. That’s because we have not defined our functions yet, which we will be doing now. Go back to App.vue, and go to line 221 where you can see methods, but everything just contains a console.log().
Our first function is retrieving all projects and their details. Let’s modify the getProjects() function to look like this:
For this part, we simply call the returnAllProjects() function of our Crowdfunding contract to get all the projects’ contract addresses. Then, for each of them, we call getDetails() and store them in our defined objects, projectInstances, projectData, etc.
Next, we modify the function for starting a new project, startProject():
Here, we’re just calling Crowdfunding contract’s startProject() function, while passing the data that has been inputted through the form. The contract then receives the data and creates a new project. After that, we get data being returned by the ProjectStarted event, and store the new project, along with some default values, in the web app too.
Note that we use this.account
in this part, which was retrieved in the mounted() part of the code (executed when component has been mounted). It’s basically the current account that is active in Metamask.
Now that we’ve set the functions for starting and viewing projects, let’s see them in action, shall we?
Let’s start a new project by clicking “Start a Project”, filling the form, and then submitting it. Note that there aren’t any form validation in place, so it’d be ideal if you input valid values for now :)
Once that’s done, your newly created project should immediately show up on the projects list like this:
Note: The app might not appear like the one shown on the image though. The interface for funding the project might not show because project creators are not allowed to fund their own project.
Moving on, we have the method that handles the event when a user funds a certain project, fundProject():
Remember the contribute() function in our smart contract? We just call that function in fundProject() which sends the amount the user inputted in to the form.
After defining the fundProject() function, we should now be able to use the previously ‘not functional’ fund button. What’s more is that immediately after the transaction is completed, the progress bar is updated. It should look like this:
Finally, we have getRefund(), which allows the user to retrieve his or her previously donated funds to an already expired (past deadline) project.
And, we’re done!
Refresh your browser to see the changes. This time, the whole web app is complete, and everything is functional! You should then be able to use it like this:
You can see the final result on this GitHub repository (master branch) which you can always refer to :)
Conclusion
We just finished making our simple crowdfunding platform! Awesome!
We learned how to instantiate a contract using another contract, and many more concepts related to Solidity through this application. We also learned how to set up our own project using Vue.js, and created a simple application.
So, what’s next?
Ethereum’s website has a crowdsale tutorial which you might want to check out. It’s similar to what we just did, but uses a different approach (more into having a Decentralized Autonomous Organization). You might also want to write everything from scratch as you already have an idea on how the whole thing works.
On a side note, you might want to check out openberry’s previous tutorial, Ethereum Solidity + Vue.js Tutorial Simple Auction Dapp within 10 minutes.
’til the next tutorial!
openberry is a tutorial marketplace, designed to allow anyone to learn blockchain programming.