# dAppBooster > A modern starter kit built with React to quickly get started with your next web3 project. ## Building your first dApp \[Wrapping and Unwrapping WETH] ### Introduction :::warning **Initial setup** Before continuing, be sure to have followed the steps in [getting started](/introduction/installation) ::: This guide will walk you through developing your first dApp using dappBooster. You'll learn how to create a simple dApp that enables users to wrap and unwrap WETH (in less than five minutes). ### Network configuration The Sepolia network is pre-configured in [src/lib/networks.config.ts](https://github.com/BootNodeDev/dAppBooster/blob/develop/src/lib/networks.config.ts). Review this file if you're interested in adding more networks by following the existing pattern. ### Contract configuration For this example, we have already deployed a smart contract to the Sepolia network. Now it's time to let the dApp know about it existence: :::steps #### ABI download Download the [ABI](https://sepolia.etherscan.io/address/0xa45f5716cab1a49b107a5de96ec26da26d1eba9e#code) and save it in `src/constants/contracts/abis/WETH.ts` using the following format: ```tsx [WETH.ts] showLineNumbers export const WETH_ABI = [ // ...abi code ] as const ``` #### Contracts update Update `src/constants/contracts/contracts.ts` with the WETH contract address and ABI: ```tsx [contracts.ts] showLineNumbers import { WETH_ABI } from '@/src/constants/contracts/abis/WETH' export const contracts = { // ... { abi: WETH_ABI, name: 'WETH', address: { [sepolia.id]: '0xa45f5716cab1a49b107a5de96ec26da26d1eba9e', }, }, } ``` ::: ### Generate the hooks Use the wagmi utility to generate React hooks for the WETH contract. We have [configured](https://github.com/BootNodeDev/dAppBooster/blob/develop/src/lib/wagmi/config.ts) wagmi to generate hooks with both suspense and promised hooks. ```bash [Terminal] pnpm wagmi-generate ``` ### Create the page :::steps #### Add a new route Create a new file `/src/routes/weth.lazy.tsx` with the following content: ```tsx [weth.lazy.tsx] showLineNumbers import { createLazyFileRoute } from '@tanstack/react-router' import { Weth } from '@/src/components/pageComponents/weth' export const Route = createLazyFileRoute('/weth')({ component: Weth, }) ``` With this file we are registering a new page under the path `/weth`. #### Create the component * Create a new folder `src/components/pageComponents/weth` * Create `src/components/pageComponents/weth/index.tsx` with this content: ```tsx [index.tsx] showLineNumbers import { Card } from '@chakra-ui/react' export const Weth = () => { return (Hello User! } ``` ::: This is just a simple component that we will use to add all the WETH logic. You can see the new page and component in action in [http://localhost:5173/weth](http://localhost:5173/weth) ### Add a custom token list dappBooster has a set of components and utilities designed to simplify the integration of tokens while following the standard defined by [tokenlists.org](https://tokenlists.org/). As we're working with a home-made WETH token, we will create a custom token link where the only token it holds is our WETH token. Let's add it to our dApp: :::steps #### Create the tokens file Create `public/tokens.json` with the following content: ```json [tokens.json] showLineNumbers { "name": "custom", "tokens": [ { "address": "0xa45f5716cab1a49b107a5de96ec26da26d1eba9e", "chainId": 11155111, "name": "WETH", "symbol": "WETH", "decimals": 18, "logoURI": "https://assets.coingecko.com/coins/images/2518/thumb/weth.png?1696503332" } ] } ``` #### Add the tokens list Add the new tokens list to `src/constants/tokenLists.ts` like so: ```tsx [tokenLists.ts] showLineNumbers { // ... CUSTOM: '/tokens.json', } ``` ::: Now, all the token related utilities will make use of this new list. :::info **Get the tokens** Use the [useTokenLists](https://github.com/BootNodeDev/dAppBooster/blob/develop/src/hooks/useTokenLists.ts) hook it to obtain all the tokens configured. ::: ### The TokenInput component We will use the [TokenInput](https://github.com/BootNodeDev/dAppBooster/blob/develop/src/components/sharedComponents/TokenInput/index.tsx) component. This component has this useful features: * Show the user the token they are interacting with (ETH when wrapping and WETH when unwrapping). * It will allow the user to enter the token amount in decimal format and will return the parsed amount in wei. * It will fetch the selected token's balance. * It will notify the user of any issues found with the input value entered. Let's modify the `/src/components/pageComponents/weth/index.tsx` file as follows: ```tsx [index.tsx] showLineNumbers import { Card } from '@chakra-ui/react' import { sepolia } from 'viem/chains' import TokenInput from '@/src/components/sharedComponents/TokenInput' import { useTokenInput } from '@/src/components/sharedComponents/TokenInput/useTokenInput' import { getContract } from '@/src/constants/contracts/contracts' import { env } from '@/src/env' import { useTokenLists } from '@/src/hooks/useTokenLists' export const Weth = () => { // get the list of tokens. const { tokensByChainId } = useTokenLists() // helper that give us information given a contract name. const weth = getContract('WETH', sepolia.id) // get the tokens from the token list we need to use. const wethToken = tokensByChainId[sepolia.id].find((token) => token.address === weth.address) const ethToken = tokensByChainId[sepolia.id].find( (token) => token.address === env.PUBLIC_NATIVE_TOKEN_ADDRESS, ) if (!wethToken) throw new Error('WETH token not found') if (!ethToken) throw new Error('ETH token not found') // hook that gives us the state that needs. const tokenInput = useTokenInput(ethToken) return (

