Compare commits

...
Author SHA1 Message Date
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
f2c12781ef Version Packages (#4044)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-08-15 17:14:31 +12:00
kien-ngo 9d7d513d37 [Dashboard] PrimarySaleRecipient to v5 (#4098)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on updating the contract UI settings for primary sale recipient address handling.

### Detailed summary
- Updated handling of primary sale recipient address in contract settings UI
- Refactored usage of Thirdweb SDK functions
- Added error handling for invalid recipient address
- Improved transaction handling and form reset functionality

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

<!-- end pr-codex -->
2024-08-15 01:11:20 +00:00
kien-ngo 10de2712dd [Dashboard] Remove useClaimNFT; use erc1155/claimTo (#4102)
The component in this PR is meant for Edition Drop only

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update the `ClaimTab` component to support ERC1155 contracts and improve transaction handling.

### Detailed summary
- Renamed `ClaimTab` component to `ClaimTabERC1155`.
- Updated `ClaimTabERC1155` to work with ERC1155 contracts.
- Improved transaction handling in `ClaimTabERC1155`.
- Removed unnecessary imports and updated dependencies.

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

<!-- end pr-codex -->
2024-08-15 00:59:13 +00:00
gregfromstl 0ca1a79342 feat: cleanup ui (#4092)
- Reduced border radius on buttons
- Reduced connected button size
- Removed layout shift between connected and unconnected states
- Remove Rainbow from default wallets (replaced with Rabby)

https://github.com/user-attachments/assets/334f09d5-46d1-40e3-8b3a-5937771f277c

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on UI cosmetic improvements for wallet-related components.

### Detailed summary
- Added `io.rabby` wallet
- Adjusted padding and borderRadius in various components
- Modified button sizes and styles
- Updated wallet image sizes and text styles

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

<!-- end pr-codex -->
2024-08-15 00:44:18 +00:00
kien-ngo be344ac8c4 [Dashboard] Migration Royalties to v5 (#4051)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the `SettingsRoyalties` component to use new contract and royalty information and improves error handling during royalty settings updates.

### Detailed summary
- Updated `SettingsRoyalties` component to use new contract and royalty information
- Improved error handling during royalty settings updates
- Replaced `thirdweb` imports with `sonner` and `thirdweb/react`
- Refactored default royalty info handling and transaction mutation logic

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

<!-- end pr-codex -->
2024-08-15 00:26:39 +00:00
754ad99cfd Feat: Transaction Simulator (#3715)
Co-authored-by: Kien Ngo <[email protected]>
Co-authored-by: Manan Tank <[email protected]>
2024-08-14 17:24:31 -07:00
MananTank d6e4898458 Add Pay success tracking (#4103)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR enhances payment tracking in `MismatchButton` and `PayModalButton` components.

### Detailed summary
- Added tracking events for payment attempts and successes in `MismatchButton` and `PayModalButton`
- Utilized `useTrack` hook for event tracking
- Improved event tracking for different payment types and statuses

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

<!-- end pr-codex -->
2024-08-14 21:37:11 +00:00
YashandGitHub 191fb3a3a6 Modular contracts - rename extensions to modules (#3969) 2024-08-14 21:35:36 +00:00
MananTank 03a809a33f Add onPurchaseSuccess callback for Pay (#4101)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR adds `onPurchaseSuccess` callback to various components and hooks in the codebase, triggering when a user completes a purchase using thirdweb pay.

### Detailed summary
- Added `onPurchaseSuccess` callback to `PayEmbed`, `ConnectButton`, `TransactionButton`, and `useSendTransaction`
- Updated props in multiple components to include `onSuccess` callback parameter
- Added type definitions for `BuyWithCryptoStatus` and `BuyWithFiatStatus`
- Implemented logic to call `onSuccess` callback upon successful purchase completion

> The following files were skipped due to too many changes: `packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatFlow.tsx`

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

<!-- end pr-codex -->
2024-08-14 21:05:41 +00:00
kien-ngo 874ef7af4e [Dashboard] Hide ERC721 Claim button if viewing ERC1155 Drop (#4104)
For Edition Drop we have a dedicated ClaimTabERC1155 inside each Edition's page
2024-08-14 20:10:11 +00:00
joaquim-verges ef9c7df220 feat(native): add passkey support in connect UI (#4077)
## Problem solved

Added passkey UI in connect for react native

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces passkey login support in React Native.

### Detailed summary
- Updated colors in the design system
- Added passkey domain logic
- Improved wallet loading components
- Added passkey authentication screen
- Updated wallet icons and images

> The following files were skipped due to too many changes: `packages/thirdweb/src/react/native/ui/connect/InAppWalletUI.tsx`

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

<!-- end pr-codex -->
2024-08-14 19:44:37 +00:00
joaquim-verges a640a1e147 feat(inapp): add passkey authentication for native clients (#4022)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces support for `passkeyDomain` in in-app wallets, updates error handling in signup screens, and improves storage handling.

### Detailed summary
- Added `passkeyDomain` support in in-app wallets
- Updated error handling in signup screens
- Improved storage handling for in-app wallets

> The following files were skipped due to too many changes: `packages/thirdweb/src/wallets/in-app/web/utils/Storage/LocalStorage.ts`, `packages/thirdweb/src/utils/bytecode/cbor-decode.ts`, `packages/thirdweb/package.json`, `packages/thirdweb/src/wallets/wallet-connect/receiver/session-store.test.ts`, `pnpm-lock.yaml`, `packages/thirdweb/src/wallets/in-app/native/native-connector.ts`, `packages/thirdweb/src/wallets/in-app/web/lib/web-connector.ts`, `packages/thirdweb/src/wallets/in-app/core/authentication/passkeys.ts`, `packages/thirdweb/src/wallets/in-app/native/auth/passkeys.ts`, `packages/thirdweb/src/wallets/in-app/web/lib/auth/passkeys.ts`

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

<!-- end pr-codex -->
2024-08-14 19:44:35 +00:00
kien-ngo 52678e02a8 [Dashboard] use MediaRenderer for contract's avatar (#4095)
- [x] Contract metadata header now uses <MediaRenderer /> instead of <Image/>
This way is works with videos and it gets rid of that weird border-radius bug (see image)

<img width="324" alt="image" src="https://github.com/user-attachments/assets/a57f95c1-eb45-4e6f-8121-0d10358c7c6b">

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to refactor the `MetadataHeader` component in the custom-contract folder by replacing the `resolveScheme` function with `MediaRenderer` for image rendering.

### Detailed summary
- Replaced `resolveScheme` with `MediaRenderer` for image rendering
- Updated image rendering logic with additional props
- Removed unused imports and variables

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

<!-- end pr-codex -->
2024-08-14 14:04:07 +00:00
MananTank b9ed7535a4 Fix Connection with Safe using WalletConnect Link (#4091)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on fixing the connection with Safe using WalletConnect link.

### Detailed summary
- Added support for Safe supported chains in WalletConnect
- Updated chain selection logic based on walletId
- Included specific chains for Safe connection

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

<!-- end pr-codex -->
2024-08-14 11:39:29 +00:00
Joaquim VergesandGitHub 70d4a5a3db fix(dashboard): fix wrong 'version' prop import (#4096) 2024-08-14 21:51:56 +12:00
jnsdls ea28704a04 [Refactor] Remove unused functions and improve faucet validation (#4093) 2024-08-14 00:50:22 +00:00
jnsdls 814024ae24 [Chore] Remove unused 'amount' field from FaucetButton component and claim route (#4090)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update the testnet faucet claim route to fix issues related to the amount handling.

### Detailed summary
- Removed `amount` from request payload
- Updated amount handling in the faucet claim route to always transfer 0.01
- Improved error handling and response consistency

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

<!-- end pr-codex -->
2024-08-13 23:11:24 +00:00
joaquim-verges 9d3fa73da7 feat(dashboard): bring zksync signer back to direct deploys (#4089)
## Problem solved

for direct deploys, right now go back to the zksync ethers signer wrapper - will implement it properly inside account v5
2024-08-13 22:14:05 +00:00
jnsdls fea4a4afe8 [Fix] Remove unused loginRequired prop from MismatchButton component (#4088)
<!-- start pr-codex -->

## PR-Codex overview
This PR updates the `MismatchButton.tsx` component in the dashboard app.

### Detailed summary
- Updated `CustomConnectWallet` component with new props
- Removed `loginRequired={false}` prop from `CustomConnectWallet` usage

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

<!-- end pr-codex -->
2024-08-13 22:00:38 +00:00
Phillip HoandGitHub 2e16f9ecef chore: Add queue metrics to dashboard (#4075) 2024-08-13 21:59:34 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1032bc7cc4 chore(deps): bump @stripe/react-stripe-js from 2.7.2 to 2.7.3 (#4063)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-13 13:02:34 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
7e6d1decfc chore(deps-dev): bump react-native from 0.74.2 to 0.74.5 (#4061)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-13 12:48:51 -07:00
jnsdls 73b2c512ce [Chore] Add temporary redirect for /gas to /explore and remove GasPage component (#4087) 2024-08-13 18:14:18 +00:00
MananTank 13cda91d10 Remove sign-in requirement for TransactionButton (#4086)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the `MismatchButton` component in the dashboard by adding the `loginRequired` prop to `CustomConnectWallet`.

### Detailed summary
- Added `loginRequired={false}` prop to `CustomConnectWallet` in `MismatchButton.tsx`

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

<!-- end pr-codex -->
2024-08-13 17:58:37 +00:00
MananTank e91421a252 Fix isLoggedin auth action (#4085)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the authentication logic in `auth-actions.ts` to check for a matching creatorWalletAddress in the JSON data.

### Detailed summary
- Updated condition to check for `creatorWalletAddress` in JSON data instead of `address`.

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

<!-- end pr-codex -->
2024-08-13 17:45:31 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
74c6bca538 chore(deps): bump @hookform/resolvers from 3.6.0 to 3.9.0 (#4064)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-13 10:45:02 -07:00
MananTank 23beb9d263 Add validation for NFT claim amount to be integer (#4080)
## Problem solved

Short description of the bug fixed or feature added
2024-08-13 17:21:15 +00:00
jnsdls 69657377f4 [Fix] Lower faucet amount to 0.01 (#4084) 2024-08-13 16:48:33 +00:00
MananTank 9db4b293a5 dynamically import onboarding components - reduce Stripe errors and bundle size (#4081)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the codebase by implementing lazy loading for onboarding components to improve performance.

### Detailed summary
- Implemented lazy loading for onboarding components
- Added `LazyOnboardingBilling` component for billing
- Updated multiple files to use lazy loading for onboarding components

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

<!-- end pr-codex -->
2024-08-13 16:37:26 +00:00
MananTank 867d2dae8a Fix useLayoutEffect warnings (#4079)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the usage of `useLayoutEffect` to `useIsomorphicLayoutEffect` for consistent server-side rendering compatibility.

### Detailed summary
- Replaces `useLayoutEffect` with `useIsomorphicLayoutEffect` in multiple files
- Ensures consistent rendering behavior across client and server side

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

<!-- end pr-codex -->
2024-08-13 16:26:34 +00:00
MananTank cb27dafca7 Do not show "No Funds" Modal when switch chain is required (#4083)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to handle a specific condition `networksMismatch` before executing the button's `onClick` functionality.

### Detailed summary
- Added a condition to check for `networksMismatch` before executing the button's `onClick` functionality.
- Stored the event reference in `eventRef.current` when `networksMismatch` is true.

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

<!-- end pr-codex -->
2024-08-13 16:21:33 +00:00
kien-ngo 6b7eedeecb [Dash] various small updates and fixes (#4076)
- [x] Fix clipboard value for the [copy button] inside /explorer page
- [x] Better handling for some edge cases where the contract's compilation target is a very long string
- [x] Instead of displaying "Custom" for non-thirdweb contracts, display the contract type based on the compilation target

<hr />

Before:
<img width="1241" alt="image" src="https://github.com/user-attachments/assets/397cc15f-5941-4a5c-ae11-cae5a7a7fbde">

After:
<img width="830" alt="image" src="https://github.com/user-attachments/assets/2a353e9c-04c8-4d6d-b15f-c26b7f423213">

<hr />

Before:
<img width="665" alt="image" src="https://github.com/user-attachments/assets/93465f35-d3c4-466c-b9cd-ab905c4fc6f1">

After:
<img width="667" alt="image" src="https://github.com/user-attachments/assets/24c59796-913d-42a4-95a2-2a63e6e726c3">

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to enhance how contract metadata is displayed in the dashboard.

### Detailed summary
- Improved handling of long contract names from the thirdweb endpoint
- Updated the display of contract type in the contract table
- Refactored the usage of contract metadata in different components

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

<!-- end pr-codex -->
2024-08-13 07:16:13 +00:00
MananTank 53da850397 Fix Various "couldn't be rendered statically" errors in Sentry (#4067)
TLDR; is - In the Chain landing page, we don't really care about filtering the popular contracts - so I removed so we can statically render the chain page,

Added force-dynamic for /popular and /trending pages where we allow filtering by search params

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to implement dynamic rendering using searchParams and improve sorting functionality in the dashboard pages.

### Detailed summary
- Implemented dynamic rendering using `searchParams`
- Updated sorting functionality in trending pages
- Refactored `searchParams` in components
- Removed unnecessary imports

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

<!-- end pr-codex -->
2024-08-13 04:11:48 +00:00
kien-ngo de1bd6e903 [Dashboard] Fix contract query key (#4073)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to refactor the `useDashboardContractMetadata` hook to use a more descriptive query key and improve code readability.

### Detailed summary
- Refactored the query key to include contract metadata details
- Improved code readability by restructuring the Promise.all block
- Updated the return object format for consistency

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

<!-- end pr-codex -->
2024-08-13 03:56:15 +00:00
ff7f61c038 Dustin/treasure chain page update (#4072)
Co-authored-by: Jonas Daniels <[email protected]>
2024-08-12 20:26:37 -07:00
FirekeeperandGitHub 2408a7f9ed Docs - .NET 1.4.0 // Unity 5.0.0-beta.3 (#4071) 2024-08-12 20:25:49 -07:00
98bb37c1a1 chore(deps-dev): bump @swc-node/register from 1.10.0 to 1.10.9 (#4060)
Co-authored-by: dependabot <[email protected]>
2024-08-12 20:24:21 -07:00
gregfromstl 3c32b99b3a refactor(thirdweb): update siwe interface (#4045)
<!-- start pr-codex -->

## PR-Codex overview
This PR updates the SIWE interface to include a new `wallet` authentication option and refactors related methods for consistency.

### Detailed summary
- Added `wallet` as a new authentication option
- Updated interface methods to support `wallet` authentication
- Refactored SIWE-related functions for consistency

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

<!-- end pr-codex -->
2024-08-13 02:36:29 +00:00
kien-ngo e5a046ecdd [Dashboard] Fix missing contract metadata (#4070)
- [x] Remove duplicated formatCompilerMetadata method
- [x] Add getCompilerMetadata method to the SDK
- [x] Add a custom hook for Dashboard for fetching basic contract metadata (useDashboardContractMetadata)

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add a contract utility method `getCompilerMetadata()` and update contract metadata handling in the dashboard.

### Detailed summary
- Added `getCompilerMetadata()` utility method to fetch and format compiler metadata
- Updated contract metadata handling in the dashboard components
- Added `useDashboardContractMetadata` hook for fetching contract metadata in the dashboard

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

<!-- end pr-codex -->
2024-08-13 02:07:44 +00:00
kien-ngo 237f5faf42 [Dashboard] Migrate PlatformFees to v5 (#4050)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to migrate zod schemas from SDK v4 to a new location for form validations in the dashboard.

### Detailed summary
- Migrated zod schemas for PlatformFees and Royalties from SDK v4 to `schemas.ts`
- Updated `page.tsx` and `platform-fees.tsx` to use the new zod schemas and adapt to the changes in the SDK
- Refactored form validations and platform fee settings handling in `platform-fees.tsx`

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

<!-- end pr-codex -->
2024-08-13 01:50:49 +00:00
gregandGitHub ad2588b5de chore: fix deploy-split test (#4068) 2024-08-12 18:49:52 -07:00
kien-ngo db8695d0e8 [Dashboard]: Migrate major NFT features to v5 (#3998)
# High level changes
- `mint-form.tsx` is "over-abstracted" (not sure if that's the right word) - it's being used for too many different NFT features, making the code hard-to-migrate.
- solution: breaking it down to different component which makes it much easier to remove v4 code

# to test
- [x] UpdateMetadataForm
  - [x] Drop contracts
  - [x] Collection contracts
- [x] SharedMetadataForm
- [x] NFTMintForm
- [x] LazyMintForm

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces NFT extensions for ERC721 and ERC1155 contracts, adds a new `updateTokenURI` function, and updates components for NFT minting and metadata management.

### Detailed summary
- Added NFT extension with `updateTokenURI` function for ERC721 and ERC1155 contracts
- Updated components for NFT minting and metadata management

> The following files were skipped due to too many changes: `apps/dashboard/src/contract-ui/tabs/permissions/components/contract-permission.tsx`, `packages/thirdweb/src/extensions/erc721/write/updateTokenURI.ts`, `packages/thirdweb/src/extensions/erc1155/write/updateTokenURI.ts`, `apps/dashboard/src/contract-ui/tabs/nfts/components/shared-metadata-form.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/lazy-mint-form.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/update-metadata-form.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/mint-form.tsx`

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

<!-- end pr-codex -->
2024-08-13 00:27:22 +00:00
MananTank 2d4a5c3384 Update Deploy modal (#4057)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to refactor the custom contract deployment process by introducing a new `DeployStatusModal` component.

### Detailed summary
- Added `DeployStatusModal` component for custom contract deployment status tracking
- Refactored `useCustomContractDeployMutation` to use `DeployStatusModal`
- Removed `DeployModalProvider` component and related context logic

> The following files were skipped due to too many changes: `apps/dashboard/src/components/contract-components/contract-deploy-form/deploy-context-modal.tsx`

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

<!-- end pr-codex -->
2024-08-13 00:06:43 +00:00
Joaquim VergesandGitHub dbf3873aaf feat(dashboard): add handle_all_urls relation to assetlinks.json for Android app link verification (#4069) 2024-08-13 12:06:09 +12:00
MananTank b15aa4cdff Add Deploy button link on the Contract Card (#4066)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add a deploy button with a rocket icon to the ContractCard component in the Explore section.

### Detailed summary
- Added `RocketIcon` and deploy button to `ContractCard`
- Adjusted styling of `ContractCard` component for better layout
- Linked deploy button to deployment page with `Link`

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

<!-- end pr-codex -->
2024-08-12 23:31:51 +00:00
gregfromstl 689b8dc160 test: fix split tests (#4065)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates test descriptions in the `split` extension to run only if a secret key is present, enhancing security.

### Detailed summary
- Updated test descriptions to run only if a secret key is present
- Renamed test suites for `getAllRecipientsAddresses`, `getAllRecipientsPercentages`, and `getRecipientSplitPercentage`

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

<!-- end pr-codex -->
2024-08-12 22:40:18 +00:00
gregfromstl 218355bf95 docs: fix multi auth jsdocs (#4056)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates documentation comments in `useProfiles.ts` and `profiles.ts` for clarity.

### Detailed summary
- Updated description comments in `profiles.ts` for clarity and consistency.
- Added `@wallet` tag to indicate in-app wallet-specific methods.
- Removed redundant descriptions to improve readability.

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

<!-- end pr-codex -->
2024-08-12 22:01:39 +00:00
9be0a2fe85 Update Startup program page layout (#4058)
Co-authored-by: Ginessi <[email protected]>
Co-authored-by: Manan Tank <[email protected]>
2024-08-12 14:49:03 -07:00
gregfromstl 22b335b1f2 chore: delete solutions page (#4059)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to restructure the directory layout by deleting specific files and updating URL redirects related to gaming solutions.

### Detailed summary
- Deleted `page.mdx`, `layout.tsx`, and `sidebar.tsx` in `solutions` directory
- Removed images `unreal.png` and `preview.png` in `gaming/assets`
- Deleted `page.mdx` in `gaming/overview` directory
- Updated URL redirects for `/gaming`, `/solutions`, and `/solutions/gaming`
- Redirected `/gaming` to `/`
- Redirected `/solutions` to `/`
- Redirected `/solutions/gaming` to `/`
- Updated redirect from `/signature-minting` to `/contracts/design-docs/signature-mint`
- Updated reference from `/references/typescript/v5/embeddedWallet` to `/references/typescript/v5/inAppWallet`

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

<!-- end pr-codex -->
2024-08-12 20:57:30 +00:00
MananTank dfbaeb1c3d [dashboard] Fix chains fetch failture in localhost (#4053)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to simplify the API request in the `useApi.ts` file by removing unnecessary headers and changing the request method to GET.

### Detailed summary
- Removed unnecessary headers from the API request
- Changed the request method to GET

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

<!-- end pr-codex -->
2024-08-12 20:46:03 +00:00
MananTank dc99b88cac Fix Chainlist can't be rendered statically error in sentry (#4054)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR adds a `dynamic` export to force the page as dynamic for determining table/grid view based on viewport.

### Detailed summary
- Added `dynamic` export to force page as dynamic
- Updated comments to explain the purpose of the `dynamic` export

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

<!-- end pr-codex -->
2024-08-12 19:13:27 +00:00
Phillip HoandGitHub 66906dbef3 chore: Engine v2-beta in docs (#4049) 2024-08-12 10:04:29 -07:00
gregfromstl 7a68e3b8ed fix(react): switch chains for SIWE (#4047)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating authentication logic to switch to the proper chain before signing payloads.

### Detailed summary
- Updated `getLoginPayload` to include `chainId` parameter
- Added logic to switch to the correct chain before signing payloads
- Updated initialization of `thirdwebAuth` to handle chain switching
- Imported `getCachedChain` function in `useSiweAuth.ts`

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

<!-- end pr-codex -->
2024-08-12 05:34:36 +00:00
gregfromstl cb4b6fde85 fix(playground): do not attempt to decode nonexistent jwt (#4046)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update how the authentication result is retrieved in the `GatedContentPreview` function.

### Detailed summary
- Refactored the authentication result retrieval logic to handle `jwt?.value` more efficiently.
- Updated the conditional check for `authResult` to account for the new retrieval logic.

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

<!-- end pr-codex -->
2024-08-12 05:01:02 +00:00
kien-ngo 141fd53759 [Dashboard/SDK] Add more Split extensions and remove Split v4 code from Dashboard (#4033)
<!-- start pr-codex -->

## PR-Codex overview
This PR adds more functionality to the `Split` contract extensions, including deploying the `Split` contract, reading recipient addresses and percentages, and testing these features.

### Detailed summary
- Added more Split contract extensions
- Updated `deploys.ts` with new exports for deploying Split contract
- Updated `split.ts` with new exports for reading recipient addresses and percentages
- Modified `page.tsx` to display contract balance using `getContract`
- Added new files for reading recipient addresses and percentages
- Updated `account-balance.tsx` to use `getContract` and `useSplitBalances`
- Added tests for getting all recipient addresses and percentages
- Added functionality to get recipient split percentage and corresponding tests

> The following files were skipped due to too many changes: `packages/thirdweb/src/extensions/split/__generated__/Split/read/totalShares.ts`, `apps/dashboard/src/contract-ui/tabs/split/components/distribute-button.tsx`, `packages/thirdweb/test/src/test-contracts.ts`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useSplit.ts`, `packages/thirdweb/src/extensions/prebuilts/deploy-split.ts`, `packages/thirdweb/src/extensions/prebuilts/__generated__/Split/write/initialize.ts`, `apps/dashboard/src/contract-ui/tabs/split/page.tsx`

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

<!-- end pr-codex -->
2024-08-11 22:17:38 +00:00
joaquim-verges 478d843975 feat(dashboard): add apple-app-site-association for iOS app link verification (#4043)
## Problem solved

for passkeys on ios

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the `apple-app-site-association` and `assetlinks.json` files in the dashboard public directory to include specific app and web credentials information.

### Detailed summary
- Added `webcredentials` for specific app in `apple-app-site-association`
- Updated `sha256_cert_fingerprints` in `assetlinks.json`

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

<!-- end pr-codex -->
2024-08-11 22:11:13 +00:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
386fe1ce68 Version Packages (#4042)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-08-11 12:38:36 -07:00
jnsdls 539bdab403 [Refactor] Remove unused Bun availability check in CLI bin file (#4040)
FIXES: https://github.com/thirdweb-dev/js/issues/3991
2024-08-11 19:13:39 +00:00
jnsdls 0e3cb1338b [Hotfix] Remove async modifier from TrendingContractSection in trending-table.tsx (#4041)
FIXES: DASH-128
2024-08-11 19:02:09 +00:00
34cdd4ce95 feat(dashboard): add assetlinks.json for Android app link verification (#4039)
Co-authored-by: joaquim-verges <[email protected]>
2024-08-11 11:18:22 -07:00
Jonas DanielsandGitHub c31617436c [Chore] Remove unused 'faucet' service from chain logic (#4038) 2024-08-11 01:31:34 -07:00
Jonas DanielsandGitHub 40fbe9abb9 [Feature] Refactor chain services handling in API calls (#4037) 2024-08-11 00:08:15 -07:00
Nick PapadakisandGitHub 74e005214d Update page.mdx (#4036)
Signed-off-by: Nick Papadakis <[email protected]>
2024-08-10 20:54:45 -07:00
LubovandGitHub 1c48c20785 Update page.mdx (#4035)
Signed-off-by: Lubov <[email protected]>
2024-08-10 21:28:38 +12:00
gregfromstl 7befc61b70 Unreal 1.1 Docs (#3917)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to enhance the Thirdweb Unreal SDK documentation by adding detailed information about Blueprint system, signers, runtime settings, and common enums.

### Detailed summary
- Added documentation for Blueprint Overview, ThirdwebSigner, ThirdwebRuntimeSettings, and ThirdwebCommon.
- Updated sidebar links and icons.
- Updated tsconfig.json with consistent casing.
- Added Getting Started guide with integration steps and images.

> The following files were skipped due to too many changes: `apps/portal/src/app/unreal/thirdweb-wallet-handle/page.mdx`, `apps/portal/src/app/unreal/thirdweb-subsystem/page.mdx`, `apps/portal/src/app/unreal/thirdweb/page.mdx`, `apps/portal/src/app/unreal/page.mdx`, `apps/portal/src/app/unreal/thirdweb-function-library/page.mdx`

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

<!-- end pr-codex -->
2024-08-10 03:42:49 +00:00
MananTank 6b4503a91c Deploy form layout updates, Fix faucet claim condition (#4030)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the logic for checking if a user can claim in the testnet faucet, adds a new React switch component, refactors common form fieldsets, and improves UI components.

### Detailed summary
- Updated `canClaim` logic in testnet faucet route
- Added `@radix-ui/react-switch` component
- Refactored common form fieldsets into `Fieldset` component
- Improved UI components and form field layouts

> The following files were skipped due to too many changes: `apps/dashboard/src/components/contract-components/contract-deploy-form/platform-fee-fieldset.tsx`, `pnpm-lock.yaml`, `apps/dashboard/src/components/contract-components/contract-deploy-form/trusted-forwarders-fieldset.tsx`, `apps/dashboard/src/components/contract-components/contract-deploy-form/split-fieldset.tsx`, `apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx`

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

<!-- end pr-codex -->
2024-08-09 22:04:48 +00:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
0fe38b9210 Version Packages (#3987)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-08-09 14:51:07 -07:00
Alec AnanianandGitHub c953c3f4c8 feat(react): add enabled param to useWalletBalance hook (#4032) 2024-08-09 14:38:14 -07:00
MananTank 1a71de0983 Fix broken Contract metadata image (#4031)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to enhance the `MetadataHeader` component by adding a new function `resolveScheme` to handle image URIs with a thirdweb client.

### Detailed summary
- Added `resolveScheme` function import from `thirdweb/storage`
- Modified `src` attribute in `Image` component to use `resolveScheme` for handling image URIs

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

<!-- end pr-codex -->
2024-08-09 21:09:32 +00:00
gregfromstl b0494f6eb4 fix(wallet): fix SIWE auth in ecosystem wallets (#4029)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on fixing SIWE authentication in ecosystem wallets.

### Detailed summary
- Added `ecosystem` parameter to SIWE authentication functions
- Updated SIWE authentication logic to include `ecosystem` parameter

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

<!-- end pr-codex -->
2024-08-09 20:15:32 +00:00
MananTank fe9e9c7ba3 Show No Funds modal with Faucet/Pay options for TransactionButton (#4025)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates components related to the testnet faucet functionality and improves the UI/UX of the dashboard.

### Detailed summary
- Added a new `CanClaimResponseType` type for claim eligibility status
- Updated styles and logic for the `FaucetButton` component
- Improved tooltip functionality with a new `ToolTipLabel` component
- Added a new dialog component and updated styles for `MismatchButton`

> The following files were skipped due to too many changes: `apps/dashboard/src/components/buttons/MismatchButton.tsx`

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

<!-- end pr-codex -->
2024-08-09 19:05:45 +00:00
FirekeeperandGitHub d41dc9a632 Force legacy 248, 9372, 841, 842 (#4020) 2024-08-09 12:04:18 -07:00
Jonas DanielsandGitHub 4c659a1d82 fix account signer crash (#4028) 2024-08-09 12:03:26 -07:00
gregfromstl b56f21b87d chore: upgrade viem to 2.19.3 and cleanup redundant imports (#4023)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The PR updates `viem` to version 2.19.3 and removes a constant from `constants.ts`.

### Detailed summary
- Updated `viem` dependency to version 2.19.3
- Removed `universalSignatureValidatorAbi` constant from `constants.ts`

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

<!-- end pr-codex -->
2024-08-09 18:10:23 +00:00
MananTank 4d49a7c228 add type='button' as default to shadcn button component (#4026)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR adds a conditional `type` property to the `button` component based on the component type.

### Detailed summary
- Added `btnOnlyProps` variable to conditionally set `type` property for button component based on the component type.

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

<!-- end pr-codex -->
2024-08-09 17:50:33 +00:00
GWSzeto d8569fbd1f added back in build for cli (#4024)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to enhance the build process for smart contracts in the portal app by adding a new build command with options for detecting and compiling contracts.

### Detailed summary
- Added a new `Build` section in `page.mdx`
- Introduced a `Build` command to compile smart contracts
- Provided usage instructions and options for the `Build` command

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

<!-- end pr-codex -->
2024-08-09 17:42:37 +00:00
MananTank ed7d153cf6 Update Error Handler Modal UI (#4017)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the styling and functionality of error handling components in the dashboard.

### Detailed summary
- Updated styling and functionality of error handling components
- Added `CopyAddressFormControl` component
- Improved error message copying functionality
- Updated dialog structure and content
- Added support link button in the error dialog

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

<!-- end pr-codex -->
2024-08-09 17:37:42 +00:00
MananTank a3c0be4f40 Update Deploy Form Header UI (#4016)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add a share button feature for contracts, enabling users to share contract links easily.

### Detailed summary
- Added `shareLink` function to enable sharing contract links
- Updated `ShareButton` component to use `toast` from `sonner`
- Modified UI to include a share button for contracts
- Improved version selection functionality for contracts

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

<!-- end pr-codex -->
2024-08-09 17:31:27 +00:00
kien-ngo c31f25c51e Add Vote extensions (#3993)
- This will be a part of the Dashboard migration to v5
- The changes in modular extensions are probably because whoever added the extensions, was not using the latest generate script (Joaquim modified it to include erc20Value)

<!-- start pr-codex -->

---

## PR-Codex overview
This PR adds `erc20Value` functionality to various contract extensions in the `thirdweb` package.

### Detailed summary
- Added `erc20Value` functionality to multiple contract extensions in the `thirdweb` package.

> The following files were skipped due to too many changes: `packages/thirdweb/src/extensions/modular/__generated__/BatchMetadataERC1155/write/uploadMetadata.ts`, `packages/thirdweb/src/extensions/modular/__generated__/RoyaltyERC721/write/setDefaultRoyaltyInfo.ts`, `packages/thirdweb/src/extensions/modular/__generated__/RoyaltyERC1155/write/setDefaultRoyaltyInfo.ts`, `packages/thirdweb/src/extensions/modular/__generated__/RoyaltyERC721/write/setRoyaltyInfoForToken.ts`, `packages/thirdweb/src/extensions/modular/__generated__/RoyaltyERC1155/write/setRoyaltyInfoForToken.ts`, `packages/thirdweb/src/extensions/modular/__generated__/DelayedRevealBatchMetadataERC721/write/reveal.ts`, `packages/thirdweb/src/extensions/modular/__generated__/MintableERC20/write/completeOwnershipHandover.ts`, `packages/thirdweb/src/extensions/modular/__generated__/ClaimableERC1155/write/setClaimConditionByTokenId.ts`, `packages/thirdweb/src/extensions/modular/__generated__/OpenEditionMetadataERC721/write/setSharedMetadata.ts`, `packages/thirdweb/src/extensions/modular/__generated__/OpenEditionMetadataERC1155/write/setSharedMetadata.ts`, `packages/thirdweb/src/extensions/modular/__generated__/DelayedRevealBatchMetadataERC721/write/uploadMetadata.ts`, `packages/thirdweb/src/extensions/vote/read/quorumNumeratorByBlockNumber.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/token.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/votingDelay.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/votingPeriod.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/COUNTING_MODE.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/proposalIndex.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/BALLOT_TYPEHASH.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/proposalThreshold.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/quorumDenominator.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/getAllProposals.ts`, `packages/thirdweb/scripts/generate/abis/vote/Vote.json`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/state.ts`, `packages/thirdweb/src/exports/extensions/vote.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/quorum.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/proposals.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/hasVoted.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/getVotes.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/proposalDeadline.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/proposalSnapshot.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/proposalVotes.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/write/setVotingDelay.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/write/castVote.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/getVotesWithParams.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/write/setVotingPeriod.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/write/relay.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/read/hashProposal.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/write/setProposalThreshold.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/write/updateQuorumNumerator.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/write/propose.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/write/execute.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/write/castVoteWithReason.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/write/castVoteBySig.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/write/castVoteWithReasonAndParams.ts`, `packages/thirdweb/src/extensions/vote/__generated__/Vote/write/castVoteWithReasonAndParamsBySig.ts`

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

<!-- end pr-codex -->
2024-08-09 01:38:27 +00:00
kien-ngo 5367eed3b6 Split extensions (#3995)
This will be a part of the Dashboard migration to v5 (Split page)

<!-- start pr-codex -->

---

## PR-Codex overview
This PR adds Split contract extensions for Thirdweb, enabling token-specific functions like distribute and release.

### Detailed summary
- Added new Split contract extensions for token-specific operations
- Included functions like distributeByToken, totalReleasedByToken, releasableByToken
- Updated existing functions to support tokenAddress parameter

> The following files were skipped due to too many changes: `packages/thirdweb/src/extensions/split/__generated__/Split/read/totalReleased.ts`, `packages/thirdweb/src/extensions/split/__generated__/Split/read/payee.ts`, `packages/thirdweb/src/extensions/split/__generated__/Split/read/shares.ts`, `packages/thirdweb/src/extensions/split/__generated__/Split/read/released.ts`, `packages/thirdweb/src/extensions/split/__generated__/Split/read/releasable.ts`, `packages/thirdweb/src/extensions/split/__generated__/Split/write/release.ts`

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

<!-- end pr-codex -->
2024-08-09 01:23:19 +00:00
kien-ngo 1586d774df Dashboard: Migrate account-signer to v5 (#4019)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to update the account permissions feature in the dashboard.

### Detailed summary
- Added `thirdwebClient` and `useV5DashboardChain` for contract handling
- Updated `AccountSigners` component to fetch admins and signers
- Refactored `AccountSigner` component for better data handling

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

<!-- end pr-codex -->
2024-08-09 01:11:51 +00:00
YashandGitHub 0aeeccd42a Fix add to dashboard for zksync (#4007) 2024-08-08 18:05:49 -07:00
MananTank 4a807e41e8 Fix stretched chain icons (#4018)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to refactor the `ChainIcon` component to use the `cn` utility function for handling class names.

### Detailed summary
- Imported `cn` utility function
- Updated class name handling in `ChainIcon` component to use `cn` function for better readability and maintainability

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

<!-- end pr-codex -->
2024-08-09 00:32:09 +00:00
gregfromstl 05cee23bbb fix(wallet): resolve issues with native AutoConnect and URL token retrieval (#4015)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to fix the native AutoConnect feature in the `thirdweb` package by checking if the code is running in a web environment.

### Detailed summary
- Added a check for `window?.location` to ensure code is running in a web environment before fetching a URL token.

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

<!-- end pr-codex -->
2024-08-09 00:11:49 +00:00
gregfromstl bbb4f1c53f feat(react): multi-auth UI (#3870)
## Problem solved

Short description of the bug fixed or feature added

## Changes made

- [ ] Public API changes: list the public API changes made if any
- [ ] Internal API changes: explain the internal logic changes

## How to test

- [ ] Automated tests: link to unit test file
- [ ] Manual tests: step by step instructions on how to test

## Contributor NFT

Paste in your wallet address below and we will airdrop you a special NFT when your pull request is merged.

```Address: ```

<!-- start pr-codex -->

---

## PR-Codex overview
This PR adds account linking functionality, SIWE authentication, and profile management features to the Connect UI in `thirdweb`.

### Detailed summary
- Added account linking to Connect UI
- Introduced `useProfiles` hook for fetching linked profiles
- Updated UI components and locales for profile management
- Enhanced authentication options with SIWE
- Improved wallet icons and authentication methods

> The following files were skipped due to too many changes: `packages/thirdweb/src/react/web/ui/ConnectWallet/icons/AddUserIcon.tsx`, `packages/thirdweb/src/react/web/wallets/shared/oauthSignIn.ts`, `packages/thirdweb/src/wallets/ecosystem/types.ts`, `packages/thirdweb/src/wallets/in-app/core/authentication/types.ts`, `packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/AnyWalletConnectUI.tsx`, `packages/thirdweb/src/react/web/ui/ConnectWallet/icons/MultiUserIcon.tsx`, `packages/thirdweb/src/wallets/in-app/web/lib/auth/oauth.ts`, `packages/thirdweb/src/wallets/in-app/core/authentication/getLoginPath.ts`, `packages/thirdweb/src/react/web/wallets/ecosystem/EcosystemWalletFormUI.tsx`, `packages/thirdweb/src/wallets/in-app/core/authentication/linkAccount.ts`, `packages/thirdweb/src/react/core/hooks/others/useProfiles.ts`, `packages/thirdweb/src/react/web/ui/components/WalletImage.tsx`, `packages/thirdweb/src/react/web/wallets/ecosystem/EcosystemWalletConnectUI.tsx`, `packages/thirdweb/src/react/web/ui/ConnectWallet/screens/ManageWalletScreen.tsx`, `packages/thirdweb/src/react/web/wallets/in-app/InAppWalletConnectUI.tsx`, `packages/thirdweb/src/react/web/wallets/in-app/InAppWalletFormUI.tsx`, `packages/thirdweb/src/wallets/in-app/core/authentication/siwe.ts`, `packages/thirdweb/src/react/web/ui/ConnectWallet/screens/LinkProfileScreen.tsx`, `packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts`, `packages/thirdweb/src/react/web/wallets/shared/ConnectWalletSocialOptions.tsx`, `packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx`, `packages/thirdweb/src/react/web/ui/ConnectWallet/screens/LinkedProfilesScreen.tsx`, `packages/thirdweb/src/react/web/wallets/shared/SocialLogin.tsx`, `packages/thirdweb/src/wallets/in-app/web/lib/web-connector.ts`, `packages/thirdweb/src/wallets/in-app/native/native-connector.ts`, `packages/thirdweb/src/react/web/wallets/shared/PassKeyLogin.tsx`, `packages/thirdweb/src/react/web/wallets/shared/OTPLoginUI.tsx`, `packages/thirdweb/src/wallets/in-app/native/auth/native-auth.ts`

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

<!-- end pr-codex -->
2024-08-08 23:37:35 +00:00
gregfromstl f74d52369f feat(thirdweb): headless multi-auth (#3797)
### TL;DR

Wallets can now add additional profiles to an account. Once added, any connected profile can be used to access the same wallet. This feature allows multiple profiles such as Google and Discord to be linked to a single wallet.

### What changed?

- Introduced a new method `linkProfile` to connect additional profiles to an existing wallet
- Added backend logic to handle profile linking and retrieval of linked profiles
- Minor modifications in types and export statements
- Updated embedded wallet URL to `localhost:3000`

### How to test?

1. Connect a wallet using one strategy (e.g., Google)
2. Use the `linkProfile` method to add another profile (e.g., Discord)
3. Verify both profiles can access the same wallet
4. Retrieve all linked profiles using the `getProfiles` method and verify the details

### Why make this change?

This change provides more flexibility and convenience to users by allowing them to link multiple profiles to a single wallet. It enhances user experience by providing multiple avenues for wallet access.

---

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates authentication types and imports across different wallet-related files.

### Detailed summary
- Updated imports and types in authentication-related files
- Replaced `type.js` with `types.js` in multiple files
- Added `Profile` type in `authentication/types.ts`
- Updated functions from `authenticate` to `connect` in multiple files

> The following files were skipped due to too many changes: `.changeset/green-wombats-rest.md`, `packages/thirdweb/src/wallets/in-app/native/auth/native-auth.ts`, `packages/thirdweb/src/wallets/in-app/core/interfaces/connector.ts`, `packages/thirdweb/src/wallets/in-app/web/lib/auth/abstract-login.ts`, `packages/thirdweb/src/wallets/in-app/native/native-connector.ts`, `packages/thirdweb/src/wallets/in-app/core/wallet/profiles.ts`, `packages/thirdweb/src/wallets/in-app/core/wallet/in-app-core.ts`, `packages/thirdweb/src/wallets/in-app/core/authentication/linkAccount.ts`, `packages/thirdweb/src/wallets/in-app/web/lib/web-connector.ts`, `packages/thirdweb/src/wallets/in-app/web/lib/auth/iframe-auth.ts`, `packages/thirdweb/src/wallets/in-app/web/lib/auth/base-login.ts`, `packages/thirdweb/src/extensions/marketplace/english-auctions/english-auctions.test.ts`, `packages/thirdweb/src/extensions/marketplace/direct-listings/direct-listings.test.ts`

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

<!-- end pr-codex -->
2024-08-08 23:37:32 +00:00
kien-ngo 419873a3c6 [Hotfix] ethers v5 adapter (#4014)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to make a small fix in the `ethers5.ts` adapter by replacing the `chainId` parameter with a predefined chain value.

### Detailed summary
- Replaced `chainId` with a predefined chain value in the `fromEthersContract` function in `ethers5.ts` adapter.

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

<!-- end pr-codex -->
2024-08-08 21:53:52 +00:00
gregfromstl 357a03aa8f test(smart-wallet): update tests to run sequentially and improve admin check (#4011)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update the test suite for SmartWallet integration by making adjustments to the expectations related to event logs.

### Detailed summary
- Updated expectations for event logs in tests
- Changed `expect` assertions to use `logs.some` method for checking conditions

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

<!-- end pr-codex -->
2024-08-08 21:27:49 +00:00
kien-ngo 164dbed673 Dashboard v5 Aug 07 run (#3988)
# High-level changes
- [x] ContractMetadata section now fully on v5
- [x] Moved some code of the ClaimCondition section to v5
- [x] Removed claimCondition utils methods -> used the inner logics directly to avoid importing types from v4 packages
- [x] Forcefully hard-coded some types in v4 that are not in v5
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update contract metadata handling and claim condition detection.

### Detailed summary
- Updated `ContractMetadata` component to use `ThirdwebContract`
- Improved claim condition detection in various components
- Refactored claim condition form components for better functionality

> The following files were skipped due to too many changes: `apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/phase.tsx`

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

<!-- end pr-codex -->
2024-08-08 21:08:10 +00:00
6ccb6be3a0 Joe plume additions (#4013)
Signed-off-by: Joe-Thirdweb <[email protected]>
Co-authored-by: Jonas Daniels <[email protected]>
2024-08-08 13:58:13 -07:00
MananTank 7cba594046 Fix "All Wallets" not shown by default in Pay UI when trying to connect a new wallet (#4008)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on fixing the issue where "All Wallets" were not shown by default in the Pay UI when connecting a new wallet.

### Detailed summary
- Modified `BuyScreen.tsx` to ensure "All Wallets" are shown by default in the Pay UI
- Updated the logic for displaying recommended wallets and wallet options

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

<!-- end pr-codex -->
2024-08-08 20:32:37 +00:00
gregfromstl d48cd13d53 test(thirdweb): skip deployModularCore tests dependent on TW_SECRET_KEY (#4012)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR skips the test `deployModularCore` in `deploy-modular-core.test.ts`.

### Detailed summary
- Skips the test `deployModularCore` in `deploy-modular-core.test.ts` by changing `describe.runIf` to `describe.skip`

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

<!-- end pr-codex -->
2024-08-08 19:33:05 +00:00
MananTank ae83544c3a Move CMD+K search to shadcn/tailwind, clamp search result title to 2 lines (#4010)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to refactor the search functionality in the `CmdKSearch` component by introducing a new dialog UI for searching contracts.

### Detailed summary
- Added a new dialog UI for searching contracts
- Replaced Chakra UI components with custom UI components
- Updated search functionality with new design and features

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

<!-- end pr-codex -->
2024-08-08 19:20:31 +00:00
GWSzeto a996b54323 updated from modules to extensions in the build sidebar (#4009)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to update the file `sidebar.tsx` in the contracts app to replace references to "modules" with "extensions" for clarity and consistency.

### Detailed summary
- Replaced all occurrences of `modulesSlug` with `extensionsSlug` for better naming
- Updated links and names to reflect the change from "Modules" to "Extensions"

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

<!-- end pr-codex -->
2024-08-08 18:23:05 +00:00
BahadorandGitHub 91317dcba3 Update page.mdx (#4000)
Signed-off-by: Bahador <[email protected]>
2024-08-08 10:38:53 -07:00
MananTank e6ac1cc802 [dashboard] No sign-in required for /dashboard/connect/playground page (#4002)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the middleware and user hook in the dashboard app to use a new `isLoginRequired` function for checking logged-in paths.

### Detailed summary
- Added `isLoginRequired` function in `constants/auth.ts`
- Updated middleware to use `isLoginRequired` function
- Updated user hook to use `isLoginRequired` function

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

<!-- end pr-codex -->
2024-08-08 17:20:36 +00:00
MananTank 3649e3994a [dash] deploy form layout + various UI updates/fixes (#3994)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update various UI components and layouts across different pages in the dashboard app.

### Detailed summary
- Updated styling for `nav-link.client.tsx` and `color-mode-toggle.tsx`
- Refactored layout in `publish/[...paths].tsx`
- Removed `MobileMenu` import in `chain-header.tsx`
- Added `Sidebar` component in `layout.tsx` and `chainPage/layout.tsx`
- Updated UI components in `BurgerMenuButton.tsx` and `publish.tsx`

> The following files were skipped due to too many changes: `apps/dashboard/src/components/pages/publish.tsx`

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

<!-- end pr-codex -->
2024-08-08 13:11:45 +00:00
gregfromstl dd7d28c44f fix(ts): migrate serializeTransaction and universalSignatureValidatorByteCode to viem (#3997)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to enhance the `serializeTransaction` interface in the `thirdweb` package to include a separate signature input while maintaining backwards compatibility.

### Detailed summary
- Improved `serializeTransaction` interface in `thirdweb` package
- Added separate signature input while maintaining backwards compatibility
- Updated dependencies in `crypto/package.json`
- Updated `package.json` in `thirdweb`
- Updated `typesVersions` in `package.json` of `thirdweb`
- Updated imports in `verify-hash.ts`
- Updated exports in `package.json` of `thirdweb`
- Updated types and functions in `serialize-transaction.test.ts`
- Updated types and functions in `serialize-transaction.ts`

> The following files were skipped due to too many changes: `packages/thirdweb/src/transaction/serialize-transaction.ts`, `pnpm-lock.yaml`

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

<!-- end pr-codex -->
2024-08-08 08:35:05 +00:00
Jonas DanielsandGitHub b58a0e531f [Chore] Unify import statements in chain definition files (#3999) 2024-08-07 23:24:40 -07:00
2b4629b505 Added Fraxtal and Mode Testnets to the chain-definitions (#3996)
Signed-off-by: Jonas Daniels <[email protected]>
Co-authored-by: Jonas Daniels <[email protected]>
2024-08-07 21:42:16 -07:00
MananTank 698b8dbb97 allow useActiveWalletChain direct usage in dashboard (#3990)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to replace the usage of `useDashboardActiveWalletChain` with `useActiveWalletChain` for consistency and clarity.

### Detailed summary
- Replaced `useDashboardActiveWalletChain` with `useActiveWalletChain` in multiple files for consistent usage.
- Removed unnecessary imports of `useDashboardActiveWalletChain`.
- Updated functions and components to use `useActiveWalletChain` for better readability and understanding.

> The following files were skipped due to too many changes: `apps/dashboard/src/components/buttons/MismatchButton.tsx`

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

<!-- end pr-codex -->
2024-08-08 01:19:05 +00:00
MananTank a4bc285cb7 Sync Chain object changes to Connection manager and wallets from UI components (#3989)
* When `chain` or `chains` prop passed to UI components like `ConnectButton` , `ConnectEmbed` etc are updated - make sure that those chain makes their way to connection manager ( useActiveWalletChain ) and to all the wallets ( getChain )

This is mainly for dashboard - where users can modify the chains and we need to update the chain objects when that's done

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates wallet adapters to use cached chain objects for improved performance.

### Detailed summary
- Added `getCachedChainIfExists` function to retrieve cached chain objects.
- Updated `getChain` method in wallet adapters to use cached chains.
- Removed unnecessary `cacheChains` function calls.
- Added `useConnectionManager` hook to manage defined chains store.

> The following files were skipped due to too many changes: `packages/thirdweb/src/react/native/ui/connect/ConnectButton.tsx`, `packages/thirdweb/src/wallets/manager/index.ts`

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

<!-- end pr-codex -->
2024-08-08 01:19:01 +00:00
GWSzeto 7c2f616dfe renamed from extension to module for modular contracts (#3985)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to remove numerous contract pages and assets related to ERC standards and extensions.

### Detailed summary
- Deleted multiple contract pages and assets related to ERC standards and extensions
- Renamed "extensions" to "modules" in contract descriptions and comments

> The following files were skipped due to too many changes: `apps/portal/src/app/contracts/modular-contracts/core-contracts/erc-20/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/core-contracts/erc-1155/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-20/misc/transferableERC20/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-721/misc/transferableERC721/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-1155/misc/transferableERC1155/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-1155/metadata/simpleMetadataERC1155/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-20/minting/mintableERC20/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-721/metadata/batchMetadataERC721/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-1155/metadata/batchMetadataERC1155/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-1155/metadata/openEditionMetadataERC1155/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-721/minting/mintableERC721/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-1155/minting/mintableERC1155/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-721/metadata/openEditionMetadataERC721/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-20/minting/claimableERC20/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-721/minting/claimableERC721/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-1155/minting/claimableERC1155/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-721/metadata/delayedRevealBatchMetadataERC721/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/how-it-works/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-721/misc/royaltyERC721/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/extension-contracts/erc-1155/misc/royaltyERC1155/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/overview/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/modular-contracts/page.mdx`, `apps/portal/src/app/contracts/modular-contracts/get-started/page.mdx`, `apps/portal/src/app/contracts/sidebar.tsx`

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

<!-- end pr-codex -->
2024-08-07 19:15:43 +00:00
4d0e00a7c4 Add Abstract testnet to ZK Sync chain checks (#3986)
Co-authored-by: Jonas Daniels <[email protected]>
2024-08-07 11:18:54 -07:00
kien-ngo e3220d4a8d Dashboard v5: Remove v4 code (#3982)
High-level changes:
- [x] useAdmin migrated to v5
- [x] useAdminOrSelf migrated to v5
- [x] ERC20 mint form to v5
2024-08-07 16:12:49 +00:00
FirekeeperandGitHub 68e0aa2d90 Unity v5 initial docs (#3958) 2024-08-06 21:24:56 -07:00
MananTank ce00999e95 cleanup-imports (#3983)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates import paths to use absolute imports and removes unnecessary imports.

### Detailed summary
- Updated import paths to use absolute imports (`@/lib/utils`, `@/components/ui`, `@/components/pagination-buttons`, etc.)
- Removed unnecessary imports from various files

> The following files were skipped due to too many changes: `apps/dashboard/src/pages/grant/superchain.tsx`, `apps/dashboard/src/pages/open-source.tsx`, `apps/dashboard/src/@/components/color-mode-toggle.tsx`, `apps/dashboard/src/pages/learn/index.tsx`, `apps/dashboard/src/components/pay/PayAnalytics/components/Payouts.tsx`, `apps/dashboard/src/components/homepage/sections/PricingEngine.tsx`, `apps/dashboard/src/lib/vercel-utils.ts`, `apps/dashboard/src/components/color-mode/color-mode-toggle.tsx`, `apps/dashboard/src/components/pay/PayAnalytics/components/PayNewCustomers.tsx`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/[slug]/(active)/hooks/use-ecosystem.ts`, `apps/dashboard/src/components/pay/PayConfig.tsx`, `apps/dashboard/src/components/explore/publisher/index.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useApi.ts`, `apps/dashboard/src/pages/template/[id].tsx`, `apps/dashboard/src/contract-ui/tabs/english-auctions/components/table.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useLoggedInUser.ts`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx`, `apps/dashboard/src/components/contract-components/contract-deploy-form/trusted-forwarders-fieldset.tsx`, `apps/dashboard/src/components/pay/PayAnalytics/components/PaymentsSuccessRate.tsx`, `apps/dashboard/src/components/contract-components/contract-deploy-form/contract-metadata-fieldset.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/sidebar-content.tsx`, `apps/dashboard/src/app/login/auth-actions.ts`, `apps/dashboard/src/pages/api/moralis/balances.ts`, `apps/dashboard/src/pages/404.tsx`, `apps/dashboard/src/pages/hackathon/earn.tsx`, `apps/dashboard/src/components/landing-pages/layout.tsx`, `apps/dashboard/src/pages/hackathon/consumer-crypto.tsx`, `apps/dashboard/src/pages/_app.tsx`, `apps/dashboard/src/pages/index.tsx`, `apps/dashboard/src/pages/hackathon/readyplayer3.tsx`, `apps/dashboard/src/pages/community/ambassadors.tsx`, `apps/dashboard/src/contract-ui/tabs/manage/components/getExtensionInstalledParams.ts`, `apps/dashboard/src/components/engine/overview/backend-wallets-table.tsx`, `apps/dashboard/src/components/product-pages/common/ProductPage.tsx`, `apps/dashboard/src/components/pay/PayAnalytics/components/PayCustomersTable.tsx`, `apps/dashboard/src/components/cmd-k-search/index.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts`, `apps/dashboard/src/components/buttons/TransactionButton.tsx`, `apps/dashboard/src/components/pages/publish.tsx`, `apps/dashboard/src/components/onboarding/Steps.tsx`, `apps/dashboard/src/components/pay/PayAnalytics/PayAnalytics.tsx`, `apps/dashboard/src/contract-ui/tabs/manage/page.tsx`, `apps/dashboard/src/components/pay/PayAnalytics/components/PaymentHistory.tsx`, `apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx`, `apps/dashboard/src/app/(dashboard)/trending/components/trending-table.tsx`, `apps/dashboard/src/contract-ui/tabs/settings/components/metadata.tsx`, `apps/dashboard/src/components/selects/CustomChainRenderer.tsx`, `apps/dashboard/src/components/selects/NetworkSelectorButton.tsx`

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

<!-- end pr-codex -->
2024-08-07 01:29:48 +00:00
MananTank 347c4de046 Update deploy form layout (#3938)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update various text labels and add a new sidebar component for contracts in the dashboard.

### Detailed summary
- Updated text labels for wallet addresses in different contract settings
- Added a new `ContractsSidebar` component to the dashboard
- Updated styling for file upload components
- Modified form field labels and descriptions for contract settings

> The following files were skipped due to too many changes: `apps/dashboard/src/components/contract-components/contract-deploy-form/contract-metadata-fieldset.tsx`, `apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx`

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

<!-- end pr-codex -->
2024-08-07 01:29:45 +00:00
MananTank 48eb472645 Move deploy form outside the drawer to a page (#3936)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update components related to publishing contracts, including adding deployment functionality and improving UI elements.

### Detailed summary
- Updated `NetworkSelectorButton` to handle deployment theme
- Added deployment functionality in `PublishPage`
- Enhanced `ShareButton` UI and functionality
- Improved UI elements in `TrustedForwardersFieldset`
- Updated `PublishWithVersionPage` with deployment logic and UI enhancements

> The following files were skipped due to too many changes: `apps/dashboard/src/components/pages/publish.tsx`

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

<!-- end pr-codex -->
2024-08-07 00:45:27 +00:00
Jonas DanielsandGitHub 6530e41948 [Chore] Update turbo dependency to version 2.0.12 (#3979) 2024-08-06 16:19:11 -07:00
MananTank 06bc0c1ed4 Preserve Chain overrides in dashboard + enable editing / adding new chains in CustomConnectWallet button (#3972)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update chain-related functions and improve chain handling in various components.

### Detailed summary
- Updated chain-related functions in multiple files
- Improved chain handling in components and SDK contexts
- Refactored chain mapping and RPC URL retrieval functions

> The following files were skipped due to too many changes: `apps/dashboard/src/middleware.ts`, `apps/dashboard/src/components/contract-components/import-contract/modal.tsx`, `apps/dashboard/src/components/smart-wallets/AccountFactories/factory-contracts.tsx`, `apps/dashboard/.eslintrc.js`, `apps/dashboard/src/contract-ui/tabs/shared-components/cancel-tab.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useRegistry.ts`, `apps/dashboard/src/contract-ui/tabs/account/components/deposit-native.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx`, `apps/dashboard/src/contract-ui/tabs/shared-components/list-button.tsx`, `apps/dashboard/src/components/contract-components/contract-deploy-form/index.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts`, `apps/dashboard/src/hooks/useContractAbiItems.ts`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx`, `apps/dashboard/src/pages/api/moralis/balances.ts`, `apps/dashboard/src/contract-ui/tabs/direct-listings/components/table.tsx`, `apps/dashboard/src/contract-ui/tabs/settings/components/platform-fees.tsx`, `apps/dashboard/src/contract-ui/tabs/settings/components/primary-sale.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/mint-form.tsx`, `apps/dashboard/src/contract-ui/tabs/english-auctions/components/table.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/mint-supply-tab.tsx`, `apps/dashboard/src/contract-ui/tabs/settings/components/royalties.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/claim-tab.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/FaucetButton.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/airdrop-tab.tsx`, `apps/dashboard/src/contract-ui/tabs/tokens/components/mint-button.tsx`, `apps/dashboard/src/contract-ui/tabs/accounts/page.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/burn-tab.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/mint-button.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/chain-header.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/add-chain-to-wallet.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/lazy-mint-button.tsx`, `apps/dashboard/src/components/buttons/TransactionButton.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/transfer-tab.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/reveal-button.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/batch-lazy-mint-button.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/reveal-form.tsx`, `apps/dashboard/src/contract-ui/tabs/tokens/components/claim-form.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/shared-metadata-button.tsx`, `apps/dashboard/src/contract-ui/tabs/manage/page.tsx`, `apps/dashboard/src/components/app-layouts/app.tsx`, `apps/dashboard/src/components/engine/contract-subscription/contract-subscriptions-table.tsx`, `apps/dashboard/src/components/selects/NetworkSelectorButton.tsx`, `apps/dashboard/src/components/app-layouts/provider-setup.tsx`, `apps/dashboard/src/contract-ui/tabs/overview/components/MarketplaceDetails.tsx`, `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/tx/[txHash]/page.tsx`, `apps/dashboard/src/contract-ui/tabs/settings/components/metadata.tsx`, `apps/dashboard/src/components/app-layouts/providers.tsx`, `apps/dashboard/src/contract-ui/tabs/split/page.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/components/connect-wallet/index.tsx`, `apps/dashboard/src/pages/[chain_id]/[...paths].tsx`, `apps/dashboard/src/lib/v5-adapter.ts`, `apps/dashboard/src/components/buttons/MismatchButton.tsx`, `apps/dashboard/src/components/contract-components/hooks.ts`

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

<!-- end pr-codex -->
2024-08-06 22:47:21 +00:00
Jonas DanielsandGitHub ccc3a2d2c8 speed up docs (#3967) 2024-08-06 15:44:36 -07:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
deb704a084 Version Packages (#3966)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-08-06 15:26:32 -07:00
dc86fa2e6e updated pay interface for onramp + gas (#3894)
Signed-off-by: Jonas Daniels <[email protected]>
Co-authored-by: Jonas Daniels <[email protected]>
2024-08-06 15:16:49 -07:00
Aryan MalikandGitHub 64d1b79b61 fix: update import statement for smartWallet in smart-wallet.ts (#3968) 2024-08-06 15:09:37 -07:00
gregfromstl f4e84e099a test(ts): adds test case for signMessage (#3978)
### TL;DR

Added a new test case to `sign-message.test.ts` to verify the signature generated by the `signMessage` function when provided with a specific message and private key.

### What changed?

The test file `sign-message.test.ts` in the `thirdweb` package has been updated to include a new test case that checks the signature generated by the `signMessage` function.

### How to test?

Run the test suite for the `thirdweb` package to ensure all tests, including the new one, pass correctly.

### Why make this change?

To enhance test coverage and ensure that the `signMessage` function generates the expected signature when given specific inputs.

---
2024-08-06 21:39:57 +00:00
jnsdls b9807f001b [Feature] Add analytics tracking to FaucetButton component (#3977)
### TL;DR

Added analytics tracking to the `FaucetButton` component.

### What changed?

Integrated `useTrack` hook to capture and track events (attempt, success, error) for claiming funds via the FaucetButton. Updated error handling for clarity.

### How to test?

1. Deploy the dashboard.
2. Navigate to the FaucetButton component.
3. Attempt to claim funds and observe tracking behavior in the configured analytics dashboard.

### Why make this change?

To gain better insights into how users interact with the FaucetButton and to capture relevant events for analysis.

---
2024-08-06 21:10:38 +00:00
gregfromstl 358a7577c1 fix(wallet): resolve wallet adapter info retrieval issue (#3976) 2024-08-06 20:54:38 +00:00
kien-ngo c05a94d985 Dashboard: Delete Marketplace v2 listing page (#3975)
- [x] Marketplace v2 is very outdated
- [x] Marketplace v3 is out for over 2 years
- [x] After the _incident_, people should be on v3 now
- [x] This also helps remove more sdk v4 code

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to refactor and clean up the contract UI listings components.

### Detailed summary
- Removed unused components from listings page
- Updated route configuration for listings
- Refactored ListingStats component
- Updated imports and dependencies

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

<!-- end pr-codex -->
2024-08-06 20:49:05 +00:00
ianandGitHub ab5d6bcfe2 New Pay Guides + Sidebar Structure (#3970) 2024-08-06 13:11:00 -07:00
d7e59305bd upstream viem tweaks (#3934)
Co-authored-by: greg <[email protected]>
Co-authored-by: Jonas Daniels <[email protected]>
2024-08-06 10:48:48 -07:00
Jonas DanielsandGitHub edb86b9728 [Chore] Update CI badge link in README.md (#3973) 2024-08-06 10:45:44 -07:00
Jonas DanielsandGitHub 23c1cfa283 [Test] Conditionally run toSerializableTransaction tests based on TW_SECRET_KEY environment variable (#3965) 2024-08-06 00:12:22 -07:00
Jonas DanielsandGitHub 9944f9d731 [Chore] Remove benchmark job from CI workflow (#3964) 2024-08-06 00:10:33 -07:00
jnsdls 2e3c5e9dbd [Fix] Handle account switching inside connected wallet for SIWE auth (#3963)
FIXES: #3912

### TL;DR
This PR fixes the handling of account switching within a connected wallet in Sign-In with Ethereum (SIWE) authentication states.

### What changed?
- Updated the `isLoggedIn` function to accept an `address` argument and added more checks to validate the JWT and the associated address.
- Pass `account` as a new parameter to `useSiweAuth` to ensure the correct account is handled.
- Removed experimental server external packages from `next.config.mjs`.
- Removed `@shikijs/twoslash` dependency from `package.json`.

### How to test?
1. Switch accounts within a connected wallet and ensure the SIWE authentication state updates correctly.
2. Verify that the application runs without errors related to the removed experimental packages and dependencies.

### Why make this change?
To ensure better account management and state consistency within the SIWE authentication framework, and to remove unused or experimental configurations for better stability and performance.

---

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing account switching in SIWE authentication states.

### Detailed summary
- Updated functions to include `account` parameter for SIWE authentication
- Changed login and authentication logic
- Added `getAuthResult` function for server-side auth
- Updated dependencies and imports

> The following files were skipped due to too many changes: `pnpm-lock.yaml`

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

<!-- end pr-codex -->
2024-08-06 06:53:24 +00:00
gregfromstl 206b825d7c fix(portal): update prefix URL in EditPage component (#3962)
Updated the GitHub edit URL prefix in the EditPage component from 'https://github.com/thirdweb-dev/docs-v2/edit/main/src/app' to 'https://github.com/thirdweb-dev/js/edit/main/apps/portal/src/app'.

---

## Problem solved

Short description of the bug fixed or feature added
2024-08-06 06:33:23 +00:00
gregfromstl 584aa7a5fe test(thirdweb): add condition to serialize-transaction eip1559 test based on TW_SECRET_KEY (#3955)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on adding a conditional test suite for the `eip1559` function based on the presence of a secret key.

### Detailed summary
- Conditionally runs the `eip1559` test suite based on the presence of `TW_SECRET_KEY` environment variable.

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

<!-- end pr-codex -->
2024-08-06 05:29:27 +00:00
kien-ngo 2500be36e7 Dashboard v5: Aug 05 updates (#3942)
### High level changes
- [x] Deleted `apps/dashboard/src/components/contract-tabs/code/ContractCode.tsx` - doesn't seem to be used anywhere
- [x] Uninstall v4's react-core and wallets packages
- [x] Rename some components's names to make it clear that they are for ERC20 only (`mint-form-erc20`)
- [x] `useTxNotifications` now only accepts v5 contract

### Tested areas
- [x] ERC20 mintTo button
- [x] CreateListingButton (minor change but need to test anyway)
- [x] ContractSidebar.tsx

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update contract-related components and dependencies.

### Detailed summary
- Updated `CreateListingButton` props in different tab pages
- Added `contractV5` variable in multiple components
- Updated dependencies and removed unused ones

> The following files were skipped due to too many changes: `apps/dashboard/src/contract-ui/tabs/nfts/components/batch-lazy-mint-button.tsx`, `apps/dashboard/src/core-ui/batch-upload/batch-lazy-mint.tsx`, `apps/dashboard/src/contract-ui/tabs/shared-components/list-button.tsx`, `apps/dashboard/src/hooks/useTxNotifications.ts`, `apps/dashboard/src/core-ui/sidebar/detail-page.tsx`, `apps/dashboard/src/contexts/error-handler.tsx`, `apps/dashboard/src/contract-ui/tabs/tokens/components/mint-form.tsx`

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

<!-- end pr-codex -->
2024-08-06 05:18:27 +00:00
gregfromstl b7daefb394 fix(app): update header texts and contract address (#3956)
### TL;DR
Updates various UI headings in the payment-related pages and updates the NFT contract address in the transaction button component.

### What changed?
- Updated headings in `pay/page.tsx`:
  - 'Fund wallets' to 'Top Up'
  - 'Direct Payments' to 'Commerce'
  - 'Onchain Payments' to 'Transactions'
- Changed NFT contract address in `transaction-button.tsx` from `0x96B30d36f783c7BC68535De23147e2ce65788e93` to `0x827c1c3889923015C1FC31BF677D00FbE6F01D52`.

### How to test?
1. Navigate to the payment page and verify that the headings are updated.
2. Ensure that the transactions are working correctly with the new contract address.

### Why make this change?
The updates are intended to enhance user comprehension and ensure the correct NFT contract is being used.

---

## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update text and component names related to payment transactions in the playground web app.

### Detailed summary
- Updated the `nftContract` address in `transaction-button.tsx`
- Changed "Fund wallets" to "Top Up" in `page.tsx`
- Renamed "Direct Payments" to "Commerce"
- Replaced "Onchain Payments" with "Transactions"

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

<!-- end pr-codex -->
2024-08-06 05:14:51 +00:00
ianandGitHub 9eeb69e3dd Add direct payments guide and webhooks documentation (#3957) 2024-08-05 22:10:43 -07:00
2e963137fb Updating Aleph Zero and Lumia chainlist (#3960)
Co-authored-by: Jonas Daniels <[email protected]>
2024-08-05 22:04:23 -07:00
kien-ngo 0ae539f384 Docs: Update locale table (#3959)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the language codes for French and Korean in the sign-in customization page.

### Detailed summary
- Updated language code for French to `fr_FR`
- Updated language code for Korean to `ko_KR`

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

<!-- end pr-codex -->
2024-08-06 03:13:25 +00:00
gregfromstl dce096fba4 chore: remove faulty test (#3954)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR skips unit tests requiring a secret key and updates a URL in the downloadMock function.

### Detailed summary
- Skips unit tests in claimERC20, claimERC721, and claimERC1155 if no secret key available
- Updated URL in `downloadMock` function in `storage.ts`

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

<!-- end pr-codex -->
2024-08-06 00:07:45 +00:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>GitHub Action
34e6f69568 Version Packages (#3953)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <[email protected]>
2024-08-05 17:04:41 -07:00
Jonas Daniels c9e14e366c Revert "Version Packages (#3950)"
This reverts commit 65eb299eb0.
2024-08-05 16:24:13 -07:00
Jonas DanielsandGitHub 4308c4a1cf [Chore] Update thirdweb dependency to use workspace protocol (#3952) 2024-08-05 16:20:44 -07:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
65eb299eb0 Version Packages (#3950)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-08-05 16:18:53 -07:00
gregfromstl 1309602889 docs: adds telegram changeset (#3951)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR adds a new feature to the `thirdweb` module, enabling users to log in to in-app wallets using Telegram.

### Detailed summary
- Added support for Telegram login option in in-app wallets using `thirdweb`
- Updated `inAppWallet` function to include Telegram login strategy
- Added example code snippet for connecting to wallet using Telegram strategy

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

<!-- end pr-codex -->
2024-08-05 22:54:17 +00:00
GWSzeto 09ebee8e41 added build back into the docs (#3949)
Modified .gitignore so that it accepts the build folder

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add detailed documentation for various ERC standards in smart contracts.

### Detailed summary
- Added documentation for ERC721, ERC1155, and ERC20 smart contract standards
- Included usage examples and base contracts for each extension
- Updated metadata and images for clarity and consistency

> The following files were skipped due to too many changes: `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155Mintable/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-721/ERC721Mintable/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155Enumerable/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-721/ERC721Revealable/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155Revealable/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-721/ERC721Enumerable/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155Burnable/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-721/ERC721BatchMintable/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-20/ERC20BatchMintable/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-721/ERC721Supply/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155Supply/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155Claimable/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155BatchMintable/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-721/ERC721Claimable/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-20/ERC20ClaimConditions/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-20/ERC20/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-721/ERC721ClaimConditions/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-20/base/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/Multicall/page.mdx`, `apps/portal/src/app/contracts/build/modular-contracts/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-721/ERC721ClaimCustom/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155ClaimCustom/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-4337/account-factory/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-20/vote/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155ClaimConditions/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/PermissionsEnumerable/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-4337/managed-account-factory/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-20/drop/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155ClaimPhases/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/Ownable/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-20/drop-vote/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-721/ERC721ClaimPhases/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/BatchMintMetadata/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/Permissions/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-721/ERC721Staking/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-20/ERC20Permit/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-20/signature-mint/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-4337/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-20/ERC20Staking/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/ContractMetadata/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/PlatformFee/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-721/delayed-reveal/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-20/signature-mint-vote/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-1155/delayed-reveal/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/LazyMint/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-721/signature-mint/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-4337/AccountExtension/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/PrimarySale/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-1155/signature-mint/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-4337/managed-account/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155Staking/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-721/base/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-4337/SmartWallet/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-4337/account/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-721/lazy-mint/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/DelayedReveal/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-4337/SmartWalletFactory/page.mdx`, `apps/portal/src/app/contracts/build/get-started/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/Royalty/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-721/drop/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-1155/lazy-mint/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-1155/base/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/erc-1155/drop/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-20/ERC20SignatureMint/page.mdx`, `apps/portal/src/app/contracts/build/base-contracts/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-721/ERC721SignatureMint/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155SignatureMint/page.mdx`, `apps/portal/src/app/contracts/build/extensions/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155DropSinglePhase/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/DropSinglePhase/page.mdx`, `apps/portal/src/app/contracts/build/extensions/general/Drop/page.mdx`, `apps/portal/src/app/contracts/build/extensions/erc-1155/ERC1155Drop/page.mdx`, `apps/portal/src/app/contracts/build/overview/assets/extension-model.svg`

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

<!-- end pr-codex -->
2024-08-05 22:42:20 +00:00
ea2247c40c Added Celo Alfajores Testnet within the chain-definitions (#3941)
Signed-off-by: Jonas Daniels <[email protected]>
Co-authored-by: Jonas Daniels <[email protected]>
2024-08-05 15:30:42 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
a8061277fb chore(deps-dev): bump typescript from 5.5.2 to 5.5.4 (#3945)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-05 15:23:19 -07:00
Jonas DanielsandGitHub eb94d2ad18 [Feature] Add Content Security Policy and security headers configuration (#3943) 2024-08-05 15:20:13 -07:00
kien-ngo b3aabee23b Dashboard v5: Remove more v4 code (#3927)
This PR is the first step to eventually remove all the v4 code inside `src/contract-ui/tabs/nfts/page.tsx`

2 main components that is now v4-free:
- [x] useIsMinter
- [x] MinterOnly

In fear of putting up a huge PR, I submit this PR as the first in this series

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates contract handling and minter role detection across multiple components.

### Detailed summary
- Updated contract handling to use `ThirdwebContract`
- Improved minter role detection logic
- Refactored minting components to use updated contract handling

> The following files were skipped due to too many changes: `apps/dashboard/src/contract-ui/tabs/nfts/components/shared-metadata-button.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/batch-lazy-mint-button.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/page.tsx`

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

<!-- end pr-codex -->
2024-08-05 20:43:02 +00:00
kien-ngo 72fad8f22d Dashboard v5: Remove useStorageUpload (#3929)
- Add new React hook that uses v5's `upload` under the hood
- Sacrifice has been made - we remove the progress % from the loading bar

<!-- start pr-codex -->

---

## PR-Codex overview
The PR focuses on replacing `useStorageUpload` with `useDashboardStorageUpload` in multiple components for IPFS file uploads.

### Detailed summary
- Replaced `useStorageUpload` with `useDashboardStorageUpload` in `button.tsx`, `string-input.tsx`, `IconUpload.tsx`, and `dropzone.tsx`.
- Updated file upload logic in `FileUpload` component in `dropzone.tsx`.
- Added `useDashboardStorageUpload` in `useDashboardStorageUpload.tsx` for IPFS file uploads.

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

<!-- end pr-codex -->
2024-08-05 20:26:18 +00:00
MananTank e2db196790 Fix Forced dark theme on certain pages (#3940)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add a new `useForceDarkTheme` hook to enforce dark theme across multiple pages.

### Detailed summary
- Added `useForceDarkTheme` hook to enforce dark theme.
- Updated multiple pages to use the new hook.
- Removed `DarkMode` component from affected pages.

> The following files were skipped due to too many changes: `apps/dashboard/src/pages/404.tsx`, `apps/dashboard/src/pages/index.tsx`, `apps/dashboard/src/pages/template/[id].tsx`, `apps/dashboard/src/pages/open-source.tsx`, `apps/dashboard/src/pages/contact-us.tsx`, `apps/dashboard/src/pages/community/ambassadors.tsx`

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

<!-- end pr-codex -->
2024-08-05 20:06:59 +00:00
gregfromstl ae28e27a8c feat: telegram login (#3830)
## TL;DR

This PR introduces support for Telegram OAuth across various components of the thirdweb packages.

## What changed?

- Added 'Telegram' as an OAuth option in `WALLETS` array within the `constants.ts` file.
- Introduced `telegramIconUri` constant and its usage across the application.
- Updated `socialIcons` object and methods to handle new Telegram icon.
- Enhanced `WalletImage` components to recognize and display the Telegram icon.
- Included Telegram in OAuth login path determination within `oauthSignIn.ts`.
- Updated enumerations and type definitions to include Telegram.
- Modified `InAppNativeConnector` and `InAppWebConnector` to handle Telegram OAuth redirection.

## How to test?

1. Navigate to the authentication section in the application.
2. Check for the new 'Sign in with Telegram' option.
3. Attempt to sign in using a Telegram account and verify the successful login flow.

## Why make this change?

To expand the authentication options available to users, providing more flexibility and convenience. Telegram is a popular messaging app, and integrating it as an OAuth option can enhance user experience.

---

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add `Telegram` as a supported authentication option across various parts of the application.

### Detailed summary
- Added `Telegram` as an authentication option in various files
- Included `TELEGRAM_ICON` in multiple components
- Updated social icons with `telegramIconUri`

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

<!-- end pr-codex -->
2024-08-05 19:49:16 +00:00
kien-ngo 9640b184ad Dashboard: Fix [Open IPFS folder] link (#3935)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to refactor the logic for getting the folder path from an IPFS hash URL in the `dropzone.tsx` component.

### Detailed summary
- Refactored logic to extract folder path from IPFS hash URL
- Updated return statement to use the extracted folder path for the IPFS URL

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

<!-- end pr-codex -->
2024-08-05 16:59:18 +00:00
kien-ngo a2e13820f2 Dashboard v5: Update dashboard [...paths].tsx to v5 (#3925)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to refactor contract detection logic and improve metadata handling.

### Detailed summary
- Removed `detectContractFeature` from `@thirdweb-dev/sdk`
- Added functions for detecting ERC20, ERC721, and ERC1155 extensions
- Improved contract metadata handling with `getContractMetadata` function

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

<!-- end pr-codex -->
2024-08-05 16:46:09 +00:00
jnsdls d0ea16e887 [Fix] Add 'Chainlist' link to header and update navigation structure (#3939)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add a new `Chainlist` link in the header and a corresponding button in the app shell.

### Detailed summary
- Added `Chainlist` link in the header navigation.
- Included a `Chainlist` button in the app shell for quick access.
- Removed previous `Chainlist` link implementation.

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

<!-- end pr-codex -->
2024-08-05 16:41:37 +00:00
kien-ngo 1f3448e1ea Portal: Improve ts docs (#3937)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR enhances error handling and callback functionality in various components like `TransactionButton` and `CreateDirectListingButton`.

### Detailed summary
- Added guidance for error handling and callbacks in `TransactionButton`
- Updated comments in `CreateDirectListingButton`
- Improved error handling info in `ClaimButton`
- Added examples and instructions for handling errors and callbacks in components

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

<!-- end pr-codex -->
2024-08-05 06:27:14 +00:00
MananTank ad619a779c Use shadcn checkbox in deploy form (#3928)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to refactor and improve the UI components in the custom contract form.

### Detailed summary
- Added `CheckboxWithLabel` component with enhanced functionality.
- Refactored `Tooltip` to `ToolTipLabel` for better usability.
- Updated usage of components like `TrackedLinkTW` and `Spinner`.
- Improved layout and styling for better user experience.

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

<!-- end pr-codex -->
2024-08-04 18:55:17 +00:00
MananTank 09e89e5e6b Move FileInput from chakra to tailwind (#3926)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates various components to replace Chakra UI props with className for styling consistency.

### Detailed summary
- Replaced Chakra UI props with className for consistent styling in multiple components.
- Updated styling in `FileInput` component for better consistency and maintainability.
- Added new imports and removed unnecessary imports in `FileInput` component.

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

<!-- end pr-codex -->
2024-08-04 18:46:46 +00:00
jnsdls baefa5e9c7 [Chore] Uniform formatting in package.json and update fs imports (#3933) 2024-08-03 23:53:16 +00:00
kien-ngo 57e87528c8 chore: add a small test for numberToHex() (#3932)
Happened to write this quick test when debugging an issue

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add a test for the `numberToHex` function in `hex.ts`.

### Detailed summary
- Added a test suite for `numberToHex` function in `hex.ts`
- Tested conversion of a number to a hexadecimal string with specified size and sign
- Asserted the correctness of the conversion result

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

<!-- end pr-codex -->
2024-08-03 23:39:39 +00:00
Jonas DanielsandGitHub 0b5dc2a137 [Fix] Validate and decode nextPath to ensure it is a relative path before redirecting (#3930) 2024-08-03 15:56:32 -07:00
jnsdls 0d23d5d6d5 [Fix] Exclude auth token from pay URLs when setting request headers (#3931)
This PR updates the fetch utility in the Thirdweb package to exclude the authorization token from being sent when the endpoint is related to the pay service. This ensures that requests to 'pay.' prefixed URLs are always made on behalf of the 'developer' rather than the 'end user.' It introduces a new function, isPayUrl, to determine if the URL belongs to the pay service.

---
2024-08-03 22:38:12 +00:00
kien-ngo 16376e56d7 Fix typo in docs (#3924)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces information about using Ethers.js in version 5 of the thirdweb SDK.

### Detailed summary
- Added a section titled "Ethers.js in v5" in `page.mdx`
- Clarified that SDK v5 is compatible with Ethers.js v5 and v6

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

<!-- end pr-codex -->
2024-08-03 05:19:07 +00:00
kien-ngo 3f923e4469 Update to React migration docs (#3923)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on migrating React SDK v4 to v5. It includes changes in installation steps, interacting with contracts, and introducing an ethers.js adapter.

### Detailed summary
- Updated installation steps for React SDK v5
- Added new components for interacting with contracts
- Introduced an ethers.js adapter for compatibility with v5
- Updated sidebar links for migration guidance

> The following files were skipped due to too many changes: `apps/portal/src/app/react/v5/sidebar.tsx`

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

<!-- end pr-codex -->
2024-08-03 05:09:30 +00:00
kien-ngo c7a417e285 <Crusade> Claim NFT drop to v5 (#3910)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to optimize NFT claiming functionality in the dashboard.

### Detailed summary
- Refactored NFTClaimButton to use `contractAddress` and `chainId`
- Updated NFTClaimForm to use `contractAddress` and `chainId` instead of `contract`
- Improved error handling in NFTClaimForm
- Added transaction handling in NFTClaimForm

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

<!-- end pr-codex -->
2024-08-03 01:58:31 +00:00
gregfromstl a97d7636ba docs: add callouts for generating client ID across multiple guides (#3921)
### TL;DR

Added information callouts across various SDK documentation pages, prompting users to generate a client ID to access blockchain APIs, storage, and more.

### What changed?

1. Integrated `Link` and `Button` components from `next/link` and `@/components/ui/button` respectively.
2. Added `<Callout>` components with instructional text and links for generating client IDs.
3. Changed existing callout in TypeScript client page from 'Api Key' to 'Client ID'.

### How to test?

Check the following pages for the new callout additions:
- `/connect`
- `/react-native/v5`
- `/react/v5`
- `/typescript/v5`
- `/typescript/v5/client`

### Why make this change?

To guide users in generating a client ID, which is necessary to access various features offered by the SDK.

---

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update references from "Api Key" to "Client ID" and add a `Link` and `Button` component for generating client IDs in various pages.

### Detailed summary
- Updated "Api Key" to "Client ID" in callouts
- Added `Link` and `Button` components for generating client IDs in multiple pages

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

<!-- end pr-codex -->
2024-08-03 01:55:02 +00:00
Jonas DanielsandGitHub 80e0957857 [Feature] Add portal build configuration to turbo.json and update changeset (#3922) 2024-08-02 18:11:35 -07:00
gregfromstl 14d3d18ad2 fix: portal dependencies (#3920)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating dependencies and adding webpack configuration.

### Detailed summary
- Skipped a test for executing zkcandy tx via SDK
- Updated `remark-gfm` version
- Added webpack configuration for external libraries
- Updated dependencies for linting and fixed scripts
- Updated various `mdast-util` packages
- Updated `micromark-extension` packages
- Updated `remark-gfm` version in multiple places

> The following files were skipped due to too many changes: `pnpm-lock.yaml`

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

<!-- end pr-codex -->
2024-08-03 00:38:06 +00:00
MananTank 079dc921d4 [dashboard] Enhance UI consistency across chain page components (#3919)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update various UI components in the dashboard app for better styling consistency and functionality.

### Detailed summary
- Updated styling of `CopyTextButton`, `ExplorerSection`, `LiveStats`, and `ChainOverviewSection`.
- Replaced `CopyButton` import with `CopyTextButton`.
- Improved button and link styling for better user experience.

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

<!-- end pr-codex -->
2024-08-03 00:10:36 +00:00
kien-ngo c2e86c6828 <Crusade> Type-only migration! (#3909)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update types and imports related to NFT metadata handling in various files.

### Detailed summary
- Updated types to use `NFTInput` instead of `NFTMetadataInput` for NFT metadata handling.
- Updated imports to use `NFTInput` from "thirdweb/utils" in multiple files.
- Adjusted function signatures and parameters accordingly for consistency and compatibility.

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

<!-- end pr-codex -->
2024-08-02 23:32:06 +00:00
gregfromstl 9d519c6590 chore: move the docs to the monorepo (#3915)
Adds the docs to the monorepo
2024-08-02 22:41:36 +00:00
kien-ngo d04b03226a <Crusade> Dashboard to v5: Marketplace v3 (#3907)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add a `type` field to `DirectListing` and `EnglishAuction` types in the marketplace extensions.

### Detailed summary
- Added `type` field to `DirectListing` and `EnglishAuction` types
- Updated components to handle `type` field for pricing display
- Refactored contract role checks for Marketplace v3 compatibility

> The following files were skipped due to too many changes: `apps/dashboard/src/contract-ui/tabs/listings/components/list-form.tsx`

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

<!-- end pr-codex -->
2024-08-02 22:17:03 +00:00
MananTank c24dadaa60 Chain page tweaks (#3916)
<!-- start pr-codex -->

## PR-Codex overview
This PR updates various components and functions related to chain metadata and wallet connection logic.

### Detailed summary
- Improved conditional rendering for `ChainCTA` component
- Updated styles and behavior in `SidebarContent` and `MobileMenu`
- Added `useCustomConnectModal` hook for custom wallet connection modal
- Enhanced `AddChainToWallet` component with custom connect modal functionality

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

<!-- end pr-codex -->
2024-08-02 22:09:42 +00:00
gregfromstl 2c751b4fce test: adds msw (#3913)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add `msw` for network call mocking, update dependencies, and enhance wallet integration tests.

### Detailed summary
- Added `msw` for network call mocking in tests
- Updated dependencies
- Improved wallet integration tests with new functions

> The following files were skipped due to too many changes: `pnpm-lock.yaml`

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

<!-- end pr-codex -->
2024-08-02 20:16:31 +00:00
Joe-Thirdweb e7f7ae8452 Chainlist default banner for PAID CHAINS (#3911)
## Problem solved

Short description of the bug fixed or feature added
Added a default banner and CTA image for every paying chain except lens.
Added an about section to every paying chain
Added a link to their website for every paying chain

##How to test
Visit the chain's chainlist page and view the images.
Click on their "learn More" butttons to be taken to their website.
Chains Added
- Lumia Mainnet
- Superposition Testnet
- Aleph 0 Mainnet
- b3 Mainnet
- Campnetwork v2 testnet
- Donatuz mainnet
- Fuse
- Gemuchain
- 0g labs testnet
- zkCandy
- zkSync

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add metadata for different blockchains in the dashboard.

### Detailed summary
- Added metadata for Lumia Mainnet, Superposition Testnet, Aleph 0 Mainnet, B3 Mainnet, CampNetwork Testnet v2, Donatuz, Fuse, Gemuchain, 0G-Newton-Testnet, Plume, zkCandy, and zkSync
- Updated `utils.ts` with imports for new assets
- Updated chain metadata record with details for each blockchain

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

<!-- end pr-codex -->
2024-08-02 19:14:22 +00:00
9c292a4903 [dashboard] Chain page redesign (#3826)
Co-authored-by: Manan Tank <[email protected]>
2024-08-02 19:01:12 +00:00
jnsdls b06272c35d [Feature] Add Chainlist link and update header styles (#3899)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to add a new link "Chainlist" to the dashboard header and update styles for better user experience.

### Detailed summary
- Added "Chainlist" link to the dashboard header
- Updated styles for the "Chainlist" link to match the design
- Adjusted styles for active links in the header for better visibility and consistency

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

<!-- end pr-codex -->
2024-08-02 17:44:14 +00:00
joaquim-verges 366646e354 chore(jsdocs): enhance JSDoc examples across multiple hooks and functions (#3908)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces enhancements related to wallet interactions, contract calls, and event monitoring in the application.

### Detailed summary
- Added functionality to pre-authenticate users via email or phone number
- Enhanced wallet connection components with account abstraction and gas sponsorship options
- Updated wallet connection buttons to support account abstraction and gas sponsorship
- Improved wallet information retrieval with examples
- Expanded capabilities for fetching wallet balances for native and specific tokens
- Enhanced contract call preparation with examples of different method signatures and value options
- Improved contract event monitoring with event extensions and custom event watching
- Updated contract read hooks to automatically update on contract changes

> The following files were skipped due to too many changes: `packages/thirdweb/src/react/core/hooks/contract/useReadContract.ts`, `packages/thirdweb/src/transaction/actions/send-transaction.ts`, `packages/thirdweb/src/react/web/hooks/transaction/useSendTransaction.tsx`

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

<!-- end pr-codex -->
2024-08-02 03:17:02 +00:00
joaquim-verges 8eeec64388 fix(tests): update PayEmbed tests to use waitFor for render assertions (#3906)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update test files in `PayEmbed-disconnected.test.tsx` and `PayEmbed.test.tsx` to use `waitFor` for asynchronous operations.

### Detailed summary
- Added `waitFor` for asynchronous operations in test files
- Updated test cases to handle asynchronous rendering and interactions

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

<!-- end pr-codex -->
2024-08-01 20:03:45 +00:00
2234 changed files with 105194 additions and 36526 deletions
+1
View File
@@ -20,6 +20,7 @@
"playground-web",
"thirdweb-dashboard",
"wallet-ui",
"portal",
"@thirdweb-dev/auth",
"@thirdweb-dev/chains",
"@thirdweb-dev/cli",
+2 -1
View File
@@ -44,7 +44,8 @@ packages/unity-js-bridge/ @joaquim-verges @0xFirekeeper @jnsdls
apps/ @jnsdls @joaquim-verges
apps/dashboard/ @jnsdls @MananTank @joaquim-verges
apps/playground-web/ @joaquim-verges @gregfromstl @jnsdls @joaquim-verges
apps/wallet-ui/ @gregfromstl @jnsdls @joaquim-verges
apps/wallet-ui/ @gregfromstl @jnsdls @joaquim-verges @MananTank
apps/portal/ @gregfromstl @jnsdls @joaquim-verges @MananTank
# .github folder + .changeset + turbo config is owned by jonas for now
scripts/ @jnsdls @joaquim-verges
+15
View File
@@ -77,6 +77,21 @@ Many of the tests use forked versions of live chains like mainnet. We fork these
If you need to use accounts in your tests, use the predefined accounts in `test/src/test-wallets.ts`. These are the default anvil accounts that are pre-funded on the local test forks.
##### Mocking Network Calls
If your test depends on a downstream network call, you must mock the call using `msw`. You can use one of the existing mocks in `test/src/mocks` or create your own. Once you've created a mock request, setup the server and add all your mocks like so:
```ts
import { setupServer } from "msw/node";
import { downloadMock, uploadMock } from "../../../test/src/mocks/storage.js";
const server = setupServer(uploadMock("HASH"), downloadMock({ name: "Test NFT" }));
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
```
#### Linting
We use a linter to maintain best practices across projects. Once your changes are complete (or periodically while making changes), run the linter with the following command from the repo root:
+3
View File
@@ -11,3 +11,6 @@ legacy_packages:
packages:
- changed-files:
- any-glob-to-any-file: "packages/**/*"
portal:
- changed-files:
- any-glob-to-any-file: "apps/portal/**/*"
-25
View File
@@ -142,31 +142,6 @@ jobs:
echo "Bundling failed"
exit 1
fi
benchmark:
# cannot run benchmarks on merge group
if: github.event_name != 'merge_group'
timeout-minutes: 15
name: "Benchmarks"
runs-on: ubuntu-latest
steps:
- name: Check out the code
uses: actions/checkout@v4
- name: Setup & Install
uses: ./.github/composite-actions/install
- name: Set up foundry
uses: foundry-rs/foundry-toolchain@v1
with:
cache: false
- name: Run benchmarks
uses: CodSpeedHQ/action@v3
with:
token: ${{ secrets.CODSPEED_TOKEN }}
run: "pnpm bench"
size:
# only run on pull requests
-75
View File
@@ -1,75 +0,0 @@
# On the Version Packages branch
# Generate and Commit the Typedoc JSON files and the Snippets JSON files
name: Commit Release Artifacts
on:
push:
branches:
- changeset-release/main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
# cancel any previous runs if they were started before this one
cancel-in-progress: true
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
TW_SECRET_KEY: ${{ secrets.TW_SECRET_KEY }}
jobs:
release-artifacts:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v4
# bun setup is required, because pnpm typdoc will run pnpm build and some packages uses bun for build
- name: Setup bun
uses: oven-sh/setup-bun@v1
with:
bun-version: 1.0.35
- name: Install
uses: ./.github/composite-actions/install
- name: Build
run: pnpm build
- name: Typedoc
run: pnpm typedoc
- name: Generate Docs
run: |
cd legacy_packages/sdk
pnpm generate-docs
cd ../react-core
pnpm generate-docs
cd ../react
pnpm generate-docs
cd ../..
- name: Generate Snippets
run: pnpm generate-snippets
- name: Commit changes
run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
git status
git add legacy_packages/react/typedoc/documentation.json.gz
git add legacy_packages/react-core/typedoc/documentation.json.gz
git add legacy_packages/react-native/typedoc/documentation.json.gz
git add legacy_packages/sdk/typedoc/documentation.json.gz
git add legacy_packages/storage/typedoc/documentation.json.gz
git add legacy_packages/wallets/typedoc/documentation.json.gz
git add packages/thirdweb/typedoc/documentation.json.gz
git add snippets/feature_snippets_react.json
git add snippets/feature_snippets_sdk.json
git add snippets/snippets.json
git commit -m "Commit Release Artifacts [skip ci]"
git push
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+6 -2
View File
@@ -14,7 +14,7 @@ public/dist
.idea/
.yalc/
yalc.lock
build/
./build/
playwright-report/
.env/
@@ -25,4 +25,8 @@ legacy_packages/cli/artifacts/
codecov
# Remove sitemap files (generated at build time)
sitemap*.xml
sitemap*.xml
# typedoc
legacy_packages/*/typedoc/*
packages/*/typedoc/*
+3
View File
@@ -18,5 +18,8 @@
},
"[json]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
+15
View File
@@ -15,6 +15,21 @@ module.exports = {
message:
'Are you *sure* you need to use "useEffect" here? If you loading any async function prefer using "useQuery".',
},
{
selector: "CallExpression[callee.name='defineChain']",
message:
"Use useV5DashboardChain instead if you are using it inside a component",
},
{
selector: "CallExpression[callee.name='defineDashboardChain']",
message:
"Use useV5DashboardChain instead if you are using it inside a component",
},
{
selector: "CallExpression[callee.name='mapV4ChainToV5Chain']",
message:
"Use useV5DashboardChain instead if you are using it inside a component",
},
],
"no-restricted-imports": [
"error",
+6 -7
View File
@@ -27,7 +27,7 @@
"@coinbase/onchainkit": "^0.14.2",
"@emotion/react": "11.11.4",
"@emotion/styled": "11.11.5",
"@hookform/resolvers": "^3.6.0",
"@hookform/resolvers": "^3.9.0",
"@n8tb1t/use-scroll-position": "^2.0.3",
"@radix-ui/react-alert-dialog": "^1.1.1",
"@radix-ui/react-aspect-ratio": "^1.0.3",
@@ -40,23 +40,22 @@
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.0",
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "1.1.2",
"@react-icons/all-files": "^4.1.0",
"@sentry/nextjs": "^8.8.0",
"@stripe/react-stripe-js": "^2.7.2",
"@stripe/react-stripe-js": "^2.7.3",
"@stripe/stripe-js": "^3.5.0",
"@tanstack/query-async-storage-persister": "^4.36.1",
"@tanstack/react-query": "^4.36.1",
"@tanstack/react-query-persist-client": "^4.36.1",
"@tanstack/react-table": "^8.17.3",
"@thirdweb-dev/react": "workspace:*",
"@thirdweb-dev/react-core": "workspace:*",
"@thirdweb-dev/sdk": "workspace:*",
"@thirdweb-dev/service-utils": "workspace:*",
"@thirdweb-dev/storage": "workspace:*",
"@thirdweb-dev/wallets": "workspace:*",
"@vercel/og": "^0.6.2",
"abitype": "1.0.5",
"chakra-react-select": "^4.7.6",
@@ -106,13 +105,13 @@
"server-only": "^0.0.1",
"sonner": "^1.5.0",
"spdx-correct": "^3.2.0",
"spin-wheel-game": "1.0.3-alpha.3",
"swagger-ui-react": "^5.17.14",
"tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7",
"thirdweb": "workspace:*",
"tiny-invariant": "^1.3.3",
"use-debounce": "^10.0.1",
"vaul": "^0.9.1",
"zksync-ethers": "5.9.0",
"zod": "3.23.8"
},
@@ -120,7 +119,7 @@
"@chakra-ui/cli": "^2.4.1",
"@next/bundle-analyzer": "^14.2.4",
"@next/eslint-plugin-next": "^14.2.4",
"@playwright/test": "^1.44.1",
"@playwright/test": "1.44.1",
"@types/color": "^3.0.6",
"@types/node": "20.14.9",
"@types/papaparse": "^5.3.14",
@@ -150,7 +149,7 @@
"next-sitemap": "^4.2.3",
"next-unused": "^0.0.6",
"tailwindcss": "^3.4.4",
"typescript": "5.5.2"
"typescript": "5.5.4"
},
"next-unused": {
"alias": {},
@@ -0,0 +1,7 @@
{
"applinks": {},
"webcredentials": {
"apps": ["XYHGSFAMHX.com.thirdweb.demo"]
},
"appclips": {}
}
@@ -0,0 +1,15 @@
[
{
"relation": [
"delegate_permission/common.handle_all_urls",
"delegate_permission/common.get_login_creds"
],
"target": {
"namespace": "android_app",
"package_name": "com.thirdweb.demo",
"sha256_cert_fingerprints": [
"40:EB:0D:96:57:F3:D8:1F:BA:87:B8:E4:26:E0:3A:DB:C8:35:96:A8:A2:B2:55:F0:B1:64:F1:39:F8:6F:7E:EB"
]
}
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 646 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

+7
View File
@@ -282,6 +282,13 @@ function redirects() {
"https://support.thirdweb.com/troubleshooting-errors/7Y1BqKNvtLdBv5fZkRZZB3/issue-linking-device-on-the-authorization-page-via-thirdweb-cli/cn9LRA3ax7XCP6uxwRYdvx",
permanent: false,
},
// temporary redirect gas -> explore page
{
source: "/gas",
destination: "/explore",
permanent: false,
},
];
}
@@ -0,0 +1,49 @@
"use client";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
import { MenuIcon } from "lucide-react";
import { useState } from "react";
import { NavLink } from "../ui/NavLink";
export function BurgerMenuButton(props: {
links?: { href: string; label: React.ReactNode }[];
footer?: React.ReactNode;
}) {
const [isOpen, setIsOpen] = useState(false);
return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button size="icon" variant="outline">
<MenuIcon strokeWidth={1} />
</Button>
</DialogTrigger>
<DialogContent
className="p-6 rounded-xl"
dialogCloseClassName="hidden"
onClick={(e) => {
if (e.target instanceof HTMLAnchorElement) {
setIsOpen(false);
}
}}
>
<div className="flex flex-col gap-2">
{props.links?.map((link) => {
return (
<Button size="sm" variant="ghost" asChild key={link.href}>
<NavLink
href={link.href}
className="!text-left justify-start flex gap-2 h-auto py-3"
activeClassName="bg-accent"
>
{link.label}
</NavLink>
</Button>
);
})}
</div>
{props.footer}
</DialogContent>
</Dialog>
);
}
@@ -0,0 +1,33 @@
import type React from "react";
import { cn } from "../../lib/utils";
import { NavLink } from "../ui/NavLink";
export type SidebarContentProps = {
header?: React.ReactNode;
links?: { href: string; label: React.ReactNode }[];
className?: string;
};
export function Sidebar(props: SidebarContentProps) {
return (
<aside
className={cn("w-[240px] flex-shrink-0 hidden lg:block", props.className)}
>
<div className="sticky top-0 pt-8">
{props.header}
<div className="flex flex-col border-l-2 border-border">
{props.links?.map((link) => (
<NavLink
key={link.href}
href={link.href}
className="text-sm py-1.5 pl-4 text-muted-foreground hover:text-foreground border-l-2 ml-[-2px] border-transparent hover:border-foreground transition-colors"
activeClassName="text-foreground border-link-foreground"
>
{link.label}
</NavLink>
))}
</div>
</div>
</aside>
);
}
@@ -1,5 +1,6 @@
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { ThirdwebMiniLogo } from "app/components/ThirdwebMiniLogo";
import Link from "next/link";
import {
SiDiscord,
@@ -11,7 +12,6 @@ import {
SiX,
SiYoutube,
} from "react-icons/si";
import { ThirdwebMiniLogo } from "../../../app/components/ThirdwebMiniLogo";
type AppFooterProps = {
className?: string;
@@ -1,10 +1,10 @@
"use client";
import { Button } from "@/components/ui/button";
import { ClientOnly } from "components/ClientOnly/ClientOnly";
import { Moon, Sun } from "lucide-react";
import { useTheme } from "next-themes";
import * as React from "react";
import { ClientOnly } from "../../components/ClientOnly/ClientOnly";
import { Skeleton } from "./ui/skeleton";
export function ColorModeToggle() {
@@ -1,9 +1,18 @@
"use client";
import { ThemeProvider as NextThemesProvider } from "next-themes";
import { ThemeProvider as NextThemesProvider, useTheme } from "next-themes";
import type { ThemeProviderProps } from "next-themes/dist/types";
import * as React from "react";
import { useEffect } from "react";
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}
export function useForceDarkTheme() {
const { setTheme } = useTheme();
// eslint-disable-next-line no-restricted-syntax
useEffect(() => {
setTheme("dark");
}, [setTheme]);
}
@@ -0,0 +1,47 @@
import { Highlight } from "prism-react-renderer";
import React from "react";
import { cn } from "../../lib/utils";
import { CopyButton } from "./CopyButton";
import { Card } from "./card";
interface CodeBlockProps {
code: string;
language?: string;
className?: string;
canCopy?: boolean;
}
export const CodeBlock = ({
code,
language = "sh",
canCopy = true,
}: CodeBlockProps) => {
return (
<Highlight code={code} language={language}>
{({ className, tokens, getLineProps, getTokenProps }) => (
<Card className={className}>
{canCopy && (
<CopyButton text={code} className="float-right p-2 m-2" />
)}
<div
className={cn(
"block font-mono text-sm whitespace-pre-wrap p-4 overflow-auto",
className,
)}
>
{tokens.map((line, i) => (
// biome-ignore lint/suspicious/noArrayIndexKey: index IS the key here
<div {...getLineProps({ line, key: i })} key={i}>
{line.map((token, key) => (
// biome-ignore lint/suspicious/noArrayIndexKey: index IS the key here
<span {...getTokenProps({ token, key })} key={key} />
))}
</div>
))}
</div>
</Card>
)}
</Highlight>
);
};
@@ -10,9 +10,9 @@ import {
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import type { buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import type { VariantProps } from "class-variance-authority";
import type React from "react";
import { cn } from "../../lib/utils";
export interface ConfirmationDialogProps
extends VariantProps<typeof buttonVariants> {
@@ -1,6 +1,6 @@
"use client";
import { cn } from "../../lib/utils";
import { cn } from "@/lib/utils";
import { CopyTextButton } from "./CopyTextButton";
export function CopyAddressButton(props: {
@@ -1,8 +1,8 @@
"use client";
import { cn } from "@/lib/utils";
import { CheckIcon, CopyIcon } from "lucide-react";
import { useState } from "react";
import { cn } from "../../lib/utils";
import { Button } from "./button";
import { ToolTipLabel } from "./tooltip";
@@ -1,8 +1,8 @@
"use client";
import { cn } from "@/lib/utils";
import { CheckIcon, CopyIcon } from "lucide-react";
import { useState } from "react";
import { cn } from "../../lib/utils";
import { Button } from "./button";
import { ToolTipLabel } from "./tooltip";
@@ -23,10 +23,15 @@ export function CopyTextButton(props: {
}) {
const [isCopied, setIsCopied] = useState(false);
const copyButton = isCopied ? (
<CheckIcon className={cn("size-3 text-green-500", props.iconClassName)} />
<CheckIcon
className={cn("size-3 text-green-500 shrink-0", props.iconClassName)}
/>
) : (
<CopyIcon
className={cn("size-3 text-muted-foreground", props.iconClassName)}
className={cn(
"size-3 text-muted-foreground shrink-0",
props.iconClassName,
)}
/>
);
@@ -36,7 +41,7 @@ export function CopyTextButton(props: {
variant={props.variant || "outline"}
aria-label={props.tooltip}
className={cn(
"h-auto w-auto px-2.5 py-1.5 flex gap-2 rounded-lg text-foreground",
"h-auto w-auto px-2.5 py-1.5 flex gap-2 rounded-lg text-foreground font-normal",
props.className,
)}
onClick={() => {
@@ -47,13 +52,13 @@ export function CopyTextButton(props: {
>
{props.copyIconPosition === "right" ? (
<>
{props.textToShow}
<span className="truncate min-w-0"> {props.textToShow} </span>
{copyButton}
</>
) : (
<>
{copyButton}
{props.textToShow}
<span className="truncate min-w-0"> {props.textToShow} </span>
</>
)}
</Button>
@@ -1,7 +1,8 @@
"use client";
import { useIsomorphicLayoutEffect } from "@/lib/useIsomorphicLayoutEffect";
import type React from "react";
import { useLayoutEffect, useRef, useState } from "react";
import { useRef, useState } from "react";
export function DynamicHeight(props: {
children: React.ReactNode;
@@ -37,7 +38,7 @@ export function useHeightObserver() {
const elementRef = useRef<HTMLDivElement>(null);
const [height, setHeight] = useState<number | undefined>();
useLayoutEffect(() => {
useIsomorphicLayoutEffect(() => {
const element = elementRef.current;
if (!element) {
return;
@@ -0,0 +1,24 @@
"use client";
import { cn } from "@/lib/utils";
import Link from "next/link";
import { usePathname } from "next/navigation";
export type NavButtonProps = {
className?: string;
activeClassName?: string;
href: string;
};
export function NavLink(props: React.PropsWithChildren<NavButtonProps>) {
const pathname = usePathname();
const isActive = pathname === props.href;
return (
<Link
href={props.href}
className={cn(props.className, isActive && props.activeClassName)}
>
{props.children}
</Link>
);
}
@@ -1,7 +1,8 @@
"use client";
import { useIsomorphicLayoutEffect } from "@/lib/useIsomorphicLayoutEffect";
import { cn } from "@/lib/utils";
import { useLayoutEffect, useRef } from "react";
import { useRef } from "react";
import styles from "./ScrollShadow.module.css";
export function ScrollShadow(props: {
@@ -17,7 +18,7 @@ export function ScrollShadow(props: {
const shadowRightEl = useRef<HTMLDivElement>(null);
const wrapperEl = useRef<HTMLDivElement>(null);
useLayoutEffect(() => {
useIsomorphicLayoutEffect(() => {
const content = scrollableEl.current;
const shadowTop = shadowTopEl.current;
const shadowBottom = shadowBottomEl.current;
+1 -1
View File
@@ -10,7 +10,7 @@ const alertVariants = cva(
variant: {
default: "bg-background text-foreground",
destructive:
"bg-destructive/10 border-destructive/50 dark:border-destructive [&>svg]:text-destructive",
"bg-destructive/30 border-destructive/50 dark:border-destructive [&>svg]:text-destructive",
info: "bg-primary/10 border-primary/50 dark:border-primary [&>svg]:text-primary",
warning:
"bg-warning/10 border-warning/50 dark:border-warning [&>svg]:text-warning",
@@ -44,10 +44,13 @@ export interface ButtonProps
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
const btnOnlyProps =
Comp === "button" ? { type: "button" as const } : undefined;
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...btnOnlyProps}
{...props}
/>
);
@@ -28,3 +28,19 @@ const Checkbox = React.forwardRef<
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
export { Checkbox };
export function CheckboxWithLabel(props: {
children: React.ReactNode;
className?: string;
}) {
return (
<label
className={cn(
"flex gap-2 items-start text-secondary-foreground text-sm cursor-pointer select-none [&>button]:mt-0.5",
props.className,
)}
>
{props.children}
</label>
);
}
+12 -4
View File
@@ -31,14 +31,17 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
dialogOverlayClassName?: string;
dialogCloseClassName?: string;
}
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogOverlay className={props.dialogOverlayClassName} />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed grid w-full max-w-lg gap-4 border bg-background p-6 shadow-lg duration-300 rounded-lg border-border",
"fixed grid w-full max-w-lg gap-4 border bg-background p-6 shadow-lg duration-300 rounded-t-xl md:rounded-lg border-border",
// on mobile - put the dialog at the bottom of the screen, animate - slide up and fade in
"bottom-0 left-0 right-0",
"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
@@ -54,7 +57,12 @@ const DialogContent = React.forwardRef<
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<DialogPrimitive.Close
className={cn(
"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",
props.dialogCloseClassName,
)}
>
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
@@ -0,0 +1,118 @@
"use client";
import * as React from "react";
import { Drawer as DrawerPrimitive } from "vaul";
import { cn } from "@/lib/utils";
const Drawer = ({
shouldScaleBackground = true,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
<DrawerPrimitive.Root
shouldScaleBackground={shouldScaleBackground}
{...props}
/>
);
Drawer.displayName = "Drawer";
const DrawerTrigger = DrawerPrimitive.Trigger;
const DrawerPortal = DrawerPrimitive.Portal;
const DrawerClose = DrawerPrimitive.Close;
const DrawerOverlay = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay
ref={ref}
className={cn("fixed inset-0 z-50 bg-black/80", className)}
{...props}
/>
));
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
const DrawerContent = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
className,
)}
{...props}
>
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
));
DrawerContent.displayName = "DrawerContent";
const DrawerHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
{...props}
/>
);
DrawerHeader.displayName = "DrawerHeader";
const DrawerFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props}
/>
);
DrawerFooter.displayName = "DrawerFooter";
const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className,
)}
{...props}
/>
));
DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
const DrawerDescription = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
export {
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
};
@@ -75,7 +75,7 @@ const SelectContent = React.forwardRef<
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className,
@@ -0,0 +1,29 @@
"use client";
import * as SwitchPrimitives from "@radix-ui/react-switch";
import * as React from "react";
import { cn } from "@/lib/utils";
const Switch = React.forwardRef<
React.ElementRef<typeof SwitchPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
>(({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-foreground data-[state=unchecked]:bg-input",
className,
)}
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb
className={cn(
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0",
)}
/>
</SwitchPrimitives.Root>
));
Switch.displayName = SwitchPrimitives.Root.displayName;
export { Switch };
+6 -3
View File
@@ -1,6 +1,9 @@
"use client";
import { useIsomorphicLayoutEffect } from "@/lib/useIsomorphicLayoutEffect";
import { cn } from "@/lib/utils";
import Link from "next/link";
import { useCallback, useLayoutEffect, useRef, useState } from "react";
import { cn } from "../../lib/utils";
import { useCallback, useRef, useState } from "react";
import { ScrollShadow } from "./ScrollShadow/ScrollShadow";
import { Button } from "./button";
@@ -126,7 +129,7 @@ function useUnderline<El extends HTMLElement>() {
setActiveTabEl(el);
}, []);
useLayoutEffect(() => {
useIsomorphicLayoutEffect(() => {
if (activeTabEl && containerRef.current && lineRef.current) {
const containerRect = containerRef.current.getBoundingClientRect();
const lineEl = lineRef.current;
+12 -3
View File
@@ -31,15 +31,24 @@ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
export function ToolTipLabel(props: {
children: React.ReactNode;
label: string;
label: string | undefined;
rightIcon?: React.ReactNode;
leftIcon?: React.ReactNode;
}) {
if (!props.label) {
return props.children;
}
return (
<TooltipProvider>
<Tooltip delayDuration={100} disableHoverableContent={true}>
<TooltipTrigger asChild>{props.children}</TooltipTrigger>
<TooltipContent sideOffset={10}>
<TooltipTrigger asChild className="!pointer-events-auto">
{props.children}
</TooltipTrigger>
<TooltipContent
sideOffset={10}
className="max-w-[300px] leading-relaxed"
>
<div className="p-2 text-sm flex items-center gap-1.5">
{props.leftIcon}
{props.label}
+10 -1
View File
@@ -1,4 +1,4 @@
export const LOGGED_IN_ONLY_PATHS = [
const LOGGED_IN_ONLY_PATHS = [
// anything that _starts_ with /dashboard is logged in only
"/dashboard",
// anything that _starts_ with /cli is logged in only
@@ -6,3 +6,12 @@ export const LOGGED_IN_ONLY_PATHS = [
"/support",
// TODO: add any other logged in only paths here
];
export function isLoginRequired(pathname: string) {
// exceptions from LOGGED_IN_ONLY_PATHS
if (pathname.startsWith("/dashboard/connect/playground")) {
return false;
}
return LOGGED_IN_ONLY_PATHS.some((path) => pathname.startsWith(path));
}
+17
View File
@@ -0,0 +1,17 @@
import { toast } from "sonner";
// if browser supports sharing use native sharing - use that, else just copy to clipboard + show toast
export async function shareLink(_data: ShareData) {
const data = { ..._data, url: _data.url || window.location.href };
if (
"canShare" in navigator &&
navigator.canShare &&
navigator.canShare(data)
) {
await navigator.share(data);
} else {
await navigator.clipboard.writeText(data.url);
toast.info("URL copied to clipboard");
}
}
@@ -0,0 +1,4 @@
import { useEffect, useLayoutEffect } from "react";
export const useIsomorphicLayoutEffect =
typeof window !== "undefined" ? useLayoutEffect : useEffect;
+16 -16
View File
@@ -55,7 +55,7 @@
--inverted: var(--foreground);
/* bg - colorful */
--primary: 215.88 100% 55%;
--primary: 221 83% 54%;
--destructive: 0 62.8% 15%;
--success: 156.2 71.6% 10%;
--warning: 40.61deg 96.12% 8%;
@@ -93,23 +93,23 @@
/* shadcn charts */
@layer base {
:root {
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
}
.dark {
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
:root {
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
}
.dark {
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}
@keyframes skeleton {
0%,
100% {
@@ -90,8 +90,10 @@ export const engineKeys = {
health: (instance: string) =>
[...engineKeys.all, instance, "health"] as const,
latestVersion: () => [...engineKeys.all, "latestVersion"] as const,
metrics: (engineId: string) =>
[...engineKeys.all, engineId, "metrics"] as const,
systemMetrics: (engineId: string) =>
[...engineKeys.all, engineId, "systemMetrics"] as const,
queueMetrics: (engineId: string) =>
[...engineKeys.all, engineId, "queueMetrics"] as const,
};
export const contractKeys = {
@@ -14,13 +14,22 @@ import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useCallback, useMemo } from "react";
import { defineChain } from "thirdweb";
import { AutoConnect, ConnectButton } from "thirdweb/react";
import type { Chain } from "thirdweb";
import { AutoConnect, ConnectButton, useConnectModal } from "thirdweb/react";
import { getSDKTheme } from "../../../../app/components/sdk-component-theme";
import { CustomChainRenderer } from "../../../../components/selects/CustomChainRenderer";
import { mapV4ChainToV5Chain } from "../../../../contexts/map-chains";
import { useSetIsNetworkConfigModalOpen } from "../../../../hooks/networkConfigModal";
import { useFavoriteChains } from "../../hooks/useFavoriteChains";
import { useLoggedInUser } from "../../hooks/useLoggedInUser";
import { popularChains } from "../popularChains";
export const CustomConnectWallet: React.FC = () => {
export const CustomConnectWallet = (props: {
loginRequired?: boolean;
connectButtonClassName?: string;
}) => {
const loginRequired =
props.loginRequired === undefined ? true : props.loginRequired;
const { theme } = useTheme();
const recentChainsv4 = useRecentlyUsedChains();
const addRecentlyUsedChainId = useAddRecentlyUsedChainId();
@@ -28,16 +37,16 @@ export const CustomConnectWallet: React.FC = () => {
const t = theme === "light" ? "light" : "dark";
const allv4Chains = useSupportedChains();
const favChainsQuery = useFavoriteChains();
const setIsNetworkConfigModalOpen = useSetIsNetworkConfigModalOpen();
const allChains = useMemo(() => {
return allv4Chains.map((c) => defineChain(c));
return allv4Chains.map(mapV4ChainToV5Chain);
}, [allv4Chains]);
const chainSections = useMemo(() => {
return [
{
label: "Favorites",
chains: favChainsQuery.data.map(defineChain),
chains: favChainsQuery.data.map(mapV4ChainToV5Chain),
},
{
label: "Popular",
@@ -45,7 +54,7 @@ export const CustomConnectWallet: React.FC = () => {
},
{
label: "Recent",
chains: recentChainsv4.map(defineChain),
chains: recentChainsv4.map(mapV4ChainToV5Chain),
},
];
}, [recentChainsv4, favChainsQuery.data]);
@@ -57,7 +66,7 @@ export const CustomConnectWallet: React.FC = () => {
if (isLoading) {
return (
<>
<div className="w-[144px] h-[48px] bg-muted border rounded-lg flex items-center justify-center">
<div className="w-[144px] h-[48px] bg-muted border border-border rounded-lg flex items-center justify-center">
<Spinner className="size-4" />
</div>
{/* need autoconnect here so that we actually connect */}
@@ -66,7 +75,7 @@ export const CustomConnectWallet: React.FC = () => {
);
}
if (!isLoggedIn) {
if (!isLoggedIn && loginRequired) {
return (
<>
<Button asChild variant="default" className="gap-2" size="lg">
@@ -84,7 +93,7 @@ export const CustomConnectWallet: React.FC = () => {
return (
<ConnectButton
theme={t}
theme={getSDKTheme(t)}
client={thirdwebClient}
connectModal={{
privacyPolicyUrl: "/privacy",
@@ -107,6 +116,9 @@ export const CustomConnectWallet: React.FC = () => {
console.error("Failed to log out", err);
}
}}
connectButton={{
className: props.connectButtonClassName,
}}
chains={allChains}
detailsModal={{
networkSelector: {
@@ -114,8 +126,10 @@ export const CustomConnectWallet: React.FC = () => {
onSwitch(chain) {
addRecentlyUsedChainId(chain.id);
},
// TODO: bring this back when it works reliably
// renderChain: CustomChainRenderer,
renderChain: CustomChainRenderer,
onCustomClick: () => {
setIsNetworkConfigModalOpen(true);
},
},
}}
/>
@@ -193,6 +207,35 @@ export function ConnectWalletWelcomeScreen(props: {
);
}
export function useCustomConnectModal() {
const { connect } = useConnectModal();
const { theme } = useTheme();
return useCallback(
(options?: { chain?: Chain }) => {
return connect({
client: thirdwebClient,
appMetadata: {
name: "thirdweb",
logoUrl: "https://thirdweb.com/favicon.ico",
url: "https://thirdweb.com",
},
chain: options?.chain,
privacyPolicyUrl: "/privacy",
termsOfServiceUrl: "/tos",
showThirdwebBranding: false,
welcomeScreen: () => (
<ConnectWalletWelcomeScreen
theme={theme === "light" ? "light" : "dark"}
/>
),
theme: getSDKTheme(theme === "light" ? "light" : "dark"),
});
},
[connect, theme],
);
}
/**
* A link component extends the `Link` component and adds tracking.
*/
@@ -2,11 +2,11 @@ import {
useIsAdmin,
useIsAdminOrSelf,
} from "@3rdweb-sdk/react/hooks/useContractRoles";
import type { ValidContractInstance } from "@thirdweb-dev/sdk";
import type { ThirdwebContract } from "thirdweb";
import type { ComponentWithChildren } from "types/component-with-children";
interface AdminOnlyProps {
contract?: ValidContractInstance;
contract: ThirdwebContract;
fallback?: JSX.Element;
}
@@ -22,7 +22,9 @@ export const AdminOnly: ComponentWithChildren<AdminOnlyProps> = ({
return <>{children}</>;
};
interface AdminOrSelfOnlyProps extends AdminOnlyProps {
interface AdminOrSelfOnlyProps {
contract: ThirdwebContract;
fallback?: JSX.Element;
/**
* The address of the account to check against
*/
@@ -1,9 +1,9 @@
import { useIsLister } from "@3rdweb-sdk/react/hooks/useContractRoles";
import type { ValidContractInstance } from "@thirdweb-dev/sdk";
import type { ThirdwebContract } from "thirdweb";
import type { ComponentWithChildren } from "types/component-with-children";
interface IListerOnlyProps {
contract?: ValidContractInstance;
contract: ThirdwebContract;
}
export const ListerOnly: ComponentWithChildren<IListerOnlyProps> = ({
@@ -1,9 +1,9 @@
import { useIsMinter } from "@3rdweb-sdk/react/hooks/useContractRoles";
import type { ValidContractInstance } from "@thirdweb-dev/sdk";
import type { ThirdwebContract } from "thirdweb";
import type { ComponentWithChildren } from "types/component-with-children";
interface IMinterOnlyProps {
contract?: ValidContractInstance;
contract: ThirdwebContract;
}
export const MinterOnly: ComponentWithChildren<IMinterOnlyProps> = ({
@@ -4,9 +4,9 @@ import {
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import { THIRDWEB_API_HOST } from "constants/urls";
import type { ChainMetadata } from "thirdweb/chains";
import invariant from "tiny-invariant";
import { THIRDWEB_API_HOST } from "../../../constants/urls";
import { accountKeys, apiKeys, authorizedWallets } from "../cache-keys";
import { useMutationWithInvalidate } from "./query/useQueryWithNetwork";
import { useLoggedInUser } from "./useLoggedInUser";
@@ -913,12 +913,7 @@ export function useAuthorizedWallets() {
export async function fetchChainsFromApi() {
// always fetch from prod for chains for now
// TODO: re-visit this
const res = await fetch("https://api.thirdweb.com/v1/chains", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
const res = await fetch("https://api.thirdweb.com/v1/chains");
const json = await res.json();
if (json.error) {
@@ -1,110 +1,73 @@
import {
type ContractWithRoles,
type RolesForContract,
useContractType,
useRoleMembers,
} from "@thirdweb-dev/react";
import type { ValidContractInstance } from "@thirdweb-dev/sdk";
import { ZERO_ADDRESS } from "thirdweb";
import { useActiveAccount } from "thirdweb/react";
import { type ThirdwebContract, ZERO_ADDRESS } from "thirdweb";
import { hasRole } from "thirdweb/extensions/permissions";
import { useActiveAccount, useReadContract } from "thirdweb/react";
import type { RequiredParam } from "utils/types";
function isContractWithRoles(
contract: RequiredParam<ValidContractInstance>,
): contract is ContractWithRoles {
if (contract && "roles" in contract) {
return true;
}
return false;
}
function useIsAccountRole<TContract extends ContractWithRoles>(
role: RolesForContract<TContract>[number],
contract: RequiredParam<TContract>,
account: RequiredParam<string>,
): boolean {
const contractHasRoles = isContractWithRoles(contract);
const { data } = useRoleMembers(contract, role);
if (contractHasRoles === false) {
return false;
}
if (data?.includes(ZERO_ADDRESS)) {
return true;
}
return !!(account && data?.includes(account));
}
export function useIsAdmin<TContract extends ValidContractInstance>(
contract: RequiredParam<TContract>,
) {
export function useIsAdmin(contract: ThirdwebContract) {
const address = useActiveAccount()?.address;
const { data: contractType } = useContractType(contract?.getAddress());
const { data: userIsAdmin, isError } = useReadContract(hasRole, {
contract,
targetAccountAddress: address ?? "",
role: "admin",
queryOptions: { enabled: !!address },
});
const contractHasRoles = isContractWithRoles(contract);
const isAccountRole = useIsAccountRole(
"admin",
contractHasRoles ? contract : undefined,
address,
);
if (contractType === "custom") {
return true;
}
return isAccountRole;
// If the request results in an error, it's likely that the contract is a non-thirdweb contract
// in that case we return `true` anyway
return userIsAdmin || isError;
}
export function useIsAdminOrSelf<TContract extends ValidContractInstance>(
contract: RequiredParam<TContract>,
export function useIsAdminOrSelf(
contract: ThirdwebContract,
self: RequiredParam<string>,
) {
const address = useActiveAccount()?.address;
const { data: contractType } = useContractType(contract?.getAddress());
const isAdmin = useIsAdmin(contract);
if (address === self) {
return true;
}
if (contractType === "custom") {
return true;
}
return isAdmin;
}
export function useIsMinter<TContract extends ValidContractInstance>(
contract: RequiredParam<TContract>,
) {
export function useIsMinter(contract: ThirdwebContract) {
const address = useActiveAccount()?.address;
const { data: contractType } = useContractType(contract?.getAddress());
const contractHasRoles = isContractWithRoles(contract);
const isAccountRole = useIsAccountRole(
"minter",
contractHasRoles ? contract : undefined,
address,
);
const userCanMintQuery = useReadContract(hasRole, {
contract,
targetAccountAddress: address ?? "",
role: "minter",
queryOptions: { enabled: !!address },
});
if (contractType === "custom") {
return true;
}
return isAccountRole;
const anyoneCanMintQuery = useReadContract(hasRole, {
contract,
targetAccountAddress: ZERO_ADDRESS,
role: "minter",
});
// If both requests "error out", we can safely assume that
// this is a custom (aka. non-thirdweb) contract
// so we just return `true` in that case
const isCustomContract =
userCanMintQuery.isError && anyoneCanMintQuery.isError;
return anyoneCanMintQuery.data || userCanMintQuery.data || isCustomContract;
}
export function useIsLister<TContract extends ValidContractInstance>(
contract: RequiredParam<TContract>,
) {
// Applicable to Marketplace v3 only
export function useIsLister(contract: ThirdwebContract) {
const address = useActiveAccount()?.address;
const { data: contractType } = useContractType(contract?.getAddress());
const contractHasRoles = isContractWithRoles(contract);
const isAccountRole = useIsAccountRole(
"lister",
contractHasRoles ? contract : undefined,
address,
);
const { data: userCanList } = useReadContract(hasRole, {
contract,
targetAccountAddress: address ?? "",
role: "lister",
queryOptions: { enabled: !!address },
});
if (contractType === "custom") {
return true;
}
return isAccountRole;
const { data: anyoneCanList } = useReadContract(hasRole, {
contract,
targetAccountAddress: ZERO_ADDRESS,
role: "lister",
});
return anyoneCanList || userCanList;
}
@@ -0,0 +1,54 @@
import { useQuery } from "@tanstack/react-query";
import type { ThirdwebContract } from "thirdweb";
import { getCompilerMetadata } from "thirdweb/contract";
import { getContractMetadata, name, symbol } from "thirdweb/extensions/common";
/**
* Fetch the contract metadata for Dashboard
*
* If the contract itself doesn't implement the metadata extension,
* we try to fall back to:
* 1. name(), symbol()
* 2. our API endpoint
*/
export function useDashboardContractMetadata(contract: ThirdwebContract) {
return useQuery(
["contract-metadata-header", contract.chain.id, contract.address],
async () => {
const [contractMetadata, _name, _symbol, compilerMetadata] =
await Promise.all([
getContractMetadata({ contract }).catch(() => ({
image: "",
name: "",
symbol: "",
})),
name({ contract }).catch(() => ""),
symbol({ contract }).catch(() => ""),
getCompilerMetadata(contract).catch(() => undefined),
]);
/**
* Handle the case where the contract.thirdweb.com endpoint returns a very long name
* example url: https://contract.thirdweb.com/metadata/324/0x66E298335c5992d599132582De8eaAF75348e6e6
* In that case, we split the solidity name on ":" and take the second part
*/
if (compilerMetadata?.name.includes(":")) {
const _name = compilerMetadata.name.split(":")[1];
if (_name) {
compilerMetadata.name = compilerMetadata.name.split(":")[1];
}
}
const contractName =
contractMetadata?.name || _name || compilerMetadata?.name || "";
const contractSymbol = contractMetadata?.symbol || _symbol || "";
return {
name: contractName,
symbol: contractSymbol,
image: contractMetadata.image || "",
contractType: compilerMetadata?.name || "",
};
},
);
}
@@ -0,0 +1,26 @@
import { thirdwebClient } from "@/constants/client";
import { useMutation } from "@tanstack/react-query";
import { upload } from "thirdweb/storage";
type DashboardUploadOptions = {
uploadWithoutDirectory?: boolean;
metadata?: Record<string, string>;
};
export function useDashboardStorageUpload(options?: DashboardUploadOptions) {
return useMutation({
mutationFn: async (files: Array<File | string>): Promise<string[]> => {
const uris = await upload({
client: thirdwebClient,
files,
...options,
});
// the upload method in SDK v5 has this logic
// that will make it return only a string if you upload only 1 file
if (typeof uris === "string") {
return [uris];
}
return uris;
},
});
}
@@ -1,9 +1,9 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { ResultItem } from "components/engine/system-metrics/components/StatusCodes";
import { THIRDWEB_API_HOST } from "constants/urls";
import { useState } from "react";
import { useActiveAccount, useActiveWalletChain } from "thirdweb/react";
import invariant from "tiny-invariant";
import type { ResultItem } from "../../../components/engine/system-metrics/components/StatusCodes";
import { engineKeys } from "../cache-keys";
import { useMutationWithInvalidate } from "./query/useQueryWithNetwork";
import { useLoggedInUser } from "./useLoggedInUser";
@@ -126,9 +126,9 @@ export function useEngineSystemHealth(
instanceUrl: string,
pollInterval: number | false = false,
) {
return useQuery(
engineKeys.health(instanceUrl),
async () => {
return useQuery({
queryKey: engineKeys.health(instanceUrl),
queryFn: async () => {
const res = await fetch(`${instanceUrl}system/health`, {
headers: getEngineRequestHeaders(null),
});
@@ -138,23 +138,57 @@ export function useEngineSystemHealth(
const json = (await res.json()) as EngineSystemHealth;
return json;
},
{
enabled: !!instanceUrl,
refetchInterval: pollInterval,
enabled: !!instanceUrl,
refetchInterval: pollInterval,
});
}
export interface EngineSystemQueueMetrics {
result: {
queued: number;
pending: number;
latency?: {
msToSend: { p50: number; p90: number };
msToMine: { p50: number; p90: number };
};
};
}
export function useEngineQueueMetrics(
instanceUrl: string,
pollInterval: number | false = false,
) {
const token = useLoggedInUser().user?.jwt ?? null;
return useQuery({
queryKey: engineKeys.queueMetrics(instanceUrl),
queryFn: async () => {
const res = await fetch(`${instanceUrl}system/queue`, {
headers: getEngineRequestHeaders(token),
});
if (!res.ok) {
throw new Error(`Unexpected status ${res.status}: ${await res.text()}`);
}
return (await res.json()) as EngineSystemQueueMetrics;
},
);
enabled: !!instanceUrl && !!token,
refetchInterval: pollInterval,
});
}
export function useEngineLatestVersion() {
return useQuery(engineKeys.latestVersion(), async () => {
const res = await fetch(`${THIRDWEB_API_HOST}/v1/engine/latest-version`, {
method: "GET",
});
if (!res.ok) {
throw new Error(`Unexpected status ${res.status}: ${await res.text()}`);
}
const json = await res.json();
return json.data.version as string;
return useQuery({
queryKey: engineKeys.latestVersion(),
queryFn: async () => {
const res = await fetch(`${THIRDWEB_API_HOST}/v1/engine/latest-version`, {
method: "GET",
});
if (!res.ok) {
throw new Error(`Unexpected status ${res.status}: ${await res.text()}`);
}
const json = await res.json();
return json.data.version as string;
},
});
}
@@ -1462,11 +1496,11 @@ export interface EngineResourceMetrics {
};
}
export function useEngineResourceMetrics(engineId: string) {
export function useEngineSystemMetrics(engineId: string) {
const [enabled, setEnabled] = useState(true);
return useQuery(
engineKeys.metrics(engineId),
engineKeys.systemMetrics(engineId),
async () => {
const res = await fetch(
`${THIRDWEB_API_HOST}/v1/engine/${engineId}/metrics`,
@@ -1,7 +1,7 @@
import { useSupportedChains } from "@thirdweb-dev/react";
import { useFavouriteChainIds } from "app/(dashboard)/(chain)/components/client/star-button";
import { useMemo } from "react";
import type { ChainMetadata } from "thirdweb/chains";
import { useFavouriteChainIds } from "../../../app/(dashboard)/(chain)/components/client/star-button";
export function useFavoriteChains() {
const allChains = useSupportedChains();
@@ -1,12 +1,12 @@
import { LOGGED_IN_ONLY_PATHS } from "@/constants/auth";
import { isLoginRequired } from "@/constants/auth";
import { useQuery } from "@tanstack/react-query";
import type { EnsureLoginResponse } from "app/api/auth/ensure-login/route";
import { usePathname, useRouter } from "next/navigation";
import { useRef } from "react";
import {
useActiveAccount,
useActiveWalletConnectionStatus,
} from "thirdweb/react";
import type { EnsureLoginResponse } from "../../../app/api/auth/ensure-login/route";
// define "TW_AUTH_TOKEN" to exist on the window object
declare global {
@@ -35,12 +35,12 @@ export function useLoggedInUser(): {
// enabled if:
// - there is a pathname
// - we are not already currently connecting
// - the pathname is one of the LOGGED_IN_ONLY_PATHS
// - the pathname requires login
enabled:
!!pathname &&
connectionStatus !== "connecting" &&
statusWasEverConnecting.current &&
LOGGED_IN_ONLY_PATHS.some((path) => pathname.startsWith(path)),
isLoginRequired(pathname),
// the last "persist", part of the queryKey, is to make sure that we do not cache this query in indexDB
// convention in v4 of the SDK that we are (ab)using here
queryKey: ["logged_in_user", connectedAddress, { persist: false }],
@@ -113,7 +113,7 @@ export function useLoggedInUser(): {
}
// if we are not on a logged in path, we can simply return the connected address
if (!LOGGED_IN_ONLY_PATHS.some((path) => pathname.startsWith(path))) {
if (!isLoginRequired(pathname)) {
return {
isLoading: false,
isLoggedIn: true,
@@ -8,8 +8,8 @@ import type { BasicContract } from "contract-ui/types/types";
import { getAllMultichainRegistry } from "dashboard-extensions/common/read/getAllMultichainRegistry";
import { useAllChainsData } from "hooks/chains/allChains";
import { useSupportedChainsRecord } from "hooks/chains/configureChains";
import { defineDashboardChain } from "lib/defineDashboardChain";
import { thirdwebClient } from "lib/thirdweb-client";
import { defineDashboardChain } from "lib/v5-adapter";
import { useMemo } from "react";
import { getContract } from "thirdweb";
import { polygon } from "thirdweb/chains";
@@ -22,7 +22,8 @@ const MULTICHAIN_REGISTRY_ADDRESS =
const registryContract = getContract({
client: thirdwebClient,
address: MULTICHAIN_REGISTRY_ADDRESS,
chain: defineDashboardChain(polygon.id),
// eslint-disable-next-line no-restricted-syntax
chain: defineDashboardChain(polygon.id, undefined),
});
function useMultiChainRegContractList(walletAddress?: string) {
@@ -1,29 +1,21 @@
import { useToast } from "@chakra-ui/react";
import { useSDKChainId } from "@thirdweb-dev/react";
import type { Split } from "@thirdweb-dev/sdk";
import type {
BalanceQueryRequest,
BalanceQueryResponse,
} from "pages/api/moralis/balances";
import { toast } from "sonner";
import type { ThirdwebContract } from "thirdweb";
import { distribute, distributeByToken } from "thirdweb/extensions/split";
import { useSendAndConfirmTransaction } from "thirdweb/react";
import invariant from "tiny-invariant";
import { parseErrorToMessage } from "utils/errorParser";
import { splitsKeys } from "..";
import {
useMutationWithInvalidate,
useQueryWithNetwork,
} from "./query/useQueryWithNetwork";
export function useSplitData(contract?: Split) {
return useQueryWithNetwork(
splitsKeys.list(contract?.getAddress()),
async () => contract?.getAllRecipients(),
{
enabled: !!contract,
},
);
}
export function useSplitBalances(contractAddress?: string) {
const chainId = useSDKChainId();
export function useSplitBalances(contract: ThirdwebContract) {
const chainId = contract.chain.id;
const contractAddress = contract.address;
const currencies = useQueryWithNetwork(
splitsKeys.currencies(contractAddress),
async () => {
@@ -48,72 +40,31 @@ export function useSplitBalances(contractAddress?: string) {
return currencies;
}
export function useSplitDistributeFunds(contract?: Split) {
const contractAddress = contract?.getAddress();
const balances = useSplitBalances(contractAddress);
const toast = useToast();
export function useSplitDistributeFunds(contract: ThirdwebContract) {
const contractAddress = contract.address;
const balances = useSplitBalances(contract);
const { mutateAsync } = useSendAndConfirmTransaction();
return useMutationWithInvalidate(
async () => {
invariant(contract, "split contract is not ready");
invariant(balances.data, "No balances to distribute");
const distributions = (balances.data || [])
.filter((token) => token.display_balance !== "0.0")
.map(async (currency) => {
if (currency.name === "Native Token") {
await contract
.distribute()
.then(() => {
toast({
position: "bottom",
variant: "solid",
title: "Success",
description: `Successfully distributed ${currency.name}`,
status: "success",
duration: 5000,
isClosable: true,
const transaction =
currency.name === "Native Token"
? distribute({ contract })
: distributeByToken({
contract,
tokenAddress: currency.token_address,
});
return void 0;
})
.catch((err: unknown) => {
toast({
position: "bottom",
variant: "solid",
title: `Error distributing ${currency.name}`,
description: parseErrorToMessage(err),
status: "error",
duration: 9000,
isClosable: true,
});
});
} else {
await contract
.distributeToken(currency.token_address)
.then(() => {
toast({
position: "bottom",
variant: "solid",
title: "Success",
description: `Successfully distributed ${currency.name}`,
status: "success",
duration: 5000,
isClosable: true,
});
return void 0;
})
.catch((err: unknown) => {
toast({
position: "bottom",
variant: "solid",
title: `Error distributing ${currency.name}`,
description: parseErrorToMessage(err),
status: "error",
duration: 9000,
isClosable: true,
});
});
}
const promise = mutateAsync(transaction);
toast.promise(promise, {
success: `Successfully distributed ${currency.name}`,
error: `Error distributing ${currency.name}`,
loading: "Distributing funds",
});
});
return await Promise.all(distributions);
@@ -1,59 +0,0 @@
import { redirect } from "next/navigation";
import { getChain } from "../../../utils";
import { InfoCard } from "../components/server/info-card";
export default async function Page(props: { params: { chain_id: string } }) {
const chain = await getChain(props.params.chain_id);
const enabled = chain.services.find(
(s) => s.service === "account-abstraction",
)?.enabled;
if (!enabled) {
redirect(`/${props.params.chain_id}`);
}
return (
<div>
<InfoCard
title="Account Abstraction"
links={[
{
label: "Get Started",
href: "/dashboard/connect/account-abstraction",
},
{
label: "Learn More",
href: "https://portal.thirdweb.com/connect/account-abstraction/how-it-works",
},
]}
>
<p>
Everything you need to leverage account abstraction technology to
enable seamless user experiences for your users.
</p>
<p>
You get all the tools to integrate account abstraction into your app.
This includes:
</p>
<div className="h-3" />
<ul className="text-secondary-foreground pl-4 [&_li]:list-disc [&_li]:mb-3 [&_li]:pl-1">
<li>
Account factory contracts that let you spin up smart accounts for
your users
</li>
<li>
Bundler, which is the infrastructure needed to process account
abstraction transactions (known as User Ops)
</li>
<li>
Paymaster, which lets you sponsor transaction fees for your users
</li>
</ul>
</InfoCard>
</div>
);
}
@@ -0,0 +1,195 @@
"use client";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Button } from "@/components/ui/button";
import { THIRDWEB_ENGINE_FAUCET_WALLET } from "@/constants/env";
import { CustomConnectWallet } from "@3rdweb-sdk/react/components/connect-wallet";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { CanClaimResponseType } from "app/api/testnet-faucet/can-claim/CanClaimResponseType";
import { mapV4ChainToV5Chain } from "contexts/map-chains";
import { useTrack } from "hooks/analytics/useTrack";
import { thirdwebClient } from "lib/thirdweb-client";
import { toast } from "sonner";
import { toUnits } from "thirdweb";
import type { ChainMetadata } from "thirdweb/chains";
import { useActiveAccount, useWalletBalance } from "thirdweb/react";
function formatTime(seconds: number) {
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
if (hours > 0) {
return rtf.format(+hours, "hour");
}
if (minutes > 0) {
return rtf.format(+minutes, "minute");
}
return rtf.format(+seconds, "second");
}
export function FaucetButton({
chain,
amount,
}: {
chain: ChainMetadata;
amount: string;
}) {
const address = useActiveAccount()?.address;
const chainId = chain.chainId;
// do not include local overrides for chain pages
// eslint-disable-next-line no-restricted-syntax
const definedChain = mapV4ChainToV5Chain(chain);
const faucetWalletBalanceQuery = useWalletBalance({
address: THIRDWEB_ENGINE_FAUCET_WALLET,
chain: definedChain,
client: thirdwebClient,
});
const trackEvent = useTrack();
const queryClient = useQueryClient();
const claimMutation = useMutation({
mutationFn: async () => {
trackEvent({
category: "faucet",
action: "claim",
label: "attempt",
chain_id: chainId,
});
const response = await fetch("/api/testnet-faucet/claim", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
chainId: chainId,
toAddress: address,
}),
});
if (!response.ok) {
const data = await response.json();
throw new Error(data?.error || "Failed to claim funds");
}
},
onSuccess: () => {
trackEvent({
category: "faucet",
action: "claim",
label: "success",
chain_id: chainId,
});
},
onError: (error) => {
trackEvent({
category: "faucet",
action: "claim",
label: "error",
chain_id: chainId,
errorMsg: error instanceof Error ? error.message : "Unknown error",
});
},
onSettled: () => {
return queryClient.invalidateQueries([
"testnet-faucet-can-claim",
chainId,
]);
},
});
const canClaimFaucetQuery = useQuery({
queryKey: ["testnet-faucet-can-claim", chainId],
queryFn: async () => {
const response = await fetch(
`/api/testnet-faucet/can-claim?chainId=${chainId}`,
);
if (!response.ok) {
throw new Error("Failed to get claim status");
}
const data = (await response.json()) as CanClaimResponseType;
return data;
},
});
const isFaucetEmpty =
faucetWalletBalanceQuery.data !== undefined &&
faucetWalletBalanceQuery.data.value < toUnits("1", 17);
// loading state
if (faucetWalletBalanceQuery.isLoading || canClaimFaucetQuery.isLoading) {
return (
<Button variant="secondary" className="w-full gap-2">
Checking Faucet <Spinner className="size-3" />
</Button>
);
}
// faucet is empty
if (isFaucetEmpty) {
return (
<Button variant="secondary" disabled className="w-full !opacity-100 ">
Faucet is empty right now
</Button>
);
}
// Can not claim
if (canClaimFaucetQuery.data && canClaimFaucetQuery.data.canClaim === false) {
return (
<Button variant="secondary" className="w-full !opacity-100 " disabled>
{canClaimFaucetQuery.data.type === "throttle" && (
<>
Your next claim is available{" "}
{formatTime(canClaimFaucetQuery.data.ttlSeconds)}
</>
)}
{canClaimFaucetQuery.data.type === "unsupported-chain" &&
"Faucet is empty right now"}
</Button>
);
}
if (!address) {
return (
<CustomConnectWallet
loginRequired={false}
connectButtonClassName="!w-full !rounded !bg-primary !text-primary-foreground !px-4 !py-2 !text-sm"
/>
);
}
// eligible to claim and faucet has balance
return (
<div className="flex flex-col w-full text-center">
<Button
variant="primary"
className="w-full gap-2"
onClick={() => {
const claimPromise = claimMutation.mutateAsync();
toast.promise(claimPromise, {
success: `${amount} ${chain.nativeCurrency.symbol} sent successfully`,
error: `Failed to claim ${amount} ${chain.nativeCurrency.symbol}`,
});
}}
>
{claimMutation.isLoading ? (
<>
Claiming <Spinner className="size-3" />
</>
) : (
`Get ${amount} ${chain.nativeCurrency.symbol}`
)}
</Button>
{faucetWalletBalanceQuery.data && (
<p className="mt-3 text-xs text-secondary-foreground">
{Number(faucetWalletBalanceQuery.data.displayValue).toFixed(3)}{" "}
{faucetWalletBalanceQuery.data.symbol} left in the faucet
</p>
)}
</div>
);
}
@@ -0,0 +1,84 @@
"use client";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
import { thirdwebClient } from "@/constants/client";
import { useTrack } from "hooks/analytics/useTrack";
import { defineDashboardChain } from "lib/defineDashboardChain";
import { useTheme } from "next-themes";
import { PayEmbed } from "thirdweb/react";
import { getSDKTheme } from "../../../../../../components/sdk-component-theme";
export function PayModalButton(props: { chainId: number; label: string }) {
const { theme } = useTheme();
const trackEvent = useTrack();
return (
<Dialog>
<DialogTrigger asChild>
<Button
variant="primary"
className="w-full"
onClick={() => {
trackEvent({
category: "pay",
action: "buy",
label: "attempt",
});
}}
>
{props.label}
</Button>
</DialogTrigger>
<DialogContent
className="md:max-w-[360px] p-0 border-none bg-transparent"
dialogOverlayClassName="backdrop-blur-lg"
dialogCloseClassName="focus:ring-0"
>
<PayEmbed
client={thirdwebClient}
theme={getSDKTheme(theme === "dark" ? "dark" : "light")}
className="!w-auto"
payOptions={{
onPurchaseSuccess(info) {
if (
info.type === "crypto" &&
info.status.status !== "NOT_FOUND"
) {
trackEvent({
category: "pay",
action: "buy",
label: "success",
type: info.type,
chainId: info.status.quote.toToken.chainId,
tokenAddress: info.status.quote.toToken.tokenAddress,
amount: info.status.quote.toAmount,
});
}
if (info.type === "fiat" && info.status.status !== "NOT_FOUND") {
trackEvent({
category: "pay",
action: "buy",
label: "success",
type: info.type,
chainId: info.status.quote.toToken.chainId,
tokenAddress: info.status.quote.toToken.tokenAddress,
amount: info.status.quote.estimatedToTokenAmount,
});
}
},
prefillBuy: {
// Do not include local chain overrides for chain pages
// eslint-disable-next-line no-restricted-syntax
chain: defineDashboardChain(props.chainId, undefined),
allowEdits: {
chain: false,
amount: true,
token: true,
},
},
}}
/>
</DialogContent>
</Dialog>
);
}
@@ -3,8 +3,9 @@
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Button } from "@/components/ui/button";
import { ToolTipLabel } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { useCustomConnectModal } from "@3rdweb-sdk/react/components/connect-wallet";
import { useMutation } from "@tanstack/react-query";
import { toast } from "sonner";
import type { Chain } from "thirdweb";
import {
useActiveAccount,
@@ -14,56 +15,54 @@ import {
import { useDebounce } from "use-debounce";
type AddChainToWalletProps = {
chain?: Chain;
hasBackground?: boolean;
chain: Chain;
};
export const AddChainToWallet: React.FC<AddChainToWalletProps> = (props) => {
const address = useActiveAccount()?.address;
const account = useActiveAccount();
const switchChain = useSwitchActiveWalletChain();
const activeWalletChainId = useActiveWalletChain()?.id;
const customConnectModal = useCustomConnectModal();
const switchChainMutation = useMutation({
mutationFn: async () => {
if (!props.chain) {
throw new Error("Chain is not defined");
}
await switchChain(props.chain);
},
});
// debounce the loading state to prevent flickering
const [debouncedLoading] = useDebounce(switchChainMutation.isLoading, 50);
const buttonContent = (
<Button
disabled={
!address || debouncedLoading || activeWalletChainId === props.chain?.id
}
className={cn(
"w-full md:min-w-40 gap-2",
props.hasBackground && "invert dark:invert-0",
)}
onClick={() => switchChainMutation.mutate()}
>
<span>Add to wallet</span>
{debouncedLoading && <Spinner className="size-3" />}
</Button>
);
if (address && activeWalletChainId !== props.chain?.id) {
return buttonContent;
}
const disabled = debouncedLoading || activeWalletChainId === props.chain?.id;
return (
<ToolTipLabel
label={
activeWalletChainId === props.chain?.id
? "You are already connected to this chain"
: "Connect your wallet first"
activeWalletChainId === props.chain.id
? "Wallet is already connected to this chain"
: undefined
}
>
<div className="cursor-not-allowed">{buttonContent}</div>
<Button
disabled={disabled}
className="gap-2 w-full"
variant="outline"
onClick={() => {
// Connct directly to this chain
if (!account) {
return customConnectModal({ chain: props.chain });
}
// switch to this chain
const switchPromise = switchChainMutation.mutateAsync();
toast.promise(switchPromise, {
success: `${props.chain.name} added to wallet`,
error: `Failed to add ${props.chain.name} to wallet`,
});
}}
>
<span>Add to wallet</span>
{debouncedLoading && <Spinner className="size-3" />}
</Button>
</ToolTipLabel>
);
};
@@ -1,6 +1,6 @@
"use client";
import { CopyButton } from "@/components/ui/CopyButton";
import { CopyTextButton } from "@/components/ui/CopyTextButton";
import { Skeleton } from "@/components/ui/skeleton";
import { ToolTipLabel } from "@/components/ui/tooltip";
import { useQuery } from "@tanstack/react-query";
@@ -9,7 +9,7 @@ import { thirdwebClient } from "lib/thirdweb-client";
import { CircleCheck, XIcon } from "lucide-react";
import { useState } from "react";
import { hostnameEndsWith } from "utils/url";
import { PrimaryInfoItem } from "../../../components/server/primary-info-item";
import { PrimaryInfoItem } from "../server/primary-info-item";
function useChainStatswithRPC(_rpcUrl: string) {
const [shouldRefetch, setShouldRefetch] = useState(true);
@@ -79,19 +79,24 @@ export function ChainLiveStats(props: { rpc: string }) {
}
>
<div className="flex items-center gap-1">
<div className="text-lg">{new URL(props.rpc).origin}</div>
<CopyButton text={new URL(props.rpc).origin} />
<CopyTextButton
tooltip="Copy RPC URL"
textToShow={new URL(props.rpc).origin}
textToCopy={props.rpc}
copyIconPosition="right"
variant="ghost"
className="px-2 py-1 -translate-x-2 text-base"
iconClassName="size-4"
/>
</div>
</PrimaryInfoItem>
{/* Latency */}
<PrimaryInfoItem title="RPC Latency" titleIcon={<PulseDot />}>
{stats.isError ? (
<p className="text-lg fade-in-0 animate-in text-destructive-text">
N/A
</p>
<p className="fade-in-0 animate-in text-destructive-text">N/A</p>
) : stats.data ? (
<p className="text-lg fade-in-0 animate-in">{stats.data.latency}ms</p>
<p className="fade-in-0 animate-in">{stats.data.latency}ms</p>
) : (
<div className="flex py-1 h-[28px] w-[70px]">
<Skeleton className="h-full w-full" />
@@ -102,13 +107,9 @@ export function ChainLiveStats(props: { rpc: string }) {
{/* Block Height */}
<PrimaryInfoItem title="Block Height" titleIcon={<PulseDot />}>
{stats.isError ? (
<p className="text-lg fade-in-0 animate-in text-destructive-text">
N/A
</p>
<p className="fade-in-0 animate-in text-destructive-text">N/A</p>
) : stats.data ? (
<p className="text-lg fade-in-0 animate-in">
{stats.data.blockNumber}
</p>
<p className="fade-in-0 animate-in">{stats.data.blockNumber}</p>
) : (
<div className="flex py-1 h-[28px] w-[140px]">
<Skeleton className="h-full w-full" />
@@ -122,9 +123,9 @@ export function ChainLiveStats(props: { rpc: string }) {
function PulseDot() {
return (
<ToolTipLabel label={"Live Data"}>
<span className="relative flex size-3">
<span className="relative flex size-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-sky-400 opacity-75" />
<span className="relative inline-flex rounded-full size-3 bg-primary" />
<span className="relative inline-flex rounded-full size-2 bg-primary" />
</span>
</ToolTipLabel>
);
@@ -1,50 +0,0 @@
"use client";
import { TabLinks } from "@/components/ui/tabs";
import { useSelectedLayoutSegment } from "next/navigation";
import { useMemo } from "react";
import { products } from "../../../../components/server/products";
import type { ChainSupportedService } from "../../../../types/chain";
export function getEnabledTabs(enabledServices: ChainSupportedService[]) {
return products
.map((p) => ({
name: p.name,
segment: p.id === "contracts" ? "" : p.id,
serviceId: p.id,
icon: p.icon,
isEnabled: enabledServices.includes(p.id) ?? false,
}))
.sort((a, b) => {
if (a.isEnabled && !b.isEnabled) {
return -1;
}
if (!a.isEnabled && b.isEnabled) {
return 1;
}
return 0;
});
}
export function ChainPageTabs(props: {
chainSlug: string;
enabledServices: ChainSupportedService[];
}) {
const layoutSegment = useSelectedLayoutSegment() || "";
const links = useMemo(() => {
return getEnabledTabs(props.enabledServices);
}, [props.enabledServices]);
return (
<TabLinks
links={links.map((tab) => ({
name: tab.name,
href: `/${props.chainSlug}/${tab.segment}`,
isActive: layoutSegment === tab.segment,
isEnabled: tab.isEnabled,
icon: tab.icon,
}))}
/>
);
}
@@ -0,0 +1,89 @@
export function CreditCardIcon(props: {
bg: string;
className?: string;
}) {
return (
<svg
width={48}
height={48}
viewBox="0 0 48 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
className={props.className}
>
<rect width={48} height={48} rx={16} fill={props.bg} />
<rect
x={1}
y={1}
width={46}
height={46}
rx={15}
stroke="url(#paint0_linear_1315_3638)"
strokeOpacity="0.2"
strokeWidth={2}
/>
<rect x={5} y={5} width={38} height={38} rx={11} fill={props.bg} />
<rect
x={5}
y={5}
width={38}
height={38}
rx={11}
stroke="url(#paint1_linear_1315_3638)"
strokeWidth={2}
/>
<path
d="M32.3337 22.3333H15.667M23.167 25.6666H19.0003M15.667 20.8333L15.667 27.1666C15.667 28.1 15.667 28.5668 15.8486 28.9233C16.0084 29.2369 16.2634 29.4918 16.577 29.6516C16.9335 29.8333 17.4002 29.8333 18.3337 29.8333L29.667 29.8333C30.6004 29.8333 31.0671 29.8333 31.4236 29.6516C31.7372 29.4918 31.9922 29.2369 32.152 28.9233C32.3337 28.5668 32.3337 28.1 32.3337 27.1666V20.8333C32.3337 19.8999 32.3337 19.4332 32.152 19.0766C31.9922 18.763 31.7372 18.5081 31.4236 18.3483C31.0671 18.1666 30.6004 18.1666 29.667 18.1666L18.3337 18.1666C17.4002 18.1666 16.9335 18.1666 16.577 18.3483C16.2634 18.5081 16.0084 18.763 15.8486 19.0766C15.667 19.4332 15.667 19.8999 15.667 20.8333Z"
stroke="url(#paint2_linear_1315_3638)"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<defs>
<linearGradient
id="paint0_linear_1315_3638"
x1="-3.26045"
y1="15.4021"
x2="45.7807"
y2="50.1547"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#F213A4" />
<stop offset="0.1517" stopColor="#E011A7" />
<stop offset="0.4554" stopColor="#B20DAF" />
<stop offset="0.8789" stopColor="#6806BB" />
<stop offset={1} stopColor="#5204BF" />
</linearGradient>
<linearGradient
id="paint1_linear_1315_3638"
x1="1.28296"
y1="16.835"
x2="42.1506"
y2="45.7956"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#F213A4" />
<stop offset="0.1517" stopColor="#E011A7" />
<stop offset="0.4554" stopColor="#B20DAF" />
<stop offset="0.8789" stopColor="#6806BB" />
<stop offset={1} stopColor="#5204BF" />
</linearGradient>
<linearGradient
id="paint2_linear_1315_3638"
x1="14.5349"
y1="21.9102"
x2="27.1676"
y2="34.6989"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#F213A4" />
<stop offset="0.1517" stopColor="#E011A7" />
<stop offset="0.4554" stopColor="#B20DAF" />
<stop offset="0.8789" stopColor="#6806BB" />
<stop offset={1} stopColor="#5204BF" />
</linearGradient>
</defs>
</svg>
);
}
@@ -0,0 +1,98 @@
export function GiftIcon(props: {
bg: string;
className?: string;
}) {
return (
<svg
width={48}
height={48}
viewBox="0 0 48 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<rect width={48} height={48} rx={16} fill={props.bg} />
<rect
x={1}
y={1}
width={46}
height={46}
rx={15}
stroke="url(#paint0_linear_1214_43510)"
strokeOpacity="0.2"
strokeWidth={2}
/>
<rect x={5} y={5} width={38} height={38} rx={11} fill={props.bg} />
<rect
x={5}
y={5}
width={38}
height={38}
rx={11}
stroke="url(#paint1_linear_1214_43510)"
strokeWidth={2}
/>
<g clipPath="url(#clip0_1214_43510)">
<path
d="M23.9993 19.0001V32.3334M23.9993 19.0001H21.0529C20.6188 19.0001 20.2024 18.8245 19.8955 18.5119C19.5885 18.1994 19.416 17.7754 19.416 17.3334C19.416 16.8914 19.5885 16.4675 19.8955 16.1549C20.2024 15.8423 20.6188 15.6667 21.0529 15.6667C23.3446 15.6667 23.9993 19.0001 23.9993 19.0001ZM23.9993 19.0001H26.9458C27.3799 19.0001 27.7963 18.8245 28.1032 18.5119C28.4102 18.1994 28.5827 17.7754 28.5827 17.3334C28.5827 16.8914 28.4102 16.4675 28.1032 16.1549C27.7963 15.8423 27.3799 15.6667 26.9458 15.6667C24.6541 15.6667 23.9993 19.0001 23.9993 19.0001ZM30.666 23.1667V29.6667C30.666 30.6002 30.666 31.0669 30.4844 31.4234C30.3246 31.737 30.0696 31.992 29.756 32.1518C29.3995 32.3334 28.9328 32.3334 27.9993 32.3334L19.9993 32.3334C19.0659 32.3334 18.5992 32.3334 18.2427 32.1518C17.9291 31.992 17.6741 31.737 17.5143 31.4234C17.3327 31.0669 17.3327 30.6002 17.3327 29.6667V23.1667M15.666 20.3334L15.666 21.8334C15.666 22.3001 15.666 22.5335 15.7568 22.7117C15.8367 22.8685 15.9642 22.996 16.121 23.0759C16.2993 23.1667 16.5326 23.1667 16.9993 23.1667L30.9994 23.1667C31.4661 23.1667 31.6994 23.1667 31.8777 23.0759C32.0345 22.996 32.162 22.8685 32.2419 22.7117C32.3327 22.5335 32.3327 22.3001 32.3327 21.8334V20.3334C32.3327 19.8667 32.3327 19.6333 32.2419 19.4551C32.162 19.2983 32.0345 19.1708 31.8777 19.0909C31.6994 19.0001 31.4661 19.0001 30.9993 19.0001L16.9993 19.0001C16.5326 19.0001 16.2993 19.0001 16.121 19.0909C15.9642 19.1708 15.8367 19.2983 15.7568 19.4551C15.666 19.6333 15.666 19.8667 15.666 20.3334Z"
stroke="url(#paint2_linear_1214_43510)"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</g>
<defs>
<linearGradient
id="paint0_linear_1214_43510"
x1="-3.26045"
y1="15.4021"
x2="45.7807"
y2="50.1547"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#F213A4" />
<stop offset="0.1517" stopColor="#E011A7" />
<stop offset="0.4554" stopColor="#B20DAF" />
<stop offset="0.8789" stopColor="#6806BB" />
<stop offset={1} stopColor="#5204BF" />
</linearGradient>
<linearGradient
id="paint1_linear_1214_43510"
x1="1.28296"
y1="16.835"
x2="42.1506"
y2="45.7956"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#F213A4" />
<stop offset="0.1517" stopColor="#E011A7" />
<stop offset="0.4554" stopColor="#B20DAF" />
<stop offset="0.8789" stopColor="#6806BB" />
<stop offset={1} stopColor="#5204BF" />
</linearGradient>
<linearGradient
id="paint2_linear_1214_43510"
x1="14.5339"
y1="21.0147"
x2="31.5621"
y2="33.0816"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#F213A4" />
<stop offset="0.1517" stopColor="#E011A7" />
<stop offset="0.4554" stopColor="#B20DAF" />
<stop offset="0.8789" stopColor="#6806BB" />
<stop offset={1} stopColor="#5204BF" />
</linearGradient>
<clipPath id="clip0_1214_43510">
<rect
width={20}
height={20}
fill="white"
transform="translate(14 14)"
/>
</clipPath>
</defs>
</svg>
);
}
@@ -0,0 +1,61 @@
import { ExternalLinkIcon } from "lucide-react";
import Link from "next/link";
import type { ChainMetadata } from "thirdweb/chains";
import { ChainIcon } from "../../../../components/server/chain-icon";
import { PayModalButton } from "../client/PayModal";
import { CreditCardIcon } from "../icons/CreditCardIcon";
import { SectionTitle } from "./SectionTitle";
export function BuyFundsSection(props: { chain: ChainMetadata }) {
const sanitizedChainName = props.chain.name.replace("Mainnet", "").trim();
return (
<section>
<SectionTitle title="Buy Funds" />
<div className="border border-border px-4 py-10 rounded-lg flex justify-center">
<div className="max-w-[520px] flex flex-col items-center ">
<div className="flex items-center">
<ChainIcon
className="size-12 -mr-2 rounded-full border p-1"
iconUrl={props.chain.icon?.url}
/>
<CreditCardIcon
bg="hsl(var(--background))"
className="size-12 -ml-2"
/>
</div>
<div className="h-6" />
<h2 className="text-lg tracking-tight font-semibold text-center px-4">
Buy Funds on {sanitizedChainName} using thirdweb Pay
</h2>
<div className="h-2" />
<p className="text-secondary-foreground text-sm max-w-[520px] text-center px-4">
Instantly onramp, bridge & swap into {sanitizedChainName} with any
token.
</p>
<div className="h-8" />
<PayModalButton
chainId={props.chain.chainId}
label={`Buy Funds on ${sanitizedChainName}`}
/>
<div className="h-4" />
<Link
href="https://portal.thirdweb.com/connect/pay/overview"
className="inline-flex gap-1.5 items-center text-sm text-secondary-foreground hover:text-foreground"
>
Learn more about thirdweb Pay{" "}
<ExternalLinkIcon className="size-3" />
</Link>
</div>
</div>
</section>
);
}
@@ -0,0 +1,52 @@
import { CopyTextButton } from "@/components/ui/CopyTextButton";
import { ExternalLinkIcon } from "lucide-react";
import Link from "next/link";
import React from "react";
import type { ChainMetadata } from "thirdweb/chains";
import { ChainLiveStats } from "../client/live-stats";
import { SectionTitle } from "./SectionTitle";
import { PrimaryInfoItem } from "./primary-info-item";
export function ChainOverviewSection(props: { chain: ChainMetadata }) {
const { chain } = props;
return (
<section>
<SectionTitle title="Chain Overview" />
<div className="grid grid-cols-1 gap-6 lg:gap-8 md:grid-cols-2 lg:grid-cols-3 border rounded-lg p-4 md:p-6">
{/* Info */}
{chain.infoURL && (
<PrimaryInfoItem title="Info">
<Link
href={chain.infoURL}
target="_blank"
className="inline-flex items-center gap-1.5 hover:text-link-foreground"
>
{new URL(chain.infoURL).hostname}
<ExternalLinkIcon className="size-4" />
</Link>
</PrimaryInfoItem>
)}
{/* Chain Id */}
<PrimaryInfoItem title="Chain ID">
<CopyTextButton
textToCopy={chain.chainId.toString()}
textToShow={chain.chainId.toString()}
tooltip="Copy Chain ID"
variant="ghost"
className="-translate-x-2 py-1 px-2 text-base"
iconClassName="size-4"
copyIconPosition="right"
/>
</PrimaryInfoItem>
{/* Native token */}
<PrimaryInfoItem title="Native Token">
{chain.nativeCurrency.name} ({chain.nativeCurrency.symbol})
</PrimaryInfoItem>
{chain.rpc[0] && <ChainLiveStats rpc={chain.rpc[0]} />}
</div>
</section>
);
}
@@ -0,0 +1,30 @@
import { Button } from "@/components/ui/button";
import { ExternalLinkIcon } from "lucide-react";
import Link from "next/link";
import { SectionTitle } from "./SectionTitle";
export function ClaimChainSection() {
return (
<section>
<SectionTitle title="Claim Chain" />
<div className="border p-4 rounded-lg">
<p className="mb-1"> This chain page is unclaimed </p>
<p className="text-secondary-foreground text-sm mb-5">
Are you the owner of this ecosystem? Claim this page to add additional
information on this page to help your developers get started!
</p>
<Button variant="outline" asChild>
<Link
className="gap-2"
href="https://share.hsforms.com/1o01TyfsZRAao2eCrzuXSVgea58c"
target="_blank"
>
<span>Claim Chain</span>
<ExternalLinkIcon className="size-4 -mt-[3px]" />
</Link>
</Button>
</div>
</section>
);
}
@@ -0,0 +1,48 @@
import type { ChainMetadata } from "thirdweb/chains";
import { ChainIcon } from "../../../../components/server/chain-icon";
import { FaucetButton } from "../client/FaucetButton";
import { GiftIcon } from "../icons/GiftIcon";
import { SectionTitle } from "./SectionTitle";
const amountToGive = "0.01";
export async function FaucetSection(props: { chain: ChainMetadata }) {
const { chain } = props;
// Check eligibilty.
const sanitizedChainName = chain.name.replace("Mainnet", "").trim();
return (
<section>
<SectionTitle title="Faucet" />
<div className="border border-border px-4 py-10 rounded-lg flex justify-center">
<div className="max-w-[520px] w-full flex flex-col items-center ">
<div className="flex items-center">
<ChainIcon
className="size-12 -mr-2 rounded-full border p-1"
iconUrl={props.chain.icon?.url}
/>
<GiftIcon bg="hsl(var(--background))" className="size-12 -ml-2" />
</div>
<div className="h-6" />
<h2 className="text-lg tracking-tight font-semibold text-center px-4">
{sanitizedChainName} Faucet
</h2>
<div className="h-2" />
<p className="text-secondary-foreground text-sm max-w-[520px] text-center px-4">
Get free {chain.nativeCurrency.symbol} fast and reliably.{" "}
{amountToGive} {chain.nativeCurrency.symbol}/day.
</p>
<div className="h-8" />
<FaucetButton chain={chain} amount={amountToGive} />
</div>
</div>
</section>
);
}
@@ -0,0 +1,5 @@
export function SectionTitle(props: { title: string }) {
return (
<h2 className="text-xl tracking-tight mb-2 font-semibold">{props.title}</h2>
);
}
@@ -0,0 +1,53 @@
import { CircleCheckIcon } from "lucide-react";
import Link from "next/link";
import { products } from "../../../../components/server/products";
import type { ChainMetadataWithServices } from "../../../../types/chain";
import { SectionTitle } from "./SectionTitle";
export function SupportedProductsSection(props: {
services: ChainMetadataWithServices["services"];
}) {
const enabledProducts = products.filter((product) => {
return props.services.find(
(service) => service.service === product.id && service.enabled,
);
});
if (enabledProducts.length === 0) {
return null;
}
return (
<section>
<SectionTitle title="thirdweb Products" />
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
{enabledProducts.map((product) => {
return (
<div
key={product.id}
className="border rounded-lg p-4 flex gap-3 relative hover:bg-secondary transition-colors duration-300 pr-8"
>
<CircleCheckIcon className="size-5 text-success-text absolute top-4 right-4" />
<product.icon className="size-5 shrink-0 mt-0.5" />
<div>
<h3 className="font-medium mb-1.5">
<Link
href={product.link}
className="before:absolute before:inset-0"
target="_blank"
>
{" "}
{product.name}{" "}
</Link>
</h3>
<p className="text-sm text-secondary-foreground">
{product.description}
</p>
</div>
</div>
);
})}
</div>
</section>
);
}
@@ -0,0 +1,67 @@
import { AspectRatio } from "@/components/ui/aspect-ratio";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import type { ChainMetadata } from "thirdweb/chains";
import { mapV4ChainToV5Chain } from "../../../../../../../contexts/map-chains";
import { ChainIcon } from "../../../../components/server/chain-icon";
import { AddChainToWallet } from "../client/add-chain-to-wallet";
type ChainHeaderProps = {
headerImageUrl?: string;
logoUrl?: string;
chain: ChainMetadata;
};
// TODO: improve the behavior when clicking "Get started with thirdweb", currently just redirects to the dashboard
export function ChainHeader(props: ChainHeaderProps) {
return (
// force the banner image to be 4:1 aspect ratio and full-width on mobile devices
<div className="flex flex-col">
{!props.headerImageUrl && <div className="h-8 md:hidden" />}
<AspectRatio
ratio={props.headerImageUrl ? 4 : 8}
className="border-b border-border -mx-4 lg:-mx-6"
>
{props.headerImageUrl && (
// eslint-disable-next-line @next/next/no-img-element
<img
src={props.headerImageUrl}
alt=""
className="object-cover object-center h-full w-full"
/>
)}
</AspectRatio>
{/* below header */}
<div className="relative flex flex-row justify-end items-end">
{/* chain logo */}
<ChainIcon
iconUrl={props.logoUrl}
className="p-2 lg:p-4 absolute top-0 left-0 size-20 lg:size-36 rounded-full bg-background -translate-y-[50%] overflow-hidden border border-border"
/>
{/* action group */}
<div className="pt-3 lg:pt-6">
{/* Desktop only */}
<div className="hidden lg:flex flex-row gap-2">
<AddChainToWallet
chain={
// Do not include chain overrides for chain pages
// eslint-disable-next-line no-restricted-syntax
mapV4ChainToV5Chain(props.chain)
}
/>
<Button variant="primary" asChild>
<Link href="https://thirdweb.com/dashboard" target="_blank">
Get started with thirdweb
</Link>
</Button>
</div>
</div>
</div>
</div>
);
}
@@ -11,36 +11,33 @@ export type ChainCTAProps = {
export function ChainCTA(props: ChainCTAProps) {
return (
<div className="container">
<div
className="w-full overflow-hidden rounded-xl shadow-lg bg-cover bg-center bg-no-repeat"
style={{
backgroundImage: `url(${props.backgroundImageUrl})`,
}}
>
<div className="grid items-center justify-center gap-6 bg-gradient-to-r from-accent/0 to-accent/0 p-8 sm:p-12 md:grid-cols-[1fr_auto] md:gap-12 lg:p-16">
<div className="space-y-4 text-center md:text-left">
<h2 className="text-3xl font-bold tracking-tighter text-white sm:text-4xl md:text-5xl">
{props.title}
</h2>
{props.description && (
<p className="max-w-[600px] md:text-lg text-white">
{props.description}
</p>
)}
</div>
<Button asChild size="lg" className="invert dark:invert-0">
<Link
href={props.buttonLink}
prefetch={false}
target={
props.buttonLink.startsWith("http") ? "_blank" : undefined
}
>
{props.buttonText}
</Link>
</Button>
<div
className="bg-cover bg-center bg-no-repeat rounded-xl border border-border overflow-hidden"
style={{
backgroundImage: `url(${props.backgroundImageUrl})`,
}}
>
<div className="grid items-center justify-center gap-6 p-8 md:grid-cols-[1fr_auto] md:gap-12 bg-gradient-to-r from-background to-background/90">
<div className="space-y-4 text-center md:text-left">
<h2 className="text-2xl md:text-3xl font-bold tracking-tighter text-foreground md:max-w-[85%]">
{props.title}
</h2>
{props.description && (
<p className="max-w-[600px] text-secondary-foreground leading-relaxed text-sm md:text-base">
{props.description}
</p>
)}
</div>
<Button asChild>
<Link
href={props.buttonLink}
prefetch={false}
target={props.buttonLink.startsWith("http") ? "_blank" : undefined}
className="font-semibold"
>
{props.buttonText}
</Link>
</Button>
</div>
</div>
);
@@ -1,22 +1,22 @@
import { ExternalLinkIcon } from "lucide-react";
import Link from "next/link";
import type { ChainMetadataWithServices } from "../../../../types/chain";
import { SectionTitle } from "./SectionTitle";
export function ExplorersSection(props: {
explorers: NonNullable<ChainMetadataWithServices["explorers"]>;
}) {
return (
<div>
<h2 className="text-base text-muted-foreground mb-2 font-medium">
Explorers
</h2>
<section>
<SectionTitle title="Explorers" />
<div className="grid grid-cols-1 gap-3 md:gap-4 md:grid-cols-2 lg:grid-cols-3">
{props.explorers.map((explorer) => {
return (
<div
key={explorer.url}
className="p-4 border rounded-xl relative bg-secondary hover:bg-muted"
className="p-4 border rounded-xl relative hover:bg-secondary"
>
<ExternalLinkIcon className="size-4 absolute top-4 right-4 text-muted-foreground" />
<h3 className="mb-1 text-base font-semibold capitalize">
{explorer.name}
</h3>
@@ -29,11 +29,10 @@ export function ExplorersSection(props: {
? explorer.url.slice(0, -1)
: explorer.url}
</Link>
<ExternalLinkIcon className="size-4 absolute top-4 right-4 text-muted-foreground" />
</div>
);
})}
</div>
</div>
</section>
);
}
@@ -1,44 +0,0 @@
import { ExternalLinkIcon } from "lucide-react";
import Link from "next/link";
export function FaucetsSection(props: { faucets: readonly string[] }) {
return (
<div>
<h2 className="text-base text-muted-foreground mb-2 font-medium">
Faucets
</h2>
<div className="grid grid-cols-1 gap-3 md:gap-4 md:grid-cols-2 lg:grid-cols-3">
{props.faucets.map((faucet) => {
const url = new URL(faucet);
const hostnameSplit = url.hostname.split(".");
const tld = hostnameSplit.pop();
const domain = hostnameSplit.pop();
const displayTitle = `${domain}.${tld}`;
let displayUrl = url.port + url.hostname + url.pathname;
displayUrl = displayUrl.endsWith("/")
? displayUrl.slice(0, -1)
: displayUrl;
return (
<div
key={faucet}
className="p-4 border rounded-xl relative bg-secondary hover:bg-muted"
>
<h3 className="mb-1 text-base font-semibold capitalize">
{displayTitle}
</h3>
<Link
href={faucet}
target="_blank"
className="text-sm flex gap-1.5 items-center before:absolute before:inset-0 before:z-0 text-muted-foreground"
>
{displayUrl}
</Link>
<ExternalLinkIcon className="size-4 absolute top-4 right-4 text-muted-foreground" />
</div>
);
})}
</div>
</div>
);
}
@@ -1,41 +0,0 @@
import { Button } from "@/components/ui/button";
import { ExternalLinkIcon } from "lucide-react";
import Link from "next/link";
import type React from "react";
export function InfoCard(props: {
title: string;
links?: { label: string; href: string }[];
children: React.ReactNode;
}) {
return (
<div className="border rounded-xl px-4 py-4 bg-secondary relative">
<h2 className="text-xl font-semibold tracking-tight mb-4">
{props.title}
</h2>
<div className="[&_p]:mb-3 [&_p]:text-secondary-foreground max-w-[1000px]">
{props.children}
</div>
{props.links && (
<div className="flex flex-col lg:flex-row mt-7 gap-3">
{props.links.map((link) => {
return (
<Button asChild variant="outline" key={link.label}>
<Link
href={link.href}
className="items-center gap-2"
target="_blank"
>
{link.label}{" "}
<ExternalLinkIcon className="size-3 text-muted-foreground" />
</Link>
</Button>
);
})}
</div>
)}
</div>
);
}
@@ -4,14 +4,14 @@ export function PrimaryInfoItem(props: {
children: React.ReactNode;
}) {
return (
<section className="border-b pb-4 lg:pb-6">
<div>
<div className="flex items-center gap-2">
<h2 className="text-base text-muted-foreground font-medium">
<h3 className="text-base text-muted-foreground font-medium">
{props.title}
</h2>
</h3>
{props.titleIcon}
</div>
{props.children}
</section>
</div>
);
}
@@ -1,104 +0,0 @@
import Link from "next/link";
import { redirect } from "next/navigation";
import { FaReact } from "react-icons/fa";
import { FaUnity } from "react-icons/fa6";
import { SiDotnet, SiSolidity, SiTypescript } from "react-icons/si";
import { getChain } from "../../../utils";
import { InfoCard } from "../components/server/info-card";
type SDKInfo = {
name: string;
href: string;
icon: React.FC<{ className?: string }>;
};
const sdks: SDKInfo[] = [
{
name: "TypeScript",
href: "https://portal.thirdweb.com/typescript/v5",
icon: SiTypescript,
},
{
name: "React",
href: "https://portal.thirdweb.com/typescript/v5/react",
icon: FaReact,
},
{
name: "React Native",
href: "https://portal.thirdweb.com/typescript/v5/react-native",
icon: FaReact,
},
{
name: "Unity",
href: "https://portal.thirdweb.com/unity",
icon: FaUnity,
},
{
name: "Solidity",
href: "https://portal.thirdweb.com/contracts/build/overview",
icon: SiSolidity,
},
{
name: ".NET SDK",
href: "https://portal.thirdweb.com/dotnet",
icon: SiDotnet,
},
];
export default async function Page(props: { params: { chain_id: string } }) {
const chain = await getChain(props.params.chain_id);
const enabled = chain.services.find(
(s) => s.service === "connect-sdk",
)?.enabled;
if (!enabled) {
redirect(`/${props.params.chain_id}`);
}
return (
<div>
<InfoCard
title="Connect SDK"
links={[
{
label: "Learn More",
href: "https://portal.thirdweb.com/connect",
},
]}
>
<p>
Connect is the complete toolkit for connecting every user to your
application.
</p>
<p>
It features customizable onboarding flows, self-custodial in-app
wallets, account abstraction, onramps, and more.
</p>
</InfoCard>
<div className="h-10" />
<h3 className="text-foreground text-3xl tracking-tighter font-semibold">
Get Started
</h3>
<div className="h-3" />
<div className="grid gap-3 md:gap-4 grid-cols-1 md:grid-cols-3 lg:grid-cols-4">
{sdks.map((sdk) => {
return (
<Link
key={sdk.name}
href={sdk.href}
target="_blank"
className="border p-4 bg-secondary rounded-lg hover:bg-muted font-medium flex items-center gap-3"
>
<sdk.icon className="size-5 text-muted-foreground" />
{sdk.name}
</Link>
);
})}
</div>
</div>
);
}
@@ -1,35 +0,0 @@
import { redirect } from "next/navigation";
import { getChain } from "../../../utils";
import { InfoCard } from "../components/server/info-card";
export default async function Page(props: { params: { chain_id: string } }) {
const chain = await getChain(props.params.chain_id);
const enabled = chain.services.find((s) => s.service === "engine")?.enabled;
if (!enabled) {
redirect(`/${props.params.chain_id}`);
}
return (
<div>
<InfoCard
title="thirdweb Engine"
links={[
{
label: "Setup Engine Instance",
href: "/dashboard/engine",
},
{
label: "Learn More",
href: "https://portal.thirdweb.com/engine",
},
]}
>
<p>
thirdweb Engine is a backend HTTP server that reads, writes, and
deploys contracts at production scale.
</p>
</InfoCard>
</div>
);
}
@@ -1,205 +0,0 @@
"use client";
import { CopyTextButton } from "@/components/ui/CopyTextButton";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Skeleton } from "@/components/ui/skeleton";
import { THIRDWEB_ENGINE_FAUCET_WALLET } from "@/constants/env";
import { CustomConnectWallet } from "@3rdweb-sdk/react/components/connect-wallet";
import { useMutation } from "@tanstack/react-query";
import type { ChainMetadataWithServices } from "app/(dashboard)/(chain)/types/chain";
import { thirdwebClient } from "lib/thirdweb-client";
import { useRouter } from "next/navigation";
import Confetti from "react-confetti";
import { toast } from "sonner";
import { type ISpinWheelProps, SpinWheel } from "spin-wheel-game";
import { defineChain, toUnits } from "thirdweb";
import { useActiveAccount, useWalletBalance } from "thirdweb/react";
const segments = [
{ segmentText: "Come back tomorrow", segColor: "#f771c9" }, // Mid-dark, optimized for dark mode
{ segmentText: "0.1", segColor: "#f65ac0" }, // Lightest, optimized for dark mode
{ segmentText: "Come back tomorrow", segColor: "#f542b7" }, // Slightly darker, optimized
{ segmentText: "0.01", segColor: "#f32bae" }, // Mid-light, optimized for dark mode
{ segmentText: "0.05", segColor: "#f213a5" }, // Mid, optimized for dark mode
{ segmentText: "0.01", segColor: "#da1195" }, // Mid-dark, optimized for dark mode
{ segmentText: "0.05", segColor: "#c20f84" }, // Darker, optimized for dark mode
{ segmentText: "0.01", segColor: "#a90d73" }, // Even darker, optimized
{ segmentText: "0.05", segColor: "#910b63" }, // Near darkest, optimized for dark mode
{ segmentText: "0.01", segColor: "#790a53" }, // Lightest, optimized for dark mode
{ segmentText: "0.05", segColor: "#610842" }, // Slightly darker, optimized
{ segmentText: "0.01", segColor: "#490632" }, // Mid-light, optimized for dark mode
];
function formatTime(seconds: number) {
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
if (hours > 0) {
return rtf.format(+hours, "hour");
}
if (minutes > 0) {
return rtf.format(+minutes, "minute");
}
return rtf.format(+seconds, "second");
}
export function TestnetSpinWheel({
chain,
ttlSeconds,
}: {
chain: ChainMetadataWithServices;
ttlSeconds: number;
}) {
const address = useActiveAccount()?.address;
const chainId = chain.chainId;
const definedChain = defineChain(chainId);
const { data: evmBalance, isLoading } = useWalletBalance({
address: THIRDWEB_ENGINE_FAUCET_WALLET,
chain: definedChain,
client: thirdwebClient,
});
const router = useRouter();
const claimMutation = useMutation({
mutationFn: async (result: string) => {
const amount = result === "Come back tomorrow" ? "0.01" : result;
const requestBody = {
chainId: chainId,
toAddress: address,
amount: amount,
};
const response = await fetch("/api/testnet-faucet/claim", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(requestBody),
});
if (!response.ok) {
const error = await response.json();
throw error.error;
}
},
onError: async (error: string) => {
toast.error(error);
},
onSuccess: () => {
router.refresh();
const successMessage =
claimMutation.variables === "Come back tomorrow"
? "You're not lucky today, but don't worry you got 0.01 💜"
: `${claimMutation.variables} ${chain?.nativeCurrency?.name} sent to ${address}`;
toast.success(successMessage);
},
});
const isFaucetEmpty =
evmBalance?.value !== undefined && evmBalance.value < toUnits("1", 17);
const faucetMessage = isFaucetEmpty ? (
<div>
<p>
There is no {chain.nativeCurrency.symbol} available. Please send funds
to the following address:
</p>
<div className="h-2" />
<CopyTextButton
textToCopy={THIRDWEB_ENGINE_FAUCET_WALLET}
textToShow={THIRDWEB_ENGINE_FAUCET_WALLET}
tooltip="Copy"
className="text-lg -translate-x-2 py-0.5"
copyIconPosition="right"
/>
</div>
) : (
<p>You may claim {chain.nativeCurrency.symbol} once every 24 hours.</p>
);
const claimButtonCta =
ttlSeconds > 0
? `Your next claim is available ${formatTime(ttlSeconds)}`
: `Spin for ${chain.nativeCurrency.symbol}`;
const closeButtonCta = ttlSeconds > 0 ? "Done" : "Close";
const spinWheelProps: ISpinWheelProps = {
segments,
onFinished: claimMutation.mutateAsync,
primaryColor: "black",
contrastColor: "white",
buttonText: "💜",
isOnlyOnce: false,
size: 290,
// Used to randomize result.
upDuration: Math.random() * 100 + 100,
downDuration: 600,
arrowLocation: "top",
showTextOnSpin: false,
isSpinSound: false,
};
if (!address) return <CustomConnectWallet />;
return (
<>
{isLoading ? (
<Skeleton className="h-20" />
) : (
<>
<div className="mb-3">{faucetMessage}</div>
<Dialog>
<DialogTrigger asChild>
{!isFaucetEmpty && (
<Button className="min-w-48" disabled={ttlSeconds > 0}>
{claimButtonCta}
</Button>
)}
</DialogTrigger>
<DialogContent className="w-auto h-fit max-w-none">
{claimMutation.isSuccess && (
<Confetti className="w-full h-full" />
)}
<DialogHeader>
<DialogTitle>
Spin to claim {chain.nativeCurrency.symbol} on {chain.name}
</DialogTitle>
<DialogDescription>
<p className="py-2">
Click the wheel to get your claim amount.
</p>
<div className="p-4">
<SpinWheel {...spinWheelProps} />
</div>
</DialogDescription>
</DialogHeader>
<DialogFooter className="flex justify-between">
<DialogClose asChild>
<Button variant="outline">
<span className="text-muted-foreground">
{closeButtonCta}
</span>
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</>
)}
</>
);
}
@@ -1,94 +0,0 @@
import { CopyTextButton } from "@/components/ui/CopyTextButton";
import { THIRDWEB_ENGINE_FAUCET_WALLET } from "@/constants/env";
import { ClientOnly } from "components/ClientOnly/ClientOnly";
import { getIpAddress } from "lib/ip";
import { cacheTtl } from "lib/redis";
import { redirect } from "next/navigation";
import type { Metadata } from "next/types";
import { getChain } from "../../../utils";
import { InfoCard } from "../components/server/info-card";
import { TestnetSpinWheel } from "./components/SpinWheel";
export async function generateMetadata({
params,
}: { params: { chain_id: string } }): Promise<Metadata> {
const chain = await getChain(params.chain_id);
const sanitizedChainName = chain.name.replace("Mainnet", "").trim();
return {
title: `thirdweb ${sanitizedChainName} faucet`,
description: `Get ${chain.nativeCurrency.symbol} testnet funds on ${chain.name}. Powered by thirdweb.`,
};
}
export default async function Page(props: { params: { chain_id: string } }) {
const chain = await getChain(props.params.chain_id);
if (!chain.testnet) {
redirect(`/${props.params.chain_id}`);
}
// Check eligibilty.
const ipAddress = getIpAddress();
const cacheKey = `testnet-faucet:${chain.chainId}:${ipAddress}`;
const ttlSeconds = await cacheTtl(cacheKey);
return (
<>
<div className="items-center">
<h3 className="mb-3 text-lg font-semibold"> Faucet </h3>
<ClientOnly ssr={null}>
<TestnetSpinWheel chain={chain} ttlSeconds={ttlSeconds} />
</ClientOnly>
<div className="h-10" />
<InfoCard title="Resources">
<h3 className="mb-2 text-lg font-semibold">What is a faucet?</h3>
<p>
An testnet faucet is an online service that provides free testnet
currency to web3 app and blockchain developers. This allows them to
experiment with and test smart contracts and decentralized
applications (dApps) on EVM testnets like {chain.name} without using
real cryptocurrency.
</p>
<h2>How often can I claim from the faucet?</h2>
<p>You may claim funds once per testnet chain every 24 hours.</p>
<h3 className="mb-2 text-lg font-semibold">
How can I refill the faucet?
</h3>
<p>Please send funds the following address:</p>
<div>
<CopyTextButton
textToCopy={THIRDWEB_ENGINE_FAUCET_WALLET}
textToShow={THIRDWEB_ENGINE_FAUCET_WALLET}
tooltip="Copy"
copyIconPosition="right"
className="mb-2"
/>
</div>
<h3 className="mb-2 text-lg font-semibold">
How does the faucet work?
</h3>
<p>
When you request testnet funds, a multi-chain backend wallet
transfers a small amount of {chain.nativeCurrency.symbol} on{" "}
{chain.name} with{" "}
<a
href="https://thirdweb.com/engine"
target="_blank"
className="underline"
rel="noreferrer"
>
thirdweb Engine
</a>
.
</p>
</InfoCard>
</div>
</>
);
}
@@ -1,36 +1,23 @@
import { CopyTextButton } from "@/components/ui/CopyTextButton";
import { Badge } from "@/components/ui/badge";
import { BurgerMenuButton } from "@/components/blocks/BurgerMenuButton";
import { Sidebar } from "@/components/blocks/Sidebar";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import { cn } from "@/lib/utils";
import {
ArrowLeftIcon,
CircleAlertIcon,
ExternalLinkIcon,
TicketCheckIcon,
} from "lucide-react";
import { ArrowLeftIcon, TicketCheckIcon } from "lucide-react";
import type { Metadata } from "next";
import Link from "next/link";
import { redirect } from "next/navigation";
import { defineChain } from "thirdweb";
import { mapV4ChainToV5Chain } from "../../../../../contexts/map-chains";
import { StarButton } from "../../components/client/star-button";
import { ChainIcon } from "../../components/server/chain-icon";
import { getChain, getChainMetadata } from "../../utils";
import { AddChainToWallet } from "./components/client/add-chain-to-wallet";
import { ChainPageTabs } from "./components/client/tabs";
import { ChainCTA } from "./components/server/cta-card";
import { ExplorersSection } from "./components/server/explorer-section";
import { PrimaryInfoItem } from "./components/server/primary-info-item";
import { ChainHeader } from "./components/server/chain-header";
export async function generateMetadata(
{ params }: { params: { chain_id: string } },
// parent: ResolvingMetadata,
): Promise<Metadata> {
// read route params
// TODO: improve the behavior when clicking "Get started with thirdweb", currently just redirects to the dashboard
export async function generateMetadata({
params,
}: { params: { chain_id: string } }): Promise<Metadata> {
const chain = await getChain(params.chain_id);
const sanitizedChainName = chain.name.replace("Mainnet", "").trim();
const title = `${sanitizedChainName}: RPC and Chain Settings`;
const description = `Use the best ${sanitizedChainName} RPC and add to your wallet. Discover the chain ID, native token, explorers, and ${
@@ -53,226 +40,137 @@ export default async function ChainPageLayout({
}) {
const chain = await getChain(params.chain_id);
// Enable faucet for all testnet chains.
if (chain.testnet) {
chain.services = [
...chain.services,
{
service: "faucet",
enabled: true,
},
];
}
if (params.chain_id !== chain.slug) {
redirect(chain.slug);
}
const chainMetadata = await getChainMetadata(chain.chainId);
// true if we *have* chainMetadata for the chain
const isVerified = !!chainMetadata;
const isDeprecated = chain.status === "deprecated";
const sidebarLinks = [
{
href: `/${chain.slug}`,
label: "Overview",
},
{
href: `/${chain.slug}/popular`,
label: "Popular Contracts",
},
];
return (
<>
{isDeprecated && (
<>
<div className="bg-destructive">
<div className="container py-4 flex flex-row items-center gap-4 text-white">
<CircleAlertIcon className="size-6 flex-shrink-0" />
<h3 className="font-semibold">
This chain has been marked as deprecated. Some or all services
may no longer function.
</h3>
</div>
<div className="container flex flex-row h-full">
<Sidebar
header={
<div className="flex items-center gap-1.5 mb-5 flex-wrap">
<Link
href="/chainlist"
className="text-secondary-foreground hover:text-foreground text-sm"
>
Chainlist
</Link>
<span className="text-secondary-foreground text-sm"> / </span>
<Link href={`/${chain.slug}`} className="text-foreground text-sm">
{chain.name.replace("Mainnet", "")}
</Link>
</div>
<Separator />
</>
)}
<section className="flex flex-col h-full gap-8">
{/* Header */}
<header
className={cn(
"py-6 md:py-8 border-b relative overflow-hidden",
!chainMetadata?.gasSponsored && !isVerified && "md:pb-2",
chainMetadata?.headerImgUrl && "md:py-10",
}
links={sidebarLinks}
/>
<div className="flex flex-col w-full lg:px-6 lg:border-x pb-10">
{/* Icon + Background */}
<ChainHeader
headerImageUrl={chainMetadata?.headerImgUrl}
logoUrl={chain.icon?.url}
chain={chain}
/>
<div className="flex lg:hidden justify-end">
<BurgerMenuButton
links={sidebarLinks}
footer={
<div className="mt-5 border-t pt-6 pb-2">
<Link
href="/chainlist"
className="px-2 text-sm flex justify-start gap-2 items-center text-secondary-foreground 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">
{/* Gas Sponsored badge - Mobile */}
{chainMetadata?.gasSponsored && (
<div className="md:hidden flex">
<GasSponseredBadge />
</div>
)}
>
{/* header background image shenanigans */}
<div className="absolute top-0 left-0 right-0 bottom-0 -z-10">
<div
className="absolute top-0 left-0 right-0 bottom-0 bg-cover bg-center bg-no-repeat bg-secondary"
style={
chainMetadata?.headerImgUrl
? {
backgroundImage: `url(${chainMetadata.headerImgUrl})`,
}
: undefined
}
{/* Chain name */}
<div className="flex flex-row gap-1.5 items-center">
<h1 className="text-2xl font-semibold lg:text-3xl lg:font-semibold tracking-tight">
{chain.name}
</h1>
{/* Favorite */}
<StarButton
chainId={chain.chainId}
iconClassName="size-5"
className="p-1"
/>
<div className="absolute top-0 left-0 right-0 bottom-0 bg-ba bg-gradient-to-b from-black/25 to-black/0 shadow-inner" />
</div>
{/* end header shaningans */}
<div className="container flex flex-col md:flex-row justify-between md:items-center">
<div className="flex flex-col gap-2 md:gap-6">
<Link
href="/chainlist"
className={cn(
"text-foreground mt-4 inline-flex items-center gap-1",
// if we have a header image always light text
chainMetadata?.headerImgUrl && "text-white",
)}
>
<ArrowLeftIcon className="size-5" />
Chainlist
</Link>
<div className="flex gap-3 md:gap-5 items-center">
{chain.icon?.url && (
<div
className={cn(
"bg-secondary p-2 border rounded-full overflow-hidden",
)}
>
<ChainIcon
iconUrl={chain.icon.url}
className={cn(
"size-14 md:size-18 rounded-full",
// if we it's "mantle" chain, invert the icon in dark mode
chain.chainId === 5000 && "dark:invert",
)}
/>
</div>
)}
{/* Chain Name */}
<h1
className={cn(
"font-semibold tracking-tighter text-4xl md:text-6xl",
// if we have a header image always light text
chainMetadata?.headerImgUrl && "text-white",
)}
>
{chain.name}
</h1>
<StarButton chainId={chain.chainId} variant="secondary" />
{/* Gas Sponsored badge - Desktop */}
{chainMetadata?.gasSponsored && (
<div className="hidden md:block">
<GasSponseredBadge />
</div>
<div className="flex flex-row gap-2 md:gap-4 items-center h-8 mb-4 md:mb-6">
{chainMetadata?.gasSponsored && (
<Badge
variant="secondary"
className="text-accent-foreground pointer-events-none flex flex-row items-center h-full gap-1.5 border border-border"
>
<TicketCheckIcon className="size-5" />
<span className="font-bold text-xs uppercase">
gas sponsored
</span>
</Badge>
)}
</div>
</div>
<div className="flex flex-row md:flex-col gap-4">
<AddChainToWallet
chain={defineChain(chain)}
hasBackground={!!chainMetadata?.headerImgUrl}
/>
{isVerified ? null : (
<Button
className="w-full md:min-w-40"
variant="outline"
asChild
>
<Link
className="gap-2"
href="https://share.hsforms.com/1o01TyfsZRAao2eCrzuXSVgea58c"
target="_blank"
>
<span>Claim this chain</span>
<ExternalLinkIcon className="size-3" />
</Link>
</Button>
)}
</div>
</div>
</header>
{chainMetadata?.cta && <ChainCTA {...chainMetadata.cta} />}
<main className="container pb-20 flex-1">
{/* About section */}
{chainMetadata?.about && (
<>
<div className="border rounded-xl px-4 py-4 bg-card relative">
<h2 className="text-xl font-semibold tracking-tight mb-4">
About
</h2>
<div className="[&_p]:mb-3 [&_p]:text-card-foreground">
<pre className="text-wrap font-sans">
{chainMetadata.about}
</pre>
</div>
</div>
<div className="h-8" />
</>
)}
{/* Chain Overview */}
<div className="flex flex-col gap-10 pt-2">
{/* Info Grid */}
<div className="grid grid-cols-1 gap-4 lg:gap-6 md:grid-cols-2 lg:grid-cols-3">
{/* Info */}
{chain.infoURL && (
<PrimaryInfoItem title="Info">
<div className="flex items-center gap-1.5 hover:text-primary">
<Link
href={chain.infoURL}
target="_blank"
className="text-lg"
>
{new URL(chain.infoURL).hostname}
</Link>
<ExternalLinkIcon className="size-4" />
</div>
</PrimaryInfoItem>
)}
{/* Chain Id */}
<PrimaryInfoItem title="Chain ID">
<CopyTextButton
textToCopy={chain.chainId.toString()}
textToShow={chain.chainId.toString()}
tooltip="Copy Chain ID"
variant="ghost"
className="text-lg -translate-x-2 py-0.5"
copyIconPosition="right"
/>
</PrimaryInfoItem>
{/* Native token */}
<PrimaryInfoItem title="Native Token">
<div className="text-lg">
{chain.nativeCurrency.name} ({chain.nativeCurrency.symbol})
</div>
</PrimaryInfoItem>
</div>
{/* Explorers */}
{chain.explorers && chain.explorers.length > 0 && (
<ExplorersSection explorers={chain.explorers} />
)}
</div>
<div className="h-14" />
<ChainPageTabs
chainSlug={params.chain_id}
enabledServices={chain.services
.filter((s) => s.enabled)
.map((s) => s.service)}
/>
<div className="h-8" />
<div>{children}</div>
</main>
</section>
</>
{/* description */}
{chainMetadata?.about && (
<p className="text-secondary-foreground text-sm lg:text-base mb-2">
{chainMetadata.about}
</p>
)}
{/* mobile action row */}
<div className="sm:hidden w-full">
<div className="grid grid-cols-2 gap-2">
<AddChainToWallet
chain={
// Do not include chain overrides for chain pages
// eslint-disable-next-line no-restricted-syntax
mapV4ChainToV5Chain(chain)
}
/>
<Button variant="primary">
<Link href="https://thirdweb.com/dashboard" target="_blank">
Get started
</Link>
</Button>
</div>
</div>
</div>
<div className="h-8" />
{children}
</div>
</div>
);
}
function GasSponseredBadge() {
return (
<div className="flex items-center gap-2 rounded-full text-[hsl(334,81.12%,69.65%)] bg-[hsla(335,57%,51%,0.2)] px-2.5 py-1">
<TicketCheckIcon className="size-4" />
<span className="font-medium text-xs">Gas Sponsored</span>
</div>
);
}
@@ -1,166 +1,97 @@
import { ChevronRight, ShieldCheckIcon } from "lucide-react";
import Image from "next/image";
import { Button } from "@/components/ui/button";
import { fetchTopContracts } from "lib/search";
import { ArrowRightIcon, CircleAlertIcon } from "lucide-react";
import Link from "next/link";
import {
type SortBy,
type TimeRange,
fetchTopContracts,
} from "../../../../../lib/search";
import { TrendingContractSection } from "../../../trending/components/trending-table";
import { getChain } from "../../utils";
import { InfoCard } from "./components/server/info-card";
import twPublisherImage from "./tw-publisher.png";
type ContractCardInfo = {
name: string;
description: string;
href: string;
};
// currently the metadata is hardcoded - TODO:fetch it
const popularContracts: ContractCardInfo[] = [
{
name: "NFT Drop",
description: "Release collection of unique NFTs for a set price",
href: "/thirdweb.eth/DropERC721",
},
{
name: "NFT Collection",
description: "Create a collection of unique NFTs",
href: "/thirdweb.eth/TokenERC721",
},
{
name: "Edition Drop",
description: "Release ERC1155 tokens for a set price",
href: "/thirdweb.eth/DropERC1155",
},
{
name: "Token",
description: "Create cryptocurrency compliant with ERC20 standard",
href: "/thirdweb.eth/TokenERC20",
},
{
name: "Edition",
description: "Create editions of ERC1155 tokens",
href: "/thirdweb.eth/TokenERC1155",
},
];
import { getChain, getChainMetadata } from "../../utils";
import { BuyFundsSection } from "./components/server/BuyFundsSection";
import { ChainOverviewSection } from "./components/server/ChainOverviewSection";
import { ClaimChainSection } from "./components/server/ClaimChainSection";
import { FaucetSection } from "./components/server/FaucetSection";
import { SupportedProductsSection } from "./components/server/SupportedProductsSection";
import { ChainCTA } from "./components/server/cta-card";
import { ExplorersSection } from "./components/server/explorer-section";
export default async function Page(props: {
params: { chain_id: string };
searchParams: { timeRange?: TimeRange; page?: number; sortBy?: SortBy };
}) {
const chain = await getChain(props.params.chain_id);
const chainMetadata = await getChainMetadata(chain.chainId);
const isDeprecated = chain.status === "deprecated";
const topContracts = await fetchTopContracts({
chainId: chain.chainId,
timeRange: props.searchParams.timeRange,
page: props.searchParams.page,
sortBy: props.searchParams.sortBy,
perPage: 3,
timeRange: "month",
});
return (
<div>
<div className="h-4" />
{topContracts.length > 0 && (
<>
<div className="flex flex-col gap-4">
<h3 className="text-foreground text-2xl tracking-tighter font-semibold">
Popular Contracts on {chain.name.split(" ")[0]}
</h3>
<TrendingContractSection
topContracts={topContracts}
chainId={chain.chainId}
searchParams={props.searchParams}
/>
</div>
<div className="h-10" />
</>
<div className="flex flex-col gap-10">
{/* Custom CTA */}
{(chainMetadata?.cta?.title || chainMetadata?.cta?.description) && (
<ChainCTA {...chainMetadata.cta} />
)}
<div className="flex items-center justify-between">
<h3 className="text-foreground text-2xl tracking-tighter font-semibold">
Deploy Contracts on {chain.name.split(" ")[0]}
</h3>
<Link
href="/explore"
className="text-link-foreground inline-flex items-center gap-1 text-base hover:text-foreground font-medium"
>
View All
<ChevronRight className="size-5" />
</Link>
</div>
{/* Deprecated Alert */}
{isDeprecated && (
<section className="bg-destructive rounded-lg text-destructive-foreground border border-destructive-foreground/20">
<div className="container py-4 flex flex-row items-center gap-4">
<CircleAlertIcon className="size-6 flex-shrink-0" />
<h3 className="font-medium">
This chain has been marked as deprecated. Some or all services may
no longer function.
</h3>
</div>
</section>
)}
<div className="h-3" />
{/* Buy Funds */}
{chain.services.find((c) => c.service === "pay" && c.enabled) && (
<BuyFundsSection chain={chain} />
)}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3 md:gap-4">
{popularContracts.map((c) => {
return (
<ContractCard
key={c.name}
name={c.name}
description={c.description}
href={c.href}
/>
);
})}
</div>
{/* Faucet */}
{chain.testnet && <FaucetSection chain={chain} />}
<div className="h-10" />
{/* Chain Overview */}
<ChainOverviewSection chain={chain} />
<InfoCard
title="thirdweb Contracts"
links={[
{
label: "Learn More",
href: "https://portal.thirdweb.com/contracts",
},
]}
>
<p>End-to-end tools for smart contract development</p>
<p>
Trusted, modular smart contracts that can be deployed securely on any
EVM chain
</p>
</InfoCard>
</div>
);
}
function ContractCard(props: ContractCardInfo) {
return (
<div className="border bg-secondary rounded-xl p-4 hover:bg-muted relative flex flex-col h-full shadow-sm min-h-[200px]">
<div className="text-success-text flex items-center gap-1 mb-4 text-sm font-medium">
<ShieldCheckIcon className="size-4 text-success-text" />
Audited
</div>
<h3 className="text-lg tracking-tight font-semibold text-foreground mb-1">
<Link
href={props.href}
className="before:absolute before:inset-0 before:z-0"
>
{props.name}
</Link>
</h3>
<p className="text-base text-muted-foreground mb-5">
{props.description}
</p>
<Link
className="inline-flex items-center gap-1.5 z-10 relative mt-auto text-muted-foreground hover:text-foreground"
href="/thirdweb.eth"
>
<Image
src={twPublisherImage}
alt="thirdweb.eth"
className="size-4 rounded-full"
/>
<p className="text-sm">thirdweb.eth</p>
</Link>
{/* Explorers */}
{chain.explorers && chain.explorers.length > 0 && (
<ExplorersSection explorers={chain.explorers} />
)}
{topContracts.length > 0 && (
<section>
<div className="mb-3 flex items-center justify-between">
<h2 className="text-xl tracking-tight font-semibold">
Popular Contracts
</h2>
<Button asChild variant="outline">
<Link
href={`/${chain.slug}/popular`}
className="flex gap-2 items-center"
>
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} />
)}
{/* Claim Chain */}
{!chainMetadata && <ClaimChainSection />}
</div>
);
}
@@ -1,26 +0,0 @@
"use client";
import { thirdwebClient } from "@/constants/client";
import { useTheme } from "next-themes";
import { useMemo } from "react";
import { defineChain } from "thirdweb";
import { PayEmbed } from "thirdweb/react";
export function CustomPayEmbed(props: { chainId: number }) {
const { resolvedTheme } = useTheme();
const theme = resolvedTheme === "dark" ? "dark" : "light";
const chain = useMemo(() => defineChain(props.chainId), [props.chainId]);
return (
<PayEmbed
client={thirdwebClient}
connectOptions={{ chain }}
theme={theme}
payOptions={{
prefillBuy: {
chain,
allowEdits: { chain: false, amount: true, token: true },
},
}}
/>
);
}
@@ -1,34 +0,0 @@
import { redirect } from "next/navigation";
import { getChain } from "../../../utils";
import { InfoCard } from "../components/server/info-card";
import { CustomPayEmbed } from "./components/pay-embed.client";
export default async function Page(props: { params: { chain_id: string } }) {
const chain = await getChain(props.params.chain_id);
const enabled = chain.services.find((s) => s.service === "pay")?.enabled;
if (!enabled) {
redirect(`/${props.params.chain_id}`);
}
return (
<div className="pb-20 flex flex-col xl:flex-row gap-8">
<CustomPayEmbed chainId={chain.chainId} />
<InfoCard
title="thirdweb Pay"
links={[
{
label: "Get Started",
href: "https://portal.thirdweb.com/connect/pay/overview",
},
]}
>
<p>
thirdweb Pay allows your users to purchase cryptocurrencies and
execute transactions with their credit/debit card, or with any token
via cross-chain routing.
</p>
</InfoCard>
</div>
);
}
@@ -0,0 +1,54 @@
import { type SortBy, fetchTopContracts } from "lib/search";
import { CircleAlertIcon } from "lucide-react";
import React from "react";
import { TrendingContractSection } from "../../../../trending/components/trending-table";
import { getChain } from "../../../utils";
// we're using searchParams here - use dynamic rendering
export const dynamic = "force-dynamic";
export default async function Page(props: {
params: { chain_id: string };
searchParams: { page?: number; sortBy?: SortBy };
}) {
const chain = await getChain(props.params.chain_id);
const topContracts = await fetchTopContracts({
chainId: chain.chainId,
page: props.searchParams.page,
sortBy: props.searchParams.sortBy,
perPage: 15,
timeRange: "month",
});
return (
<section className="mt-2">
<h2 className="text-2xl tracking-tighter font-semibold mb-2">
Popular Contracts
</h2>
<p className="text-sm text-secondary-foreground">
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={props.searchParams}
showPagination={true}
/>
)}
{topContracts.length === 0 && (
<div className="text-secondary-foreground text-lg flex border rounded-lg h-[200px] border-border items-center justify-center">
<div className="flex items-center gap-2">
<CircleAlertIcon className="size-5 text-destructive-text" />
No contracts found
</div>
</div>
)}
</section>
);
}
@@ -1,43 +0,0 @@
import { redirect } from "next/navigation";
import { getChain } from "../../../utils";
import { InfoCard } from "../components/server/info-card";
import { ChainLiveStats } from "./components/client/live-stats";
export default async function Page(props: { params: { chain_id: string } }) {
const chain = await getChain(props.params.chain_id);
const enabled = chain.services.find((s) => s.service === "rpc-edge")?.enabled;
if (!enabled) {
redirect(`/${props.params.chain_id}`);
}
return (
<div className="pb-20">
<InfoCard
title="thirdweb RPC Edge"
links={[
{
label: "Learn More",
href: "https://portal.thirdweb.com/infrastructure/rpc-edge/overview",
},
]}
>
<p>
Remote Procedure Call (RPC) Edge provides reliable access to querying
data and interacting with the blockchain through global edge RPCs
</p>
<p>
By default, thirdweb provides publicly available RPCs for over 1000+
EVM Networks
</p>
</InfoCard>
{chain.rpc[0] && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 mt-10 gap-4">
<ChainLiveStats rpc={chain.rpc[0]} />
</div>
)}
</div>
);
}
@@ -0,0 +1,8 @@
// handle deprecated route
// redirect /<chain_id>/faucet to /<chain_id>
import { redirect } from "next/navigation";
export default function Page(props: { params: { chain_id: string } }) {
redirect(`/${props.params.chain_id}`);
}
@@ -1,14 +1,8 @@
import { Badge } from "@/components/ui/badge";
import { Separator } from "@/components/ui/separator";
import { IPFS_GATEWAY_URL } from "@/constants/env";
import { DASHBOARD_THIRDWEB_SECRET_KEY, PROD_OR_DEV_URL } from "constants/rpc";
import {
ZERO_ADDRESS,
createThirdwebClient,
defineChain,
toTokens,
} from "thirdweb";
import type { ChainMetadata } from "thirdweb/chains";
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "constants/rpc";
import { ZERO_ADDRESS, createThirdwebClient, toTokens } from "thirdweb";
import {
eth_getBlockByHash,
eth_getTransactionByHash,
@@ -16,18 +10,9 @@ import {
getRpcClient,
} from "thirdweb/rpc";
import { hexToNumber, shortenAddress, toEther } from "thirdweb/utils";
import { mapV4ChainToV5Chain } from "../../../../../../contexts/map-chains";
import { getChain } from "../../../utils";
function defineDashboardChain(chainId: number, dashboardChain?: ChainMetadata) {
return defineChain({
id: chainId,
rpc:
dashboardChain?.rpc?.[0] || `https://${chainId}.rpc.${PROD_OR_DEV_URL}`,
slug: dashboardChain?.slug,
nativeCurrency: dashboardChain?.nativeCurrency,
});
}
export default async function Page(props: {
params: { chain_id: string; txHash: `0x${string}` };
}) {
@@ -43,7 +28,9 @@ export default async function Page(props: {
const rpcRequest = getRpcClient({
client: thirdwebClient,
chain: defineDashboardChain(chain.chainId),
// Do not include chain overrides for chain pages
// eslint-disable-next-line no-restricted-syntax
chain: mapV4ChainToV5Chain(chain),
});
const [transaction, receipt] = await Promise.all([
@@ -1,8 +1,8 @@
"use client";
import { PaginationButtons } from "@/components/pagination-buttons";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useCallback } from "react";
import { PaginationButtons } from "../../../../../../@/components/pagination-buttons";
type ChainlistPaginationProps = {
totalPages: number;

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