Skip to content

Commit 5ec35e1

Browse files
committed
feat: merged main.
2 parents 047043d + c5f9921 commit 5ec35e1

File tree

64 files changed

+1828
-740
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1828
-740
lines changed

.changeset/rude-bags-say.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Handle sponsored gas on TransactionWidget

.changeset/slimy-tigers-trade.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@thirdweb-dev/service-utils": minor
3+
---
4+
5+
feat: Add webhook producer to service-utils

.changeset/wild-cases-ask.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Deprecate PayEmbed

CLAUDE.md

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Development Commands
6+
7+
### Package Management
8+
9+
- Use `pnpm install` (or `pnpm install --ignore-scripts` on Windows)
10+
- Monorepo managed with Turborepo and pnpm workspaces
11+
12+
### Building
13+
14+
```bash
15+
# Build all packages
16+
pnpm build
17+
18+
# Build specific packages with dependencies
19+
turbo run build --filter=./packages/*
20+
21+
# Development with watch mode
22+
pnpm dev # Core thirdweb package
23+
pnpm dashboard # Run dashboard + dependencies
24+
pnpm playground # Run playground + dependencies
25+
pnpm portal # Run portal docs + dependencies
26+
```
27+
28+
### Testing
29+
30+
```bash
31+
# Run all tests
32+
pnpm test
33+
34+
# Interactive testing (thirdweb package)
35+
cd packages/thirdweb && pnpm test:devr
36+
37+
# Test specific file
38+
pnpm test:dev <path-to-test-file>
39+
40+
# E2E testing (dashboard)
41+
cd apps/dashboard && pnpm playwright
42+
```
43+
44+
### Code Quality
45+
46+
```bash
47+
# Lint all packages
48+
pnpm lint
49+
50+
# Auto-fix linting issues
51+
pnpm fix
52+
53+
# Format code
54+
turbo run format
55+
56+
# Biome is the primary linter/formatter
57+
```
58+
59+
### Development Workflow
60+
61+
```bash
62+
# Start development server for dashboard
63+
pnpm dashboard
64+
65+
# Start playground for SDK testing
66+
pnpm playground
67+
68+
# Generate changeset for releases
69+
pnpm changeset
70+
71+
# Version packages
72+
pnpm version-packages
73+
```
74+
75+
## Repository Architecture
76+
77+
### Monorepo Structure
78+
79+
This is a Turborepo monorepo with the main thirdweb v5 SDK consolidated into `/packages/thirdweb/`. Legacy packages are in `/legacy_packages/`.
80+
81+
### Core Package (`/packages/thirdweb/`)
82+
83+
**Main Modules:**
84+
85+
- `client/` - ThirdwebClient foundation
86+
- `chains/` - 50+ supported blockchain definitions
87+
- `contract/` - Contract interaction with automatic ABI resolution
88+
- `transaction/` - Transaction management and execution
89+
- `wallets/` - Comprehensive wallet integration system
90+
- `extensions/` - Modular contract extensions (ERC20, ERC721, etc.)
91+
- `auth/` - SIWE authentication and signature verification
92+
- `pay/` - Fiat and crypto payment infrastructure
93+
- `storage/` - IPFS integration for decentralized storage
94+
- `rpc/` - Low-level blockchain communication
95+
96+
**Exports Structure:**
97+
The SDK uses modular exports from `src/exports/` including:
98+
99+
- `thirdweb.ts` - Core client and utilities
100+
- `chains.ts` - Chain definitions
101+
- `wallets.ts` - Wallet connectors
102+
- `react.ts` - React hooks and components
103+
- `extensions/` - Contract standards and protocols
104+
105+
### Applications (`/apps/`)
106+
107+
- **dashboard** - Web-based developer console (Next.js, Chakra UI)
108+
- **playground-web** - Interactive SDK testing environment
109+
- **portal** - Documentation site with MDX
110+
- **nebula** - Account abstraction and smart wallet management
111+
- **wallet-ui** - Wallet interface and testing
112+
113+
### Key Packages (`/packages/`)
114+
115+
- **thirdweb** - Main SDK (TypeScript, React, React Native)
116+
- **engine** - thirdweb Engine API client
117+
- **insight** - Analytics and data APIs
118+
- **nebula** - Account abstraction client
119+
- **service-utils** - Shared utilities across services
120+
121+
## Development Practices
122+
123+
### GitHub Workflow & Pull Requests
124+
125+
- **PR titles**: Must start with affected workspace in brackets (e.g. `[SDK]`, `[Dashboard]`, `[Portal]`, `[Playground]`)
126+
- **PR descriptions**: Begin with one-sentence summary, add checklist of changes, reference issues with `Fixes #123`
127+
- **Commits**: Keep small and topical – one logical change per commit
128+
- **Branch naming**: Use `area/brief-topic` format (e.g. `sdk/fix-gas-estimate`). Avoid personal names
129+
- **Reviews**: Request at least one core maintainer review. Do not self-merge unless sole package owner
130+
- **CI requirements**: All checks (type-check, Biome, tests) must pass before merging
131+
132+
### Code Quality & Formatting
133+
134+
- **Biome**: Primary linter/formatter (rules in `biome.json`)
135+
- **Pre-commit**: Run `pnpm biome check --apply` before committing
136+
- **Build verification**: Run `pnpm build` after each file change to ensure everything builds
137+
- Avoid editor-specific configs; rely on shared settings
138+
139+
### TypeScript Guidelines
140+
141+
- **Style**: Write idiomatic TypeScript with explicit function declarations and return types
142+
- **File structure**: Limit each file to one stateless, single-responsibility function for clarity
143+
- **Types**: Re-use shared types from `@/types` or local `types.ts` barrels
144+
- **Interfaces vs Types**: Prefer type aliases over interface except for nominal shapes
145+
- **Type safety**: Avoid `any` and `unknown` unless unavoidable; narrow generics when possible
146+
- **Architecture**: Choose composition over inheritance; leverage utility types (`Partial`, `Pick`, etc.)
147+
148+
### Testing Strategy
149+
150+
- **Co-location**: Place tests alongside code: `foo.ts``foo.test.ts`
151+
- **Test approach**: Use real function invocations with stub data; avoid brittle mocks
152+
- **Network mocking**: Use Mock Service Worker (MSW) for fetch/HTTP call interception
153+
- **Test quality**: Keep tests deterministic and side-effect free
154+
- **Running tests**: `cd packages/thirdweb && pnpm test:dev <filename>`
155+
- **Test accounts**: Predefined accounts in `test/src/test-wallets.ts`
156+
- **Chain forking**: Use `FORKED_ETHEREUM_CHAIN` for mainnet interactions, `ANVIL_CHAIN` for isolated tests
157+
158+
### SDK Development (`packages/thirdweb`)
159+
160+
#### Public API Guidelines
161+
- **Exports**: Export everything via `exports/` directory, grouped by feature
162+
- **Documentation**: Every public symbol must have comprehensive TSDoc with:
163+
- At least one `@example` block that compiles
164+
- Custom annotation tags (`@beta`, `@internal`, `@experimental`)
165+
- **Comments**: Comment only ambiguous logic; avoid restating TypeScript in prose
166+
167+
#### Performance Optimization
168+
- **Lazy loading**: Load heavy dependencies inside async paths to keep initial bundle lean:
169+
```typescript
170+
const { jsPDF } = await import("jspdf");
171+
```
172+
- **Bundle budgets**: Track via `package.json#size-limit`
173+
- **Dependencies**: De-duplicate across packages through pnpm workspace hoisting
174+
175+
### Dashboard & Playground Development
176+
177+
#### UI Component Standards
178+
- **Core components**: Import primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator)
179+
- **Navigation**: Use `NavLink` for internal navigation with automatic active states
180+
- **Organization**: Group feature-specific components under `feature/components/*` with barrel `index.ts`
181+
182+
#### Styling Conventions
183+
- **CSS framework**: Tailwind CSS only – no inline styles or CSS modules
184+
- **Class merging**: Use `cn()` from `@/lib/utils` for conditional logic
185+
- **Design tokens**: Use design system tokens (backgrounds: `bg-card`, borders: `border-border`, muted text: `text-muted-foreground`)
186+
- **Component API**: Expose `className` prop on root element for overrides
187+
188+
#### Component Architecture
189+
- **Server Components** (Node edge):
190+
- Start files with `import "server-only";`
191+
- Read cookies/headers with `next/headers`
192+
- Access server-only environment variables
193+
- Perform heavy data fetching
194+
- Implement redirect logic with `redirect()` from `next/navigation`
195+
- **Client Components** (browser):
196+
- Begin files with `'use client';`
197+
- Handle interactive UI with React hooks (`useState`, `useEffect`, React Query, wallet hooks)
198+
- Access browser APIs (`localStorage`, `window`, `IntersectionObserver`)
199+
- Support fast transitions with prefetched data
200+
201+
#### Data Fetching Patterns
202+
- **Server Side**:
203+
- Always call `getAuthToken()` to retrieve JWT from cookies
204+
- Use `Authorization: Bearer` header – never embed tokens in URLs
205+
- Return typed results (`Project[]`, `User[]`) – avoid `any`
206+
- **Client Side**:
207+
- Wrap calls in React Query (`@tanstack/react-query`)
208+
- Use descriptive, stable `queryKeys` for cache hits
209+
- Configure `staleTime`/`cacheTime` based on freshness (default ≥ 60s)
210+
- Keep tokens secret via internal API routes or server actions
211+
212+
#### Analytics Event Guidelines
213+
- **When to add**: Only create events that answer clear product/business questions
214+
- **Check duplicates**: Review `src/@/analytics/report.ts` first
215+
- **Naming**:
216+
- Event name: human-readable `<subject> <verb>` (e.g. "contract deployed")
217+
- Function: `report<Subject><Verb>` (PascalCase)
218+
- **Template**:
219+
```typescript
220+
/**
221+
* ### Why do we need to report this event?
222+
* - Tracks number of contracts deployed
223+
*
224+
* ### Who is responsible for this event?
225+
* @username
226+
*/
227+
export function reportContractDeployed(properties: {
228+
address: string;
229+
chainId: number;
230+
}) {
231+
posthog.capture("contract deployed", properties);
232+
}
233+
```
234+
- **Client-side only**: Never import `posthog-js` in server components
235+
- **Changes**: Inform **#eng-core-services** before renaming/removing events
236+
237+
### Extension Development
238+
239+
- Extensions follow modular pattern in `src/extensions/`
240+
- Auto-generated contracts from ABI definitions
241+
- Composable functions with TypeScript safety
242+
- Support for read/write operations
243+
244+
### Wallet Architecture
245+
246+
- Unified `Wallet` and `Account` interfaces
247+
- Support for in-app wallets (social/email login)
248+
- Smart wallets with account abstraction
249+
- EIP-1193, EIP-5792, EIP-7702 standard support
250+
251+
## Contribution Workflow
252+
253+
1. **Fork and Clone**: Create fork, clone, create feature branch
254+
2. **Install**: `pnpm install` (use `--ignore-scripts` on Windows)
255+
3. **Develop**: Use appropriate dev commands above
256+
4. **Test**: Write unit tests, run linting, test on demo apps
257+
5. **Changeset**: Run `pnpm changeset` for semantic versioning
258+
6. **PR**: Submit pull request to main branch
259+
260+
### Release Testing
261+
262+
Comment `/release-pr` on PR to trigger dev release to npm for testing.
263+
264+
### Changeset Guidelines
265+
266+
Each change in `packages/*` should contain a changeset for the appropriate package with the appropriate version bump:
267+
- **patch**: Changes that don't impact the public API
268+
- **minor**: Any new/modified public API
269+
- **major**: Breaking changes (surface prominently in PR descriptions)
270+
271+
### Documentation Standards
272+
273+
- For new UI components, add Storybook stories (`*.stories.tsx`) alongside the code
274+
- Surface breaking changes prominently in PR descriptions
275+
- Keep documentation focused on developer experience and practical usage
276+
277+
## Multi-Platform Support
278+
279+
The SDK supports:
280+
281+
- **Web**: React hooks and components
282+
- **React Native**: Mobile-specific exports and components
283+
- **Node.js**: Server-side functionality
284+
- **Framework Adapters**: Wagmi, Ethers compatibility layers
285+
286+
Key files:
287+
288+
- `src/exports/react.native.ts` - React Native specific exports
289+
- `packages/react-native-adapter/` - Mobile platform shims
290+
- `packages/wagmi-adapter/` - Wagmi ecosystem integration