WETH EXAMPLE

) } ``` Now, you should see the `TokenInput` component in action. Connect a wallet with a Sepolia ETH balance, and the component will display it. ### Suspense loading As you might have noticed, after the page is loaded the component will take some time before appearing. This is happening because dappBooster makes use of [Suspense](https://react.dev/reference/react/Suspense) for some internal requests. To improve the UX we can show a spinner or skeleton loadin component until the component is ready to be rendered. We'll use a utility function called `withSuspenseAndRetry` to wrap our `Weth` component, and indicate that while the component is fetching data, we want to render a "loading..." text: ```tsx [index.tsx] showLineNumbers import { withSuspenseAndRetry } from '@/src/utils/suspenseWrapper' export const SuspendedWeth = withSuspenseAndRetry(() => { // ... }) export const Weth = () => ( Loading...} /> ) ``` ### Wallet status & contract interaction Now it's time to develop the functionality for deposit and withdrawal. We will consume different hooks that will take care of triggering the transactions for deposit, approve and withdraw. Also, we will make use of another special hook [useWeb3Status()](https://github.com/BootNodeDev/dAppBooster/blob/develop/src/hooks/useWeb3Status.tsx) provided by dappBooster. This hook will return important information of the context of the connected wallet and selected chain. ```tsx [index.tsx] showLineNumbers import { Card } from '@chakra-ui/react' import { Address } from 'viem' import { sepolia } from 'viem/chains' import TokenInput from '@/src/components/sharedComponents/TokenInput' import { useTokenInput } from '@/src/components/sharedComponents/TokenInput/useTokenInput' import { getContract } from '@/src/constants/contracts/contracts' import { env } from '@/src/env' import { // [!code focus] useReadWethAllowance, // [!code focus] useWriteWethApprove, // [!code focus] useWriteWethDeposit, // [!code focus] useWriteWethWithdraw, // [!code focus] } from '@/src/hooks/generated' // [!code focus] import { useTokenLists } from '@/src/hooks/useTokenLists' import { useWeb3Status } from '@/src/hooks/useWeb3Status' // [!code focus] import { withSuspenseAndRetry } from '@/src/utils/suspenseWrapper' export const SuspendedWeth = withSuspenseAndRetry(() => { // get the list of tokens. const { tokensByChainId } = useTokenLists() // helper that give us information given a contract name. const weth = getContract('WETH', sepolia.id) // get the tokens from the token list we need to use. const wethToken = tokensByChainId[sepolia.id].find((token) => token.address === weth.address) const ethToken = tokensByChainId[sepolia.id].find( (token) => token.address === env.PUBLIC_NATIVE_TOKEN_ADDRESS, ) if (!wethToken) throw new Error('WETH token not found') if (!ethToken) throw new Error('ETH token not found') // hook that gives us the state that needs. const tokenInput = useTokenInput(ethToken) // status of the Web3 connection. // [!code focus] const { address } = useWeb3Status() // [!code focus] // contracts calls // [!code focus] const { writeContractAsync: wethDeposit } = useWriteWethDeposit() // [!code focus] const { writeContractAsync: wethApprove } = useWriteWethApprove() // [!code focus] const { writeContractAsync: wethWithdraw } = useWriteWethWithdraw() // [!code focus] // contracts reads // [!code focus] const wethAllowance = useReadWethAllowance({ // [!code focus] args: [address as Address, weth.address], // [!code focus] query: { // [!code focus] enabled: !!address, // [!code focus] }, // [!code focus] }) // [!code focus] return (

WETH EXAMPLE

) }) export const Weth = () => ( Loading...} /> ) ``` ### Deposit, approve and withdraw After the user enters a valid value, we need a button to trigger one of the possible actions. We will make use of the [TransactionButton](https://github.com/BootNodeDev/dAppBooster/blob/develop/src/components/sharedComponents/TransactionButton.tsx) component to handle the transaction lifecycle. We will only pass two properties `transaction`, which receives a function returning a promise with a transaction hash, and `onMined` where we will refetch the user balance once the transaction has been mined. ```tsx [index.tsx] showLineNumbers import { ChangeEvent, useState } from 'react' // [!code focus] import { Card } from '@chakra-ui/react' import { Address } from 'viem' // [!code focus] import { sepolia } from 'viem/chains' import TokenInput from '@/src/components/sharedComponents/TokenInput' import { useTokenInput } from '@/src/components/sharedComponents/TokenInput/useTokenInput' import TransactionButton from '@/src/components/sharedComponents/TransactionButton' // [!code focus] import { getContract } from '@/src/constants/contracts/contracts' import { env } from '@/src/env' import { useReadWethAllowance, useWriteWethApprove, useWriteWethDeposit, useWriteWethWithdraw, } from '@/src/hooks/generated' import { useTokenLists } from '@/src/hooks/useTokenLists' import { useWeb3Status } from '@/src/hooks/useWeb3Status' import { withSuspenseAndRetry } from '@/src/utils/suspenseWrapper' type Operation = 'Deposit' | 'Withdraw' // [!code focus] export const SuspendedWeth = withSuspenseAndRetry(() => { const [operation, setOperation] = useState('Deposit') // [!code focus] // get the list of tokens. const { tokensByChainId } = useTokenLists() // helper that give us information given a contract name. const weth = getContract('WETH', sepolia.id) // get the tokens from the token list we need to use. const wethToken = tokensByChainId[sepolia.id].find((token) => token.address === weth.address) const ethToken = tokensByChainId[sepolia.id].find( (token) => token.address === env.PUBLIC_NATIVE_TOKEN_ADDRESS, ) if (!wethToken) throw new Error('WETH token not found') if (!ethToken) throw new Error('ETH token not found') // hook that gives us the state that needs. const tokenInput = useTokenInput(ethToken) // status of the Web3 connection. const { address } = useWeb3Status() // contracts calls const { writeContractAsync: wethDeposit } = useWriteWethDeposit() const { writeContractAsync: wethApprove } = useWriteWethApprove() const { writeContractAsync: wethWithdraw } = useWriteWethWithdraw() // contracts reads const wethAllowance = useReadWethAllowance({ args: [address as Address, weth.address], query: { enabled: !!address, }, }) const sendOperation = async () => { // [!code focus] if (operation == 'Deposit') { // [!code focus] const res = await wethDeposit({ value: tokenInput.amount }) // [!code focus] return res // [!code focus] } else if (tokenInput.amount > (wethAllowance.data || 0n)) { // [!code focus] const res = await wethApprove({ args: [weth.address, tokenInput.amount] }) // [!code focus] return res // [!code focus] } else { // [!code focus] const res = await wethWithdraw({ args: [tokenInput.amount] }) // [!code focus] return res // [!code focus] } // [!code focus] } // [!code focus] // giving context to the toast // [!code focus] sendOperation.methodId = `WETH:${operation}` // [!code focus] if (operation === 'Withdraw' && tokenInput.amount > (wethAllowance.data || 0n)) { // [!code focus] sendOperation.methodId = `WETH:Approve` // [!code focus] } // [!code focus] const getActionText = () => { // [!code focus] if (operation === 'Withdraw' && tokenInput.amount > (wethAllowance.data || 0n)) { // [!code focus] return 'Approve' // [!code focus] } // [!code focus] return operation // [!code focus] } const handleOperation = (e: ChangeEvent) => { // [!code focus] const newValue = e.target.value as Operation // [!code focus] tokenInput.setTokenSelected(newValue === 'Deposit' ? ethToken : wethToken) // [!code focus] setOperation(e.target.value as Operation) // [!code focus] } // [!code focus] return (

