ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React] web3-react로 MetaMask 지갑을 연결해보자
    WEBn/React 2022. 1. 19. 17:40

     

    안녕하세요 오늘은 개발 내용을

    올려보려 합니다. 취업하고 나서 

    바쁜 일정을 보내느라(..핑계) 포스팅을 못했는데

    오늘은 꽤 유용할 내용을 포스팅하겠습니다.

    Vue.js에서는 MetaMask 연결을 손쉽게 했었는데

    React.js는 좀처럼 잘되지 않았습니다ㅠ

    고생하지 않도록 React에서 MetaMask 연결 시작하겠습니다 !

     

     

     


     

    오늘의 목표

    web3-react를 이용해서 frontend에서 metamask를 연결

     

     

    git 주소https://github.com/HongDaeEui/web3-react-connect-MetaMask/blob/main/README.md

     

    🔰시연 영상

     

     

     

    web3-react란?

     

    React를 사용하여 Etherum dAPP을 구축하기 위한 프레임워크

    • MetaMask/Trust/TokenaryInfura/QuikNodeTrezor/LedgerWalletConnectFortmatic/Portis 등을 포함하여 일반적으로 사용되는 web3 provider를 지원
    • ethers.js 또는 web3.js 인스턴스, 현재 계정 및 네트워크 ID를 포함하는 개발자 친화적인 컨텍스트를 제공
    • 이더리움 블록체인 및 사용자 계정과의 dApp 연결의 모든 측면을 관리하는 기능을 갖춘 맞춤형 커넥터를 작성가능

     

     

    시작

     

    기본적인 create-react-app을 사용하여 해보겠습니다.

    먼저 create-reat-app을 설치해 줍니다.

    npm install -g create-react-app
    

     

    다음 새 프로젝트를 하나 만듭니다. 저는 이름을 web3-react-project라 하였습니다.

    npx create-react-app web3-react-project
    

     

    연결을 하기 전 Connection을 할 UI를 만들겠습니다. CSS는 중요한 것이 아니므로 TailwindCSS를 이용해서 간단히 만들었지만 원하는대로 만들어 보세요ㅎㅎ 전체 코드는 깃헙에 올려놓았습니다.

     

    🔰App.js

     

     

     

    더해서 버튼 중간에는 “연결되지 않음”이라는 텍스트를 추가하고 연결된 경우 “{address}와 연결됨” 이라는 텍스트를 추가하겠습니다.

     

     

     

    커넥터 추가

     

    이제 커넥터를 추가해보겠습니다. component folder를 하나 만들고 그 안에다 wallet folder를 만듭니다. 그 안에 Connector.js라는 파일을 생성합니다.

     

     

     

    MetaMask에 연결할 수 있는 web3-react dependeny를 설치하겠습니다.

    npm install @web3-react/injected-connector
    

     

    InjectedConnectorr를 import하고 export 시킵니다.

    import { InjectedConnector } from '@web3-react/injected-connector'
    export const injected = new InjectedConnector({
      supportedChainIds: [1, 3, 4, 5, 42],
    })
    

    여기서 chainID는 블록체인의 네트워크 상에서 각각의 망을 식별하는 식별자로서 Public 망은 모두 고유의 번호가 있다.

     

     

    InjectedConnector
    import { Connectors } from 'web3-react'
    const { InjectedConnector, NetworkOnlyConnector } = Connectors
     
    const MetaMask = new InjectedConnector({ supportedNetworks: [1, 4] })
     
    const Infura = new NetworkOnlyConnector({
      providerURL: '<https://mainnet.infura.io/v3/>...'
    })
     
    const connectors = { MetaMask, Infura }
    

    => 사용자가 dApp과 상호 작용하는 방식을 결정하게 해줍니다. MetaMask, Infura, Trezor/Ledger, WalletConnect, Fortmatic/Portis 등의 일부 조합에서 발생합니다.

     

     

    다음 파일에서는 전체 코드를 올린 뒤에 각 부분을 설명하겠습니다.

     

     

    web3, web3-react 연결

     

    ✨App.js

    import logo from './logo.svg';
    import './App.css';
    import './styles/globals.css'
    import 'tailwindcss/tailwind.css'
    import {useWeb3React} from "@web3-react/core"
    import { injected } from "./components/wallet/connectors"
    
    export default function App() {
        const {active, account, library, connector, activate, deactivate} = useWeb3React()
    
        async function connect() {
            try {
                await activate(injected)
            } catch (ex) {
                console.log(ex)
            }
        }
    
        async function disconnect() {
            try {
                deactivate()
            } catch (ex) {
                console.log(ex)
            }
        }
    
        return (
            <div className="App flex flex-col items-center justify-center">
                <header className="App-header">
                    <img src={logo} className="App-logo" alt="logo"/>
                    <p>
                        Connecting MetaMask with React
                    </p>
                    <button
                        onClick={connect}
                        className="py-2 mt-20 mb-4 text-lg font-bold text-white rounded-lg w-56 bg-blue-600 hover:bg-blue-800">Connect
                        to MetaMask
                    </button>
                    {active ? <span className="mt-10 text-lg">Connected with <b className="text-yellow-400">{account}</b></span> : <span className="mt-10 text-lg">Not connected</span>}
                    <button
                        onClick={disconnect}
                        className="py-2 mt-20 mb-4 text-lg font-bold text-white rounded-lg w-56 bg-blue-600 hover:bg-blue-800">Disconnect
                    </button>
                </header>
            </div>
        );
    }
    

     

    아까 wallet에 만들었던 connectors.js를 가져옵니다.

    import {injected} from "../components/wallet/connectors"
    

     

    App 구성 요소 내부에 connect function를 만들어 줍니다.

    function connect() {}
    

     

    아까 만들어 두었던 버튼에 click 이벤트를 연결합니다.

    <button
        onClick={connect}
        className="py-2 mt-20 mb-4 text-lg font-bold text-white rounded-lg w-56 bg-blue-600 hover:bg-blue-800">Connect
        to MetaMask
    </button>
    

     

    나의 지갑에 연결하기 위해 @web3-react/core를 설치합니다.

    npm install @web3-react/core
    

    web3-react Documentation 보기

     

     

    그리고 web3ethers를 설치해 줍니다.

    npm install web3
    

    web3 Documentation 보기

     

     

    지갑 연결

     

    provider를 셋업해야 합니다.

     

     

    ✨index.js

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import Web3 from "web3";
    import {Web3ReactProvider} from "@web3-react/core"
    
    function getLibrary(provider, connector) {
        return new Web3(provider)
    }
    
    ReactDOM.render(
        <React.StrictMode>
            <Web3ReactProvider  getLibrary={getLibrary}>
            <App/>
            </Web3ReactProvider>
        </React.StrictMode>,
        document.getElementById('root')
    );
    

     

    pages 폴더를 만들고 안에 _app.js를 만듭니다. Web3ReactProviderWeb3import 시켜줍니다.

    import { Web3ReactProvider } from '@web3-react/core'
    import Web3 from 'web3'
    

     

    Web3Provider
    // Props
    getLibrary: (provider?: any, connector?: AbstractConnectorInterface) => any
    
    // Example
    import { Web3ReactProvider } from '@web3-react/core'
    // import your favorite web3 convenience library here
    
    function getLibrary(provider, connector) {
      return new Web3Provider(provider) // this will vary according to whether you use e.g. ethers or web3.js
    }
    
    function App () {
      return (
        <Web3ReactProvider getLibrary={getLibrary}>
          {/* <...> */}
        </Web3ReactProvider>
      )
    }
    

    => web3-react는 응용 프로그램의 루트(web3 기능을 포함하려는 하위 트리의 루트)에 Web3ReactProvider에 의존합니다. 저수준 제공자로부터 web3 라이브러리 객체를 인스턴스화하는 역할을 하기위해 getLibrary porp이 필요합니다

    getLibiary function을 만듭니다.

     

     

    web3 인스턴스화를 해줄 getLibrary function를 선언해 줍니다.

    function getLibrary(provider) {
      return new Web3(provider)
    }
    

     

    다음 Web3ReactProvider을 최상위 element에 감싸주고 getLibrary를 전달합니다.

    <Web3ReactProvider  getLibrary={getLibrary}>
        <App/>
    </Web3ReactProvider>
    

     

    App.js로 다시 가서 useWeb3React 훅을 사용하여 필요한 모든 값을 가져옵니다.

    const { active, account, library, connector, activate, deactivate } = useWeb3React()
    

     

    • active: 지금 지갑이 연결되어 있는지
    • account: 연결된 블록체인 주소
    • library: 전달한 내용에 따라 web3.js나 ethers.js
    • connector: 현재 커넥터. 예제에서는 연결할 때 injected connector가 됩니다.
    • activate: 지갑에 연결하는 메서드
    • deactivate: 지갑 연결을 끊는 메서드

     

    connect function 안에서 activate function이 사용됩니다. 이로써 유저는 MetaMask 지갑의 연결을 시작할 수 있습니다.

    async function connect() {
      try {
        await activate(injected)
      } catch (ex) {
        console.log(ex)
      }
    }
    

     

    하지만 지갑 연결은 되었지만 유저의 눈에는 연결되었다는 표시가 되지 않습니다. 이를 위해 간단한 조건부 템플릿을 작성합니다. 유저의 지갑이 연결되어 있건 활성화되어 있으면 주소를 표시합니다.

    {active ? <span>Connected with <b>{account}</b></span> : <span>Not connected</span>}
    

     

    disconnect function 또한 위와 같은 방법으로 만듭니다.

    async function disconnect() {
      try {
        deactivate()
      } catch (ex) {
        console.log(ex)
      }
    }
    ...
    <button
        onClick={disconnect}
        className="py-2 mt-20 mb-4 text-lg font-bold text-white rounded-lg w-56 bg-blue-600 hover:bg-blue-800">Disconnect
    </button>
    

     

    여기서 잠깐 !

    이렇게 실행하면 오류가 납니다.

    Module not found: Error: Can't resolve 'crypto' in ...
    ...
    

    이러한 오류가 뜨는데 찾아보니 CRA의 react-scripts에서 문제가 난다.

    최신버전은 5.0.0 버전인데 이를 ^4.0.3 버전으로 다운그레이드하면 해결이됩니다

     

     

     

     


     

    자 이제 우리는 이 앱에 지갑을 연결하고 끊을 수 있습니다 ~!

    이후 토큰을 보내거나 스마트 컨트랙트와 상호작용하는 등의

    여러 가지 작업들을 할 수 있습니다. 읽어주셔서 감사합니다.

    행복한 개발하세요 ㅎㅎㅎ

     

     

     

    ✔ 참고한 글

    https://github.com/NoahZinsmeister/web3-react/tree/v6/docs#useweb3react

    https://medium.com/coinmonks/web3-react-connect-users-to-metamask-or-any-wallet-from-your-frontend-241fd538ed39

     

     

    댓글

Designed by Tistory.