İçeriğe geç

Web3 Dapp'inizde EIP-6963 Desteği Nasıl Uygulanır

Web3 dapp'ınızda daha sorunsuz bir bağlı cüzdan deneyimi için EIP-6963'ü nasıl uygulayacağınızı öğrenin

6 dk okuma
Web3 Dapp'inizde EIP-6963 Desteği Nasıl Uygulanır

Mayıs 2023'te bir grup Ethereum cüzdan geliştiricisi, dapp'lerle bağlantı kurmak için yeni bir endüstri standardı oluşturmak amacıyla bir araya geldi. Bundan önce yaygın uygulama, cüzdanların web tarayıcılarındaki window.ethereum global nesnesi aracılığıyla bir EIP-1193 sağlayıcısı sunmasıydı. Bu teknik, kullanıcıların genellikle tek bir cüzdana sahip olduğu ve bağlandığı ilk dönemlerde iyi çalışıyordu.

Ekosistem büyüdükçe ve kullanıcılar aynı anda birden fazla cüzdan kullanmaya başladıkça, dapp geliştiricilerinin bir kullanıcının hangi cüzdana bağlı olduğunu tespit etme sürecini doğru şekilde yönetmesi ya da birden fazla cüzdan yüklüyken kullanıcılara hangi cüzdanı kullanacaklarını seçme imkânı sunması güçleşti.

Ekim 2023'te, artık EIP-6963 veya Multi-Wallet Injected Provider Discovery olarak bilinen bu standart kabul edildi. O tarihten bu yana cüzdan geliştiricileri, EIP-6963'ü cüzdan sağlayıcılarını keşfetmenin varsayılan yolu olarak sunmaya başladı. MetaMask da bu konuda bir istisna değildir; bu standardın MetaMask cüzdan API'si ve MetaMask SDK tarafından desteklenmesini sağladık.

Bunun yanı sıra, window.ethereum'a dayanan dapp'lerin desteğinin süreceği güvence altına alınmıştır. Ancak, tercih edilen sağlayıcı keşif mekanizması olarak tüm dapp'lere EIP-6963 desteğinin eklenmesini öneriyoruz. Bunu yapmanın en kolay yolu, EIP-6963'ü destekleyen üçüncü taraf kütüphanelerle entegrasyon sağlamaktır. Mevcut kütüphanelerin büyüyen listesi için MetaMask belgelerini ziyaret edin.

Bu eğitim, mevcut üçüncü taraf kütüphaneleri kullanmamaya karar verirseniz dapp'inize EIP-6963 desteği eklemenin temel adımlarını size gösterecektir. React ve TypeScript kullanılmaktadır; ancak herhangi bir JavaScript geliştiricisi bu adımları takip edebilmeli ve tercih ettiği framework'te uygulayabilmelidir.

Web3 Cüzdanları için Desteklenen Arayüzleri ve Türleri Tanımlayın

Dapp'inizde çoklu cüzdan keşfini desteklemenin ilk adımı, iyileştirme önerisinde belirtilen tüm desteklenen arayüzleri ve türleri tanımlamaktır. Bu arayüzler ve türler, Ethereum cüzdan sağlayıcılarını yönetmek için yapılandırılmış ve standartlaştırılmış bir yol sunarak birden fazla Ethereum cüzdanının entegrasyonunu ve keşfini kolaylaştırır.

// EthereumProviderTypes.d.ts

// Interface for provider information following EIP-6963.
interface EIP6963ProviderInfo {
  walletId: string; // Unique identifier for the wallet e.g io.metamask, io.metamask.flask 
  uuid: string; // Globally unique ID to differentiate between provider sessions for the lifetime of the page
  name: string; // Human-readable name of the wallet
  icon: string; // URL to the wallet's icon
}

// Interface for Ethereum providers based on the EIP-1193 standard.
interface EIP1193Provider {
  isStatus?: boolean; // Optional: Indicates the status of the provider
  host?: string; // Optional: Host URL of the Ethereum node
  path?: string; // Optional: Path to a specific endpoint or service on the host
  sendAsync?: (request: { method: string, params?: Array<unknown> }, callback: (error: Error | null, response: unknown) => void) => void; // For sending asynchronous requests
  send?: (request: { method: string, params?: Array<unknown> }, callback: (error: Error | null, response: unknown) => void) => void; // For sending synchronous requests
  request: (request: { method: string, params?: Array<unknown> }) => Promise<unknown>; // Standard method for sending requests per EIP-1193
}

// Interface detailing the structure of provider information and its Ethereum provider.
interface EIP6963ProviderDetail {
  info: EIP6963ProviderInfo; // The provider's info
  provider: EIP1193Provider; // The EIP-1193 compatible provider
}

