Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
2fa5393
chore: add CLAUDE.md and basic claude settings
gabitoesmiapodo Feb 24, 2026
293edc7
chore: add ignore
gabitoesmiapodo Mar 23, 2026
5f33ece
docs: fix pipe separator in CLAUDE.md and convert AGENTS.md to regula…
gabitoesmiapodo Mar 23, 2026
2dd84b7
docs: add sync reminder between CLAUDE.md and AGENTS.md
gabitoesmiapodo Mar 23, 2026
1a9a0aa
test: add utility and env test coverage (Tier 1)
gabitoesmiapodo Mar 23, 2026
7edb47f
test: address review feedback on Tier 1 test suite
gabitoesmiapodo Mar 23, 2026
55510e5
test: enhance BigNumberInput and HashInput coverage (Tier 2)
gabitoesmiapodo Mar 23, 2026
33e3ca3
test: address review feedback on Tier 2 test suite
gabitoesmiapodo Mar 23, 2026
40e06d3
test: address review feedback on Tier 1 test suite (round 2)
gabitoesmiapodo Mar 23, 2026
543f5f4
test: import ComponentProps from react instead of using React namespace
gabitoesmiapodo Mar 23, 2026
2b605b6
test: add hook test coverage (Tier 3)
gabitoesmiapodo Mar 23, 2026
d6ced76
test: address review feedback on Tier 3 hook test suite
gabitoesmiapodo Mar 23, 2026
7bda650
test: add component test coverage (Tier 4)
gabitoesmiapodo Mar 23, 2026
7b00d3b
test: address review feedback on Tier 4 component tests
gabitoesmiapodo Mar 23, 2026
09e9de1
test: add demo page smoke tests (Tier 5)
gabitoesmiapodo Mar 23, 2026
4fe5f28
test: fix detectHash mock in HashHandling smoke test
gabitoesmiapodo Mar 23, 2026
b0fe779
test: address review feedback on Tier 5 demo smoke tests
gabitoesmiapodo Mar 23, 2026
cf8852d
fix(a11y): fix color contrast, skip link, focus rings, and aria attri…
gabitoesmiapodo Mar 23, 2026
1ae1991
fix(a11y): address review feedback on accessibility fixes
gabitoesmiapodo Mar 23, 2026
6a2f37e
fix(a11y): guard parseUnits in BigNumberInput sync effect against throws
gabitoesmiapodo Mar 24, 2026
ad55ae2
fix(performance): lazy loading, dns-prefetch, and vendor chunk splitting
gabitoesmiapodo Mar 23, 2026
ba8c91b
fix(performance): add react-dom/client to vendor-react chunk
gabitoesmiapodo Mar 23, 2026
a37445c
fix(seo): add JSON-LD structured data and fix sitemap hostname
gabitoesmiapodo Mar 23, 2026
d0c83c8
fix(seo): use || instead of ?? for sitemap hostname fallback
gabitoesmiapodo Mar 23, 2026
d8cb437
fix(security): add CSP report-only header and security headers
gabitoesmiapodo Mar 23, 2026
4b34dfe
chore(deps): update minor and patch dependencies
gabitoesmiapodo Mar 23, 2026
9ab7ee5
chore(deps): align @tanstack devtools versions with runtime packages
gabitoesmiapodo Mar 23, 2026
49b989f
chore(deps): use actual latest available versions for @tanstack devtools
gabitoesmiapodo Mar 23, 2026
a412c4f
test: fix redundant cases in isNativeToken test suite
gabitoesmiapodo Mar 25, 2026
990a656
chore: ignore .worktrees directory
gabitoesmiapodo Mar 25, 2026
ff358c9
Merge pull request #416 from BootNodeDev/test/enhance-existing
gabitoesmiapodo Mar 25, 2026
5861213
refactor(tests): use Address type from viem instead of template literal
gabitoesmiapodo Mar 25, 2026
11fb2a4
Merge pull request #417 from BootNodeDev/test/hooks
gabitoesmiapodo Mar 25, 2026
9d1aff7
Merge pull request #418 from BootNodeDev/test/components
gabitoesmiapodo Mar 25, 2026
cb38783
Merge pull request #419 from BootNodeDev/test/demo-smoke
gabitoesmiapodo Mar 25, 2026
2a34495
Merge branch 'test/utils' into fix/a11y
gabitoesmiapodo Mar 25, 2026
f0b550e
Merge branch 'fix/a11y' into fix/performance
gabitoesmiapodo Mar 25, 2026
aadc0ed
Merge branch 'fix/performance' into fix/seo
gabitoesmiapodo Mar 25, 2026
c03c5cb
Merge branch 'fix/seo' into fix/security
gabitoesmiapodo Mar 25, 2026
80f0ad8
Merge branch 'fix/security' into fix/deps
gabitoesmiapodo Mar 25, 2026
a23f494
fix: throw when getExplorerLink has no block explorer URL available
gabitoesmiapodo Mar 25, 2026
e5e488e
Merge pull request #415 from BootNodeDev/test/utils
gabitoesmiapodo Mar 30, 2026
ebcb13f
Merge branch 'feat/ai-integration' into fix/a11y
gabitoesmiapodo Mar 30, 2026
4048312
Merge branch 'fix/a11y' into fix/performance
gabitoesmiapodo Mar 30, 2026
ec94c35
Merge branch 'fix/performance' into fix/seo
gabitoesmiapodo Mar 30, 2026
738bfda
fix: add default rel="noopener noreferrer" to ExternalLinkButton
gabitoesmiapodo Mar 30, 2026
f6ad4a3
Merge pull request #421 from BootNodeDev/fix/a11y
gabitoesmiapodo Mar 30, 2026
3f36cb2
Merge branch 'fix/seo' into fix/security
gabitoesmiapodo Mar 30, 2026
f157866
Merge pull request #422 from BootNodeDev/fix/performance
gabitoesmiapodo Mar 30, 2026
421d074
Merge pull request #423 from BootNodeDev/fix/seo
gabitoesmiapodo Mar 30, 2026
c35e0ff
fix(security): remove broken report-uri from CSP header
gabitoesmiapodo Mar 30, 2026
caf5c07
Merge pull request #424 from BootNodeDev/fix/security
gabitoesmiapodo Mar 30, 2026
5456c99
Merge pull request #425 from BootNodeDev/fix/deps
gabitoesmiapodo Mar 30, 2026
7dd2a8e
Merge pull request #426 from BootNodeDev/fix/explorer-link-missing-ex…
gabitoesmiapodo Mar 30, 2026
2a9ac26
fix: use ReactElement type import in WalletStatusVerifier test
gabitoesmiapodo Mar 30, 2026
1de9337
fix: use explicit undefined checks for bigint min/max bounds
gabitoesmiapodo Mar 30, 2026
30f1062
fix: read PUBLIC_APP_URL via loadEnv in vite config
gabitoesmiapodo Mar 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"permissions": {
"allow": [
"WebFetch(domain:docs.dappbooster.dev)",
"WebFetch(domain:components.dappbooster.dev)"
]
}
}
7 changes: 7 additions & 0 deletions .env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Test environment variables for Vitest
PUBLIC_APP_NAME=dAppBooster Test
PUBLIC_NATIVE_TOKEN_ADDRESS=0x0000000000000000000000000000000000000000
PUBLIC_WALLETCONNECT_PROJECT_ID=test-project-id
PUBLIC_SUBGRAPHS_API_KEY=test-api-key
PUBLIC_SUBGRAPHS_CHAINS_RESOURCE_IDS=1:test:test-resource-id
PUBLIC_SUBGRAPHS_ENVIRONMENT=production
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ src/subgraphs/gql
src/hooks/generated.ts
vite.config.ts.timestamp*