WETH EXAMPLE


// [!code focus]
// [!code focus]
// [!code focus] Operation{' '} // [!code focus] // [!code focus]
// [!code focus]
// [!code focus]
// [!code focus] wethAllowance.refetch()} // [!code focus] transaction={sendOperation} // [!code focus] > // [!code focus] {getActionText()} // [!code focus] // [!code focus]
// [!code focus] ) }) export const Weth = () => ( Loading...} /> ) ``` :::info **Giving meaningful information** The `sendOperation.methodId` is used to provide additional context to the toast notification displayed by the `TransactionButton`. This is optional, but if you include a `methodId` property in the function passed to the transaction property, it will display that context in the toast, offering the user more detailed information. ::: ## Subgraphs :::warning **Initial setup** Before continuing, be sure to have followed the steps in the [Subgraphs Plugin](/advanced/subgraph-plugin) section. ::: This guide will walk you through the use of the [subgraphs plugin](https://www.npmjs.com/package/@bootnodedev/db-subgraph) in dAppBooster. We'll implement the consumption of data from the [Polygon (137) Uniswap pools](https://app.uniswap.org/explore/pools/polygon) query. ### Consume the Subgraph :::steps #### Create the query To create a query to list Uniswap pools by liquidity first create a new file `src/subgraphs/queries/uniswap/pool.ts` with the following content: ```ts [pool.ts] showLineNumbers import { graphql } from '@/src/subgraphs/gql/uniswap' export const allUniswapPoolsQueryDocument = graphql(/* GraphQL */ ` query allUniswapPools { positions(first: 3, orderBy: liquidityUSD, orderDirection: asc) { id pool { id symbol } } } `) ``` #### Run the code generation script ```bash [Terminal] pnpm subgraph-codegen ``` This will consume the query you just created, poll the information from [The Graph](https://thegraph.com/) services and create the types for you. #### Create a component Create a new component to consume the data in `src/components/sharedComponents/UniswapPoolsPolygon.tsx`. We'll use it to show the pool's data. ```tsx [UniswapPoolsPolygon.tsx] showLineNumbers import { generateSchemasMapping } from '@bootnodedev/db-subgraph' import { useSuspenseQuery } from '@tanstack/react-query' import { env } from '@/src/env' import { withSuspenseAndRetry } from '@/src/utils/suspenseWrapper' const appSchemas = generateSchemasMapping({ apiKey: env.PUBLIC_SUBGRAPHS_API_KEY!, chainsResourceIds: env.PUBLIC_SUBGRAPHS_CHAINS_RESOURCE_IDS!, environment: env.PUBLIC_SUBGRAPHS_ENVIRONMENT, productionUrl: env.PUBLIC_SUBGRAPHS_PRODUCTION_URL, }) export const UniswapPoolsPolygon = withSuspenseAndRetry(() => { const { data } = useSuspenseQuery({ queryKey: ['allUniswapPools', 137], queryFn: async () => { const { positions } = await request( appSchemas.uniswap[137], allUniswapPoolsQueryDocument, ) return positions }, }) return (