// Type representing the event structure for announcing a provider based on EIP-6963.
type EIP6963AnnounceProviderEvent = {
  detail: {
    info: EIP6963ProviderInfo; // The provider's info
    provider: EIP1193Provider; // The EIP-1193 compatible provider
  }
}
Kopyala

Her arayüzün ve türün ne anlama geldiğini anlamanıza yardımcı olmak için açıklamalar ekledim. Daha ayrıntılı bir açıklama için lütfen iyileştirme önerisine başvurun.

Olaylara Abone Olun ve Yeni Bağlantılardan Haberdar Olun

Bir sonraki adım, yeni cüzdan bağlantıları tespit edildiğinde dapp'inizi uyaracak bir mekanizma oluşturmaktır. Unutmayın, EIP-6963'ün amacı birden fazla cüzdan arasında kesintisiz bağlantı ve geçiş sağlamaktır. React'te bunu aşağıdaki örnek kodla gerçekleştirebiliriz.

// store.tsx

declare global {
  interface WindowEventMap {
    "eip6963:announceProvider": CustomEvent<EIP6963AnnounceProviderEvent>;
  }
}

let providers: EIP6963ProviderDetail[] = [];

export const store = {
  value: () => providers,

  subscribe: (callback: () => void) => {
    function onAnnouncement(event: EIP6963AnnounceProviderEvent) {
      // Prevent adding a provider if it already exists in the list based on its uuid.
      if (providers.some(p => p.info.uuid === event.detail.info.uuid)) return;

      // Add the new provider to the list and call the provided callback function.
      providers = [...providers, event.detail];
      callback();
    }

    window.addEventListener("eip6963:announceProvider", onAnnouncement as EventListener);
    window.dispatchEvent(new Event("eip6963:requestProvider"));

    return () => window.removeEventListener("eip6963:announceProvider", onAnnouncement as EventListener);
  }
}
Kopyala

Yukarıdaki kod örneğinin açıklaması:

  • WindowEventMap'i "eip6963:announceProvider" adlı özel bir olayla genişleterek yeni Ethereum cüzdan sağlayıcılarının kullanılabilirliğini duyurmak için global bir olay türü oluşturuyoruz.

  • Tespit edilen tüm cüzdan sağlayıcılarını takip etmek için kullanılan, adlandırılmış sağlayıcılar dizisiyle temsil edilen harici bir store başlatıyoruz. Bu dizi, cüzdan sağlayıcısı ve ilgili Ethereum sağlayıcısı hakkında bilgi içeren EIP6963ProviderDetail arayüzüne uyan nesneleri depolar.

  • Store nesnesi içindeki subscribe fonksiyonu aracılığıyla bir abonelik mekanizması sunuyoruz. Bu fonksiyon "eip6963:announceProvider" olayını dinler ve harici store'u yeni duyurulan sağlayıcıların ayrıntılarıyla günceller. Yinelenen girişleri önlemek amacıyla sağlayıcıların yalnızca store'da bulunmuyorsa eklenmesini sağlar.

  • Store nesnesi iki temel işlev sunar: 1. value fonksiyonu, harici store'un mevcut durumunu, yani tespit edilen cüzdan sağlayıcılarının listesini almayı sağlar.

  1. subscribe fonksiyonu, bileşenlerin veya uygulamanın diğer bölümlerinin store'daki değişikliklere abone olmasını sağlar. Yeni bir sağlayıcı duyurulup store'a eklendiğinde, abone olan öğeler bir callback mekanizması aracılığıyla bilgilendirilir ve güncellenmiş sağlayıcı listesine tepki verebilirler.

Şimdi, yerel durumu yukarıdaki store.tsx'te tanımlanan harici store ile senkronize etmek için bir useSyncExternalStore hook'u tanımlayalım:

// useSyncProviders.tsx

import { useSyncExternalStore } from "react";
import { store } from "./store";

export const useSyncProviders = ()=> useSyncExternalStore(store.subscribe, store.value, store.value)
Kopyala

Tespit Edilen Her Web3 Cüzdan Sağlayıcısı için Dinamik Olarak Butonlar Görüntüleyin

Tespit edilen her cüzdan sağlayıcısı için dinamik olarak bir buton oluşturmak amacıyla useSyncProviders hook'unu kullanan bir React bileşeni tanımlayalım:

import { useState } from 'react';
import { useSyncProviders } from '../hooks/useSyncProviders';
import { formatAddress } from '~/utils';

