Integracja portfela MetaMask w aplikacji React

Integracja portfela MetaMask w aplikacji React

19 grudnia

/

Blockchain

Wprowadzenie

W większości zdecentralizowanych aplikacji portfele kryptograficzne są wymagane aby użytkownicy mogli dokonywać w nich interakcji z blockchain. Aby to było możliwe developerzy zajmujący się implementacją warstwy frontend muszą dokonać integracji z aplikacjami portfelowymi użytkowników. Poniższy artykuł poświęcony jest developerem zajmującym się tworzeniem interfejsów użytkownika z pomocą biblioteki React. Jest to poradnik krok po kroku jak dokonać integracji aplikacji reactowej z wtyczką do przeglądarki obecnie jednego z najbardziej popularnych porteli jakim jest MetaMask.

Podstawowa aplikacja w React

Kod źródłowy aplikacji napisanej na potrzeby tego tutariala znajduje się pod tym linkiem. Do stworzenia aplikacji wykorzystałem następujące biblioteki:

Do pracy z tym poradnikiem można wykorzystać aplikację zamieszczoną pod linkiem wyżej, bądź samodzielnie skonfigurować aplikację w React z pomocą np. create-react-app lub vite.

Gdy nasza aplikacja jest już skonfigurowana, należy upewnić się że mamy zainstalowane wszystkie niezbędne zależności, aby tego dokonać należy wykonać komendę

npm install wagmi ethers

Do przygotowania aplikacji skorzystałem równiez bliblioteki komponentów o nazwie Material-ui, jeśli również chcesz z niej skorzystać zainstaluj następujące paczki komendą:

npm install @mui/material @emotion/react @emotion/styled

Po ukończonej konfiguracji i zainstalowaniu wszystkich niezbędnych zależności możemy przejść do kolejnego punktu.

Biblioteka Wagmi

Do integracji z aplikacją portfelową MetaMask wykorzystamy dedykowaną bibliotekę do React o nazwie wagmi zawierającą pokaźną liczbę hooków oraz funkcji potrzebnych w codziennej pracy przy interakcjach z blockchain w aplikacjach frontendowych.

Pierwszym krokiem będzie konfiguracja biblioteki, aby tego dokonać należy opakować naszą aplikację w komponent WagmiConfig przekazując zmienną client z naszą konfiguracją:

import { WagmiConfig, createClient } from "wagmi";
import { getDefaultProvider } from "ethers";
 
import { Home } from "./pages";
import "./styles.css";
 
const client = createClient({
 autoConnect: true,
 provider: getDefaultProvider()
});
 
export default function App() {
 return (
   <WagmiConfig client={client}>
     <Home />
   </WagmiConfig>
 );
}

Wszystkie dostępne opcje konfiguracyjne znajdziejsz pod tym linkiem w oficjalnej dokumentacji wagmi

Podłączenie portfela MetaMask

Po ukończonej konfiguracji bliblioteki wagmi możemy przejść do tworzenia komponentu odpowiedzialnego za połączenie z naszym portfelem. W implementacji pomocne będą hooki dostępne w blibliotece.

Aby uzyskać dostęp do funkcji, która umożliwi nam wykonanie requestu o podłączenie portfela należy skorzystać z hooka useConnect(). Aby wskazać, że portfelem, z którym chcemy się połączoyć jest MetaMask, w obiekcie konfiguracyjnym do hooka pod kluczem connecter należy przekazać utworzoną instancję klasy InjectedConnector

import { useConnect } from "wagmi";
import { InjectedConnector } from "wagmi/dist/connectors/injected";
 
 ...
 
 const { connect } = useConnect({
   connector: new InjectedConnector()
 });
 
 ...

Hook zwraca nam funkcję connect, którą możemy wywołać np. po kliknięciu przycisku.

 ...
 
<Button onClick={() => connect()}>Connect</Button>
 
 ...