# Claude Code
.claude/settings.local.json
CLAUDE.local.md

# Project .env files
.env.local
.env
Expand All @@ -39,3 +43,4 @@ yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
.worktrees
231 changes: 231 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
# dAppBooster

> This file is mirrored as `CLAUDE.md` for Claude. Keep both files in sync when making changes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we going with this approach instead of the symlink?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd go with the symlink approach, but in this case this is a tool and it should work on as many platforms as possible. Symlinks are OK for Unix-like systems (which I assume is what most people use to develop web apps), but leave out people working on Windows so I guess this is a better way until a standard is adopted by everyone / most LLMs.


A repository template / starter-kit for building decentralized applications (dApps). Built by BootNode based on 5+ years of dApp development. Docs: https://docs.dappbooster.dev/ Components: https://components.dappbooster.dev/

## Requirements

- Node 24+ (see `.nvmrc`)
- pnpm 10.30.2+ (enforced via `packageManager` in package.json; corepack will block npm/yarn)

## Setup

1. `pnpm install` (postinstall automatically runs `pnpm wagmi-generate`)
2. `cp .env.example .env.local`
3. Edit `.env.local`:
- `PUBLIC_APP_NAME` is mandatory
- `PUBLIC_WALLETCONNECT_PROJECT_ID` is needed for wallet connection to work
- RPC vars (`PUBLIC_RPC_*`) are optional -- wagmi falls back to default public RPCs
- Subgraph vars are all-or-nothing: if ANY `PUBLIC_SUBGRAPHS_*` var is missing or empty, codegen will skip and the app will crash at runtime. Either set them all or remove all subgraph-related code.
4. `pnpm subgraph-codegen` (only if subgraph vars are configured)
5. `pnpm dev`

