
📜 시나리오
- 사용자가 "지갑 연결" 버튼 클릭 시, MetaMask와 연결 시도
- 연결에 성공하면 지갑 주소를 화면에 표시
- 해당 주소의 ETH 잔액을 불러와 화면에 표시
- 단위는 ETH (소수점 4자리까지)
import { useEffect, useRef, useState } from "react";
import { ethers } from "ethers";
export default function WalletInfo() {
const [address, setAddress] = useState("");
const [balance, setBalance] = useState("");
//useRef를 사용해 provider을 저장해서 재사용
const providerRef = useRef<ethers.BrowserProvider | null>(null);
const connectWallet = async () => {
if (!window.ethereum) {
alert("MetaMask가 필요합니다.");
return;
}
const provider = new ethers.BrowserProvider(window.ethereum);
providerRef.current = provider;
const accounts = await provider.send("eth_requestAccounts", []);
const account = accounts[0];
setAddress(account);
};
useEffect(() => {
if (!address || !providerRef.current) return;
const updateBalance = async () => {
const balanceBigInt = await providerRef.current!.getBalance(address);
//wei를 ETH로 바꿔주세요
const ethBalance = ethers.formatEther(balanceBigInt);
setBalance(parseFloat(ethBalance).toFixed(4));
};
// 최초 조회
updateBalance();
// 5초마다 잔액 갱신
const interval = setInterval(updateBalance, 5000);
return () => clearInterval(interval); // cleanup
}, [address]);
return (
<div>
<button onClick={connectWallet}>지갑 연결</button>
{address && (
<div>
<p>주소: {address}</p>
<p>잔액: {balance} ETH</p>
</div>
)}
</div>
);
}
- provider.send와 provider.getSigner()의 차이는?
- provider.send("eth_requestAccounts"):메타마스크로부터 read-only 계정 목록을 요청합니다.
- provider.getSigner(): 서명이나 트랜잭션을 보낼 수 있는 서명자 객체를 반환합니다.
- formatEther, parseEther 사용 이유?
- 👉 이더리움의 단위는 Wei(10^18) 기준이기 때문에,
실제로 표시하거나 보낼 때는 사람이 읽을 수 있는 ETH 단위로 변환해야 해요. - formatEther: wei -> ETH
- parseEther: ETH -> wei
- 👉 이더리움의 단위는 Wei(10^18) 기준이기 때문에,
- 잔액이 실시간으로 변동될 경우 어떻게 반영할 수 있을까?
- **setInterval**로 주기적으로 잔액 갱신
- **provider.on("block", callback)**을 사용해서 블록마다 잔액 확인
- provider.on("pending") 이벤트 활용해서 감지 (희귀하지만 가능)
