Integracja portfela MetaMask w aplikacji React

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 […]

Author avatar: Paulina Lewandowska

Paulina LewandowskaDEC 19, 2022

Integracja portfela MetaMask w aplikacji React

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.

Po co czekać? Otrzymaj swój plan Blockchain + AI w 24h

Jedna bezpłatna rozmowa z naszymi inżynierami może zaoszczędzić Ci tygodnie niepewności.

LinkedInInstagramX
[ zdrap mnie ]
Unia EuropejskaFundusze Europejskie

NEXT ENTERPRISES SPÓŁKA Z OGRANICZONĄ ODPOWIEDZIALNOŚCIĄ

realizuje projekt „Audyt smart kontraktów z wykorzystaniem sztucznej inteligencji”

Dofinansowanie projektu z UE:
3 090 156,39 PLN