My attempt to build a GoFundMe version on the Ethereum Blockchain part 2

Gbenro Adesoye
Coinmonks
10 min readDec 6, 2018

--

This is the second part to building a decentralized application similar to gofundme on the Ethereum blockchain.

The link to the part one is here

Photo by José Alejandro Cuffia on Unsplash

Additional code for the FundMe contract.

We are going to add a fundmeFactory contract. This will be responsible for producing the FundMe contract, yea, the factory gave it away. Here is the code for it.

As you can see, it is a very simple contract. we created an array of address called deployedFundraisers. Created a function called createFundMe which accepts the firstname, lastname, description and amount needed, this function calls the constructor of FundMe contract, pass all those parameters to it including the msg.sender. We get back an address which is what we get back when a contract is created. We saved the newly created contract address in newFundMe then push it to the deployedFundraisers array.

The second function, getDeployedFundraisers just returns the deployedFundraisers array. Why do we need this function when solidity automatically allows us to call a public variable(i.e deployedFundraisers) like a function? Good, you asked. The freely created function for the array will only allow us to access one item at a time, but we want to have access to all item when we call the array, hence, we create a getDeployedFundraisers.

We have written our contract in part one, added a factory contract to it, time to test it. But before that, we need to compile our contract. To do this we will need to download some dependencies.

We need Solc to compile our contract. Use npm install solc

We need fs-extra, a node module for building our file path. Use npm install fs-extra

I am assuming you are familiar with the node package manager and node js. If not you can download Nodejs, navigate to your project directory on the command line then run the command npm init.

Compiling

Create a new file called compile.js and add the following code to it.

Note: I put my fundme.sol file in a folder called contracts, you can also do that

Run the command on your terminal node compile.js make sure you are in the same directory on your terminal where the compile.js file is. If your code compiles, you should see a build folder turn up in your project, inside it will be two files, FundMe.json and FundMeFactory.json. These are your contract ABI in JSON format. This is what we will use to communicate with our contract when we deploy it to the blockchain

If you see the two compiled contract in your build folder, congratulations, you are ready for the main dish.

Testing

Now its time for the fun part. I have written 10 tests for this smart contract. It is very important to write a comprehensive and robust test, especially for smart contracts. If you don't know why by now, you really shouldn't be writing smart contracts but just to mention a few reasons, this is due to their immutability and with the fact that we are might be dealing with money or other valuables. Once deployed, we can't change it, this becomes worse if a malicious user finds out a contract’s vulnerabilities first. So we must ensure that our contract does what it is supposed to do.

Add the following dependencies to begin.

We need Mocha for testing. Use npm install mocha.

We need Web3 for communicating with our contract. Use npm install web3@1.0.0-beta.26. That is the version of web3 I am using.

We need ganache-cli for creating a local blockchain environment on our computer use npm install ganache-cli.

In your package.json file add to the scripts “test”: “mocha”.

Create a new file called FundMe.test.js

At the top require the following

For the compiledFactory and compiledFundMe, remember that they are in your build folder, make sure you navigate to the right directory as mine will be different from yours.

we will need the following variables

let accounts. the list of accounts from ganache

let factory. the instance of a FundMeFactory contract

let fundMeAddress. the FundMe contract address

let fundMe. the instance of a FundMe contract

In our beforeEach, we are going to get a list of all accounts from web3, deploy the FundMe factory contract to the blockchain, we then call the createFundMe function to create a new FundMe contract, get the address of the newly created fundMe contract. We then access the newly created contract. Do not forget to mark your beforeEach as async because we are dealing with the blockchain which requires a promise. If you don't know what that means, don't sweat it. It just means the action we want to perform won't happen immediately, so we need to wait a bit.

This is the code for the Above.

Now we can begin our test.

Create a describe, I called mine FundMe, with a callback function, put the ….I will just show you

So here, we are testing if we have successfully deployed both contracts. We then assert.ok if there is an address in the factory contract instance we created. We did the same for fundME.

Our test passed. Good job, we have successfully deployed our contracts.

Note: Put each test inside the describe and enter in the terminal npm run test each time you want to test