## Git Hooks (Husky)

Three hooks run automatically and will block on failure:

- **pre-commit:** lint-staged runs Biome check + Vitest on related files for staged changes
- **commit-msg:** commitlint enforces conventional commit format. Valid types: `feat`, `fix`, `docs`, `test`, `ci`, `refactor`, `perf`, `chore`, `revert`. PR titles are also validated via CI.
- **pre-push:** full `tsc --noEmit` type check (pushes with type errors will be rejected)

## Quick Reference

- **Dev server:** `pnpm dev`
- **Build:** `pnpm build` (runs tsc + vite build)
- **Lint:** `pnpm lint` (Biome) / `pnpm lint:fix`
- **Test:** `pnpm test` / `pnpm test:watch` / `pnpm test:coverage`
- **Generate contract hooks:** `pnpm wagmi-generate`
- **Generate routes:** `pnpm routes:generate`
- **Generate subgraph types:** `pnpm subgraph-codegen`
- **Docs site:** `pnpm docs:dev`

## Tech Stack

- React 19 + TypeScript (strict mode, ESM -- `"type": "module"`, no `require()`)
- Vite + SWC (fast JSX transform)
- Wagmi 2 + viem 2 (Ethereum interaction)
- TanStack Router (file-based routing with auto code-splitting)
- TanStack Query (server state / data fetching)
- Chakra UI 3 (component library + theming)
- ConnectKit (default wallet connector; RainbowKit and Web3Modal also available)
- LI.FI SDK (token prices/balances)
- Zod + @t3-oss/env-core (environment variable validation)
- Biome (linting + formatting)
- Vitest + Testing Library (testing)

## Project Structure

```
src/
components/
pageComponents/ # Page-level components (home/, weth/, demos/)
sharedComponents/ # Reusable UI + business components
ui/ # Chakra provider + theme setup
hooks/ # Custom React hooks
generated.ts # Auto-generated by wagmi-cli (do not edit)
providers/ # Web3Provider, TransactionNotificationProvider
routes/ # TanStack Router file-based routes
__root.tsx # Root layout (provider stack + shell)
lib/
networks.config.ts # Chain + transport configuration
wagmi/ # Wagmi CLI config + custom Suspense plugin
wallets/ # ConnectKit, RainbowKit, Web3Modal configs
constants/
contracts/ # Contract ABIs + addresses per chain
tokenLists.ts # Token list URLs
common.ts # Shared constants (isDev, includeTestnets)
types/ # TypeScript type definitions
utils/ # Utility functions
subgraphs/ # GraphQL codegen config + queries
env.ts # Zod-validated environment variables
main.tsx # Entry point
routeTree.gen.ts # Auto-generated route tree (do not edit)
```

