이 글에서 NFC를 탭하면 블록체인 지갑을 만들어주는 기능에 대해 글을 썼었다.
그런데 useWalletAuth라는 지갑 생성 hook에 지갑 생성 기능 외에도 NFC를 감지하는 기능도 들어있어 단일책임원칙(SRP)을 위반하는 것 같아 리팩토링을 진행했다.
NFC 기능은 useNfc라는 hook으로 빼고
매개변수에 nfc가 감지된 후에 실행할 함수를 넣도록 했다.
import { useState } from "react";
export const useNfc = (nextFunction: () => Promise<void>) => {
const [nfc, setNfc] = useState<any>(null);
const [nfcSerialNumber, setNfcSerialNumber] = useState<string | null>(null);
const [isNfcConnecting, setIsNfcConnecting] = useState(false);
async function handleNfcReading() {
if (typeof NDEFReader === "undefined") {
console.log("NFC is not supported in this browser.");
return;
}
try {
console.log("NFC Reading Start");
const ndef = new NDEFReader();
setNfc(ndef);
await ndef.scan();
setIsNfcConnecting(true);
ndef.addEventListener("readingerror", () => {
console.log("Argh! Cannot read data from the NFC tag. Try another one?");
setIsNfcConnecting(false);
});
ndef.addEventListener("reading", (event: any) => {
const { message, serialNumber } = event;
// setNfcMessage(message);
setNfcSerialNumber(serialNumber);
setIsNfcConnecting(false);
nextFunction();
});
} catch (e) {
console.log((e as Error).message);
}
}
return {
nfc,
nfcSerialNumber,
isNfcConnecting,
handleNfcReading,
};
};
아래처럼 useNfc hook을 이용한다.
"use client";
import {
ComethProvider,
ComethWallet,
ConnectAdaptor,
SupportedNetworks,
} from "@cometh/connect-sdk";
import { useState } from "react";
import { useWalletContext } from "./useWalletContext";
import { useNfc } from "./useNfc";
import { ethers } from "ethers";
import { COUNTER_ABI } from "@/abi/counter";
import { TOKEN_ABI } from "@/abi/sample-token";
export function useWalletAuth() {
const { isNfcConnecting, nfcSerialNumber, handleNfcReading } = useNfc(connect);
const { wallet, setWallet, setProvider, contract, setContract } = useWalletContext();
const [isConnecting, setIsConnecting] = useState(false);
const [isConnected, setIsConnected] = useState(false);
const [connectionError, setConnectionError] = useState<string | null>(null);
const apiKey = process.env.NEXT_PUBLIC_COMETH_API_KEY;
const COUNTER_CONTRACT_ADDRESS = "0x3633A1bE570fBD902D10aC6ADd65BB11FC914624";
const MATIC_ADDRESS = "0x0000000000000000000000000000000000001010";
function displayError(message: string) {
setConnectionError(message);
}
async function connect() {
if (!apiKey) throw new Error("no apiKey provided");
try {
const walletAdaptor = new ConnectAdaptor({
chainId: SupportedNetworks.MUMBAI,
apiKey,
});
const instance = new ComethWallet({
authAdapter: walletAdaptor,
apiKey,
});
const localStorageAddress = window.localStorage.getItem("walletAddress");
if (localStorageAddress) {
const parsedLocalStorageAddress = JSON.parse(localStorageAddress);
if (parsedLocalStorageAddress[nfcSerialNumber!]) {
// if it is in localStorage, connect to it
await instance.connect(parsedLocalStorageAddress[nfcSerialNumber!]);
} else {
// if it is not in localStorage, connect to it and save it to localStorage
await instance.connect();
const walletAddress = await instance.getAddress();
parsedLocalStorageAddress[nfcSerialNumber!] = walletAddress;
window.localStorage.setItem("walletAddress", JSON.stringify(parsedLocalStorageAddress));
}
} else {
// if there is no localStorage, connect to it and save it to localStorage
await instance.connect();
const walletAddress = await instance.getAddress();
const addressObject = { [nfcSerialNumber!]: walletAddress };
window.localStorage.setItem("walletAddress", JSON.stringify(addressObject));
}
const instanceProvider = new ComethProvider(instance);
// const contract = new ethers.Contract(MATIC_ADDRESS, TOKEN_ABI, instanceProvider.getSigner());
const contract = new ethers.Contract(
COUNTER_CONTRACT_ADDRESS,
COUNTER_ABI,
instanceProvider.getSigner()
);
setContract(contract);
setIsConnected(true);
setWallet(instance as any);
setProvider(instanceProvider as any);
} catch (e) {
displayError((e as Error).message);
} finally {
setIsConnecting(false);
}
}
async function disconnect() {
if (wallet) {
try {
await wallet!.logout();
setIsConnected(false);
setWallet(null);
setProvider(null);
// setContract(null);
} catch (e) {
displayError((e as Error).message);
}
}
}
return {
wallet,
connect,
disconnect,
isConnected,
isConnecting,
isNfcConnecting,
nfcSerialNumber,
handleNfcReading,
connectionError,
setConnectionError,
contract,
setContract,
};
}