Build Transfer PWR DApp using Next.js
In this lesson, you will learn how to build a decentralized application (DApp) that allows users to transfer PWR tokens using Next.js. This DApp will provide a seamless interface for users to connect their wallets and initiate PWR token transfers securely and efficiently.
Prerequisites
Before starting, make sure you have the following:
- Download and setup PWR Wallet if you do not have it already.
- Request some Testnet PWR from a faucet like this one - PWR Chain Faucet.
- Install Node.js if you do not have it already (Use the LTS version, as that is stable. The latest version is experimental and may have bugs).
- We can start building.
Setting up our Next.js project
Open up your Terminal and run the following command to create a new project:
npx create-next-app@latest tranfer-dapp && cd tranfer-dapp
You will get options to create your project, select them as follows:
✔️ Would you like to use TypeScript? … (No)
✔️ Would you like to use ESLint? … (Yes)
✔️ Would you like to use Tailwind CSS? … (Yes)
✔️ Would you like to use src/ directory? … (No)
✔️ Would you like to use App Router? (recommended) … (Yes)
✔️ Would you like to customize the default import alias (@/*)? … (No)
Once it's done, you'll need to install the PWRJS library into the project, run the following command:
npm install @pwrjs/core
Build the homepage
In this part we will build, connect wallet, disconnect, listen for events and send transactions (transferPWR) to PWR Chain.
Building the homepage (src/app/page.js
) which will show everything. The code is explained in the comments, take the time to write it yourself and understand it.
"use client";
import { useState, useEffect } from "react";
import {
PWRWallet, connect, disconnect,
isInstalled, getConnection, getEvent,
} from "@pwrjs/core";
export default function Home() {
// Create a new pwr wallet
const pwr = new PWRWallet();
// Check if the user's wallet is connected
const [connected, setConnected] = useState(false);
// State variable to store recipient address input
const [recipient, setRecipient] = useState("");
// State variable to store amount input
const [amount, setAmount] = useState(0);
// State variable to store tx hash after send it
const [txHash, setTxHash] = useState("");
// Connect wallet with the website
const connectWallet = async () => {
const res = await connect();
// Check if the connect completed
res && setConnected(true);
}
// Disconnect wallet from the website
const disconnectWallet = async () => {
const res = await disconnect();
// Check if the disconnect completed
(!res) && setConnected(false);
}
// Transfer pwr tokens from the user's wallet connected to recipient address
const trasnfer = async () => {
if (connected && recipient.length==42) {
// send the transfer tx to pwr chain
// the `true` parameter means send the transaction from the browser user's wallet
const tx = await pwr.transferPWR(recipient, amount.toString(), true);
if (tx) {
setTxHash(tx);
alert(`Sent ${amount} to ${recipient.slice(0, 7)}...${recipient.slice(-5)}`);
}
} else {
alert("Check from the recipient address or wallet connection.");
}
}
// Piece of code that runs everytime the user's wallet changes or disconnected
useEffect(() => {
// Check if pwr wallet already installed
if (isInstalled()) {
// Used to re-fetch the connected user's account every time
// the website is refreshed.
getConnection().then(address => {
address && setConnected(true);
});
// Used to listen to any account changes that occur in the wallet.
getEvent("onAccountChange", (accounts) => {
console.log(accounts[0])
setConnected(accounts.length > 0);
})
}
}, []);
return (
<div className='max-w-md mx-auto bg-[#0c1012] p-5 rounded-lg justify-center items-center mt-36'>
<p className="text-center mb-6 font-bold">TRANSFER PWR APP</p>
<form>
<div className="mb-5">
<label className="block mb-2 text-md font-medium text-[#bebbbb]">Recipient Address</label>
<input onChange={(e) => setRecipient(e.target.value)} placeholder='0xac09bec...f80' className="border text-sm rounded-lg block w-full p-2.5 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500"/>
</div>
<div className="mb-5">
<label className="block mb-2 text-md font-medium text-[#bebbbb]">Amount</label>
<input onChange={(e) => setAmount(e.target.value)} placeholder='0' className="border text-sm rounded-lg block w-full p-2.5 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500"/>
</div>
</form>
{connected ? (
<div>
<button onClick={() => trasnfer()} className="text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-sm w-full mt-4 px-5 py-2.5 text-center bg-blue-600 hover:bg-blue-700 focus:ring-blue-800">
Transfer
</button>
<button onClick={disconnectWallet} className="text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-sm w-full mt-4 px-5 py-2.5 text-center bg-blue-600 hover:bg-blue-700 focus:ring-blue-800">
Disconnect
</button>
{txHash && (
<p className="text-[#bebbbb] pt-4">
Transaction hash: {" "}
<a href={`https://explorer.pwrlabs.io/transactions/${txHash}`} className="text-blue-300 underline" target="_blank">
{txHash.slice(0, 6)}...{txHash.slice(-4)}
</a>
</p>
)}
</div>
) : (
<button onClick={connectWallet} className="text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-sm w-full mt-4 px-5 py-2.5 text-center bg-blue-600 hover:bg-blue-700 focus:ring-blue-800">
Connect Wallet
</button>
)}
</div>
);
}
Testing the app
Let's run it! With your Terminal pointing to the frontend directory - execute the following command:
npm run dev
This will start the Next.js server and your website should be accessible at http://localhost:3000/
Go through the app, try out different things - connect wallet, transfer pwr and send transactios, change accounts, and disconnect and see all the things happening on PWR Chain Explorer as well.
Submit your first transaction using your app - what should appear after submitting the transaction:
If you've made it this far, you're done 🥳
Congratulations!
You're all done! I hope you were able to learn a few new things from this one.
If you have any doubts or questions, join the Discord Server and we'll be waiting for you there!