-
Notifications
You must be signed in to change notification settings - Fork 615
Add solana transactions and wallets tables #8256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add solana transactions and wallets tables #8256
Conversation
Co-authored-by: prithvish <[email protected]>
|
Cursor Agent can help with this pull request. Just |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: b83e372 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. |
WalkthroughAdds comprehensive Solana support: new Solana types/utilities, Vault-backed Solana wallet listing/creation and permission upgrade flows, SendTestSolanaTransaction UI and modal, unified EVM+Solana transactions table and details UI, server-side Vault client helpers, and related wiring and type adjustments. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Dashboard
participant UnifiedTable as UnifiedTransactionsTable
participant Engine as Engine Cloud Proxy
User->>Dashboard: Open Transactions Analytics
Dashboard->>UnifiedTable: Render (project, team, client)
UnifiedTable->>UnifiedTable: Apply chain/filter/page
alt Active = EVM
UnifiedTable->>Engine: GET /v1/transactions?limit&page&status&id&from
Engine-->>UnifiedTable: TransactionsResponse
else Active = Solana
UnifiedTable->>Engine: GET /v1/solana/transactions?limit&page&status&id&from
Engine-->>UnifiedTable: SolanaTransactionsResponse
end
UnifiedTable-->>Dashboard: Render rows & pagination
sequenceDiagram
actor User
participant Dashboard
participant Modal as SendTestSolanaTransactionModal
participant Engine as Engine Cloud Proxy
participant Query as React Query
User->>Dashboard: Click "Send test Solana tx"
Dashboard->>Modal: Open with wallets + project
User->>Modal: Select wallet, enter token/secret, Submit
Modal->>Engine: POST /v1/solana/transactions (headers vary by vault mode)
alt Success
Engine-->>Modal: 200 OK
Modal-->>User: Success toast + auto-close
Modal->>Query: Invalidate solana-transactions
else Error
Engine-->>Modal: Error
Modal-->>User: Error toast
end
sequenceDiagram
participant Page as /transactions/tx/[id]
participant Lib as analytics.ts
participant UI as Details UI
Page->>Lib: getSingleSolanaTransaction(id)
Page->>Lib: getSingleTransaction(id)
par Parallel fetch
end
alt Solana found
Page->>Lib: getSolanaTransactionActivityLogs(id)
Lib-->>Page: logs[]
Page->>UI: SolanaTransactionDetailsUI(tx, logs)
else EVM found
Page->>Lib: getTransactionActivityLogs(id)
Lib-->>Page: logs[]
Page->>UI: TransactionDetailsUI(tx, decoded, logs)
else none
Page-->>Page: notFound()
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
Co-authored-by: prithvish <[email protected]>
size-limit report 📦
|
Co-authored-by: prithvish <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/lib/vault.client.ts (2)
79-81: Improve error message extraction.Using
JSON.stringify(response.error)produces opaque error messages. Extract a human-readable message if available.Apply this diff:
error: response.error - ? new Error(JSON.stringify(response.error)) + ? new Error(response.error.message || JSON.stringify(response.error)) : new Error("Failed to fetch Solana accounts"),Apply the same pattern at line 177 in
createSolanaAccount.
44-53: Consider logging missing configuration.The function silently returns an error when
managementAccessTokenor vault URL is missing. For debugging, consider logging a warning.if (!managementAccessToken || !NEXT_PUBLIC_THIRDWEB_VAULT_URL) { + console.warn("Vault client: missing managementAccessToken or NEXT_PUBLIC_THIRDWEB_VAULT_URL"); return {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/lib/vault.client.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/lib/vault.client.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/lib/vault.client.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/lib/vault.client.ts
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/_(e.g., Button, Input, Tabs, Card)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/lib/vault.client.ts
🧬 Code graph analysis (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/lib/vault.client.ts (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/wallet-table/types.ts (1)
SolanaWallet(1-11)apps/dashboard/src/@/constants/public-envs.ts (1)
NEXT_PUBLIC_THIRDWEB_VAULT_URL(4-5)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Size
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/lib/vault.client.ts (5)
1-9: LGTM! Server directive and imports are correct.The "use server" directive is properly placed, and imports follow the expected patterns for server-side vault integration.
11-27: Internal types are well-defined.The local interface definitions provide clear contracts for vault API responses and internal mapping.
163-168: Verify teamId usage in metadata.The function passes
teamIdin metadata (line 166), but theSolanaWallettype definition (from types.ts) does not includeteamIdin its metadata shape. Confirm whether:
- The vault API requires/stores
teamId, or- This field should be omitted or the type definition should be updated
67-67: 1-based pagination assumption verified
Callers parsesolana_pagefromsearchParams.solana_page ?? "1", sopage - 1correctly converts to Vault SDK’s 0-based index.
89-113: Use API’s totalRecords and avoid client-side pagination breakage
Client-side filtering byprojectIdskewstotalRecordsand breaks pagination. Capture and return the SDK’s total before filtering instead ofwallets.length:+ // preserve API total before filtering + const apiTotalRecords = response.data.totalRecords ?? response.data.items?.length ?? 0; return { data: { items: wallets, - totalRecords: wallets.length, + totalRecords: apiTotalRecords, }, error: null, success: true, };Prefer passing
projectIdintovaultListSolanaAccounts({ projectId, … })if the SDK supports it—confirm in the Vault SDK docs.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8256 +/- ##
=======================================
Coverage 55.01% 55.01%
=======================================
Files 919 919
Lines 60588 60588
Branches 4126 4126
=======================================
Hits 33334 33334
Misses 27150 27150
Partials 104 104
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx (1)
204-220: Sensitive tokens are still leaking intoServerWalletsTable.This client component continues to receive
managementAccessTokenand the JWT-backedclient, exposing privileged credentials to the browser. The earlier review comment on this point still applies—please move privileged actions into server actions/API routes and pass only safe callbacks/data to the client UI.
🧹 Nitpick comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx (1)
51-55: LGTM! Optional accessibility enhancement available.The implementation correctly highlights the new Transactions feature using the Badge component with proper Tailwind styling. The code follows the coding guidelines for importing UI primitives from
@/components/ui/*and using Tailwind CSS classes.Optionally, consider adding semantic context for screen readers:
label: ( - <span className="flex items-center gap-2"> - Transactions <Badge>New</Badge> + <span className="flex items-center gap-2"> + Transactions <Badge aria-label="New feature">New</Badge> </span> ),
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (11)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/analytics/send-test-solana-tx.client.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/transactions-table.client.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx(5 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx(0 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table.tsx(0 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/components/create-solana-wallet.client.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/components/upgrade-solana-permissions.client.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx(5 hunks)
💤 Files with no reviewable changes (2)
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/components/create-solana-wallet.client.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/analytics/send-test-solana-tx.client.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/transactions-table.client.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/components/upgrade-solana-permissions.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.tsapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/components/upgrade-solana-permissions.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.tsapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/components/upgrade-solana-permissions.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.tsapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/_(e.g., Button, Input, Tabs, Card)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/components/upgrade-solana-permissions.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.tsapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx
apps/{dashboard,playground}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Expose a
classNameprop on the root element of every component
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/components/upgrade-solana-permissions.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx
🧠 Learnings (3)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/components/upgrade-solana-permissions.client.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Prefer API routes or server actions to keep tokens secret; the browser only sees relative paths.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Keep tokens secret via internal API routes or server actions
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx
🧬 Code graph analysis (4)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/components/upgrade-solana-permissions.client.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts (1)
upgradeAccessTokensForSolana(804-977)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/wallet-table/types.ts (1)
SolanaWallet(1-11)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/lib/vault.client.ts (1)
listSolanaAccounts(29-129)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx (1)
ServerWalletsTable(85-320)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts (3)
apps/dashboard/src/@/hooks/useApi.ts (1)
updateProjectClient(264-289)packages/service-utils/src/node/index.ts (1)
hashSecretKey(187-189)packages/service-utils/src/core/encryption.ts (2)
decrypt(49-96)encrypt(1-47)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/wallet-table/types.ts (1)
SolanaWallet(1-11)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx (1)
ServerWalletsTable(85-320)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Size
- GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx (1)
88-88: LGTM!The simplification of the Tokens label is appropriate and aligns with the PR's focus on highlighting the new Transactions features.
| const form = useForm<FormValues>({ | ||
| defaultValues: { | ||
| secretKey: "", | ||
| }, | ||
| resolver: zodResolver(formSchema), | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Submit button stays disabled.
useForm defaults to mode: "onSubmit", so formState.isValid remains false until after a submit attempt. Because the button is disabled when !isValid, users can never submit. Set mode: "onChange" (or remove the disable check) so validity updates while typing. Example fix:
- const form = useForm<FormValues>({
+ const form = useForm<FormValues>({
+ mode: "onChange",
defaultValues: {
secretKey: "",
},
resolver: zodResolver(formSchema),
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const form = useForm<FormValues>({ | |
| defaultValues: { | |
| secretKey: "", | |
| }, | |
| resolver: zodResolver(formSchema), | |
| }); | |
| const form = useForm<FormValues>({ | |
| mode: "onChange", | |
| defaultValues: { | |
| secretKey: "", | |
| }, | |
| resolver: zodResolver(formSchema), | |
| }); |
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/components/upgrade-solana-permissions.client.tsx
around lines 41 to 46, the form is created with useForm but left at the default
mode ("onSubmit"), so formState.isValid stays false and the submit button
remains disabled; change the useForm options to include mode: "onChange" (or
alternatively remove/adjust the isValid-based disabling) so validation runs as
the user types and the submit button becomes enabled when the form is valid.
| <ServerWalletsTable | ||
| client={client} | ||
| currentPage={currentPage} | ||
| evmCurrentPage={currentPage} | ||
| evmTotalPages={Math.ceil(eoas.data.totalRecords / pageSize)} | ||
| evmTotalRecords={eoas.data.totalRecords} | ||
| evmWallets={eoas.data.items as Wallet[]} | ||
| managementAccessToken={managementAccessToken ?? undefined} | ||
| project={project} | ||
| solanaCurrentPage={solanCurrentPage} | ||
| solanaTotalPages={Math.ceil( | ||
| solanaAccounts.data.totalRecords / pageSize, | ||
| )} | ||
| solanaTotalRecords={solanaAccounts.data.totalRecords} | ||
| solanaWallets={solanaAccounts.data.items} | ||
| teamSlug={params.team_slug} | ||
| totalPages={Math.ceil(eoas.data.totalRecords / pageSize)} | ||
| totalRecords={eoas.data.totalRecords} | ||
| wallets={serverWallets ?? []} | ||
| solanaPermissionError={isSolanaPermissionError || false} | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stop sending vault tokens to the client table.
ServerWalletsTable is a client component; handing it managementAccessToken (and the JWT-backed client) leaks privileged credentials into the browser. Per dashboard guidelines we must keep these tokens server-side and expose only server actions/API routes for privileged flows. Please refactor so the page performs sensitive work on the server and the client table receives non-sensitive callbacks instead.
… of github.com:thirdweb-dev/js into cursor/add-solana-transactions-and-wallets-tables-2ff0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts (3)
775-781: Clarify param semantics in docstring (adminKey vs project secret key)Avoid confusion for ejected vaults vs non-ejected.
Apply this diff:
/** * Upgrades existing access tokens to include Solana permissions * This is needed when a project was created before Solana support was added * * Returns an object with success/error instead of throwing for Next.js server actions + * For ejected vaults: pass the Vault admin key via `projectSecretKey`. + * For non-ejected vaults: pass the project secret key used to encrypt the admin key. */
929-933: Preserve maskedAdminKey if absent (defensive)If older projects lack
maskedAdminKey, set it to avoid UI gaps.Apply this diff:
{ ...engineCloudService, managementAccessToken: managementToken.accessToken, - encryptedAdminKey, + encryptedAdminKey, encryptedWalletAccessToken, + maskedAdminKey: + engineCloudService.maskedAdminKey ?? maskSecret(adminKey), },
912-915: Optional: avoid re-encrypting unchanged adminKeyYou can keep the existing encrypted admin key and only encrypt/store the new wallet token, reducing churn.
Apply this diff:
- const [encryptedAdminKey, encryptedWalletAccessToken] = await Promise.all([ - encrypt(adminKey, projectSecretKey), - encrypt(walletToken.accessToken, projectSecretKey), - ]); + const encryptedWalletAccessToken = await encrypt( + walletToken.accessToken, + projectSecretKey, + );And update usage below:
- encryptedAdminKey, + encryptedAdminKey: engineCloudService.encryptedAdminKey, encryptedWalletAccessToken,
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/_(e.g., Button, Input, Tabs, Card)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts
🧬 Code graph analysis (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts (3)
apps/dashboard/src/@/hooks/useApi.ts (1)
updateProjectClient(264-289)packages/service-utils/src/node/index.ts (1)
hashSecretKey(187-189)packages/service-utils/src/core/encryption.ts (2)
decrypt(49-96)encrypt(1-47)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Size
- GitHub Check: Lint Packages
- GitHub Check: Build Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts (1)
3-3: Import looks correct
decryptis now used in the new upgrade flow. No issues.
| export async function upgradeAccessTokensForSolana(props: { | ||
| project: Project; | ||
| projectSecretKey?: string; | ||
| }): Promise<{ | ||
| success: boolean; | ||
| error?: string; | ||
| data?: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Handle freshly rotated secret keys (accept projectSecretHash like other path)
Without including projectSecretHash, valid just-rotated keys can be rejected. Mirror createAndEncryptVaultAccessTokens behavior.
Apply this diff:
-export async function upgradeAccessTokensForSolana(props: {
- project: Project;
- projectSecretKey?: string;
-}): Promise<{
+export async function upgradeAccessTokensForSolana(props: {
+ project: Project;
+ projectSecretKey?: string;
+ projectSecretHash?: string;
+}): Promise<{
@@
- const { project, projectSecretKey } = props;
+ const { project, projectSecretKey, projectSecretHash } = props;
@@
- const projectSecretKeyHash = await hashSecretKey(projectSecretKey);
- if (!project.secretKeys.some((key) => key?.hash === projectSecretKeyHash)) {
+ const projectSecretKeyHash = await hashSecretKey(projectSecretKey);
+ const secretKeysHashed = [
+ ...project.secretKeys,
+ ...(projectSecretHash ? [{ hash: projectSecretHash }] : []),
+ ];
+ if (!secretKeysHashed.some((key) => key?.hash === projectSecretKeyHash)) {
return {
success: false,
error: "Invalid project secret key",
};
}Run to find call sites and ensure they pass projectSecretHash where applicable:
Also applies to: 792-792, 873-876
🏁 Script executed:
#!/bin/bash
rg -nP --type=ts -C3 '\bupgradeAccessTokensForSolana\s*\('Length of output: 2247
🏁 Script executed:
#!/bin/bash
sed -n '760,840p' 'apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts'Length of output: 2300
🏁 Script executed:
#!/bin/bash
rg -n -C3 'hashSecretKey' 'apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts'Length of output: 950
Handle freshly rotated secret keys in upgradeAccessTokensForSolana
- Add
projectSecretHash?: stringto the function signature and destructuring. - In both secret-key validation blocks (around lines 255–261 and 873–876 in
vault.client.ts), buildthen matchconst secretKeysHashed = [ ...project.secretKeys, ...(projectSecretHash ? [{ hash: projectSecretHash }] : []), ];
projectSecretKeyHashagainstsecretKeysHashed. - Update all call sites (e.g.
upgrade-solana-permissions.client.tsx) to pass the newprojectSecretHashprop.
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/lib/vault.client.ts
around lines 781 to 787, the function upgradeAccessTokensForSolana must accept a
freshly rotated secret hash: add projectSecretHash?: string to the function
signature and destructuring; in both secret-key validation blocks (near lines
~255–261 and ~873–876) construct const secretKeysHashed =
[...project.secretKeys, ...(projectSecretHash ? [{ hash: projectSecretHash }] :
[])]; and then match projectSecretKeyHash against secretKeysHashed (instead of
just project.secretKeys); finally update all call sites (e.g.
upgrade-solana-permissions.client.tsx) to pass projectSecretHash when available.
Merge activity
|
[Dashboard] Feature: Add Solana Transactions and Server Wallets tables
Notes for the reviewer
This PR introduces dedicated tables for Solana transactions and server wallets on the dashboard's transactions page, mirroring the existing functionality for EVM.
Key features include:
Important: A large binary file
apps/dashboard/corewas added in this PR. This appears to be abiomebinary and should likely not be part of this PR. Please advise on its removal or purpose.How to test
Transactionspage for a project (/{team_slug}/{project_slug}/transactions).Slack Thread
PR-Codex overview
This PR focuses on enhancing Solana wallet functionality within the application. It includes the addition of new types, components, and logic for handling Solana transactions, as well as updates to existing wallet management features.
Detailed summary
tx-tableandwallet-tablecomponents.GetSolanaAccountsDatatype to useitemsinstead ofaccounts.SolanaWallettype for wallet details.statusDetailsfor transaction statuses.TransactionsTablewithUnifiedTransactionsTable.CreateSolanaWalletcomponent for wallet creation.listSolanaAccountsandcreateSolanaAccountfunctions for better account management.Summary by CodeRabbit
New Features
Bug Fixes
Style
Chores