Build a Crowdfunding dApp on Mantle Network Using Ankr | Part 1

07/14/2312 min read

Mantleby Mantle

Developers

Tutorials

Build a Crowdfunding dApp on Mantle Network Using Ankr | Part 1

Gm gm! 👋🏼

Before we begin, please make sure bookmark/save the following link as all developer content will be posted to Mantle Network’s official website — link. In this tutorial, we will be building a crowdfunding dApp on Mantle Network using Ankr and ..

A quick shoutout to Ankr’s DevRel team for their articles in the docs, which made it really easy to reference existing examples and build this on short-notice!

By the end of this tutorial, you’ll be able to:

  • deploy crowdfunding smart contract on Mantle Network
  • and create a full-fledged frontend for your dApp

1

The Functionalities

  1. Start New Campaign — users will be able to start a new crowdfunding project by inputting some details about the campaign like title, story and goal amount to be raised.
  2. View Projects — users can see all the existing projects and campaign details on the homepage
  3. Make Donation — anyone can fund to the project they want to support in $MNT tokens

Step 1: Create a Hardhat project

We’re going to set up our project using Hardhat, the industry-standard development environment for Ethereum smart contracts. Additionally, we’ll also install OpenZeppelin contracts.

To set up Hardhat, run the following commands in your terminal:

mkdir mantle_crowdfunding-dapp && cd mantle_crowdfunding-dapp
npm init -y
npm install --save-dev hardhat
npx hardhat

Note: Choose the Create a Javascript project option from the menu and accept all defaults. To verify everything is installed properly, run this command in your terminal:

npx hardhat test

To install OpenZeppelin, run the following commands in your terminal:

npm install @openzeppelin/contracts

Step 2: Set Up Hardhat Configs

Navigate back to the project and find the hardhat.config.js file in root directory and the following code:

File: hardhat.config.js

/**
* @type import('hardhat/config').HardhatUserConfig
*/

require("dotenv").config();
require("@nomiclabs/hardhat-ethers");
require("@nomiclabs/hardhat-etherscan");

module.exports = {
solidity: "0.8.15",
networks: {
"mantle-testnet": {
url: "https://rpc.ankr.com/mantle_testnet",
accounts: [process.env.PRIVATE_KEY], // Uses the private key from the .env file
}
}
};

In this file, we have configured the solidity version, and network details and plugged Ankr’s free public RPC ↗ for Mantle Network Testnet.

Step 3: Connect Mantle Network to Your Project

Having created a MetaMask wallet and a smart contract, we can now interlink them. To accomplish this, we’ll employ the dotenv package.

  1. Install the dotenv pack in your project directory by running the following command from your terminal:
npm install dotenv --save
  1. Create a .env file in the root directory of our project. Note: Your .env file must only be named .env. Do not change the name to any form xx.env.
  2. Add your MetaMask private key 
PRIVATE_KEY = 0x___your__private___key

Step 4: Write Crowdfunding Smart Contract

Now that we have everything set up, we are all ready to write the smart contract for the donation-based crowdfunding platform. For that, navigate to contracts directory and you'll create a new file named crowdfunding.sol file. There's two main things to consider while making a crowdfunding contract -

  1. CrowdfundingProject — deals with a single project or campaign being created. It includes the makeDonation() function which calculates the amount raised and checks if the goalAmount is achieved or not while recording the wallet address of the donor.
  2. CrowdFactory — records for all the crowdfunding projects being created and launched.

Complete crowdfunding.sol file would look like:

// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.15;

//contract to record all crowdfunding projects
contract CrowdFactory {
address[] public publishedProjs;

event Projectcreated(
string projTitle,
uint256 goalAmount,
address indexed ownerWallet,
address projAddress,
uint256 indexed timestamp
)
;

function totalPublishedProjs() public view returns (uint256) {
return publishedProjs.length;
}

function createProject(
string memory projectTitle,
uint256 projgoalAmount,
string memory projDescript,
address ownerWallet
) public
{
//initializing CrowdfundingProject contract
CrowdfundingProject newproj = new CrowdfundingProject(
//passing arguments from constructor function
projectTitle,
projgoalAmount,
projDescript,
ownerWallet
);

//pushing project address
publishedProjs.push(address(newproj));

//calling Projectcreated (event above)
emit Projectcreated(
projectTitle,
projgoalAmount,
msg.sender,
address(newproj
),
block.timestamp
)
;
}
}

contract CrowdfundingProject {
//defining state variables
string public projTitle;
string public projDescription;
uint256 public goalAmount;
uint256 public raisedAmount;
address ownerWallet; //address where amount to be transfered

event Funded(
address indexed donar,
uint256 indexed amount,
uint256 indexed timestamp
)
;

constructor(
string memory projectTitle,
uint256 projgoalAmount,
string memory projDescript,
address ownerWallet_
) {
//mapping values
projTitle = projectTitle;
goalAmount = projgoalAmount;
projDescription = projDescript;
ownerWallet = ownerWallet_;
}

//donation function
function makeDonation() public payable {
//if goal amount is achieved, close the proj
require(goalAmount > raisedAmount, "GOAL ACHIEVED");

//record walletaddress of donor
(bool success, ) = payable(ownerWallet).call{value: msg.value}("");
require(success, "VALUE NOT TRANSFERRED");

//calculate total amount raised
raisedAmount += msg.value;

emit Funded(msg.sender, msg.value, block.timestamp);
}
}

Now, let’s compile hardhat to see if everything’s good to go!

yarn hardhat compile

Output would look something like this below 🦄

2

Step 5: Write the Deploy Script(s)

