From 2ea78f5df148e5d6801632e9931ab787aa7a09bf Mon Sep 17 00:00:00 2001 From: lbqds Date: Wed, 30 Aug 2023 10:59:13 +0800 Subject: [PATCH] Add dapp recipes --- docs/dapps/alephium-web3.md | 2 +- docs/dapps/dapp-recipes.md | 215 ++++++++++++++++++++++++++++++++++ docs/dapps/ecosystem.md | 2 +- docs/dapps/public-services.md | 2 +- 4 files changed, 218 insertions(+), 3 deletions(-) create mode 100644 docs/dapps/dapp-recipes.md diff --git a/docs/dapps/alephium-web3.md b/docs/dapps/alephium-web3.md index 9c8e154d..c91ebb5a 100644 --- a/docs/dapps/alephium-web3.md +++ b/docs/dapps/alephium-web3.md @@ -1,5 +1,5 @@ --- -sidebar_position: 30 +sidebar_position: 40 title: Web3 SDK sidebar_label: Web3 SDK --- diff --git a/docs/dapps/dapp-recipes.md b/docs/dapps/dapp-recipes.md new file mode 100644 index 00000000..d33c82b7 --- /dev/null +++ b/docs/dapps/dapp-recipes.md @@ -0,0 +1,215 @@ +--- +sidebar_position: 30 +title: Dapp Recipes +sidebar_label: Dapp Recipes +--- + +import UntranslatedPageText from "@site/src/components/UntranslatedPageText"; + + + +# Contract + +## Fetch contract state + +When using the `npx @alephium/cli compile` command to compile a contract, it will generate TypeScript code based on the contract code. +Taking the [TokenFaucet](https://github.com/alephium/nextjs-template/blob/main/contracts/token.ral) contract as an example, +[here](https://github.com/alephium/nextjs-template/blob/main/artifacts/ts/TokenFaucet.ts) is the generated TypeScript code. +We can use the generated TypeScript code to fetch the contract state: + +```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() + +// The names in `contractState.fields` are the same as the field names in the TokeFaucet contract +const { symbol, name, decimals, supply, balance } = contractState.fields + +// You can also get the assets owned by the contract +const { alphAmount, tokens } = contractState.asset +``` + +## Call contract method + +You can use the generated TypeScript code to call the contract methods, it is similar to the `eth_call` in Ethereum: + +```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() +``` + +## Subscribe to contract events + +In the [TokenFaucet](https://github.com/alephium/nextjs-template/blob/main/contracts/token.ral) contract, +we have defined a [Withdraw](https://github.com/alephium/nextjs-template/blob/c846a675235198045cdf91ba0304aa287f2fc68d/contracts/token.ral#L18) event. +Every time the `withdraw` function is called, the contract will emit a `Withdraw` event. +We can subscribe to the withdraw events using the following approach: + +```typescript +import { TokenFaucet, TokenFaucetTypes } from 'artifacts/ts' +import { EventSubscribeOptions } from '@alephium/web3' + +// `TokenFaucetTypes.WithdrawEvent` is a generated TypeScript type +const options: EventSubscribeOptions = { + // We specify the pollingInterval as 4 seconds, which will query the contract for new events every 4 seconds + pollingInterval: 4000, + // The `messageCallback` will be called every time we recive a new event + messageCallback: (event: TokenFaucetTypes.WithdrawEvent): Promise => { + console.log(`Withdraw(${event.fields.to}, ${event.fields.amount})`) + return Promise.resolve() + }, + // The `errorCallback` will be called when an error occurs, here we unsubscribe the subscription and log the error + errorCallback: (error, subscription): Promise => { + console.error(error) + subscription.unsubscribe() + return Promise.resolve() + }, + // The `onEventCountChanged` callback is an optional parameter that will be called when the contract event count changes + onEventCountChanged: (eventCount): Promise => { + }, +} + +// We subscribe to contract events starting from event count 0. +// We can also persist the current event count within the `onEventCountChanged` callback, +// allowing us to subscribe from the last event count for the next subscription. +const fromEventCount = 0 +const subscription = tokenFaucet.subscribeWithdrawEvent(options, fromEventCount) + +// Unsubscribe the subscription +subscription.unsubscribe() +``` + +# Transaction + +## Query transaction status + +You can query the transaction status using the following approach: + +```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 }) +``` + +You can differentiate the transaction status using the `txStatus.type`: + +1. `MemPooled`: this means the transaction is in the mempool +2. `Confirmed`: the transaction has been confirmed, and you can get the confirmations using `txStatus.chainConfirmations` +3. `TxNotFound`: the transaction does not exist + +# Hooks + +The `@alephium/web3-react` package provides several hooks to facilitate the development of frontend user interfaces. + +## useWallet + +```typescript +import { useWallet, Wallet } from '@alephium/web3-react' + +const wallet: Wallet | undefined = useWallet() +``` + +If the return value is `undefined`, it indicates that the wallet is not connected. The returned wallet has the following fields: + +* `wallet.signer`: you can use the signer to sign transactions +* `wallet.account`: this is the currently connected account +* `wallet.nodeProvider`: you can use the node provider to communicate with the full node, note that this value may be `undefined` + +## useBalance + +```typescript +import { useBalance } from '@alephium/web3-react' + +const { balance, updateBalanceForTx } = useBalance() +``` + +The `useBalance` hook returns two values: + +1. `balance`: the current balance of the connected account +2. `updateBalanceForTx`: this is used to update the balance when the user makes a transaction. It takes a transaction id as a parameter, and it will update the balance once this transaction is confirmed. + +## useTxStatus + +```typescript +import { useState } from 'react' +import { useTxStatus } from '@alephium/web3-react' + +const { txStatus } = useTxStatus(txId) +const confirmed = useMemo(() => { + return txStatus?.type === 'Confirmed' +}, [txStatus]) +``` + +The `useTxStatus` hook also accepts an optional callback parameter of type `(txStatus: node.TxStatus) => Promise`, it will be called after each transaction status query. + +# Utils + +## Rate limit + +`NodeProvider` is used to communicate with the full node when developing a dApp, +and you can use the public [API services](./public-services.md) provided by Alephium. +But all APIs are rate limited to prevent spam. So if the client sends too many requests in a given amount of time, it will receive the HTTP 429 error. + +You can use the [fetch-retry](https://github.com/jonbern/fetch-retry) to solve this issue: + +```typescript +import * as fetchRetry from 'fetch-retry' + +// We specify up to 10 retries, with 1 second retry delay +const retryFetch = fetchRetry.default(fetch, { + retries: 10, + retryDelay: 1000 +}) +const nodeProvider = new NodeProvider('node-url', undefined, retryFetch) +``` + +## Custom wallet connect button + +`@alephium/web3-react` provides the `AlephiumConnectButton` component to facilitate the development of user interfaces, +you can also use the `AlephiumConnectButton.Custom` to customize the style of the connect button: + +```typescript +import { AlephiumConnectButton, useConnect } from '@alephium/web3' + +function CustomWalletConnectButton = () => { + const { disconnect } = useConnect({ + addressGroup: 0, + networkId: 'mainnet' + }) + + return ( + account.address}> + {({ isConnected, show, address }) => { + return isConnected ? ( + + ) : ( + + ) + }} + + ) +} +``` diff --git a/docs/dapps/ecosystem.md b/docs/dapps/ecosystem.md index 579c506b..7fecf9a9 100644 --- a/docs/dapps/ecosystem.md +++ b/docs/dapps/ecosystem.md @@ -1,5 +1,5 @@ --- -sidebar_position: 20 +sidebar_position: 30 title: Ecosystem sidebar_label: Ecosystem --- diff --git a/docs/dapps/public-services.md b/docs/dapps/public-services.md index 39311f21..5ecf9d43 100644 --- a/docs/dapps/public-services.md +++ b/docs/dapps/public-services.md @@ -1,5 +1,5 @@ --- -sidebar_position: 40 +sidebar_position: 50 title: Public Services sidebar_label: Public services ---