QRコードでNFT認証
QRコードを読み込むことでそのユーザーがNFTを所有していることを証明する
- QRコードにはトークンIDの値
- erc721とerc1155で実装は多少変わってくる
- erc721はownerOf関数
- erc1155はbalanceOf関数
erc721
qrコードで読み込んできたtokenIDからownerOf(tokenId)の値を算出
それとアプリ側で保持したユーザーのアドレスが等しいかを判定する
code:erc721Ether.js
// erc721実装 -> ownerOfから所有者のアドレスをとってくる
const checkNftOwnershipERC721 = async (qrTokenId, userAddress) => {
// const { qrCodeNftAddress, qrCodeTokenId } = nftData;
const tokenId = parseInt(qrTokenId);
const provider = new ethers.providers.Web3Provider(window.ethereum);
const network = await provider.getNetwork();
const contractCode = await provider.getCode(nftContractAddress);
console.log('contractCode:', contractCode);
console.log('Connected network:', network);
const contract = new ethers.Contract(
nftContractAddress,
nftContractAbi,
provider
);
try {
const owner = await contract.ownerOf(tokenId);
if (owner.toLowerCase() === userAddress.toLowerCase()) {
// setIsNftOwner(true);
router.push('/success');
} else {
// setIsNftOwner(false);
router.push('/failure');
}
} catch (err) {
console.error(err);
// setIsNftOwner(false);
router.push('/failure');
}
};
erc1155
qrコードで読み込んできたtokenIDとアプリ側で保持していたユーザーアドレスをbalanceOf(userAddress, tokenId)の形で渡す。その値が1以上 balanceOf(userAddress, tokenId) ≥ 1であればNFTの所有証明になる
code:erc1155Ether.js
// erc1155実装 -> ownerOfから所有者のアドレスをとってくる
const checkNftOwnershipERC1155 = async (qrTokenId, userAddress) => {
const tokenId = parseInt(qrTokenId);
const provider = new ethers.providers.Web3Provider(window.ethereum);
const network = await provider.getNetwork();
const contractCode = await provider.getCode(nftContractAddress);
console.log('contractCode:', contractCode);
console.log('Connected network:', network);
const contract = new ethers.Contract(
nftContractAddress,
nftContractAbi,
provider
);
try {
const balance = await contract.balanceOf(userAddress, tokenId);
if (balance.gt(0)) { // Checks if the balance is greater than 0
// setIsNftOwner(true);
router.push('/success');
} else {
// setIsNftOwner(false);
router.push('/failure');
}
} catch (err) {
console.error(err);
// setIsNftOwner(false);
router.push('/failure');
}
};
QRコード生成や読み取りについて備忘録
読み取り側
code:read.js
import { useState, useEffect } from 'react';
import dynamic from 'next/dynamic';
// import { QrReader } from 'react-qr-reader';
import { ethers } from 'ethers';
import { useRouter } from 'next/router';
import {
nftContractAddress,
nftContractAbi,
userAddress,
} from '../utils/contractInfo';
const QrReader = dynamic(() => import('react-qr-reader'), { ssr: false });
// NFTコントラクトのアドレスとABIを設定
// const nftContractAddress = '0x2953399124F0cBB46d2CbACD8A89cF0599974963';
// const nftContractAbi = []; // この配列にコントラクトのABIを入れてください
// const userAddress = '';
// const tokenId = '1';
export default function Home() {
const qrResult, setQrResult = useState(null);
// const isNftOwner, setIsNftOwner = useState(false);
const router = useRouter();
const showQrReader, setShowQrReader = useState(false);
const tokenId, setTokenId = useState(null);
console.log(nftContractAddress, userAddress);
const handleScan = (qrData) => {
if (qrData) {
// QR コードから tokenId を抽出する
setQrResult(qrData);
const urlSearchParams = new URLSearchParams(new URL(qrData).search);
const extractedTokenId = urlSearchParams.get('tokenId');
if (extractedTokenId) {
setTokenId(extractedTokenId);
} else {
console.error('tokenId not found in QR code data');
}
}
// if (data) {
// setQrResult(data);
// }
// else if (showQrReader) {
// setShowQrReader(false);
// setTimeout(() => setShowQrReader(true), 1000);
// }
};
const handleError = (err) => {
console.error(err);
};
const handleButtonClick = () => {
setShowQrReader(!showQrReader);
};
const buttonClickToCreate = () => {
router.push('/createQRCode');
};
// erc721実装 -> ownerOfから所有者のアドレスをとってくる
const checkNftOwnershipERC721 = async (qrTokenId, userAddress) => {
// const { qrCodeNftAddress, qrCodeTokenId } = nftData;
const tokenId = parseInt(qrTokenId);
const provider = new ethers.providers.Web3Provider(window.ethereum);
const network = await provider.getNetwork();
const contractCode = await provider.getCode(nftContractAddress);
console.log('contractCode:', contractCode);
console.log('Connected network:', network);
const contract = new ethers.Contract(
nftContractAddress,
nftContractAbi,
provider
);
try {
const owner = await contract.ownerOf(tokenId);
if (owner.toLowerCase() === userAddress.toLowerCase()) {
// setIsNftOwner(true);
router.push('/success');
} else {
// setIsNftOwner(false);
router.push('/failure');
}
} catch (err) {
console.error(err);
// setIsNftOwner(false);
router.push('/failure');
}
};
// erc1155実装 -> ownerOfから所有者のアドレスをとってくる
const checkNftOwnershipERC1155 = async (qrTokenId, userAddress) => {
const tokenId = parseInt(qrTokenId);
const provider = new ethers.providers.Web3Provider(window.ethereum);
const network = await provider.getNetwork();
const contractCode = await provider.getCode(nftContractAddress);
console.log('contractCode:', contractCode);
console.log('Connected network:', network);
const contract = new ethers.Contract(
nftContractAddress,
nftContractAbi,
provider
);
try {
const balance = await contract.balanceOf(userAddress, tokenId);
if (balance.gt(0)) { // Checks if the balance is greater than 0
// setIsNftOwner(true);
router.push('/success');
} else {
// setIsNftOwner(false);
router.push('/failure');
}
} catch (err) {
console.error(err);
// setIsNftOwner(false);
router.push('/failure');
}
};
useEffect(() => {
if (tokenId) {
checkNftOwnershipERC721(tokenId, userAddress);
}
}, tokenId);
return (
<div>
<h1>QRコードリーダー</h1>
<button onClick={buttonClickToCreate}>QRコードを作成する</button>
<br />
<button onClick={handleButtonClick}>
{' '}
{showQrReader ? 'QRコードリーダーを閉じる' : 'NFTを利用する'}
</button>
{showQrReader && (
<QrReader
delay={300}
onError={handleError}
onScan={handleScan}
style={{ width: '70%' }}
// facingMode="environment" // この行を追加
// legacyMode // この行を追加
/>
)}
<p>
{qrResult
? QRコードのデータ: ${qrResult}
: 'QRコードをスキャンしてください'}
</p>
{/* <p>
{isNftOwner
? 'このアドレスは指定されたNFTの所有者です'
: 'このアドレスは指定されたNFTの所有者ではありません'}
</p> */}
</div>
);
}
QRコード生成
code:make.js
import QRCode from 'qrcode';
import { useEffect, useRef, useState } from 'react';
import { useRouter } from 'next/router';
function generateQRCodeUrl(tokenId) {
const qrCodeData = https://example.com/?tokenId=${tokenId}; // トークンIDを含むURL
const qrCodeSize = 200; // QRコードのサイズ
const qrCodeErrorCorrectionLevel = 'H'; // QRコードのエラー訂正レベル
const canvas = document.createElement('canvas');
QRCode.toCanvas(canvas, qrCodeData, {
width: qrCodeSize,
height: qrCodeSize,
color: {
dark: '#000000',
light: '#ffffff',
},
errorCorrectionLevel: qrCodeErrorCorrectionLevel,
});
// QRコードをデータURIに変換する
const dataUrl = canvas.toDataURL();
return dataUrl;
}
export default function QRCodePage() {
const qrCodeUrl, setQRCodeUrl = useState(null);
const tokenId, setTokenId = useState(null);
const inputId, setInputId = useState('');
const router = useRouter();
const handleChange = (e) => {
setInputId(e.target.value);
};
const handleClick = () => {
setTokenId(inputId);
};
// トークンIDを設定する
// const tokenId = 10;
const buttonClickToCreate = () => {
router.push('/');
};
useEffect(() => {
// QRコードのデータURIを生成する
const url = generateQRCodeUrl(tokenId);
// QRコードのデータURIを設定する
setQRCodeUrl(url);
}, tokenId);
return (
<>
<div>
<input type="text" value={inputId} onChange={handleChange} />
<button onClick={handleClick}>tokenIdをセットする</button>
<p>tokenId : {tokenId}</p>
{qrCodeUrl && <img src={qrCodeUrl} alt="QR code" />}
</div>
<button onClick={buttonClickToCreate}>homeに戻る</button>
</>
);
}