Aller au contenu

Recettes de dApp

Portefeuille

Connectez le portefeuille à l'application décentralisée (dApp).

Le package @alephium/web3-react fournit des composants React et des hooks puissants pour connecter un portefeuille à votre dApp.

Connectez le portefeuille
TypeScript
// Alephium Context Provider
<AlephiumWalletProvider theme='retro' network='devnet'>
  <YourComponent />
</AlephiumWalletProvider>

// Bouton de connexion
<AlephiumConnectButton />

// Hook de portefeuille
const { connectionStatus, signer, account } = useWallet()

// Hook de solde
const { balance } = useBalance()

// Hook de connexion utilisé par `<AlephiumConnectButton />` sous le capot
const { connect, disconnect } = useConnect()

Portefeuilles du SDK Web3

Le SDK fournit quelques portefeuilles de base pour les développeurs.

Portefeuille HD/Portefeuille de clé privée
TypeScript
// Portefeuille HD
const mnemonic = bip39.generateMnemonic(128)
const hdWallet = new HDWallet({ mnemonic })

// Portefeuille de clé privée
const wallet0 = new PrivateKeyWallet({ privateKey })
const wallet1 = PrivateKeyWallet.Random()
const wallet2 = PrivateKeyWallet.FromMnemonic({ mnemonic })

Portefeuille de test

La bibliothèque @alephium/web3-test fournit des portefeuilles pratiques à des fins de test.

Portefeuille de test
TypeScript
// Portefeuille de test du devnet, qui a 1 million d'ALPH par défaut
const wallet = testNodeWallet()

// Générer un portefeuille de signature aléatoire pour les tests
const signer = getSigner()

// Générer une liste de portefeuilles aléatoires pour les tests
const signers = getSigners()

Token

Récupérer les métadonnées du jeton fongible

TypeScript
nodeProvider.fetchFungibleTokenMetaData(tokenId)

Récupérer l'offre en circulation / l'offre totale d'un jeton

Le code suivant récupère l'offre totale programmée par le développeur du jeton. Notez que la vérification réelle du contrat est nécessaire pour la fiabilité.

TypeScript
(await nodeProvider.fetchFungibleTokenMetaData(tokenId)).totalSupply

Il n'y a pas de fonction directe pour l'offre en circulation suivant la norme ERC20.

TODO

interroger le montant d'émission du jeton dans le backend de l'explorateur pour fournir des informations plus fiables.

Récupérer les métadonnées du NFT

TypeScript
nodeProvider.fetchNFTMetaData(nftTokenId)

Récupérer les métadonnées de la collection

TypeScript
nodeProvider.fetchNFTCollectionMetaData(nftCollectionId)

Contrat

Récupérer l'état du contrat

Lors de l'utilisation de la commande npx @alephium/cli compile our compiler un contrat, elle générera du code TypeScript basé sur le code du contrat. Prenons l'exemple du contrat TokenFaucet, ici se trouve le code TypeScript généré. Nous pouvons utiliser le code TypeScript généré pour récupérer l'état du contrat :

Token Faucet/Récupérer l'état du contrat
TypeScript
import { TokenFaucet } from 'artifacts/ts' // Note that you may need to change the import path according to your project directory structure
import { web3, NodeProvider } from '@alephium/web3'

const nodeUrl = 'http://127.0.0.1:12973'
const nodeProvider = new NodeProvider(nodeUrl)
web3.setCurrentNodeProvider(nodeProvider)

const tokenFaucetAddress = 'y1btMZHTvMvHEqLTdx1JHvEXq3tmVfqsY2rwM669upiT'
const tokenFaucet = TokenFaucet.at(tokenFaucetAddress)
const contractState = await tokenFaucet.fetchState()

// Les noms dans `contractState.fields` sont les mêmes que les noms de champ dans le contrat TokeFaucet
const { symbol, name, decimals, supply, balance  } = contractState.fields

// Vous pouvez également obtenir les actifs détenus par le contrat
const { alphAmount, tokens } = contractState.asset

Appeler une méthode de contrat

Vous pouvez utiliser le code TypeScript généré pour appeler les méthodes du contrat, c'est similaire à eth_call dans Ethereum :

Token Faucet/Appeler une méthode de contrat
TypeScript
import { TokenFaucet } from 'artifacts/ts'
import { web3, NodeProvider } from '@alephium/web3'