No top-level barrel exports. Import directly from each file/folder path.

## Provider Stack

The root layout (`src/routes/__root.tsx`) wraps the app in this order:

```
Chakra Provider (theme, color mode)
Web3Provider (WagmiProvider -> QueryClientProvider -> WalletProvider)
TransactionNotificationProvider (tx toast context)
Header / Outlet (page) / Footer
```

New providers should be inserted at the appropriate layer based on their dependencies.

## Code Style

- **No semicolons** in TypeScript/JavaScript
- **Single quotes**
- 2-space indentation, 100 char line width
- Import organization handled by Biome
- Path aliases: `@/src/*` and `@packageJSON`
- All env vars prefixed with `PUBLIC_` and validated in `src/env.ts`
- JSDoc comments on exported functions/components (follow existing patterns)

## Styling

- **Chakra UI props** are the primary styling method. No CSS modules, no Tailwind, no styled-components.
- Theme is defined in `src/components/ui/provider.tsx` using `createSystem` extending `defaultConfig`.
- Use **semantic tokens** for colors: `bg`, `primary`, `text`, `danger`, `ok`, `warning`. These support light/dark mode. Do not hardcode color values.
- Fonts: Manrope (body/heading), Roboto Mono (mono/code).
- Complex components export style objects from a `styles.ts` file, consumed via Chakra's `css` prop or spread into component props.

## Component Conventions

- **Simple components:** single file (e.g., `ExplorerLink.tsx`, `SwitchNetwork.tsx`)
- **Complex components:** folder with:
- `index.tsx` -- main component and public API
- `Components.tsx` -- sub-components (styled primitives, layout pieces)
- `styles.ts` -- style objects
- `useComponentName.ts` -- dedicated hook (optional)
- Page components go in `src/components/pageComponents/<pagename>/`
- Shared/reusable components go in `src/components/sharedComponents/`

## Key Patterns

### Adding a New Contract

1. Save ABI in `src/constants/contracts/abis/YourContract.ts` (export as const)
2. Register in `src/constants/contracts/contracts.ts` with name, ABI, and addresses per chain
3. Run `pnpm wagmi-generate` to auto-generate typed hooks in `src/hooks/generated.ts`

The contracts array uses `as const satisfies ContractConfig<Abi>[]` for full type inference. Follow this pattern.

Use `getContract(name, chainId)` to retrieve a typed contract config at runtime (e.g., `getContract('WETH', sepolia.id)` returns `{ abi, address }`).

### Generated Hook Naming Convention

`pnpm wagmi-generate` produces hooks in `src/hooks/generated.ts` following this naming pattern:

- `useReadContractNameFunctionName` -- standard read hook
- `useWriteContractNameFunctionName` -- write hook
- `useSuspenseReadContractNameFunctionName` -- Suspense-enabled read hook
- `useSimulateContractNameFunctionName` -- simulation hook

Example: contract named `WETH` with function `allowance` generates `useReadWethAllowance`, `useWriteWethApprove`, `useSuspenseReadWethAllowance`, etc.

### Adding a New Route/Page

1. Create route file in `src/routes/` using `.lazy.tsx` extension for code-split lazy loading (e.g., `yourpage.lazy.tsx`). Use plain `.tsx` only for routes that must be eagerly loaded.
2. Create page component in `src/components/pageComponents/yourpage/`
3. Route tree auto-generates via TanStack Router plugin

### Adding a New Network

1. Import chain from `viem/chains` in `src/lib/networks.config.ts`
2. Add to the appropriate chain array (devChains or prodChains)
3. Add transport entry with optional custom RPC from env
4. Add RPC env var to `src/env.ts` if needed

### Environment Variables

