From 9a6164e2ca06d3be9c53232f1ee3465dd9194574 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Wed, 25 Jun 2025 12:56:13 +1200 Subject: [PATCH 1/2] Handle sponsored gas on TransactionWidget --- .changeset/rude-bags-say.md | 5 +++++ .../src/react/core/hooks/useTransactionDetails.ts | 10 +++++++++- .../src/react/web/ui/Bridge/TransactionPayment.tsx | 3 +++ .../web/ui/Bridge/payment-details/PaymentOverview.tsx | 3 +++ 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 .changeset/rude-bags-say.md diff --git a/.changeset/rude-bags-say.md b/.changeset/rude-bags-say.md new file mode 100644 index 00000000000..9841317ac6e --- /dev/null +++ b/.changeset/rude-bags-say.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +Handle sponsored gas on TransactionWidget diff --git a/packages/thirdweb/src/react/core/hooks/useTransactionDetails.ts b/packages/thirdweb/src/react/core/hooks/useTransactionDetails.ts index 472a6c853b2..c3039109aec 100644 --- a/packages/thirdweb/src/react/core/hooks/useTransactionDetails.ts +++ b/packages/thirdweb/src/react/core/hooks/useTransactionDetails.ts @@ -14,6 +14,8 @@ import type { PreparedTransaction } from "../../../transaction/prepare-transacti import { getTransactionGasCost } from "../../../transaction/utils.js"; import { resolvePromisedValue } from "../../../utils/promise/resolve-promised-value.js"; import { toTokens } from "../../../utils/units.js"; +import type { Wallet } from "../../../wallets/interfaces/wallet.js"; +import { hasSponsoredTransactionsEnabled } from "../../../wallets/smart/is-smart-wallet.js"; import { formatCurrencyAmount, formatTokenAmount, @@ -40,6 +42,7 @@ interface TransactionDetails { interface UseTransactionDetailsOptions { transaction: PreparedTransaction; client: ThirdwebClient; + wallet: Wallet | undefined; } /** @@ -49,8 +52,10 @@ interface UseTransactionDetailsOptions { export function useTransactionDetails({ transaction, client, + wallet, }: UseTransactionDetailsOptions) { const chainMetadata = useChainMetadata(transaction.chain); + const hasSponsoredTransactions = hasSponsoredTransactionsEnabled(wallet); return useQuery({ enabled: !!transaction.to && !!chainMetadata.data, @@ -76,7 +81,9 @@ export function useTransactionDetails({ erc20Value ? erc20Value.tokenAddress : NATIVE_TOKEN_ADDRESS, transaction.chain.id, ).catch(() => null), - getTransactionGasCost(transaction).catch(() => null), + hasSponsoredTransactions + ? 0n + : getTransactionGasCost(transaction).catch(() => null), ]); // Process function info from ABI if available @@ -172,6 +179,7 @@ export function useTransactionDetails({ transaction.to, transaction.chain.id, transaction.erc20Value?.toString(), + hasSponsoredTransactions, ], }); } diff --git a/packages/thirdweb/src/react/web/ui/Bridge/TransactionPayment.tsx b/packages/thirdweb/src/react/web/ui/Bridge/TransactionPayment.tsx index 90c2875fedb..6bbb7a93c62 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/TransactionPayment.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/TransactionPayment.tsx @@ -15,6 +15,7 @@ import { import { useChainMetadata } from "../../../core/hooks/others/useChainQuery.js"; import { useTransactionDetails } from "../../../core/hooks/useTransactionDetails.js"; import { useActiveAccount } from "../../../core/hooks/wallets/useActiveAccount.js"; +import { useActiveWallet } from "../../../core/hooks/wallets/useActiveWallet.js"; import { ConnectButton } from "../ConnectWallet/ConnectButton.js"; import { PoweredByThirdweb } from "../ConnectWallet/PoweredByTW.js"; import { Container, Line } from "../components/basic.js"; @@ -57,6 +58,7 @@ export function TransactionPayment({ }: TransactionPaymentProps) { const theme = useCustomTheme(); const activeAccount = useActiveAccount(); + const wallet = useActiveWallet(); // Get chain metadata for native currency symbol const chainMetadata = useChainMetadata(uiOptions.transaction.chain); @@ -65,6 +67,7 @@ export function TransactionPayment({ const transactionDataQuery = useTransactionDetails({ client, transaction: uiOptions.transaction, + wallet, }); const contractName = diff --git a/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentOverview.tsx b/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentOverview.tsx index f10b444c453..3402b288367 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentOverview.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentOverview.tsx @@ -188,6 +188,7 @@ export function PaymentOverview(props: { {props.uiOptions.mode === "transaction" && ( )} @@ -198,12 +199,14 @@ export function PaymentOverview(props: { const TransactionOverViewCompact = (props: { uiOptions: Extract; + paymentMethod: PaymentMethod; client: ThirdwebClient; }) => { const theme = useCustomTheme(); const txInfo = useTransactionDetails({ client: props.client, transaction: props.uiOptions.transaction, + wallet: props.paymentMethod.payerWallet, }); if (!txInfo.data) { From ba90e201597d772fbafdfb981eb32fc12772d482 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Wed, 25 Jun 2025 13:24:38 +1200 Subject: [PATCH 2/2] Add CLAUDE.md for repository development guidance --- CLAUDE.md | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000000..8f832d18f9c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,290 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Development Commands + +### Package Management + +- Use `pnpm install` (or `pnpm install --ignore-scripts` on Windows) +- Monorepo managed with Turborepo and pnpm workspaces + +### Building + +```bash +# Build all packages +pnpm build + +# Build specific packages with dependencies +turbo run build --filter=./packages/* + +# Development with watch mode +pnpm dev # Core thirdweb package +pnpm dashboard # Run dashboard + dependencies +pnpm playground # Run playground + dependencies +pnpm portal # Run portal docs + dependencies +``` + +### Testing + +```bash +# Run all tests +pnpm test + +# Interactive testing (thirdweb package) +cd packages/thirdweb && pnpm test:devr + +# Test specific file +pnpm test:dev + +# E2E testing (dashboard) +cd apps/dashboard && pnpm playwright +``` + +### Code Quality + +```bash +# Lint all packages +pnpm lint + +# Auto-fix linting issues +pnpm fix + +# Format code +turbo run format + +# Biome is the primary linter/formatter +``` + +### Development Workflow + +```bash +# Start development server for dashboard +pnpm dashboard + +# Start playground for SDK testing +pnpm playground + +# Generate changeset for releases +pnpm changeset + +# Version packages +pnpm version-packages +``` + +## Repository Architecture + +### Monorepo Structure + +This is a Turborepo monorepo with the main thirdweb v5 SDK consolidated into `/packages/thirdweb/`. Legacy packages are in `/legacy_packages/`. + +### Core Package (`/packages/thirdweb/`) + +**Main Modules:** + +- `client/` - ThirdwebClient foundation +- `chains/` - 50+ supported blockchain definitions +- `contract/` - Contract interaction with automatic ABI resolution +- `transaction/` - Transaction management and execution +- `wallets/` - Comprehensive wallet integration system +- `extensions/` - Modular contract extensions (ERC20, ERC721, etc.) +- `auth/` - SIWE authentication and signature verification +- `pay/` - Fiat and crypto payment infrastructure +- `storage/` - IPFS integration for decentralized storage +- `rpc/` - Low-level blockchain communication + +**Exports Structure:** +The SDK uses modular exports from `src/exports/` including: + +- `thirdweb.ts` - Core client and utilities +- `chains.ts` - Chain definitions +- `wallets.ts` - Wallet connectors +- `react.ts` - React hooks and components +- `extensions/` - Contract standards and protocols + +### Applications (`/apps/`) + +- **dashboard** - Web-based developer console (Next.js, Chakra UI) +- **playground-web** - Interactive SDK testing environment +- **portal** - Documentation site with MDX +- **nebula** - Account abstraction and smart wallet management +- **wallet-ui** - Wallet interface and testing + +### Key Packages (`/packages/`) + +- **thirdweb** - Main SDK (TypeScript, React, React Native) +- **engine** - thirdweb Engine API client +- **insight** - Analytics and data APIs +- **nebula** - Account abstraction client +- **service-utils** - Shared utilities across services + +## Development Practices + +### GitHub Workflow & Pull Requests + +- **PR titles**: Must start with affected workspace in brackets (e.g. `[SDK]`, `[Dashboard]`, `[Portal]`, `[Playground]`) +- **PR descriptions**: Begin with one-sentence summary, add checklist of changes, reference issues with `Fixes #123` +- **Commits**: Keep small and topical – one logical change per commit +- **Branch naming**: Use `area/brief-topic` format (e.g. `sdk/fix-gas-estimate`). Avoid personal names +- **Reviews**: Request at least one core maintainer review. Do not self-merge unless sole package owner +- **CI requirements**: All checks (type-check, Biome, tests) must pass before merging + +### Code Quality & Formatting + +- **Biome**: Primary linter/formatter (rules in `biome.json`) +- **Pre-commit**: Run `pnpm biome check --apply` before committing +- **Build verification**: Run `pnpm build` after each file change to ensure everything builds +- Avoid editor-specific configs; rely on shared settings + +### TypeScript Guidelines + +- **Style**: Write idiomatic TypeScript with explicit function declarations and return types +- **File structure**: Limit each file to one stateless, single-responsibility function for clarity +- **Types**: Re-use shared types from `@/types` or local `types.ts` barrels +- **Interfaces vs Types**: Prefer type aliases over interface except for nominal shapes +- **Type safety**: Avoid `any` and `unknown` unless unavoidable; narrow generics when possible +- **Architecture**: Choose composition over inheritance; leverage utility types (`Partial`, `Pick`, etc.) + +### Testing Strategy + +- **Co-location**: Place tests alongside code: `foo.ts` ↔ `foo.test.ts` +- **Test approach**: Use real function invocations with stub data; avoid brittle mocks +- **Network mocking**: Use Mock Service Worker (MSW) for fetch/HTTP call interception +- **Test quality**: Keep tests deterministic and side-effect free +- **Running tests**: `cd packages/thirdweb && pnpm test:dev ` +- **Test accounts**: Predefined accounts in `test/src/test-wallets.ts` +- **Chain forking**: Use `FORKED_ETHEREUM_CHAIN` for mainnet interactions, `ANVIL_CHAIN` for isolated tests + +### SDK Development (`packages/thirdweb`) + +#### Public API Guidelines +- **Exports**: Export everything via `exports/` directory, grouped by feature +- **Documentation**: Every public symbol must have comprehensive TSDoc with: + - At least one `@example` block that compiles + - Custom annotation tags (`@beta`, `@internal`, `@experimental`) +- **Comments**: Comment only ambiguous logic; avoid restating TypeScript in prose + +#### Performance Optimization +- **Lazy loading**: Load heavy dependencies inside async paths to keep initial bundle lean: + ```typescript + const { jsPDF } = await import("jspdf"); + ``` +- **Bundle budgets**: Track via `package.json#size-limit` +- **Dependencies**: De-duplicate across packages through pnpm workspace hoisting + +### Dashboard & Playground Development + +#### UI Component Standards +- **Core components**: Import primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) +- **Navigation**: Use `NavLink` for internal navigation with automatic active states +- **Organization**: Group feature-specific components under `feature/components/*` with barrel `index.ts` + +#### Styling Conventions +- **CSS framework**: Tailwind CSS only – no inline styles or CSS modules +- **Class merging**: Use `cn()` from `@/lib/utils` for conditional logic +- **Design tokens**: Use design system tokens (backgrounds: `bg-card`, borders: `border-border`, muted text: `text-muted-foreground`) +- **Component API**: Expose `className` prop on root element for overrides + +#### Component Architecture +- **Server Components** (Node edge): + - Start files with `import "server-only";` + - Read cookies/headers with `next/headers` + - Access server-only environment variables + - Perform heavy data fetching + - Implement redirect logic with `redirect()` from `next/navigation` +- **Client Components** (browser): + - Begin files with `'use client';` + - Handle interactive UI with React hooks (`useState`, `useEffect`, React Query, wallet hooks) + - Access browser APIs (`localStorage`, `window`, `IntersectionObserver`) + - Support fast transitions with prefetched data + +#### Data Fetching Patterns +- **Server Side**: + - Always call `getAuthToken()` to retrieve JWT from cookies + - Use `Authorization: Bearer` header – never embed tokens in URLs + - Return typed results (`Project[]`, `User[]`) – avoid `any` +- **Client Side**: + - Wrap calls in React Query (`@tanstack/react-query`) + - Use descriptive, stable `queryKeys` for cache hits + - Configure `staleTime`/`cacheTime` based on freshness (default ≥ 60s) + - Keep tokens secret via internal API routes or server actions + +#### Analytics Event Guidelines +- **When to add**: Only create events that answer clear product/business questions +- **Check duplicates**: Review `src/@/analytics/report.ts` first +- **Naming**: + - Event name: human-readable ` ` (e.g. "contract deployed") + - Function: `report` (PascalCase) +- **Template**: + ```typescript + /** + * ### Why do we need to report this event? + * - Tracks number of contracts deployed + * + * ### Who is responsible for this event? + * @username + */ + export function reportContractDeployed(properties: { + address: string; + chainId: number; + }) { + posthog.capture("contract deployed", properties); + } + ``` +- **Client-side only**: Never import `posthog-js` in server components +- **Changes**: Inform **#eng-core-services** before renaming/removing events + +### Extension Development + +- Extensions follow modular pattern in `src/extensions/` +- Auto-generated contracts from ABI definitions +- Composable functions with TypeScript safety +- Support for read/write operations + +### Wallet Architecture + +- Unified `Wallet` and `Account` interfaces +- Support for in-app wallets (social/email login) +- Smart wallets with account abstraction +- EIP-1193, EIP-5792, EIP-7702 standard support + +## Contribution Workflow + +1. **Fork and Clone**: Create fork, clone, create feature branch +2. **Install**: `pnpm install` (use `--ignore-scripts` on Windows) +3. **Develop**: Use appropriate dev commands above +4. **Test**: Write unit tests, run linting, test on demo apps +5. **Changeset**: Run `pnpm changeset` for semantic versioning +6. **PR**: Submit pull request to main branch + +### Release Testing + +Comment `/release-pr` on PR to trigger dev release to npm for testing. + +### Changeset Guidelines + +Each change in `packages/*` should contain a changeset for the appropriate package with the appropriate version bump: +- **patch**: Changes that don't impact the public API +- **minor**: Any new/modified public API +- **major**: Breaking changes (surface prominently in PR descriptions) + +### Documentation Standards + +- For new UI components, add Storybook stories (`*.stories.tsx`) alongside the code +- Surface breaking changes prominently in PR descriptions +- Keep documentation focused on developer experience and practical usage + +## Multi-Platform Support + +The SDK supports: + +- **Web**: React hooks and components +- **React Native**: Mobile-specific exports and components +- **Node.js**: Server-side functionality +- **Framework Adapters**: Wagmi, Ethers compatibility layers + +Key files: + +- `src/exports/react.native.ts` - React Native specific exports +- `packages/react-native-adapter/` - Mobile platform shims +- `packages/wagmi-adapter/` - Wagmi ecosystem integration