---
# System prepended metadata

title: Creating a charity donation dApp using Celo Composer and React + RainbowKit Celo

---

# Creating a charity donation dApp using Celo Composer and React + RainbowKit Celo

This article is a step by step guide on building a charity donation dapp using Celo   Composer and React + Rainbow Kit

**RainbowKit**

[RainbowKit](https://www.rainbowkit.com) is a React library that makes it easy to add wallet connection to your dapp. You can customize it as you like as well. RainbowKit supports a good number of wallets it can also resolve address to ENS and display balance and much more! Rainbowkit rely on [ethers](https://github.com/ethers-io/ethers.js) and [wagmi](https://wagmi.sh).

**Set up your development environment**

Here are the steps to take to make sure your development environment is properly set up

1. Install Node.js and NPM (Node Package Manager) on your machine.
2. Install the Celo Extension Wallet on your browser or add Celo test network (Alfajores) to your MetaMask Wallet


**Creating your project using Celo Composer**

In your terminal, run the following command

`npx @celo/celo-composer create `

We are working with React so when prompted to choose a front-end framework, select React

![](https://i.imgur.com/WPCMTH0.png)

Next up, choose a web3 library for react app, select Rainbokit-celo

![](https://i.imgur.com/lSkmoz3.png)

We are using built-in contracts from Celo-Composer and will be selecting Hardhat framework, so select Hardhat 

![](https://i.imgur.com/ZUA2MKk.png)

For next steps, we will be prompted to create a Subgraph. We would not be creating a subgraph, so go ahead to select No

![](https://i.imgur.com/Wvir6rZ.png)

Then, proceed to give your project a name

![](https://i.imgur.com/6BInaOQ.png)

You did it! You just created a starter project dApp in few minutes using Celo-Composer

![](https://i.imgur.com/LZRt683.png)

Navigate to your project and let's continue buidling.

**Building out the smart contract**

In your IDE, drilldown packages to see the hardhat foler, here we will see contracts folder with inbuilt contracts

![](https://i.imgur.com/KfOuJvO.png)

Open the SupportToken.sol as this is the one we will be using. Here is how the code looks like 

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/**
 * @notice A simple ERC20 Token implementation that also accepts donation for the project
 */
contract SupportToken is ERC20 {
    uint sentIn;
    address payable owner;

    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    constructor() ERC20("Support Token", "STT") {
        /// @notice mint 10000 tokens to the owner
        _mint(msg.sender, 10000e18);
        owner = payable(msg.sender);
        sentIn = 0;
    }

    function acceptDonation(uint amount)
        public
        payable
        returns (bool accepted)
    {
        require(amount == msg.value, "Invalid amount!");

        sentIn += msg.value;

        return true;
    }

    function withdrawChest() public onlyOwner returns (bool) {
        bool success = owner.send(address(this).balance);

        if (success) return true;

        return false;
    }
}
```

Basically, this contract allows users to donate to the project by sending funds to the contract address. It also allows the owner of the contract to withdraw the donated funds. 

Create a .env file to store your environment variables, copy your private key from your Celo/Metamask wallet as applicable

CELO_NETWORK=https://alfajores-forno.celo-testnet.org
PRIVATE_KEY=YOUR_PRIVATE_KEY

Compile the contract by running the following command in the terminal

```bash
cd packages/hardhat/contracts
npm install --save-dev hardhat
npx hardhat compile
```

> Incase you run into any error like this ![](https://i.imgur.com/OYopWwo.png)
 
> As at February 2023, hardhat waffle has been depreciated, replace that in your hardhatconfig.js file with chai matchers.

Change` require("@nomiclabs/hardhat-waffle")` to `require("@nomicfoundation/hardhat-chai-matchers");`

 
 After a successful compilation, here is what you should see, 
 
` Compiled x Solidity files successfully`

**Testing your Smart Contract**

It is good practice to test your code. In the test folder, create a new file called support-token-test.js and test for different use cases like below 

```javascript
import { ethers } from "hardhat";
import { Signer } from "ethers";
import { expect } from "chai";

describe("SupportToken", function () {
  let owner;
  let supportToken;

  beforeEach(async function () {
    // Get the owner of the contract
    [owner] = await ethers.getSigners();

    // Deploy the SupportToken contract
    const supportTokenFactory = await ethers.getContractFactory("SupportToken", owner);
    supportToken = await supportTokenFactory.deploy();

    // Wait for the contract to be mined
    await supportToken.deployed();
  });

  it("should mint 10000 tokens to the owner", async function () {
    const balance = await supportToken.balanceOf(await owner.getAddress());
    expect(balance).to.equal(10000 * 10 ** 18);
  });

  it("should accept donation and update sentIn variable", async function () {
    const donationAmount = 1000;

    // Send a donation to the contract
    await owner.sendTransaction({
      to: supportToken.address,
      value: donationAmount
    });

    // Check that the sentIn variable has been updated correctly
    const sentIn = await supportToken.sentIn();
    expect(sentIn).to.equal(donationAmount);
  });

  it("should withdraw donation to owner's address", async function () {
    const donationAmount = 1000;

    // Send a donation to the contract
    await owner.sendTransaction({
      to: supportToken.address,
      value: donationAmount
    });

    // Get the initial balance of the owner's address
    const initialBalance = await owner.getBalance();

    // Withdraw the donation to the owner's address
    await supportToken.withdrawChest();

    // Check that the owner's address balance has been updated correctly
    const expectedBalance = initialBalance.add(donationAmount);
    const actualBalance = await owner.getBalance();
    expect(actualBalance).to.equal(expectedBalance);
  });
});
```

**Deploying your Smart Contract**

Deploy the contract to the network by creating a deploy.js file in the scripts directory

```bash
cd packages/hardhat/scripts
```

```javascript
const hre = require("hardhat");

async function main() {
  const SupportToken = await hre.ethers.getContractFactory("SupportToken");
  const supportToken = await SupportToken.deploy();
  await supportToken.deployed();
  console.log("SupportToken address deployed to:", supportToken.address);
}

main();
```

Then run this command

`npx hardhat --network alfajores run scripts/deploy.js`

After a succesful deployment, you would see the message

```bash
SupportToken address deployed to: 0x188AB17e37aF04a43f69f1454Fc4caC3edd3Af2D
```

You can also verify your contract on https://alfajores.celoscan.io

![](https://i.imgur.com/O4jjcBz.png)

**Creating your frontend**

Let us now start out our React frontend, we start by navigating to the react-app folder after the hardhat folder. 

![](https://i.imgur.com/9fBFUOw.png)


Rainbowkit has saved us the stress of writing functionalities for connecting wallet, we can see this in our` HeaderRK.tsx` file under components

```
import { ConnectButton } from "@rainbow-me/rainbowkit";
```


For starters, we need the web3 package so let's start by installing that running this command

`npm install web3`

Go to components folder and create a new component, you can call it Charities.tsx. In your component, import React like this 

`import React, { useState } from "react";`


Create a charity card with props making your code look like this

```typescript
type CharityCardProps = {
  imageSrc: string;
  name: string;
  description: string;
  address: string;
  onDonate: (amount: string) => void;
  donated: boolean
};

const CharityCard = ({
  imageSrc,
  name,
  description,
  address,
  onDonate,
}: CharityCardProps) => {
  const [donationAmount, setDonationAmount] = useState("");
```


Create a variable charities as well with values 

```typescript
const charities = [
  {
    name: "British Heart Foundation",
    description: "Description of Charity 1",
    address: "0x1234...",
    imageSrc: "https://via.placeholder.com/150?text=Charity+1",
  },
  {
    name: "World Vision UK",
    description: "Description of Charity 2",
    address: "0x5678...",
    imageSrc: "https://via.placeholder.com/150?text=Charity+2",
  },
  {
    name: "Save the Children",
    description: "Description of Charity 3",
    address: "0x9abc...",
    imageSrc: "https://via.placeholder.com/150?text=Charity+3",
  },
];
```

The rest of the code can look like this 

```javascript
const Charities = () => {
  const handleDonate = (amount: string) => {
    // Send donation to the charity address
  };

  return (
    <div className="container">
      <div className="row">
        {charities.map((charity, index) => (
          <div key={index} className="col-md-4">
            <CharityCard {...charity} onDonate={handleDonate} />
          </div>
        ))}
      </div>
    </div>
  );
};

export default Charities;
```

Create a wrapper that handles the contract, in your root folder, create a SupportTokenWrapper.js file and call your contract together with specifying the function you want to call in your component

```javascript
export async function getContract() {
  console.log("hey");
  const contractAddress = "0x188AB17e37aF04a43f69f1454Fc4caC3edd3Af2D";
  const contractABI = abi;
  let supportTokenContract;
  try {
    const { ethereum } = window;
    console.log(ethereum.chainId);
    if (ethereum.chainId === "0xaef3") {
      const provider = new providers.Web3Provider(ethereum);
      console.log("provider", provider);
      const signer = provider.getSigner();
      supportTokenContract = new Contract(contractAddress, contractABI, signer);
    } else {
      throw new Error("Please connect to the Alfajores network");
    }
  } catch (error) {
    console.log("ERROR:", error);
  }
  console.log(supportTokenContract);
  return supportTokenContract;
}

export async function donate(amount) {
  // Approve the transfer of donation amount to the charity address

  const contract = await getContract();
  const approvalTx = await contract.approve(
    "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
    amount
  );
  console.log(await contract);
  console.log(await approvalTx);
  // Transfer tokens to another account
  const transferTx = await contract.transfer(
    "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
    amount
  );
  console.log("Transfer transaction hash: ", transferTx.transactionHash);
  const finalTx = await contract.acceptDonation(amount, {
    value: amount,
  });
}

```

From here, notice the 2 transactions that will happen, first we will grant permission to access funds, next is transferring the funds from the donators account to the receivers address. 

Run you application by using this command

```
npm run dev
```

Your application will look like this

![](https://i.imgur.com/QA8JVdp.png)

To see RainbowKit in action, click on connect wallet to see a variety of wallets to choose from, then proceed to choose the one applicable to you


![](https://i.imgur.com/98oXx2f.png)


![](https://i.imgur.com/lr2iMmZ.png)

Fill in the donation amount in any charity of your choice and click donate. Your wallet will pop up as so, to first give access to funds

![](https://i.imgur.com/4uev7TB.png)

![](https://i.imgur.com/AoKZvOa.png)

And then send to the receiving account

![](https://i.imgur.com/XkxAslx.png)

If you look through your wallet transactions, you will find these 

![](https://i.imgur.com/aVxYvXD.png)

The recipient can confirm the tokens in their wallet as well by importing the token with the contract address 0x188AB17e37aF04a43f69f1454Fc4caC3edd3Af2D for this demo and check 

![](https://i.imgur.com/dmZwxwy.png)

Great job! You just created a simple charity donation dApp with Celo Composer and React Rainbowkit! 