Construire une dapp sur Tezos (édition 2023)
Partie 2 sur 4-> Portefeuille et jetons de l'utilisateur
Parlons maintenant du portefeuille.
Le portefeuille est un élément clé de votre dapp, sans lui, les utilisateurs ne pourront pas interagir avec la blockchain Tezos, ce qui va à l'encontre de votre objectif. Il y a plusieurs considérations à prendre en compte lors de la configuration du portefeuille que nous expliquerons ci-dessous.
Tout d'abord, nous voulons isoler le portefeuille et ses différentes interactions et valeurs dans le même composant, appelé Wallet.sveltedans notre exemple. Lors de l'utilisation du SDK Beacon, il est crucial de conserver une seule instance de Beacon en cours d'exécution afin d'éviter les bogues.
Lorsque le composant Wallet est monté, nous voulons faire différentes choses :
onMount(async () => {
const wallet = new BeaconWallet({
name: "Tezos dev portal dapp tutorial",
preferredNetwork: network
});
store.updateWallet(wallet);
const activeAccount = await wallet.client.getActiveAccount();
if (activeAccount) {
const userAddress = (await wallet.getPKH()) as TezosAccountAddress;
store.updateUserAddress(userAddress);
$store.Tezos.setWalletProvider(wallet);
await getWalletInfo(wallet);
// fetches user's XTZ, tzBTC and SIRS balances
const res = await fetchBalances($store.Tezos, userAddress);
if (res) {
store.updateUserBalance("XTZ", res.xtzBalance);
store.updateUserBalance("tzBTC", res.tzbtcBalance);
store.updateUserBalance("SIRS", res.sirsBalance);
} else {
store.updateUserBalance("XTZ", null);
store.updateUserBalance("tzBTC", null);
store.updateUserBalance("SIRS", null);
}
}
});
Maintenant, vous voulez vérifier si l'utilisateur a déjà connecté un portefeuille. Beacon gardera une trace des connexions en direct dans le stockage local, c'est ainsi que vos utilisateurs peuvent naviguer vers votre dapp et avoir leur portefeuille connecté automatiquement !
L' BeaconWalletinstance fournit une clientpropriété avec différentes méthodes, celle dont vous avez besoin ici est getActiveAccount(), qui récupérera toute connexion en direct stockée dans le stockage local. S'il existe une connexion en direct, vous pouvez récupérer l'adresse de l'utilisateur et l'enregistrer dans le magasin, mettre à jour le magasin avec l'adresse de l'utilisateur avant de configurer le portefeuille en tant que signataire avec , obtenir les informations dont vous avez besoin sur le portefeuille (principalement, le $store.Tezos.setWalletProvider(wallet)nom du portefeuille) avec la getWalletInfo()fonction, puis récupérez les soldes de l'adresse associée à la fetchBalances()fonction décrite précédemment. Une fois les soldes récupérés, ils sont enregistrés dans la boutique pour être affichés dans l'interface.
Remarque : TezosAccountAddressest un type personnalisé que j'aime utiliser pour valider les adresses Tezos pour les comptes implicites : type TezosAccountAddress = tz${"1" | "2" | "3"}${string}, TypeScript déclenchera un avertissement si vous essayez d'utiliser une chaîne qui ne correspond pas à ce modèle.
Connecter le portefeuille
Taquito et Beacon fonctionnant à l'unisson, il est très facile de connecter le portefeuille. Quelques lignes de code utilisant les API de ces deux librairies incontournables sur Tezos vont faire des miracles.
Voici comment faire:
const connectWallet = async () => {
if (!$store.wallet) {
const wallet = new BeaconWallet({
name: "Tezos dev portal dapp tutorial",
preferredNetwork: network
});
store.updateWallet(wallet);
}
await $store.wallet.requestPermissions({
network: { type: network, rpcUrl }
});
const userAddress = (await $store.wallet.getPKH()) as TezosAccountAddress;
store.updateUserAddress(userAddress);
$store.Tezos.setWalletProvider($store.wallet);
// finds account info
await getWalletInfo($store.wallet);
// fetches user's XTZ, tzBTC and SIRS balances
const res = await fetchBalances($store.Tezos, userAddress);
if (res) {
store.updateUserBalance("XTZ", res.xtzBalance);
store.updateUserBalance("tzBTC", res.tzbtcBalance);
store.updateUserBalance("SIRS", res.sirsBalance);
} else {
store.updateUserBalance("XTZ", null);
store.updateUserBalance("tzBTC", null);
store.updateUserBalance("SIRS", null);
}
};
Ensuite, vous demandez à l'utilisateur de sélectionner un portefeuille avec la requestPermissions()méthode présente sur l'instance du BeaconWallet. Le paramètre est un objet où vous indiquez le réseau auquel vous souhaitez vous connecter ainsi que l'URL du nœud RPC Tezos avec lequel vous allez interagir.
Une fois que l'utilisateur a sélectionné un portefeuille à utiliser avec notre dapp, vous obtenez son adresse avec la getPKH()méthode sur l' BeaconWalletinstance, vous mettez à jour le signataire de l' TezosToolkitinstance en transmettant l'instance de portefeuille à setWalletProvider(), vous obtenez les informations dont vous avez besoin du portefeuille et vous récupérez le les soldes des utilisateurs.
Maintenant, le portefeuille est connecté et l'utilisateur voit ses différents soldes, ainsi qu'un statut de connexion dans la barre latérale !
IMPORTANT : quelle que soit la façon dont vous souhaitez concevoir votre dapp, il est essentiel de conserver une seule instance du BeaconWalletet il est fortement recommandé de faire de même avec l'instance du TezosToolkit. La création de plusieurs instances perturbe l'état de votre application et Taquito en général.
Déconnecter le portefeuille
Déconnecter le portefeuille est aussi important que le connecter. Il n'y a rien de plus frustrant que de chercher comment déconnecter votre portefeuille pendant des heures quand ce n'est pas explicite. N'oubliez pas que de nombreux utilisateurs ont plusieurs portefeuilles (comme Temple ou Kukai) et même plusieurs adresses dans le même portefeuille qu'ils souhaitent utiliser pour interagir avec votre dapp. Facilitez la déconnexion du portefeuille pour eux.
const disconnectWallet = async () => {
$store.wallet.client.clearActiveAccount();
store.updateWallet(undefined);
store.updateUserAddress(undefined);
connectedNetwork = "";
walletIcon = "";
};
$store.wallet.client.clearActiveAccount()-> tue la connexion actuelle à Beaconstore.updateWallet(undefined)-> supprime le wallet de l'état afin de déclencher un rechargement de l'interfacestore.updateUserAddress(undefined)-> supprime l'adresse de l'utilisateur actuel de l'état pour mettre à jour l'interface utilisateurconnectedNetwork = ""; walletIcon = ""-> également nécessaire pour réinitialiser l'état de la dapp et présenter une interface où aucun portefeuille n'est connecté
Considérations sur la conception
Écrire du code pour interagir avec un portefeuille dans une application décentralisée est un tout nouveau paradigme et bien que vous puissiez réutiliser de nombreux concepts et bonnes pratiques issus de votre expérience de développeur, il y a aussi quelques nouveautés à garder à l'esprit :
- N'invitez jamais les utilisateurs à connecter leur portefeuille après le montage de la dapp : obtenir une fenêtre contextuelle de portefeuille sur votre écran juste après le chargement de l'application est ennuyeux, vous devez vous rappeler que beaucoup de vos utilisateurs ne sont pas techniques et ne comprennent pas cela connecter un portefeuille est inoffensif, ils peuvent donc se méfier de votre dapp si vous leur demandez de connecter leur portefeuille dès le départ. Au lieu de cela, présentez quelques informations sur votre dapp et un bouton pour connecter manuellement leur portefeuille, si c'est leur première fois.
- Le bouton pour connecter un portefeuille doit se démarquer dans votre interface, que vous l'agrandissiez, avec une couleur différente ou une police différente, les utilisateurs ne doivent pas passer plus de quelques secondes pour le trouver.
- Le bouton doit être dans une position prévisible : la plupart des dapps sur Tezos placent leur bouton pour connecter un portefeuille en haut à gauche ou en haut à droite de l'interface utilisateur. Vous n'êtes pas "créatif" en plaçant le bouton à un autre endroit, vous finirez simplement par confondre vos utilisateurs.
- Le texte du bouton doit lire Connecter ou quelque chose de similaire, éviter Sync ou d'autres mots mais "connecter" car ils peuvent signifier quelque chose de différent dans le contexte d'une application décentralisée.
- Le statut du portefeuille doit être affiché dans la dapp. Qu'il soit connecté ou déconnecté, l'utilisateur doit pouvoir le dire. De plus, vous pouvez ajouter des informations sur le portefeuille qu'ils utilisent (comme nous le faisons dans ce tutoriel), le réseau auquel ils sont connectés ou leur solde.
- Vous devez activer/désactiver les interactions de votre dapp qui dépendent du wallet. Les utilisateurs ne devraient pas pouvoir interagir avec une fonctionnalité de votre application qui nécessite que leur portefeuille soit connecté si ce n'est pas le cas.
L'une des fonctionnalités les plus importantes de la dapp, qui est également parmi les plus faciles à négliger, est la récupération des soldes de l'utilisateur. Les utilisateurs peuvent dire que quelque chose ne va pas si leurs soldes ne s'affichent pas correctement ou ne sont pas mis à jour en conséquence après une interaction avec le contrat, c'est pourquoi il est crucial de prendre soin d'afficher et de mettre à jour leurs soldes.
Parce que vous allez chercher des soldes dans différents composants de notre application, vous allez créer une fonction dans le utils.tsfichier et l'importer si nécessaire.
Afin de récupérer les soldes, vous utiliserez Taquito pour le solde XTZ de l'utilisateur et une API très populaire sur Tezos pour les soldes tzBTC et SIRS, l' API TzKT . Si vous souhaitez créer des applications plus complexes sur Tezos, une bonne connaissance de l'API TzKT est essentielle car elle fournit de nombreuses fonctionnalités qui rendront vos applications plus riches en contenu et plus rapides.
Regardons le type de fonction :
export const fetchBalances = async (
Tezos: TezosToolkit,
userAddress: TezosAccountAddress
): Promise<{
xtzBalance: number;
tzbtcBalance: number;
sirsBalance: number;
} | null> => {
try {
// the code will be here
} catch (error) {
console.error(error);
return null;
}
}
Tout d'abord, récupérons le solde XTZ :
const xtzBalance = await Tezos.tz.getBalance(userAddress);
if (!xtzBalance) throw "Unable to fetch XTZ balance";
Ensuite, vous vérifiez l'existence d'un solde et vous rejetez la promesse si elle n'existe pas. Si tel est le cas, le solde sera disponible sous la forme d'un BigNumber .
Remarque : comme c'est le cas la plupart du temps, Taquito renvoie les valeurs numériques de la blockchain en tant que BigNumber, car certaines valeurs peuvent être de très grands nombres et JavaScript est connu pour sa mauvaise gestion des grands nombres.
Une fois le solde XTZ récupéré, vous pouvez continuer et récupérer les soldes de tzBTC et SIRS :
import { tzbtcAddress, sirsAddress } from "./config";
// previous code for the function
const res = await fetch(
`https://api.tzkt.io/v1/tokens/balances?account=${userAddress}&token.contract.in=${tzbtcAddress},${sirsAddress}`
);
if (res.status === 200) {
const data = await res.json();
if (Array.isArray(data) && data.length === 2) {
const tzbtcBalance = +data[0].balance;
const sirsBalance = +data[1].balance;
if (!isNaN(tzbtcBalance) && !isNaN(sirsBalance)) {
return {
xtzBalance: xtzBalance.toNumber(),
tzbtcBalance,
sirsBalance
};
} else {
return null;
}
}
} else {
throw "Unable to fetch tzBTC and SIRS balances";
}
Lorsque la promesse se résout avec un 200code, cela signifie que les données ont été reçues. Vous l'analysez en JSON avec la .json()méthode sur la réponse et nous vérifions que les données ont la forme attendue, c'est-à-dire un tableau contenant 2 éléments.
Le premier élément est le solde tzBTC et le second est le solde SIRS. Vous les stockez dans leurs propres variables que vous convertissez en nombres avant de vérifier qu'ils ont été correctement convertis avec isNaN. Si tout se passe bien, les 3 soldes sont retournés et si quelque chose ne va pas en cours de route, la fonction retourne null.
Après avoir récupéré les soldes dans n'importe quel composant de notre application, vous stockez ces données dans le magasin pour mettre à jour l'état :
const res = await fetchBalances($store.Tezos, userAddress);
if (res) {
store.updateUserBalance("XTZ", res.xtzBalance);
store.updateUserBalance("tzBTC", res.tzbtcBalance);
store.updateUserBalance("SIRS", res.sirsBalance);
} else {
store.updateUserBalance("XTZ", null);
store.updateUserBalance("tzBTC", null);
store.updateUserBalance("SIRS", null);
}
Dans la troisième partie, échange de jetons =>
![Qu'est-ce qu'une liste liée, de toute façon? [Partie 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