Aby otrzymać informacje o podłączonym portfelu bądź stanie jego podłączenia, można skorzystać z hooka useAccount(), który zwraca nam m.in. takie informacje jak:

  • adres podłączonego portfela
  • to czy akcją podłączania portfela jest w trakcie
  • Czy aktualnie w aplikacji portfel użytkownika jest podłączony
...
 
 const { address, isConnected, isConnecting } = useAccount();
 
 ...

Jeśli użytkownikowi naszej aplikacji udało się podłączyć portfel należy umożliwić mu również jego odłączenie, do tego należy skorzystać z funkcji disconnect do której możemy się dostać z pomocą hooka useDisconnect()

 ...
 
 const { disconnect } = useDisconnect();
 
 ...

Z pomocą tych trzech prostych hooków jesteśmy w stanie obsłużyć podłącznie portfela. Pełny kod źródłowy komponentu obsługującego podłączanie z przykładowej aplikacjij:

import { useConnect, useDisconnect, useAccount } from "wagmi";
import { InjectedConnector } from "wagmi/dist/connectors/injected";
import { Card, Button, Heading } from "../../components";
import Typography from "@mui/material/Typography";
import { WalletInfo } from "./WalletInfo";
 
export const WalletConnect = () => {
 const { isConnected, isConnecting } = useAccount();
 
 const { connect } = useConnect({
   connector: new InjectedConnector()
 });
 
 const { disconnect } = useDisconnect();
 
 return (
   <Card>
     <Heading sx={{ mb: 2 }}>
       {isConnected ? "Your connected wallet:" : "Connect your MetaMask"}
     </Heading>
 
     {isConnecting && <Typography>Connecting...</Typography>}
 
     {isConnected ? (
       <>
         <WalletInfo />
         <Button sx={{ mt: 2 }} onClick={() => disconnect()}>
           Disconnect
         </Button>
       </>
     ) : (
       <Button
         disabled={isConnecting}
         sx={{ mt: 2 }}
         onClick={() => connect()}
       >
         Connect
       </Button>
     )}
   </Card>
 );
};

Na powyższym przykładzie znajduje się komponent <WalletInfo />, który posłuży nam do wyświetlenia informacji o podłączonym portfelu, jego utworzeniem zajmiemy się w kolejnym kroku

Wyświetlanie informacji o podłączonym portfelu

Kolejnym krokiem będzie wyświetlenie użytkownikowi informacji o podłączonym portfelu takich jak:

  • Adres portfela
  • Aktualny balans ETH na portfelu

W tym celu przygotujemy dwa proste komponenty <WalletAddress/> oraz <WalletBalance/>, które następnie umieścimy w komponencie <WalletInfo/>:

Adres aktualnie podłączonego portfela

import { WalletAddress } from "./WalletAddress";
import { WalletBalance } from "./WalletBalance";
 
export const WalletInfo = () => {
 return (
   <div>
     <walletaddress />
     <walletbalance />
   </div>
 );
};
import { useAccount } from "wagmi";
import Typography from "@mui/material/Typography";
 
export const WalletAddress = () => {
 const { address } = useAccount();
 return (
   <typography>
     <strong>Address: </strong>
     {address}
   </typography>
 );
};

W celu wyświetlenia podłączonego portfela skorzystamy z wcześniej wspomnianego hooka useAccount(), który zwraca nam zmienną address. Implementacja prostego komponentu do wyświetlenia adresu wygląda następująco:

import { useAccount } from "wagmi";
import Typography from "@mui/material/Typography";
 
export const WalletAddress = () => {
 const { address } = useAccount();
 return (
   <typography>
     <strong>Address: </strong>
     {address}
   </typography>
 );
};

Balans aktualnie podłączonego portfela