Now that we’ve got our contract set up, let’s create the deployment scripts. There will be two scripts, one for deploying the CrowdFactory contract and second for a dummy campaign creation with some dummy project info.

  • For the first script, navigate to the scripts folder and add the following code in deploy.js file
const { ethers } = require("hardhat");

async function main() {
// Grab the contract factory
const CrowdFactory = await ethers.getContractFactory("CrowdFactory");

// Start deployment, returning a promise that resolves to a contract object
const crowd = await CrowdFactory.deploy(); // Instance of the contract
await crowd.deployed();
console.log("Contract deployed to address:", crowd.address);
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
  • Save this file and run the following command to deploy the CrowdFactory contract
npx hardhat run scripts/deploy.js --network mantle-testnet

3

Running this command will prompt you with the address of the deployed contract.

4

Note: Save/copy your contract address as you will need it in your next deployment script.

Before we go on deploying another contract, let’s save this contract address in a file named constants.tx under src directory.

File: src/constants.tx

export const FACTORY_CONTRACT_ADDRESS = "paste your contract which was deployed above";
//just for testing purpose
export const DEBUG = false;

Now let’s deploy another contract with a sudo campaign details for us to get started. For this, we are going to create createCampaigns.js file under scripts directory. Navigate to that file and save the following code.

⚠️ Edits to make:

  1. Line 6, replace your contract address with the address mentioned already in the script (check line 6)
  2. Line 13, replace my wallet address with yours.

scripts/createCampaigns.js

const { ethers } = require("hardhat");
async function main() {
const contract = await ethers.getContractAt("CrowdFactory",
//add the contract address that you just deployed in the last step
"0x997ab899CC4b4a21EE3407b93b3EA2C4e32c4e21") //line 6
await contract.createProject(
"first title",
ethers.utils.parseUnits("0.1", 18),
"description",
//insert your wallet's public key
"0x0e7771d884588C77e0c65d062b30a6b6850b8337") //line 13
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

Once done, run the following command to deploy this script as well:

yarn hardhat run scripts/createCampaigns.js --network mantle-testnet

Step 6: Get Contract ABI for Verified Codes

In this step, we are going to do two things:

  1. we will verify our smart contracts on Mantle Explorer ↗
  2. get contract ABIs for verified contract source codes

Verifying Smart Contracts

  • Go to verify-factory.js file under scripts folder and add the following verify script:
Note: In this file you need to edit one thing. The contractAddress you see on line number 5 needs to be replaced by your contract’s address.
const { run } = require("hardhat");

async function main() {
//add the contract address that you deployed in the prev steps
const contractAddress = "0x997ab899CC4b4a21EE3407b93b3EA2C4e32c4e21"; //line 5

try {
await run("verify:verify", {
address: contractAddress,
constructorArguments: [],
contract: "contracts/crowdfunding.sol:CrowdFactory",
});
} catch (error) {
if (error.message.toLowerCase().includes("already verified")) {
console.log("Already verified!");
} else {
console.log(error);
}
}
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
  • Now in the terminal, run this command to verify the CrowdFactory smart contract on:
yarn hardhat run scripts/verify-factory.js --network mantle-testnet

Output:

5

Note: You might wonder how the above step worked when the Mantle Explorer isn’t built on EtherScan. Adding Mantle Network’s configuration to the hardhat.config.js file to enable contract verification on a custom network. This worked because Blockscout's contract verification interface is the same as Etherscan!

We could have also used Sourcify to verify our contracts — https://docs.mantle.xyz/network/for-devs/tutorials/verifying-smart-contracts. Next, head over to the Mantle Explorer link you get as the output after running the command and it will land you to the verified contract’s page. Click on Code and you’ll find the Contract ABI section.

6

  • Copy the ABI and paste it into the crowdfactory.json file under src/abis directory
  • Go back to the same Mantle Explorer link, click on the Read Contract button, and query “0” from the publishedProjs.
Copy and save the address it outputs, we will need it in line 5 of the next file.

6

Now, we are going to follow the similar steps to first verify our dummy crowdfunding project and get the contract’s ABI.

  • Navigate to verify-crowdfundingproject.js file under the scripts folder and insert the following code in the file:
Replace contractAddress in the file with the one we saved above querying the 0th publishedProj and also insert your wallet address on line 9
const { run, ethers } = require("hardhat");

async function main() {
//replace contractAddress with the one we saved above querying the 0th publishedProj
const contractAddress = "0x4a086a54e4d6bb8becb5752f46d290341f0e9af9"; //line5
const args = [
"first title", ethers.utils.parseUnits("0.1", 18), "description",
//Insert you wallet's public address here
"0x0e7771d884588C77e0c65d062b30a6b6850b8337", //line 9

];

try {
await run("verify:verify", {
address: contractAddress,
constructorArguments: args,
contract: "contracts/crowdfunding.sol:CrowdfundingProject",
});
} catch (error) {
if (error.message.toLowerCase().includes("already verified")) {
console.log("Already verified!");
} else {
console.log(error);
}
}
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
  • Once you save the above file, run this command to verify it on Mantle Explorer:
yarn hardhat run scripts/verify-crowdfundingproject.js --network mantle-testnet

Output:

7

  • Head over to the Mantle Explorer link you get as the output after running the command and it will land you on the verified contract’s page
  • Click on Code and you’ll find the Contract ABI section. find Contract ABI section and copy-paste ABI in the crowdfundingproject.json file under src/abis directory

Once this is done, run the following command in the terminal:

yarn typechain

TypeChain is a typescript binding and code generator used to create smart contracts that feature static typing and IDE support.

Congrats if you’ve followed along till now! In the next part, we will be creating components and building the UI.


Join the Community