const nodeUrl = 'http://127.0.0.1:12973'
const nodeProvider = new NodeProvider(nodeUrl)
web3.setCurrentNodeProvider(nodeProvider)

const tokenFaucetAddress = 'y1btMZHTvMvHEqLTdx1JHvEXq3tmVfqsY2rwM669upiT'
const tokenFaucet = TokenFaucet.at(tokenFaucetAddress)
const totalSupply = await tokenFaucet.methods.getTotalSupply()

S'abonner aux événements du contrat

Dans le contrat TokenFaucet, nous avons défini un événement Withdraw. Chaque fois que la fonction withdraw est appelée, le contrat émettra un événement Withdraw. Nous pouvons nous abonner aux événements de retrait en utilisant l'approche suivante:

token.ral
TypeScript
import { TokenFaucet, TokenFaucetTypes } from 'artifacts/ts'
import { EventSubscribeOptions } from '@alephium/web3'

// `TokenFaucetTypes.WithdrawEvent` est un type TypeScript généré
const options: EventSubscribeOptions<TokenFaucetTypes.WithdrawEvent> = {
  // Nous spécifions l'intervalle de sondage à 4 secondes, ce qui interrogera le contrat pour de nouveaux événements toutes les 4 secondes
  pollingInterval: 4000,
  // Le `messageCallback` sera appelé chaque fois que nous recevons un nouvel événement
  messageCallback: (event: TokenFaucetTypes.WithdrawEvent): Promise<void> => {
    console.log(`Withdraw(${event.fields.to}, ${event.fields.amount})`)
    return Promise.resolve()
  },
  // Le `errorCallback` sera appelé en cas d'erreur, ici nous désabonnons l'abonnement et journalisons l'erreur
  errorCallback: (error, subscription): Promise<void> => {
    console.error(error)
    subscription.unsubscribe()
    return Promise.resolve()
  },
  // Le rappel `onEventCountChanged` est un paramètre facultatif qui sera appelé lorsque le nombre d'événements du contrat change
  onEventCountChanged: (eventCount): Promise<void> => {
  },
}

// Nous nous abonnons aux événements de contrat à partir du nombre d'événements 0.
// Nous pouvons également persister le nombre d'événements actuel dans le rappel `onEventCountChanged`,
// nous permettant de nous abonner depuis le dernier nombre d'événements pour l'abonnement suivant.
const fromEventCount = 0
const subscription = tokenFaucet.subscribeWithdrawEvent(options, fromEventCount)

// Désabonner l'abonnement
subscription.unsubscribe()

Fonctions de test avec temps de bloc simulé

Il est possible de tester les fonctions avec un temps de bloc simulé dans les tests unitaires. Pour les tests d'intégration basés sur le testnet ou le devnet, il n'y a cependant aucun moyen de changer le temps de bloc.

Voici un exemple simple:

Token Faucet
TypeScript
import { TokenFaucet } from 'artifacts/ts'

const result = await TokenFaucet.tests.withdraw({
  blockTimeStamp: 1706284941000, // l'unité est la milliseconde
  address: ...,
  initialFields: ...,
  ...
})

Enregistrer des messages de débogage

Ralph prend en charge les messages de débogage en émettant l'événement intégré Debug. Notez que de tels événements sont ignorés sur le mainnet.

Contrat Ralph simple
TypeScript
// Contrat Ralph simple
Contract Debug() {
    pub fn debug() -> () {
        emit Debug(`Hello, ${nullContractAddress!()}!`)
    }
}

// Test unitaire en TypeScript
const result = await Debug.tests.debug()

// La ligne suivante apparaîtra dans la sortie de la console et dans les journaux du nœud complet:
//   Debug - tgx7VNFoP9DJiFMFgXXtafQZkUvyEdDHT9ryamHJYrjq - Bonjour, tgx7VNFoP9DJiFMFgXXtafQZkUvyEdDHT9ryamHJYrjq!

// Récupérer tous les messages de débogage
console.log(result.debugMessages)

Transaction

Interroger le statut de la transaction

Vous pouvez interroger le statut de la transaction en utilisant l'approche suivante:

NodeProvider
TypeScript
import { NodeProvider } from '@alephium/web3'

const nodeUrl = 'http://127.0.0.1:12973'
const nodeProvider = new NodeProvider(nodeUrl)

const txId = '919d4e4b1080d74beb56a1f78ea7c0569a358e3ea3988058987cc1addf4b93cc'
const txStatus = await nodeProvider.transactions.getTransactionsStatus({ txId })