Test 2

We will add a second “it” to make sure the contract marks the contract caller as the recipient.

Here we are calling the freely created method by solidity, recipient(), notice that we added .call(). This is because we are just reading data and not changing the state of the contract. So this operation is free. We save it in recipient, we then assert.equal account[0] with the recipient. Remember we deployed our contract from account[0] in the beforeEach.

Our test passed.

Test 3

We will test if our contract allows people to donate money and also check if money was donated.

We called donate(), this time we will be changing the state of the contract which will cost some gas. The value is converted from ether to wei (0.5 ether, our contracts only accepts wei) and the donor is accounts[1]. So how do we check if they have actually donated, we can check the amountSoFar or check the balance of the contract, but here we are using the donorsAmount that shows how much each address have donated to the fundraiser. We can now assert to see if the amount is greater than 0.

Our test passed. you can see the value in wei, it is 17 zeros, I counted for you.

Test 4

We are testing here if the contract allows the recipient to withdraw money from the contract.

We first donated. Then we withdrew funds by calling from accounts[0], which is the account that created the contract, our recipient. To confirm that money was actually taken, we got the balance of the contract and assert if the balance was 0.

Our test passed.

Test 5.

We will test if the recipient can end the fundraiser.

Here we call the method end from acounts[0]. To confirm that this fundraiser has ended, we called the ongoing method which returns a boolean and save it inside isLive, should be false. We assert(!isLive). ! should negate the false making the assert true.

Our test passed. We are halfway there, for some programmers, testing is not fun but to be a blockchain developer, you must love testing, so get used to it now.

Test 6

We will test if the fundraiser ends when the goal is reached.

Here we donated from accounts[1] and donated more than what is needed which should end the fundraiser. Confirming is the same logic as above.

Our test passed.

Test 7

This test will be a little different, we will let our operation fail by trying to withdraw money with an address that is not the recipient.

Here we donated to the contract, then we added a try catch because the operation we want to do will fail. We try to withdraw from account[2], which should obviously fail. In the catch, we assert err to confirm there was an error.

Test 8

we will do something similar to the above, here we will check that our contract does not allow anyone else to end the contract.

Here we donated to the fundraiser, then in our try, we called the end function from accounts[2], which should obviously fail. To confirm that our fundraiser is still live, we called the ongoing() like we did in test 5 and 6 but this time we are checking if the fundraiser is still live.

Test 9

We want to test that the contract does not collect donation after the fundraiser has ended

Here, the recipient ends the fundraiser, we checked if the fundraiser is still ongoing to confirm if it has ended. We then put our logic in a try, we attempt to donate from account[2], this should fail. We assert if there is an error in the catch to confirm that the donation failed.

Test 10

Finally, we have reached the last test. Here we will do an end to end test i.e try to mimic the flow of a fundraiser. The flow will go like so:

The contract takes two donations.

Checks if two people donated.

Recipient withdraws the balance which makes contract balance 0.

The fundraiser should still be ongoing.

Contracts take a third donation.

The third donation should trigger the end of the fundraiser.

Checks if there are 3 donors now

Check if contract balance is 0

Checks if the goal was reached

Checks if the recipient’s balance is greater than the initial balance

Checks if fundraiser has ended

The contract does not allow any more donations

Yea, the last test is much longer. but we are finally done.

Note: The original balance in each account is 100ether. as we can see there is now 102.96 in account[0] balance.

The link to the test is above.

Thanks for reaching the end of this test, for many beginners this might be stressful, but it is a good idea to start getting used to testing.

I am sure there are other things we can still test for. Think of one more test we can write and let me know down in the comment.

We now have all the logic to communicate with our contract and can easily make a frontend for this smart contract.

I will be writing a smart contract audit next. It is always important to audit your contract, just to add that extra security and be close to being sure that there are no vulnerabilities in your smart contract. It is vital to allow external blockchain experts do the audit because they use their fresh eyes and expertise, they will probably find something you have missed. In the case of this audit. I will try to do it from a fresh perspective.

Get Best Software Deals Directly In Your Inbox

Click to read today’s top story

--

--