Compare commits

..
Author SHA1 Message Date
Joaquim VergesGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
c65022174d Version Packages (#6111)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-29 22:45:20 -08:00
Phillip HoandGitHub 6818cbabf2 chore: change to per-product usageV2 topic (#6113) 2025-01-29 22:32:42 -08:00
gregfromstl a7fb844d87 [Dashboard] Fix: Remove learn more button (#6109)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on simplifying the `WalletAddress` component by removing the "Learn more" button and its associated link to the blog, while also cleaning up the imports by removing the unused `ExternalLinkIcon`.

### Detailed summary
- Removed the unused import of `ExternalLinkIcon` from `lucide-react`.
- Eliminated the "Learn more" button, which included:
  - The button element with `asChild`, `variant`, `className`, and `size` props.
  - The inner `<a>` element linking to the blog post.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-30 06:05:07 +00:00
Manan TankandGitHub bf431961ec [TOOL-3260] SDK: Fix Pay Modal logging react-query error when opened (#6104) 2025-01-29 16:59:25 -08:00
gregandGitHub c5d4cab8f8 [Portal] Fix: deployContract doc imports (#6108) 2025-01-29 16:55:21 -08:00
Joaquim VergesGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
1ee0dffec4 Version Packages (#6107)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-29 14:52:28 -08:00
Jonas DanielsandGitHub 33611409b0 update dependencies (#6106) 2025-01-29 14:34:20 -08:00
Joaquim VergesandGitHub ab55aec10c [SDK] feat: Optional wallet activation during connection (#6105) 2025-01-29 14:21:08 -08:00
Joaquim VergesGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
ca22e4659e Version Packages (#6097)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-29 12:18:06 -08:00
gregandGitHub 411895c002 [Wagmi Adapter] Fix: Fallback to smart account chain in autoconnect (#6100) 2025-01-29 11:35:51 -08:00
Jonas DanielsGitHubsaminacodesJoaquim Vergesgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>samina
cfa1c20a91 Saminacodes patch 1 (#6103)
Co-authored-by: saminacodes <[email protected]>
Co-authored-by: Joaquim Verges <[email protected]>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: samina <[email protected]>
2025-01-29 11:34:04 -08:00
Jonas DanielsGitHubsaminaJoaquim Vergesgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>samina
2b16f90715 Open ai docs (#6102)
Co-authored-by: samina <[email protected]>
Co-authored-by: Joaquim Verges <[email protected]>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: samina <[email protected]>
2025-01-29 11:33:18 -08:00
Jonas DanielsGitHubJoaquim Vergesgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
e8892b152f Pass team instead of project to rate limit (#6101)
Co-authored-by: Joaquim Verges <[email protected]>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-29 11:32:13 -08:00
Joaquim VergesGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
073b25afd7 Version Packages (#6083)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-28 17:40:13 -08:00
Joaquim VergesandGitHub 4550bb2663 [SDK] feat: Expose Account and Wallet components in React Native (#6082) 2025-01-28 16:29:50 -08:00
Manan TankandGitHub f5f8a40320 [TOOL-3251] Dashboard: Add Rotate Secret Key feature in Project Settings page (#6087) 2025-01-28 14:21:25 -08:00
Joaquim VergesandGitHub 3569763501 [Dashboard] fix: Use API key for in-app wallet analytics (#6086) 2025-01-29 09:44:02 +13:00
Joaquim VergesandGitHub 1401f8d039 [SDK] fix: Auto-connection of in-app wallets in React Native (#6076) 2025-01-29 07:13:09 +13:00
Jonas DanielsandGitHub 1616b7f619 update dependencies (#6079) 2025-01-27 23:08:39 -08:00
saminaandGitHub aa548a359f Nebula docs (#6080) 2025-01-27 19:22:38 -08:00
Jonas DanielsandGitHub eef52dfa7e update plan selection copy and tracking (#6078) 2025-01-27 16:56:30 -08:00
Joaquim VergesandGitHub 19ec571500 chore: Update PR template format (#6077) 2025-01-28 13:13:07 +13:00
Jonas DanielsandGitHub 47dce2e05c remove growth trial eligibility (#6070) 2025-01-27 15:13:51 -08:00
Joaquim VergesGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
8b4695224c Version Packages (#6075)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-28 12:00:53 +13:00
Joaquim VergesandGitHub 94e2d5b8dd [SDK] fix: Account linking for ecosystem smart wallets (#6074) 2025-01-28 11:44:05 +13:00
Joaquim VergesGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
40fa323294 Version Packages (#6073)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-28 11:02:56 +13:00
Joaquim VergesandGitHub 2cebb420e6 [SDK] fix: Show link profiles for ecosystem smart wallets (#6072) 2025-01-28 10:59:05 +13:00
Joaquim VergesandGitHub e89ddb24f2 [SDK] fix: Update ecosystem name and admin wallet handling (#6071) 2025-01-28 10:54:27 +13:00
Joaquim VergesGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
86f205e2aa Version Packages (#6069)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-28 10:14:31 +13:00
Joaquim VergesandGitHub 6c277ae676 [SDK] fix: Respect chain param in in-app wallet connection (#6068) 2025-01-28 09:57:07 +13:00
MananTank 153651df35 [TOOL-3241] Fix previous account shown after logging out in onboarding flow (#6061) 2025-01-27 19:49:51 +00:00
MananTank 8ba460b6fc [NEB-77] Nebula: Various UI updates (#6060) 2025-01-27 18:18:13 +00:00
MananTank 1e61a9edfc [TOOL-3238] Fix Engine backend wallet balances not updating on chain change (#6059) 2025-01-27 17:00:48 +00:00
MananTank d03e687aa9 [TOOL-3231] Show View Project Link after creating a project in Modal (#6055)
<!-- start pr-codex -->

## PR-Codex overview
This PR introduces the `teamSlug` prop across multiple components to enhance API key management by associating it with specific teams. This allows for better project handling and user navigation within the dashboard.

### Detailed summary
- Added `teamSlug` prop to `CreateAPIKeyModal` and related components.
- Updated `embed-setup.tsx` to handle `teamSlug` as `undefined`.
- Integrated `teamSlug` in `TeamProjectsPage` and `AccountHeader`.
- Modified `CreateAPIKeyDialog` to include `teamSlug` in props.
- Enhanced `APIKeyDetails` to fetch projects based on `teamSlug`.
- Implemented conditional rendering for "View Project" button based on `teamSlug`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-27 09:52:19 +00:00
Joaquim VergesandGitHub e1c0dbe19e [SDK] chore: Increase CJS bundle size limit to 130kb (#6058) 2025-01-27 20:42:56 +13:00
Joaquim VergesGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
3e7df081d7 Version Packages (#6048)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-27 20:41:53 +13:00
Joaquim VergesandGitHub b6f189c220 [SDK] update dependencies (#6057) 2025-01-27 16:48:24 +13:00
Phillip HoandGitHub fb4d0a26f1 [service-utils] Replace client_id with project_id in usage_v2 (#6050) 2025-01-24 17:02:15 +08:00
Phillip HoandGitHub bc345371ba [service-utils] usage_v2 accepts a project_id field (#6049) 2025-01-24 16:44:26 +08:00
Phillip HoandGitHub 7a8e4e5f86 [service-utils] Export UsageV2 helpers (#6047) 2025-01-24 15:55:41 +08:00
Joaquim VergesGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
6ba3b30b60 Version Packages (#6030)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-24 15:08:14 +13:00
Joaquim VergesandGitHub 5ad442cf0c [SDK] fix: Simplify in-app wallet logout flow (#6046) 2025-01-24 14:49:15 +13:00
Phillip HoandGitHub 5756c74a71 [service-utils] feat: Add usageV2 support (#6021) 2025-01-24 08:52:35 +08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
a1cff7a579 build(deps-dev): bump checkly from 4.15.0 to 4.18.0 (#6045)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-24 13:46:30 +13:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
eafaefec20 build(deps-dev): bump vite from 6.0.10 to 6.0.11 in the npm_and_yarn group (#6022)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-24 13:37:31 +13:00
Manan TankandGitHub b81d7a1854 [TOOL-3207] Portal: Delete V4 SDK pages, Setup knip lint, Fix lint config (#6039) 2025-01-24 13:37:03 +13:00
Winston YeoandGitHub 21cc45adc2 Winston/tool 3161 cannot create backend wallets using latest version (#6025) 2025-01-24 13:36:33 +13:00
Joaquim VergesandGitHub a67d342779 [SDK] fix: Improve smart wallet signature verification (#6040) 2025-01-24 13:35:58 +13:00
Joaquim VergesandGitHub 60edce49c0 [SDK] fix: Improve WalletConnect mobile connection handling (#6042) 2025-01-24 13:35:31 +13:00
Joaquim VergesandGitHub 20c0dca958 [Portal] fix: Update useAutoConnect hook reference link (#6043) 2025-01-24 13:35:11 +13:00
Joaquim VergesandGitHub 4b30b847e2 [Dashboard] fix: Use formatted ABI for contract function calls (#6044) 2025-01-24 13:34:47 +13:00
MananTank b2cc17fd1e [TOOL-3220] Dashboard: Reset Project pagination on filter change, SDK: Fix WalletProvider JSDoc (#6041) 2025-01-23 23:58:47 +00:00
MananTank ace1dc5b09 [TOOL-3124] Dashboard: paginate projects, sort by Montly active users (#6027)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on enhancing the project analytics in the dashboard by changing how project data is retrieved and displayed. It updates the calculation of user connections to reflect monthly active users and introduces pagination for project listings.

### Detailed summary
- Replaced `getProjectsWithTotalWallets` with `getProjectsWithAnalytics`.
- Updated project data structure to include `monthlyActiveUsers` instead of `totalConnections`.
- Introduced pagination in the `TeamProjectsPage` component.
- Changed sorting criteria from `totalConnections` to `monthlyActiveUsers`.
- Updated UI elements to reflect the new data fields.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-23 12:09:59 +00:00
Joaquim VergesandGitHub 9f79277344 [Dashboard] perf: Optimize chain and contract data processing (#6035) 2025-01-23 13:47:14 +13:00
MananTank 6e0fd205ff [TOOL-2964] Dashboard: Fix crash on unix time converter page for invalid unix time, UI improvements (#6036)
=
2025-01-22 23:58:04 +00:00
MananTank 69b1ee9176 [TOOL-3082] Dashboard: Replace NetworkSelectorButton with SingleNetworkSelector where switching chain in wallet is not required (#6031)
<!-- start pr-codex -->

## PR-Codex overview
This PR introduces enhancements to the `SingleNetworkSelector` component and its usage across various files. It adds new props for alignment and positioning, replaces existing network selector buttons, and integrates chain ID handling in several components.

### Detailed summary
- Added `side`, `disableChainId`, and `align` props to `SingleNetworkSelector`.
- Updated `SingleNetworkSelector` to conditionally render the chain ID badge.
- Replaced `NetworkSelectorButton` with `SingleNetworkSelector` in multiple components.
- Integrated `chainId` state management using `useState` in `BackendWalletsSection` and `ImportForm`.
- Updated `BackendWalletsTable` and `BackendWalletBalanceCell` to accept `chainId` as a prop.
- Changed the way active chains are retrieved with `useActiveChainAsDashboardChain` to `useV5DashboardChain`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-22 23:48:14 +00:00
MananTank 0a19142a24 [TOOL-3120] Redirect to last visited team page if authenticated (#6028) 2025-01-22 23:39:05 +00:00
MananTank feb4fd0908 [TOOL-3123] Dashboard: Order projects by total wallets (#6026)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on enhancing the `CopyTextButton` component, optimizing the project fetching logic, and improving project display features by integrating total wallet connections in the dashboard.

### Detailed summary
- Changed `tooltip` type in `CopyTextButton` to `string | undefined`.
- Updated the API call in `getChangelog` to limit results to 7.
- Replaced cookie-based token retrieval with `getAuthToken` in `getProjects`.
- Added `getProjectsWithTotalWallets` to calculate total wallet connections.
- Updated `TeamProjectsPage` to display projects with total connections.
- Modified sorting logic in `TeamProjectsPage` to include total connections.
- Replaced `CopyButton` with `CopyTextButton` in `ProjectCard`.
- Enhanced project display to show total users.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-22 23:30:11 +00:00
gregfromstl 1d8695eb42 [SDK] Fix: Opt out of 1559 on lumia mainnet (#6032)
<!-- start pr-codex -->

## PR-Codex overview
This PR adds support for the `Lumia Mainnet` in the fee data configuration.

### Detailed summary
- Added a new entry for `Lumia Mainnet` in the fee data array.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-22 22:34:34 +00:00
Joaquim VergesandGitHub 858dc53a25 [Dashboard] fix: Add error reason to analytics API error logs (#6034) 2025-01-23 11:34:16 +13:00
Joaquim VergesandGitHub 8997fac1b0 [Dashboard] fix: Improve error logging for analytics API failures (#6033) 2025-01-23 11:25:35 +13:00
gregfromstl 403e4224e4 Chore: Remove Jakub from CODEOWNERS (#6029)
<!-- start pr-codex -->

## PR-Codex overview
This PR modifies the `.github/CODEOWNERS` file to remove a specific code owner from the `apps/` directory.

### Detailed summary
- Removed `@jakubkrehel` as a code owner for the `apps/` directory.
- Retained `@thirdweb-dev/developer-tools` and `@thirdweb-dev/core-platform` as code owners for the `apps/` directory.
- `scripts/` code ownership remains unchanged with `@jnsdls` and `@joaquim-verges`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-22 20:17:33 +00:00
Phillip HoandGitHub de039ef462 [service-utils] fix: Don't hash cache key (#6023) 2025-01-23 04:16:16 +08:00
Joaquim VergesandGitHub 35fd3bcafa [Dashboard] feat: Add transaction analytics and tracking (#6019) 2025-01-23 08:36:04 +13:00
MananTank 80a22ff45e [TOOL-3173] Portal: Update hero iamge, OG image on landing page (#6017) 2025-01-22 21:46:05 +05:30
Joaquim VergesGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
eefa2ab424 Version Packages (#6018)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-22 17:40:37 +13:00
Joaquim VergesandGitHub ab9a148b75 [SDK] feat: Add transaction tracking for smart wallets (#6020) 2025-01-22 17:12:38 +13:00
gregandGitHub 8bbee03c77 [SDK] Fix: Allow smart wallets for site linking (#6015) 2025-01-21 17:02:11 -08:00
gregandGitHub b38604cce8 [SDK] Fix: Do not remove chain listener on disconnect (#6011) 2025-01-21 15:45:55 -08:00
MananTank 59eda22043 [TOOL-3066] Dashboard: Fix 404 on example asset files, robots.txt, sitemap.xml (#6014) 2025-01-21 21:17:22 +00:00
MananTank 577636c037 [TOOL-3156] Dashboard: Fix localhost engine not loading, fetch engine permission on client side (#6013)
<!-- start pr-codex -->

## PR-Codex overview
This PR enhances the engine access permission handling in the dashboard. It introduces a new component, `EnsureEnginePermission`, which checks permissions before rendering engine details and handles various error states more effectively.

### Detailed summary
- Added `account` to the return object in `getEngineInstancePageMeta.ts`.
- Improved URL handling in `getEngineAccessPermission.ts`.
- Introduced `EnsureEnginePermission` component.
- Replaced direct permission checks in `Layout` with `EnsureEnginePermission`.
- Removed `EngineInstanceLayoutContent` component.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-21 20:50:21 +00:00
jnsdls 1d844ac5d6 add connect/pay to framer rewrites (#6012)
closes: CORE-708

### TL;DR
Added `/connect/pay` route to Framer rewrites

### What changed?
Added a new route `/connect/pay` to the list of Framer rewrites in the dashboard application

### How to test?
1. Navigate to `/connect/pay` in the dashboard
2. Verify the route resolves correctly
3. Ensure the page loads without any routing errors

### Why make this change?
To enable proper routing and rendering of the new payment page in the Connect section of the dashboard
2025-01-21 19:21:28 +00:00
MananTank c7be92f75b [TOOL-3166] Update portal theming to match dashboard (#6010)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on updating the styling and structure of various components in the `apps/portal` project, enhancing UI consistency and accessibility. It introduces color changes, layout adjustments, and modifies several components' props for better integration.

### Detailed summary
- Deleted `docs-hero.png` and `docs-hero.svg`.
- Updated `fill` attribute in `UnrealEngineIcon.tsx` and `UnityIcon.tsx` to `currentColor`.
- Changed color definitions in `layout.tsx` and several components to use `text-foreground` and `text-muted-foreground`.
- Modified class names in `Paragraph.tsx`, `InlineCode.tsx`, and `Document` components for improved styling.
- Adjusted button classes in `Button.tsx` and `Feedback.tsx` for consistency.
- Refactored links to use `DocLink` for better routing.
- Updated `Callout` component styling to use `bg-card`.
- Enhanced accessibility features across various components by modifying text colors and ensuring proper contrast.
- Modified `tailwind.config.ts` to introduce new color variables for better theme management.
- Improved layout consistency in multiple `page.mdx` files by adjusting grid gaps and spacing.

> The following files were skipped due to too many changes: `apps/portal/src/app/contracts/deploy/overview/page.mdx`, `apps/portal/src/components/others/ScrollShadow/ScrollShadow.tsx`, `apps/portal/src/components/ui/select.tsx`, `apps/portal/src/components/others/Sidebar.tsx`, `apps/portal/src/app/contracts/explore/pre-built-modular/token-drop/page.mdx`, `apps/portal/src/components/others/DocSearch.tsx`, `apps/portal/src/icons/products/nebula/NebulaIcon.tsx`, `apps/portal/src/app/contracts/explore/pre-built-modular/nft-drop/page.mdx`, `apps/portal/src/app/connect/wallet/overview/page.mdx`, `apps/portal/src/app/globals.css`, `apps/portal/src/app/page.tsx`, `apps/portal/src/app/contracts/explore/pre-built-modular/edition-drop/page.mdx`, `apps/portal/src/icons/sdks/ReactIcon.tsx`, `apps/portal/src/app/contracts/explore/pre-built-modular/edition/page.mdx`, `apps/portal/src/app/contracts/explore/pre-built-modular/nft-collection/page.mdx`, `apps/portal/src/app/Header.tsx`

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-21 19:11:53 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>greg
79ed399e56 build(deps-dev): bump @types/react-dom from 19.0.2 to 19.0.3 (#6000)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: greg <[email protected]>
2025-01-21 21:05:25 +13:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ded5e22bb7 build(deps-dev): bump tailwindcss from 3.4.16 to 3.4.17 (#6001)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-21 21:05:10 +13:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
5029345461 build(deps-dev): bump vite from 6.0.3 to 6.0.10 (#6002)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-21 21:04:57 +13:00
Joaquim VergesGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
c9ccc59464 Version Packages (#6003)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-20 17:47:15 -08:00
gregfromstl dc05f2ea3c [SDK]Fix: use base autoconnect in wagmi adapter (#6005)
<!-- start pr-codex -->

## PR-Codex overview
This PR introduces minor updates to the `@thirdweb-dev/wagmi-adapter` package, enhancing the autoconnection feature to accept URL token parameters and making adjustments to the package's metadata.

### Detailed summary
- Added support for URL token parameters in the autoconnection feature within `packages/wagmi-adapter/src/connector.ts`.
- Updated the `autoConnect` function call to include `wallets: [wallet]`.
- Minor updates to the `package.json` file's metadata and dependencies.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-21 01:13:26 +00:00
Joaquim VergesandGitHub 7d9986f066 [Dashboard] fix: handle unreachable engine instances (#6006) 2025-01-21 14:00:59 +13:00
Joaquim VergesandGitHub bb6c71e968 fix: fallback to eip1193 provider chain when switching chains is not supported (#6004) 2025-01-21 13:59:32 +13:00
Giselle Chacon NessiandGitHub 89beb3c5d3 enhance manage billing visibility in dashboard (#5990) 2025-01-21 11:44:54 +13:00
Giselle Chacon NessiandGitHub 3b98fbf8bb fix: default option tab in docs (#5991) 2025-01-21 11:42:21 +13:00
gregandGitHub 8b5cb47339 [SDK] Feature: Adds deployMarketplaceContract (#5989) 2025-01-20 14:17:21 -08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
0760706dbb build(deps-dev): bump @storybook/react from 8.4.7 to 8.5.0 (#5995)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-20 13:21:00 -08:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
eded4ff1be Version Packages (#5955)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-18 22:37:50 +13:00
Joaquim VergesandGitHub b705406c5d [Dashboard] fix: Update dashboard redirect paths to /team (#5986) 2025-01-18 22:05:04 +13:00
gregfromstl 17374d15f2 [Portal] Fix: Supported Chains Page (#5975)
TOOL-3130
2025-01-18 06:59:19 +00:00
MananTank 79769d6859 [TOOL-3054] Dashboard: Fix Engine backend wallet list not updating on create/delete (#5983) 2025-01-17 22:35:10 +00:00
gregfromstl b6d65cf1c4 [SDK] Feature: Add Mode chain definition (#5982)
---
title: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"
---

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer
Anything important to call out? Be sure to also clarify these in your comments.

## How to test
Unit tests, playground, etc.

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces a new blockchain chain called `mode` to the `thirdweb` package, enhancing the available options for developers.

### Detailed summary
- Added `mode` as a predefined chain in `packages/thirdweb/src/chains/chain-definitions/mode.ts`.
- Exported `mode` from `packages/thirdweb/src/exports/chains.ts`.
- Defined `mode` with properties such as `id`, `name`, `nativeCurrency`, and `blockExplorers`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-17 22:25:40 +00:00
saminaandGitHub a92617f0b0 docs cleanup (#5981) 2025-01-18 11:24:45 +13:00
MananTank 8e82ec860c [TOOL-3119] Dashboard: Move Connect settings from Project settings to Connect pages (#5980)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on restructuring and enhancing the routing and layout of the `settings` pages within the dashboard, as well as integrating new components for better user experience in the `account-abstraction` section.

### Detailed summary
- Added a new `Settings` route in multiple layout files.
- Refactored paths in `ProjectGeneralSettingsPageForTeams` to point to the new settings structure.
- Updated imports to reflect the new file structure for components.
- Introduced `AccountAbstractionAnalytics` and `AccountAbstractionSummary` components.
- Modified layout components to improve styling and organization.
- Replaced `AccountAbstractionPage` with `AccountAbstractionLayout` for better structure.
- Implemented loading states for API calls in `AccountAbstractionSettingsPage`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-17 22:00:23 +00:00
Joaquim VergesandGitHub 0b6239735e [SDK] feat: Support multiple messages in Nebula API and update input props (#5972) 2025-01-18 10:37:17 +13:00
MananTank df4da68d68 [TOOL-3128] SDK: Fix typo in deployPublishedContract JSDoc example (#5977) 2025-01-17 21:10:03 +00:00
MananTank 94ba9cf7aa [TOOL-3091] Dashboard: Remove trending contracts, Hide Contract Search (#5978) 2025-01-17 21:01:03 +00:00
gregfromstl 1b64d6eb2d [Playground] Feature: Adds smart account auth (#5979)
---
title: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"
---

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer
Anything important to call out? Be sure to also clarify these in your comments.

## How to test
Unit tests, playground, etc.

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces a new smart account authentication feature in the `playground-web` application, allowing users to sign in using Ethereum. It adds a new component for the authentication button and integrates it into the main application page.

### Detailed summary
- Added `SmartAccountAuthButton` component for Ethereum authentication.
- Implemented `SmartAccountAuthPreview` to display JWT cookies.
- Updated `page.tsx` to include `SmartAccountAuth` section.
- Added a code example demonstrating the authentication button usage.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-17 20:35:18 +00:00
MananTank f1afa3b52d [TOOL-3112]: Various Engine Overview page improvements, Chart style adjustments, Improved Pagination component (#5976)
<!-- start pr-codex -->

## PR-Codex overview
This PR primarily focuses on improving the styling and functionality of various chart components, enhancing pagination controls, and refining transaction details presentation in the dashboard application.

### Detailed summary
- Added `strokeWidth` and `className` properties to several chart components for consistent styling.
- Updated pagination components to include input for direct page navigation.
- Enhanced transaction details with improved layout and added tooltips.
- Refined UI elements for better visibility and usability across various components.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-17 19:09:58 +00:00
kumaryash90 dbb64ea190 [SDK] Update implementations (#5973)
TOOL-3135

## Notes for the reviewer
Anything important to call out? Be sure to also clarify these in your comments.

## How to test
Unit tests, playground, etc.

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the implementations for `MarketplaceV3` and `ZKSYNC_WETH` in the `thirdweb` package, specifically for the `zksync` deployment.

### Detailed summary
- Added a new entry for `MarketplaceV3` with the address `0x9EB0830B0b10010F2a53383517A7D0B75531Bb1b` for the network ID `[555271]`.
- Added a new entry for `ZKSYNC_WETH` with the address `0xb0b8b267d44c64BA6dD1Daf442949887c85199f6` for the network ID `[555271]`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-17 16:09:44 +00:00
Joaquim VergesandGitHub eed734c766 [SDK] feat: Add pay event tracking for transaction modal states (#5971) 2025-01-17 13:11:41 +13:00
MananTank a3a3062ae1 [TOOL-3111] Nebula: Add events on transaction button (#5970) 2025-01-16 21:55:22 +00:00
MananTank 4ffcf305ab [TOOL-3096] React SDK: Fix NFT components not including contract address in queryKey (#5966)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on improving the handling of NFT metadata in the `thirdweb` library by adding `contractAddress` to various query keys, which resolves issues with metadata caching when multiple contracts share the same token ID.

### Detailed summary
- Added `contractAddress` to the query keys in `getQueryKey` functions for `NFTName`, `NFTMedia`, and `NFTDescription`.
- Updated related queries to include `contractAddress`.
- Fixed metadata display issues when rendering multiple contracts with the same token ID.
- Enhanced tests in `name.test.tsx` and `media.test.tsx` to validate the new `contractAddress` parameter.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-16 20:48:24 +00:00
MananTank fe3f24e309 [TOOL-3110] Dashboard: Engine pages cleanup: Fetch engine info on server + Use layout (#5968)
Engine pages were in a weird "pages router" type of state - Its now properly migrated to app router

* Common skeleton is moved to layout
* engine instances are fetched on server

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring and enhancing the engine instance management in the application. It removes obsolete files, improves error handling, and introduces new utility functions for fetching engine instances and permissions.

### Detailed summary
- Deleted multiple obsolete `.tsx` files related to engine instance management.
- Improved error handling in engine import functionality.
- Added `getEngineAccessPermission` and `getEngineInstances` utility functions.
- Refactored components to utilize new utility functions for fetching engine data.
- Enhanced the layout and error handling in the engine instance pages.
- Updated components to use consistent instance data and permissions checks.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-16 20:34:33 +00:00
Joaquim VergesandGitHub 9f5510018e docs: Reorder sidebar groups and update claim params tags (#5969) 2025-01-17 09:33:39 +13:00
73894d23b9 [Dashboard] - Update copyright year to 2025 (#5936)
Co-authored-by: Joaquim Verges <[email protected]>
Co-authored-by: greg <[email protected]>
2025-01-16 12:14:34 -08:00
saminacodes 4538441334 nebula doc restructure (#5964)
---
title: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"
---

NEB-73

## Notes for the reviewer
Mostly documentation changes to add Nebula restructure and also add tutorial for the Eliza Plugin

## How to test
View preview.

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the `Nebula` documentation and user experience by adding new content, updating existing descriptions, and introducing a new `RocketIcon`. It also restructures the sidebar and adds new pages for getting started and Eliza plugin integration.

### Detailed summary
- Added new `RocketIcon` to the `sidebar`.
- Updated `Nebula` description in `page.mdx` for improved clarity.
- Introduced `get-started` page with setup instructions for the `Nebula API`.
- Improved `Eliza` plugin documentation with new prerequisites and setup steps.
- Updated sidebar links and removed the old `Use Cases` section.
- Added images for better visual guidance in documentation.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-16 19:32:28 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Joaquim Verges
913f2e4366 Bump shiki from 1.24.2 to 1.27.0 (#5953)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Joaquim Verges <[email protected]>
2025-01-17 08:24:49 +13:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
da4ba21a52 build(deps-dev): bump react-native from 0.76.5 to 0.76.6 (#5943)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-17 08:23:49 +13:00
MananTank 8d9854daf1 [TOOL-3095] Portal: Enable Table of contents in Nebula pages, Adjust TOC component (#5965)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on refining the `Layout` component's structure and updating the styling for the `TOCLink` component to enhance the user interface.

### Detailed summary
- In `Layout`, the `DocLayout` component now wraps `props.children` directly without unnecessary line breaks.
- In `TOCLink`, the `data-active` class styling was changed from `text-accent-500` to `text-f-100` for active links.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-16 18:51:34 +00:00
gregandGitHub 9cbcbe7760 [SDK] Fix: Lumia Testnet is pre-1559 (#5967) 2025-01-16 10:51:16 -08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Joaquim Verges
00f1d29654 build(deps-dev): bump eslint-config-next from 15.1.2 to 15.1.4 (#5942)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Joaquim Verges <[email protected]>
2025-01-16 20:28:18 +13:00
MananTank b511a695f9 [TOOL-3056]: Add Engine transactions bar chart, Make shadcn table header sticky (#5963)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on enhancing the user interface and functionality of various components in the dashboard application, particularly around data visualization and table displays.

### Detailed summary
- Updated `chartClassName` for better aspect ratio in multiple chart components.
- Added `tableScrollableClassName` and `tableContainerClassName` to improve table layouts.
- Modified text in `engine-overview.tsx` for clarity.
- Introduced new props in `ThirdwebBarChart` for customizable tooltips and titles.
- Implemented data processing logic in `TransactionsTable` for analytics display.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-16 01:52:15 +00:00
MananTank ea34a975ca [TOOL-3090] Dashboard: Add Deprecated alert in Embeds page, UI adjustments (#5960)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on updating the `EmbedSetup` component to enhance user experience by introducing a deprecation alert for NFT embeds, reorganizing the UI layout, and adding new configuration options.

### Detailed summary
- Added an `Alert` component indicating the deprecation of thirdweb NFT Embeds.
- Replaced `Flex` with `div` for layout simplification.
- Consolidated form controls for configuration and added new fields for `Client ID`, `RPC Url`, and `Gasless` options.
- Introduced a theme selection dropdown.
- Updated embed code section and preview area for clarity.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-16 01:52:13 +00:00
Joaquim VergesandGitHub a834199dac [SDK] test: Refactor smart wallet signature verification tests (#5962) 2025-01-16 14:46:18 +13:00
MananTank be7759d2fe [TOOL-3075] Dashboard: Adjust theming, Improved light mode (#5956)
Fix "inverted look" of light mode - light mode now correctly has a slightly dark background and lighter cards on top

* Instead of `bg-muted/50`, use `bg-card` instead. `--card` color is updated
* For cards that are links, don't change the background color on hover - apply a subtle border change instead - added a `--active-border` for this - this looks great in both light and dark mode
* Prefer using `bg-accent` for hover effects instead of `bg-muted` (even though they are currently both same color) for adding hover accent. Use `bg-accent/50` for applying a very subtle accent - use cases: clickable table row

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the styles of various components in the application to replace the `bg-muted` class with `bg-card`, enhancing the visual consistency across the UI.

### Detailed summary
- Changed `className` from `bg-muted/50` to `bg-card` in multiple components.
- Updated hover effects from `hover:bg-muted` to `hover:bg-card`.
- Modified background colors in various layouts to use `bg-card` instead of `bg-muted`.
- Adjusted button and input styles for consistent theming.

> The following files were skipped due to too many changes: `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/table.tsx`, `apps/dashboard/src/components/configure-networks/ConfigureNetworkForm.tsx`, `apps/dashboard/src/app/team/[team_slug]/[project_slug]/insight/[blueprint_slug]/blueprint-playground.client.tsx`, `apps/dashboard/src/@/styles/globals.css`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/embed/embed-setup.tsx`, `apps/dashboard/src/components/pay/PayAnalytics/PayAnalytics.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/chainlist/components/client/filters.tsx`, `apps/dashboard/src/app/components/sdk-component-theme.ts`, `apps/dashboard/src/components/settings/ApiKeys/Create/index.tsx`, `apps/dashboard/src/app/team/components/Analytics/EmptyState.tsx`, `apps/dashboard/src/components/settings/Account/Billing/CreditsItem.tsx`

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-16 01:08:04 +00:00
MananTank 15178b2f96 [NEB-71] Nebula: Update example prompts (#5957)
<!-- start pr-codex -->

## PR-Codex overview
This PR introduces a new type `ExamplePrompt` and a list of example prompts in `examplePrompts.ts`. It replaces hardcoded example prompts in `EmptyStateChatPageContent.tsx` with a dynamic mapping from the newly created `examplePrompts`, enhancing maintainability and readability.

### Detailed summary
- Added type `ExamplePrompt` with `title` and `message` properties.
- Created `examplePrompts` array containing several example prompts.
- Refactored `EmptyStateChatPageContent.tsx` to dynamically render `ExamplePrompt` components using `examplePrompts`.
- Removed hardcoded example prompts from `EmptyStateChatPageContent.tsx`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-16 00:38:38 +00:00
Joe-Thirdweb afd0ccfdfd [Dashboard] Feature: Chainlist page updates (#5959)
---
title: "[Dashboard] Feature: Chainlist page updates"
---

Issue Tags:
INFRA-610
INFRA-698
XSOL-1806
XSOL-1824
INFA-676
XSOL-1046
XSOL-1086

## Notes for the reviewer

Updated Chain Page Banners, About, and CTA:
- EVM on Flow Mainnet/Testnet-> All updated
- Lisk Mainnet/Testnet -> Banner update
- Plume Mainnet/Testnet -> Banner update
- Rivalz Mainnet/Testnet -> All updated
- Saakuru Mainnet/Testnet -> All updated
- Viction Mainnet/Testnet -> All updated
- Worldchain Mainnet/Testnet -> All updated
- Soneium Mainnet -> All updated

Adding OP Superchain banner:
- Celo
- Metal L2
- Ozean
- Unichain
- Worldchain
- Sonium

## How to test
Visit the chain pages for each chain.

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the asset imports and metadata for various blockchain networks, including adding new assets for `Flow`, `Rivalz`, `Saakuru`, `Viction`, and `World Chain`, while removing outdated assets and enhancing descriptions for some blockchain networks.

### Detailed summary
- Added imports for new assets: `flowBanner`, `flowCTA`, `rivalzBanner`, `rivalzCTA`, `saakuruBanner`, `saakuruCTA`, `victionBanner`, `victionCTA`, `worldChainBanner`, `worldChainCTA`.
- Removed imports for deleted assets: `plumev2Banner`, `plumev2CTA`.
- Updated `chainMetaRecord` to include new entries for `Flow`, `Rivalz`, `Saakuru`, `Viction`, and `World Chain`.
- Enhanced descriptions for `Flow`, `Rivalz`, `Saakuru`, and `Viction`.
- Deprecated the `Plume` entries and updated their descriptions.
- Removed commented-out code related to `fhenix` and `metal` CTAs.
- Added gas sponsorship for several blockchain entries.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-01-15 23:57:35 +00:00
gregandGitHub 07a5c98b5b [Dashboard] Fix: AA Testnet Transaction Count (#5958) 2025-01-15 15:56:58 -08:00
Joaquim VergesandGitHub 51a28c4ed6 [SDK] test: Skip Nebula AI tests by default (#5961) 2025-01-16 12:11:12 +13:00
Nischit Prasad Nhuchhe PradhanandGitHub c290997b11 track ratelimit only on creation (#5950) 2025-01-15 15:17:12 +08:00
933 changed files with 15707 additions and 746293 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ packages/eslint-config-thirdweb/ @thirdweb-dev/core-platform @edwardysun
packages/tw-tsconfig/ @thirdweb-dev/core-platform @edwardysun
# apps
apps/ @thirdweb-dev/developer-tools @thirdweb-dev/core-platform @jakubkrehel
apps/ @thirdweb-dev/developer-tools @thirdweb-dev/core-platform
# .github folder + .changeset + turbo config is owned by jonas for now
scripts/ @jnsdls @joaquim-verges
+6 -3
View File
@@ -1,12 +1,15 @@
---
title: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"
---
<!--
## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"
If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):
## Notes for the reviewer
Anything important to call out? Be sure to also clarify these in your comments.
## How to test
Unit tests, playground, etc.
-->
+5 -1
View File
@@ -27,5 +27,9 @@
},
"[css]": {
"editor.defaultFormatter": "biomejs.biome"
}
},
"eslint.workingDirectories": [
{ "pattern": "./packages/*/" },
{ "pattern": "./apps/*/" }
]
}
+1
View File
@@ -9,6 +9,7 @@ module.exports = [
// -- connect
"/connect",
"/connect/sign-in",
"/connect/pay",
// -- nebula
"/nebula",
// --insight
+3 -1
View File
@@ -3,7 +3,9 @@
"next": true,
"ignore": [
"src/@/components/ui/**",
"src/components/notices/AnnouncementBanner.tsx"
"src/components/notices/AnnouncementBanner.tsx",
"src/components/cmd-k-search/index.tsx",
"src/lib/search.ts"
],
"project": ["src/**"],
"ignoreBinaries": ["only-allow", "biome"],
+45 -45
View File
@@ -31,29 +31,29 @@
"@marsidev/react-turnstile": "^1.1.0",
"@n8tb1t/use-scroll-position": "^2.0.3",
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-alert-dialog": "^1.1.4",
"@radix-ui/react-alert-dialog": "^1.1.5",
"@radix-ui/react-avatar": "^1.1.2",
"@radix-ui/react-checkbox": "^1.1.3",
"@radix-ui/react-dialog": "1.1.4",
"@radix-ui/react-dropdown-menu": "^2.1.3",
"@radix-ui/react-hover-card": "^1.1.3",
"@radix-ui/react-dialog": "1.1.5",
"@radix-ui/react-dropdown-menu": "^2.1.5",
"@radix-ui/react-hover-card": "^1.1.5",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-popover": "^1.1.3",
"@radix-ui/react-popover": "^1.1.5",
"@radix-ui/react-progress": "^1.1.1",
"@radix-ui/react-radio-group": "^1.2.2",
"@radix-ui/react-select": "^2.1.3",
"@radix-ui/react-select": "^2.1.5",
"@radix-ui/react-separator": "^1.1.1",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-switch": "^1.1.2",
"@radix-ui/react-tooltip": "1.1.5",
"@sentry/nextjs": "8.45.1",
"@shazow/whatsabi": "^0.18.0",
"@tanstack/react-query": "5.62.16",
"@radix-ui/react-tooltip": "1.1.7",
"@sentry/nextjs": "8.52.0",
"@shazow/whatsabi": "^0.19.0",
"@tanstack/react-query": "5.65.1",
"@tanstack/react-table": "^8.20.6",
"@thirdweb-dev/service-utils": "workspace:*",
"@vercel/functions": "^1.5.2",
"@vercel/og": "^0.6.4",
"abitype": "1.0.7",
"@vercel/functions": "^1.6.0",
"@vercel/og": "^0.6.5",
"abitype": "1.0.8",
"chakra-react-select": "^4.7.6",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -62,19 +62,19 @@
"date-fns": "4.1.0",
"fetch-event-stream": "0.1.5",
"flat": "^6.0.1",
"framer-motion": "11.15.0",
"framer-motion": "12.0.6",
"fuse.js": "7.0.0",
"input-otp": "^1.4.1",
"ioredis": "^5.4.1",
"ipaddr.js": "^2.2.0",
"lucide-react": "0.468.0",
"next": "15.1.3",
"lucide-react": "0.474.0",
"next": "15.1.6",
"next-plausible": "^3.12.4",
"next-themes": "^0.4.4",
"nextjs-toploader": "^1.6.12",
"openapi-types": "^12.1.3",
"p-limit": "^6.2.0",
"papaparse": "^5.4.1",
"papaparse": "^5.5.2",
"pluralize": "^8.0.0",
"posthog-js": "1.67.1",
"qrcode": "^1.5.3",
@@ -83,17 +83,17 @@
"react-day-picker": "^8.10.1",
"react-dom": "19.0.0",
"react-dropzone": "^14.3.5",
"react-error-boundary": "^4.1.2",
"react-error-boundary": "^5.0.0",
"react-hook-form": "7.54.2",
"react-markdown": "^9.0.1",
"react-table": "^7.8.0",
"recharts": "2.14.1",
"recharts": "2.15.1",
"remark-gfm": "^4.0.0",
"server-only": "^0.0.1",
"shiki": "1.24.2",
"sonner": "^1.7.1",
"shiki": "1.27.0",
"sonner": "^1.7.3",
"spdx-correct": "^3.2.0",
"swagger-ui-react": "^5.18.2",
"swagger-ui-react": "^5.18.3",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
"thirdweb": "workspace:*",
@@ -103,42 +103,42 @@
},
"devDependencies": {
"@chakra-ui/cli": "^2.4.1",
"@chromatic-com/storybook": "3.2.2",
"@next/bundle-analyzer": "15.1.0",
"@next/eslint-plugin-next": "15.1.3",
"@playwright/test": "1.49.1",
"@storybook/addon-essentials": "8.4.7",
"@storybook/addon-interactions": "8.4.7",
"@storybook/addon-links": "8.4.7",
"@storybook/addon-onboarding": "8.4.7",
"@storybook/addon-viewport": "8.4.7",
"@storybook/blocks": "8.4.7",
"@storybook/nextjs": "8.4.7",
"@storybook/react": "8.4.7",
"@storybook/test": "8.4.7",
"@chromatic-com/storybook": "3.2.4",
"@next/bundle-analyzer": "15.1.6",
"@next/eslint-plugin-next": "15.1.6",
"@playwright/test": "1.50.0",
"@storybook/addon-essentials": "8.5.2",
"@storybook/addon-interactions": "8.5.2",
"@storybook/addon-links": "8.5.2",
"@storybook/addon-onboarding": "8.5.2",
"@storybook/addon-viewport": "8.5.2",
"@storybook/blocks": "8.5.2",
"@storybook/nextjs": "8.5.2",
"@storybook/react": "8.5.2",
"@storybook/test": "8.5.2",
"@types/color": "4.2.0",
"@types/node": "22.10.2",
"@types/node": "22.10.10",
"@types/papaparse": "^5.3.15",
"@types/pluralize": "^0.0.33",
"@types/qrcode": "^1.5.5",
"@types/react": "19.0.2",
"@types/react-dom": "19.0.2",
"@types/react": "19.0.8",
"@types/react-dom": "19.0.3",
"@types/react-table": "^7.7.20",
"@types/spdx-correct": "^3.1.3",
"@types/swagger-ui-react": "^4.18.3",
"@types/swagger-ui-react": "^4.19.0",
"@typescript-eslint/eslint-plugin": "7.14.1",
"@typescript-eslint/parser": "7.14.1",
"autoprefixer": "^10.4.19",
"checkly": "^4.15.0",
"checkly": "^4.19.1",
"eslint": "8.57.0",
"eslint-config-biome": "1.9.4",
"eslint-plugin-react-compiler": "19.0.0-beta-df7b47d-20241124",
"eslint-plugin-storybook": "^0.11.1",
"knip": "5.41.0",
"knip": "5.43.6",
"next-sitemap": "^4.2.3",
"postcss": "8.4.49",
"storybook": "8.4.7",
"tailwindcss": "3.4.16",
"typescript": "5.7.2"
"postcss": "8.5.1",
"storybook": "8.5.2",
"tailwindcss": "3.4.17",
"typescript": "5.7.3"
}
}
@@ -1,2 +1,2 @@
name,description,external_url,background_color,youtube_url,additional,properties,can be,added
name,description,external_url,background_color,youtube_url,additional,properties,can be,added
Token 0 Name,Token 0 Description,https://thirdweb.com,#0098EE,,every,row,is a ,property
1 name description external_url background_color youtube_url additional properties can be added
2 Token 0 Name Token 0 Description https://thirdweb.com #0098EE every row is a property

Before

Width:  |  Height:  |  Size: 881 KiB

After

Width:  |  Height:  |  Size: 881 KiB

+3 -3
View File
@@ -21,7 +21,7 @@ const legacyDashboardToTeamRedirects = [
},
{
source: "/dashboard/settings/api-keys",
destination: "/team/~/~/projects",
destination: "/team",
permanent: false,
},
{
@@ -160,12 +160,12 @@ async function redirects() {
},
{
source: "/create-api-key",
destination: "/team/~/~/projects",
destination: "/team",
permanent: false,
},
{
source: "/dashboard/settings",
destination: "/team/~/~/projects",
destination: "/team",
permanent: false,
},
{
+29 -1
View File
@@ -3,6 +3,7 @@ import type {
AnalyticsQueryParams,
InAppWalletStats,
RpcMethodStats,
TransactionStats,
UserOpStats,
WalletStats,
WalletUserStats,
@@ -77,7 +78,10 @@ export async function getUserOpUsage(
});
if (res?.status !== 200) {
console.error("Failed to fetch user ops usage");
const reason = await res?.text();
console.error(
`Failed to fetch user ops usage: ${res?.status} - ${res.statusText} - ${reason}`,
);
return [];
}
@@ -85,6 +89,30 @@ export async function getUserOpUsage(
return json.data as UserOpStats[];
}
export async function getClientTransactions(
params: AnalyticsQueryParams,
): Promise<TransactionStats[]> {
const searchParams = buildSearchParams(params);
const res = await fetchAnalytics(
`v1/transactions/client?${searchParams.toString()}`,
{
method: "GET",
headers: { "Content-Type": "application/json" },
},
);
if (res?.status !== 200) {
const reason = await res?.text();
console.error(
`Failed to fetch client transactions stats: ${res?.status} - ${res.statusText} - ${reason}`,
);
return [];
}
const json = await res.json();
return json.data as TransactionStats[];
}
export async function getRpcMethodUsage(
params: AnalyticsQueryParams,
): Promise<RpcMethodStats[]> {
+3 -12
View File
@@ -1,7 +1,6 @@
import "server-only";
import { COOKIE_ACTIVE_ACCOUNT, COOKIE_PREFIX_TOKEN } from "@/constants/cookie";
import { API_SERVER_URL } from "@/constants/env";
import { cookies } from "next/headers";
import { getAuthToken } from "../../app/api/lib/getAuthToken";
export type Project = {
id: string;
@@ -21,11 +20,7 @@ export type Project = {
};
export async function getProjects(teamSlug: string) {
const cookiesManager = await cookies();
const activeAccount = cookiesManager.get(COOKIE_ACTIVE_ACCOUNT)?.value;
const token = activeAccount
? cookiesManager.get(COOKIE_PREFIX_TOKEN + activeAccount)?.value
: null;
const token = await getAuthToken();
if (!token) {
return [];
@@ -46,11 +41,7 @@ export async function getProjects(teamSlug: string) {
}
export async function getProject(teamSlug: string, projectSlug: string) {
const cookiesManager = await cookies();
const activeAccount = cookiesManager.get(COOKIE_ACTIVE_ACCOUNT)?.value;
const token = activeAccount
? cookiesManager.get(COOKIE_PREFIX_TOKEN + activeAccount)?.value
: null;
const token = await getAuthToken();
if (!token) {
return null;
+1 -1
View File
@@ -25,7 +25,7 @@ export type Team = {
billingPlan: "pro" | "growth" | "free" | "starter";
billingStatus: "validPayment" | (string & {}) | null;
billingEmail: string | null;
growthTrialEligible: boolean | null;
growthTrialEligible: false;
enabledScopes: EnabledTeamScope[];
};
@@ -12,7 +12,7 @@ export function ProjectAvatar(props: {
className={cn("rounded-lg border border-border", props.className)}
alt={""}
fallback={
<div className="flex items-center justify-center bg-muted/50">
<div className="flex items-center justify-center bg-card">
<BoxIcon className="size-[50%] text-muted-foreground" />
</div>
}
@@ -30,7 +30,7 @@ export function DangerSettingCard(props: {
return (
<div
className={cn(
"overflow-hidden rounded-lg border border-red-500/70",
"overflow-hidden rounded-lg border border-red-500/70 bg-card",
props.className,
)}
>
@@ -25,7 +25,7 @@ export function Img(props: imgElementProps) {
: _status;
const { className, fallback, skeleton, ...restProps } = props;
const defaultSkeleton = <div className="animate-pulse bg-accent" />;
const defaultFallback = <div className="bg-muted" />;
const defaultFallback = <div className="bg-accent" />;
const imgRef = useRef<HTMLImageElement>(null);
useIsomorphicLayoutEffect(() => {
@@ -47,7 +47,7 @@ export function MobileSidebar(props: {
const defaultTrigger = (
<Button
className={cn(
"w-full justify-between gap-2 bg-muted/50 text-left lg:hidden",
"w-full justify-between gap-2 bg-card text-left lg:hidden",
props.triggerClassName,
)}
variant="outline"
@@ -16,6 +16,8 @@ type Option = { label: string; value: string };
export function MultiNetworkSelector(props: {
selectedChainIds: number[];
onChange: (chainIds: number[]) => void;
disableChainId?: boolean;
className?: string;
}) {
const { allChains, idToChain } = useAllChainsData();
@@ -53,16 +55,24 @@ export function MultiNetworkSelector(props: {
return (
<div className="flex justify-between gap-4">
<span className="flex grow gap-2 truncate text-left">
<ChainIcon
className="size-5"
ipfsSrc={chain.icon?.url}
loading="lazy"
/>
{cleanChainName(chain.name)}
</span>
<Badge variant="outline" className="gap-2">
<span className="text-muted-foreground">Chain ID</span>
{chain.chainId}
</Badge>
{!props.disableChainId && (
<Badge variant="outline" className="gap-2">
<span className="text-muted-foreground">Chain ID</span>
{chain.chainId}
</Badge>
)}
</div>
);
},
[idToChain],
[idToChain, props.disableChainId],
);
return (
@@ -79,6 +89,7 @@ export function MultiNetworkSelector(props: {
disabled={allChains.length === 0}
overrideSearchFn={searchFn}
renderOption={renderOption}
className={props.className}
/>
);
}
@@ -90,6 +101,9 @@ export function SingleNetworkSelector(props: {
popoverContentClassName?: string;
// if specified - only these chains will be shown
chainIds?: number[];
side?: "left" | "right" | "top" | "bottom";
disableChainId?: boolean;
align?: "center" | "start" | "end";
}) {
const { allChains, idToChain } = useAllChainsData();
@@ -140,16 +154,19 @@ export function SingleNetworkSelector(props: {
ipfsSrc={chain.icon?.url}
loading="lazy"
/>
{chain.name}
{cleanChainName(chain.name)}
</span>
<Badge variant="outline" className="gap-2 max-sm:hidden">
<span className="text-muted-foreground">Chain ID</span>
{chain.chainId}
</Badge>
{!props.disableChainId && (
<Badge variant="outline" className="gap-2 max-sm:hidden">
<span className="text-muted-foreground">Chain ID</span>
{chain.chainId}
</Badge>
)}
</div>
);
},
[idToChain],
[idToChain, props.disableChainId],
);
const isLoadingChains = allChains.length === 0;
@@ -162,12 +179,15 @@ export function SingleNetworkSelector(props: {
onValueChange={(chainId) => {
props.onChange(Number(chainId));
}}
closeOnSelect={true}
placeholder={isLoadingChains ? "Loading Chains..." : "Select Chain"}
overrideSearchFn={searchFn}
renderOption={renderOption}
className={props.className}
popoverContentClassName={props.popoverContentClassName}
disabled={isLoadingChains}
side={props.side}
align={props.align}
/>
);
}
@@ -30,7 +30,7 @@ export function SettingsCard(
}>,
) {
return (
<div className="relative rounded-lg border border-border bg-muted/50">
<div className="relative rounded-lg border border-border bg-card">
<div
className={cn(
"relative border-border border-b px-4 py-6 lg:px-6",
@@ -67,7 +67,7 @@ export function RenderSidebarLinks(props: { links: SidebarLink[] }) {
// biome-ignore lint/suspicious/noArrayIndexKey: items won't be reordered
key={i}
href={link.href}
className="flex items-center gap-2 rounded-md px-3 py-2 text-muted-foreground text-sm hover:bg-muted"
className="flex items-center gap-2 rounded-md px-3 py-2 text-muted-foreground text-sm hover:bg-accent"
activeClassName="text-foreground"
exactMatch={link.exactMatch}
>
@@ -19,7 +19,7 @@ export function AppFooter(props: AppFooterProps) {
return (
<footer
className={cn(
"w-full border-border border-t bg-muted/50 py-6 md:py-8",
"w-full border-border border-t bg-card py-6 md:py-8",
props.className,
)}
>
@@ -28,7 +28,9 @@ export function AppFooter(props: AppFooterProps) {
<div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
<div className="flex flex-row items-center gap-3">
<ThirdwebMiniLogo className="h-7" />
<p className="text-muted-foreground text-sm">© 2024 thirdweb</p>
<p className="text-muted-foreground text-sm">
© {new Date().getFullYear()} thirdweb
</p>
</div>
<div className="flex flex-row gap-3">
<Button size="icon" variant="ghost" asChild className="size-9">
@@ -23,6 +23,7 @@ import {
EmptyChartState,
LoadingChartState,
} from "../../../../components/analytics/empty-chart-state";
import { cn } from "../../../lib/utils";
type ThirdwebBarChartProps<TConfig extends ChartConfig> = {
// metadata
@@ -36,6 +37,9 @@ type ThirdwebBarChartProps<TConfig extends ChartConfig> = {
// chart className
chartClassName?: string;
isPending: boolean;
toolTipLabelFormatter?: (label: string, payload: unknown) => React.ReactNode;
hideLabel?: boolean;
titleClassName?: string;
};
export function ThirdwebBarChart<TConfig extends ChartConfig>(
@@ -45,10 +49,13 @@ export function ThirdwebBarChart<TConfig extends ChartConfig>(
// if there are more than 4 keys then we should stack them by default
const variant =
props.variant || configKeys.length > 4 ? "stacked" : "grouped";
return (
<Card>
<CardHeader>
<CardTitle className="mb-2">{props.title}</CardTitle>
<CardTitle className={cn("mb-2", props.titleClassName)}>
{props.title}
</CardTitle>
{props.description && (
<CardDescription>{props.description}</CardDescription>
)}
@@ -69,7 +76,16 @@ export function ThirdwebBarChart<TConfig extends ChartConfig>(
tickMargin={10}
tickFormatter={(value) => formatDate(new Date(value), "MMM d")}
/>
<ChartTooltip content={<ChartTooltipContent hideLabel />} />
<ChartTooltip
content={
<ChartTooltipContent
hideLabel={
props.hideLabel !== undefined ? props.hideLabel : true
}
labelFormatter={props.toolTipLabelFormatter}
/>
}
/>
{props.showLegend && (
<ChartLegend content={<ChartLegendContent />} />
)}
@@ -92,6 +108,8 @@ export function ThirdwebBarChart<TConfig extends ChartConfig>(
: [0, 0, 0, 0]
: [4, 4, 4, 4]
}
strokeWidth={1}
className="stroke-background"
/>
))}
</BarChart>
@@ -23,7 +23,7 @@ export function UnexpectedValueErrorMessage(props: {
{stringifiedValue && (
<div className="mt-3">
<p className="mb-0.5 text-muted-foreground text-sm">Value Received</p>
<ScrollShadow className="rounded-lg bg-muted/50">
<ScrollShadow className="rounded-lg bg-card">
<code className="block whitespace-pre p-4 font-mono text-xs">
{stringifiedValue}
</code>
@@ -202,7 +202,7 @@ export const MultiSelect = forwardRef<HTMLButtonElement, MultiSelectProps>(
event.stopPropagation();
handleClear();
}}
className="rounded p-1 hover:bg-muted"
className="rounded p-1 hover:bg-accent"
>
<XIcon className="h-4 cursor-pointer text-muted-foreground" />
</div>
@@ -57,8 +57,9 @@ export const PricingCard: React.FC<PricingCardProps> = ({
return (
<div
className={cn(
"z-[999] flex w-full flex-col gap-6 rounded-xl border border-border bg-muted/50 p-4 md:p-6",
"z-10 flex w-full flex-col gap-6 rounded-xl border border-border bg-card p-4 md:p-6",
current && "border-blue-500",
highlighted && "border-active-border",
)}
style={
highlighted
@@ -31,6 +31,9 @@ interface SelectWithSearchProps
) => boolean;
renderOption?: (option: { value: string; label: string }) => React.ReactNode;
popoverContentClassName?: string;
side?: "left" | "right" | "top" | "bottom";
align?: "center" | "start" | "end";
closeOnSelect?: boolean;
}
export const SelectWithSearch = React.forwardRef<
@@ -48,6 +51,7 @@ export const SelectWithSearch = React.forwardRef<
overrideSearchFn,
popoverContentClassName,
searchPlaceholder,
closeOnSelect,
...props
},
ref,
@@ -107,7 +111,7 @@ export const SelectWithSearch = React.forwardRef<
}, [searchValue]);
return (
<Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
<Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen} modal>
<PopoverTrigger asChild>
<Button
ref={ref}
@@ -118,23 +122,24 @@ export const SelectWithSearch = React.forwardRef<
className,
)}
>
<div className="flex w-full items-center justify-between">
<div className="flex w-full items-center justify-between gap-2">
<span
className={cn(
"text-muted-foreground text-sm",
"truncate text-muted-foreground text-sm",
selectedOption && "text-foreground",
)}
>
{selectedOption?.label || placeholder}
</span>
<ChevronDown className="h-4 cursor-pointer text-muted-foreground" />
<ChevronDown className="size-4 cursor-pointer text-muted-foreground" />
</div>
</Button>
</PopoverTrigger>
<PopoverContent
className={cn("z-[10001] p-0", popoverContentClassName)}
align="center"
align={props.align || "center"}
side={props.side}
sideOffset={10}
onEscapeKeyDown={() => setIsPopoverOpen(false)}
style={{
@@ -174,7 +179,12 @@ export const SelectWithSearch = React.forwardRef<
key={option.value}
role="option"
aria-selected={isSelected}
onClick={() => onValueChange(option.value)}
onClick={() => {
onValueChange(option.value);
if (closeOnSelect) {
setIsPopoverOpen(false);
}
}}
variant="ghost"
className="flex w-full cursor-pointer justify-start gap-3 rounded-sm px-3 py-2 text-left"
ref={
@@ -8,7 +8,7 @@ import {
import { useThirdwebClient } from "@/constants/thirdweb.client";
import { resolveSchemeWithErrorHandler } from "@/lib/resolveSchemeWithErrorHandler";
import { useClipboard } from "hooks/useClipboard";
import { Check, Copy, ExternalLinkIcon } from "lucide-react";
import { Check, Copy } from "lucide-react";
import { useMemo } from "react";
import { type ThirdwebClient, isAddress } from "thirdweb";
import { ZERO_ADDRESS } from "thirdweb";
@@ -148,21 +148,6 @@ export function WalletAddress(props: {
);
})
)}
<Button
asChild
variant="upsell"
className="flex flex-row items-center gap-2 text-sm"
size="sm"
>
<a
target="_blank"
href="https://blog.thirdweb.com/changelog/introducing-the-social-sdk?ref=dashboard-social-wallet"
rel="noreferrer"
>
Learn more
<ExternalLinkIcon className="size-4" />
</a>
</Button>
</div>
</HoverCardContent>
</HoverCard>
@@ -0,0 +1,58 @@
import type { Meta, StoryObj } from "@storybook/react";
import { useState } from "react";
import { BadgeContainer, mobileViewport } from "../../stories/utils";
import { PaginationButtons } from "./pagination-buttons";
const meta = {
title: "blocks/PaginationButtons",
component: Story,
parameters: {
nextjs: {
appDirectory: true,
},
},
} satisfies Meta<typeof Story>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Desktop: Story = {
args: {},
};
export const Mobile: Story = {
args: {},
parameters: {
viewport: mobileViewport("iphone14"),
},
};
function Story() {
return (
<div className="container flex max-w-[1000px] flex-col gap-8 py-10">
<Variant label="10 Pages" totalPages={10} />
<Variant label="100 Pages" totalPages={100} />
<Variant label="3 Pages" totalPages={2} />
<Variant label="6 Pages" totalPages={6} />
<Variant label="1 Page - nothing rendered" totalPages={1} />
</div>
);
}
function Variant(props: {
label: string;
totalPages: number;
}) {
const [activePage, setActivePage] = useState(1);
return (
<BadgeContainer label={props.label}>
<div className="border bg-card py-5">
<PaginationButtons
activePage={activePage}
onPageClick={setActivePage}
totalPages={props.totalPages}
/>
</div>
</BadgeContainer>
);
}
@@ -9,6 +9,11 @@ import {
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination";
import { ArrowUpRightIcon } from "lucide-react";
import { useState } from "react";
import { cn } from "../lib/utils";
import { Button } from "./ui/button";
import { Input } from "./ui/input";
export const PaginationButtons = (props: {
activePage: number;
@@ -16,6 +21,47 @@ export const PaginationButtons = (props: {
onPageClick: (page: number) => void;
}) => {
const { activePage, totalPages, onPageClick: setPage } = props;
const [inputHasError, setInputHasError] = useState(false);
const [pageNumberInput, setPageNumberInput] = useState("");
if (totalPages === 1) {
return null;
}
function handlePageInputSubmit() {
const page = Number(pageNumberInput);
setInputHasError(false);
if (Number.isInteger(page) && page > 0 && page <= totalPages) {
setPage(page);
setPageNumberInput("");
} else {
setInputHasError(true);
}
}
// just render all the page buttons directly
if (totalPages <= 6) {
const pages = [...Array(totalPages)].map((_, i) => i + 1);
return (
<Pagination>
<PaginationContent>
{pages.map((page) => (
<PaginationItem key={page}>
<PaginationLink
isActive={activePage === page}
onClick={() => {
setPage(page);
}}
>
{page}
</PaginationLink>
</PaginationItem>
))}
</PaginationContent>
</Pagination>
);
}
return (
<Pagination>
@@ -28,24 +74,28 @@ export const PaginationButtons = (props: {
}}
/>
</PaginationItem>
{/* First page + ... */}
{activePage - 3 > 0 && (
<PaginationItem className="max-sm:hidden">
<PaginationEllipsis />
</PaginationItem>
)}
{activePage - 2 > 0 && (
<PaginationItem className="max-sm:hidden">
<PaginationLink
onClick={() => {
setPage(activePage - 2);
}}
>
{activePage - 2}
</PaginationLink>
</PaginationItem>
<>
<PaginationItem>
<PaginationLink
onClick={() => {
setPage(1);
}}
>
1
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationEllipsis className="max-sm:w-3" />
</PaginationItem>
</>
)}
{activePage - 1 > 0 && (
<PaginationItem>
<PaginationItem className="max-sm:hidden">
<PaginationLink
onClick={() => {
setPage(activePage - 1);
@@ -55,11 +105,13 @@ export const PaginationButtons = (props: {
</PaginationLink>
</PaginationItem>
)}
<PaginationItem>
<PaginationLink isActive>{activePage}</PaginationLink>
</PaginationItem>
{activePage + 1 <= totalPages && (
<PaginationItem>
<PaginationItem className="max-sm:hidden">
<PaginationLink
onClick={() => {
setPage(activePage + 1);
@@ -69,22 +121,26 @@ export const PaginationButtons = (props: {
</PaginationLink>
</PaginationItem>
)}
{activePage + 2 <= totalPages && (
<PaginationItem className="max-sm:hidden">
<PaginationLink
onClick={() => {
setPage(activePage + 2);
}}
>
{activePage + 2}
</PaginationLink>
</PaginationItem>
)}
{/* ... + Last page */}
{activePage + 3 <= totalPages && (
<PaginationItem className="max-sm:hidden">
<PaginationEllipsis />
</PaginationItem>
<>
<PaginationItem>
<PaginationEllipsis className="max-sm:w-3" />
</PaginationItem>
<PaginationItem>
<PaginationLink
onClick={() => {
setPage(totalPages);
}}
>
{totalPages}
</PaginationLink>
</PaginationItem>
</>
)}
<PaginationItem>
<PaginationNext
disabled={activePage === totalPages}
@@ -93,6 +149,34 @@ export const PaginationButtons = (props: {
}}
/>
</PaginationItem>
<div className="relative flex items-center">
<Input
value={pageNumberInput}
onChange={(e) => {
setInputHasError(false);
setPageNumberInput(e.target.value);
}}
type="number"
placeholder="Page"
className={cn(
"w-[60px] bg-transparent [appearance:textfield] max-sm:placeholder:text-sm lg:w-[100px] lg:pr-8 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
inputHasError && "text-red-500",
)}
onKeyDown={(e) => {
if (e.key === "Enter") {
handlePageInputSubmit();
}
}}
/>
<Button
variant="ghost"
className="absolute right-1 h-auto w-auto p-2 max-sm:hidden"
onClick={handlePageInputSubmit}
>
<ArrowUpRightIcon className="size-4" />
</Button>
</div>
</PaginationContent>
</Pagination>
);
@@ -9,7 +9,7 @@ import { ToolTipLabel } from "./tooltip";
export function CopyTextButton(props: {
textToShow: string;
textToCopy: string;
tooltip: string;
tooltip: string | undefined;
className?: string;
iconClassName?: string;
variant?:
+1 -1
View File
@@ -4,7 +4,7 @@ import * as React from "react";
import { cn } from "@/lib/utils";
const alertVariants = cva(
"dark:bg-muted/50 relative w-full rounded-lg border border-border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
"bg-card relative w-full rounded-lg border border-border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
{
variants: {
variant: {
+1 -1
View File
@@ -186,7 +186,7 @@ const ChartTooltipContent = React.forwardRef<
<div
ref={ref}
className={cn(
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-popover px-2.5 py-1.5 text-xs shadow-xl",
className,
)}
>
@@ -21,7 +21,7 @@ export function CodeBlockContainer(props: {
return (
<div
className={cn(
"group relative max-w-full overflow-hidden rounded-lg border border-border bg-background",
"group relative max-w-full overflow-hidden rounded-lg border border-border bg-card",
props.className,
)}
>
@@ -33,7 +33,7 @@ const ImageUpload = React.forwardRef<HTMLInputElement, ImageUploadProps>(
<div
{...getRootProps()}
className={cn(
"group relative flex cursor-pointer flex-col items-center justify-center gap-1.5 overflow-hidden rounded-md border bg-card p-4 py-6 text-muted-foreground transition-all hover:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"group relative flex cursor-pointer flex-col items-center justify-center gap-1.5 overflow-hidden rounded-md border bg-background p-4 py-6 text-muted-foreground transition-all hover:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
isDragActive ? "border-primary" : "border-input",
!activeFile ? "w-full" : "min-h-32 min-w-32",
className,
+1 -1
View File
@@ -11,7 +11,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-card px-3 py-2 text-base ring-offset-background selection:bg-foreground selection:text-background file:border-0 file:bg-transparent file:font-medium file:text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background selection:bg-foreground selection:text-background file:border-0 file:bg-transparent file:font-medium file:text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className,
)}
ref={ref}
@@ -63,11 +63,11 @@ const PaginationPrevious = ({
<PaginationLink
aria-label="Go to previous page"
size="default"
className={cn("gap-1 pl-2.5", className)}
className={cn("h-10 gap-1 pl-2.5", className)}
{...props}
>
<ChevronLeft className="h-4 w-4" />
<span>Previous</span>
<span className="max-sm:hidden">Previous</span>
</PaginationLink>
);
PaginationPrevious.displayName = "PaginationPrevious";
@@ -79,10 +79,10 @@ const PaginationNext = ({
<PaginationLink
aria-label="Go to next page"
size="default"
className={cn("gap-1 pr-2.5", className)}
className={cn("h-10 gap-1 pr-2.5", className)}
{...props}
>
<span>Next</span>
<span className="max-sm:hidden">Next</span>
<ChevronRight className="h-4 w-4" />
</PaginationLink>
);
@@ -51,7 +51,7 @@ const RadioGroupItemButton = React.forwardRef<
<RadioGroupPrimitive.Item
ref={ref}
className={cn(
"group flex min-w-32 cursor-pointer items-center space-x-3 space-y-0 rounded-lg border px-4 py-3 font-medium transition-all hover:border-foreground/25 hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 peer-hover:border-nonce data-[state=checked]:border-muted-foreground",
"group flex min-w-32 cursor-pointer items-center space-x-3 space-y-0 rounded-lg border px-4 py-3 font-medium transition-all hover:border-foreground/25 hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 peer-hover:border-nonce data-[state=checked]:border-muted-foreground",
className,
)}
{...props}
@@ -21,7 +21,7 @@ const SelectTrigger = React.forwardRef<
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-10 w-full items-center justify-between gap-2 rounded-md border border-input bg-card px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
"flex h-10 w-full items-center justify-between gap-2 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className,
)}
{...props}
@@ -114,7 +114,9 @@ function TableDemo(props: {
<TableRow
key={invoice.invoice}
linkBox={props.linkBox}
className={cn(props.linkBox && "cursor-pointer hover:bg-muted")}
className={cn(
props.linkBox && "cursor-pointer hover:bg-accent/50",
)}
>
<TableCell className="font-medium">
<Link
+15 -4
View File
@@ -25,7 +25,8 @@ const TableHeader = React.forwardRef<
<thead
ref={ref}
className={cn(
"border-border border-b bg-muted/50 [&_tr]:border-b",
"border-border border-b bg-background",
"sticky top-0 z-20 border-none before:absolute before:inset-0 before:border-border before:border-b",
className,
)}
{...props}
@@ -53,7 +54,7 @@ const TableFooter = React.forwardRef<
<tfoot
ref={ref}
className={cn(
"border-border border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
"border-border border-t bg-card font-medium [&>tr]:last:border-b-0",
className,
)}
{...props}
@@ -125,10 +126,20 @@ const TableCaption = React.forwardRef<
));
TableCaption.displayName = "TableCaption";
function TableContainer(props: { children: React.ReactNode }) {
function TableContainer(props: {
children: React.ReactNode;
className?: string;
scrollableContainerClassName?: string;
}) {
return (
<ScrollShadow
className="relative whitespace-nowrap rounded-lg border border-border"
shadowClassName="z-30"
disableTopShadow
className={cn(
"relative whitespace-nowrap rounded-lg border border-border bg-card",
props.className,
)}
scrollableClassName={props.scrollableContainerClassName}
shadowColor="hsl(var(--muted))"
>
{props.children}
+1 -1
View File
@@ -51,7 +51,7 @@ export function TabLinks(props: {
href={tab.href}
aria-disabled={tab.isDisabled}
className={cn(
"relative h-auto rounded-lg px-3 font-normal text-muted-foreground text-sm hover:bg-muted lg:text-sm",
"relative h-auto rounded-lg px-3 font-normal text-muted-foreground text-sm hover:bg-accent lg:text-sm",
!tab.isActive && !tab.isDisabled && "hover:text-foreground",
tab.isDisabled && "pointer-events-none",
tab.isActive && "!text-foreground",
@@ -10,7 +10,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
return (
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-card px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className,
)}
ref={ref}
+11 -10
View File
@@ -6,12 +6,12 @@
:root,
[data-theme="light"] {
/* bg - neutral */
--background: 0 0% 100%;
--background: 0 0% 98%;
--popover: 0 0% 100%;
--card: 0 0% 100%;
--secondary: 0 0% 92%;
--muted: 0 0% 95%;
--accent: 0 0% 95%;
--secondary: 0 0% 90%;
--muted: 0 0% 93%;
--accent: 0 0% 93%;
--inverted: 0 0% 4%;
/* bg - colorful */
@@ -34,9 +34,10 @@
--destructive-text: 357.15deg 100% 68.72%;
/* Borders */
--border: 0 0% 80%;
--input: 0 0% 80%;
--ring: 0 0% 85%;
--border: 0 0% 85%;
--active-border: 0 0% 70%;
--input: 0 0% 85%;
--ring: 0 0% 80%;
/* Others */
--radius: 0.5rem;
@@ -46,7 +47,7 @@
[data-theme="dark"] {
/* bg - neutral */
--background: 0 0% 0%;
--card: 0 0% 0%;
--card: 0 0% 3.92%;
--popover: 0 0% 0%;
--secondary: 0 0% 11%;
--muted: 0 0% 11%;
@@ -74,6 +75,7 @@
/* Borders */
--border: 0 0% 15%;
--active-border: 0 0% 22%;
--ring: 0 0% 30%;
--input: 0 0% 15%;
}
@@ -159,13 +161,12 @@ input:-webkit-autofill:active {
.shiki,
.shiki span {
background-color: var(--background) !important;
background-color: transparent !important;
}
.dark .shiki,
.dark .shiki span {
color: var(--shiki-dark) !important;
background-color: var(--background) !important;
/* Optional, if you also want font styles */
font-style: var(--shiki-dark-font-style) !important;
font-weight: var(--shiki-dark-font-weight) !important;
@@ -76,8 +76,8 @@ export const engineKeys = {
[...engineKeys.all, address, "instances"] as const,
backendWallets: (instance: string) =>
[...engineKeys.all, instance, "backendWallets"] as const,
transactions: (instance: string) =>
[...engineKeys.all, instance, "transactions"] as const,
transactions: (instance: string, params: object) =>
[...engineKeys.all, instance, "transactions", params] as const,
permissions: (instance: string) =>
[...engineKeys.all, instance, "permissions"] as const,
accessTokens: (instance: string) =>
@@ -1,12 +1,18 @@
"use client";
import { apiServerProxy } from "@/actions/proxies";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
keepPreviousData,
useMutation,
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import type { ResultItem } from "app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/metrics/components/StatusCodes";
import type { EngineBackendWalletType } from "lib/engine";
import { useState } from "react";
import { useActiveAccount, useActiveWalletChain } from "thirdweb/react";
import { useActiveAccount } from "thirdweb/react";
import invariant from "tiny-invariant";
import type { EngineStatus } from "../../../app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/overview/components/transactions-table";
import { engineKeys } from "../cache-keys";
export type EngineTier = "STARTER" | "PREMIUM" | "ENTERPRISE";
@@ -47,45 +53,6 @@ const getEngineRequestHeaders = (token: string | null): HeadersInit => {
};
};
// TODO - add authToken in queryKey instead
export function useEngineInstances() {
const address = useActiveAccount()?.address;
return useQuery({
queryKey: engineKeys.instances(address || ""),
queryFn: async (): Promise<EngineInstance[]> => {
type Result = {
data?: {
instances: EngineInstance[];
};
};
const res = await apiServerProxy<Result>({
pathname: "/v1/engine",
method: "GET",
});
if (!res.ok) {
throw new Error(res.error);
}
const json = res.data;
const instances = json.data?.instances || [];
return instances.map((instance) => {
// Sanitize: Add trailing slash if not present.
const url = instance.url.endsWith("/")
? instance.url
: `${instance.url}/`;
return {
...instance,
url,
};
});
},
enabled: !!address,
});
}
// GET Requests
export type BackendWallet = {
address: string;
@@ -106,7 +73,7 @@ export function useEngineBackendWallets(params: {
}) {
const { instanceUrl, authToken } = params;
return useQuery({
queryKey: [engineKeys.backendWallets(instanceUrl), authToken],
queryKey: [...engineKeys.backendWallets(instanceUrl), authToken],
queryFn: async () => {
const res = await fetch(`${instanceUrl}backend-wallet/get-all?limit=50`, {
method: "GET",
@@ -422,13 +389,29 @@ export function useEngineTransactions(params: {
instanceUrl: string;
autoUpdate: boolean;
authToken: string;
queryParams?: {
limit?: number;
page?: number;
status?: EngineStatus;
};
}) {
const { instanceUrl, autoUpdate, authToken } = params;
return useQuery({
queryKey: engineKeys.transactions(instanceUrl),
queryKey: engineKeys.transactions(instanceUrl, params),
queryFn: async () => {
const res = await fetch(`${instanceUrl}transaction/get-all`, {
const url = new URL(`${instanceUrl}transaction/get-all`);
if (params.queryParams) {
for (const key in params.queryParams) {
const value =
params.queryParams[key as keyof typeof params.queryParams];
if (value !== undefined) {
url.searchParams.append(key, value.toString());
}
}
}
const res = await fetch(url, {
method: "GET",
headers: getEngineRequestHeaders(authToken),
});
@@ -437,8 +420,8 @@ export function useEngineTransactions(params: {
return (json.result as TransactionResponse) || {};
},
enabled: !!instanceUrl,
refetchInterval: autoUpdate ? 4_000 : false,
placeholderData: keepPreviousData,
});
}
@@ -486,12 +469,12 @@ export function useEngineBackendWalletBalance(params: {
instanceUrl: string;
address: string;
authToken: string;
chainId: number;
}) {
const { instanceUrl, address, authToken } = params;
const chainId = useActiveWalletChain()?.id;
const { instanceUrl, address, authToken, chainId } = params;
return useQuery({
queryKey: engineKeys.backendWalletBalance(address, chainId || 1),
queryKey: engineKeys.backendWalletBalance(address, chainId),
queryFn: async () => {
invariant(chainId, "chainId is required");
@@ -12,7 +12,7 @@ export function BuyFundsSection(props: { chain: ChainMetadata }) {
return (
<section>
<SectionTitle title="Buy Funds" />
<div className="flex justify-center rounded-lg border border-border bg-muted/30 px-4 py-10">
<div className="flex justify-center rounded-lg border border-border bg-card px-4 py-10">
<div className="flex max-w-[520px] flex-col items-center ">
<div className="flex items-center">
<ChainIcon
@@ -11,7 +11,7 @@ export function ChainOverviewSection(props: { chain: ChainMetadata }) {
return (
<section>
<SectionTitle title="Chain Overview" />
<div className="grid grid-cols-1 gap-6 rounded-lg border bg-muted/50 p-4 md:grid-cols-2 md:p-6 lg:grid-cols-3 lg:gap-8">
<div className="grid grid-cols-1 gap-6 rounded-lg border bg-card p-4 md:grid-cols-2 md:p-6 lg:grid-cols-3 lg:gap-8">
{/* Info */}
{chain.infoURL && (
<PrimaryInfoItem title="Info">
@@ -7,7 +7,7 @@ export function ClaimChainSection() {
return (
<section>
<SectionTitle title="Claim Chain" />
<div className="rounded-lg border bg-muted/50 p-4">
<div className="rounded-lg border bg-card p-4">
<p className="mb-1"> This chain page is unclaimed </p>
<p className="mb-5 text-muted-foreground text-sm">
Are you the owner of this ecosystem? Claim this page to add additional
@@ -19,7 +19,7 @@ export async function FaucetSection(props: {
return (
<section>
<SectionTitle title="Faucet" />
<div className="flex justify-center rounded-lg border border-border bg-muted/50 px-4 py-10">
<div className="flex justify-center rounded-lg border border-border bg-card px-4 py-10">
<div className="flex w-full max-w-[520px] flex-col items-center ">
<div className="flex items-center">
<ChainIcon
@@ -25,7 +25,7 @@ export function SupportedProductsSection(props: {
return (
<div
key={product.id}
className="relative flex gap-3 rounded-lg border bg-muted/50 p-4 pr-8 transition-colors duration-300 hover:bg-muted"
className="relative flex gap-3 rounded-lg border bg-card p-4 pr-8 transition-colors hover:border-active-border"
>
<CircleCheckIcon className="absolute top-4 right-4 size-5 text-success-text" />
<product.icon className="mt-0.5 size-5 shrink-0" />
@@ -14,7 +14,7 @@ export function ExplorersSection(props: {
return (
<div
key={explorer.url}
className="relative rounded-xl border bg-muted/50 p-4 hover:bg-muted"
className="relative rounded-xl border bg-card p-4 transition-colors hover:border-active-border"
>
<ExternalLinkIcon className="absolute top-4 right-4 size-4 text-muted-foreground" />
<h3 className="mb-1 font-semibold text-base capitalize">
@@ -1,5 +1,3 @@
import { MobileSidebar } from "@/components/blocks/MobileSidebar";
import { Sidebar } from "@/components/blocks/Sidebar";
import {
Breadcrumb,
BreadcrumbItem,
@@ -15,12 +13,7 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
ArrowLeftIcon,
ChevronDownIcon,
MenuIcon,
TicketCheckIcon,
} from "lucide-react";
import { ChevronDownIcon, TicketCheckIcon } from "lucide-react";
import type { Metadata } from "next";
import Link from "next/link";
import { redirect } from "next/navigation";
@@ -71,18 +64,6 @@ export default async function ChainPageLayout(props: {
const chainMetadata = await getChainMetadata(chain.chainId);
const sidebarLinks = [
{
href: `/${chain.slug}`,
label: "Overview",
exactMatch: true,
},
{
href: `/${chain.slug}/popular`,
label: "Popular Contracts",
},
];
return (
<>
<div className="flex h-14 border-border border-b pl-7">
@@ -125,9 +106,7 @@ export default async function ChainPageLayout(props: {
</BreadcrumbList>
</Breadcrumb>
</div>
<div className="container flex h-full flex-row">
<Sidebar links={sidebarLinks} />
<div className="container flex h-full max-w-[1180px] flex-row">
<div className="flex w-full flex-col pb-10">
{/* Icon + Background */}
<ChainHeader
@@ -136,28 +115,6 @@ export default async function ChainPageLayout(props: {
chain={chain}
/>
<div className="flex justify-end lg:hidden">
<MobileSidebar
links={sidebarLinks}
trigger={
<Button size="icon" variant="outline">
<MenuIcon strokeWidth={1} />
</Button>
}
footer={
<div className="mt-5 border-t pt-6 pb-2">
<Link
href="/chainlist"
className="flex items-center justify-start gap-2 px-2 text-muted-foreground text-sm hover:text-foreground"
>
<ArrowLeftIcon className="size-4" />
View all chains
</Link>
</div>
}
/>
</div>
<div className="h-4 md:h-8" />
<div className="flex flex-col gap-3 md:gap-2">
@@ -1,9 +1,5 @@
import { Button } from "@/components/ui/button";
import { fetchTopContracts } from "lib/search";
import { ArrowRightIcon, CircleAlertIcon } from "lucide-react";
import Link from "next/link";
import { CircleAlertIcon } from "lucide-react";
import { getRawAccount } from "../../../../account/settings/getAccount";
import { TrendingContractSection } from "../../../trending/components/trending-table";
import { getChain, getChainMetadata } from "../../utils";
import { BuyFundsSection } from "./components/server/BuyFundsSection";
import { ChainOverviewSection } from "./components/server/ChainOverviewSection";
@@ -21,14 +17,7 @@ export default async function Page(props: {
const chainMetadata = await getChainMetadata(chain.chainId);
const isDeprecated = chain.status === "deprecated";
const [account, topContracts] = await Promise.all([
getRawAccount(),
fetchTopContracts({
chainId: chain.chainId,
perPage: 3,
timeRange: "month",
}),
]);
const account = await getRawAccount();
return (
<div className="flex flex-col gap-10">
@@ -65,31 +54,6 @@ export default async function Page(props: {
<ExplorersSection explorers={chain.explorers} />
)}
{topContracts.length > 0 && (
<section>
<div className="mb-3 flex items-center justify-between">
<h2 className="font-semibold text-xl tracking-tight">
Popular Contracts
</h2>
<Button asChild variant="outline">
<Link
href={`/${chain.slug}/popular`}
className="flex items-center gap-2"
>
See All
<ArrowRightIcon className="size-4" />
</Link>
</Button>
</div>
<TrendingContractSection
topContracts={topContracts}
chainId={chain.chainId}
showPagination={false}
searchParams={undefined}
/>
</section>
)}
{chain.services.filter((s) => s.enabled).length > 0 && (
<SupportedProductsSection services={chain.services} />
)}
@@ -1,48 +0,0 @@
import { type SortBy, fetchTopContracts } from "lib/search";
import { CircleAlertIcon } from "lucide-react";
import { TrendingContractSection } from "../../../../trending/components/trending-table";
import { getChain } from "../../../utils";
export default async function Page(props: {
params: Promise<{ chain_id: string }>;
searchParams: Promise<{ page?: number; sortBy?: SortBy }>;
}) {
const searchParams = await props.searchParams;
const params = await props.params;
const chain = await getChain(params.chain_id);
const topContracts = await fetchTopContracts({
chainId: chain.chainId,
page: searchParams.page,
sortBy: searchParams.sortBy,
perPage: 15,
timeRange: "month",
});
return (
<section className="mt-2">
<h2 className="mb-2 font-semibold text-2xl tracking-tighter">
Popular Contracts
</h2>
<p className="text-muted-foreground text-sm">
Explore contracts on Ethereum and sort them by your preferred metrics
</p>
<div className="h-8" />
{topContracts.length > 0 && (
<TrendingContractSection
topContracts={topContracts}
chainId={chain.chainId}
searchParams={searchParams}
showPagination={true}
/>
)}
{topContracts.length === 0 && (
<div className="flex h-[200px] items-center justify-center rounded-lg border border-border text-lg text-muted-foreground">
<div className="flex items-center gap-2">
<CircleAlertIcon className="size-5 text-destructive-text" />
No contracts found
</div>
</div>
)}
</section>
);
}
@@ -247,7 +247,7 @@ export const MarketplaceTable: React.FC<MarketplaceTableProps> = ({
<Tr
{...row.getRowProps()}
role="group"
className="hover:bg-muted/50"
className="hover:bg-card"
style={{ cursor: "pointer" }}
onClick={() => setTokenRow(row.original)}
borderBottomWidth={1}
@@ -4,6 +4,7 @@ import {
toTokens,
toUnits,
} from "thirdweb";
import { getContract } from "thirdweb/contract";
import type { OverrideEntry } from "thirdweb/dist/types/utils/extensions/drops/types";
import type { Prettify } from "thirdweb/dist/types/utils/type-utils";
import { getContractMetadata } from "thirdweb/extensions/common";
@@ -71,7 +72,10 @@ export async function getClaimPhasesInLegacyFormat(
conditions.map(async (condition) => {
const [currencyMetadata, metadata, contractMetadata] = await Promise.all([
await ERC20Ext.getCurrencyMetadata({
contract: { ...options.contract, address: condition.currency },
contract: getContract({
...options.contract,
address: condition.currency,
}),
}).then((m) => ({
...m,
displayValue: toTokens(condition.pricePerToken, m.decimals),
@@ -160,7 +160,7 @@ const SnapshotViewerSheetContent: React.FC<SnapshotUploadProps> = ({
<div
className={cn(
"flex h-full cursor-pointer rounded-md border border-border hover:border-primary",
noCsv ? "bg-red-200" : "bg-card",
noCsv ? "bg-red-200" : "bg-background",
)}
{...getRootProps()}
>
@@ -197,7 +197,7 @@ const SnapshotViewerSheetContent: React.FC<SnapshotUploadProps> = ({
<a
className="text-link-foreground hover:text-foreground"
download
href="/snapshot-with-maxclaimable.csv"
href="/assets/examples/snapshot-with-maxclaimable.csv"
>
<DownloadIcon className="inline size-3" /> Example
snapshot
@@ -212,7 +212,7 @@ const SnapshotViewerSheetContent: React.FC<SnapshotUploadProps> = ({
<a
download
className="text-link-foreground hover:text-foreground"
href="/snapshot-with-overrides.csv"
href="/assets/examples/snapshot-with-overrides.csv"
>
<DownloadIcon className="inline size-3" /> Example
snapshot
@@ -228,7 +228,7 @@ const SnapshotViewerSheetContent: React.FC<SnapshotUploadProps> = ({
<a
download
className="text-link-foreground hover:text-foreground"
href="/snapshot.csv"
href="/assets/examples/snapshot.csv"
>
<DownloadIcon className="inline size-3" /> Example
snapshot
@@ -243,7 +243,7 @@ const SnapshotViewerSheetContent: React.FC<SnapshotUploadProps> = ({
<a
download
className="text-link-foreground hover:text-foreground"
href="/snapshot-with-maxclaimable.csv"
href="/assets/examples/snapshot-with-maxclaimable.csv"
>
<DownloadIcon className="inline size-3" /> Example
snapshot
@@ -262,7 +262,7 @@ const SnapshotViewerSheetContent: React.FC<SnapshotUploadProps> = ({
<a
download
className="text-link-foreground hover:text-foreground"
href="/snapshot-with-overrides.csv"
href="/assets/examples/snapshot-with-overrides.csv"
>
<DownloadIcon className="inline size-3" /> Example
snapshot
@@ -83,7 +83,7 @@ export const MetadataHeader: React.FC<MetadataHeaderProps> = ({
{chain && (
<Link
href={`/${chain.slug}`}
className="flex w-fit shrink-0 items-center gap-2 rounded-3xl border border-border bg-muted/50 px-2.5 py-1.5 hover:bg-muted"
className="flex w-fit shrink-0 items-center gap-2 rounded-3xl border border-border bg-card px-2.5 py-1.5 hover:bg-accent"
>
<ChainIcon ipfsSrc={chain.icon?.url} className="size-4" />
{cleanedChainName && (
@@ -109,7 +109,7 @@ export const MetadataHeader: React.FC<MetadataHeaderProps> = ({
<CopyAddressButton
address={address}
copyIconPosition="left"
className="bg-muted/50 text-xs"
className="bg-card text-xs"
variant="outline"
/>
@@ -138,7 +138,7 @@ function BadgeLink(props: {
<Button
variant="outline"
asChild
className="!h-auto gap-2 rounded-lg bg-muted/50 px-3 py-1.5 text-xs capitalize"
className="!h-auto gap-2 rounded-lg bg-card px-3 py-1.5 text-xs capitalize"
>
<Link href={props.href} target="_blank">
{props.name}
@@ -136,7 +136,7 @@ function UniqueWalletsChart(props: ChartProps) {
color: "hsl(var(--chart-1))",
},
}}
chartClassName="aspect[2] lg:aspect-[4.5]"
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
/>
);
}
@@ -161,7 +161,7 @@ function TotalTransactionsChart(props: ChartProps) {
color: "hsl(var(--chart-1))",
},
}}
chartClassName="aspect[2] lg:aspect-[4.5]"
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
/>
);
}
@@ -181,7 +181,7 @@ function TotalEventsChart(props: ChartProps) {
color: "hsl(var(--chart-1))",
},
}}
chartClassName="aspect[2] lg:aspect-[4.5]"
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
/>
);
}
@@ -233,7 +233,7 @@ function FunctionBreakdownChart(
},
{} as Record<string, { label: string; color: string }>,
)}
chartClassName="aspect[2] lg:aspect-[4.5]"
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
showLegend
/>
);
@@ -286,7 +286,7 @@ function EventBreakdownChart(
},
{} as Record<string, { label: string; color: string }>,
)}
chartClassName="aspect[2] lg:aspect-[4.5]"
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
showLegend
/>
);
@@ -1,5 +1,6 @@
"use client";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { CodeClient } from "@/components/ui/code/code.client";
import {
@@ -11,8 +12,8 @@ import { Flex, FormControl, Input, Select } from "@chakra-ui/react";
import { LazyCreateAPIKeyDialog } from "components/settings/ApiKeys/Create/LazyCreateAPIKeyDialog";
import { useTrack } from "hooks/analytics/useTrack";
import { useAllChainsData } from "hooks/chains/allChains";
import { useClipboard } from "hooks/useClipboard";
import { CheckIcon, CopyIcon } from "lucide-react";
import { AlertCircleIcon } from "lucide-react";
import { useTheme } from "next-themes";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useMemo, useState } from "react";
@@ -211,6 +212,7 @@ export const EmbedSetup: React.FC<EmbedSetupProps> = ({
twAccount,
}) => {
const trackEvent = useTrack();
const { theme } = useTheme();
const apiKeys = useApiKeys({
isLoggedIn: !!twAccount,
@@ -268,7 +270,7 @@ export const EmbedSetup: React.FC<EmbedSetupProps> = ({
listingId: "0",
directListingId: "0",
englishAuctionId: "0",
theme: "dark",
theme: theme === "light" ? "light" : "dark",
primaryColor: "purple",
secondaryColor: "orange",
},
@@ -298,13 +300,12 @@ export const EmbedSetup: React.FC<EmbedSetupProps> = ({
[iframeSrc],
);
const { hasCopied, onCopy } = useClipboard(embedCode, 3000);
const [showCreateAPIKeyModal, setShowCreateAPIKeyModal] = useState(false);
const activeAccount = useActiveAccount();
const pathname = usePathname();
return (
<Flex gap={8} direction="column">
<div>
<LazyCreateAPIKeyDialog
prefill={{
name: "Embed API Key",
@@ -322,206 +323,223 @@ export const EmbedSetup: React.FC<EmbedSetupProps> = ({
apiKeys.refetch();
}}
enableNebulaServiceByDefault={false}
teamSlug={undefined}
/>
<Flex gap={8} direction={{ base: "column", md: "row" }}>
<Card className="flex w-full flex-col gap-5 md:w-1/2">
<Heading size="title.sm">Configuration</Heading>
<Alert variant="warning">
<AlertCircleIcon className="size-5" />
<AlertTitle>Deprecated</AlertTitle>
<AlertDescription className="leading-relaxed">
<span>
thirdweb NFT Embeds are deprecated and not actively maintained
</span>{" "}
<br />
<span>
Use the{" "}
<Link
href="https://github.com/thirdweb-example/nft-minting-template"
target="_blank"
className="underline underline-offset-2 hover:text-foreground"
>
{" "}
NFT Minting Template
</Link>{" "}
or build a custom NFT minting app using{" "}
<Link
href="https://portal.thirdweb.com/react/v5"
className="underline underline-offset-2 hover:text-foreground"
>
thirdweb React SDK components
</Link>{" "}
instead
</span>
</AlertDescription>
</Alert>
<div className="h-8" />
<div className="grid grid-cols-1 gap-6 lg:grid-cols-2">
<div>
<h2 className="mb-3 font-semibold text-xl tracking-tight">
Configuration
</h2>
<Card className="flex w-full flex-col gap-5 bg-card">
{ercOrMarketplace === "marketplace" ? (
<FormControl>
<FormLabel>Listing ID</FormLabel>
<Input type="number" {...register("listingId")} />
<FormHelperText>
The listing ID the embed should display
</FormHelperText>
</FormControl>
) : null}
{ercOrMarketplace === "marketplace-v3" ? (
<FormControl>
<FormLabel>Listing type</FormLabel>
<Select {...register("listingType")}>
<option value="direct-listing">Direct Listing</option>
<option value="english-auction">English Auction</option>
</Select>
<FormHelperText>
The type of listing the embed should display
</FormHelperText>
</FormControl>
) : null}
{ercOrMarketplace === "marketplace-v3" &&
watch("listingType") === "direct-listing" ? (
<FormControl>
<FormLabel>Direct Listing ID</FormLabel>
<Input type="number" {...register("directListingId")} />
<FormHelperText>
The direct listing ID the embed should display
</FormHelperText>
</FormControl>
) : null}
{ercOrMarketplace === "marketplace-v3" &&
watch("listingType") === "english-auction" ? (
<FormControl>
<FormLabel>English Auction ID</FormLabel>
<Input type="number" {...register("englishAuctionId")} />
<FormHelperText>
The english auction ID the embed should display
</FormHelperText>
</FormControl>
) : null}
{ercOrMarketplace === "erc1155" ? (
<FormControl>
<FormLabel>Token ID</FormLabel>
<Input type="number" {...register("tokenId")} />
<FormHelperText>
The token ID the embed should display
</FormHelperText>
</FormControl>
) : null}
{ercOrMarketplace === "marketplace" ? (
<FormControl>
<FormLabel>Listing ID</FormLabel>
<Input type="number" {...register("listingId")} />
<FormHelperText>
The listing ID the embed should display
</FormHelperText>
</FormControl>
) : null}
<FormLabel>Client ID</FormLabel>
{!activeAccount ? (
<Button asChild className="w-full">
<Link
href={`/login${
pathname ? `?next=${encodeURIComponent(pathname)}` : ""
}`}
>
Sign in to create a client ID
</Link>
</Button>
) : validApiKey ? (
<Input
readOnly
disabled
value={`${validApiKey?.name} - ${validApiKey?.key}`}
/>
) : (
<Button
className="w-full"
onClick={() => {
trackEvent({
category: "api-keys",
action: "create",
label: "attempt",
fromEmbed: true,
});
{ercOrMarketplace === "marketplace-v3" ? (
<FormControl>
<FormLabel>Listing type</FormLabel>
<Select {...register("listingType")}>
<option value="direct-listing">Direct Listing</option>
<option value="english-auction">English Auction</option>
</Select>
<FormHelperText>
The type of listing the embed should display
</FormHelperText>
</FormControl>
) : null}
{ercOrMarketplace === "marketplace-v3" &&
watch("listingType") === "direct-listing" ? (
<FormControl>
<FormLabel>Direct Listing ID</FormLabel>
<Input type="number" {...register("directListingId")} />
<FormHelperText>
The direct listing ID the embed should display
</FormHelperText>
</FormControl>
) : null}
{ercOrMarketplace === "marketplace-v3" &&
watch("listingType") === "english-auction" ? (
<FormControl>
<FormLabel>English Auction ID</FormLabel>
<Input type="number" {...register("englishAuctionId")} />
<FormHelperText>
The english auction ID the embed should display
</FormHelperText>
</FormControl>
) : null}
{ercOrMarketplace === "erc1155" ? (
<FormControl>
<FormLabel>Token ID</FormLabel>
<Input type="number" {...register("tokenId")} />
<FormHelperText>
The token ID the embed should display
</FormHelperText>
</FormControl>
) : null}
<FormControl>
<FormLabel>Client ID</FormLabel>
{!activeAccount ? (
<Button asChild className="w-full">
<Link
href={`/login${
pathname ? `?next=${encodeURIComponent(pathname)}` : ""
}`}
setShowCreateAPIKeyModal(true);
}}
disabled={createKeyMutation.isPending}
>
Sign in to create a client ID
</Link>
</Button>
) : validApiKey ? (
<Input
readOnly
disabled
value={`${validApiKey?.name} - ${validApiKey?.key}`}
/>
) : (
<Button
className="w-full"
onClick={() => {
trackEvent({
category: "api-keys",
action: "create",
label: "attempt",
fromEmbed: true,
});
setShowCreateAPIKeyModal(true);
}}
disabled={createKeyMutation.isPending}
>
Create Client ID
</Button>
)}
<FormHelperText>
You need a client ID to use embeds.{" "}
<Link
href="https://portal.thirdweb.com/account/api-keys"
className="text-link-foreground hover:text-foreground"
target="_blank"
>
Learn more
</Link>
.
</FormHelperText>
</FormControl>
<FormControl>
<FormLabel>RPC Url</FormLabel>
<Input type="url" {...register("rpcUrl")} />
<FormHelperText>
RPC the embed should use to connect to the blockchain.
</FormHelperText>
</FormControl>
{ercOrMarketplace === "marketplace" ||
ercOrMarketplace === "marketplace-v3" ? null : (
<FormControl gap={4}>
<Heading size="title.sm" my={4}>
Gasless
</Heading>
<Select {...register("gasless")} mb={4}>
<option value="false">Disabled</option>
<option value="openZeppelin">OpenZeppelin Relayer</option>
<option value="biconomy">Biconomy Relayer</option>
</Select>
{watch("gasless") === "openZeppelin" && (
<FormControl>
<FormLabel>OpenZeppelin Relayer URL</FormLabel>
<Input type="url" {...register("relayUrl")} />
</FormControl>
)}
{watch("gasless") === "biconomy" && (
<Flex gap={4} flexDir="column">
<FormControl>
<FormLabel>Biconomy API key</FormLabel>
<Input type="url" {...register("biconomyApiKey")} />
</FormControl>
<FormControl>
<FormLabel>Biconomy API ID</FormLabel>
<Input type="url" {...register("biconomyApiId")} />
</FormControl>
</Flex>
Create Client ID
</Button>
)}
<FormHelperText>
A relayer can be used to make the transaction gasless for the
end user.{" "}
You need a client ID to use embeds.{" "}
<Link
target="_blank"
href="https://portal.thirdweb.com/account/api-keys"
className="text-link-foreground hover:text-foreground"
href="https://blog.thirdweb.com/guides/setup-gasless-transactions"
target="_blank"
>
Learn more
</Link>
.
</FormHelperText>
</FormControl>
)}
<FormControl>
<Heading size="title.sm" my={4}>
Customization
</Heading>
<FormLabel>Theme</FormLabel>
<Select {...register("theme")}>
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="system">User system</option>
</Select>
<FormHelperText>
Selecting system will make it so the embed would change depending
on the user system&apos;s preferences.
</FormHelperText>
</FormControl>
<FormControl>
<FormLabel>Primary Color</FormLabel>
<Select {...register("primaryColor")}>
{ercOrMarketplace === "erc721" && (
<option value="default">Default</option>
)}
{colorOptions.map((color) => (
<option key={color} value={color}>
{color[0]?.toUpperCase() + color.substring(1)}
</option>
))}
</Select>
<FormHelperText>
Used for the main actions button backgrounds.
</FormHelperText>
</FormControl>
{ercOrMarketplace === "marketplace" ||
ercOrMarketplace === "marketplace-v3" ? (
<FormControl>
<FormLabel>Secondary Color</FormLabel>
<Select {...register("secondaryColor")}>
<FormLabel>RPC Url</FormLabel>
<Input type="url" {...register("rpcUrl")} />
<FormHelperText>
RPC the embed should use to connect to the blockchain.
</FormHelperText>
</FormControl>
{ercOrMarketplace === "marketplace" ||
ercOrMarketplace === "marketplace-v3" ? null : (
<FormControl gap={4}>
<Heading size="title.sm" mb={2}>
Gasless
</Heading>
<Select {...register("gasless")} mb={4}>
<option value="false">Disabled</option>
<option value="openZeppelin">OpenZeppelin Relayer</option>
<option value="biconomy">Biconomy Relayer</option>
</Select>
{watch("gasless") === "openZeppelin" && (
<FormControl>
<FormLabel>OpenZeppelin Relayer URL</FormLabel>
<Input type="url" {...register("relayUrl")} />
</FormControl>
)}
{watch("gasless") === "biconomy" && (
<Flex gap={4} flexDir="column">
<FormControl>
<FormLabel>Biconomy API key</FormLabel>
<Input type="url" {...register("biconomyApiKey")} />
</FormControl>
<FormControl>
<FormLabel>Biconomy API ID</FormLabel>
<Input type="url" {...register("biconomyApiId")} />
</FormControl>
</Flex>
)}
<FormHelperText>
A relayer can be used to make the transaction gasless for the
end user.{" "}
<Link
target="_blank"
className="text-link-foreground hover:text-foreground"
href="https://blog.thirdweb.com/guides/setup-gasless-transactions"
>
Learn more
</Link>
</FormHelperText>
</FormControl>
)}
<FormControl>
<FormLabel>Theme</FormLabel>
<Select {...register("theme")}>
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="system">User system</option>
</Select>
<FormHelperText>
Selecting system will make it so the embed would change
depending on the user system&apos;s preferences.
</FormHelperText>
</FormControl>
<FormControl>
<FormLabel>Primary Color</FormLabel>
<Select {...register("primaryColor")}>
{ercOrMarketplace === "erc721" && (
<option value="default">Default</option>
)}
{colorOptions.map((color) => (
<option key={color} value={color}>
{color[0]?.toUpperCase() + color.substring(1)}
@@ -529,21 +547,38 @@ export const EmbedSetup: React.FC<EmbedSetupProps> = ({
))}
</Select>
<FormHelperText>
Use for secondary actions (like when the user is connected to
the wrong network)
Used for the main actions button backgrounds.
</FormHelperText>
</FormControl>
) : null}
</Card>
<Card className="flex w-full flex-col gap-2 md:w-1/2">
<Heading size="title.sm">Embed Code</Heading>
<CodeClient code={embedCode} lang="html" />
<Button
className="w-auto gap-2"
variant="outline"
onClick={() => {
onCopy();
{ercOrMarketplace === "marketplace" ||
ercOrMarketplace === "marketplace-v3" ? (
<FormControl>
<FormLabel>Secondary Color</FormLabel>
<Select {...register("secondaryColor")}>
{colorOptions.map((color) => (
<option key={color} value={color}>
{color[0]?.toUpperCase() + color.substring(1)}
</option>
))}
</Select>
<FormHelperText>
Use for secondary actions (like when the user is connected to
the wrong network)
</FormHelperText>
</FormControl>
) : null}
</Card>
</div>
<div>
<h2 className="mb-3 font-semibold text-xl tracking-tight">
Embed Code
</h2>
<CodeClient
code={embedCode}
lang="html"
onCopy={() => {
trackEvent({
category: "embed",
action: "click",
@@ -552,19 +587,15 @@ export const EmbedSetup: React.FC<EmbedSetupProps> = ({
chainId,
});
}}
>
{hasCopied ? (
<CheckIcon className="size-4" />
) : (
<CopyIcon className="size-4" />
)}
{hasCopied ? "Copied!" : "Copy to clipboard"}
</Button>
</Card>
</Flex>
/>
</div>
</div>
<div className="flex flex-col items-center gap-2">
<Heading size="title.sm">Preview</Heading>
<div className="h-8" />
<h2 className="mb-3 font-semibold text-xl tracking-tight">Preview</h2>
<div className="overflow-hidden rounded-lg border border-border">
{!validApiKey ? (
<Text>You need to create a client ID to use embeds</Text>
) : iframeSrc ? (
@@ -577,6 +608,6 @@ export const EmbedSetup: React.FC<EmbedSetupProps> = ({
/>
) : null}
</div>
</Flex>
</div>
);
};
@@ -35,7 +35,7 @@ export const ContractExplorerPage: React.FC<ContractExplorePageProps> = ({
const functions = getContractFunctionsFromAbi(abi);
return (
<div className="flex h-[70vh] flex-col">
<div className="flex h-[70vh] flex-col ">
{functions && functions.length > 0 ? (
<ContractFunctionsOverview
onlyFunctions
@@ -44,7 +44,7 @@ export const ContractExplorerPage: React.FC<ContractExplorePageProps> = ({
twAccount={twAccount}
/>
) : (
<div className="flex flex-col items-center justify-center gap-2 text-center">
<div className="flex flex-col items-center justify-center gap-2 bg-card text-center">
<h2 className="font-semibold text-2xl tracking-tight">
No callable functions discovered in ABI.
</h2>
@@ -4,13 +4,13 @@ import { ScrollShadow } from "@/components/ui/ScrollShadow/ScrollShadow";
import { Alert, AlertTitle } from "@/components/ui/alert";
import type { Account as TWAccount } from "@3rdweb-sdk/react/hooks/useApi";
import { CircleSlash } from "lucide-react";
import type { ContractOptions } from "thirdweb";
import type { ThirdwebContract } from "thirdweb/contract";
import type { Account } from "thirdweb/wallets";
import { ModuleCard } from "./module-card";
import { useAllModuleContractInfo } from "./moduleContractInfo";
export const InstalledModulesTable = (props: {
contract: ContractOptions;
contract: ThirdwebContract;
installedModules: {
data?: string[];
isPending: boolean;
@@ -15,8 +15,9 @@ import { FormProvider, type UseFormReturn, useForm } from "react-hook-form";
import { toast } from "sonner";
import {
type Chain,
type ContractOptions,
type ThirdwebClient,
type ThirdwebContract,
getContract,
sendTransaction,
waitForReceipt,
} from "thirdweb";
@@ -47,7 +48,7 @@ type FormData = {
};
type InstallModuleFormProps = {
contract: ContractOptions;
contract: ThirdwebContract;
refetchModules: () => void;
account: Account;
installedModules: {
@@ -180,11 +181,13 @@ export const InstallModuleForm = (props: InstallModuleFormProps) => {
return Promise.all(
moduleAddress.map(async (address) => {
const result = await resolveImplementation({
client,
address,
chain: contract.chain,
});
const result = await resolveImplementation(
getContract({
client,
address,
chain: contract.chain,
}),
);
if (!result) {
throw new Error("Failed to fetch bytecode for module");
@@ -23,7 +23,7 @@ import { Suspense, useEffect, useState } from "react";
import { ErrorBoundary, type FallbackProps } from "react-error-boundary";
import { toast } from "sonner";
import {
type ContractOptions,
type ThirdwebContract,
getContract,
sendTransaction,
waitForReceipt,
@@ -35,7 +35,7 @@ import { useModuleContractInfo } from "./moduleContractInfo";
type ModuleCardProps = {
moduleAddress: string;
contract: ContractOptions;
contract: ThirdwebContract;
onRemoveModule: () => void;
ownerAccount: Account | undefined;
allModuleContractInfo: {
@@ -204,7 +204,7 @@ export type ModuleCardUIProps = {
export function ModuleCardUI(props: ModuleCardUIProps) {
return (
<section className="rounded-lg border border-border bg-muted/50">
<section className="rounded-lg border border-border bg-card">
{/* Header */}
<div className="relative p-4 lg:p-6">
{/* Title */}
@@ -239,7 +239,7 @@ export const NFTGetAllTable: React.FC<ContractOverviewNFTGetAllProps> = ({
<Flex gap={4} direction="column">
<TableContainer
maxW="100%"
className="relative rounded-lg border border-border"
className="relative rounded-lg border border-border bg-card"
>
{getNFTsQuery.isFetching && (
<Spinner
@@ -251,7 +251,7 @@ export const NFTGetAllTable: React.FC<ContractOverviewNFTGetAllProps> = ({
/>
)}
<Table {...getTableProps()}>
<Thead className="!bg-muted/50">
<Thead className="!bg-background">
{headerGroups.map((headerGroup, headerGroupIndex) => (
// biome-ignore lint/suspicious/noArrayIndexKey: FIXME
<Tr {...headerGroup.getHeaderGroupProps()} key={headerGroupIndex}>
@@ -275,7 +275,7 @@ export const NFTGetAllTable: React.FC<ContractOverviewNFTGetAllProps> = ({
<Tbody
{...getTableBodyProps()}
position="relative"
className="!bg-background"
className="!bg-card"
>
{page.map((row, rowIndex) => {
const failedToLoad = !row.original.tokenURI;
@@ -284,7 +284,7 @@ export const NFTGetAllTable: React.FC<ContractOverviewNFTGetAllProps> = ({
<Tr
{...row.getRowProps()}
role="group"
className="hover:bg-muted/50"
className="bg-card hover:bg-accent/50"
style={{ cursor: "pointer" }}
onClick={() => {
const tokenId = row.original.id;
@@ -135,7 +135,7 @@ function OverviewAnalytics(props: ChartProps) {
data={mergedData || []}
isPending={isPending}
showLegend
chartClassName="aspect[2] lg:aspect-[4.5]"
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
/>
);
}
@@ -265,7 +265,7 @@ const ListingCards: React.FC<ListingCardsProps> = ({
<div className="grid grid-cols-2 gap-3 md:grid-cols-3 md:gap-6 max-sm:[&>*:nth-child(n+3)]:hidden">
{listings.map((listing, index) => (
<div
className="relative rounded-lg border border-border bg-muted/50 hover:border-foreground hover:bg-muted"
className="relative rounded-lg border border-border bg-card transition-colors hover:border-active-border"
key={`${listing.creatorAddress}-${index}`}
>
<div className="relative aspect-square w-full overflow-hidden rounded-lg">
@@ -6,7 +6,7 @@ export function StatCard(props: {
label: string;
}) {
return (
<dl className="block rounded-lg border border-border bg-muted/50 p-4">
<dl className="block rounded-lg border border-border bg-card p-4">
<dt className="mb-1.5 text-sm md:text-base">{props.label}</dt>
<SkeletonContainer
loadedData={props.isPending ? undefined : props.value}
@@ -157,7 +157,7 @@ export const AirdropUpload: React.FC<AirdropUploadProps> = ({
<div
className={cn(
"flex h-full cursor-pointer items-center justify-center rounded-md border border-border hover:border-primary",
noCsv ? "bg-red-200" : "bg-card",
noCsv ? "bg-red-200" : "bg-background",
)}
{...getRootProps()}
>
@@ -193,7 +193,11 @@ export const AirdropUpload: React.FC<AirdropUploadProps> = ({
Files <em>must</em> contain one .csv file with an address and
quantity column, if the quantity column is not provided, that
record will be flagged as invalid.
<Link download color="primary.500" href="/airdrop.csv">
<Link
download
color="primary.500"
href="/assets/examples/airdrop.csv"
>
Download an example CSV
</Link>
</li>
@@ -158,7 +158,7 @@ export default async function Page(props: {
<div className="grid grid-cols-2 items-start">
<div className="flex items-center gap-x-2">Raw Input:</div>
<div className="break-words rounded-lg bg-muted/50 p-4 text-sm">
<div className="break-words rounded-lg bg-card p-4 text-sm">
{transaction.input}
</div>
</div>
@@ -182,7 +182,9 @@ export const ChainTypeFilter: React.FC<ChainTypeFilterProps> = ({
<PopoverTrigger asChild>
<Button
variant="outline"
className={value === "all" ? undefined : "border-primary pr-11"}
className={
value === "all" ? "bg-card" : "border-active-border bg-card pr-11"
}
>
{value === "mainnets"
? "Mainnets Only"
@@ -196,7 +198,7 @@ export const ChainTypeFilter: React.FC<ChainTypeFilterProps> = ({
<Button
variant="ghost"
size="icon"
className="absolute top-[1px] right-[1px] bottom-[1px] h-auto w-10"
className="absolute top-[1px] right-[1px] bottom-[1px] h-auto w-10 bg-card"
onClick={() => {
const url = makeUrl("all");
router.replace(url);
@@ -275,7 +277,9 @@ export const ChainOptionsFilter: React.FC<ChainOptionsFilterProps> = ({
<PopoverTrigger asChild>
<Button
variant="outline"
className={hasFilters ? "border-primary pr-11" : undefined}
className={
hasFilters ? "border-active-border bg-card pr-11" : "bg-card"
}
>
Chain Options
{!hasFilters && <ChevronDownIcon className="ml-2 size-4" />}
@@ -285,7 +289,7 @@ export const ChainOptionsFilter: React.FC<ChainOptionsFilterProps> = ({
<Button
variant="ghost"
size="icon"
className="absolute top-[1px] right-[1px] bottom-[1px] h-auto w-10"
className="absolute top-[1px] right-[1px] bottom-[1px] h-auto w-10 bg-card"
onClick={() => {
mutableSearchParams.delete("includeDeprecated");
mutableSearchParams.delete("page");
@@ -399,7 +403,9 @@ export const ChainServiceFilter: React.FC<ChainServiceFilterProps> = ({
<PopoverTrigger asChild>
<Button
variant="outline"
className={hasActiveFilter ? "border-primary pr-11" : undefined}
className={
hasActiveFilter ? "border-active-border bg-card pr-11" : "bg-card"
}
>
{buttonTitle}
{!hasActiveFilter && <ChevronDownIcon className="ml-2 size-4" />}
@@ -48,7 +48,7 @@ export const SearchInput: React.FC = () => {
<SearchIcon className="-translate-y-1/2 absolute top-[50%] left-3 size-4 text-muted-foreground" />
<Input
placeholder="Search by name or chain ID"
className="h-10 rounded-lg py-2 pl-9"
className="h-10 rounded-lg bg-card py-2 pl-9 lg:min-w-[300px]"
defaultValue={searchParams?.get("query") || ""}
onChange={(e) => handleSearch(e.target.value)}
ref={inputRef}
@@ -33,7 +33,7 @@ export async function ChainListCard({
return (
<div className="relative h-full">
<Card className="h-full w-full bg-muted/50 hover:bg-muted">
<Card className="h-full w-full transition-colors hover:border-active-border">
<CardHeader className="flex flex-row items-center justify-between p-4">
<div className="flex flex-row items-center gap-2">
<ChainIcon iconUrl={iconUrl} className="size-6" />
@@ -39,7 +39,7 @@ export async function ChainListRow({
}: ChainListRowProps) {
const chainMetadata = await getChainMetadata(chainId);
return (
<TableRow linkBox className="hover:bg-muted/50">
<TableRow linkBox className="hover:bg-accent/50">
{/* Name */}
<TableCell>
<div className="flex w-[370px] flex-row items-center gap-4">
@@ -52,7 +52,7 @@ export default async function ChainListPage(props: {
</h1>
<AddYourChainButton className="lg:hidden" />
</div>
<div className="flex flex-row items-end gap-4 lg:flex-col">
<div className="flex flex-row items-end gap-4 lg:flex-col ">
<div className="flex w-full flex-row gap-4">
<SearchInput />
<ChainListView activeView={activeView} />
Binary file not shown.

After

Width:  |  Height:  |  Size: 919 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 KiB

After

Width:  |  Height:  |  Size: 918 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 764 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 546 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 546 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 KiB

@@ -38,17 +38,19 @@ import creatorCTA from "./temp-assets/creatorCTA.png";
import lumiaBanner from "./temp-assets/lumiaBanner.png";
import somniaBanner from "./temp-assets/somniaBanner.png";
import plumeBannerv2 from "./temp-assets/plumev2Banner.png";
import plumeCTAv2 from "./temp-assets/plumev2CTA.png";
import flowBanner from "./temp-assets/flowBanner.png";
import flowCTA from "./temp-assets/flowCTA.png";
import mantleBanner from "./temp-assets/mantle.png";
import metalBanner from "./temp-assets/metalBanner.png";
import metalCTA from "./temp-assets/metalCTA.png";
import plumeBanner from "./temp-assets/plumeBanner.png";
import plumeCTA from "./temp-assets/plumeCTA.png";
import rivalzBanner from "./temp-assets/rivalzBanner.png";
import rivalzCTA from "./temp-assets/rivalzCTA.png";
import rootStockBanner from "./temp-assets/rootstock-banner.png";
import rootStockCTABG from "./temp-assets/rootstock-cta.png";
import saakuruBanner from "./temp-assets/saakuruBanner.png";
import saakuruCTA from "./temp-assets/saakuruCTA.png";
import shidoBanner from "./temp-assets/shidoBanner.png";
import shidoCta from "./temp-assets/shidoCta.png";
import soneiumBanner from "./temp-assets/soneiumBanner.png";
@@ -59,15 +61,15 @@ import treasureBanner from "./temp-assets/treasureBanner.png";
import treasureCTA from "./temp-assets/treasureCta.png";
import vanarBanner from "./temp-assets/vanar-banner.png";
import vanarCTABG from "./temp-assets/vanar-cta.png";
import victionBanner from "./temp-assets/victionBanner.png";
import victionCTA from "./temp-assets/victionCTA.png";
import worldChainBanner from "./temp-assets/worldChainBanner.jpg";
import worldChainCTA from "./temp-assets/worldChainCTA.jpg";
import xaiBanner from "./temp-assets/xai-banner.jpg";
import zetachainBanner from "./temp-assets/zetachainBanner.png";
import zetachainCTA from "./temp-assets/zetachainCTA.png";
import zytronBanner from "./temp-assets/zytronBanner.png";
import zytronCTA from "./temp-assets/zytronCTA.jpg";
import fhenixBanner from "./temp-assets/fhenixBanner.png";
import fhenixCTA from "./temp-assets/fhenixCTA.png";
// END TEMPORARY
import { API_SERVER_URL } from "@/constants/env";
@@ -169,6 +171,11 @@ const chainMetaRecord = {
cta: OP_CTA,
},
//celo Mainnet
42220: {
cta: OP_CTA,
gasSponsored: true,
},
// optimism
10: {
cta: OP_CTA,
@@ -419,15 +426,29 @@ const chainMetaRecord = {
buttonText: "Learn More",
},
},
//fhenix Nitrogen
8008148: {
headerImgUrl: fhenixBanner.src,
//EVM on Flow testnet
545: {
headerImgUrl: flowBanner.src,
about:
"Discover Fhenix—the first-ever FHE-based blockchain. Fhenix is an L2 built on Ethereum that brings powerful Fully Homomorphic Encryption (FHE) into the EVM space. This technology enables confidential computation on-chain, allowing users to explore a new generation of use cases.",
"Flow is a secure, high-performance, decentralized L1 EVM equivalent chain, with innovative next-generation features not available on other EVM compatible chains, the lowest fees anywhere, and a vibrant ecosystem of major consumer brands",
cta: {
backgroundImageUrl: fhenixCTA.src,
title: "Onchain confidentiality powered by the first FHE L2 Rollup",
buttonLink: "https://thirdweb.com/fhenix-nitrogen",
backgroundImageUrl: flowCTA.src,
title:
"Explore Flow's innovative features not available on any other EVM compatible chain",
buttonLink: "https://developers.flow.com/evm/how-it-works",
buttonText: "Learn More",
},
},
//EVM on Flow Mainnet
747: {
headerImgUrl: flowBanner.src,
about:
"Flow is a secure, high-performance, decentralized L1 EVM equivalent chain, with innovative next-generation features not available on other EVM compatible chains, the lowest fees anywhere, and a vibrant ecosystem of major consumer brands",
cta: {
backgroundImageUrl: flowCTA.src,
title:
"Learn about innovative features not available on any other EVM compatible chains!",
buttonLink: "https://developers.flow.com/evm/how-it-works",
buttonText: "Learn More",
},
},
@@ -467,7 +488,7 @@ const chainMetaRecord = {
buttonText: "Learn More",
},
},
//Gemuchain
//Gemuchain -- Deprecated
1903648807: {
headerImgUrl: thirdwebBanner.src,
about:
@@ -547,12 +568,19 @@ const chainMetaRecord = {
headerImgUrl: metalBanner.src,
about:
"Metal L2 is a banking-focused Layer 2 blockchain built on the Optimism Superchain, designed to enable direct on-chain fiat deposits through its connection to The Digital Banking Network—an open-source blockchain banking protocol developed by Metallicus",
cta: {
backgroundImageUrl: metalCTA.src,
title: "Connect to The Banking Layer, Metal L2",
buttonLink: "https://metall2.com/",
buttonText: "Connect Here",
},
// cta: {
// backgroundImageUrl: metalCTA.src,
// title: "Connect to The Banking Layer, Metal L2",
// buttonLink: "https://metall2.com/",
// buttonText: "Connect Here",
// },
cta: OP_CTA,
gasSponsored: true,
},
//Ozean Testnet
7849306: {
cta: OP_CTA,
gasSponsored: true,
},
//0G-Newton-Testnet
16600: {
@@ -566,11 +594,11 @@ const chainMetaRecord = {
buttonText: "Learn more",
},
},
//Plume
161221135: {
//Plume Testnet
98864: {
headerImgUrl: plumeBanner.src,
about:
"Plume is the first modular L2 blockchain dedicated for all real-world assets (RWAs) that integrates asset tokenization and compliance providers directly into the chain. Our mission is to simplify the convoluted processes of RWA project deployment and offer investors a blockchain ecosystem to cross-pollinate and invest in various RWAs. In addition, Plume enables RWA composability through its thriving DeFi applications and provides access to high-quality buyers to increase liquidity for all tokenized RWAs.",
"Plume Network is the first full-stack L1 RWA Chain and ecosystem purpose-built for RWAfi, enabling the rapid adoption and demand-driven integration of real world assets. With 180+ projects building on the network, Plume offers a composable, EVM-compatible environment for onboarding and managing diverse real world assets. Coupled with an end-to-end tokenization engine and a network of financial infrastructure partners, Plume simplifies asset onboarding and enables seamless DeFi integration for RWAs so anyone can tokenize real world assets, distribute them globally, and make them useful for native crypto users.",
cta: {
backgroundImageUrl: plumeCTA.src,
title: "Participate on the Testnet Now!",
@@ -578,27 +606,64 @@ const chainMetaRecord = {
buttonText: "Learn more",
},
},
98864: {
headerImgUrl: plumeBannerv2.src,
//Plume Mainnet
98865: {
headerImgUrl: plumeBanner.src,
about:
"Plume is the first full stack L1 blockchain purpose-built for RWAfi. Our products and chain make it easy for anyone to interact with RWAs just like they would with any other crypto native asset. Earn, trade, speculate on anything from financial instruments, collectibles, alternative assets, and more.",
"Plume Network is the first full-stack L1 RWA Chain and ecosystem purpose-built for RWAfi, enabling the rapid adoption and demand-driven integration of real world assets. With 180+ projects building on the network, Plume offers a composable, EVM-compatible environment for onboarding and managing diverse real world assets. Coupled with an end-to-end tokenization engine and a network of financial infrastructure partners, Plume simplifies asset onboarding and enables seamless DeFi integration for RWAs so anyone can tokenize real world assets, distribute them globally, and make them useful for native crypto users.",
cta: {
backgroundImageUrl: plumeCTAv2.src,
backgroundImageUrl: plumeCTA.src,
title: "Bringing the Real World Onchain",
buttonLink: "https://plumenetwork.xyz/",
buttonLink: "https://miles.plumenetwork.xyz/",
buttonText: "Learn more",
},
},
//Plume
98865: {
headerImgUrl: plumeBannerv2.src,
//Rivalz Mainnet
753: {
headerImgUrl: rivalzBanner.src,
about:
"Plume is the first full stack L1 blockchain purpose-built for RWAfi. Our products and chain make it easy for anyone to interact with RWAs just like they would with any other crypto native asset. Earn, trade, speculate on anything from financial instruments, collectibles, alternative assets, and more.",
"Rivalz merges real-world economies with AI, redefining how agents interact with global resources. Through its modular infrastructure, Rivalz enables AI agents to tap into the global workforce, digital services, and DePIN—from computers to smart homes—seamlessly connecting AI with reality.",
cta: {
backgroundImageUrl: plumeCTAv2.src,
title: "Bringing the Real World Onchain",
buttonLink: "https://plumenetwork.xyz/",
buttonText: "Learn more",
backgroundImageUrl: rivalzCTA.src,
title: "Empower the Age of AI Agents with Rivalz",
buttonLink: "https://rivalz.ai/download",
buttonText: "Learn More",
},
},
//Rivalz Testnet
6966: {
headerImgUrl: rivalzBanner.src,
about:
"Rivalz merges real-world economies with AI, redefining how agents interact with global resources. Through its modular infrastructure, Rivalz enables AI agents to tap into the global workforce, digital services, and DePIN—from computers to smart homes—seamlessly connecting AI with reality.",
cta: {
backgroundImageUrl: rivalzCTA.src,
title: "Empower the Age of AI Agents with Rivalz",
buttonLink: "https://rivalz.ai/download",
buttonText: "Learn More",
},
},
//Saakuru Mainnet
7225878: {
headerImgUrl: saakuruBanner.src,
about:
"Saakuru Labs is a Web3 GameFi innovation and growth hub, dedicated to empowering game studios through tailored collaborations that cater to their unique needs and stages of game development. By providing a structured process to evaluate and support studios, Saakuru Labs aims to expand the Saakuru gaming ecosystem while ensuring the success of its partners.",
cta: {
backgroundImageUrl: saakuruCTA.src,
title: "Empowering Next-Gen Blockchain Gaming",
buttonLink: "https://saakuru.com/",
buttonText: "Learn More",
},
},
//Saakuru Testnet
247253: {
headerImgUrl: saakuruBanner.src,
about:
"Saakuru Labs is a Web3 GameFi innovation and growth hub, dedicated to empowering game studios through tailored collaborations that cater to their unique needs and stages of game development. By providing a structured process to evaluate and support studios, Saakuru Labs aims to expand the Saakuru gaming ecosystem while ensuring the success of its partners.",
cta: {
backgroundImageUrl: saakuruCTA.src,
title: "Empowering Next-Gen Blockchain Gaming",
buttonLink: "https://saakuru.com/",
buttonText: "Learn More",
},
},
//Somnia Devnet
@@ -613,6 +678,63 @@ const chainMetaRecord = {
buttonText: "Learn More",
},
},
//Unichain Sepolis Testnet
1301: {
cta: OP_CTA,
gasSponsored: true,
},
//viction Mainnet
88: {
headerImgUrl: victionBanner.src,
about:
"Viction is a global layer-1 EVM blockchain that empowers builders at every level, provides both the foundation and enhancements necessary for projects to achieve stability and soar to their higher selves. \n We provide seamless interoperability, scalability, flexible development, zero gas fees, enhanced security, and speed to enable builders with tech capabilities. Beyond technical advantages, Viction offers holistic guidance through consultation, resources, funding, and strong network connections to foster project growth.",
cta: {
backgroundImageUrl: victionCTA.src,
title:
"Build, own, win, and be part of Viction World Wide Chain where everyone scales beyond limits.",
buttonLink: "https://thirdweb.com/viction",
buttonText: "Learn More",
},
},
//viction Testnet
89: {
headerImgUrl: victionBanner.src,
about:
"Viction is a global layer-1 EVM blockchain that empowers builders at every level, provides both the foundation and enhancements necessary for projects to achieve stability and soar to their higher selves. \n We provide seamless interoperability, scalability, flexible development, zero gas fees, enhanced security, and speed to enable builders with tech capabilities. Beyond technical advantages, Viction offers holistic guidance through consultation, resources, funding, and strong network connections to foster project growth.",
cta: {
backgroundImageUrl: victionCTA.src,
title:
"Build, own, win, and be part of Viction World Wide Chain where everyone scales beyond limits.",
buttonLink: "https://thirdweb.com/viction",
buttonText: "Learn More",
},
},
// World Chain Mainnet
480: {
headerImgUrl: worldChainBanner.src,
about:
"World Chain is the blockchain for real humans, offering priority blockspace and gas-free transactions for World ID-verified users.",
// cta: {
// backgroundImageUrl: worldChainCTA.src,
// title: "Build for real humans with World Chain",
// buttonLink: "https://world.org/world-chain",
// buttonText: "Learn More",
// },
cta: OP_CTA,
gasSponsored: true,
},
//World Chain Testnet
4801: {
headerImgUrl: worldChainBanner.src,
about:
"World Chain is the blockchain for real humans, offering priority blockspace and gas-free transactions for World ID-verified users.",
cta: {
backgroundImageUrl: worldChainCTA.src,
title: "Build for real humans with World Chain",
buttonLink: "https://world.org/world-chain",
buttonText: "Learn More",
},
},
//zkCandy
302: {
headerImgUrl: thirdwebBanner.src,
@@ -721,13 +843,20 @@ const chainMetaRecord = {
buttonText: "Learn more",
},
},
//Soneium
//Soneium Testnet
1946: {
headerImgUrl: soneiumBanner.src,
about:
"Soneium, an Ethereum layer-2 developed by Sony Block Solutions Labs. This versatile chain is a general-purpose blockchain platform that aims to evoke emotion, empower creativity, and meet diverse needs to go mainstream. Soneium will be simplifying blockchain experiences while empowering developers, creators, and communities. Built on accessibility, scalability, and efficiency, it aims to solve real-world problems across industries globally. Soneium will change the way we interact with the internet, opening up a world of innovative applications and unlimited potential for users worldwide.",
cta: OP_CTA,
},
//Soneium Mainnet
1868: {
headerImgUrl: soneiumBanner.src,
about:
"Soneium, an Ethereum layer-2 developed by Sony Block Solutions Labs. This versatile chain is a general-purpose blockchain platform that aims to evoke emotion, empower creativity, and meet diverse needs to go mainstream. Soneium will be simplifying blockchain experiences while empowering developers, creators, and communities. Built on accessibility, scalability, and efficiency, it aims to solve real-world problems across industries globally. Soneium will change the way we interact with the internet, opening up a world of innovative applications and unlimited potential for users worldwide.",
cta: OP_CTA,
},
//Shido
9008: {
headerImgUrl: shidoBanner.src,

Some files were not shown because too many files have changed in this diff Show More