Vous pouvez différencier le statut de la transaction en utilisant txStatus.type:

  1. MemPooled: cela signifie que la transaction se trouve dans le mempool
  2. Confirmed: la transaction a été confirmée, et vous pouvez obtenir les confirmations en utilisant txStatus.chainConfirmations
  3. TxNotFound: la transaction n'existe pas

Hooks

Le package @alephium/web3-react fournit plusieurs hooks pour faciliter le développement des interfaces utilisateur frontend.

useWalletConfig

useWalletConfig
TypeScript
import { useWalletConfig } from '@alephium/web3-react'

export function Component() {
  const { network, setNetwork, addressGroup, setAddressGroup } = useWalletConfig()

  return <div>
    <button onClick={() => setNetwork('testnet')}>Network: {network}</button>
    <button onClick={() => setAddressGroup(3)}>Address group: {addressGroup}</button>
  </div>
}

Le hook useWalletConfig renvoie les configurations du bouton de connexion et des fonctions utilitaires pour mettre à jour ces configurations.

useWallet

useWallet
TypeScript
import { useWallet, Wallet } from '@alephium/web3-react'

function Component() {
  const { account, connectionStatus } = useWallet()

  if (connectionStatus === 'connecting') return <div>Connecting</div>
  if (connectionStatus === 'disconnected') return <div>Disconnected</div>

  // connecté
  return <div>{account}</div>
}

Si la valeur de retour est undefined, cela indique que le portefeuille n'est pas connecté. Le portefeuille renvoyé a les champs suivants:

  • wallet.signer: vous pouvez utiliser le signataire pour signer des transactions
  • wallet.account: il s'agit du compte actuellement connecté
  • wallet.nodeProvider: vous pouvez utiliser le fournisseur de nœuds pour communiquer avec le nœud complet, notez que cette valeur peut être undefined

useBalance

useBalance
TypeScript
import { useBalance } from '@alephium/web3-react'

const { balance, updateBalanceForTx } = useBalance()

Le hook useBalance renvoie deux valeurs:

  1. balance: le solde actuel du compte connecté
  2. updateBalanceForTx: cela est utilisé pour mettre à jour le solde lorsque l'utilisateur effectue une transaction. Il prend un identifiant de transaction en paramètre, et il mettra à jour le solde une fois cette transaction confirmée.

useTxStatus

useTxStatus
TypeScript
import { useState } from 'react'
import { useTxStatus } from '@alephium/web3-react'

const { txStatus } = useTxStatus(txId)
const confirmed = useMemo(() => {
  return txStatus?.type === 'Confirmed'
}, [txStatus])

Le hook useTxStatus accepte également un paramètre de rappel optionnel de type (txStatus: node.TxStatus) => Promise<any>, il sera appelé après chaque requête de statut de transaction.


Utilitaires

Limitation du taux

NodeProvider est utilisé pour communiquer avec le nœud complet lors du développement d'une dApp, et vous pouvez utiliser les API services fournis par Alephium. Mais tous les API sont limités en termes de taux pour éviter le spam. Donc, si le client envoie trop de requêtes dans un laps de temps donné, il recevra l'erreur HTTP 429.

Vous pouvez utiliser le fetch-retry pour résoudre ce problème :

fetchRetry
TypeScript
import * as fetchRetry from 'fetch-retry'

// Nous spécifions jusqu'à 10 nouvelles tentatives, avec un délai de 1 seconde entre chaque tentative.
const retryFetch = fetchRetry.default(fetch, {
  retries: 10,
  retryDelay: 1000
})
const nodeProvider = new NodeProvider('node-url', undefined, retryFetch)

Bouton de connexion personnalisé

@alephium/web3-react fournit le composant AlephiumConnectButton pour faciliter le développement des interfaces utilisateur, vous pouvez également utiliser AlephiumConnectButton.Custom pour personnaliser le style du bouton de connexion:

Alephium Bouton de connexion
TypeScript
import { AlephiumConnectButton } from '@alephium/web3'

function CustomWalletConnectButton = () => {
  return (
    <AlephiumConnectButton.Custom>
      {({ isConnected, disconnect, show, account }) => {
        return isConnected ? (
          <button onClick={disconnect}>
            Disconnect
          </button>
        ) : (
          <button onClick={show}>
            Connect
          </button>
        )
      }}
    </AlephiumConnectButton.Custom>
  )
}