Biblioteka wagmi posiada również hooka useBalance(), który znacznie ułatwi nam proces pobierania aktualnego balansu portfela. Proces pobierania tej wartości z blockchain jest asynchroniczny, więc hook ten zwraca na m.in. takie informacje w zmiennych jak:

  • isLoading - czy pobieranie balansu jest w trakcie
  • isFetched - czy balans portfela został pobrany
  • isError - czy podczas pobierania danych wystąpił błąd
  • data - obiekt zawierający takie pola jak:
    • value - balans użytkownika w jednostach WEI
    • formatted - balans użytkownika sformatowany do jednostek ETH
    • symbol - Symbol aktywa dla którego został pobrany balans
    • decimals - Liczba miejsc po przecinku jakie może posiadać liczba opisująca ilość danego aktywa

W celu lepszego zrozumienia czym jest jednostka WEI, ETH bądź parametr decimals zachęcam do zapoznania się z tymi artykułami:

Aby wskazać, dla jakiego portfela chcemy pobrać balans środków, przy wywołaniu hooka musimy przekazać adres tego portfela jako parametr w następujący sposób, aby to zrobić możemy skorzystać ponownie z hooka useAccount() z poprzedniego kroku:

 ...
 
 const { address } = useAccount();
 const { isLoading, isFetched, isError, data } = useBalance({ address });
 
 ...

Dzięki tym informacjom jesteśmy w stanie zaimplementować cały komponent z obsługą procesu ładowania danych:

import { useAccount, useBalance } from "wagmi";
import Typography from "@mui/material/Typography";
import Skeleton from "@mui/material/Skeleton";
 
export const WalletBalance = () => {
 const { address } = useAccount();
 const { isLoading, isFetched, isError, data } = useBalance({ address });
 
 return (
   <typography>
     {isLoading && <skeleton width="{200}" />}
     {isFetched && (
       <>
         <strong>Balance: </strong>
         {data?.formatted} {data?.symbol}
       </>
     )}
     {isError && "Fetching balance failed!"}
   </typography>
 );
};

Podsumowanie

Przedstawiona aplikacja to tylko przykład, w produkcyjnych aplikacjach developerzy często muszą się mierzyć z integracją wielu aplikacji portfelowych, wspieraniem połączenia na wielu sieciach blockchain oraz interakcjami podłączonych portfeli z smart kontraktami. Wszystkie te funkcjonalności oraz znacznie więcej wspiera biblioteka wagmi zaprezentowana w tym turorialu. Dlatego też zachęcam do przestudiowania dokumentacji tej biblioteki w celu zapoznania się, jakie możliwości oferuje.

Never miss a story

Stay updated about Nextrope news as it happens.

You are subscribed

More of our Blog

See the latest collection of articles produced by our seasoned professionals

Zakres projektu

API/Backend
Development

Strony Internetowe
Development

Aplikacje Mobilne
Development

Projektowanie
Design

Blockchain
Solutions

Usługi Internetowe
Services

Next Enterprises zapewniło bankowi usługę technologiczną potrzebną do wprowadzenia projektu opartego na blockchainie. W ramach współpracy firma zaprojektowała usługę w modelu SaaS. Rozwiązanie przechowuje na swoich serwerach, udostępniając je bankowi i jednocześnie gwarantując jakość zgodną ze standardami zawartymi w umowie.

Tomasz Sienicki

Tomasz Sienicki

Blockchain Strategy Manager, Alior Bank

Współpraca z zespołem Nextrope wyznacza zupełnie nowy poziom jakości, innowacyjnych rozwiązań i profesjonalnych usług. Jeśli potrzebujesz wsparcia przy technologii blockchain, trafiłeś na profesjonalistów. Zdecydowanie polecam!

Kajetan Komar-Komarowski

Kajetan Komar-Komarowski

Współzałożyciel i prawnik Lex Secure

W listopadzie 2017 r. opublikowaliśmy grę wykorzystującą inteligentne kontrakty jako mechanizm dystrybucji i transakcji. Zespół Nextrope wspierał nas w najważniejszej części projektu - tworzeniu i testowaniu bezpieczeństwa inteligentnych kontraktów blockchain w sieci Ethereum. Mogę gorąco polecić Mateusza i jego zespół - to prawdziwi eksperci w dziedzinie blockchaina.

Maciej Skrzypczak

Maciej Skrzypczak

CEO Gameset