- Defined and validated with Zod in `src/env.ts`
- Access via `import { env } from '@/src/env'` (never `import.meta.env` directly)
- New variables MUST be added to both `.env.example` and `src/env.ts`

### Web3 Status

- Use `useWeb3Status()` for unified wallet/chain state
- Use `useWeb3StatusConnected()` when wallet connection is guaranteed (throws otherwise)
- Use `withWalletStatusVerifier()` HOC to gate components behind wallet connection

### Suspense and Error Boundaries

- Contract read hooks use React Suspense via custom `reactSuspenseRead` wagmi plugin
- `useTokenLists` is Suspense-based
- Wrap async components with `withSuspenseAndRetry()` from `src/utils/suspenseWrapper.tsx` -- this is the primary error boundary pattern. It integrates with TanStack Query's `QueryErrorResetBoundary` for automatic retry on query failures.
- `withSuspenseAndRetry` accepts: `suspenseFallback`, `errorFallback`, `defaultFallbackFormat` ('dialog' | 'default'), `spinnerSize`
- Simpler variant `withSuspense()` available when retry logic is not needed

### Transaction Handling

Two components for two different jobs -- both auto-wrap with `withWalletStatusVerifier` (do not double-wrap):

- **`TransactionButton`** -- for on-chain transactions. Takes `transaction: () => Promise<Hash>` prop. Attach a `methodId` string property to the function for notification context. Calls `onMined(receipt)` on confirmation.
- **`SignButton`** -- for message signing only (uses `useSignMessage`). Takes `message`, `onSign`, `onError` props.

`TransactionNotificationProvider` handles toast notifications and tx watching for both.

### Token Management

- Token lists configured in `src/constants/tokenLists.ts`
- Fetch with `useTokenLists()` hook (Suspense-based). Tokens are deduplicated by `chainId + address` (lowercased). Native tokens are auto-injected for each configured chain.
- Token prices/balances via `useTokens()` (LI.FI SDK)
- `TokenInput` + `useTokenInput()` for amount input with validation
- For raw bigint/decimal conversion in inputs, use `BigNumberInput` (wraps viem's `parseUnits`/`formatUnits`). Never use `parseFloat` or `Number()` for token amounts.

### Wallet Provider

- Default: ConnectKit (configured in `src/lib/wallets/connectkit.config.tsx`)
- To switch: modify `src/providers/Web3Provider.tsx` imports
- Alternatives available: RainbowKit (`rainbowkit.config.tsx`), Web3Modal (`web3modal.config.tsx`)

## Auto-Generated Files (Do Not Edit, Do Not Commit)

These files are gitignored and regenerated from source:

- `src/hooks/generated.ts` -- regenerate with `pnpm wagmi-generate`
- `src/routeTree.gen.ts` -- regenerate with `pnpm routes:generate`
- `src/subgraphs/gql/` -- regenerate with `pnpm subgraph-codegen`

## Utilities

- **Number formatting:** Use `formatNumber()` from `src/utils/numberFormat.ts` with the appropriate `NumberType` context (`TokenTx`, `FiatTokenPrice`, `SwapPrice`, `PortfolioBalance`, etc.). Never use raw `.toString()` or `.toFixed()` for user-facing numbers.
- **Explorer links:** `getExplorerLink()` from `src/utils/getExplorerLink.ts`
- **String truncation:** `truncateStringInTheMiddle()`, `getTruncatedHash()` from `src/utils/strings.ts`
- **Native token check:** `isNativeToken()` from `src/utils/address.ts`
- **Hash detection:** `detectHash()` from `src/utils/hash.ts` -- identifies ENS names, transaction hashes, contract addresses, and EOAs

## Testing

- Framework: Vitest with jsdom environment
- Test files: colocated as `*.test.ts` / `*.test.tsx`
- Mocking: `vi.mock()` for module mocks
- Component testing: Testing Library + jest-dom matchers
- Run: `pnpm test` (single run) or `pnpm test:watch`
Loading
Loading