इस ट्यूटोरियल में, हम सीखेंगे कि एक Web3 Dapp (Decentralized Application) कैसे बनाया जाए जो आपके crypto wallet से कनेक्ट होता है, जिससे आप फंड ट्रांसफर कर सकते हैं और NFTs mint कर सकते हैं। हम Next.js, जो एक लोकप्रिय React फ्रेमवर्क है, और Wagmi.sh, जो React Hooks का एक कलेक्शन है जो आसानी से आपके वॉलेट को आपकी वेबसाइट के साथ इंटीग्रेट करता है, का उपयोग करेंगे।
यहाँ ट्यूटोरियल की एक रूपरेखा दी गई है:
- शुरुआत करें
- भाग 1: React + Wagmi के साथ Crypto ट्रांसफर करना
- भाग 2: React + Wagmi के साथ NFT Mint करना
Authorship
यह लेख RareSkills के एक रिसर्च इंटर्न Aymeric Taylor (LinkedIn, Twitter) द्वारा सह-लेखक (co-authored) किया गया है।
शुरुआत करें
सरलता के लिए, हम इस ट्यूटोरियल के लिए अपने टेस्ट नेटवर्क के रूप में “Polygon Mumbai” का उपयोग करेंगे, यह OpenSea पर भी सपोर्टेड है।
अपने Wallet को Polygon Mumbai - MetaMask से कनेक्ट करें
MetaMask → Settings → Advanced पर जाएं और सुनिश्चित करें कि आपने Show test networks को अनुमति दी है।

इसके बाद, ऊपर दाईं ओर के सेक्शन में Network Selection पर क्लिक करें और Add network चुनें।

यदि Polygon Mumbai पहले से ही चुनने के लिए उपलब्ध नहीं है, तो आप नीचे दिए गए चरणों का पालन कर सकते हैं।
Add a network manually चुनें और निम्नलिखित इनपुट करें:
Network Name: Matic Mumbai
New RPC URL : https://rpc-mumbai.maticvigil.com/
Chain ID : 80001
Currency Symbol : MATIC
Block explorer URL (वैकल्पिक) : https://mumbai.polygonscan.com/
अब बस Polygon Network पर स्विच करें।
Wagmi Examples भाग 1: React + Wagmi के साथ Ether ट्रांसफर करना
चरण 1: node js के साथ वेबसाइट सेट अप करें
इसके लिए आपके पास nodejs इंस्टॉल होना चाहिए।
सबसे पहले इसके साथ अपना Next.js प्रोजेक्ट बनाएं:
npx create-next-app@latest myapp
एरोज़ (arrows) और एंटर की (enter key) का उपयोग करके Typescript और ESLint विकल्प को चेक करें। यह कुछ इस तरह दिखना चाहिए:

अपने प्रोजेक्ट को vscode में खोलें और wagmi.sh और use-debounce package इंस्टॉल करें (हम इसके बारे में बाद में बात करेंगे)।
npm i wagmi ethers@^5
npm i use-debounce --save
Wagmi मूल रूप से React Hooks का एक सेट है जो Ethereum development को सरल बनाता है, इसके लिए यह वॉलेट्स को कनेक्ट करने और कॉन्ट्रैक्ट्स के साथ इंटरैक्ट करने जैसे उपयोगी फीचर्स प्रदान करता है, जिन्हें हम इस ट्यूटोरियल में सीखेंगे। wagmi.sh पर अधिक जानकारी।
चरण 2: कनेक्ट करने के लिए नेटवर्क चुनने हेतु configureChains का उपयोग करें
pages/_app.tsx पर जाएं और निम्नलिखित कोड जोड़ें। प्रत्येक कार्यक्षमता को कमेंट सेक्शन में समझाया गया है।
import "@/styles/globals.css"; // CSS doesnt really matter now
import type { AppProps } from "next/app";
import { WagmiConfig, configureChains, createClient, mainnet } from "wagmi";
import { publicProvider } from "wagmi/providers/public";
import { polygonMumbai } from "wagmi/chains";
import { CoinbaseWalletConnector } from 'wagmi/connectors/coinbaseWallet'
import { InjectedConnector } from 'wagmi/connectors/injected'
import { MetaMaskConnector } from 'wagmi/connectors/metaMask'
import { WalletConnectConnector } from 'wagmi/connectors/walletConnect'
// configure the chains and provider that you want to use for your app,
// keep in mind that you're allowed to pass any EVM-compatible chain.
// It is also encouraged that you pass both alchemyProvider and infuraProvider.
const { chains, provider, webSocketProvider } = configureChains(
[mainnet, polygonMumbai],
[publicProvider()]
);
// This creates a wagmi client instance of createClient
// and passes in the provider and webSocketProvider.
const client = createClient({
autoConnect: false,
provider,
webSocketProvider,
connectors: [ // connectors is to connect your wallet, defaults to InjectedConnector();
new MetaMaskConnector({ chains }),
new CoinbaseWalletConnector({
chains,
options: {
appName: 'wagmi',
},
}),
new WalletConnectConnector({
chains,
options: {
projectId: '...',
},
}),
new InjectedConnector({
chains,
options: {
name: 'Injected',
shimDisconnect: true,
},
}),
],
});
export default function App({ Component, pageProps }: AppProps) {
return (
// Wrap your application with the WagmiConfig component
// and pass the client instance as a prop to it.
<WagmiConfig client={client}>
<Component {...pageProps} />
</WagmiConfig>
);
}
अब हमारे नेटवर्क्स कॉन्फ़िगर हो गए हैं, हमारा अगला कदम यूज़र्स को यह चुनने की अनुमति देना है कि वे किस वॉलेट से कनेक्ट होना चाहते हैं। जैसा कि आप ऊपर देख सकते हैं, हमने 4 वॉलेट कनेक्टर्स सेट किए हैं। MetaMask, WalletConnect, Coinbase और Injected (जो फिर से मूल रूप से आपका डिफ़ॉल्ट वॉलेट है)।
चरण 3: ब्राउज़र वॉलेट चुनने में सक्षम करने के लिए useConnect का उपयोग करें
pages/index.tsx पर निम्नलिखित कोड को कॉपी और पेस्ट करें। सुनिश्चित करें कि आप css जोड़ते हैं, ताकि यह अच्छा दिखे!
import { useAccount, useConnect } from "wagmi";
import { useEffect } from "react";
import styles from "@/styles/Home.module.css";
export default function Home() {
const { connect, connectors } = useConnect();
const { isConnected } = useAccount();
useEffect(() => {
console.log(
`Current connection status: ${isConnected ? "connected" : "disconnected"}`
);
}, [isConnected]);
return (
<>
<p
className={styles.status}
style={{
color: isConnected ? "green" : "red",
}}
>
{" "}
{isConnected !== undefined
? isConnected
? "Connected"
: "Disconnected"
: "loading..."}
</p>
<div className={styles.maincontainer}>
<div className={styles.container}>
<div className={styles.buttonswrapper}>
<div className={styles.buttonswrapperGrid}>
{connectors.map((connector) => (
<button
suppressHydrationWarning
key={connector.id}
onClick={() => connect({ connector })}
className={styles.button28}
>
{connector.name}
</button>
))}
</div>
</div>
</div>
{/* send funds */}
{/* mint nft */}
</div>
</>
);
}
चरण 4: इसे अच्छा दिखाने के लिए css जोड़ें
styles/globals.css और styles/Home.module.css से सब कुछ डिलीट कर दें।
नीचे दिए गए css कोड को styles/globals.css पर कॉपी पेस्ट करें।
body {
height: 100vh;
background: rgb(11,3,48); /* For browsers that do not support gradients */
background: linear-gradient(to bottom right,#0b0330, #5904a4);
font-family: 'Inter Medium', sans-serif;
}
नीचे दिए गए css कोड को styles/Home.module.css में कॉपी पेस्ट करें।
.status {
text-align: left;
margin: 0px;
font-family: "Inter Medium", sans-serif;
}
.maincontainer {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 60%;
width: 60%;
}
.buttonswrapperGrid {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr);
grid-gap: 1.5rem;
justify-items: center;
align-items: center;
justify-content: center;
margin-bottom: 40px;
padding: 20px;
}
/* CSS */
.button28 {
align-items: center;
background-color: #da5fff;
border: 2px solid #1d0321;
border-radius: 8px;
box-sizing: border-box;
color: #111;
cursor: pointer;
display: flex;
font-family: Inter, sans-serif;
font-size: 16px;
height: 55px;
justify-content: center;
line-height: 24px;
max-width: 75%;
padding: 0 25px;
position: relative;
text-align: center;
text-decoration: none;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
width: 100%;
}
.button28:after {
background-color: #210c20;
border-radius: 8px;
content: "";
display: block;
height: 48px;
left: 0;
width: 100%;
position: absolute;
top: -2px;
transform: translate(8px, 14px);
transition: transform 0.2s ease-out;
z-index: -1;
}
.button28:hover:after {
transform: translate(0, 0);
}
.button28:active {
background-color: #ffdeda;
outline: 0;
}
.button28:hover {
outline: 0;
}
@media (min-width: 768px) {
.button28 {
padding: 0 40px;
}
}
.myinput {
background-color: rgb(253, 232, 255);
border-radius: 15px;
border: 2px solid #1d0321;
padding: 20px;
width: 44%;
height: 15px;
}
.inputcontainer {
display: flex;
justify-content: space-between; /* Space the input fields evenly */
align-items: center; /* Align the input fields vertically in the container */
}
.buttoncontainer {
display: flex;
justify-content: center; /* Center the button horizontally */
align-items: center; /* Center the button vertically */
margin-top: 16px;
margin-bottom: 16px;
}
.mintcontainer {
display: flex;
justify-content: center; /* Center the button horizontally */
align-items: center; /* Center the button vertically */
margin-top: 50px;
margin-bottom: 16px;
}
/* CSS */
.button64 {
align-items: center;
background-image: linear-gradient(144deg, #af40ff, #280b36 50%, #e30eff);
border: 0;
border-radius: 8px;
box-shadow: rgba(151, 65, 252, 0.2) 0 15px 30px -5px;
box-sizing: border-box;
color: #ffffff;
display: flex;
font-family: Phantomsans, sans-serif;
font-size: 20px;
justify-content: center;
line-height: 2em;
max-width: 100%;
min-width: 140px;
padding: 3px;
text-decoration: none;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
white-space: nowrap;
cursor: pointer;
}
.button64:active,
.button64:hover {
outline: 0;
}
.button64 span {
background-color: rgb(5, 6, 45);
padding: 16px 24px;
border-radius: 6px;
width: 100%;
height: 100%;
transition: 300ms;
}
.button64:hover span {
background: none;
}
@media (min-width: 768px) {
.button64 {
font-size: 24px;
min-width: 196px;
}
}
/* CSS */
.button49,
.button49:after {
width: 150px;
height: 76px;
line-height: 78px;
font-size: 20px;
font-family: 'Bebas Neue', sans-serif;
background: linear-gradient(45deg, transparent 5%, #ff01ee 5%);
border: 0;
color: #fff;
letter-spacing: 3px;
box-shadow: 6px 0px 0px #00E6F6;
outline: transparent;
position: relative;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
}
.button49:after {
--slice-0: inset(50% 50% 50% 50%);
--slice-1: inset(80% -6px 0 0);
--slice-2: inset(50% -6px 30% 0);
--slice-3: inset(10% -6px 85% 0);
--slice-4: inset(40% -6px 43% 0);
--slice-5: inset(80% -6px 5% 0);
content: 'GET YOUR NFT';
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(45deg, transparent 3%, #00E6F6 3%, #00E6F6 5%, #c401ff 5%);
text-shadow: -3px -3px 0px #F8F005, 3px 3px 0px #00E6F6;
clip-path: var(--slice-0);
}
.button49:hover:after {
animation: 1s glitch;
animation-timing-function: steps(2, end);
}
@keyframes glitch {
0% {
clip-path: var(--slice-1);
transform: translate(-20px, -10px);
}
10% {
clip-path: var(--slice-3);
transform: translate(10px, 10px);
}
20% {
clip-path: var(--slice-1);
transform: translate(-10px, 10px);
}
30% {
clip-path: var(--slice-3);
transform: translate(0px, 5px);
}
40% {
clip-path: var(--slice-2);
transform: translate(-5px, 0px);
}
50% {
clip-path: var(--slice-3);
transform: translate(5px, 0px);
}
60% {
clip-path: var(--slice-4);
transform: translate(5px, 10px);
}
70% {
clip-path: var(--slice-2);
transform: translate(-10px, 10px);
}
80% {
clip-path: var(--slice-5);
transform: translate(20px, -10px);
}
90% {
clip-path: var(--slice-1);
transform: translate(-10px, 0px);
}
100% {
clip-path: var(--slice-1);
transform: translate(0);
}
}
@media (min-width: 768px) {
.button49,
.button49:after {
width: 200px;
height: 86px;
line-height: 88px;
}
}
चरण 5: वेबसाइट चलाएं और इसका परीक्षण करें
जब आप इसे रन करेंगे, तो यह आपके वॉलेट के साथ एक कनेक्शन इनीशिएट करेगा। एक बार जब आप कनेक्शन को अप्रूव कर देते हैं, तो यह कुछ इस तरह दिखना चाहिए:
npm run dev

चरण 6: क्रिप्टोकरेंसी ट्रांसफर करने की क्षमता जोड़ें
अब जब हमने अपना वॉलेट कनेक्ट कर लिया है, तो हम अपने वॉलेट से दूसरों को फंड ट्रांसफर कर सकते हैं। सुनिश्चित करें कि आपके वॉलेट में कुछ Mumbai MATIC हैं। आप यहां से कुछ प्राप्त कर सकते हैं: https://faucet.polygon.technology
अब हम ट्रांजेक्शन के लिए इनपुट फील्ड्स और सेंड (send) बटन बनाएंगे। pages/ डायरेक्टरी के तहत एक नई फ़ाइल बनाएं और इसे RareSend.tsx नाम दें। नीचे दिए गए कोड को कॉपी पेस्ट करें। स्पष्टीकरण कोड कमेंट्स में दिए गए हैं।
import { parseEther } from "ethers/lib/utils.js";
import React, { useState } from "react";
import { useDebounce } from "use-debounce";
import { usePrepareSendTransaction, useSendTransaction } from "wagmi";
import styles from "@/styles/Home.module.css";
// what this does is simply disable the SendFunds function if the value passed is false
interface SendFundsProps {
disabled?: boolean;
}
export default function SendFunds(props: SendFundsProps) {
// declare two state variables for the recipient and the amount
const [to, setTo] = useState("");
const [debouncedTo] = useDebounce(to, 500); // useDebounce() hook to debounce the recipient input
const [amount, setAmount] = useState("");
const [debouncedAmount] = useDebounce(amount, 500); // useDebounce() hook to debounce the amount input
// use the usePrepareSendTransaction() hook to prepare a transaction request
const { config } = usePrepareSendTransaction({
request: {
to: debouncedTo, // recipient from debounced input
value: debouncedAmount ? parseEther(debouncedAmount) : undefined, // amount from debounced input
},
});
// use the useSendTransaction() hook to create a transaction and send it
const { sendTransaction } = useSendTransaction(config);
return (
<>
<form
onSubmit={(e) => {
e.preventDefault();
sendTransaction?.(); // if sendTransaction is defined, execute it
}}
>
<div className={styles.inputcontainer}>
<input
aria-label="Recipient"
onChange={(e) => setTo(e.target.value)} // update the recipient state on input change
placeholder="Address destination"
value={to}
className={styles.myinput}
/>
<input
aria-label="Amount (ether)"
onChange={(e) => setAmount(e.target.value)} // update the amount state on input change
placeholder="enter amount"
value={amount}
className={styles.myinput}
/>
</div>
<div className={styles.buttoncontainer}>
<button
disabled={!sendTransaction || !to || !amount}
className={styles.button64}
>
Send
</button>{" "}
{/* disable the button if required fields are empty */}
</div>
</form>
</>
);
}
useDebounce() को समझना
RPC को ओवरलोड करने और रेट-लिमिटेड होने से बचने के लिए, हम usePrepareContractWrite हुक के उपयोग को सीमित करेंगे, जो कंपोनेंट माउंट और args मॉडिफिकेशन पर गैस एस्टीमेट्स का अनुरोध करता है। यदि कोई परिवर्तन नहीं किया गया है, तो हम टोकन ID को अपडेट करने में 500ms की देरी करने के लिए कंपोनेंट में useDebounce हुक का उपयोग करते हैं।
चरण 7: sendFunds कंपोनेंट को इंसर्ट करें
इसके बाद, बस pages/index.tsx में इस तरह <SendFunds disabled={!isConnected}/> जोड़ें।
import { useAccount, useConnect } from "wagmi";
import SendFunds from "./RareSend";
import { useEffect } from "react";
import styles from "@/styles/Home.module.css";
export default function Home() {
{
/* some code... */
}
return (
<>
<div>
{/* some code... */}
{/* send funds */}
<SendFunds disabled={!isConnected} />
{/* mint nft */}
</div>
</>
);
}
जब तक आपके एड्रेस में Matic है, तब तक आप इसे दूसरे अकाउंट में भेज सकते हैं!
आपकी वेबसाइट कुछ इस तरह दिखनी चाहिए:

इस बिंदु तक पहुंचने के लिए बधाई! आपने सफलतापूर्वक अपनी खुद की वेबसाइट बना ली है जो आपके वॉलेट से दूसरे अकाउंट में फंड भेज सकती है। अब आप किसी थर्ड-पार्टी सर्विस पर निर्भर हुए बिना या मैन्युअली ट्रांजेक्शन डिटेल्स दर्ज किए बिना, अकाउंट्स के बीच आसानी से क्रिप्टोकरेंसी ट्रांसफर करने में सक्षम हैं। बहुत बढ़िया! यह इतना आसान है!
Wagmi Examples भाग 2: React + Wagmi के साथ NFT Mint करना
हम मानकर चल रहे हैं कि आपने पहले से ही ब्लॉकचेन पर एक NFT smart contract डिप्लॉय (deploy) कर दिया है। ऐसा करने के लिए आप इस वीडियो ट्यूटोरियल को फॉलो कर सकते हैं: https://youtu.be/LIoFbudNVZs।

AI जनरेटेड बिल्लियों के NFTs
mint फंक्शन को निम्नानुसार बनाया जा सकता है। एक mint.tsx बनाएं और नीचे दिए गए कोड्स जोड़ें।
// Initialize ethers.js and wagmi dependencies
import { ethers } from "ethers";
import * as React from "react";
import {
usePrepareContractWrite,
useContractWrite,
useWaitForTransaction,
} from "wagmi";
import styles from "@/styles/Home.module.css";
// Define a React function component to mint an NFT
export function MintNFT() {
// Prepare the contract write configuration by providing the contract's address, ABI, function name, and overrides
const { config } = usePrepareContractWrite({
address: "Your Contract Address",
abi: [
{
name: "mint",
type: "function",
stateMutability: "payable",
inputs: [],
outputs: [],
},
],
functionName: "mint",
overrides: {
from: "Your Walllet Address",
value: ethers.utils.parseEther("0.000000001"), //the integer value should match your nft minting requirements
},
});
// Use the useContractWrite hook to write to the contract's mint function and obtain the transaction data and write function
const { data, write } = useContractWrite(config);
// Use the useWaitForTransaction hook to wait for the transaction to be mined and return loading and success states
const { isLoading, isSuccess } = useWaitForTransaction({
hash: data?.hash,
});
// Render the component with a button that triggers the mint transaction when clicked, a loading message while the transaction is in progress, and a success message when the transaction is successful
return (
<div className={styles.mintcontainer}>
<button
disabled={!write || isLoading}
onClick={() => write?.()}
className={styles.button49}
>
{isLoading ? "Minting..." : "Mint"}
</button>
{isSuccess && (
<div>
Successfully minted your NFT!
<div>
<a href={`https://etherscan.io/tx/${data?.hash}`}>Etherscan</a>
</div>
</div>
)}
</div>
);
}
अब आप इसे आसानी से index.tsx फ़ाइल में इस प्रकार इंसर्ट कर सकते हैं:
import { useAccount, useConnect } from "wagmi";
import SendFunds from "./RareSend";
import { useEffect } from "react";
import styles from "@/styles/Home.module.css";
import { MintNFT } from "./mint";
export default function Home() {
const { connect, connectors } = useConnect();
const { isConnected } = useAccount();
useEffect(() => {
console.log(
`Current connection status: ${isConnected ? "connected" : "disconnected"}`
);
}, [isConnected]);
return (
<>
<p
className={styles.status}
style={{
color: isConnected ? "green" : "red",
}}
>
{" "}
{isConnected !== undefined
? isConnected
? "Connected"
: "Disconnected"
: "loading..."}
</p>
<div className={styles.maincontainer}>
<div className={styles.container}>
<div className={styles.buttonswrapper}>
<div className={styles.buttonswrapperGrid}>
{connectors.map((connector) => (
<button
suppressHydrationWarning
key={connector.id}
onClick={() => connect({ connector })}
className={styles.button28}
>
{connector.name}
</button>
))}
</div>
</div>
</div>
{/* send funds */}
<SendFunds disabled={!isConnected} />
{/* mint nft */}
<MintNFT />
</div>
</>
);
}
आपकी फाइनल वेबसाइट कुछ इस तरह दिखनी चाहिए:

बधाई हो! आपने अभी अपना खुद का Decentralized Application बनाया है जो Transactions भेजने और NFT Mint करने में सक्षम है।
मूल रूप से 24 अप्रैल, 2023 को प्रकाशित