lesson-4_NFTをミントしてみよう
このレッスンではsrc/pages/index.tsx
を変更して、以下の実装をしていきます。
- ユーザーがメンバーシップNFTを持っていない場合は、NFTをミントするボタンを表示します。
- ユーザーがメンバーシップNFTを持っていることを検知したら、プロポーザルに投票したり、DAO関連の情報を見ることができる「DAOダッシュボード」画面を表示します。
さあ、やってみましょう! まず、ケース1について説明します。
🤔 メンバーシップ NFT を持っているかどうかを確認する
src/pages/index.tsx
に移動し、コードを以下のとおり変更します。
※ あなたのコントラクトアドレスを設定することを忘れないでください!
import { Sepolia } from "@thirdweb-dev/chains";
import {
ConnectWallet,
useAddress,
useChain,
useContract,
} from "@thirdweb-dev/react";
import type { NextPage } from "next";
import { useEffect, useState } from "react";
import styles from "../styles/Home.module.css";
const Home: NextPage = () => {
const address = useAddress();
console.log("👋Wallet Address: ", address);
const chain = useChain();
// editionDrop コントラクトを初期化
const editionDrop = useContract(
"INSERT_EDITION_DROP_ADDRESS",
"edition-drop"
).contract;
// ユーザーがメンバーシップ NFT を持っているかどうかを知るためのステートを定義
const [hasClaimedNFT, setHasClaimedNFT] = useState(false);
useEffect(() => {
// もしウォレットに接続されていなかったら処理をしない
if (!address) {
return;
}
// ユーザーがメンバーシップ NFT を持っているかどうかを確認する関数を定義
const checkBalance = async () => {
try {
const balance = await editionDrop!.balanceOf(address, 0);
if (balance.gt(0)) {
setHasClaimedNFT(true);
console.log("🌟 this user has a membership NFT!");
} else {
setHasClaimedNFT(false);
console.log("😭 this user doesn't have a membership NFT.");
}
} catch (error) {
setHasClaimedNFT(false);
console.error("Failed to get balance", error);
}
};
// 関数を実行
checkBalance();
}, [address, editionDrop]);
// テストネットが Sepolia ではなかった場合に警告を表示
if (chain && chain.chainId !== Sepolia.chainId) {
console.log("wallet address: ", address);
console.log("chain name: ", chain.name);
return (
<div className={styles.container}>
<main className={styles.main}>
<h1 className={styles.title}>Sepolia に切り替えてください⚠️</h1>
<p>この dApp は Sepolia テストネットのみで動作します。</p>
<p>ウォレットから接続中のネットワークを切り替えてください。</p>
</main>
</div>
);
} else {
return (
<div className={styles.container}>
<main className={styles.main}>
<h1 className={styles.title}>Welcome to Tokyo Sauna Collective !!</h1>
<div className={styles.connect}>
<ConnectWallet />
</div>
</main>
</div>
);
}
};
export default Home;
まず、editionDrop
コントラクトを初期化します。
そこから、editionDrop!.balanceOf(address, "0")
を使って、ユーザーがNFTを持っているかどうかを確認します。
これは、実際にデプロイされたスマートコントラクトにデータを問い合わせることになります。
なぜ"0"
なのでしょうか?
基本的には、 "0"
がメンバーシップNFTのtokenchainId
であることを思い出してください。
つまり、ここではコントラクトに「このユーザーはchainID "0"
のトークンを所有しているのかどうか」を確認しているのです。
このページを更新すると、このように表示されるはずです。
今の段階ではメンバーシップNFTを持っていないため、😭 this user doesn't have a membership NFT.
と表示されます。
✨ "Mint NFT" ボタンをつくろう
それでは、src/pages/index.tsx
へ移動しメンバーシップNFTをミントできるようにしていきましょう。
下記のとおりコードを変更してください。
※ あなたのコントラクトアドレスを設定することを忘れないでください!
import { Sepolia } from "@thirdweb-dev/chains";
import {
ConnectWallet,
useAddress,
useChain,
useContract,
} from "@thirdweb-dev/react";
import type { NextPage } from "next";
import { useEffect, useState } from "react";
import styles from "../styles/Home.module.css";
const Home: NextPage = () => {
const address = useAddress();
console.log("👋Wallet Address: ", address);
const chain = useChain();
// editionDrop コントラクトを初期化
const editionDrop = useContract(
"INSERT_EDITION_DROP_ADDRESS",
"edition-drop"
).contract;
// ユーザーがメンバーシップ NFT を持っているかどうかを知るためのステートを定義
const [hasClaimedNFT, setHasClaimedNFT] = useState(false);
// NFT をミンティングしている間を表すステートを定義
const [isClaiming, setIsClaiming] = useState(false);
useEffect(() => {
// もしウォレットに接続されていなかったら処理をしない
if (!address) {
return;
}
// ユーザーがメンバーシップ NFT を持っているかどうかを確認する関数を定義
const checkBalance = async () => {
try {
const balance = await editionDrop!.balanceOf(address, 0);
if (balance.gt(0)) {
setHasClaimedNFT(true);
console.log("🌟 this user has a membership NFT!");
} else {
setHasClaimedNFT(false);
console.log("😭 this user doesn't have a membership NFT.");
}
} catch (error) {
setHasClaimedNFT(false);
console.error("Failed to get balance", error);
}
};
// 関数を実行
checkBalance();
}, [address, editionDrop]);
const mintNft = async () => {
try {
setIsClaiming(true);
await editionDrop!.claim("0", 1);
console.log(
`🌊 Successfully Minted! Check it out on etherscan: https://sepolia.etherscan.io/address/${editionDrop!.getAddress()}`
);
setHasClaimedNFT(true);
} catch (error) {
setHasClaimedNFT(false);
console.error("Failed to mint NFT", error);
} finally {
setIsClaiming(false);
}
};
// ウォレットと接続していなかったら接続を促す
if (!address) {
return (
<div className={styles.container}>
<main className={styles.main}>
<h1 className={styles.title}>Welcome to Tokyo Sauna Collective !!</h1>
<div className={styles.connect}>
<ConnectWallet />
</div>
</main>
</div>
);
}
// テストネットが Sepolia ではなかった場合に警告を表示
else if (chain && chain.chainId !== Sepolia.chainId) {
console.log("wallet address: ", address);
console.log("chain name: ", chain.name);
return (
<div className={styles.container}>
<main className={styles.main}>
<h1 className={styles.title}>Sepolia に切り替えてください⚠️</h1>
<p>この dApp は Sepolia テストネットのみで動作します。</p>
<p>ウォレットから接続中のネットワークを切り替えてください。</p>
</main>
</div>
);
}
// ウォレットと接続されていたら Mint ボタ ンを表示
else {
return (
<div className={styles.container}>
<main className={styles.main}>
<h1 className={styles.title}>Mint your free 🍪DAO Membership NFT</h1>
<button disabled={isClaiming} onClick={mintNft}>
{isClaiming ? "Minting..." : "Mint your nft (FREE)"}
</button>
</main>
</div>
);
}
};
export default Home;
まず最初に行っているのは、実際にトランザクションを送信するために必要となるユーザーの代わりのsigner
の設定です。
詳しくはこちらをご覧ください。
ここからeditionDrop!.claim('0', 1)
を呼び出し、ユーザーがボタンをクリックした際にNFTをウォレットに実際にミントします。
この場合、メンバーシップNFTのtokenchainIdは'0'
なので、'0'
を渡します。
次に、1
を渡します。これは、ユーザーのウォレットに1つのメンバーシップNFTを作成したいだけだからです。
すべて完了したら、setIsClaiming(false)