apps/dashboard/src/@/api/getProjectContracts.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import "server-only";
2+
import { getAddress } from "thirdweb";
23
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
34

45
export type ProjectContract = {
@@ -43,3 +44,43 @@ export async function getProjectContracts(options: {
4344

4445
return data.result;
4546
}
47+
48+
export type PartialProject = {
49+
id: string;
50+
name: string;
51+
slug: string;
52+
image: string | null;
53+
};
54+
55+
/**
56+
* get a list of projects within a team that have a given contract imported
57+
*/
58+
export async function getContractImportedProjects(options: {
59+
teamId: string;
60+
authToken: string;
61+
chainId: number;
62+
contractAddress: string;
63+
}) {
64+
const url = new URL(
65+
`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/teams/${options.teamId}/projects/contracts/lookup?chainId=${options.chainId}&contractAddress=${getAddress(options.contractAddress)}`,
66+
);
67+
68+
const res = await fetch(url, {
69+
headers: {
70+
Authorization: `Bearer ${options.authToken}`,
71+
},
72+
});
73+
74+
if (!res.ok) {
75+
const errorMessage = await res.text();
76+
console.error("Error fetching: /projects/contracts/lookup");
77+
console.error(errorMessage);
78+
return [];
79+
}
80+
81+
const data = (await res.json()) as {
82+
result: PartialProject[];
83+
};
84+
85+
return data.result;
86+
}

apps/dashboard/src/@/components/contracts/import-contract/modal.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ type ImportModalProps = {
3737
onClose: () => void;
3838
teamId: string;
3939
projectId: string;
40+
projectSlug: string;
41+
teamSlug: string;
4042
client: ThirdwebClient;
4143
type: "contract" | "asset";
4244
onSuccess?: () => void;
@@ -69,7 +71,9 @@ export const ImportModal: React.FC<ImportModalProps> = (props) => {
6971
client={props.client}
7072
onSuccess={props.onSuccess}
7173
projectId={props.projectId}
74+
projectSlug={props.projectSlug}
7275
teamId={props.teamId}
76+
teamSlug={props.teamSlug}
7377
type={props.type}
7478
/>
7579
</DialogContent>
@@ -96,6 +100,8 @@ const importFormSchema = z.object({
96100
function ImportForm(props: {
97101
teamId: string;
98102
projectId: string;
103+
teamSlug: string;
104+
projectSlug: string;
99105
client: ThirdwebClient;
100106
type: "contract" | "asset";
101107
onSuccess?: () => void;
@@ -216,7 +222,7 @@ function ImportForm(props: {
216222
addContractToProject.data?.result ? (
217223
<Button asChild className="gap-2">
218224
<Link
219-
href={`/${chainSlug}/${addContractToProject.data.result.contractAddress}`}
225+
href={`/team/${props.teamSlug}/${props.projectSlug}/contract/${chainSlug}/${addContractToProject.data.result.contractAddress}`}
220226
rel="noopener noreferrer"
221227
target="_blank"
222228
>

0 commit comments

Comments
 (0)