Skip to main content

Claim an ERC20 Token with NextJS

· 5 min read
Raza Zaidi

In this guide, we will allow users to claim ERC-20 tokens in a Next.js app and show the holders of our token!

Intro

Just like our NFT Drop contract, the Token Drop contract makes the token available for users to claim. In other words, the actual minting happens when a user claims the token. In this app a user can claim our token. Right at that time the ERC-20 token is minted and sent to the wallet of that user. This app also shows all the wallets that hold this token.

Check out our example repository with the project built out on Github and click here to see a live example of the app.

Flow

The user flow of this app is as follows, a user enters the app, connects their wallet and enters the number of tokens they want to claim. Once the claim button is clicked, the transaction is processed and the user receives their tokens. Please note, the tokens have to be imported in the wallet to be visible inside the wallet. Once the transaction is processed, the user’s wallet is added to the list of token holders.

Setup

To build this app, we need to walk through the following steps.

  1. Deploy a Token Drop contract and define the claim phases for your NFTs
  2. Build the NextJS project (we will be using the starter template thirdweb has made available!)
  3. Build the front end, including a Claim button for the token
  4. Build a list of token holders in our front end

Build

First, deploy a Token Drop contract from thirdweb’s dashboard by clicking on + Deploy new contract. Navigate to the Token Drop contract by clicking on Pre-built contracts and then Release a drop.

Don't forget to set your claim conditions under Claim Phases once you have deployed!

Next, go ahead and run the following command to get the Next.js JavaScript starter template.

npx thirdweb create --next --js

Inside the _app.js file, change the chain ID to the chain you deployed the smart contract to.

import { ChainId, ThirdwebProvider } from "@thirdweb-dev/react";

// This is the chainId your dApp will work on.
const activeChainId = ChainId.Mainnet;

function MyApp({ Component, pageProps }) {
return (
<ThirdwebProvider desiredChainId={activeChainId}>
<Component {...pageProps} />
</ThirdwebProvider>
);
}

export default MyApp;

We will go through the logic but won't show every piece of code. If you want to have a look at the full piece of code, check out the repo!

Connect our smart contract

Inside the index.js file import the hook to connect to our Token Drop contract and pass your contract address.

import {useTokenDrop} from "@thirdweb-dev/react";
//add your own contract address below
const tokenDropContract = useTokenDrop(<CONTRACT_ADDRESS>);

Claim component

We’re going to use the useClaimToken hook from the React SDK to allow the connected wallet to claim tokens from the drop.

Because we’re allowing the user to enter the amount, we need to make use of the react hook useState to allow our app to handle the dynamic input.

const address = useAddress();
const [amountToClaim, setAmountToClaim] = useState("");
const { mutate: claimTokens } = useClaimToken(tokenDropContract);

async function claim() {
if (!amountToClaim || !address) {
return;
}

try {
claimTokens(
{
to: address,
amount: amountToClaim,
},
{
onSuccess: (data) => {
console.log("Claimed", data);
alert("Successfully claimed!");
},
},
);
} catch (e) {
console.error(e);
alert(e);
}
}

Finally, we bind the method via a function to a button

<button onClick={claim}>

The full code looks something like this 👇

import { useAddress, useClaimToken } from "@thirdweb-dev/react";
import React, { useState } from "react";

export default function Claim({ tokenDropContract }) {
const address = useAddress();
const [amountToClaim, setAmountToClaim] = useState("");
const { mutate: claimTokens } = useClaimToken(tokenDropContract);

async function claim() {
if (!amountToClaim || !address) {
return;
}

try {
claimTokens(
{
to: address,
amount: amountToClaim,
},
{
onSuccess: (data) => {
console.log("Claimed", data);
alert("Successfully claimed!");
},
},
);
} catch (e) {
console.error(e);
alert(e);
}
}

return (
<div>
<input
type="text"
placeholder="Enter amount to claim"
onChange={(e) => setAmountToClaim(e.target.value)}
/>

<button onClick={claim}>Claim</button>
</div>
);
}

Token Holders

Now to render out a list of our token holders, we’ll use the getAllHolderBalances method.

It’s straightforward, build the function and render it out inside the component like this.

Let’s build out the function first:

const [holders, setHolders] = useState([]);

async function checkHolders() {
//define the method
const balances = await token.history.getAllHolderBalances();
//assign the data to the variable balances
setHolders(balances);
}

Next, we’ll trigger the function upon loading the page. We can do that with the hook useEffect

useEffect(() => {
checkHolders();
}, []);

Now we need to render out the data inside our page. We can use a map method to render out all the holders and their balances like this.

{
holders?.map((holder) => (
<div key={holder.holder}>
<p>{holder.holder}</p>
<p>
{holder.balance.displayValue} {holder.balance.symbol}
</p>
</div>
));
}

Here is the full page, including a loading view and sorting of the balances 👇

export default function TokenHolders() {
const [loading, setLoading] = useState(true);
const [holders, setHolders] = useState([]);

async function checkHolders() {
const sdk = new ThirdwebSDK("mumbai"); // configure this to your network

const token = sdk.getToken("0xCFbB61aF7f8F39dc946086c378D8cd997C72e2F3");

const balances = await token.history.getAllHolderBalances();
setHolders(balances);
setLoading(false);
}
useEffect(() => {
checkHolders();
}, []);

if (loading) {
return <div>Loading...</div>;
}

return (
<>
<div>
{holders
.sort(
(a, b) =>
parseInt(b.balance.displayValue) -
parseInt(a.balance.displayValue),
)
.map((holder) => (
<div key={holder.holder}>
<p>{truncateAddress(holder.holder)}</p>
<p>
{holder.balance.displayValue} {holder.balance.symbol}
</p>
</div>
))}
</div>
</>
);
}

That’s it!

That’s how you integrate the Token Drop contract with a NextJS app.

This guide is just an example of how to do it. Again we went over the core logic of the app.

Feel free to go to the repo to get a full copy and start building!