프로젝트와 개발자는 Web3-Onboard와 같은 도구를 활용하여 다양한 지갑을 탈중앙화 애플리케이션(dApp)에 빠르게 통합할 수 있습니다. Web3-Onboard의 도움으로 사용자 온보딩이 간소화되었습니다. Web3-Onboard는 여러 종류의 지갑을 지원하는 기능 뿐 아니라 사용자가 계정을 다른 체인이나 네트워크에 연결하고 실시간 거래 알림을 받을 수 있는 기능 등 다양한 기능을 제공합니다.
본 가이드에서는 Web3-Onboard 라이브러리를 사용해 여러 지갑(예: Coinbase Wallet, Metamask, WalletConnect)을 클레이튼 네트워크에서 구축한 dApp에 통합하는 방법을 설명합니다.
체인에 구애받지 않는 지갑 라이브러리인 Web3-Onboard는 모든 EVM 호환 네트워크를 지원하며, 라이브러리에 새로운 네트워크를 추가할 수 있는 유연성도 제공합니다. 본 가이드에서는 Web3-Onboard를 사용하여 Klaytn 메인넷인 Cypress와 클레이튼 테스트넷인 Baobab을 dApp에 추가해 보겠습니다. 이제 Web3-Onboard를 사용해 다중지갑 호환성을 클레이튼 네트워크에 구축된 dApp에 통합해 보겠습니다.
온보드 및 지갑 모듈 설정하기
1단계: @web3-onboard/core 설치
npmi@web3-onboard/core
2단계: 지갑 모듈 가져오기 및 인스턴스화
이 단계에서 지갑 모듈을 사용하여 dApp에서 지원할 지갑을 원하는 만큼 추가할 수 있습니다. 하지만 본 가이드에서는 Web3-Onboard 구현에 Coinbase Wallet, WalletConnect, Injected Wallets을 추가해 보도록 하겠습니다. Web3-Onboard를 사용하여 dApp에 추가할 수 있는 지갑 모듈 목록은 이 docs을 참조하세요.
Web3-Onboard 공급자는 ethers.js 및 web3.js와 같은 라이브러리와 함께 사용할 수 있습니다. 본 가이드에서는 ethers.js를 사용하여 사용자 계정 가져오기, 잔액 가져오기, 트랜잭션 서명, 트랜잭션 보내기, 스마트 컨트랙트 읽기 및 쓰기와 같은 Klaytn 블록체인 호출을 수행하겠습니다.
npminstall--saveethers
App.js 파일에서 다음과 같이 ethers 패키지를 불러옵니다.
import { ethers } from"ethers";
4단계: Web3ReactProvider 불러오기 및 설정하기
이 단계에서는 생성된 모듈 및 라이브러리와 호환될 체인 목록으로 Onboard를 인스턴스화합니다. App.js 파일을 열고 아래 코드를 붙여넣습니다:
import Onboard from"@web3-onboard/core";constETH_MAINNET_RPC_URL=`Paste ETH RPC URL`;constKLAYTN_MAINNET_URL=`Paste KLAYTN MAINNET URL`constKLAYTN_BAOBAB_URL=`Paste KLAYTN BAOBAB URL`constonboard=Onboard({ wallets: modules,// created in previous step chains: [ { id:"0x1",// chain ID must be in hexadecimal token:"ETH", namespace:"evm", label:"Ethereum Mainnet", rpcUrl:ETH_MAINNET_RPC_URL }, { id:"0x2019",// chain ID must be in hexadecimal token:"KLAY", namespace:"evm", label:"Klaytn Mainnet", rpcUrl:KLAYTN_MAINNET_URL }, { id:"0x3e9",// chain ID must be in hexadecimel token:"KLAY", namespace:"evm", label:"Klaytn Testnet", rpcUrl:KLAYTN_BAOBAB_URL },// you can add as much supported chains as possible ], appMetadata: { name:"Klaytn-web3-onboard-App",// change to your dApp name icon:"https://pbs.twimg.com/profile_images/1620693002149851137/GbBC5ZjI_400x400.jpg",// paste your icon logo:"https://pbs.twimg.com/profile_images/1620693002149851137/GbBC5ZjI_400x400.jpg",// paste your logo description:"Web3Onboard-Klaytn", recommendedInjectedWallets: [ { name:"Coinbase", url:"https://wallet.coinbase.com/" }, { name:"MetaMask", url:"https://metamask.io" } ] }});
유틸리티 함수 설정하기
이 가이드에서는 truncateAddress() 및 toHex()와 같은 유틸리티 함수를 사용하겠습니다. truncateAddress() 함수는 유효한 주소를 전달 받아 읽기 쉬운 형식으로 반환합니다. toHex() 함수는 숫자를 16진수로 변환합니다. 다음은 프로젝트에서 유틸리티 함수를 설정하고 사용하는 방법을 단계별로 보여줍니다.
Connect Wallet 버튼을 클릭하면 dApp에서 Coinbase Wallet 및 기타 인스턴스화된 지갑에 원활하게 연결할 수 있는 모달이 표시됩니다.
지갑 연결 해제하기
지갑 연결을 끊으려면 사용자의 primary wallet 레이블과 함께 onboard 인스턴스에서 disconnectWallet() 메서드를 호출하면 됩니다. 또한 상태 새로고침을 하여 이전에 저장된 연결 데이터를 모두 지우는 것도 좋은 방법 중 하나입니다.
functionApp() {constconnectWallet=async () => {try {constwallets=awaitonboard.connectWallet(); } catch (error) {console.error(error); } };constdisconnect=async () => {const [primaryWallet] =awaitonboard.state.get().wallets;if (primaryWallet) awaitonboard.disconnectWallet({ label:primaryWallet.label });refreshState(); };// refresh stateconstrefreshState= () => {setAccount("");setChainId("");setProvider();// make sure to add every other state declared here. };return ( <divclassName="App"> <buttononClick={connectWallet}>Connect Wallet</button> <buttononClick={disconnect}>Disconnect</button> </div> );}
연결, 계정, 네트워크 정보에 엑세스하기
지갑 연결에 성공하면 onboard.state.get() 메서드를 사용하여 onboard 인스턴스를 통해 저장된 연결 상태를 가져올 수 있습니다. 초기 연결 중에 상태를 가져올 수도 있습니다. 이제 수정된 connectWallet() 메서드로 상태 목록을 반환할 수 있으며 이를 내 상태에 저장하고 애플리케이션 전체에서 사용할 수 있습니다.
지갑에 성공적으로 연결한 후 지갑 연결에서 반환된 공급자 객체를 connectWallet() 함수에서 수행한 것처럼 상태 변수에 저장할 수 있습니다. 따라서 이 공급자 및 서명자 객체를 사용하여 트랜잭션을 블록체인으로 전송할 수 있습니다.
// add to the existing useState hook.const [txHash,setTxHash] =useState();constsendKlay=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);constsigner=awaitethersProvider.getSigner();// Submit transaction to the blockchain and wait for it to be minedconsttx=awaitsigner.sendTransaction({ to:"0x75Bc50a5664657c869Edc0E058d192EeEfD570eb", 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 ? <ahref={`https://baobab.scope.klaytn.com/tx/${txHash}`} target="_blank">Klaytnscope</a> :' ' } </div> </div>);
스마트 컨트랙트와 상호작용하기
Web3-Onboard 공급자 및 서명자 개체를 사용하면 블록체인에 배포된 스마트 컨트랙트에 쓰기 및 읽기와 같은 컨트랙트 상호 작용을 할 수 있습니다.
// add to existing useState hookconst [contractTx,setContractTx] =useState();const [contractMessage,setContractMessage] =useState();constwriteToContract=async (e) => {e.preventDefault();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);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";// const contract = new Contract(contractAddress, contractABI, provider);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) }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"; // const contract = new Contract(contractAddress, contractABI, provider);constcontract=newethers.Contract(contractAddress, contractABI, ethersProvider)// Read message from smart contractconstcontractMessage=awaitcontract.retrieve();setContractMessage(contractMessage.toString()) }return ( <divclassName="App"> <formonSubmit={writeToContract}> <inputname="store_value"placeholder="Set contract value"required/> <inputtype="submit"value="Store"/> </form> <buttononClick={readFromContract}>Read From Contract</button> <div>Write-to-contract Tx Hash: ${contractTx}</div> <div>Read-from-contract Message: ${contractMessage}</div> </div> )
문제 해결
Polyfill node core module error
BREAKING CHANGES: webpack<5 used to include polyfills for node.js core modules by default.
이 오류는 Webpack 5 버전을 사용할 때 발생합니다. 이 버전에서는 NodeJS 폴리필이 더 이상 기본으로 지원되지 않습니다. 이 문제를 해결하려면 해당 가이드를 참조하세요.