export const DiscoverWalletProviders = () => {
  const [selectedWallet, setSelectedWallet] = useState<EIP6963ProviderDetail | undefined>();
  const [userAccount, setUserAccount] = useState<string>('');
  const providers = useSyncProviders();

  const handleConnect = async (providerWithInfo: EIP6963ProviderDetail) => {
    const accounts = await providerWithInfo.provider.request({ method: 'eth_requestAccounts' }).catch(console.error);

    if (accounts && accounts[0]) {
      setSelectedWallet(providerWithInfo);
      setUserAccount(accounts[0]);
    }
  };

  return (
    <>
      <h2>Wallets Detected:</h2>
      <div>
        {providers.length > 0 ? (
          providers.map((provider) => (
            <button key={provider.info.uuid} onClick={() => handleConnect(provider)}>
              <img src={provider.info.icon} alt={provider.info.name} />
              <div>{provider.info.name}</div>
            </button>
          ))
        ) : (
          <div>There are no announced providers.</div>
        )}
      </div>
      <hr />
      <h2>{userAccount ? 'Wallet Selected' : 'No Wallet Selected'}</h2>
      {userAccount && (
        <div>
          <img src={selectedWallet!.info.icon} alt={selectedWallet!.info.name} />
          <div>{selectedWallet!.info.name}</div>
          <div>({formatAddress(userAccount)})</div>
        </div>
      )}
    </>
  );
};
Kopyala

Yukarıdaki React bileşeninin açıklaması:

  • Şu anda seçili olan Ethereum cüzdan sağlayıcısını ve kullanıcının hesap adresini takip etmek için sırasıyla selectedWallet ve userAccount olmak üzere iki state hook kullanıyoruz.

  • Mevcut her Ethereum cüzdan sağlayıcısını dinamik olarak tespit etmek için useSyncProviders hook'unu kullanıyoruz. Bu hook, her biri sağlayıcının bilgilerini ve Ethereum sağlayıcı nesnesini içeren EIP6963ProviderDetail arayüzüne uyan bir sağlayıcılar dizisi döndürür.

  • Bir cüzdan sağlayıcısı butonu tıklandığında çağrılan handleConnect fonksiyonunu tanımlıyoruz. Bu fonksiyon, kullanıcıdan hesap erişimi istemek için eth_requestAccounts metoduyla sağlayıcının request metodunu kullanır. Erişim verilirse ilk hesap adresi userAccount'ta, sağlayıcının ayrıntıları ise selectedWallet'ta saklanır.

  • Son olarak, tespit edilen her cüzdan sağlayıcısı için sağlayıcının adını ve simgesini gösteren bir buton listesi oluşturuyoruz.

Bileşenimiz tanımlandıktan sonra son adım bu bileşeni render etmektir.

import './App.css'
import { DiscoverWalletProviders } from './components/DiscoverWalletProviders'

function App() {

  return (
    <>
      <DiscoverWalletProviders/>
    </>
  )
}

export default App
Kopyala

Bu birkaç adımla dapp'imizde temel düzeyde EIP-6963 desteğini başarıyla uyguladık. Az önce oluşturduğumuz işlevselliğin görsel bir temsili için aşağıya bakın. Görselde yer alan dapp'in tüm kodu GitHub'da bulunabilir.

EIP-6963 ve Web3 Cüzdanlarının Geleceği

Bu standardın cüzdan geliştiricileri ve üçüncü taraf bağlantı kütüphaneleri tarafından daha geniş çapta benimsenmesini görmeye devam ettikçe, özellikle yeni kullanıcıların katılımında UX'i iyileştirme açısından Ethereum topluluğuna açtığı çeşitli kullanım senaryoları konusunda heyecan duyuyoruz.

MetaMask olarak, EIP-6963'ün daha da geniş çapta benimsenmesini sağlamak için diğer cüzdan geliştiricileriyle, dapp geliştiricileriyle ve üçüncü taraf bağlantı kütüphaneleriyle iş birliği yapmak için sabırsızlanıyoruz. Bu standardı destekleme çalışmalarımız hakkında daha fazla bilgi için lütfen MetaMask belgelerine başvurun.

Yapay zeka tarafından çevrildi. Hatalar içerebilir. Lütfen her zaman bilgileri doğrulayın.

Çeviriyi değerlendir

Bu makalenin yazarı:

  • Kingsley Okonkwo

    Sertifikalı bir Ethereum Blockchain geliştiricisi olan Kingsley, Consensys'te teknik yazar olarak görev yapmakta olup özellikle geliştirici araçlarına odaklanmaktadır. Consensys'e katılmadan önce Kingsley, Gigster ve Braintrust dahil olmak üzere çeşitli platformlarda serbest back-end geliştirici olarak çalışmıştır. 5 yıllık yazılım geliştirme deneyimiyle JavaScript (Node.js ve React), GoLang, SQL ve Docker gibi araçlarda uzmandır. Kingsley, web3 teknolojisinin en güncel olanaklarını kullanarak adım adım eğitimler ve nasıl yapılır kılavuzları hazırlamada öne çıkmakta; bu sayede diğer geliştiricilerin daha iyi dapp'ler oluşturmasına yardımcı olmaktadır. Şu anda Dubai'de yaşayan Kingsley, boş zamanlarında basketbol ve futbol oynamaktan keyif almaktadır.

    Tüm makaleleri oku