블록체인과 상호작용하기 위해 web3Modal과 선호하는 라이브러리를 설치합니다. 이 튜토리얼에서는 Web3Modal에서 파생되어 Kaikas 지갑과 Klip 지갑을 추가할 수 있도록 수정된 @klaytn/web3modal을 설치해 보겠습니다. 또한, 이 튜토리얼에서는 ethers.js를 사용해 Klaytn 블록체인과 상호작용할 것입니다.
npminstall@klaytn/web3modalnpminstall--saveethers
2단계: 지갑 공급자 옵션으로 Web3Modal 인스턴스화하기
원하는 지갑 공급업체를 설치합니다. 여기에서는 Kaikas, Klip 및 Coinbase 지갑 제공업체를 설치합니다.
사용자 지갑에 연결하려면 Web3Modal 인스턴스에서 connect() 메서드를 호출합니다. 이 작업을 비동기 함수로 감싸고 검색된 공급자를 상태에 저장하여 앱 전체에서 재사용하는 것이 좋습니다.
import { ethers } from'ethers';import { useState } from'react';functionApp() {const [provider,setProvider] =useState();constconnectWallet=async () => {try {constweb3ModalProvider=awaitweb3Modal.connect();// this guide uses ethers version 6.3.0.constethersProvider=newethers.BrowserProvider(web3ModalProvider);// for ethers version below 6.3.0.// const provider = new ethers.providers.Web3Provider(web3ModalProvider);setProvider(web3ModalProvider); } catch (error) {console.error(error); } };return ( <divclassName="App"> <buttononClick={connectWallet}>Connect Wallet</button> </div> );}
유틸리티 함수 설정하기
이 가이드에서는 truncateAddress() 및 toHex()와 같은 유틸리티 함수를 사용하겠습니다. truncateAddress() 함수는 유효한 주소를 전달 받아 읽기 쉬운 형식으로 반환합니다. toHex() 함수는 숫자를 16진수로 변환합니다. 다음은 프로젝트에서 유틸리티 함수를 설정하고 사용하는 방법을 단계별로 보여줍니다.
현재 Web3Modal은 연결된 계정 및 네트워크 데이터 가져오기와 같은 이더리움 상호작용을 기본적으로 지원하지 않습니다. 사용자의 주소 또는 연결된 네트워크 ID를 읽으려면 이더리움 라이브러리에서 정보를 직접 요청해야 합니다. 이 가이드에서는 ethers.js를 사용하여 해당 정보를 가져올 것입니다. 한 가지 방법으로 사용자를 디앱에 연결할 때 이 데이터를 가져와 저장해 보겠습니다.
const [provider,setProvider] =useState();const [account,setAccount] =useState();const [chainId,setChainId] =useState();constconnectWallet=async () => {try {constweb3ModalProvider=awaitweb3Modal.connect();// this guide uses ethers version 6.3.0.constethersProvider=newethers.BrowserProvider(web3ModalProvider);// for ethers version below 6.3.0.// const provider = new ethers.providers.Web3Provider(web3ModalProvider);constaccounts=awaitethersProvider.listAccounts();constnetwork=awaitethersProvider.getNetwork();setProvider(provider);if (accounts) setAccount(accounts[0]);setChainId(network.chainId.toString()); } catch (error) {console.error(error); }};return ( <divclassName="App"> <buttononClick={connectWallet}>Connect Wallet</button> <div>Connected To Chain ID: ${chainId}</div> <div>Wallet Address: ${truncateAddress(account)}</div> </div>);
지갑 연결 해제하기
지갑 연결을 끊으려면 web3Modal 인스턴스에서 clearCachedProvider() 메서드를 사용하면 됩니다. 또한 상태 새로고침을 하여 이전에 저장된 연결 데이터를 모두 지우는 것도 좋은 방법 중 하나입니다.
functionApp() {constdisconnect=async () => {awaitweb3Modal.clearCachedProvider();refreshState(); };// refresh stateconstrefreshState= () => {setAccount();setChainId();// make sure to add every other state variable declared here.}return ( <divclassName="App"> <buttononClick={disconnect}>Disconnect</button> </div> );}
dApp 상태는 사용자가 dApp과 상호 작용할 때 변경되며, 이 때 응답으로 릴리스되는 이벤트를 구독하는 것이 가장 좋습니다. 이러한 이벤트 구독과 함께 useEffect 훅을 생성하면 변경 사항에 적절히 대응할 수 있습니다.
앞서 설명한 바와 같이 Web3Modal은 이더리움 상호작용을 기본적으로 지원하지 않습니다. 네트워크를 추가하거나 전환하려면 이더리움 라이브러리에 (EIP-3085 또는 EIP-3326을 통해) 직접 요청해야 합니다. 다음은 사용자 지갑에 해당 네트워크가 없는 경우 네트워크 전환을 요청하고 해당 네트워크를 대체 네트워크로 추가하는 예시입니다:
constswitchNetwork=async () => {if (!provider) return;try {awaitprovider.request({ method:"wallet_switchEthereumChain", params: [{ chainId:toHex(8217) }], }); } catch (switchError) {// This error code indicates that the chain has not been added to MetaMask.if (switchError.code ===4902) {try {awaitprovider.request({ method:"wallet_addEthereumChain", params: [ { chainId:toHex(8217), chainName:"Klaytn TestNet", rpcUrls: ["https://klaytn-mainnet-rpc.allthatnode.com:8551"], blockExplorerUrls: ["https://baobob.scope.com/"], }, ], }); } catch (addError) {throw addError; } } } };return ( <divclassName="App"> <buttononClick={switchNetwork}>Switch Network</button> </div>)
메시지 서명하기
공급자(Provider) 및 서명자(Signer) 객체를 초기화하면 사용자는 임의의 문자열에 서명할 수 있습니다.
한 사용자에서 다른 사용자로 KLAY를 보내는 것과 같은 네이티브 트랜잭션을 수행할 수 있습니다.
// add to the existing useState hook.const [txHash,setTxHash] =useState();constsendKlay=async () => {if (!provider) return;constdestination= “paste recipient address”;// this guide uses ethers version 6.3.0.constethersProvider=newethers.BrowserProvider(provider);// for ethers version below 6.3.0.// const provider = new ethers.providers.Web3Provider(provider);constsigner=awaitethersProvider.getSigner();// Submit transaction to the blockchain and wait for it to be minedconsttx=awaitsigner.sendTransaction({ to: destination, value:ethers.parseEther("0.1"), maxPriorityFeePerGas:"5000000000",// Max priority fee per gas maxFeePerGas:"6000000000000",// Max fee per gas })constreceipt=awaittx.wait();setTxHash(receipt.hash)}return ( <divclassName="App"> <buttononClick={sendKlay}>Send Klay</button> <div>Send-Klay Tx Hash : {txHash ? <a href={`https://baobab.scope.klaytn.com/tx/${txHash}`} target="_blank">Klaytnscope</a> : ' ' } </div>
</div>);
스마트 컨트랙트로 작업하기
Web3Modal 공급자 및 서명자 객체를 사용하면 블록체인에 배포된 스마트 컨트랙트에 쓰기 및 읽기와 같은 컨트랙트 상호 작용을 할 수 있습니다.
컨트랙트 작성하기
// add to existing useState hookconst [contractTx,setContractTx] =useState();constwriteToContract=async (e) => {e.preventDefault();if (!provider) return;// this guide uses ethers version 6.3.0.constethersProvider=newethers.BrowserProvider(provider);// for ethers version below 6.3.0.// const provider = new ethers.providers.Web3Provider(provider);constsigner=awaitethersProvider.getSigner();// Paste your contractABIconstcontractABI= [ {"inputs": [ {"internalType":"uint256","name":"_initNum","type":"uint256" } ],"stateMutability":"nonpayable","type":"constructor" }, {"inputs": [],"name":"retrieve","outputs": [ {"internalType":"uint256","name":"","type":"uint256" } ],"stateMutability":"view","type":"function" }, {"inputs": [ {"internalType":"uint256","name":"num","type":"uint256" } ],"name":"store","outputs": [],"stateMutability":"nonpayable","type":"function" } ]// Paste your contract addressconstcontractAddress="0x3b01E4025B428fFad9481a500BAc36396719092C";constcontract=newethers.Contract(contractAddress, contractABI, signer);constvalue=e.target.store_value.value;// Send transaction to smart contract to update messageconsttx=awaitcontract.store(value);// Wait for transaction to finishconstreceipt=awaittx.wait();constresult=receipt.hash;setContractTx(result) }return ( <divclassName="App"> <formonSubmit={writeToContract}> <inputname="store_value"placeholder="Set contract value"required/> <inputtype="submit"value="Store"/> </form> <div>Write-to-contract Tx Hash: ${contractTx}</div> </div>)
컨트랙트 읽기
// add to existing useState hookconst [contractMessage,setContractMessage] =useState();constreadFromContract=async () => {if (!provider) {console.log("provider not initialized yet");return; }// this guide uses ethers version 6.3.0.constethersProvider=newethers.BrowserProvider(provider);// for ethers version below 6.3.0.// const provider = new ethers.providers.Web3Provider(provider);// paste your contract ABIconstcontractABI= [ {"inputs": [ {"internalType":"uint256","name":"_initNum","type":"uint256" } ],"stateMutability":"nonpayable","type":"constructor" }, {"inputs": [],"name":"retrieve","outputs": [ {"internalType":"uint256","name":"","type":"uint256" } ],"stateMutability":"view","type":"function" }, {"inputs": [ {"internalType":"uint256","name":"num","type":"uint256" } ],"name":"store","outputs": [],"stateMutability":"nonpayable","type":"function" } ]// paste your contract addressconstcontractAddress="0x3b01E4025B428fFad9481a500BAc36396719092C"; constcontract=newethers.Contract(contractAddress, contractABI, ethersProvider)// Reading a message from the smart contractconstcontractMessage=awaitcontract.retrieve();setContractMessage(contractMessage.toString()) }return ( <divclassName="App"> <buttononClick={readFromContract}>Read From Contract</button> <div>Read-from-contract Message: ${contractMessage}</div> </div> )
문제 해결
Node fs error, add browser {fs: false} to package.json
Nodefserror,addbrowser{fs:false}topackage.json
이 문제는 Klip-web3-provider를 설치할 때 발생합니다. 이 문제를 해결하려면 다음 단계를 따르세요.
1단계: node_modules 폴더를 찾아 엽니다. 아래 @Klaytn/klip-web3-provider 폴더 경로에 위치한 package.json 파일을 엽니다.