Uniswap Pool {getNetworkIcon(chain.name.toLowerCase())}

{data.map((position) => ( {position.pool.symbol} ))}
) }) ``` Now you can use this component to show this data to the user in any place you want. ::: :::info **Working demo source code** You can find a working example of this feature in our [demos list](https://github.com/BootNodeDev/dAppBooster/blob/main/src/components/pageComponents/home/Examples/demos/subgraphs/Subgraph/index.tsx) ::: ## Installation \[Getting started with dAppBooster in just a few minutes] ### dAppBooster's installation script :::info **Requirements** * Node v20+ from [https://nodejs.org/](https://nodejs.org/) * pnpm from [https://pnpm.io/](https://pnpm.io/) * For Windows users the tested and recommended way is using [WSL](https://learn.microsoft.com/en-us/windows/wsl/install). There are no guarantees that using `bash` or other terminals will work. ::: :::steps #### Run the script Get a clean instance of the starter-kit by running this command. You can select between several configuration options for your installation, remove optional packages, etc. Choose what you need for your particular project. ```bash [Terminal] pnpm dlx dappbooster ``` #### Change the remote (optional) After you're finished with the installation, you might want to change your project's remote repository to a different one. ```bash [Terminal] git remote set-url origin ``` #### Running the dApp To run the dApp in dev mode use this command and open the link provided in your browser. ```bash [Terminal] pnpm dev ``` You can start modifying the content of the home page by editing `src/components/pageComponents/home/index.tsx`, the page auto-updates as you edit the file. ::: :::info **Additional configuration** Check `.env.local` and `.env.example` for additional configurations, most vars are self-explanatory. ::: ### A note regarding subgraphs There are no additional configuration requirements for the most part but **if you opted-in for subgraph support**, you'll need to provide the required environment vars in `.env.local` for the subgraph features to work. :::warning **Values for the mandatory subgraph env vars** You can use the default values from most of the vars you'll find in our `.env.example` file, but **you have to provide your own subgraph API key** (otherwise the dApp will not work). You can get one at [https://thegraph.com/studio/apikeys/](https://thegraph.com/studio/apikeys/) ::: ```sh [.env.local] # Subgraph API key PUBLIC_SUBGRAPHS_API_KEY='Your API key' # Environment PUBLIC_SUBGRAPHS_ENVIRONMENT='production' # comma separated list of :: PUBLIC_SUBGRAPHS_CHAINS_RESOURCE_IDS='' # URLs for the subgraphs in development and production # must have the replaceable strings [apiKey], [resourceId], and optionally [subgraphId] PUBLIC_SUBGRAPHS_DEVELOPMENT_URL='' PUBLIC_SUBGRAPHS_PRODUCTION_URL='' ``` :::warning **Code generation** After you added your API key and the other subgraph variables, don't forget to run the code generator. ::: ```bash [Terminal] pnpm subgraph-codegen ``` :::info **More about subgraphs** Read more about using subgraphs in the [subraph recipe](/recipes/subgraphs) and [subgraph plugin](/advanced/subgraph-plugin) sections. ::: ### Warming engines And that's it! We recommend starting with the [My first dApp recipe](/recipes/my-first-dapp) to see how easy it is to build a dApp with our starter kit. In just five minutes, this guide will show you how to create a dApp that lets you wrap and unwrap WETH on the Sepolia network. This hands-on introduction is an excellent first step to using dappBooster and getting familiar with its components. ## Introduction \[This section is a work in progress] :::warning **WiP** We are working on improving the documentation and adding more content. ::: You can refer to the [components technical documentation](https://bootnodedev.github.io/dAppBooster/) for more information and examples. ### Basic folder structure * `src/`: Source code * `components/`: Reusable components * `components/sharedComponents`: Components shared across multiple pages * `components/pageComponents`: Components specific to a page * `routes/`: TanStack Router routes ## Manual Installation ### Overview In case the installation script doesn't fit your needs these are the steps to perform a manual installation. It's also the recommended procedure in case you're a **dAppBooster** developer. ::::steps #### Clone the repo ```bash [Terminal] git clone git@github.com:BootNodeDev/dAppBooster.git dAppName ``` #### Move into the folder ```bash [Terminal] cd dAppName ``` #### Branch checkout The default branch is `develop`, which is fine if you're developing new features or fixing bugs, but if you're developing a new product you probably want to checkout the production-ready `main` branch: ```bash [Terminal] git checkout main ``` Or you can get the last tag (usually, but not always, in sync with `main`), which is what the install script does. ```bash [Terminal] # fetch tags git fetch --tags # get the last tag git checkout $(git describe --tags `git rev-list --tags --max-count=1`) # create a new branch from the tag git checkout -b new-branch ``` #### Create the .env file Now move into the project's folder and create a `.env.local` file. ```bash [Terminal] cd dAppBooster cp .env.example .env.local ``` #### Install the dependencies ```bash [Terminal] pnpm i ``` This will install **everything** by default, so you'll have to configure and run a few things to get your app running: most importantly, you **have to add a subgraph [API key](https://thegraph.com/studio/apikeys/)**, provide all the subgraph-related env vars and then run the code generator. Otherwise the app will not work. Check [this section](/introduction/installation#a-note-regarding-subgraphs) for extra info about configuring subgraphs and running the code generator. :::tip **Uninstalling subgraph support** Optionally you can uninstall everything subgraph related, check the [info below](#subgraphs) to see how. ::: #### Run the app Now you can run the dApp in dev mode and open the link provided by this command in the browser. ```bash [Terminal] pnpm dev ``` :::: ### Optional packages There are plenty of optional packages you can remove (tip: the installation script does this for you). We think these are useful and make for a better result and developer experience, but you might think different. Keep reading if you want to remove some or all of these packages. #### Subgraphs If you don't need subgraph support, remove these packages: ```bash [Terminal] pnpm remove @bootnodedev/db-subgraph graphql graphql-request @graphql-codegen/cli @graphql-typed-document-node/core ``` Also consider removing the related files and folders: `src/subgraph`, `src/components/pageComponents/home/Examples/demos/subgraphs` and the references in `/src/components/pageComponents/home/Examples/index.tsx` Finally remove the subgraph-related scripts from `package.json` #### Typedoc If you don't need [Typedoc](https://typedoc.org/): ```bash [Terminal] pnpm remove typedoc typedoc-github-theme typedoc-plugin-inline-sources typedoc-plugin-missing-exports typedoc-plugin-rename-defaults ``` And remove the `typedoc.json` file, `typedoc` folder, and related scripts from `package.json` #### Vocs If you don't need [Vocs](https://vocs.dev/): ```bash [Terminal] pnpm remove vocs ``` And remove the `vocs.config.ts` file, `docs` folder, and related scripts from `package.json` #### Husky If you don't need [Husky](https://typicode.github.io/husky/): ```bash [Terminal] pnpm remove husky ``` And remove the `.husky` folder and related scripts from `package.json` :::warning **Git hooks** [commitlint](https://commitlint.js.org/) and [lint-staged](https://github.com/lint-staged/lint-staged) are run by Husky's Git hooks, so you might consider removing them. You can run the scripts manually if you prefer to keep the packages, though. ::: ```bash [Terminal] pnpm remove @commitlint/cli @commitlint/config-conventional lint-staged ``` #### Biome If you don't need [Biome](https://biomejs.dev/): ```bash [Terminal] pnpm remove @biomejs/biome ``` And remove the `biome.json` file and related scripts from `package.json` #### Vercel analytics If you don't need [Vercel analytics](https://vercel.com/docs/analytics/quickstart): ```bash [Terminal] pnpm remove @vercel/analytics ``` And remove the `Analytics` import and tag in `src/routes/__root.tsx` #### Testing If you don't need automated testing: ```bash [Terminal] pnpm remove vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event @vitest/coverage-v8 ``` And remove the `setupTests.ts` file, all the `*.test.tsx` and `*.test.ts` files, and related scripts from `package.json` #### Sitemap If you don't need a sitemap: ```bash [Terminal] pnpm remove vite-plugin-sitemap ``` And remove all references from `vite.config.ts` #### Installation script Remove the `.install-files` folder. ## Networks ### Importing a network To add / remove / edit a network supported by the dApp you can do it directly in the `networks.config.ts` file. :::steps #### Import network Import the supported network of your choice, say [Base](https://www.base.org/). ```diff [networks.config.ts] - import { mainnet, optimismSepolia, sepolia } from 'viem/chains' + import { base, mainnet, optimismSepolia, sepolia } from 'viem/chains' ... - export const chains = [mainnet, optimismSepolia, sepolia] as const + export const chains = [base, mainnet, optimismSepolia, sepolia] as const ``` #### Include it in the transports Use the default RPC provided by [wagmi](https://wagmi.sh/) / [Viem](https://viem.sh/) to include it in the transports. ```diff [networks.config.ts] export const transports: RestrictedTransports = { ... + [base.id]: http(env.PUBLIC_RPC_BASE), } ``` ::: ### Specifying the RPC If you want to use an RPC different from the one provided by wagmi :::steps #### Define the env variable ```diff [.env.local] + PUBLIC_RPC_BASE=https://base.llamarpc.com ``` #### Import Import the RPC in the `src/env.ts` file ```diff [env.ts] export const env = createEnv({ client: { ... + PUBLIC_RPC_BASE: z.string().optional(), }, }) ``` ::: :::warning **Unspecified RPC** If the RPC is not specified, it will be `undefined` and the app will use the wagmi-defined RPC. ::: ## Tech Stack :::note **Overview** dAppBooster provides a minimal setup to get React working in Vite with HMR and some linting. It uses [SWC](https://swc.rs/) for fast refresh. ::: * Vite: [https://vitejs.dev/](https://vitejs.dev/) * React SWC: [https://github.com/vitejs/vite-plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) * TanStack * React Query: [https://tanstack.com/query/latest](https://tanstack.com/query/latest) * React Virtual: [https://tanstack.com/virtual/latest](https://tanstack.com/virtual/latest) * React Router: [https://tanstack.com/router/latest](https://tanstack.com/router/latest) * Dev tools: not visible in production. * Switch between several libraries for wallet connection * Connectkit: [Official docs](https://docs.family.co/connectkit/getting-started) | [Setup file](https://github.com/BootNodeDev/dAppBooster/blob/main/src/lib/wallets/connectkit.config.tsx) * Rainbowkit: [Official docs](https://www.rainbowkit.com/docs/installation) | [Setup file](https://github.com/BootNodeDev/dAppBooster/blob/main/src/lib/wallets/rainbowkit.config.tsx) * Web3modal: [Official docs](https://docs.walletconnect.com/web3modal/react/about#implementation) | [Setup file](https://github.com/BootNodeDev/dAppBooster/blob/main/src/lib/wallets/web3modal.config.tsx) * Conedison: [Github repository](https://github.com/Uniswap/conedison) | [`numberFormat.ts`](https://github.com/BootNodeDev/dAppBooster/blob/main/src/utils/numberFormat.ts) * Chakra UI: [https://www.chakra-ui.com/](https://www.chakra-ui.com/) * Vercel Web Analytics: [https://vercel.com/docs/analytics](https://vercel.com/docs/analytics) * Porto SDK: [https://porto.sh/sdk/api/porto/create](https://porto.sh/sdk/api/porto/create) | [`portoInit.ts`](https://github.com/BootNodeDev/dAppBooster/blob/main/src/lib/wallets/portoInit.ts) ## dAppBooster Subgraph Plugin This package provides a flexible and reusable solution for generating [GraphQL](https://graphql.org/) clients using `@graphql-codegen/cli`, integrated with `@tanstack/react-query`. It simplifies the process of setting up and managing GraphQL code generation for multiple subgraphs. ### Installation :::warning **Package managers** The plugin uses pnpm as the preferred package manager. ::: First, install the package along with all the required dependencies: ```bash [Terminal] pnpm add @bootnodedev/db-subgraph graphql graphql-request ``` Then, add the development dependencies: ```bash [Terminal] pnpm add -D @graphql-codegen/cli @graphql-typed-document-node/core ``` ### Usage ::::steps #### Set up the configuration Create a `src/subgraphs/codegen.ts` code generation file in your project: ```ts [codegen.ts] showLineNumbers import { generateCodegenConfig } from "@bootnodedev/db-subgraph"; import { loadEnv } from "vite"; const env = loadEnv("subgraphs", process.cwd(), ""); export default generateCodegenConfig({ subgraphs: [ { apiKey: env.PUBLIC_SUBGRAPHS_API_KEY, chainsResourceIds: env.PUBLIC_SUBGRAPHS_CHAINS_RESOURCE_IDS, environment: "production", productionUrl: env.PUBLIC_SUBGRAPHS_PRODUCTION_URL, }, ], }); ``` :::tip **Configuration values** You can use environment variables, hard-coded values, or a combination of both. Adjust the configuration according to your project's needs. ::: This file uses the `generateCodegenConfig` function from our package to create the configuration for `@graphql-codegen/cli` #### Run the code generation Add a script to your `package.json` to run the code generation: ```json [package.json] { "scripts": { "subgraph-codegen": "graphql-codegen --config ./src/subgraphs/codegen.ts" // [!code ++] } } ``` Now generate your GraphQL clients by running: ```bash [Terminal] pnpm run subgraph-codegen ``` :::: You can see a live example [here](https://dappbooster.dev/) and the source code of the demos using the plugin [here](https://github.com/BootNodeDev/dAppBooster/tree/main/src/components/pageComponents/home/Examples/demos/subgraphs) :::info **Recipes** For further information refer to the [subgraphs recipe](/recipes/subgraphs). ::: ### Configuration options The `PackageConfig` interface accepts the following options for each subgraph: * `apiKey`: Your subgraph API key. * `chainsResourceIds`: A string of comma-separated `::`. * i.e.: ```txt 137:uniswap:BvYimJ6vCLkk63oWZy7WB5cVDTVVMugUAF35RAUZpQXE,8453:aave:GQFbb95cE6d8mV989mL5figjaGaKCQB3xqYrr1bRyXqF ``` * `developmentUrl`: The URL for the development environment. * `productionUrl`: The URL for the production environment. * `environment`: Either 'development' or 'production'. * `queriesDirectory`: The directory where your GraphQL queries are located. * default: `./src/subgraphs/queries` * `destinationDirectory`: The directory where your typed queries will be generated. * defult: `./src/subgraphs/gql` ### Adding multiple subgraphs You can configure multiple subgraphs by adding more objects to the `subgraphs` array in your configuration: ```ts [codegen.ts] showLineNumbers export default generateCodegenConfig({ subgraphs: [ { // First subgraph configuration }, { // Second subgraph configuration }, // Add more as needed ], }); ``` ### Generated files The package will generate GraphQL clients in the `src/subgraphs/gql/` directory, organized by subgraph ID. ### Customization If you need to customize the generation process further, you can modify the `codegen.ts` file. The package is designed to be flexible, allowing you to define configurations in the way that best suits your project structure and requirements.