Compare commits

...
Author SHA1 Message Date
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
94f5ed601d Version Packages (#3898)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-07-31 23:24:25 -07:00
Jonas DanielsandGitHub 4463848671 [Fix] Remove 'create' command from key-requiring CLI commands (#3897) 2024-07-31 23:10:54 -07:00
gregandGitHub 3b49b18f4d fix(react): OTP validation in React Native Connect UI (#3896) 2024-07-31 23:10:43 -07:00
Joaquim VergesandGitHub 2e0ca0ecee feat(webGL): Update CB wallet v4 for webGL (#3893) 2024-08-01 13:25:05 +12:00
MananTank ff6a319caf Map generic inputs to prebuilt components for Modular Contract install params fiedsets (#3887)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to update contract form components with improved form handling and modular extension support.

### Detailed summary
- Added `isBeta` prop to `ContractCard` and `publishedContractToShow` check
- Updated `PrimarySaleFieldset` and `RoyaltyFieldset` with improved form handling
- Enhanced modular extension support in `ModularContractDefaultExtensionsFieldset`

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

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

<!-- end pr-codex -->
2024-07-31 23:23:41 +00:00
MananTank 744c570ed1 [dashboard] Use dark default Theme for first time users (#3890)
<!-- start pr-codex -->

## PR-Codex overview
This PR introduces a new `defaultTheme` prop set to "dark" in the `_app.tsx` file.

### Detailed summary
- Added `defaultTheme` prop with value "dark" in the `_app.tsx` file.

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

<!-- end pr-codex -->
2024-07-31 22:08:51 +00:00
MananTank fff9550c8f [dashboard] Fix Spinner size in Add to wallet button in chain page (#3888)
## 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 styling of the "Add to wallet" button in the `add-chain-to-wallet.tsx` component.

### Detailed summary
- Updated the `className` of the button to include `gap-2` for spacing
- Adjusted the Spinner size with the class `size-3`

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

<!-- end pr-codex -->
2024-07-31 19:16:32 +00:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>GitHub Action
f925451c15 Version Packages (#3874)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <[email protected]>
2024-08-01 06:45:44 +12:00
gregfromstl fd30702ffd fix(thirdweb): mobile auth (#3886)
### TL;DR

Improved social authentication flexibility by adding support for an optional `redirectUrl` parameter and a new `mobile` mode.

### What changed?

- `getLoginPath.ts`: Added handling for `redirectUrl` and a new mode `mobile`.
- `native-auth.ts`: Updated social login to use `mobile` mode and include `redirectUrl`.
- `auth/middleware.ts`: Enhanced error handling for recovery codes by attempting fallback recovery code method.
- `native-connector.ts`: Fixed typo in console error message and ensured `redirectUrl` defaults correctly for native social logins.

### How to test?

1. Initiate a social login with the added `mobile` mode and verify if the `redirectUrl` functions correctly.
2. Trigger an error scenario in recovery code fetching and check that the fallback method is attempted and appropriate error is thrown if both fail.
3. Check the console for corrected error messages.

### Why make this change?

To increase the robustness and flexibility of social authentication by supporting mobile specific workflows and enhanced error resilience.

---

## 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 mobile authentication in the thirdweb application by updating redirect URLs and recovery code handling.

### Detailed summary
- Updated authentication mode to "mobile" instead of "popup"
- Added `redirectUrl` parameter for mobile authentication
- Improved error handling for recovery code retrieval
- Modified login path generation to support mobile authentication

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

<!-- end pr-codex -->
2024-07-31 16:44:08 +00:00
Joaquim VergesandGitHub 6cd279bc49 fix(ethers5adapter): correct transaction result nonces handling (#3885) 2024-07-31 22:19:28 +12:00
jnsdls 75cc5a6434 [Fix] Improve contract deploy logging and optimize Redis initialization (#3883)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to refactor the Redis caching implementation by encapsulating the Redis instance creation and usage inside a function to avoid unnecessary calls during build.

### Detailed summary
- Encapsulated Redis instance creation and usage inside a function `getRedis()`
- Refactored cache functions to use `getRedis()` function for Redis instance access

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

<!-- end pr-codex -->
2024-07-30 22:07:21 +00:00
kien-ngo e7d6161819 Add prebuilt component: CreateDirectListingButton (#3881)
<!-- start pr-codex -->

## PR-Codex overview
This PR adds a `CreateDirectListingButton` component for the Marketplace v3, allowing users to create direct listings for NFTs.

### Detailed summary
- Added `CreateDirectListingButton` component
- Updated `getPayMetadata` function
- Added test file for `CreateDirectListingButton`
- Updated `CreateDirectListingButton` component implementation

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

<!-- end pr-codex -->
2024-07-30 21:51:19 +00:00
MananTank 4171f1536d Improved error messages when connection management hooks used outside ThirdwebProvider (#3882)
<!-- start pr-codex -->

## PR-Codex overview
This PR improves error messages for connection management hooks used outside `ThirdwebProvider`.

### Detailed summary
- Added `useConnectionManagerCtx` to provide specific error messages
- Updated hooks to use `useConnectionManagerCtx` instead of `useConnectionManager`

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

<!-- end pr-codex -->
2024-07-30 20:59:57 +00:00
MananTank 5eb495581d Fix autoconnect of wallets connected from "All wallets" screen (#3880)
FIXES: DASH-104

<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on fixing the `useAutoConnectCore` function in `useAutoConnect.ts` to handle auto-connect for wallets from the "All wallets" screen.

### Detailed summary
- Fixed autoConnect for wallets from "All wallets" screen
- Added `createWallet` import
- Updated logic to handle lastActiveWalletId not found in availableWallets

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

<!-- end pr-codex -->
2024-07-30 17:37:45 +00:00
MananTank 36172a0476 [dash] Use the correct chain in Smart Account deposit native funds transaction (#3879)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to update the DepositNative component to include the chain information for better functionality.

### Detailed summary
- Updated `DepositNative` component in `account/page.tsx` to include `chain` information
- Added `mapStoredChainTov5Chain` function to map chain data in `map-chains.tsx`
- Imported `mapStoredChainTov5Chain` in `NetworkSelectorButton.tsx` and `deposit-native.tsx`

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

<!-- end pr-codex -->
2024-07-30 16:56:06 +00:00
kien-ngo cee989d41d (crusade) Dashboard v5 (#3876)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to refactor components in the contract UI tabs to use `contractAddress` and `chainId` instead of passing the entire `contract` object.

### Detailed summary
- Refactored `DirectListingsTable` and `EnglishAuctionsTable` components to accept `contractAddress` and `chainId`
- Updated `CancelDirectListing` and `CancelEnglishAuction` components to use `contractAddress` and `chainId`
- Modified `MarketplaceTable` components to receive `contractAddress` and `chainId` instead of `contract` object

> The following files were skipped due to too many changes: `apps/dashboard/src/contract-ui/tabs/claim-conditions/components/snapshot-upload.tsx`, `apps/dashboard/src/utils/tx-frame.ts`, `apps/dashboard/src/contract-ui/tabs/shared-components/listing-drawer.tsx`, `apps/dashboard/src/contract-ui/tabs/shared-components/cancel-tab.tsx`, `apps/dashboard/src/constants/currencies.ts`

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

<!-- end pr-codex -->
2024-07-30 16:42:41 +00:00
MananTank c55652f310 [dash] Fix wrong balance shown in Split contract (#3878)
<!-- start pr-codex -->

## PR-Codex overview
This PR updates the `nativeBalanceQuery` function in `page.tsx` to use the `contractAddress` instead of `address`.

### Detailed summary
- Updated `nativeBalanceQuery` to use `contractAddress` instead of `address`

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

<!-- end pr-codex -->
2024-07-30 16:29:19 +00:00
MananTank 9246ecb1e6 [dashboard] Add missing chakra color in theme (#3877)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to update the `backgroundCardHighlight` theme property in `apps/dashboard/src/theme/index.ts`.

### Detailed summary
- Updated `backgroundCardHighlight` property values
- Removed unused theme properties like `backgroundBody`, `wordmark`, `heading`, etc.

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

<!-- end pr-codex -->
2024-07-30 16:22:39 +00:00
jnsdls 337c8c953e [Feature] Add German localization for ConnectWallet and related components (#3875)
<!-- start pr-codex -->

## PR-Codex overview
This PR adds German localization to the `thirdweb` package, including translations and locale updates for various wallet-related components.

### Detailed summary
- Added German localization to the `thirdweb` package
- Updated `LocaleId` type to include `"de_DE"`
- Added German translations for wallet connection screens and instructions
- Updated locale files for smart wallets, injected wallets, and shared wallets to include German translations

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

<!-- end pr-codex -->
2024-07-30 08:08:47 +00:00
IDubuque 7e21d93a77 add refund to substatus (#3856)
## Problem solved

- add refund status

## 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 a new status "REFUNDED" to the `getStatus.ts` file and defines a new `SwapType` type with values "SAME_CHAIN" and "CROSS_CHAIN".

### Detailed summary
- Added status "REFUNDED" to possible statuses in `getStatus.ts`
- Defined new `SwapType` type with values "SAME_CHAIN" and "CROSS_CHAIN"

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

<!-- end pr-codex -->
2024-07-30 07:41:48 +00:00
jnsdls 97f7ad4d29 [Fix] Redirect CLI login to support page and remove CLI login route (#3872)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to temporarily redirect the CLI login page to a support page to troubleshoot device linking issues.

### Detailed summary
- Added a temporary redirect for `/cli/login` to a support page for troubleshooting device linking issues.

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

<!-- end pr-codex -->
2024-07-30 06:54:39 +00:00
jnsdls f702cf7216 [Fix] Ensure -k flag is included for key-requiring thirdweb CLI commands (#3871)
FIXES: DASH-50

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to temporarily disable CLI login and provide guidance on using secret keys for specific commands.

### Detailed summary
- Temporarily disable CLI login functionality
- Provide guidance on passing secret keys for specific commands
- Check for missing -k flag in certain commands

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

<!-- end pr-codex -->
2024-07-30 06:42:40 +00:00
Jonas DanielsandGitHub 0797a56ba6 Update CODEOWNERS (#3873)
Signed-off-by: Jonas Daniels <[email protected]>
2024-07-29 23:41:51 -07:00
AmineAfia 76d35bd428 Add a status page to engine dashboard (#3848)
## Problem solved

Short description of the bug fixed or feature added

## Changes made

- [ ] Added status page to engine
![CleanShot 2024-07-29 at 00 34 13@2x](https://github.com/user-attachments/assets/68b79b2b-7256-4015-89c9-0cc84a361ee8)

- [ ] 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: navigate to engine page and click on the statu snavigation in the left menu

## 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
The focus of this PR is to add system metrics functionality to the dashboard, including error rates and status codes.

### Detailed summary
- Added system metrics styling for charts
- Implemented system metrics components like `Healthcheck`, `ErrorRate`, and `StatusCodes`
- Updated `useEngineSystemHealth` hook with a polling interval parameter
- Updated UI components for better visualization of metrics

> The following files were skipped due to too many changes: `apps/dashboard/src/components/engine/system-metrics/components/StatusCodes.tsx`, `apps/dashboard/src/@/components/ui/chart.tsx`

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

<!-- end pr-codex -->
2024-07-30 06:19:09 +00:00
kien-ngo 24459b259b Update OG image for thirdweb.com/support (#3868)
## 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
The focus of this PR is to add metadata for Open Graph support in the dashboard page.

### Detailed summary
- Added `metadata` object with title and openGraph properties
- Imported `Metadata` type from "next"
- Updated the title for Open Graph support on the dashboard page

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

<!-- end pr-codex -->
2024-07-30 05:01:26 +00:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>GitHub Action
195064adf7 Version Packages (#3852)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <[email protected]>
2024-07-30 14:24:25 +12:00
Joaquim VergesandGitHub bd44ce935e chore(thirdweb): better TSdocs + more exports (#3869) 2024-07-30 13:39:58 +12:00
gregfromstl 109575eba5 fix(react): update social button styling and behavior logic (#3867)
![Screenshot 2024-07-29 at 5.35.57 PM.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/G5kV6fAq4H1wu10SVop6/b85da5cc-045e-47b9-bde4-e85321c2d802.png)

![Screenshot 2024-07-29 at 4.33.04 PM.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/G5kV6fAq4H1wu10SVop6/36aa163a-2d6a-450f-879f-35a81078360a.png)

![Screenshot 2024-07-29 at 4.30.51 PM.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/G5kV6fAq4H1wu10SVop6/587c10c8-ccd3-4578-a609-83842a037894.png)

<!-- start pr-codex -->

---

## PR-Codex overview
This PR increases the minimum number of social logins displayed before switching to a different layout. It also adjusts the styling of the social login buttons.

### Detailed summary
- Increased minimum social logins displayed to 3
- Adjusted social login buttons layout based on the number of logins
- Updated styling for social login buttons to improve alignment and spacing

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

<!-- end pr-codex -->
2024-07-29 23:21:36 +00:00
kien-ngo e27ebef85b Prebuilt UI: BuyDirectListingButton for Marketplace v3 (#3847)
<!-- start pr-codex -->

## PR-Codex overview
This PR adds a new prebuilt component `BuyDirectListingButton` for Marketplace v3 in Thirdweb.

### Detailed summary
- Added `BuyDirectListingButton` component for buying NFTs from a listing
- Includes necessary logic for preparing and executing transactions
- Provides detailed documentation and testing for the component

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

<!-- end pr-codex -->
2024-07-29 22:39:16 +00:00
Manan TankandGitHub f31e21196a [dashboard] Fix faucet filter in chainlist page (#3859) 2024-07-29 22:37:50 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
5f8c7976dc chore(deps): bump CodSpeedHQ/action from 2 to 3 (#3858)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-29 15:01:42 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
07cc040391 chore(deps): bump tailwind-merge from 2.3.0 to 2.4.0 (#3862)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-29 15:00:52 -07:00
kien-ngo 91edae58a7 <Crusade> Dashboard to v5 (#3843)
<!-- start pr-codex -->

## PR-Codex overview
This PR exposes `multicall` and `encodeSafeTransferFrom` extensions, adds `RequiredParam` type, and updates NFT UI components.

### Detailed summary
- Exposed `multicall` and `encodeSafeTransferFrom` extensions
- Added `RequiredParam` type
- Updated NFT UI components with new features and improvements

> The following files were skipped due to too many changes: `apps/dashboard/src/contract-ui/tabs/nfts/components/transfer-tab.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/burn-tab.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/airdrop-tab.tsx`

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

<!-- end pr-codex -->
2024-07-29 21:38:25 +00:00
kien-ngo 7ec421f0e7 Add util function: convertParamValues (#3854)
## 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
The focus of this PR is to add a utility function `parseAbiParams` to convert parameter values based on type for Solidity smart contracts.

### Detailed summary
- Added `parseAbiParams` function to convert parameter values
- Added tests for `parseAbiParams` function
- Utility for ensuring correct parameter formatting

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

<!-- end pr-codex -->
2024-07-29 21:21:46 +00:00
gregfromstl d5e546726a feat(thirdweb): adds useChainMetadata hook to retrieve metadata for a chain (#3857)
### TL;DR

This PR adds a new hook, `useChainMetadata`, to the thirdweb library. The hook allows developers to retrieve metadata for a specific blockchain, such as name, icon, available faucets, and block explorers.

### What changed?

- Added `useChainMetadata` hook in `thirdweb/react`.
- Deprecated `useChainQuery` hook.
- Updated documentation to reflect the new hook.

### How to test?

1. Import the `useChainMetadata` from `thirdweb/react`.
2. Call the hook with a chain defined using `defineChain`.
3. Check the returned metadata for correctness.

### Why make this change?

This change provides a more intuitive and documented way to retrieve chain metadata, replacing the deprecated `useChainQuery` hook. It enhances developer experience by offering a straightforward API to access chain-related information.

---

<!-- start pr-codex -->

---

## PR-Codex overview
This PR adds a new hook `useChainMetadata` to retrieve chain metadata in Thirdweb React. It also updates the `useChainQuery` hook to `useChainMetadata`.

### Detailed summary
- Added `useChainMetadata` hook to retrieve chain metadata
- Updated `useChainQuery` to `useChainMetadata`
- Improved documentation for `useChainMetadata`

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

<!-- end pr-codex -->
2024-07-29 21:02:05 +00:00
gregfromstl e26d0705f7 fix: passkey, email, phone auth (#3860)
### TL;DR
Updated the in-app wallet authentication logic to correctly handle redirect strategies. The previous logic incorrectly threw an error when the strategy was within the list of supported social authentication options.

### What changed?
Modified the condition to check if the strategy is included in the socialAuthOptions and call `connector.authenticateWithRedirect` accordingly.

### How to test?
1. Set up an in-app wallet with a supported social authentication strategy.
2. Initiate the authentication process and verify that the redirection occurs without errors.

### Why make this change?
Ensures that supported social authentication methods that require redirection are handled correctly without causing errors.

---
2024-07-29 20:44:32 +00:00
Manan TankandGitHub 77b852af16 Fix contract card height in dashboard (#3853) 2024-07-29 15:58:22 +00:00
Manan TankandGitHub 9b043315bf Disable system option in next-theme provider (#3855) 2024-07-29 21:17:13 +05:30
kien-ngo cdb2970806 ClaimButton to handle approval for ERC20 (#3846)
## 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
The focus of this PR is to handle ERC20 approval for the ClaimButton component in the Thirdweb package.

### Detailed summary
- Added `getPayMetadata` function to handle custom Pay metadata
- Updated `ClaimButton` component to handle ERC20 approval
- Utilized hooks for contract interaction and transaction handling

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

<!-- end pr-codex -->
2024-07-29 11:50:27 +00:00
gregfromstl dcfc9363fa docs: jsdoc content improvements (#3851)
### TL;DR

This PR enhances the `createThirdwebClient` and `download` functions by adding detailed descriptions, examples, and additional parameters.

### What changed?

1. `createThirdwebClient` function now includes options for `clientId` and `secretKey`.
2. `download` function now supports multiple URI schemes (IPFS, Arweave, HTTP) and includes examples for each.
3. Added `requestTimeoutMs` parameter to `download` function.
4. Improved JSDoc comments and examples for both functions.

### How to test?

- Create a Thirdweb client using both client ID and secret key, and test its functionality.
- Test downloading files using IPFS, Arweave, and HTTP URIs with different timeout settings.

### Why make this change?

These changes enhance the flexibility and usability of the Thirdweb client and download functions by providing more detailed documentation and additional configurable parameters. This aims to improve developer experience and clarity.

---

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to enhance the Thirdweb SDK by adding the ability to create a client using a client ID or secret key and improving the file download functionality.

### Detailed summary
- Updated `createThirdwebClient` function to accept `clientId` and `secretKey`
- Added support for downloading files from IPFS, Arweave, or HTTP URIs in the `download` function
- Improved error handling and request timeout handling in the `download` function

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

<!-- end pr-codex -->
2024-07-29 05:00:49 +00:00
Jonas DanielsandGitHub 78651115d2 Update CODEOWNERS (#3850)
Signed-off-by: Jonas Daniels <[email protected]>
2024-07-28 18:52:18 -07:00
kien-ngo 7abe1b528f Update templates demo links (#3849)
## 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 updates homepage URLs for the `Vite Starter` and `Next Starter` templates to include `https://`.

### Detailed summary
- Updated homepage URL for `Vite Starter` template
- Updated homepage URL for `Next Starter` template

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

<!-- end pr-codex -->
2024-07-29 00:34:52 +00:00
2e549837f7 Add @component toshow component on components section in docs (#3832)
Co-authored-by: Joaquim Verges <[email protected]>
2024-07-28 16:51:01 -07:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>GitHub Action
4f539ad8d4 Version Packages (#3837)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <[email protected]>
2024-07-28 09:04:01 +12:00
gregfromstl b551b69291 feat(react): add tabs to view assets screen (#3845)
1. Renamed `ViewFunds` to `ViewAssets` throughout the codebase for better clarity.
2. Updated file names and corresponding imports to reflect this change.
3. Modified the styling of the tabs on the `TransactionsScreen`.
4. Updated the grid layout and spacing in the `ViewNFTs` component.
5. Streamlined token viewing logic by creating reusable content components for tokens and NFTs in `ViewAssets`, `ViewNFTs`, and `ViewTokens`.

---

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to restyle the View Assets Connect UI page and rename `ViewFunds` to `ViewAssets`.

### Detailed summary
- Restyled the View Assets Connect UI page
- Renamed `ViewFunds` component to `ViewAssets`
- Updated references and function names accordingly
- Added new components `ViewTokensContent` and `ViewNFTsContent`
- Updated UI layout and styling for better user experience

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

<!-- end pr-codex -->
2024-07-27 19:53:41 +00:00
gregfromstl 6901a41839 feat(react): adds tab icons to connect ui transactions page (#3844)
![Screenshot 2024-07-27 at 2.07.20 PM.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/G5kV6fAq4H1wu10SVop6/006213aa-0e02-4b06-a3ec-335bcbb91069.png)
![Screenshot 2024-07-27 at 2.07.25 PM.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/G5kV6fAq4H1wu10SVop6/acc841ae-cd8d-4e02-942c-4872aa2b4c2c.png)

### TL;DR
Improved the TransactionsScreen UI in the thirdweb package by adding new icons for better visualization and adjusted some layout styles for uniformity.

### What changed?
- Added CoinsIcon and FundsIcon for better tab representation in TransactionsScreen.tsx.
- Updated Tabs component to support labels with React nodes.
- Implemented padding and minHeight adjustments in BuyTxHistory and WalletTransactionHistory components.
- Conditionally rendered transaction history buttons only when transactions are available.

### How to test?
1. Navigate to the TransactionsScreen in the thirdweb package.
2. Verify that the tabs now display icons alongside text labels.
3. Check the layout adjustments in the transaction history components for proper spacing and padding.

### Why make this change?
To enhance the user experience by improving the visual representation of tabs and ensuring consistency in the layout of transaction history components.

---
2024-07-27 19:24:47 +00:00
kien-ngo d775333b40 Expose ERC20 extension: getApprovalForTransaction (#3831)
## 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
The focus of this PR is to expose a new ERC20 extension function `getApprovalForTransaction` for handling ERC20 token approvals.

### Detailed summary
- Exposed `getApprovalForTransaction` in `erc20.ts`
- Added `getApprovalForTransaction` function in `getApprovalForTransaction.ts`
- Defined `GetApprovalForTransactionParams` interface in `getApprovalForTransaction.ts`
- Provided detailed documentation and example usage for `getApprovalForTransaction`

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

<!-- end pr-codex -->
2024-07-27 18:44:11 +00:00
gregfromstl b0a303d5ef feat: farcaster login (#3827)
### TL;DR

Added Farcaster icon and login support to the thirdweb package.

### What changed?

- Added Farcaster icon to `socialIcons.ts` and `svgs.ts`
- Updated `WalletImage.tsx` to include Farcaster icon.
- Added Farcaster as a supported social login option throughout the codebase.

### How to test?

1. Ensure the Farcaster icon is rendered correctly by using the Farcaster login option.
2. Verify the Farcaster login flow works as expected on both web and native applications.

### Why make this change?

This update adds support for Farcaster as a social login option, enhancing the flexibility and options available to users for authentication.

---

<!-- start pr-codex -->

---

## PR-Codex overview
This PR adds support for the "Farcaster" authentication option in various parts of the application.

### Detailed summary
- Added "Farcaster" as an authentication option
- Updated login and connection flows to include "Farcaster"
- Introduced Farcaster icons for web and native UI components
- Enhanced social auth login paths to support Farcaster

> The following files were skipped due to too many changes: `packages/thirdweb/src/react/core/utils/socialIcons.ts`

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

<!-- end pr-codex -->
2024-07-27 06:24:10 +00:00
MananTank 95d90ea344 Explore page UI tweaks (#3840)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to update UI components and improve code readability in the dashboard explore feature.

### Detailed summary
- Updated UI components in `ContractCard` and `PublishUpsellCard`
- Simplified `showSkeleton` logic in `ContractCard`
- Replaced `ChakraNextImage` with `Image` and `Button` components
- Reorganized JSX structure for better readability

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

<!-- end pr-codex -->
2024-07-27 03:48:11 +00:00
jnsdls 0da9703284 [Refactor] Remove unused TimeRangeSwitcher component (#3839) 2024-07-27 01:17:30 +00:00
MananTank 22f7a5ddb3 Update Explorer page layout to tailwind, add Modular contracts (#3836)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to enhance the UI/UX of the dashboard explore section and components.

### Detailed summary
- Updated styling and layout for Explore page components
- Added `TrackedLinkTW` component for analytics tracking
- Introduced `isBeta` flag for contracts
- Improved UI consistency and accessibility across components

> The following files were skipped due to too many changes: `apps/dashboard/src/components/explore/upsells/deploy-your-own.tsx`, `apps/dashboard/src/components/explore/contract-card/index.tsx`

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

<!-- end pr-codex -->
2024-07-27 01:11:56 +00:00
Manan TankandGitHub 7cb39cdd2a Fix flash of dark theme when loading dashboard in light mode + replace useColorMode with useTheme (#3838) 2024-07-27 00:32:47 +00:00
Manan TankandGitHub b128530355 Move connection manager creation to context instead of global singleton (#3817) 2024-07-26 23:13:22 +00:00
kumaryash90 dd3ae00279 Refresh button for contract metadata (#3834)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to add a feature for refreshing contract metadata in the Contract Sources page.

### Detailed summary
- Added `RefreshContractMetadataButton` component for refreshing contract metadata
- Imported `useMutation` and `useQueryClient` from `@tanstack/react-query`
- Imported `toast` from `sonner`
- Updated `VerifyContractParams` type to `ContractParams`
- Modified function parameters in `verifyContract`
- Updated conditional check in `ContractSourcesPage`
- Added logic to handle refreshing contract metadata and invalidating queries

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

<!-- end pr-codex -->
2024-07-26 21:20:28 +00:00
jnsdls 676411898b [Feature] Add support for Webhooks in Pay UI component (#3810)
CLOSES: DASH-88, DASH-87, DASH-85, DASH-86

<!-- start pr-codex -->

---

## PR-Codex overview
This PR enhances the Pay UI in the dashboard by adding a new "Webhooks" tab with functionality to create, view, and delete webhooks.

### Detailed summary
- Added a new `WebhooksPage` component
- Integrated webhooks functionality with API calls
- Implemented create and delete webhook features with dialogs
- Updated UI components for webhooks management

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

<!-- end pr-codex -->
2024-07-26 21:06:34 +00:00
jnsdls 169b02020d [Fix] Update AppFooter layout: streamline class names and enhance social media links (#3833)
Refactored the AppFooter component in the dashboard app to simplify the DOM structure, clean up redundant class names and properties, and group social media icons more effectively. Adjusted the layout to use container and grid classes for better organization.

---
2024-07-26 19:42:02 +00:00
kien-ngo 794282533c Add Vanar CTA text (#3828)
## 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 updates the `title` property in the `ChainMetadata` object in `utils.ts`.

### Detailed summary
- Updated the `title` property value in the `ChainMetadata` object to "Fully EVM compatible L1 for Entertainment".

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

<!-- end pr-codex -->
2024-07-26 16:05:31 +00:00
MananTank ebfcbd7051 Fix various UI issues/improvements in dashboard (#3829)
* Improved Dialog styles on mobile
* Use the correct color in form error message
* Fix z-index issue with footer
* Fix z-index issue with tab underline
* Fix padding for various other elements

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update styles and components in the dashboard layout.

### Detailed summary
- Added padding to a container in `layout.tsx`
- Updated form layout in `create-ticket.client.tsx`
- Adjusted styling in `sidebar.client.tsx`
- Enhanced uninstall dialog in `InstalledExtensionsTable.tsx`
- Modified classnames in `form.tsx`
- Revised dialog styles in `dialog.tsx`
- Refactored layout structure in `index.tsx`

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

<!-- end pr-codex -->
2024-07-26 15:12:22 +00:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>GitHub Action
9eea6e17ab Version Packages (#3819)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <[email protected]>
2024-07-26 21:20:50 +12:00
jnsdls 74714ccf31 [Feature] Add AppFooter component and integrate it across the app (#3825)
- New `AppFooter` component added in `app-footer.tsx` under `components/blocks`.
- Replaced `DashboardFooter` with `AppFooter` in `dashboard/layout.tsx`.
- Deleted old `DashboardFooter` implementation.
- Updated social icons and layout in the footer.
- Adjusted `DashboardHeader` styles for consistency.

---

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to update the footer component and layout in the dashboard app.

### Detailed summary
- Changed `DashboardFooter` to `AppFooter` in `DashboardLayout`
- Updated styles and content in `AppFooter`
- Removed `MobileBurgerMenu` import
- Updated button variant in `MobileBurgerMenu`
- Updated header layout in `DashboardHeader`

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

<!-- end pr-codex -->
2024-07-26 08:03:19 +00:00
4a4a0612ed feat(pay): Add metadata support for purchase flows (#3750)
Co-authored-by: Manan Tank <[email protected]>
2024-07-26 20:00:51 +12:00
MananTank c7f8bea4bc Move faucet inside chain page layout + UI tweaks (#3824)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to refactor the `faucet` page in the dashboard for a specific chain.

### Detailed summary
- Moved `getChain` import to a different path
- Reorganized `InfoCard` and added new headings with styling
- Updated `SpinWheel` component with `Skeleton` import and conditional rendering

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

<!-- end pr-codex -->
2024-07-26 00:09:33 +00:00
gregfromstl 3848327373 feat(thirdweb): adds redirect oauth (#3822)
### TL;DR

Added support for OAuth redirects in the In-App wallet authentication flow.

### What changed?

1. Introduced `auth.mode` with options `

---

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces the ability to open OAuth windows as a redirect, beneficial for embedded applications like Telegram web apps.

### Detailed summary
- Added `mode: "redirect"` option for OAuth windows
- Implemented functions for OAuth redirection
- Updated authentication options for in-app wallets

> The following files were skipped due to too many changes: `packages/thirdweb/src/react/core/hooks/wallets/useAutoConnect.ts`, `packages/thirdweb/src/wallets/in-app/web/lib/web-connector.ts`

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

<!-- end pr-codex -->
2024-07-25 23:33:31 +00:00
FirekeeperandGitHub bff7a0af6f Unity 4.17.0 (#3812) 2024-07-25 14:49:19 -07:00
Manan TankandGitHub d25a169d47 Fix Modular contracts encodeAbi error when deploying (#3823) 2024-07-26 02:53:05 +05:30
YashandGitHub 9e0dd0194b Fix transaction count for modular deployments (#3820) 2024-07-26 01:29:37 +05:30
Manan TankandGitHub 3ffd555e15 Move /trending page inside dashboard layout (#3816) 2024-07-25 18:47:56 +00:00
Manan TankandGitHub 87dc9a5f90 Allow selecting non-connected wallet on sign-in screen in ConnectEmbed (#3815) 2024-07-25 18:26:53 +00:00
kien-ngo 6081ac7b18 chore: Remove more v4 code from Dashboard (#3813)
## 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 exposes new types `NFTInput` and `NFTMetadata`, updates type imports, and adds `SUPPORTED_CHAIN_ID` type.

### Detailed summary
- Exposed types: `NFTInput` and `NFTMetadata`
- Updated type imports in various files
- Added `SUPPORTED_CHAIN_ID` type definition

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

<!-- end pr-codex -->
2024-07-25 17:31:36 +00:00
kien-ngo 80379a22e3 Give Dashboard > Marketplace section some luv (#3811)
Use this preview link to test:
https://thirdweb.com/avalanche-fuji/0x8C1D464B385A2B7EAa80dcAAD66DD8BC0256e717/direct-listings

<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to enhance the listing details display in the dashboard UI.

### Detailed summary
- Added `Listing ID` and `Type` display sections
- Improved `Status` section with additional text for clarity
- Included `Price` section with currency value and symbol
- Commented out a TODO for adding a Buy button in the future

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

<!-- end pr-codex -->
2024-07-25 16:42:10 +00:00
kien-ngo 97a8405d4e Update Vanar page (thirdweb.com/vanar) (#3814)
Note: We are still waiting for the CTA text from them

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to add support for the VANAR blockchain in the dashboard.

### Detailed summary
- Added support for VANAR blockchain in `utils.ts`
- Imported `vanarBanner` and `vanarCTABG` images
- Defined metadata for VANAR blockchain in `chainMetaRecord`

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

<!-- end pr-codex -->
2024-07-25 16:37:02 +00:00
jnsdls 26c7cf17d1 [Refactor] Remove radix toast dependencies and related components (#3808)
### TL;DR

This PR refactors the dashboard application by removing the custom toast component and its dependencies, and migrating to the 'sonner' library for toasts. Key changes include the deletion of toast-related components and utilities, adjustments to the `ExportToCSVButton` component to use 'sonner' for toast notifications, and the streamlining of `package.json` and `pnpm-lock.yaml` files.

### What changed?

- Removed custom toast components (`toast.tsx`, `toaster.tsx`, `use-toast.ts`).
- Updated `ExportToCSVButton.tsx` to use 'sonner' for toast notifications.
- Removed `@radix-ui/react-toast` dependency from `package.json` and `pnpm-lock.yaml`.
- Cleaned up `package.json` and `pnpm-lock.yaml` by removing the old toast dependencies.

### How to test?

1. Export a CSV in the dashboard and confirm that toast notifications appear correctly.
2. Check the application for any missing toast notifications that might indicate issues with the migration.

### Why make this change?

The custom toast implementation was redundant with the introduction of the 'sonner' library, which provides a more efficient and streamlined approach to toast notifications. This migration simplifies the codebase and reduces dependencies.

---
2024-07-25 05:34:06 +00:00
jnsdls df4e58b754 [Fix] Remove redundant z-index values in dialog and toast components (#3807) 2024-07-25 05:02:12 +00:00
GWSzeto d6bbca576b Explorer page to show transaction information (#3674)
- ETH RPC calls to block, transaction and receipt
- TODO: tooltips (copy from blockscout), replace in ENS names where appropriate, decode input data, detect whether it's a transfer or contract interaction, event logs page

### What it looks like
<img width="1055" alt="Screenshot 2024-07-12 at 11 00 23 AM" src="https://github.com/user-attachments/assets/182f392a-1f2a-4323-ab55-706374060b4a">

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on restructuring file paths and importing components for better organization in the dashboard chain pages.

### Detailed summary
- Moved components to `(chainPage)` directory for clarity
- Updated import paths for components in various files
- Refactored file paths for consistency and organization

> The following files were skipped due to too many changes: `apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/tx/[txHash]/page.tsx`

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

<!-- end pr-codex -->
2024-07-25 04:49:46 +00:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
79e34e1f81 Version Packages (#3794)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-07-24 21:46:52 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
284cfdf95c chore(deps): bump typedoc from 0.25.13 to 0.26.5 (#3780)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-24 21:26:56 -07:00
83517fbe08 chore(deps-dev): bump @testing-library/jest-dom from 6.4.6 to 6.4.7 (#3778)
Co-authored-by: dependabot <[email protected]>
2024-07-24 21:26:28 -07:00
9cc9f05f68 fix: bun detect (#3791)
Co-authored-by: Joaquim Verges <[email protected]>
Co-authored-by: Jonas Daniels <[email protected]>
2024-07-24 21:26:08 -07:00
dependabot 25b07c4ee7 chore(deps): bump next from 14.2.4 to 14.2.5 (#3776)
Bumps [next](https://github.com/vercel/next.js) from 14.2.4 to 14.2.5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/vercel/next.js/releases">next's releases</a>.</em></p>
<blockquote>
<h2>v14.2.5</h2>
<blockquote>
<p>[!NOTE]<br />
This release is backporting bug fixes. It does <strong>not</strong> include all pending features/changes on canary.</p>
</blockquote>
<h3>Core Changes</h3>
<ul>
<li>avoid merging global css in a way that leaks into other chunk groups (<a href="https://redirect.github.com/vercel/next.js/issues/67373">#67373</a>)</li>
<li>Fix server action edge redirect with middleware rewrite (<a href="https://redirect.github.com/vercel/next.js/issues/67148">#67148</a>)</li>
<li>fix(next): reject protocol-relative URLs in image optimization (<a href="https://redirect.github.com/vercel/next.js/issues/65752">#65752</a>)</li>
<li>fix(next-swc): correct path interop to filepath for wasm (<a href="https://redirect.github.com/vercel/next.js/issues/65633">#65633</a>)</li>
<li>Use addDependency to track metadata route file changes (<a href="https://redirect.github.com/vercel/next.js/issues/66714">#66714</a>)</li>
<li>Fix noindex is missing on static not-found page (<a href="https://redirect.github.com/vercel/next.js/issues/67135">#67135</a>)</li>
<li>perf: improve retrieving versionInfo on Turbo HMR (<a href="https://redirect.github.com/vercel/next.js/issues/67309">#67309</a>)</li>
<li>fix(next/image): handle invalid url (<a href="https://redirect.github.com/vercel/next.js/issues/67465">#67465</a>)</li>
<li>fix(next): initial prefetch cache not set properly with different search params (<a href="https://redirect.github.com/vercel/next.js/issues/65977">#65977</a>)</li>
<li>fix: Backport class properties fix (<a href="https://redirect.github.com/vercel/next.js/issues/67377">#67377</a>)</li>
<li>Upgrade acorn (<a href="https://redirect.github.com/vercel/next.js/issues/67592">#67592</a>)</li>
</ul>
<h3>Misc</h3>
<ul>
<li>Log stdio for pull-turbo-cache script (<a href="https://redirect.github.com/vercel/next.js/issues/66759">#66759</a>)</li>
<li>Ensure turbo is setup when building in docker (<a href="https://redirect.github.com/vercel/next.js/issues/66804">#66804</a>)</li>
</ul>
<h3>Credits</h3>
<p>Huge thanks to <a href="https://github.com/devjiwonchoi"><code>@​devjiwonchoi</code></a>, <a href="https://github.com/ijjk"><code>@​ijjk</code></a>, <a href="https://github.com/emmerich"><code>@​emmerich</code></a>, <a href="https://github.com/huozhi"><code>@​huozhi</code></a>,  <a href="https://github.com/kdy1"><code>@​kdy1</code></a>, <a href="https://github.com/kwonoj"><code>@​kwonoj</code></a>, <a href="https://github.com/styfle"><code>@​styfle</code></a>, and <a href="https://github.com/sokra"><code>@​sokra</code></a> for helping!</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/vercel/next.js/commit/0bf7f52db8b2c1e0b13d332de105fab645240e1e"><code>0bf7f52</code></a> v14.2.5</li>
<li><a href="https://github.com/vercel/next.js/commit/30d6dfc8bb97dfa674033c27e5c6a09d6d8e11f0"><code>30d6dfc</code></a> fix: metadata route merging conflicts</li>
<li><a href="https://github.com/vercel/next.js/commit/186ec6b58b0e6cd74a00f72c3bf2d7e1fe1941aa"><code>186ec6b</code></a> Log stdio for pull-turbo-cache script (<a href="https://redirect.github.com/vercel/next.js/issues/66759">#66759</a>)</li>
<li><a href="https://github.com/vercel/next.js/commit/45656d3323d164cf3917a8d6ea21b1a4f34a9844"><code>45656d3</code></a> Ensure turbo is setup when building in docker (<a href="https://redirect.github.com/vercel/next.js/issues/66804">#66804</a>)</li>
<li><a href="https://github.com/vercel/next.js/commit/08e7fd1f010077b13e29a59ce0a5edc50e4886ec"><code>08e7fd1</code></a> Upgrade acorn (<a href="https://redirect.github.com/vercel/next.js/issues/67592">#67592</a>)</li>
<li><a href="https://github.com/vercel/next.js/commit/1d08dab887a349ebd010e99201fd64000d030066"><code>1d08dab</code></a> avoid merging global css in a way that leaks into other chunk groups (<a href="https://redirect.github.com/vercel/next.js/issues/67373">#67373</a>)</li>
<li><a href="https://github.com/vercel/next.js/commit/21a9d591412e2dd0473808216c8edce854d27d88"><code>21a9d59</code></a> Fix server action edge redirect with middleware rewrite (<a href="https://redirect.github.com/vercel/next.js/issues/67148">#67148</a>)</li>
<li><a href="https://github.com/vercel/next.js/commit/1b10b13a7486d223df87d82e93b75eac2e8ed65a"><code>1b10b13</code></a> fix(next): reject protocol-relative URLs in image optimization (<a href="https://redirect.github.com/vercel/next.js/issues/65752">#65752</a>)</li>
<li><a href="https://github.com/vercel/next.js/commit/c64c61d8a8c06d4c6f8d8c773a662c12ac20635e"><code>c64c61d</code></a> fix(next-swc): correct path interop to filepath for wasm (<a href="https://redirect.github.com/vercel/next.js/issues/65633">#65633</a>)</li>
<li><a href="https://github.com/vercel/next.js/commit/6c661d2ce5126de18abb8f6326e79725dbd5493c"><code>6c661d2</code></a> Use addDependency to track metadata route file changes (<a href="https://redirect.github.com/vercel/next.js/issues/66714">#66714</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/vercel/next.js/compare/v14.2.4...v14.2.5">compare view</a></li>
</ul>
</details>
<br />

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=next&package-manager=npm_and_yarn&previous-version=14.2.4&new-version=14.2.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

</details>

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the Next.js version to 14.2.5 in multiple packages and dependencies.

### Detailed summary
- Updated Next.js version to 14.2.5 in `wallet-ui`, `playground-web`, `dashboard`
- Updated `next-auth` to version 4.24.7
- Updated `typescript` to version 5.5.2

> 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-07-25 03:34:07 +00:00
Joaquim VergesandGitHub b27c842f26 chore(claim-button): add ClaimButton component changeset (#3806) 2024-07-25 15:14:47 +12:00
dependabot 10c292d7bd chore(deps): bump viem from 2.16.5 to 2.17.10 (#3783)
Bumps [viem](https://github.com/wevm/viem) from 2.16.5 to 2.17.10.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/wevm/viem/releases">viem's releases</a>.</em></p>
<blockquote>
<h2>[email protected]</h2>
<h3>Patch Changes</h3>
<ul>
<li>
<p><a href="https://redirect.github.com/wevm/viem/pull/2513">#2513</a> <a href="https://github.com/wevm/viem/commit/3af06fe23dda1f44d43b3d3cec5d985894c2840a"><code>3af06fe</code></a> Thanks <a href="https://github.com/hoangtan282"><code>@​hoangtan282</code></a>! - Added Funki Mainnet.</p>
</li>
<li>
<p><a href="https://redirect.github.com/wevm/viem/pull/2519">#2519</a> <a href="https://github.com/wevm/viem/commit/01cdac14d508fbae50a31492e244b7adbe858bab"><code>01cdac1</code></a> Thanks <a href="https://github.com/cbfyi"><code>@​cbfyi</code></a>! - Added dispute game factory address for Base Sepolia.</p>
</li>
<li>
<p><a href="https://redirect.github.com/wevm/viem/pull/2515">#2515</a> <a href="https://github.com/wevm/viem/commit/b7e4fa518b1798741cf029f34ed3154695ab3a16"><code>b7e4fa5</code></a> Thanks <a href="https://github.com/JoeyKhd"><code>@​JoeyKhd</code></a>! - Added Root Network chain.</p>
</li>
</ul>
<h2>[email protected].9</h2>
<h3>Patch Changes</h3>
<ul>
<li><a href="https://github.com/wevm/viem/commit/b71e656e08dadc44e2c1eccb5f505f70ce4d3aaf"><code>b71e656e</code></a> Thanks <a href="https://github.com/jxom"><code>@​jxom</code></a>! - Exported types required for inference.</li>
</ul>
<h2>[email protected].8</h2>
<h3>Patch Changes</h3>
<ul>
<li><a href="https://github.com/wevm/viem/commit/690cb9a78a801edf7ea3ab1d8cf1a0cd794fc32a"><code>690cb9a7</code></a> Thanks <a href="https://github.com/jxom"><code>@​jxom</code></a>! - Exported types required for inference.</li>
</ul>
<h2>[email protected].7</h2>
<h3>Patch Changes</h3>
<ul>
<li>
<p><a href="https://github.com/wevm/viem/commit/7d3d505221d4bb2ccc002be1cddc9e2011e33c01"><code>7d3d505</code></a> Thanks <a href="https://github.com/jxom"><code>@​jxom</code></a>! - Allow override of <code>Content-Type</code> header on <code>http</code> transport.</p>
</li>
<li>
<p><a href="https://github.com/wevm/viem/commit/aa42f47fe8b5ce19858e5855ecdceae7000dbb92"><code>aa42f47</code></a> Thanks <a href="https://github.com/jxom"><code>@​jxom</code></a>! - Updated Darwinia chain explorer URL.</p>
</li>
<li>
<p><a href="https://github.com/wevm/viem/commit/759e34dde23ca50275d9e4df38805e8f0b285753"><code>759e34d</code></a> Thanks <a href="https://github.com/jxom"><code>@​jxom</code></a>! - Enforced <code>r</code> and <code>s</code> hex values on <code>Signature</code> to be always padded to 32 bytes.</p>
</li>
</ul>
<h2>[email protected].5</h2>
<h3>Patch Changes</h3>
<ul>
<li><a href="https://redirect.github.com/wevm/viem/pull/2500">#2500</a> <a href="https://github.com/wevm/viem/commit/f6d60054bdcf8ada44c8af46b66eda50b05dd08b"><code>f6d60054</code></a> Thanks <a href="https://github.com/lucadonnoh"><code>@​lucadonnoh</code></a>! - Added OP Stack contract addresses for Mode Testnet chain.</li>
</ul>
<h2>[email protected].4</h2>
<h3>Patch Changes</h3>
<ul>
<li><a href="https://redirect.github.com/wevm/viem/pull/2493">#2493</a> <a href="https://github.com/wevm/viem/commit/ef3601d1db04e41c993943c0cfc72d3a64bbb6db"><code>ef3601d</code></a> Thanks <a href="https://github.com/billalxcode"><code>@​billalxcode</code></a>! - Added DreyerX Testnet chain</li>
</ul>
<h2>[email protected].3</h2>
<h3>Patch Changes</h3>
<ul>
<li><a href="https://github.com/wevm/viem/commit/ec3b0e08f0a379249224e65092277191f1a8502b"><code>ec3b0e0</code></a> Thanks <a href="https://github.com/jxom"><code>@​jxom</code></a>! - Added fallback verification in <code>verifyHash</code>.</li>
</ul>
<h2>[email protected].2</h2>
<h3>Patch Changes</h3>
<ul>
<li>
<p><a href="https://redirect.github.com/wevm/viem/pull/2479">#2479</a> <a href="https://github.com/wevm/viem/commit/5028b3fb723100e49ca9b301405360b23c2a1003"><code>5028b3f</code></a> Thanks <a href="https://github.com/keyding"><code>@​keyding</code></a>! - Added Artela Testnet chain.</p>
</li>
<li>
<p><a href="https://redirect.github.com/wevm/viem/pull/2478">#2478</a> <a href="https://github.com/wevm/viem/commit/795ca46cf93bc496abb23a5b868ea48bd80860ae"><code>795ca46</code></a> Thanks <a href="https://github.com/sj719045032"><code>@​sj719045032</code></a>! - Added zkLink Nova Sepolia Testnet chain.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/wevm/viem/commit/8e3c9ec058885ac94f5b3a3d8f38eee201130ab5"><code>8e3c9ec</code></a> chore: bump size</li>
<li><a href="https://github.com/wevm/viem/commit/892d62fd17d14e60cfcb36caa671516caee990c4"><code>892d62f</code></a> chore: version package (<a href="https://redirect.github.com/wevm/viem/issues/2520">#2520</a>)</li>
<li><a href="https://github.com/wevm/viem/commit/01cdac14d508fbae50a31492e244b7adbe858bab"><code>01cdac1</code></a> feat: add dispute game factory address for Base Sepolia (<a href="https://redirect.github.com/wevm/viem/issues/2519">#2519</a>)</li>
<li><a href="https://github.com/wevm/viem/commit/7e17bb1b7413cb9d9f406c6d274511a6c8b7eef4"><code>7e17bb1</code></a> chore: up solady test</li>
<li><a href="https://github.com/wevm/viem/commit/b7e4fa518b1798741cf029f34ed3154695ab3a16"><code>b7e4fa5</code></a> feat: add root and root poricini (<a href="https://redirect.github.com/wevm/viem/issues/2515">#2515</a>)</li>
<li><a href="https://github.com/wevm/viem/commit/c3fac1be047cac22b3e0e1bd154038754b2b583e"><code>c3fac1b</code></a> chore: tweak funkiMainnet</li>
<li><a href="https://github.com/wevm/viem/commit/42c197776b300c5c44f09e86157fa344ddc2659f"><code>42c1977</code></a> chore: format</li>
<li><a href="https://github.com/wevm/viem/commit/3af06fe23dda1f44d43b3d3cec5d985894c2840a"><code>3af06fe</code></a> feat: add Funki Mainnet (<a href="https://redirect.github.com/wevm/viem/issues/2513">#2513</a>)</li>
<li><a href="https://github.com/wevm/viem/commit/3354c46174cdb7e86036bf28b696a0ce6cf982d5"><code>3354c46</code></a> docs: add missing <code>http</code> import in the config file example (<a href="https://redirect.github.com/wevm/viem/issues/2517">#2517</a>)</li>
<li><a href="https://github.com/wevm/viem/commit/752680e14df5ef6b4afcff5c2b9a2ecd1491f1a7"><code>752680e</code></a> chore: update nonceManager tests</li>
<li>Additional commits viewable in <a href="https://github.com/wevm/viem/compare/[email protected]@2.17.10">compare view</a></li>
</ul>
</details>
<br />

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=viem&package-manager=npm_and_yarn&previous-version=2.16.5&new-version=2.17.10)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

</details>

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is updating the `viem` package version from `2.16.5` to `2.17.10` across multiple locations.

### Detailed summary
- Updated `viem` package version from `2.16.5` to `2.17.10` in multiple files
- Peer dependencies and dev dependencies updated to `[email protected]`

> 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-07-25 02:45:39 +00:00
kumaryash90 8599fbf4e0 Deploy modular core with default extensions (#3524)
## 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 introduces support for modular extensions in contract publishing forms.

### Detailed summary
- Added support for modular extensions in contract publishing forms
- Updated extension input fields to handle modular extensions
- Implemented extension installation parameters for modular extensions

> The following files were skipped due to too many changes: `apps/dashboard/src/components/contract-components/contract-publish-form/index.tsx`, `legacy_packages/sdk/src/evm/common/any-evm-utils/getModularDeploymentInfo.ts`, `legacy_packages/sdk/src/evm/core/sdk.ts`

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

<!-- end pr-codex -->
2024-07-25 02:18:44 +00:00
jnsdls 5c9af853fa [Refactor] Simplify RPC client map key usage in getRpcClient function (#3805)
### TL;DR
Fixes an issue with RPC client reuse to improve performance.

### What changed?
The change replaces the use of `chainId` with `rpcUrl` as the key in the `rpcClientMap` to ensure the correct RPC client is reused.

### How to test?
Test by running existing unit tests and functional tests for RPC client related functionality. Ensure that performance metrics show improvement in RPC client reuse scenarios.

### Why make this change?
This change is motivated by the need to improve performance by ensuring the RPC client is correctly reused.

---
2024-07-25 01:35:50 +00:00
joaquim-verges cb616f75ed fix(gas): correct gas estimation logic on Arbitrum Sepolia (#3804)
<!-- start pr-codex -->

## PR-Codex overview
This PR fixes gas estimation issues on Arbitrum Sepolia and ensures proper handling of zero `maxPriorityFeePerGas`.

### Detailed summary
- Fixed gas estimation for Arbitrum Sepolia
- Added test case for 0 `maxPriorityFeePerGas`
- Updated conditions for handling `maxPriorityFeePerGas` as `null`

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

<!-- end pr-codex -->
2024-07-25 00:36:07 +00:00
joaquim-verges c82c524e13 feat(smart): allow overriding nonce for smart accounts (#3782)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to allow overriding the nonce for smart accounts in the `thirdweb` package.

### Detailed summary
- Added the ability to override nonce for smart accounts
- Exported `generateRandomUint192` function
- Updated imports and added new functions in `userop.ts` file
- Modified `createUnsignedUserOp` function to use custom nonce logic

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

<!-- end pr-codex -->
2024-07-24 22:37:45 +00:00
joaquim-verges e7581fc5bd fix(tests): conditionally run ClaimButton tests based on TW_SECRET_KEY environment variable (#3803) 2024-07-24 22:32:07 +00:00
Manan TankandGitHub 8fa7eef5bc Add missing JSdoc tags for docs organization (#3802) 2024-07-24 20:40:38 +00:00
joaquim-verges 39b31d9d0c fix(tests): conditionally run tests based on TW_SECRET_KEY environment variable (#3790)
<!-- start pr-codex -->

## PR-Codex overview
This PR updates test descriptions to conditionally run based on a secret key presence.

### Detailed summary
- Updated test descriptions to run conditionally with `runIf` based on `TW_SECRET_KEY`
- Added conditional execution for specific test cases
- Ensured tests run only if the secret key is present

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

<!-- end pr-codex -->
2024-07-24 19:57:35 +00:00
gregfromstl a51f53f531 fix: standardize RPC URL construction across the codebase (#3801)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on fixing the RPC URL construction for chains in the `thirdweb` package.

### Detailed summary
- Updated RPC URL construction in `IFrameWallet` for signing transactions and typed data
- Updated RPC URL construction in chain utilities for defining, caching, and converting chains

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

<!-- end pr-codex -->
2024-07-24 19:40:26 +00:00
gregfromstl b15118a34f fix(thirdweb): clean-up send funds styles (#3800)
### TL;DR

This pull request centers the text and aligns the spinner in the SendFunds button within the ConnectWallet screen.

### What changed?

- Added `textAlign: "center"` to the button style to center the text
- Moved the spinner alignment condition to ensure it appears correctly when the button is in a pending state

### How to test?

1. Navigate to the `ConnectWallet` screen
2. Trigger the `SendFunds` action
3. Verify that the button text is centered and the spinner is correctly aligned during pending state

### Why make this change?

This change improves the UI by ensuring the button text is consistently centered and the spinner is appropriately aligned during the fund sending process.

---

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on making minor style fixes on the Connect UI Send Funds page.

### Detailed summary
- Updated the text element to be centered and multiline with a red color for error messages
- Adjusted the conditional rendering of the spinner to display only when sending funds is pending

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

<!-- end pr-codex -->
2024-07-24 19:17:08 +00:00
kien-ngo f4d44428b4 Dashboard cleanup (#3789)
- [x] Remove ethers.utils.isAddress
- [x] Remove useBalanceForAddress
- [x] Remove useTransferNativeToken

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates wallet balance functions and address validation in various components.

### Detailed summary
- Updated `getWalletBalance` function parameter from `account` to `address`
- Replaced `utils.isAddress` with `isAddress` for address validation
- Updated balance retrieval and address validation in multiple components
- Added new wallet balance hooks for fetching balances
- Refactored deposit functionality to use new wallet balance hooks

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

<!-- end pr-codex -->
2024-07-24 17:50:46 +00:00
jnsdls 634923ae29 [Fix] Handle non-SVG chain icons correctly in opengraph-image component (#3799) 2024-07-24 17:22:02 +00:00
Kien NgoandGitHub 15df5f7cbf Update middleware.ts (#3798) 2024-07-24 15:18:34 +00:00
kien-ngo 105e523ce4 Prebuilt UI: ClaimButton for all thirdweb Drop contracts (#3785)
## 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 a `ClaimButton` component for claiming tokens from thirdweb Drop contracts.

### Detailed summary
- Added `ClaimButton` component for thirdweb Drop contracts
- Defined types for different token claim parameters
- Implemented claim logic for ERC721, ERC1155, and ERC20 tokens
- Added tests for ERC721 and ERC1155 claim scenarios

> The following files were skipped due to too many changes: `packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/ClaimButton/ClaimButton.test.tsx`

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

<!-- end pr-codex -->
2024-07-24 10:19:35 +00:00
MananTank fc23b90c34 Dashboard color fixes (#3781)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to update text colors across the application for better consistency and clarity.

### Detailed summary
- Updated text color classes to `text-success-text` and `text-destructive-text` for better clarity and consistency.
- Renamed background color class from `bg-destructive` to `bg-warning` for better semantics.
- Adjusted CSS variables for text colors to enhance readability and maintain consistency.

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

<!-- end pr-codex -->
2024-07-24 07:55:31 +00:00
gregfromstl a560af22a1 fix(dashboard): audited contract icon alignment (#3793)
### TL;DR

Improve the UI layout of the contract-card component by adjusting spacing and removing unnecessary Skeleton wrappers.

### What changed?

The `gap` property for the `Flex` component was increased from 0 to 1 to provide better spacing. The `Skeleton` wrappers around the `Icon` and `Text` components were removed for a cleaner design.

### How to test?

1. Go to the dashboard and navigate to the explore section.
2. Check the contract-card components and observe the new spacing and the absence of loading skeletons around the `Icon` and `Text`.

### Why make this change?

The change is aimed at improving the user interface by making the contract-card component cleaner and visually more appealing.

---
2024-07-24 07:43:09 +00:00
Joaquim VergesandGitHub c51f7857e2 fix(gas): handle Polygon Amoy Gas Station fee data (#3796) 2024-07-24 13:29:09 +12:00
Manan TankandGitHub 5fabe66613 Fix XDC network sendTransaction issue (#3792) 2024-07-24 01:54:34 +05:30
kien-ngo 891bc988d6 update middleware to handle chainId: 404 (#3786)
<!-- start pr-codex -->

## PR-Codex overview
This PR ensures that the `possibleChainId` is not rewritten to the slug if it equals 404.

### Detailed summary
- Updated condition to exclude rewriting `possibleChainId` if it equals 404.

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

<!-- end pr-codex -->
2024-07-23 04:19:44 +00:00
MananTank 934ab63f6a Fix import contract not working in dashboard (#3784)
<!-- start pr-codex -->

## PR-Codex overview
This PR updates the `useRegistry.ts` and `hooks.ts` files to include a new `account` value of `300000n`.

### Detailed summary
- Updated `useRegistry.ts` and `hooks.ts` with `account: 300000n` value
- Called `deployContext.nextStep()` after the changes

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

<!-- end pr-codex -->
2024-07-22 23:42:27 +00:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>GitHub Action
e0e4ce016c Version Packages (#3768)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <[email protected]>
2024-07-23 10:22:02 +12:00
gregfromstl d3c83023f8 Auth Refactor (#3779)
### TL;DR
Improved the in-app wallet sign-in speed by refactoring OAuth path handling to make it more generic and efficient.

### What changed?
- Standardized the OAuth path handling to make it more generic and reusable across multiple providers.
- Updated `getLoginPath` to `getSocialAuthLoginPath` for OAuth providers like Google, Facebook, Apple, and Discord.
- Improved login speed and reduced redundancy by streamlining the OAuth path logic.
- Removed outdated and redundant code related to individual OAuth provider handling.

### How to test?
1. Test the sign-in process using various OAuth providers such as Google, Facebook, Apple, and Discord.
2. Ensure the redirection and sign-in speed are improved.
3. Verify that the in-app wallet sign-in works seamlessly without any errors.

### Why make this change?
The changes were necessary to optimize and standardize the OAuth sign-in process, improving the overall user experience. The previous implementation had redundant code for individual providers, which was refactored to be more efficient and easier to maintain.

---

<!-- start pr-codex -->

---

## PR-Codex overview
This PR improves in-app wallet sign-in speed by updating authentication strategies and paths.

### Detailed summary
- Updated OAuth authentication strategy to `SocialAuthOption`
- Improved login path retrieval for social authentication providers
- Refactored Discord-specific authentication to generic OAuth approach

> The following files were skipped due to too many changes: `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-07-22 20:58:26 +00:00
gregfromstl a9a3f0f423 fix(deploy): add missing version argument in computeDeploymentInfoFromContractId function (#3769)
Fix deterministic deploys with specified versions by adding the 'version' argument to the 'computeDeploymentInfoFromContractId' function.

---

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on fixing deterministic deploys with specified versions in the `compute-published-contract-deploy-info.ts` file under `thirdweb` package.

### Detailed summary
- Added `version` field to `computePublishedContractDeployInfo` function parameters.
- Utilizes the specified version for deterministic deployments.

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

<!-- end pr-codex -->
2024-07-22 17:34:29 +00:00
jnsdls 3de2dce384 [Feature] Add placeholder chain to provider setup and custom SDK context, make middleware method async (#3773)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to enhance the app setup process by adding placeholder chains and improving dynamic routing.

### Detailed summary
- Added `PLACEHOLDER_CHAIN` object in `Billing.tsx` and `provider-setup.tsx`
- Updated context with placeholder chain if configured chains are empty
- Added dynamic routing logic in `middleware.ts` for chain IDs

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

<!-- end pr-codex -->
2024-07-22 15:28:44 +00:00
kien-ngo 4d392efc0c Hotfix: avoid page crash on loading :chainId/contractAddress (#3772)
<!-- start pr-codex -->

## PR-Codex overview
This PR updates a conditional check in the file `apps/dashboard/src/pages/[chain_id]/[...paths].tsx`.

### Detailed summary
- Updated conditional check for `configuredChain` to compare `getDashboardChainRpc` values for different chain IDs.

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

<!-- end pr-codex -->
2024-07-22 15:07:34 +00:00
kumaryash90 f082af0403 Proxy resolution with storage slot (#3687)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on fixing proxy resolution in the `thirdweb` package. It includes updates to contract deployment and implementation extraction logic.

### Detailed summary
- Fixed proxy resolution in `resolveImplementation.ts`
- Added tests for extracting implementation address
- Updated proxy bytecode and constructor ABI for ERC1967 proxy
- Added `DUMMY_BYTECODE` for contract deployment

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

<!-- end pr-codex -->
2024-07-22 14:24:10 +00:00
jnsdls b07f9207a4 [Feature] Add Ecosystem Wallet Pricing Card component and integrate it across pages (#3770) 2024-07-22 10:52:50 +00:00
kien-ngo 9f555cab0d Dashboard: removal of @thirdweb-dev/chains (#3766)
## 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
The focus of this PR is to update chain definitions and RPC URLs, improve network configuration, and enhance contract component utilities.

### Detailed summary
- Updated chain definitions for various networks
- Adjusted RPC URLs in network configuration
- Enhanced contract component utilities with new features

> The following files were skipped due to too many changes: `packages/thirdweb/src/chains/chain-definitions/polygon-zkevm-testnet.ts`, `packages/thirdweb/src/chains/chain-definitions/scroll-sepolia-testnet.ts`, `packages/thirdweb/src/chains/chain-definitions/manta-pacific-testnet.ts`, `packages/thirdweb/src/chains/chain-definitions/scroll-alpha-testnet.ts`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useActiveChainId.tsx`, `apps/dashboard/src/lib/ens.ts`, `apps/dashboard/src/components/custom-contract/contract-header/contract-metadata.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useApi.ts`, `apps/dashboard/package.json`, `apps/dashboard/src/components/custom-contract/contract-header/metadata-header.tsx`, `apps/dashboard/src/constants/chains.ts`, `apps/dashboard/src/hooks/chains/configureChains.ts`, `apps/dashboard/src/lib/rpc.ts`, `apps/dashboard/src/pages/[chain_id]/[...paths].tsx`, `apps/dashboard/src/utils/tx-frame.ts`, `.changeset/beige-seas-design.md`, `apps/dashboard/src/utils/fetchChain.ts`, `apps/dashboard/src/components/settings/Account/Billing/CreditsItem.tsx`, `apps/dashboard/src/pages/publish/[...paths].tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useFavoriteChains.ts`, `apps/dashboard/src/components/wallets/ConnectWalletPlayground/PreviewThirdwebProvider.tsx`, `apps/dashboard/src/lib/v5-adapter.ts`, `apps/dashboard/src/pages/profile/[profileAddress].tsx`, `apps/dashboard/src/@3rdweb-sdk/react/components/popularChains.ts`, `apps/dashboard/src/components/engine/overview/transactions-table.tsx`, `apps/dashboard/src/components/explore/contract-card/index.tsx`, `apps/dashboard/src/pages/api/revalidate/publish.ts`, `apps/dashboard/src/components/smart-wallets/AccountFactories/factory-contracts.tsx`, `apps/dashboard/src/components/smart-wallets/AccountFactories/index.tsx`, `apps/dashboard/src/components/contract-components/contract-publish-form/index.tsx`, `apps/dashboard/src/contexts/all-chains.tsx`, `apps/dashboard/src/components/app-layouts/provider-setup.tsx`, `apps/dashboard/src/components/shared/DeprecatedAlert.tsx`, `apps/dashboard/src/contract-ui/tabs/embed/components/embed-setup.tsx`, `apps/dashboard/src/constants/currencies.ts`, `packages/thirdweb/src/exports/chains.ts`, `apps/dashboard/src/contexts/configured-chains.tsx`, `apps/dashboard/src/components/contract-components/hooks.ts`, `pnpm-lock.yaml`, `apps/dashboard/src/lib/wallet/nfts/types.ts`

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

<!-- end pr-codex -->
2024-07-22 10:22:37 +00:00
kien-ngo 26d825bc4f Lens extensions (no Playground) (#3764)
<!-- start pr-codex -->

## PR-Codex overview
This PR adds extension support for the Lens Protocol, updates text in a component, and includes various changes related to Lens metadata handling.

### Detailed summary
- Added extension support for Lens Protocol
- Updated text in SponsorshipPolicies component
- Added functions in various Lens-related JSON files
- Modified test files to use `MAX_UINT256`
- Updated Lens profile schema and metadata attributes
- Added tests for Lens protocol functions and metadata retrieval

> The following files were skipped due to too many changes: `packages/thirdweb/src/extensions/lens/read/getHandleFromProfileId.test.ts`, `packages/thirdweb/src/extensions/lens/consts.ts`, `packages/thirdweb/src/extensions/lens/read/getHandleFromProfileId.ts`, `packages/thirdweb/src/extensions/lens/read/getProfileMetadata.ts`, `packages/thirdweb/src/extensions/lens/__generated__/FollowNFT/read/getFollowerCount.ts`, `packages/thirdweb/src/extensions/lens/__generated__/LensHandle/read/getHandleTokenURIContract.ts`, `packages/thirdweb/src/extensions/lens/read/getFullProfile.ts`, `packages/thirdweb/src/extensions/lens/__generated__/LensHub/read/nonces.ts`, `packages/thirdweb/src/extensions/lens/__generated__/LensHub/read/exists.ts`, `packages/thirdweb/src/extensions/lens/__generated__/TokenHandleRegistry/read/nonces.ts`, `packages/thirdweb/src/extensions/lens/__generated__/TokenHandleRegistry/read/resolve.ts`, `packages/thirdweb/src/extensions/lens/__generated__/LensHandle/read/getHandle.ts`, `packages/thirdweb/src/extensions/lens/__generated__/LensHandle/read/getTokenId.ts`, `packages/thirdweb/src/extensions/lens/__generated__/LensHandle/read/getLocalName.ts`, `packages/thirdweb/src/extensions/lens/__generated__/FollowNFT/read/isFollowing.ts`, `packages/thirdweb/src/extensions/lens/__generated__/LensHub/read/tokenDataOf.ts`, `packages/thirdweb/src/extensions/lens/__generated__/LensHub/read/mintTimestampOf.ts`, `packages/thirdweb/src/extensions/lens/__generated__/FollowNFT/read/mintTimestampOf.ts`, `packages/thirdweb/src/extensions/lens/__generated__/ModuleRegistry/read/getModuleTypes.ts`, `packages/thirdweb/src/extensions/lens/__generated__/TokenHandleRegistry/read/getDefaultHandle.ts`, `packages/thirdweb/src/extensions/lens/__generated__/FollowNFT/read/getFollowTokenId.ts`, `packages/thirdweb/src/extensions/lens/__generated__/LensHub/read/getContentURI.ts`, `packages/thirdweb/src/extensions/lens/__generated__/FollowNFT/read/getFollowTimestamp.ts`, `packages/thirdweb/src/extensions/lens/__generated__/ModuleRegistry/read/isModuleRegistered.ts`, `packages/thirdweb/src/extensions/lens/__generated__/FollowNFT/read/getFollowerProfileId.ts`, `packages/thirdweb/src/extensions/lens/__generated__/FollowNFT/read/getFollowData.ts`, `packages/thirdweb/src/extensions/lens/__generated__/LensHub/read/getProfile.ts`, `packages/thirdweb/src/extensions/lens/__generated__/LensHub/read/getProfileIdByHandleHash.ts`, `packages/thirdweb/src/extensions/lens/__generated__/ModuleRegistry/read/isErc20CurrencyRegistered.ts`, `packages/thirdweb/src/extensions/lens/__generated__/FollowNFT/read/getOriginalFollowTimestamp.ts`, `packages/thirdweb/src/extensions/lens/__generated__/ModuleRegistry/read/isModuleRegisteredAs.ts`, `packages/thirdweb/src/extensions/lens/__generated__/FollowNFT/read/getProfileIdAllowedToRecover.ts`, `packages/thirdweb/src/extensions/lens/__generated__/LensHub/read/getPublication.ts`, `packages/thirdweb/src/exports/extensions/lens.ts`

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

<!-- end pr-codex -->
2024-07-21 08:29:50 +00:00
kien-ngo 11b2ad05ad Remove @thirdweb-dev/sdk from dashboard (partially) (#3767)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to expose `roleMap` and `getRoleHash` functions.

### Detailed summary
- Exposed `roleMap` and `getRoleHash` functions in `permissions.ts`
- Updated imports to use `thirdweb` instead of `@thirdweb-dev/sdk`
- Added `roleMap` import in `permissions` component
- Updated address resolution and validation in `airdrop-upload.tsx`

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

<!-- end pr-codex -->
2024-07-20 19:43:03 +00:00
kien-ngo a580e6a71e [Dashboard to v5] Remove ethers.constants, some ethers.utils, some other things (#3765)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to refactor address-related functions and constants, consolidating them under `thirdweb` library.

### Detailed summary
- Refactored address-related functions and constants to use `thirdweb` library
- Updated imports and usage of `isAddress`, `ZERO_ADDRESS`, and `NATIVE_TOKEN_ADDRESS`
- Replaced `constants.AddressZero` with `ZERO_ADDRESS` where applicable

> The following files were skipped due to too many changes: `apps/dashboard/src/contract-ui/tabs/nfts/components/claim-tab.tsx`, `apps/dashboard/src/contract-ui/tabs/claim-conditions/components/claim-conditions-form/index.tsx`, `apps/dashboard/src/contract-ui/tabs/nfts/components/airdrop-upload.tsx`, `apps/dashboard/src/contract-ui/tabs/claim-conditions/components/snapshot-upload.tsx`, `apps/dashboard/src/contract-ui/tabs/split/page.tsx`, `apps/dashboard/src/contract-ui/tabs/permissions/components/permissions-editor.tsx`, `apps/dashboard/src/components/shared/CurrencySelector.tsx`, `apps/dashboard/src/contract-ui/tabs/permissions/components/contract-permission.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/cache-keys.ts`

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

<!-- end pr-codex -->
2024-07-20 18:51:54 +00:00
kien-ngo 0148864ebc Playground Auth without Supabase example (#3757)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to enhance authentication and authorization features using Thirdweb for the `playground-web` app.

### Detailed summary
- Updated `client.ts` to handle secret key for Thirdweb client
- Modified authentication logic in `auth-button.tsx` and `basic-auth.tsx`
- Added gated content feature in `gated-content.tsx`
- Updated page layout and content for authentication in `page.tsx`

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

<!-- end pr-codex -->
2024-07-20 01:40:38 +00:00
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>GitHub Action
9a29beb460 Version Packages (#3749)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <[email protected]>
2024-07-20 13:32:24 +12:00
MananTank 6a94696c7e Fix Wallet switcher icon position in wallet details modal (#3762)
<!-- start pr-codex -->

## PR-Codex overview
This PR fixes the wallet switcher icon position in the wallet details modal.

### Detailed summary
- Adjusted the wallet switcher icon position in `Modal.tsx`
- Updated the `borderRadius` in `buttons.tsx`
- Added a new `ShuffleIconLucide` component in `ShuffleIconLucide.tsx`
- Replaced `ShuffleIcon` with `ShuffleIconLucide` in `Details.tsx`

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

<!-- end pr-codex -->
2024-07-19 22:52:06 +00:00
kumaryash90 d6b2c259d9 Register zksync contract on multichain registry after deployment (#3717)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to enhance the deployment process of contracts by adding a gas override option and improving the registration process on the multichain registry for ZkSync contracts.

### Detailed summary
- Added `gasOverride` option for contract deployment
- Improved ZkSync contract registration process
- Removed unnecessary contract registration function
- Updated contract deployment handling for ZkSync
- Refactored contract deployment logic and metadata handling

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

<!-- end pr-codex -->
2024-07-19 22:35:39 +00:00
Manan TankandGitHub 742207c8fe Fix Get started Billing form edit button not working (#3759) 2024-07-19 21:53:07 +00:00
gregfromstl ec3405b307 feat(react-native): add discord login (#3716)
<!-- start pr-codex -->

## PR-Codex overview
This PR adds Discord login functionality to the React Native SDK, including new paths, UI changes, and authentication methods.

### Detailed summary
- Added Discord login feature to React Native SDK
- Updated UI components for Discord login
- Implemented Discord authentication methods
- Created new paths for Discord login
- Updated authentication middleware for Discord integration

> The following files were skipped due to too many changes: `packages/thirdweb/src/wallets/in-app/native/helpers/wallet/recoveryCode.ts`

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

<!-- end pr-codex -->
2024-07-19 21:19:31 +00:00
ElasticBottle 31ee4e53e2 feat(thirdweb): Add support for discord auth in in app wallet (#3678)
## 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 Discord login option to thirdweb in-app and ecosystem wallets.

### Detailed summary
- Added Discord login option to in-app and ecosystem wallets
- Updated authentication constants and locales
- Implemented Discord login functionality
- Updated wallet images and social login components

> The following files were skipped due to too many changes: `packages/thirdweb/src/react/web/wallets/shared/ConnectWalletSocialOptions.tsx`, `packages/thirdweb/src/react/native/ui/icons/svgs.ts`, `packages/thirdweb/src/wallets/in-app/web/lib/auth/discord.ts`

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

<!-- end pr-codex -->
2024-07-19 21:19:27 +00:00
gregfromstl ec5ef50085 fix: correct typo in addSessionKey.ts file and update jsdocs with contract parameter (#3758) 2024-07-19 21:03:37 +00:00
gregfromstl 83cd9e5a8f fix(transaction): handle undefined predefinedGas value in estimate-gas and add test for 0 gas value (#3761)
### TL;DR

This pull request addresses a bug in the `estimateGas` function where a gas value of `0` is now respected instead of being overridden.

### What changed?

- Updated `estimateGas` function to properly handle and respect a gas value of `0`.
- Added a test case to ensure that a gas value of `0` does not throw an error and is correctly serialized.

### How to test?

- Run unit tests to ensure the new test case passes.

### Why make this change?

This change ensures that transactions explicitly set with a gas value of `0` are respected and not overridden, providing more accurate and expected behavior.

---
2024-07-19 20:41:08 +00:00
gregfromstl d8ea41dd4e fix(dashboard): replace Wrench icon with Pencil icon in partners table (#3760)
## 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
The focus of this PR is to update the icon used for editing partners in the partners table component.

### Detailed summary
- Updated icon for editing partners from `Wrench` to `Pencil` in `partners-table.tsx`

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

<!-- end pr-codex -->
2024-07-19 19:29:03 +00:00
870be083f7 fix(connect-ui): update Connect UI tabs styling with new design enhancements (#3746)
Co-authored-by: gregfromstl <[email protected]>
Co-authored-by: Manan Tank <[email protected]>
2024-07-19 19:18:28 +00:00
kien-ngo 56b34ce197 Allow to add extra call data to prepareContractCall (#3676)
<!-- start pr-codex -->

## PR-Codex overview
This PR enhances the `prepareContractCall` function in the `thirdweb` package to allow adding extra call data to transactions.

### Detailed summary
- Added support for extra call data in `prepareContractCall`
- Introduced internal functions to handle extra call data in transactions
- Updated tests to cover extra call data scenarios

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

<!-- end pr-codex -->
2024-07-19 17:38:36 +00:00
iuwqyir b7295f93c5 use workspace version for service-utils (#3756)
## Problem solved

Reverts back to workspace version for `service-utils` package

## 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
The focus of this PR is to update the dependency resolution for `@thirdweb-dev/service-utils` and `@thirdweb-dev/dynamic-contracts`.

### Detailed summary
- Updated `@thirdweb-dev/service-utils` dependency resolution to `workspace:*`
- Removed specific dependencies for `@thirdweb-dev/[email protected]`
- Updated snapshot for `@thirdweb-dev/[email protected]`

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

<!-- end pr-codex -->
2024-07-19 17:25:24 +00:00
jnsdls 38ce393078 [Feature] Add Rootstock banner and CTA images and update chain metadata (#3755) 2024-07-19 17:09:30 +00:00
gregfromstl fde7ad5e93 fix(dashboard): add update partner form and refactor domain validation (#3747)
### TL;DR

This PR introduces new functionalities and updates aimed at improving partner management within the ecosystem section of the dashboard.

### What changed?

1. **Partner Update Feature**: Added a new form and modal to enable the updating of partner details, including name, domains, bundle IDs, and permissions.
2. **Refactored Domain Validation**: Moved domain validation regex to a constants file for improved code maintainability.
3. **UI Enhancements**: Updated UI components to include an edit button for partner details in the partners' table.
4. **Code Cleanup**: Removed redundant code and improved component structure for better readability.

### How to test?

1. Navigate to the ecosystem section in the dashboard.
2. Select a partner and click the edit button to open the update modal.
3. Update the partner details and save changes. Ensure that the details are updated correctly in the database and UI.

### Why make this change?

This change aims to enhance the user experience by allowing easier management of ecosystem partners directly from the dashboard. It also improves code maintainability and readability by refactoring existing components and validation logic.

---

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates partner permission handling and refactors form validation in the ecosystem dashboard.

### Detailed summary
- Added `PartnerPermission` type and `isValidPermission` function
- Updated partner object permissions to use `PartnerPermission`
- Refactored form validation using `partnerFormSchema`
- Added `useUpdatePartner` hook for updating partners
- Updated UI components and modals for partner management

> The following files were skipped due to too many changes: `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/[slug]/(active)/components/server/partners-table.tsx`, `apps/dashboard/src/app/(dashboard)/dashboard/connect/ecosystem/[slug]/(active)/components/client/update-partner-form.client.tsx`

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

<!-- end pr-codex -->
2024-07-19 16:38:07 +00:00
gregfromstl 713ff296fd fix(tests): update wait function test precision (#3754)
### TL;DR
Improve the precision of the wait function tests by changing the expectation from a simple greater-than-or-equal check to an absolute difference check within a margin of error of 10 milliseconds.

### What changed?
In `wait.test.ts` files located in the `thirdweb/src/react/core/utils/` and `thirdweb/src/utils/promise/` paths, the expectation `expect(elapsedTime).toBeGreaterThanOrEqual(waitTime)` was updated to `expect(Math.abs(elapsedTime - waitTime)).toBeLessThan(10)` to improve test accuracy by accounting for slight timing variations.

### How to test?
Run the test suites located in `thirdweb/src/react/core/utils/wait.test.ts` and `thirdweb/src/utils/promise/wait.test.ts` to ensure that they pass successfully with the updated precision checks.

### Why make this change?
The motivation behind this change is to enhance the reliability and precision of the wait function tests by accommodating minor variations in elapsed time, which can occur due to factors like system load and execution context.

---
2024-07-19 16:23:58 +00:00
iuwqyir af4acc4319 add chainsaw service description (#3745)
## Problem solved

Added chainsaw service description so it can be used for auth

## 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 a new service called `chainsaw` to the service-utils package and updates dependencies and configurations related to it.

### Detailed summary
- Added `chainsaw` service definition in `service-utils`
- Updated dependencies and configurations for the `chainsaw` service
- Updated `service-utils` version to `0.4.36` in various files and lock files

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

<!-- end pr-codex -->
2024-07-19 15:56:20 +00:00
kien-ngo 091b6099e7 Update ancient8 banner (#3753)
## 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 updates banner images and gradient styling in the dashboard for a better visual experience.

### Detailed summary
- Deleted `ancient8-banner.jpg` and updated to `ancient8-banner.png` for better quality.
- Changed gradient styling in the header for improved visual appeal.
- Updated imports of banner images in `utils.ts` to match file extensions.

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

<!-- end pr-codex -->
2024-07-19 15:04:09 +00:00
joaquim-verges aba1266431 fix(thirdweb): Handle minimum purchase amount errors in buy with crypto flow (#3751)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on handling the minimum amount in the buy-to-crypto flow.

### Detailed summary
- Updated error handling messages for buy with fiat and crypto flows
- Added functions to set token amount and track editing status
- Improved error messages display for minimum purchase amount
- Implemented functionality to set the minimum amount in the UI

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

<!-- end pr-codex -->
2024-07-19 05:23:39 +00:00
Joaquim VergesandGitHub 24bcee24ea fix(RN): correct disconnect button color in light mode and other minor UI adjustments (#3748) 2024-07-19 14:52:02 +12:00
joaquim-verges c6741b42cd feat(pay): add async ERC20 value property to transaction options (#3661)
### TL;DR

This PR introduces support for ERC20 tokens in the transaction flow, allowing users to seamlessly interact with contracts that require ERC20 token payments.

### What changed?

1. Added ERC20 token handling in the `useSendTransaction` hook to check balance and prompt users to buy ERC20 if needed.
2. Integrated ERC20 token fields, such as `erc20Value`, into the transaction preparation and cost estimation processes.
3. Updated various contract-writing scripts to include `erc20Value` overrides where necessary.
4. Enhanced the UI in `TxModal` and `BuyScreen` to display and process ERC20 token transactions.
5. Added tests for ERC20 token transactions in the `drop721.test.ts` file.
6. Extended documentation and examples to include ERC20 token use cases in transaction flows.

### How to test?

1. Run the unit tests in the `drop721.test.ts` file to ensure ERC20 transactions are correctly processed.
2. Use the `useSendTransaction` hook in a sample component and attempt transactions with both native and ERC20 tokens.
3. Verify that the ERC20 token purchase prompt appears when balance is insufficient.

### Why make this change?

Adding ERC20 support enhances the flexibility and functionality of the transaction flow, making it easier for users to interact with a wider range of smart contracts that require different types of token payments.

---

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on handling ERC20 transaction values in Pay components.

### Detailed summary
- Added `tokenDecimals` in `types.ts`
- Modified `title` in `PayEmbed.tsx` and `transferBatch.ts`
- Added `overrides` in `transfer.ts`, `transferFrom.ts`, `approve.ts`
- Added `erc20Value` in various transaction files
- Updated `prepare-transaction.ts` with `erc20Value`
- Added `erc20Value` in generated files for different ERC20 transactions

> The following files were skipped due to too many changes: `packages/thirdweb/src/extensions/common/__generated__/IMulticall/write/multicall.ts`, `packages/thirdweb/src/extensions/erc20/__generated__/IMintableERC20/write/mintTo.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/IBurnableERC721/write/burn.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/IStaking721/write/withdraw.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IBundler/write/register.ts`, `packages/thirdweb/src/extensions/airdrop/__generated__/Airdrop/write/airdropERC20.ts`, `packages/thirdweb/src/extensions/airdrop/__generated__/Airdrop/write/claimERC1155.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IEntryPoint/write/addStake.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/IDelayedReveal/write/reveal.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/IERC721A/write/transferFrom.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IKeyGateway/write/addFor.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IMarketplace/write/buy.ts`, `packages/thirdweb/src/extensions/airdrop/__generated__/Airdrop/write/airdropERC721.ts`, `packages/thirdweb/src/extensions/airdrop/__generated__/Airdrop/write/setMerkleRoot.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IBurnableERC1155/write/burn.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IStaking1155/write/withdraw.ts`, `packages/thirdweb/src/extensions/erc20/__generated__/IBurnableERC20/write/burnFrom.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IEntryPoint/write/depositTo.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IEntryPoint/write/handleOps.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/IClaimableERC721/write/claim.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/IMintableERC721/write/mintTo.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IIdGateway/write/register.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IIdRegistry/write/recover.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IKeyRegistry/write/remove.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IOffers/write/makeOffer.ts`, `packages/thirdweb/src/extensions/airdrop/__generated__/Airdrop/write/airdropERC1155.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IEntryPoint/write/withdrawTo.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IIdRegistry/write/transfer.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IMarketplace/write/offer.ts`, `packages/thirdweb/src/extensions/modular/__generated__/ModularCore/write/grantRoles.ts`, `packages/thirdweb/src/extensions/prebuilts/__generated__/DropERC20/write/initialize.ts`, `packages/thirdweb/src/extensions/uniswap/__generated__/ISwapRouter/write/exactInput.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IClaimableERC1155/write/claim.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IMintableERC1155/write/mintTo.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IAccount/write/validateUserOp.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/IDrop/write/setClaimConditions.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/INFTMetadata/write/setTokenURI.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IStorageRegistry/write/rent.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IOffers/write/acceptOffer.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IOffers/write/cancelOffer.ts`, `packages/thirdweb/src/extensions/modular/__generated__/ModularCore/write/revokeRoles.ts`, `packages/thirdweb/src/extensions/prebuilts/__generated__/DropERC721/write/initialize.ts`, `packages/thirdweb/src/extensions/prebuilts/__generated__/TokenERC20/write/initialize.ts`, `packages/thirdweb/src/extensions/uniswap/__generated__/IQuoter/write/quoteExactInput.ts`, `packages/thirdweb/src/extensions/uniswap/__generated__/ISwapRouter/write/exactOutput.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/INFTMetadata/write/setTokenURI.ts`, `packages/thirdweb/src/extensions/erc20/__generated__/IAirdropERC20/write/airdropERC20.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/IERC721A/write/safeTransferFrom.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IIdGateway/write/registerFor.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IIdRegistry/write/recoverFor.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IKeyRegistry/write/removeFor.ts`, `packages/thirdweb/src/extensions/multicall3/__generated__/IMulticall3/write/aggregate.ts`, `packages/thirdweb/src/extensions/prebuilts/__generated__/DropERC1155/write/initialize.ts`, `packages/thirdweb/src/extensions/prebuilts/__generated__/Marketplace/write/initialize.ts`, `packages/thirdweb/src/extensions/prebuilts/__generated__/TokenERC721/write/initialize.ts`, `packages/thirdweb/src/extensions/thirdweb/__generated__/IRulesEngine/write/deleteRule.ts`, `packages/thirdweb/src/extensions/uniswap/__generated__/IQuoter/write/quoteExactOutput.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IERC1155/write/safeTransferFrom.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IStaking1155/write/claimRewards.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IEntryPoint/write/withdrawStake.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/IERC721A/write/setApprovalForAll.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IIdRegistry/write/transferFor.ts`, `packages/thirdweb/src/extensions/modular/__generated__/ModularCore/write/renounceRoles.ts`, `packages/thirdweb/src/extensions/multicall3/__generated__/IMulticall3/write/aggregate3.ts`, `packages/thirdweb/src/extensions/prebuilts/__generated__/TokenERC1155/write/initialize.ts`, `packages/thirdweb/src/extensions/airdrop/__generated__/Airdrop/write/airdropNativeToken.ts`, `packages/thirdweb/src/extensions/common/__generated__/IRoyaltyPayments/write/getRoyalty.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IBurnableERC1155/write/burnBatch.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IERC1155/write/setApprovalForAll.ts`, `packages/thirdweb/src/extensions/erc20/__generated__/IAirdropERC20Claimable/write/claim.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IEntryPoint/write/incrementNonce.ts`, `packages/thirdweb/src/extensions/permissions/__generated__/IPermissions/write/grantRole.ts`, `packages/thirdweb/src/extensions/thirdweb/__generated__/ITWMultichainRegistry/write/add.ts`, `packages/thirdweb/src/extensions/uniswap/__generated__/IUniswapV3Factory/write/setOwner.ts`, `packages/thirdweb/src/extensions/erc20/__generated__/IDropERC20/write/setClaimConditions.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/DropERC721/write/setMaxTotalSupply.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/IAirdropERC721/write/airdropERC721.ts`, `packages/thirdweb/src/extensions/multicall3/__generated__/IMulticall3/write/tryAggregate.ts`, `packages/thirdweb/src/extensions/permissions/__generated__/IPermissions/write/revokeRole.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IDrop1155/write/setClaimConditions.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IEntryPoint/write/getSenderAddress.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IEntryPoint/write/simulateHandleOp.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/DropERC721/write/freezeBatchBaseURI.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/DropERC721/write/updateBatchBaseURI.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/IAirdropERC721Claimable/write/claim.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/INFTStake/write/depositRewardTokens.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IStorageRegistry/write/batchRent.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IMarketplace/write/acceptOffer.ts`, `packages/thirdweb/src/extensions/modular/__generated__/ModularCore/write/installExtension.ts`, `packages/thirdweb/src/extensions/uniswap/__generated__/ISwapRouter/write/exactInputSingle.ts`, `packages/thirdweb/src/extensions/uniswap/__generated__/IUniswapV3Factory/write/createPool.ts`, `packages/thirdweb/src/extensions/common/__generated__/IRoyalty/write/setDefaultRoyaltyInfo.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/DropERC1155/write/setMaxTotalSupply.ts`, `packages/thirdweb/src/extensions/erc20/__generated__/ITokenStake/write/depositRewardTokens.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IAccountFactory/write/createAccount.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IAccountFactory/write/onSignerAdded.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/INFTStake/write/withdrawRewardTokens.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IMarketplace/write/closeAuction.ts`, `packages/thirdweb/src/extensions/modular/__generated__/IModularCore/write/installExtension.ts`, `packages/thirdweb/src/extensions/modular/__generated__/ModularCore/write/transferOwnership.ts`, `packages/thirdweb/src/extensions/permissions/__generated__/IPermissions/write/renounceRole.ts`, `packages/thirdweb/src/extensions/thirdweb/__generated__/ITWMultichainRegistry/write/remove.ts`, `packages/thirdweb/src/extensions/uniswap/__generated__/IQuoter/write/quoteExactInputSingle.ts`, `packages/thirdweb/src/extensions/uniswap/__generated__/ISwapRouter/write/exactOutputSingle.ts`, `packages/thirdweb/src/extensions/common/__generated__/IPlatformFee/write/setPlatformFeeInfo.ts`, `packages/thirdweb/src/extensions/common/__generated__/IRoyalty/write/setRoyaltyInfoForToken.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/DropERC1155/write/freezeBatchBaseURI.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/DropERC1155/write/updateBatchBaseURI.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IAirdropERC1155/write/airdropERC1155.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IAirdropERC1155Claimable/write/claim.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IERC1155/write/safeBatchTransferFrom.ts`, `packages/thirdweb/src/extensions/erc20/__generated__/ITokenStake/write/withdrawRewardTokens.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IEntryPoint/write/simulateValidation.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IMarketplace/write/createListing.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IMarketplace/write/updateListing.ts`, `packages/thirdweb/src/extensions/modular/__generated__/ModularCore/write/uninstallExtension.ts`, `packages/thirdweb/src/extensions/multicall3/__generated__/IMulticall3/write/aggregate3Value.ts`, `packages/thirdweb/src/extensions/prebuilts/__generated__/OpenEditionERC721/write/initialize.ts`, `packages/thirdweb/src/extensions/uniswap/__generated__/IQuoter/write/quoteExactOutputSingle.ts`, `packages/thirdweb/src/extensions/common/__generated__/IContractMetadata/write/setContractURI.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IAccountFactory/write/onSignerRemoved.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IEntryPoint/write/handleAggregatedOps.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/IERC721Receiver/write/onERC721Received.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IMarketplace/write/setContractURI.ts`, `packages/thirdweb/src/extensions/modular/__generated__/IModularCore/write/uninstallExtension.ts`, `packages/thirdweb/src/extensions/common/__generated__/IRoyaltyPayments/write/setRoyaltyEngine.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/ISharedMetadata/write/setSharedMetadata.ts`, `packages/thirdweb/src/extensions/multicall3/__generated__/IMulticall3/write/blockAndAggregate.ts`, `packages/thirdweb/src/extensions/airdrop/__generated__/Airdrop/write/airdropERC20WithSignature.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IEditionStake/write/depositRewardTokens.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IDirectListings/write/cancelListing.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IDirectListings/write/createListing.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IDirectListings/write/updateListing.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IEnglishAuctions/write/bidInAuction.ts`, `packages/thirdweb/src/extensions/thirdweb/__generated__/IRulesEngine/write/createRuleThreshold.ts`, `packages/thirdweb/src/extensions/thirdweb/__generated__/IThirdwebContract/write/setContractURI.ts`, `packages/thirdweb/src/extensions/uniswap/__generated__/IUniswapV3Factory/write/enableFeeAmount.ts`, `packages/thirdweb/src/extensions/airdrop/__generated__/Airdrop/write/airdropERC721WithSignature.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IERC1155Receiver/write/onERC1155Received.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IEditionStake/write/withdrawRewardTokens.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IPaymaster/write/validatePaymasterUserOp.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IDirectListings/write/buyFromListing.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IEnglishAuctions/write/cancelAuction.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IEnglishAuctions/write/createAuction.ts`, `packages/thirdweb/src/extensions/airdrop/__generated__/Airdrop/write/airdropERC1155WithSignature.ts`, `packages/thirdweb/src/extensions/common/__generated__/IPrimarySale/write/setPrimarySaleRecipient.ts`, `packages/thirdweb/src/extensions/erc20/__generated__/ISignatureMintERC20/write/mintWithSignature.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IIdRegistry/write/changeRecoveryAddress.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IMarketplace/write/setPlatformFeeInfo.ts`, `packages/thirdweb/src/extensions/multicall3/__generated__/IMulticall3/write/tryBlockAndAggregate.ts`, `packages/thirdweb/src/extensions/thirdweb/__generated__/IContractPublisher/write/publishContract.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/DropERC1155/write/setSaleRecipientForToken.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IMarketplace/write/cancelDirectListing.ts`, `packages/thirdweb/src/extensions/permissions/__generated__/IPermissionsEnumerable/write/grantRole.ts`, `packages/thirdweb/src/extensions/thirdweb/__generated__/IRulesEngine/write/setRulesEngineOverride.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/ISharedMetadataBatch/write/setSharedMetadata.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/ISignatureMintERC721/write/mintWithSignature.ts`, `packages/thirdweb/src/extensions/modular/__generated__/ModularCore/write/completeOwnershipHandover.ts`, `packages/thirdweb/src/extensions/permissions/__generated__/IPermissionsEnumerable/write/revokeRole.ts`, `packages/thirdweb/src/extensions/thirdweb/__generated__/IContractPublisher/write/unpublishContract.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IPackVRFDirect/write/openPackAndClaimRewards.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IIdRegistry/write/changeRecoveryAddressFor.ts`, `packages/thirdweb/src/extensions/thirdweb/__generated__/IRulesEngine/write/createRuleMultiplicative.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/IERC1155Receiver/write/onERC1155BatchReceived.ts`, `packages/thirdweb/src/extensions/erc1155/__generated__/ISignatureMintERC1155/write/mintWithSignature.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IIdRegistry/write/transferAndChangeRecovery.ts`, `packages/thirdweb/src/extensions/permissions/__generated__/IPermissionsEnumerable/write/renounceRole.ts`, `packages/thirdweb/src/extensions/erc721/__generated__/ISharedMetadataBatch/write/deleteSharedMetadata.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IEnglishAuctions/write/collectAuctionPayout.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IEnglishAuctions/write/collectAuctionTokens.ts`, `packages/thirdweb/src/extensions/farcaster/__generated__/IIdRegistry/write/transferAndChangeRecoveryFor.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IDirectListings/write/approveBuyerForListing.ts`, `packages/thirdweb/src/extensions/thirdweb/__generated__/IContractPublisher/write/setPublisherProfileUri.ts`, `packages/thirdweb/src/extensions/erc4337/__generated__/IAccountPermissions/write/setPermissionsForSigner.ts`, `packages/thirdweb/src/extensions/common/__generated__/IClaimConditionsSinglePhase/write/setClaimConditions.ts`, `packages/thirdweb/src/extensions/marketplace/__generated__/IDirectListings/write/approveCurrencyForListing.ts`, `packages/thirdweb/src/extensions/thirdweb/__generated__/IContractFactory/write/deployProxyByImplementation.ts`, `packages/thirdweb/src/extensions/erc20/write/sigMint.ts`, `packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.ts`, `packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/pay-transactions/BuyTxHistory.tsx`, `packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/pay-transactions/TxDetailsScreen.tsx`, `packages/thirdweb/src/react/web/ui/ConnectWallet/TransactionsScreen.tsx`, `packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/pay-transactions/FiatDetailsScreen.tsx`, `packages/thirdweb/src/extensions/erc20/write/deposit.ts`, `packages/thirdweb/src/utils/extensions/drops/get-claim-params.ts`, `packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/PayTokenIcon.tsx`, `packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx`, `packages/thirdweb/src/extensions/erc20/write/getApprovalForTransaction.ts`, `apps/playground-web/src/components/pay/transaction-button.tsx`, `packages/thirdweb/src/extensions/erc721/drop721.test.ts`, `packages/thirdweb/src/react/core/hooks/transaction/useSendTransaction.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-07-19 01:57:06 +00:00
1172 changed files with 42006 additions and 7632 deletions
+36 -34
View File
@@ -1,53 +1,55 @@
# Order is important; the last matching pattern takes the most precedence.
# Platform team owns everything by default
# default ownership group
- @jnsdls @joaquim-verges @MananTank @gregfromstl
# legacy packages
legacy_packages/auth/ @jnsdls
legacy_packages/chains/ @jnsdls
legacy_packages/cli/ @jnsdls
legacy_packages/contracts-js/ @jnsdls
legacy_packages/crypto/ @jnsdls
legacy_packages/generated-abis/ @jnsdls
legacy_packages/merkletree/ @jnsdls
legacy_packages/pay/ @jnsdls
legacy_packages/payments/ @jnsdls
legacy_packages/react/ @MananTank @jnsdls
legacy_packages/react-core/ @MananTank @jnsdls
legacy_packages/react-native/ @jnsdls
legacy_packages/react-native-compat/ @jnsdls
legacy_packages/auth/ @jnsdls @joaquim-verges
legacy_packages/chains/ @jnsdls @joaquim-verges
legacy_packages/cli/ @jnsdls @joaquim-verges
legacy_packages/contracts-js/ @jnsdls @joaquim-verges
legacy_packages/crypto/ @jnsdls @joaquim-verges
legacy_packages/generated-abis/ @jnsdls @joaquim-verges
legacy_packages/merkletree/ @jnsdls @joaquim-verges
legacy_packages/pay/ @jnsdls @joaquim-verges
legacy_packages/payments/ @jnsdls @joaquim-verges
legacy_packages/react/ @MananTank @jnsdls @joaquim-verges
legacy_packages/react-core/ @MananTank @jnsdls @joaquim-verges
legacy_packages/react-native/ @jnsdls @joaquim-verges
legacy_packages/react-native-compat/ @jnsdls @joaquim-verges
legacy_packages/sdk/ @joaquim-verges @jnsdls
legacy_packages/storage/ @jnsdls
legacy_packages/wallets/ @MananTank @jnsdls
legacy_packages/storage/ @jnsdls @joaquim-verges
legacy_packages/wallets/ @MananTank @jnsdls @joaquim-verges
# legacy e2e
legacy_e2e/ @jnsdls
# packages
packages/thirdweb/ @joaquim-verges @gregfromstl @jnsdls
## specific thirdweb pieces
packages/thirdweb/src/react/ @joaquim-verges @gregfromstl @MananTank @jnsdls
packages/thirdweb/src/reactive/ @joaquim-verges @gregfromstl @MananTank @jnsdls
packages/thirdweb/src/gas/ @joaquim-verges @jnsdls
packages/thirdweb/src/pay/ @joaquim-verges @gregfromstl @MananTank @jnsdls
packages/typedoc-gen/ @MananTank @jnsdls @joaquim-verges
packages/service-utils/ @arcoraven @jnsdls @joaquim-verges
packages/eslint-config-thirdweb/ @jnsdls @joaquim-verges
packages/tw-tsconfig/ @jnsdls @joaquim-verges
packages/unity-js-bridge/ @joaquim-verges @0xFirekeeper @jnsdls
packages/thirdweb/src/react/ @MananTank
packages/thirdweb/src/reactive/ @MananTank
packages/thirdweb/src/gas/ @joaquim-verges
packages/thirdweb/src/pay/ @MananTank @IDubuque
packages/typedoc-gen/ @MananTank
# owned by phil for now
packages/service-utils/ @arcoraven
packages/eslint-config-thirdweb/ @jnsdls
packages/tw-tsconfig/ @jnsdls
packages/unity-js-bridge/ @joaquim-verges @0xFirekeeper
# apps
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
# .github folder + .changeset + turbo config is owned by jonas for now
scripts/ @jnsdls @joaquim-verges
.github/ @jnsdls @joaquim-verges
.changeset/config.json @jnsdls @joaquim-verges
turbo.json @jnsdls @joaquim-verges
.vscode/ @jnsdls @joaquim-verges
scripts/ @jnsdls
.github/ @jnsdls
.changeset/config.json @jnsdls
turbo.json @jnsdls
-15
View File
@@ -2,18 +2,3 @@
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: ```
+1 -1
View File
@@ -163,7 +163,7 @@ jobs:
cache: false
- name: Run benchmarks
uses: CodSpeedHQ/action@v2
uses: CodSpeedHQ/action@v3
with:
token: ${{ secrets.CODSPEED_TOKEN }}
run: "pnpm bench"
+4 -6
View File
@@ -40,7 +40,6 @@
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-toast": "^1.2.1",
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "1.1.2",
@@ -52,7 +51,6 @@
"@tanstack/react-query": "^4.36.1",
"@tanstack/react-query-persist-client": "^4.36.1",
"@tanstack/react-table": "^8.17.3",
"@thirdweb-dev/chains": "workspace:*",
"@thirdweb-dev/react": "workspace:*",
"@thirdweb-dev/react-core": "workspace:*",
"@thirdweb-dev/sdk": "workspace:*",
@@ -72,11 +70,11 @@
"framer-motion": "^11.2.12",
"fuse.js": "7.0.0",
"idb-keyval": "^6.2.1",
"ipaddr.js": "^2.2.0",
"ioredis": "^5.4.1",
"ipaddr.js": "^2.2.0",
"lottie-react": "^2.4.0",
"lucide-react": "^0.399.0",
"next": "14.2.4",
"next": "14.2.5",
"next-plausible": "^3.12.0",
"next-seo": "^6.5.0",
"next-themes": "^0.3.0",
@@ -110,7 +108,7 @@
"spdx-correct": "^3.2.0",
"spin-wheel-game": "1.0.3-alpha.3",
"swagger-ui-react": "^5.17.14",
"tailwind-merge": "^2.3.0",
"tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7",
"thirdweb": "workspace:*",
"tiny-invariant": "^1.3.3",
@@ -179,4 +177,4 @@
"unreleased versions",
"not UCAndroid > 0"
]
}
}
+7
View File
@@ -275,6 +275,13 @@ function redirects() {
destination: "/dashboard/connect/ecosystem/:slug/permissions",
permanent: false,
},
// temporarily redirect cli login to support page
{
source: "/cli/login",
destination:
"https://support.thirdweb.com/troubleshooting-errors/7Y1BqKNvtLdBv5fZkRZZB3/issue-linking-device-on-the-authorization-page-via-thirdweb-cli/cn9LRA3ax7XCP6uxwRYdvx",
permanent: false,
},
];
}
@@ -0,0 +1,142 @@
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import Link from "next/link";
import {
SiDiscord,
SiGithub,
SiInstagram,
SiLinkedin,
SiReddit,
SiTiktok,
SiX,
SiYoutube,
} from "react-icons/si";
import { ThirdwebMiniLogo } from "../../../app/components/ThirdwebMiniLogo";
type AppFooterProps = {
className?: string;
};
export function AppFooter(props: AppFooterProps) {
return (
<footer
className={cn(
"bg-background border-t border-border py-6 md:py-8 w-full",
props.className,
)}
>
<div className="container flex flex-col gap-4 md:gap-6">
{/* top row */}
<div className="flex flex-col md:flex-row gap-4 md:justify-between md:items-center">
<div className="flex flex-row gap-3 items-center">
<ThirdwebMiniLogo className="h-7" />
<p className="text-sm text-secondary-foreground">© 2024 thirdweb</p>
</div>
<div className="flex flex-row gap-3">
<Button size="icon" variant="ghost" asChild className="size-9">
<Link href="https://github.com/thirdweb-dev" target="_blank">
<SiGithub className="text-secondary-foreground size-5" />
</Link>
</Button>
<Button size="icon" variant="ghost" asChild className="size-9">
<Link href="https://www.tiktok.com/@thirdweb" target="_blank">
<SiTiktok className="text-secondary-foreground size-5" />
</Link>
</Button>
<Button size="icon" variant="ghost" asChild className="size-9">
<Link href="https://www.instagram.com/thirdweb/" target="_blank">
<SiInstagram className="text-secondary-foreground size-5" />
</Link>
</Button>
<Button size="icon" variant="ghost" asChild className="size-9">
<Link
href="hhttps://www.linkedin.com/company/third-web/"
target="_blank"
>
<SiLinkedin className="text-secondary-foreground size-5" />
</Link>
</Button>
<Button size="icon" variant="ghost" asChild className="size-9">
<Link href="https://www.youtube.com/@thirdweb_" target="_blank">
<SiYoutube className="text-secondary-foreground size-5" />
</Link>
</Button>
<Button size="icon" variant="ghost" asChild className="size-9">
<Link href="https://discord.gg/thirdweb" target="_blank">
<SiDiscord className="text-secondary-foreground size-5" />
</Link>
</Button>
<Button size="icon" variant="ghost" asChild className="size-9">
<Link href="https://www.reddit.com/r/thirdweb/" target="_blank">
<SiReddit className="text-secondary-foreground size-5" />
</Link>
</Button>
<Button size="icon" variant="ghost" asChild className="size-9">
<Link href="https://x.com/thirdweb" target="_blank">
<SiX className="text-secondary-foreground size-5" />
</Link>
</Button>
</div>
</div>
{/* bottom row */}
<div className="grid grid-rows-5 grid-cols-2 grid-flow-col gap-2 md:flex md:flex-row md:justify-between">
<Link
className="py-[6px] px-[10px] text-secondary-foreground text-sm hover:underline"
href="/"
>
Home
</Link>
<Link
className="py-[6px] px-[10px] text-secondary-foreground text-sm hover:underline"
href="https://blog.thirdweb.com"
target="_blank"
>
Blog
</Link>
<Link
className="py-[6px] px-[10px] text-secondary-foreground text-sm hover:underline"
href="https://portal.thirdweb.com/changelog"
target="_blank"
>
Changelog
</Link>
<Link
className="py-[6px] px-[10px] text-secondary-foreground text-sm hover:underline"
href="https://feedback.thirdweb.com/"
target="_blank"
>
Feedback
</Link>
<Link
className="py-[6px] px-[10px] text-secondary-foreground text-sm hover:underline"
href="https://thirdweb.com/privacy"
target="_blank"
>
Privacy Policy
</Link>
<Link
className="py-[6px] px-[10px] text-secondary-foreground text-sm hover:underline"
href="https://thirdweb.com/tos"
target="_blank"
>
Terms of Service
</Link>
<Link
className="py-[6px] px-[10px] text-secondary-foreground text-sm hover:underline"
href="https://thirdweb.com/gas"
target="_blank"
>
Gas Estimator
</Link>
<Link
className="py-[6px] px-[10px] text-secondary-foreground text-sm hover:underline"
href="https://thirdweb.com/chainlist"
target="_blank"
>
Chain List
</Link>
</div>
</div>
</footer>
);
}
@@ -1,5 +1,6 @@
"use client";
import { cn } from "../../lib/utils";
import { CopyTextButton } from "./CopyTextButton";
export function CopyAddressButton(props: {
@@ -22,7 +23,7 @@ export function CopyAddressButton(props: {
textToCopy={props.address}
textToShow={shortenedAddress}
tooltip="Copy Address"
className="font-mono text-sm"
className={cn("font-mono text-sm", props.className)}
variant={props.variant}
copyIconPosition={props.copyIconPosition}
/>
@@ -69,7 +69,7 @@ export function DatePickerWithRange(props: {
<DynamicHeight>
<div>
{!isValid && (
<p className="text-sm pt-2 justify-center text-destructive-foreground text-center flex items-center gap-2">
<p className="text-sm pt-2 justify-center text-destructive-text text-center flex items-center gap-2">
<CalendarX2Icon className="h-4 w-4" />
Invalid date range
</p>
@@ -113,9 +113,9 @@ export function DatePickerWithRange(props: {
}
}}
classNames={{
day_range_start: "!bg-inverted",
day_range_start: "!bg-inverted !text-inverted-foreground",
day_range_end:
"!bg-inverted/20 !text-inverted pointer-events-none",
"!bg-inverted/50 !text-inverted-foreground pointer-events-none",
}}
/>
)}
@@ -135,9 +135,9 @@ export function DatePickerWithRange(props: {
}
}}
classNames={{
day_range_end: "!bg-inverted",
day_range_end: "!bg-inverted !text-inverted-foreground",
day_range_start:
"!bg-inverted/20 !text-inverted pointer-events-none",
"!bg-inverted/50 !text-inverted-foreground pointer-events-none",
}}
/>
)}
+5 -2
View File
@@ -41,7 +41,7 @@ const AlertTitle = React.forwardRef<
>(({ className, ...props }, ref) => (
<h5
ref={ref}
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
className={cn("mb-1.5 font-medium leading-none tracking-tight", className)}
{...props}
/>
));
@@ -53,7 +53,10 @@ const AlertDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("text-sm [&_p]:leading-relaxed", className)}
className={cn(
"text-sm [&_p]:leading-relaxed text-secondary-foreground",
className,
)}
{...props}
/>
));
+1 -1
View File
@@ -4,7 +4,7 @@ import type * as React from "react";
import { cn } from "@/lib/utils";
const badgeVariants = cva(
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 leading-4",
"inline-flex items-center rounded-full border border-border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 leading-4",
{
variants: {
variant: {
@@ -0,0 +1,368 @@
"use client";
import * as React from "react";
import * as RechartsPrimitive from "recharts";
import { cn } from "@/lib/utils";
// Format: { THEME_NAME: CSS_SELECTOR }
const THEMES = { light: "", dark: ".dark" } as const;
export type ChartConfig = {
[k in string]: {
label?: React.ReactNode;
icon?: React.ComponentType;
} & (
| { color?: string; theme?: never }
| { color?: never; theme: Record<keyof typeof THEMES, string> }
);
};
type ChartContextProps = {
config: ChartConfig;
};
const ChartContext = React.createContext<ChartContextProps | null>(null);
function useChart() {
const context = React.useContext(ChartContext);
if (!context) {
throw new Error("useChart must be used within a <ChartContainer />");
}
return context;
}
const ChartContainer = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
config: ChartConfig;
children: React.ComponentProps<
typeof RechartsPrimitive.ResponsiveContainer
>["children"];
}
>(({ id, className, children, config, ...props }, ref) => {
const uniqueId = React.useId();
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
return (
<ChartContext.Provider value={{ config }}>
<div
data-chart={chartId}
ref={ref}
className={cn(
"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
className,
)}
{...props}
>
<ChartStyle id={chartId} config={config} />
<RechartsPrimitive.ResponsiveContainer>
{children}
</RechartsPrimitive.ResponsiveContainer>
</div>
</ChartContext.Provider>
);
});
ChartContainer.displayName = "Chart";
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
const colorConfig = Object.entries(config).filter(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
([_, config]) => config.theme || config.color,
);
if (!colorConfig.length) {
return null;
}
return (
<style
// biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation>
dangerouslySetInnerHTML={{
__html: Object.entries(THEMES)
.map(
([theme, prefix]) => `
${prefix} [data-chart=${id}] {
${colorConfig
.map(([key, itemConfig]) => {
const color =
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
itemConfig.color;
return color ? ` --color-${key}: ${color};` : null;
})
.join("\n")}
}
`,
)
.join("\n"),
}}
/>
);
};
const ChartTooltip = RechartsPrimitive.Tooltip;
const ChartTooltipContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
React.ComponentProps<"div"> & {
hideLabel?: boolean;
hideIndicator?: boolean;
indicator?: "line" | "dot" | "dashed";
nameKey?: string;
labelKey?: string;
}
>(
(
{
active,
payload,
className,
indicator = "dot",
hideLabel = false,
hideIndicator = false,
label,
labelFormatter,
labelClassName,
formatter,
color,
nameKey,
labelKey,
},
ref,
) => {
const { config } = useChart();
const tooltipLabel = React.useMemo(() => {
if (hideLabel || !payload?.length) {
return null;
}
const [item] = payload;
const key = `${labelKey || item.dataKey || item.name || "value"}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const value =
!labelKey && typeof label === "string"
? config[label as keyof typeof config]?.label || label
: itemConfig?.label;
if (labelFormatter) {
return (
<div className={cn("font-medium", labelClassName)}>
{labelFormatter(value, payload)}
</div>
);
}
if (!value) {
return null;
}
return <div className={cn("font-medium", labelClassName)}>{value}</div>;
}, [
label,
labelFormatter,
payload,
hideLabel,
labelClassName,
config,
labelKey,
]);
if (!active || !payload?.length) {
return null;
}
const nestLabel = payload.length === 1 && indicator !== "dot";
return (
<div
ref={ref}
className={cn(
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
className,
)}
>
{!nestLabel ? tooltipLabel : null}
<div className="grid gap-1.5">
{payload.map((item, index) => {
const key = `${nameKey || item.name || item.dataKey || "value"}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const indicatorColor = color || item.payload.fill || item.color;
return (
<div
key={item.dataKey}
className={cn(
"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
indicator === "dot" && "items-center",
)}
>
{formatter && item?.value !== undefined && item.name ? (
formatter(item.value, item.name, item, index, item.payload)
) : (
<>
{/* Icon */}
{itemConfig?.icon ? (
<itemConfig.icon />
) : (
!hideIndicator && (
<div
className={cn(
"shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
{
"h-2.5 w-2.5": indicator === "dot",
"w-1": indicator === "line",
"w-0 border-[1.5px] border-dashed bg-transparent":
indicator === "dashed",
"my-0.5": nestLabel && indicator === "dashed",
},
)}
style={
{
"--color-bg": indicatorColor,
"--color-border": indicatorColor,
} as React.CSSProperties
}
/>
)
)}
<div
className={cn(
"flex flex-1 gap-2 justify-between leading-none",
nestLabel ? "items-end" : "items-center",
)}
>
<div className="grid gap-1.5">
{nestLabel ? tooltipLabel : null}
<span className="text-muted-foreground">
{itemConfig?.label || item.name}
</span>
</div>
{item.value && (
<span className="font-mono font-medium tabular-nums text-foreground">
{item.value}
</span>
)}
</div>
</>
)}
</div>
);
})}
</div>
</div>
);
},
);
ChartTooltipContent.displayName = "ChartTooltip";
const ChartLegend = RechartsPrimitive.Legend;
const ChartLegendContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> &
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
hideIcon?: boolean;
nameKey?: string;
}
>(
(
{ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
ref,
) => {
const { config } = useChart();
if (!payload?.length) {
return null;
}
return (
<div
ref={ref}
className={cn(
"flex items-center justify-center gap-4",
verticalAlign === "top" ? "pb-3" : "pt-3",
className,
)}
>
{payload.map((item) => {
const key = `${nameKey || item.dataKey || "value"}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
return (
<div
key={item.value}
className={cn(
"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground",
)}
>
{itemConfig?.icon && !hideIcon ? (
<itemConfig.icon />
) : (
<div
className="h-2 w-2 shrink-0 rounded-[2px]"
style={{
backgroundColor: item.color,
}}
/>
)}
{itemConfig?.label}
</div>
);
})}
</div>
);
},
);
ChartLegendContent.displayName = "ChartLegend";
// Helper to extract item config from a payload.
function getPayloadConfigFromPayload(
config: ChartConfig,
payload: unknown,
key: string,
) {
if (typeof payload !== "object" || payload === null) {
return undefined;
}
const payloadPayload =
"payload" in payload &&
typeof payload.payload === "object" &&
payload.payload !== null
? payload.payload
: undefined;
let configLabelKey: string = key;
if (
key in payload &&
typeof payload[key as keyof typeof payload] === "string"
) {
configLabelKey = payload[key as keyof typeof payload] as string;
} else if (
payloadPayload &&
key in payloadPayload &&
typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
) {
configLabelKey = payloadPayload[
key as keyof typeof payloadPayload
] as string;
}
return configLabelKey in config
? config[configLabelKey]
: config[key as keyof typeof config];
}
export {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
ChartLegend,
ChartLegendContent,
ChartStyle,
};
+13 -6
View File
@@ -21,7 +21,7 @@ const DialogOverlay = React.forwardRef<
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
"fixed inset-0 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className,
)}
{...props}
@@ -38,7 +38,17 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
"fixed grid w-full max-w-lg gap-4 border bg-background p-6 shadow-lg duration-300 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",
// on desktop - vertically and horizontally center the dialog, animate - zoom and fade in
"md:bottom-auto md:left-[50%] md:top-[50%] md:translate-x-[-50%] md:translate-y-[-50%] ",
"md:data-[state=closed]:zoom-out-95 md:data-[state=open]:zoom-in-95 ",
"md:data-[state=closed]:slide-out-to-left-1/2 md:data-[state=closed]:slide-out-to-top-[48%] ",
"md:data-[state=open]:slide-in-from-left-1/2 md:data-[state=open]:slide-in-from-top-[48%] ",
"data-[state=open]:animate-in data-[state=closed]:animate-out",
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className,
)}
{...props}
@@ -58,10 +68,7 @@ const DialogHeader = ({
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className,
)}
className={cn("flex flex-col space-y-1.5 text-left", className)}
{...props}
/>
);
+6 -4
View File
@@ -94,7 +94,7 @@ const FormLabel = React.forwardRef<
return (
<Label
ref={ref}
className={cn(error && "text-destructive", className)}
className={cn(error && "text-destructive-text", className)}
htmlFor={formItemId}
{...props}
/>
@@ -112,12 +112,14 @@ const RequiredFormLabel = React.forwardRef<
<ToolTipLabel label="Required">
<Label
ref={ref}
className={cn(error && "text-destructive", "relative", className)}
className={cn(error && "text-destructive-text", "relative", className)}
htmlFor={formItemId}
{...props}
>
{props.children}
<span className="absolute -top-1.5 -right-2 text-destructive">•</span>
<span className="absolute -top-1.5 -right-2 text-destructive-text">
•
</span>
</Label>
</ToolTipLabel>
);
@@ -179,7 +181,7 @@ const FormMessage = React.forwardRef<
<p
ref={ref}
id={formMessageId}
className={cn("text-sm font-medium text-destructive", className)}
className={cn("text-sm font-medium text-destructive-text", className)}
{...props}
>
{body}
@@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex gap-2 h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
"flex gap-2 h-10 w-full items-center justify-between rounded-md border border-input bg-card px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className,
)}
{...props}
@@ -25,14 +25,14 @@ function SkeletonContainer<T>(props: {
style={props.style}
aria-hidden={isLoading ? "true" : "false"}
className={cn(
isLoading && "animate-pulse rounded-lg bg-muted",
isLoading && "animate-pulse rounded-lg bg-muted inline-block",
props.className,
)}
>
<div className={cn(isLoading && "invisible")}>
<div
className={cn(
"transitino-opacity duration-300",
"transition-opacity duration-300",
isLoading ? "opacity-0" : "opacity-100",
)}
>
@@ -15,7 +15,7 @@ const Toaster = ({ ...props }: ToasterProps) => {
toastOptions={{
classNames: {
toast:
"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg group-[.toaster]:border",
description: "group-[.toast]:text-muted-foreground",
actionButton:
"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
+1 -1
View File
@@ -58,7 +58,7 @@ const TableRow = React.forwardRef<
<tr
ref={ref}
className={cn(
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
"border-b transition-colors data-[state=selected]:bg-muted",
className,
)}
{...props}
+2 -2
View File
@@ -50,7 +50,7 @@ export function TabLinks(props: {
{/* Active line */}
<div
ref={lineRef}
className="absolute left-0 bottom-0 z-10 h-[2px] bg-foreground rounded-lg fade-in-0 animate-in"
className="absolute left-0 bottom-0 h-[2px] bg-foreground rounded-lg fade-in-0 animate-in"
/>
</ScrollShadow>
{/* Bottom line */}
@@ -108,7 +108,7 @@ export function TabButtons(props: {
{/* Active line */}
<div
ref={lineRef}
className="absolute left-0 bottom-0 z-10 h-[2px] bg-foreground rounded-lg fade-in-0 animate-in"
className="absolute left-0 bottom-0 h-[2px] bg-foreground rounded-lg fade-in-0 animate-in"
/>
</ScrollShadow>
{/* Bottom line */}
@@ -1,129 +0,0 @@
"use client";
import * as ToastPrimitives from "@radix-ui/react-toast";
import { type VariantProps, cva } from "class-variance-authority";
import { X } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils";
const ToastProvider = ToastPrimitives.Provider;
const ToastViewport = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Viewport>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Viewport
ref={ref}
className={cn(
"fixed top-0 z-[10000000] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px] gap-4",
className,
)}
{...props}
/>
));
ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
const toastVariants = cva(
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
{
variants: {
variant: {
default: "border bg-background text-foreground",
destructive:
"destructive group border-destructive bg-destructive text-destructive-foreground",
},
},
defaultVariants: {
variant: "default",
},
},
);
const Toast = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
VariantProps<typeof toastVariants>
>(({ className, variant, ...props }, ref) => {
return (
<ToastPrimitives.Root
ref={ref}
className={cn(toastVariants({ variant }), className)}
{...props}
/>
);
});
Toast.displayName = ToastPrimitives.Root.displayName;
const ToastAction = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Action>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Action
ref={ref}
className={cn(
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
className,
)}
{...props}
/>
));
ToastAction.displayName = ToastPrimitives.Action.displayName;
const ToastClose = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Close>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Close
ref={ref}
className={cn(
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
className,
)}
toast-close=""
{...props}
>
<X className="h-4 w-4" />
</ToastPrimitives.Close>
));
ToastClose.displayName = ToastPrimitives.Close.displayName;
const ToastTitle = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Title>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Title
ref={ref}
className={cn("text-sm font-semibold", className)}
{...props}
/>
));
ToastTitle.displayName = ToastPrimitives.Title.displayName;
const ToastDescription = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Description>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Description
ref={ref}
className={cn("text-sm opacity-90", className)}
{...props}
/>
));
ToastDescription.displayName = ToastPrimitives.Description.displayName;
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
type ToastActionElement = React.ReactElement<typeof ToastAction>;
export {
type ToastProps,
type ToastActionElement,
ToastProvider,
ToastViewport,
Toast,
ToastTitle,
ToastDescription,
ToastClose,
ToastAction,
};
@@ -1,31 +0,0 @@
"use client";
import {
Toast,
ToastClose,
ToastDescription,
ToastProvider,
ToastTitle,
ToastViewport,
} from "@/components/ui/toast";
import { useToast } from "@/components/ui/use-toast";
export function Toaster() {
const { toasts } = useToast();
return (
<ToastProvider>
{toasts.map(({ id, title, description, action, ...props }) => (
<Toast key={id} {...props}>
<div className="grid gap-1 z-50">
{title && <ToastTitle>{title}</ToastTitle>}
{description && <ToastDescription>{description}</ToastDescription>}
</div>
{action}
<ToastClose />
</Toast>
))}
<ToastViewport />
</ToastProvider>
);
}
@@ -19,7 +19,7 @@ const TooltipContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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",
"z-50 overflow-hidden rounded-md border border-border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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",
className,
)}
{...props}
@@ -0,0 +1,24 @@
import { useTrack } from "hooks/analytics/useTrack";
import Link from "next/link";
import type React from "react";
export type TrackedLinkProps = React.ComponentProps<typeof Link> & {
category: string;
label?: string;
trackingProps?: Record<string, string>;
};
export function TrackedLinkTW(props: TrackedLinkProps) {
const trackEvent = useTrack();
const { category, label, trackingProps, ...restProps } = props;
return (
<Link
onClick={(e) => {
trackEvent({ category, action: "click", label, ...trackingProps });
props.onClick?.(e);
}}
{...restProps}
/>
);
}
@@ -1,192 +0,0 @@
/* eslint-disable no-restricted-syntax */
"use client";
import { useEffect, useState } from "react";
import type { ToastActionElement, ToastProps } from "@/components/ui/toast";
const TOAST_LIMIT = 5;
const TOAST_REMOVE_DELAY = 5000; // 5 seconds
type ToasterToast = ToastProps & {
id: string;
title?: React.ReactNode;
description?: React.ReactNode;
action?: ToastActionElement;
};
const actionTypes = {
ADD_TOAST: "ADD_TOAST",
UPDATE_TOAST: "UPDATE_TOAST",
DISMISS_TOAST: "DISMISS_TOAST",
REMOVE_TOAST: "REMOVE_TOAST",
} as const;
let count = 0;
function genId() {
count = (count + 1) % Number.MAX_SAFE_INTEGER;
return count.toString();
}
type ActionType = typeof actionTypes;
type Action =
| {
type: ActionType["ADD_TOAST"];
toast: ToasterToast;
}
| {
type: ActionType["UPDATE_TOAST"];
toast: Partial<ToasterToast>;
}
| {
type: ActionType["DISMISS_TOAST"];
toastId?: ToasterToast["id"];
}
| {
type: ActionType["REMOVE_TOAST"];
toastId?: ToasterToast["id"];
};
interface State {
toasts: ToasterToast[];
}
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
const addToRemoveQueue = (toastId: string) => {
if (toastTimeouts.has(toastId)) {
return;
}
const timeout = setTimeout(() => {
toastTimeouts.delete(toastId);
dispatch({
type: "REMOVE_TOAST",
toastId: toastId,
});
}, TOAST_REMOVE_DELAY);
toastTimeouts.set(toastId, timeout);
};
export const reducer = (state: State, action: Action): State => {
switch (action.type) {
case "ADD_TOAST":
return {
...state,
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
};
case "UPDATE_TOAST":
return {
...state,
toasts: state.toasts.map((t) =>
t.id === action.toast.id ? { ...t, ...action.toast } : t,
),
};
case "DISMISS_TOAST": {
const { toastId } = action;
// ! Side effects ! - This could be extracted into a dismissToast() action,
// but I'll keep it here for simplicity
if (toastId) {
addToRemoveQueue(toastId);
} else {
for (const toast of state.toasts) {
addToRemoveQueue(toast.id);
}
}
return {
...state,
toasts: state.toasts.map((t) =>
t.id === toastId || toastId === undefined
? {
...t,
open: false,
}
: t,
),
};
}
case "REMOVE_TOAST":
if (action.toastId === undefined) {
return {
...state,
toasts: [],
};
}
return {
...state,
toasts: state.toasts.filter((t) => t.id !== action.toastId),
};
}
};
const listeners: Array<(state: State) => void> = [];
let memoryState: State = { toasts: [] };
function dispatch(action: Action) {
memoryState = reducer(memoryState, action);
for (const listener of listeners) {
listener(memoryState);
}
}
type Toast = Omit<ToasterToast, "id">;
function toast({ ...props }: Toast) {
const id = genId();
const update = (props: ToasterToast) =>
dispatch({
type: "UPDATE_TOAST",
toast: { ...props, id },
});
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
dispatch({
type: "ADD_TOAST",
toast: {
...props,
id,
open: true,
onOpenChange: (open: boolean) => {
if (!open) dismiss();
},
},
});
return {
id: id,
dismiss,
update,
};
}
function useToast() {
const [state, setState] = useState<State>(memoryState);
// listeners is global, that's fine, I guess?
// we add a listener on mount and remove it on unmount
useEffect(() => {
listeners.push(setState);
return () => {
const index = listeners.indexOf(setState);
if (index > -1) {
listeners.splice(index, 1);
}
};
}, []);
return {
...state,
toast,
dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
};
}
export { useToast, toast };
+31 -8
View File
@@ -4,7 +4,7 @@
@layer base {
:root {
/* bg - nuetral */
/* bg - neutral */
--background: 0 0% 100%;
--secondary: 0 0% 97%;
--muted: 0 0% 95%;
@@ -15,9 +15,9 @@
/* bg - colorful */
--primary: 221.21deg 83.19% 53.33%;
--destructive: 0 84.2% 60.2%;
--success: 142.09 60.56% 80%;
--warning: 40.61deg 96.12% 88%;
--destructive: 0 84.2% 94%;
--success: 142.09 60.56% 90%;
--warning: 40.61deg 96.12% 92%;
/* Text */
--foreground: 0 0% 3.9%;
@@ -32,6 +32,8 @@
--inverted-foreground: var(--background);
--warning-foreground: 40.61deg 96.12% 40.4%;
--link-foreground: 221.21deg 83.19% 53.33%;
--destructive-text: 0 84.24% 60.2%;
--success-text: 142.09 70.56% 35.29%;
/* Borders */
--border: 0 0% 80%;
@@ -43,7 +45,7 @@
}
.dark {
/* bg - nuetral */
/* bg - neutral */
--background: 0 0% 4.5%;
--secondary: 0 0% 6.5%;
--muted: 0 0% 9%;
@@ -53,8 +55,8 @@
--inverted: var(--foreground);
/* bg - colorful */
--primary: 215.88 100% 60%;
--destructive: 358 86% 64%;
--primary: 215.88 100% 55%;
--destructive: 0 62.8% 15%;
--success: 156.2 71.6% 10%;
--warning: 40.61deg 96.12% 8%;
@@ -66,10 +68,12 @@
--secondary-foreground: 0 0% 75%;
--muted-foreground: 0 0% 63.9%;
--accent-foreground: 0 0% 98%;
--destructive-foreground: 358 0% 100%;
--destructive-foreground: 0deg 90.6% 80%;
--success-foreground: 156.2 71.6% 66.86%;
--warning-foreground: 45.4deg 93.39% 47.45%;
--link-foreground: 215.88 100% 65%;
--destructive-text: 0 84.24% 65%;
--success-text: 156.2 71.6% 66.86%;
/* Borders */
--border: 0 0% 14.9%;
@@ -87,6 +91,25 @@
}
}
/* 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%;
}
}
@keyframes skeleton {
0%,
100% {
@@ -1,5 +1,5 @@
import type { ContractType } from "@thirdweb-dev/sdk";
import { constants } from "ethers";
import type { ContractType } from "constants/contracts";
import { ZERO_ADDRESS } from "thirdweb";
export const networkKeys = {
all: ["network"] as const,
@@ -97,14 +97,11 @@ export const engineKeys = {
export const contractKeys = {
all: ["contract"] as const,
lists: () => [...contractKeys.all, "list"] as const,
list: (address = constants.AddressZero) =>
[...contractKeys.lists(), address] as const,
listWithFilters: (
address = constants.AddressZero,
filters?: ContractType[],
) => [...contractKeys.list(address), { filters }] as const,
list: (address = ZERO_ADDRESS) => [...contractKeys.lists(), address] as const,
listWithFilters: (address = ZERO_ADDRESS, filters?: ContractType[]) =>
[...contractKeys.list(address), { filters }] as const,
details: () => [...contractKeys.all, "detail"] as const,
detail: (address: string = constants.AddressZero) =>
detail: (address: string = ZERO_ADDRESS) =>
[...contractKeys.details(), address] as const,
};
@@ -117,42 +114,37 @@ export const walletKeys = {
export const splitsKeys = {
all: ["splits"] as const,
lists: () => [...splitsKeys.all, "list"] as const,
list: (address = constants.AddressZero) =>
[...splitsKeys.lists(), address] as const,
detail: (address = constants.AddressZero) =>
[...splitsKeys.all, address] as const,
currencies: (address = constants.AddressZero) =>
list: (address = ZERO_ADDRESS) => [...splitsKeys.lists(), address] as const,
detail: (address = ZERO_ADDRESS) => [...splitsKeys.all, address] as const,
currencies: (address = ZERO_ADDRESS) =>
[...splitsKeys.detail(address), "currencies"] as const,
balances: (address = constants.AddressZero) =>
balances: (address = ZERO_ADDRESS) =>
[...splitsKeys.detail(address), "balances"] as const,
};
export const voteKeys = {
all: ["vote"] as const,
detail: (address = constants.AddressZero) =>
[...voteKeys.all, address] as const,
proposals: (address = constants.AddressZero) =>
detail: (address = ZERO_ADDRESS) => [...voteKeys.all, address] as const,
proposals: (address = ZERO_ADDRESS) =>
[...voteKeys.detail(address), "proposals"] as const,
proposal: (proposalId = "-1", address = constants.AddressZero) =>
proposal: (proposalId = "-1", address = ZERO_ADDRESS) =>
[...voteKeys.proposals(address), proposalId] as const,
balances: (address = constants.AddressZero, addresses = [] as string[]) =>
balances: (address = ZERO_ADDRESS, addresses = [] as string[]) =>
[...voteKeys.detail(address), "balances", { addresses }] as const,
delegations: (address = constants.AddressZero) =>
delegations: (address = ZERO_ADDRESS) =>
[...voteKeys.detail(address), "delegations"] as const,
delegation: (
address = constants.AddressZero,
userAddress = constants.AddressZero,
) => [...voteKeys.delegations(address), userAddress] as const,
delegation: (address = ZERO_ADDRESS, userAddress = ZERO_ADDRESS) =>
[...voteKeys.delegations(address), userAddress] as const,
userHasVotedOnProposal: (
proposalId = "-1",
address = constants.AddressZero,
userAddress = constants.AddressZero,
address = ZERO_ADDRESS,
userAddress = ZERO_ADDRESS,
) =>
[
...voteKeys.proposal(proposalId, address),
"hasVotedOnProposal",
userAddress,
] as const,
canExecuteProposal: (proposalId = "-1", address = constants.AddressZero) =>
canExecuteProposal: (proposalId = "-1", address = ZERO_ADDRESS) =>
[...voteKeys.proposal(proposalId, address), "canExecute"] as const,
};
@@ -41,7 +41,7 @@ export const CustomConnectWallet: React.FC = () => {
},
{
label: "Popular",
chains: popularChains.map(defineChain),
chains: popularChains,
},
{
label: "Recent",
@@ -1,35 +1,35 @@
import {
Arbitrum,
ArbitrumSepolia,
Avalanche,
AvalancheFuji,
Base,
BaseSepoliaTestnet,
Binance,
BinanceTestnet,
Ethereum,
Localhost,
OpSepoliaTestnet,
Optimism,
Polygon,
PolygonAmoyTestnet,
Sepolia,
} from "@thirdweb-dev/chains";
arbitrum,
arbitrumSepolia,
avalanche,
avalancheFuji,
base,
baseSepolia,
bsc,
bscTestnet,
ethereum,
localhost,
optimism,
optimismSepolia,
polygon,
polygonAmoy,
sepolia,
} from "thirdweb/chains";
export const popularChains = [
Ethereum,
Sepolia,
Polygon,
PolygonAmoyTestnet,
Base,
BaseSepoliaTestnet,
Arbitrum,
ArbitrumSepolia,
Optimism,
OpSepoliaTestnet,
Binance,
BinanceTestnet,
Avalanche,
AvalancheFuji,
Localhost,
ethereum,
sepolia,
polygon,
polygonAmoy,
base,
baseSepolia,
arbitrum,
arbitrumSepolia,
optimism,
optimismSepolia,
bsc,
bscTestnet,
avalanche,
avalancheFuji,
localhost,
];
@@ -1,4 +1,3 @@
import type { Chain } from "@thirdweb-dev/chains";
import {
createContext,
useCallback,
@@ -6,11 +5,12 @@ import {
useEffect,
useState,
} from "react";
import type { ChainMetadata } from "thirdweb/chains";
import invariant from "tiny-invariant";
export type EVMContractInfo = {
// using null instead of undefined here so that this type can be JSON stringified
chain: Chain | null;
chain: ChainMetadata | null;
chainSlug: string;
contractAddress: string;
};
@@ -4,7 +4,7 @@ import {
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import type { Chain } from "@thirdweb-dev/chains";
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";
@@ -925,7 +925,7 @@ export async function fetchChainsFromApi() {
throw new Error(json.error.message);
}
return json.data as Chain[];
return json.data as ChainMetadata[];
}
export function useApiChains() {
@@ -1,13 +0,0 @@
import { useQuery } from "@tanstack/react-query";
import { useSDK } from "@thirdweb-dev/react";
import invariant from "tiny-invariant";
import { walletKeys } from "../cache-keys";
export function useBalanceForAddress(address: string | undefined) {
const sdk = useSDK();
invariant(address, "Address is not provided");
return useQuery(walletKeys.balances(address), async () => {
invariant(sdk, "SDK is not initialized");
return await sdk.getBalance(address);
});
}
@@ -1,13 +1,13 @@
import {
type ContractWithRoles,
type RequiredParam,
type RolesForContract,
useContractType,
useRoleMembers,
} from "@thirdweb-dev/react";
import type { ValidContractInstance } from "@thirdweb-dev/sdk";
import { constants } from "ethers";
import { ZERO_ADDRESS } from "thirdweb";
import { useActiveAccount } from "thirdweb/react";
import type { RequiredParam } from "utils/types";
function isContractWithRoles(
contract: RequiredParam<ValidContractInstance>,
@@ -30,7 +30,7 @@ function useIsAccountRole<TContract extends ContractWithRoles>(
return false;
}
if (data?.includes(constants.AddressZero)) {
if (data?.includes(ZERO_ADDRESS)) {
return true;
}
@@ -3,6 +3,7 @@ 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";
@@ -121,7 +122,10 @@ export interface EngineSystemHealth {
features?: string[];
}
export function useEngineSystemHealth(instanceUrl: string) {
export function useEngineSystemHealth(
instanceUrl: string,
pollInterval: number | false = false,
) {
return useQuery(
engineKeys.health(instanceUrl),
async () => {
@@ -134,7 +138,10 @@ export function useEngineSystemHealth(instanceUrl: string) {
const json = (await res.json()) as EngineSystemHealth;
return json;
},
{ enabled: !!instanceUrl },
{
enabled: !!instanceUrl,
refetchInterval: pollInterval,
},
);
}
@@ -1449,6 +1456,9 @@ export interface EngineResourceMetrics {
data: {
cpu: number;
memory: number;
errorRate: ResultItem[];
statusCodes: ResultItem[];
requestVolume: ResultItem[];
};
}
@@ -1460,9 +1470,6 @@ export function useEngineResourceMetrics(engineId: string) {
async () => {
const res = await fetch(
`${THIRDWEB_API_HOST}/v1/engine/${engineId}/metrics`,
{
method: "GET",
},
);
if (!res.ok) {
setEnabled(false);
@@ -1,6 +1,6 @@
import type { Chain } from "@thirdweb-dev/chains";
import { useSupportedChains } from "@thirdweb-dev/react";
import { useMemo } from "react";
import type { ChainMetadata } from "thirdweb/chains";
import { useFavouriteChainIds } from "../../../app/(dashboard)/(chain)/components/client/star-button";
export function useFavoriteChains() {
@@ -9,7 +9,7 @@ export function useFavoriteChains() {
const data = useMemo(() => {
if (favChainsQuery.data) {
const _chains: Chain[] = [];
const _chains: ChainMetadata[] = [];
// biome-ignore lint/complexity/noForEach: FIXME
favChainsQuery.data.forEach((chainId) => {
const chain = allChains.find((c) => String(c.chainId) === chainId);
@@ -21,7 +21,7 @@ export function useFavoriteChains() {
return _chains;
}
return [] as Chain[];
return [] as ChainMetadata[];
}, [favChainsQuery.data, allChains]);
return {
@@ -148,6 +148,7 @@ export function useAddContractMutation() {
chainId: data.chainId,
},
account,
300000n,
);
},
{
@@ -1,23 +0,0 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useSDK } from "@thirdweb-dev/react";
import invariant from "tiny-invariant";
import { walletKeys } from "../cache-keys";
type TransferInput = {
address: string;
amount: string;
};
export function useTransferNativeToken() {
const sdk = useSDK();
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (input: TransferInput) => {
invariant(sdk, "SDK is not initialized");
await sdk.wallet.transfer(input.address, input.amount);
},
onSuccess: (_, variables) => {
queryClient.invalidateQueries(walletKeys.balances(variables.address));
},
});
}
@@ -1,12 +1,8 @@
import {
type RequiredParam,
useContract,
useContractMetadata,
useSDK,
} from "@thirdweb-dev/react";
import { useContract, useContractMetadata, useSDK } from "@thirdweb-dev/react";
import type { Vote, VoteType } from "@thirdweb-dev/sdk";
import { useActiveAccount } from "thirdweb/react";
import invariant from "tiny-invariant";
import type { RequiredParam } from "utils/types";
import { voteKeys } from "../cache-keys";
import {
useMutationWithInvalidate,
@@ -1,5 +1,5 @@
import { redirect } from "next/navigation";
import { getChain } from "../../utils";
import { getChain } from "../../../utils";
import { InfoCard } from "../components/server/info-card";
export default async function Page(props: { params: { chain_id: string } }) {
@@ -41,13 +41,13 @@ export const AddChainToWallet: React.FC<AddChainToWalletProps> = (props) => {
!address || debouncedLoading || activeWalletChainId === props.chain?.id
}
className={cn(
"w-full md:min-w-40",
"w-full md:min-w-40 gap-2",
props.hasBackground && "invert dark:invert-0",
)}
onClick={() => switchChainMutation.mutate()}
>
{debouncedLoading && <Spinner />}
<span>Add to wallet</span>
{debouncedLoading && <Spinner className="size-3" />}
</Button>
);
@@ -2,10 +2,9 @@
import { TabLinks } from "@/components/ui/tabs";
import { useSelectedLayoutSegment } from "next/navigation";
import type { ChainSupportedService } from "../../../types/chain";
import { useMemo } from "react";
import { products } from "../../../components/server/products";
import { products } from "../../../../components/server/products";
import type { ChainSupportedService } from "../../../../types/chain";
export function getEnabledTabs(enabledServices: ChainSupportedService[]) {
return products
@@ -1,6 +1,6 @@
import { ExternalLinkIcon } from "lucide-react";
import Link from "next/link";
import type { ChainMetadataWithServices } from "../../../types/chain";
import type { ChainMetadataWithServices } from "../../../../types/chain";
export function ExplorersSection(props: {
explorers: NonNullable<ChainMetadataWithServices["explorers"]>;
@@ -3,7 +3,7 @@ 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 { getChain } from "../../../utils";
import { InfoCard } from "../components/server/info-card";
type SDKInfo = {
@@ -1,5 +1,5 @@
import { redirect } from "next/navigation";
import { getChain } from "../../utils";
import { getChain } from "../../../utils";
import { InfoCard } from "../components/server/info-card";
export default async function Page(props: { params: { chain_id: string } }) {
@@ -1,7 +1,6 @@
"use client";
import { CopyTextButton } from "@/components/ui/CopyTextButton";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Button } from "@/components/ui/button";
import {
Dialog,
@@ -13,6 +12,7 @@ import {
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";
@@ -157,38 +157,49 @@ export function TestnetSpinWheel({
return (
<>
{isLoading ?? <Spinner />}
{faucetMessage}
<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>
{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>
</>
)}
</>
);
}
@@ -5,7 +5,7 @@ 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 { getChain } from "../../../utils";
import { InfoCard } from "../components/server/info-card";
import { TestnetSpinWheel } from "./components/SpinWheel";
@@ -36,16 +36,15 @@ export default async function Page(props: { params: { chain_id: string } }) {
return (
<>
<div className="items-center">
<InfoCard title="Faucet">
<ClientOnly ssr={null}>
<TestnetSpinWheel chain={chain} ttlSeconds={ttlSeconds} />
</ClientOnly>
</InfoCard>
<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>What is a faucet?</h3>
<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
@@ -57,7 +56,9 @@ export default async function Page(props: { params: { chain_id: string } }) {
<h2>How often can I claim from the faucet?</h2>
<p>You may claim funds once per testnet chain every 24 hours.</p>
<h3>How can I refill the faucet?</h3>
<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
@@ -69,7 +70,9 @@ export default async function Page(props: { params: { chain_id: string } }) {
/>
</div>
<h3>How does the faucet work?</h3>
<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{" "}
@@ -13,9 +13,9 @@ import type { Metadata } from "next";
import Link from "next/link";
import { redirect } from "next/navigation";
import { defineChain } from "thirdweb";
import { StarButton } from "../components/client/star-button";
import { ChainIcon } from "../components/server/chain-icon";
import { getChain, getChainMetadata } from "../utils";
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";
@@ -109,7 +109,7 @@ export default async function ChainPageLayout({
: undefined
}
/>
<div className="absolute top-0 left-0 right-0 bottom-0 bg-gradient-to-b from-secondary/0 to-secondary/0 shadow-inner" />
<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 */}
@@ -80,20 +80,23 @@ export default async function Image({
return new Response("Chain not found", { status: 400 });
}
// TODO: handle svg - doesn't work right now
const hasWorkingChainIcon = chain.icon?.url && chain.icon?.format !== "svg";
const [interBold, chainIcon, imageData] = await Promise.all([
// fetch the font we use
fetch(new URL("og-lib/fonts/inter/700.ttf", import.meta.url)).then((res) =>
res.arrayBuffer(),
),
// download the chain icon if there is one
chain.icon?.url
chain.icon?.url && hasWorkingChainIcon
? download({ uri: chain.icon.url, client: thirdwebClient }).then((res) =>
res.arrayBuffer(),
)
: undefined,
// download the background image (based on chain)
fetch(
chain.icon?.url
chain.icon?.url && hasWorkingChainIcon
? new URL(
"og-lib/assets/chain/bg-with-icon.png",
@@ -121,7 +124,7 @@ export default async function Image({
/>
{/* the actual component starts here */}
{chainIcon && (
{hasWorkingChainIcon && (
<img
alt=""
// @ts-expect-error - TS doesn't know about the ImageResponse component
@@ -5,9 +5,9 @@ import {
type SortBy,
type TimeRange,
fetchTopContracts,
} from "../../../../lib/search";
} from "../../../../../lib/search";
import { TrendingContractSection } from "../../../trending/components/trending-table";
import { getChain } from "../utils";
import { getChain } from "../../utils";
import { InfoCard } from "./components/server/info-card";
import twPublisherImage from "./tw-publisher.png";
@@ -132,8 +132,8 @@ export default async function Page(props: {
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-foreground flex items-center gap-1 mb-4 text-sm font-medium">
<ShieldCheckIcon className="size-4 text-success-foreground" />
<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>
@@ -1,5 +1,5 @@
import { redirect } from "next/navigation";
import { getChain } from "../../utils";
import { getChain } from "../../../utils";
import { InfoCard } from "../components/server/info-card";
import { CustomPayEmbed } from "./components/pay-embed.client";
@@ -69,11 +69,11 @@ export function ChainLiveStats(props: { rpc: string }) {
titleIcon={
stats.isSuccess ? (
<ToolTipLabel label="Working">
<CircleCheck className="size-4 text-success-foreground" />
<CircleCheck className="size-4 text-success-text" />
</ToolTipLabel>
) : stats.isError ? (
<ToolTipLabel label="Not Working">
<XIcon className="size-4 text-destructive-foreground" />
<XIcon className="size-4 text-destructive-text" />
</ToolTipLabel>
) : null
}
@@ -87,7 +87,7 @@ export function ChainLiveStats(props: { rpc: string }) {
{/* Latency */}
<PrimaryInfoItem title="RPC Latency" titleIcon={<PulseDot />}>
{stats.isError ? (
<p className="text-lg fade-in-0 animate-in text-destructive-foreground">
<p className="text-lg fade-in-0 animate-in text-destructive-text">
N/A
</p>
) : stats.data ? (
@@ -102,7 +102,7 @@ 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-foreground">
<p className="text-lg fade-in-0 animate-in text-destructive-text">
N/A
</p>
) : stats.data ? (
@@ -1,5 +1,5 @@
import { redirect } from "next/navigation";
import { getChain } from "../../utils";
import { getChain } from "../../../utils";
import { InfoCard } from "../components/server/info-card";
import { ChainLiveStats } from "./components/client/live-stats";

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

@@ -0,0 +1,187 @@
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 {
eth_getBlockByHash,
eth_getTransactionByHash,
eth_getTransactionReceipt,
getRpcClient,
} from "thirdweb/rpc";
import { hexToNumber, shortenAddress, toEther } from "thirdweb/utils";
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}` };
}) {
const thirdwebClient = createThirdwebClient({
secretKey: DASHBOARD_THIRDWEB_SECRET_KEY,
config: {
storage: {
gatewayUrl: IPFS_GATEWAY_URL,
},
},
});
const chain = await getChain(props.params.chain_id);
const rpcRequest = getRpcClient({
client: thirdwebClient,
chain: defineDashboardChain(chain.chainId),
});
const [transaction, receipt] = await Promise.all([
eth_getTransactionByHash(rpcRequest, {
hash: props.params.txHash,
}),
eth_getTransactionReceipt(rpcRequest, {
hash: props.params.txHash,
}),
]);
if (!transaction.blockHash) {
return <div>no tx found</div>;
}
const block = await eth_getBlockByHash(rpcRequest, {
blockHash: transaction.blockHash,
});
return (
<main className="flex flex-col gap-y-10 container py-6">
<header className="flex flex-col gap-y-2">
<p className="text-3xl font-bold">Transaction Details</p>
<div className="flex gap-x-2">
{shortenAddress(transaction.from)} called on{" "}
{shortenAddress(transaction.to || ZERO_ADDRESS)}
</div>
</header>
<Separator orientation="horizontal" />
<section className="flex flex-col gap-y-2">
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">Transaction hash</div>
<p>{transaction.hash}</p>
</div>
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">
Status {/* and method */}
</div>
<div className="flex gap-x-2">
<Badge
className={
receipt.status === "success" ? "bg-green-500" : "bg-red-500"
}
>
{receipt.status}
</Badge>
</div>
</div>
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">Block</div>
<p>{Number(transaction.blockNumber)}</p>
</div>
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">Timestamp</div>
<p>
{new Date(
Number.parseInt(block.timestamp.toString()) * 1000,
).toLocaleString()}
</p>
</div>
</section>
<Separator orientation="horizontal" />
<section className="flex flex-col gap-y-2">
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">From</div>
<p>{transaction.from}</p>
</div>
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">
Interacted with contract
</div>
<p>{transaction.to}</p>
</div>
</section>
<Separator orientation="horizontal" />
<section className="flex flex-col gap-y-2">
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">Value</div>
<p>{toEther(transaction.value)} ETH</p>
</div>
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">Transaction fee</div>
<p>{toEther((transaction.gasPrice || 0n) * receipt.gasUsed)} ETH</p>
</div>
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">Gas price</div>
<p>{toEther(transaction.gasPrice || 0n)} ETH</p>
</div>
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">Gas usage</div>
<p>{receipt.gasUsed.toString()}</p>
</div>
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">Gas fees (Gwei)</div>
<p>
Base: {toTokens(block.baseFeePerGas || 0n, 9)} | Max:{" "}
{toTokens(transaction.maxFeePerGas || 0n, 9)} | Max priority:{" "}
{transaction.maxPriorityFeePerGas?.toString()}
</p>
</div>
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">Burnt fees</div>
<p>{toEther(block.baseFeePerGas || 0n * receipt.gasUsed)}</p>
</div>
</section>
<Separator orientation="horizontal" />
<section className="flex flex-col gap-y-2">
<div className="grid grid-cols-2">
<div className="flex gap-x-2 items-center">Other</div>
<p>
Txn type: {hexToNumber(transaction.typeHex || "0x0")} (
{transaction.type}) | Nonce: {transaction.nonce} | Position:{" "}
{transaction.transactionIndex}
</p>
</div>
<div className="grid grid-cols-2 items-start">
<div className="flex gap-x-2 items-center">Raw Input:</div>
<div className="bg-secondary p-4 rounded-lg break-words text-sm">
{transaction.input}
</div>
</div>
</section>
</main>
);
}
@@ -100,7 +100,7 @@ export async function ChainListCard({
{isDeprecated && (
<div className="gap-1.5 flex items-center">
<CircleAlertIcon className="text-destructive-foreground size-5" />
<CircleAlertIcon className="text-destructive-text size-5" />
<p className="text-sm">Deprecated</p>
</div>
)}
@@ -59,7 +59,7 @@ export async function ChainListRow({
{isDeprecated && (
<ToolTipLabel label="Deprecated">
<CircleAlertIcon className="text-destructive-foreground size-5 z-10 " />
<CircleAlertIcon className="text-destructive-text size-5 z-10 " />
</ToolTipLabel>
)}
</div>
@@ -115,9 +115,9 @@ function ProductIcon(props: {
label={props.label}
leftIcon={
props.isEnabled ? (
<CheckIcon className="text-success-foreground size-4" />
<CheckIcon className="text-success-text size-4" />
) : (
<XIcon className="text-destructive-foreground size-4" />
<XIcon className="text-destructive-text size-4" />
)
}
>
@@ -92,11 +92,18 @@ async function getChainsToRender(params: SearchParams) {
const urlServiceArray = Array.isArray(params.service)
? params.service
: [params.service];
// if the chain does not have all of the services in the filter, return false to filter it out
if (
!urlServiceArray.every((service) =>
chain.services.find((s) => s.enabled && s.service === service),
)
!urlServiceArray.every((service) => {
// TODO improve this
// We don't have "faucet" added in services array, so for now we just check if it's testnet or not
if (service === "faucet") {
return chain.testnet;
}
return chain.services.find((s) => s.enabled && s.service === service);
})
) {
// skip to the next chain
continue;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

@@ -1,16 +1,20 @@
import "server-only";
import { redirect } from "next/navigation";
import type { ChainCTAProps } from "./[chain_id]/components/server/cta-card";
import ancient8Banner from "./temp-assets/ancient8-banner.jpg";
import type { ChainCTAProps } from "./[chain_id]/(chainPage)/components/server/cta-card";
import ancient8Banner from "./temp-assets/ancient8-banner.png";
// TEMPORARY
import baseBanner from "./temp-assets/base-banner.jpeg";
import superchainCTABG from "./temp-assets/cta-bg-superchain.png";
import xaiCTABg from "./temp-assets/cta-bg-xai-connect.png";
import mantleBanner from "./temp-assets/mantle-banner.jpeg";
// import mantleCTA from "./temp-assets/mantle-cta.jpeg";
import rootStockBanner from "./temp-assets/rootstock-banner.png";
import rootStockCTABG from "./temp-assets/rootstock-cta.png";
import vanarBanner from "./temp-assets/vanar-banner.png";
import vanarCTABG from "./temp-assets/vanar-cta.png";
import xaiBanner from "./temp-assets/xai-banner.jpg";
import type { ChainMetadataWithServices } from "./types/chain";
// END TEMPORARY
const THIRDWEB_API_HOST =
@@ -138,6 +142,30 @@ const chainMetaRecord = {
// buttonLink: "https://www.mantle.xyz",
// },
},
// rootstock
30: {
headerImgUrl: rootStockBanner.src,
about:
"Deploy EVM compatible smart contracts on Rootstock and leverage the security of the Bitcoin network.",
cta: {
backgroundImageUrl: rootStockCTABG.src,
title: "Fully EVM-compatible Bitcoin L2",
buttonLink: "https://rootstock.io/",
buttonText: "Learn more",
},
},
// vanar
2040: {
headerImgUrl: vanarBanner.src,
about:
"Discover VANAR – The future of blockchain technology tailored for global adoption. This cutting-edge, L1 EVM blockchain offers high-speed transactions and scalability, powered by Google's renewable energy sources. With a suite of apps, low fixed transaction costs and a zero-cost option for brands, VANAR makes blockchain scalable, accessible and affordable.",
cta: {
buttonLink: "https://docs.vanarchain.com",
buttonText: "Learn more",
backgroundImageUrl: vanarCTABG.src,
title: "Fully EVM compatible L1 for Entertainment",
},
},
} satisfies Record<number, ChainMetadata>;
// END TEMPORARY
@@ -36,7 +36,7 @@ export const SidebarNav: React.FC<SideBarNavProps> = ({ sections }) => {
return (
<aside className="w-full md:w-[250px] lg:w-[300px] border-b md:border-b-0 relative md:sticky top-0 flex-shrink-0">
{/* mobile toggle */}
<div className="flex flex-row items-center justify-between w-full p-4 md:hidden">
<div className="flex flex-row items-center justify-between w-full py-4 md:hidden">
<label className="flex items-center h-8 pl-3 text-sm font-semibold border-l-2 text-accent-foreground border-primary">
{activeLinkInSections?.title || "Dashboard"}
</label>
@@ -16,56 +16,19 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { ToolTipLabel } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
import { ToolTipLabel } from "../../../../../../../../../@/components/ui/tooltip";
import type { z } from "zod";
import type { Ecosystem } from "../../../../types";
import { partnerFormSchema } from "../../constants";
import { useAddPartner } from "../../hooks/use-add-partner";
const isDomainRegex =
/^(?:\*|(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*(?:\*(?:\.[a-z0-9][a-z0-9-]{0,61}[a-z0-9](?:\.[a-z0-9][a-z0-9-]{0,61}[a-z0-9])*)?)|(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]|localhost(?::\d{1,5})?)$/;
const formSchema = z.object({
name: z
.string()
.trim()
.min(3, {
message: "Name must be at least 3 characters",
})
.refine((name) => /^[a-zA-Z0-9 ]*$/.test(name), {
message: "Name can only contain letters, numbers and spaces",
}),
domains: z
.string()
.trim()
.transform((s) => s.split(/,| /).filter((d) => d.length > 0))
.refine((domains) => domains.every((d) => isDomainRegex.test(d)), {
message: "Invalid domain format", // This error message CANNOT be within the array iteration, or the FormMessage won't be able to find it in the form state
})
.transform((s) => s.join(",")), // This is rejoined to return a string (and later split again) since react-hook-form's typings can't hnadle different input vs output types
bundleIds: z
.string()
.trim()
.transform((s) =>
s
.split(/,| /)
.filter((d) => d.length > 0)
.join(","),
),
permissions: z
.string({
required_error: "Please specify wallet permissions",
}) // We use a string rather than an enum here so the defualt value will work
.refine((p) => ["PROMPT_USER_V1", "FULL_CONTROL_V1"].includes(p), {
message: "Invalid permissions setting",
}),
});
export function AddPartnerForm({ ecosystem }: { ecosystem: Ecosystem }) {
const form = useForm<z.input<typeof formSchema>>({
resolver: zodResolver(formSchema),
const form = useForm<z.input<typeof partnerFormSchema>>({
resolver: zodResolver(partnerFormSchema),
});
const { addPartner, isLoading } = useAddPartner({
@@ -94,11 +57,7 @@ export function AddPartnerForm({ ecosystem }: { ecosystem: Ecosystem }) {
allowlistedBundleIds: values.bundleIds
.split(/,| /)
.filter((d) => d.length > 0),
permissions: [
values.permissions as unknown as
| "FULL_CONTROL_V1"
| "PROMPT_USER_V1",
],
permissions: [values.permissions],
});
})}
className="flex flex-col gap-2 lg:flex-row"
@@ -0,0 +1,209 @@
"use client";
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { ToolTipLabel } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { zodResolver } from "@hookform/resolvers/zod";
import { Loader2 } from "lucide-react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import type { z } from "zod";
import type { Ecosystem, Partner } from "../../../../types";
import { partnerFormSchema } from "../../constants";
import { useUpdatePartner } from "../../hooks/use-update-partner";
export function UpdatePartnerForm({
ecosystem,
partner,
onSuccess,
}: { ecosystem: Ecosystem; partner: Partner; onSuccess: () => void }) {
const form = useForm<z.input<typeof partnerFormSchema>>({
resolver: zodResolver(partnerFormSchema),
defaultValues: {
name: partner.name,
domains: partner.allowlistedDomains.join(","),
bundleIds: partner.allowlistedBundleIds.join(","),
permissions: partner.permissions[0],
},
});
const { updatePartner, isLoading } = useUpdatePartner({
onSuccess: () => {
form.reset();
onSuccess();
},
onError: (error) => {
const message =
error instanceof Error
? error.message
: "Failed to add ecosystem partner";
toast.error(message);
},
});
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit((values) => {
updatePartner({
ecosystem,
partnerId: partner.id,
name: values.name,
allowlistedDomains: values.domains
.split(/,| /)
.filter((d) => d.length > 0),
allowlistedBundleIds: values.bundleIds
.split(/,| /)
.filter((d) => d.length > 0),
permissions: [values.permissions],
});
})}
className="flex flex-col gap-4"
>
<div className="grid gap-4 grow">
<FormField
control={form.control}
name="name"
defaultValue="" // Note: you *must* provide a default value here or the field won't reset
render={({ field }) => (
<FormItem className="col-span-4">
<FormControl>
<Input
placeholder="App name"
{...field}
value={field.value}
/>
</FormControl>
<FormDescription
className={cn(
"text-xs transition-all",
form.formState.errors.name?.message
? "text-destructive block opacity-100 translate-y-0"
: "opacity-0 hidden",
)}
>
{form.formState.errors.name?.message}
</FormDescription>
</FormItem>
)}
/>
<FormField
control={form.control}
name="domains"
defaultValue="" // Note: you *must* provide a default value here or the field won't reset
render={({ field }) => (
<FormItem className="col-span-4 lg:col-span-4">
<FormControl>
<>
<Input placeholder="Domains" className="peer" {...field} />
<FormDescription
className={cn(
"text-xs block",
form.formState.errors.domains?.message &&
"text-destructive translate-y-0 opacity-100 block", // If there are errors show them rather than the tip
)}
>
{form.formState.errors.domains?.message ??
"Space or comma-separated list of regex domains (e.g. *.example.com)"}
</FormDescription>
</>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="bundleIds"
defaultValue="" // Note: you *must* provide a default value here or the field won't reset
render={({ field }) => (
<FormItem className="col-span-4">
<FormControl>
<>
<Input
placeholder="Bundle ID"
className="peer"
{...field}
/>
<FormDescription
className={cn(
"text-xs block",
form.formState.errors.bundleIds?.message &&
"text-destructive block",
)}
>
{form.formState.errors.bundleIds?.message ??
"Space or comma-separated list of bundle IDs"}
</FormDescription>
</>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="permissions"
defaultValue="PROMPT_USER_V1" // Note: you *must* provide a default value here or the field won't reset
render={({ field }) => (
<FormItem className="col-span-4">
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<ToolTipLabel label="Should wallet actions prompt the user for approval?">
<FormControl>
<SelectTrigger className="w-full">
<SelectValue placeholder="Wallet prompts" />
</SelectTrigger>
</FormControl>
</ToolTipLabel>
<SelectContent>
<SelectItem value="FULL_CONTROL_V1">
Never prompt
</SelectItem>
<SelectItem value="PROMPT_USER_V1">Prompt user</SelectItem>
</SelectContent>
<FormDescription
className={cn(
"hidden text-xs transition-all peer-focus-visible:opacity-100 peer-focus-visible:translate-y-0",
form.formState.errors.permissions?.message &&
"text-destructive block", // If there are errors show them rather than the tip
)}
>
{form.formState.errors.permissions?.message ??
"Wallet signing"}
</FormDescription>
</Select>
</FormItem>
)}
/>
</div>
<Button
disabled={isLoading}
type="submit"
variant="outline"
className="w-full"
>
{isLoading && <Loader2 className="size-4 mr-1 animate-spin" />}
Update
</Button>
</form>
</Form>
);
}
@@ -0,0 +1,35 @@
"use client";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { useState } from "react";
import type { Ecosystem, Partner } from "../../../../types";
import { UpdatePartnerForm } from "./update-partner-form.client";
export function UpdatePartnerModal({
children,
ecosystem,
partner,
}: { children: React.ReactNode; ecosystem: Ecosystem; partner: Partner }) {
const [open, setOpen] = useState(false);
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger>{children}</DialogTrigger>
<DialogContent className="w-[90vw] sm:w-auto">
<DialogHeader>
<DialogTitle>Update {partner.name}</DialogTitle>
</DialogHeader>
<UpdatePartnerForm
ecosystem={ecosystem}
partner={partner}
onSuccess={() => setOpen(false)}
/>
</DialogContent>
</Dialog>
);
}
@@ -4,12 +4,13 @@ import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import { ToolTipLabel } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { Trash2 } from "lucide-react";
import { Pencil, Trash2 } from "lucide-react";
import Link from "next/link";
import { toast } from "sonner";
import type { Ecosystem, Partner } from "../../../../types";
import { useDeletePartner } from "../../hooks/use-delete-partner";
import { usePartners } from "../../hooks/use-partners";
import { UpdatePartnerModal } from "../client/update-partner-modal.client";
export function PartnersTable({ ecosystem }: { ecosystem: Ecosystem }) {
const { partners, isLoading } = usePartners({ ecosystem });
@@ -45,7 +46,7 @@ export function PartnersTable({ ecosystem }: { ecosystem: Ecosystem }) {
</tr>
</thead>
<tbody>
{partners?.map((partner: Partner) => (
{[...partners].reverse().map((partner: Partner) => (
<TableRow key={partner.id} partner={partner} ecosystem={ecosystem} />
))}
</tbody>
@@ -117,40 +118,57 @@ function TableRow(props: {
: "Never prompt"}
</TableData>
<td className="table-cell py-1 align-middle">
<ConfirmationDialog
title={`Are you sure you want to delete the partner ${props.partner.name}?`}
description={
<span>
Their partner key will no longer be able to use your ecosystem
wallet. Their users will still have access to their assets at{" "}
<Link
href={`https://${props.ecosystem.slug.split(".")[1]}.ecosystem.thirdweb.com`}
target="_blank"
className="text-primary"
>
{props.ecosystem.slug.split(".")[1]}.ecosystem.thirdweb.com
</Link>
</span>
}
onSubmit={(): void => {
deletePartner({
ecosystem: props.ecosystem,
partnerId: props.partner.id,
});
}}
variant="destructive"
>
<Button
type="button"
variant="outline"
size="icon"
className="text-destructive hover:text-destructive-foreground hover:bg-destructive"
disabled={isDeleting}
<div className="flex gap-1.5 justify-end">
<UpdatePartnerModal
partner={props.partner}
ecosystem={props.ecosystem}
>
<Trash2 className="size-4" />
<span className="sr-only">Delete</span>
</Button>
</ConfirmationDialog>
<Button
type="button"
variant="outline"
size="icon"
className="text-accent-foreground/50 hover:text-accent-foreground hover:bg-accent"
disabled={isDeleting}
>
<Pencil className="size-4" />
<span className="sr-only">Edit</span>
</Button>
</UpdatePartnerModal>
<ConfirmationDialog
title={`Are you sure you want to delete the partner ${props.partner.name}?`}
description={
<span>
Their partner key will no longer be able to use your ecosystem
wallet. Their users will still have access to their assets at{" "}
<Link
href={`https://${props.ecosystem.slug}.ecosystem.thirdweb.com`}
target="_blank"
className="text-primary"
>
{props.ecosystem.slug.split(".")[1]}.ecosystem.thirdweb.com
</Link>
</span>
}
onSubmit={(): void => {
deletePartner({
ecosystem: props.ecosystem,
partnerId: props.partner.id,
});
}}
variant="destructive"
>
<Button
type="button"
variant="outline"
size="icon"
className="text-destructive hover:text-destructive-foreground hover:bg-destructive"
disabled={isDeleting}
>
<Trash2 className="size-4" />
<span className="sr-only">Delete</span>
</Button>
</ConfirmationDialog>
</div>
</td>
</tr>
);
@@ -0,0 +1,41 @@
import z from "zod";
import type { PartnerPermission } from "../../types";
import { isValidPermission } from "./utils";
export const isDomainRegex =
/^(?:\*|(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*(?:\*(?:\.[a-z0-9][a-z0-9-]{0,61}[a-z0-9](?:\.[a-z0-9][a-z0-9-]{0,61}[a-z0-9])*)?)|(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]|localhost(?::\d{1,5})?)$/;
export const partnerFormSchema = z.object({
name: z
.string()
.trim()
.min(3, {
message: "Name must be at least 3 characters",
})
.refine((name) => /^[a-zA-Z0-9 ]*$/.test(name), {
message: "Name can only contain letters, numbers and spaces",
}),
domains: z
.string()
.trim()
.transform((s) => s.split(/,| /).filter((d) => d.length > 0))
.refine((domains) => domains.every((d) => isDomainRegex.test(d)), {
message: "Invalid domain format", // This error message CANNOT be within the array iteration, or the FormMessage won't be able to find it in the form state
})
.transform((s) => s.join(",")), // This is rejoined to return a string (and later split again) since react-hook-form's typings can't hnadle different input vs output types
bundleIds: z
.string()
.trim()
.transform((s) =>
s
.split(/,| /)
.filter((d) => d.length > 0)
.join(","),
),
permissions: z.custom<PartnerPermission>(
(value) => isValidPermission(value),
{
message: "Invalid permissions setting",
},
),
});
@@ -0,0 +1,90 @@
import { useLoggedInUser } from "@3rdweb-sdk/react/hooks/useLoggedInUser";
import {
type UseMutationOptions,
useMutation,
useQueryClient,
} from "@tanstack/react-query";
import type { Ecosystem, Partner } from "../../../types";
export type UpdatePartnerParams = {
partnerId: string;
ecosystem: Ecosystem;
name: string;
allowlistedDomains: string[];
allowlistedBundleIds: string[];
permissions: ["PROMPT_USER_V1" | "FULL_CONTROL_V1"];
};
export function useUpdatePartner(
options?: Omit<
UseMutationOptions<Partner, unknown, UpdatePartnerParams>,
"mutationFn"
>,
) {
const { onSuccess, ...queryOptions } = options || {};
const { isLoggedIn, user } = useLoggedInUser();
const queryClient = useQueryClient();
const { mutateAsync: updatePartner, isLoading } = useMutation({
// Returns the created partner object
mutationFn: async (params: UpdatePartnerParams): Promise<Partner> => {
if (!isLoggedIn || !user?.jwt) {
throw new Error("Please login to update a partner");
}
const res = await fetch(
`${params.ecosystem.url}/${params.ecosystem.id}/partner/${params.partnerId}`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${user.jwt}`,
},
body: JSON.stringify({
name: params.name,
allowlistedDomains: params.allowlistedDomains,
allowlistedBundleIds: params.allowlistedBundleIds,
permissions: params.permissions,
}),
},
);
if (!res.ok) {
const body = await res.json();
console.error(body);
if (res.status === 401) {
throw new Error("You're not authorized to update this partner");
}
if (res.status === 406) {
throw new Error(
"Please setup billing on your account to continue managing this ecosystem",
);
}
throw new Error(
body?.message ??
body?.error?.message ??
"Failed to update ecosystem partner",
);
}
const data = await res.json();
return data;
},
onSuccess: async (partner, variables, context) => {
await queryClient.invalidateQueries([
"ecosystem",
variables.ecosystem.id,
"partners",
]);
if (onSuccess) {
return onSuccess(partner, variables, context);
}
return;
},
...queryOptions,
});
return { updatePartner, isLoading };
}
@@ -0,0 +1,6 @@
import type { PartnerPermission } from "../../types.ts";
export const isValidPermission = (
permission: string,
): permission is PartnerPermission =>
["FULL_CONTROL_V1", "PROMPT_USER_V1"].includes(permission);
@@ -0,0 +1,50 @@
import { cn } from "@/lib/utils";
import { CheckIcon } from "lucide-react";
import Image from "next/image";
import headerImage from "../../assets/header.png";
export function EcosystemWalletPricingCard(props: { className?: string }) {
return (
<div
className={cn(
"overflow-hidden border border-border shadow rounded-xl bg-card",
props.className,
)}
>
<Image src={headerImage} alt="" sizes="50vw" className="w-full" />
<div className="p-4 pb-8 border-t border-border md:p-6 md:pb-8 relative">
<h4 className="text-4xl font-bold text-foreground">
$250{" "}
<span className="text-lg font-normal text-muted-foreground">
per month
</span>
</h4>
<ul className="flex flex-col gap-4 mt-6 text-sm md:text-base text-muted-foreground">
<li className="flex items-start gap-2">
<CheckIcon className="w-5 h-5 text-green-500 md:mt-0.5" /> Share
assets across apps within your ecosystem
</li>
<li className="flex items-start gap-2">
<CheckIcon className="w-5 h-5 text-green-500 md:mt-0.5" /> Connect
with social, phone, email, or passkey
</li>
<li className="flex items-start gap-2">
<CheckIcon className="w-5 h-5 text-green-500 md:mt-0.5" /> A
standalone wallet UI for all your users
</li>
<li className="flex items-start gap-2">
<CheckIcon className="w-5 h-5 text-green-500 md:mt-0.5" /> Custom
permissions and billing across your ecosystem
</li>
<li className="flex items-start gap-2">
<CheckIcon className="w-5 h-5 text-green-500 md:mt-0.5" /> 30,000
active wallets included*
</li>
</ul>
<p className="mt-4 text-xs italic text-muted-foreground text-right">
$0.02 per additional wallet
</p>
</div>
</div>
);
}
@@ -1,7 +1,5 @@
import { CheckIcon } from "lucide-react";
import Image from "next/image";
import headerImage from "../assets/header.png";
import { CreateEcosystemForm } from "./components/client/create-ecosystem-form.client";
import { EcosystemWalletPricingCard } from "./components/pricing-card";
export default function Page() {
return (
@@ -16,42 +14,7 @@ export default function Page() {
</header>
<main className="grid w-full max-w-sm gap-8 md:max-w-lg lg:max-w-4xl xl:gap-12 lg:grid-cols-2">
<section className="flex items-start">
<div className="overflow-hidden border shadow rounded-xl bg-card">
<Image src={headerImage} alt="" sizes="50vw" className="w-full" />
<div className="p-4 pb-8 border-t md:p-6 md:pb-8 relative">
<h4 className="text-4xl font-bold text-foreground">
$250{" "}
<span className="text-lg font-normal text-muted-foreground">
per month
</span>
</h4>
<ul className="flex flex-col gap-4 mt-6 text-sm md:text-base text-muted-foreground">
<li className="flex items-start gap-2">
<CheckIcon className="w-5 h-5 text-green-500 md:mt-0.5" />{" "}
Share assets across apps within your ecosystem
</li>
<li className="flex items-start gap-2">
<CheckIcon className="w-5 h-5 text-green-500 md:mt-0.5" />{" "}
Connect with social, phone, email, or passkey
</li>
<li className="flex items-start gap-2">
<CheckIcon className="w-5 h-5 text-green-500 md:mt-0.5" /> A
standalone wallet UI for all your users
</li>
<li className="flex items-start gap-2">
<CheckIcon className="w-5 h-5 text-green-500 md:mt-0.5" />{" "}
Custom permissions and billing across your ecosystem
</li>
<li className="flex items-start gap-2">
<CheckIcon className="w-5 h-5 text-green-500 md:mt-0.5" />{" "}
30,000 active wallets included*
</li>
</ul>
<p className="mt-4 text-xs italic text-muted-foreground text-right">
$0.02 per additional wallet
</p>
</div>
</div>
<EcosystemWalletPricingCard />
</section>
<section className="mb-12 lg:px-4">
<CreateEcosystemForm />
@@ -11,12 +11,13 @@ export type Ecosystem = {
updatedAt: string;
};
export type PartnerPermission = "PROMPT_USER_V1" | "FULL_CONTROL_V1";
export type Partner = {
id: string;
name: string;
allowlistedDomains: string[];
allowlistedBundleIds: string[];
permissions: ["PROMPT_USER_V1" | "FULL_CONTROL_V1"];
permissions: [PartnerPermission];
createdAt: string;
updatedAt: string;
};
@@ -44,7 +44,7 @@ export default function DashboardConnectLayout(props: {
children: React.ReactNode;
}) {
return (
<div className="flex flex-col md:flex-row md:h-full container">
<div className="flex flex-col md:flex-row md:h-full container px-4">
<SidebarNav sections={SIDEBAR_SECTIONS} />
{props.children}
</div>
@@ -12,6 +12,7 @@ import type { ApiKey } from "@3rdweb-sdk/react/hooks/useApi";
import { PayAnalytics } from "components/pay/PayAnalytics/PayAnalytics";
import { PayConfig } from "components/pay/PayConfig";
import { useMemo, useState } from "react";
import { WebhooksPage } from "./webhooks.client";
export function PayUI(props: {
apiKeys: ApiKey[];
@@ -19,9 +20,9 @@ export function PayUI(props: {
const [selectedKeyId, setSelectedKeyId] = useState<string>(
props.apiKeys[0].key,
);
const [activeTab, setActiveTab] = useState<"settings" | "analytics">(
"analytics",
);
const [activeTab, setActiveTab] = useState<
"settings" | "analytics" | "webhooks"
>("analytics");
const selectedKey = useMemo(() => {
// biome-ignore lint/style/noNonNullAssertion: This is a valid use case for non-null assertion
@@ -40,6 +41,12 @@ export function PayUI(props: {
onClick: () => setActiveTab("analytics"),
isEnabled: true,
},
{
name: "Webhooks",
isActive: activeTab === "webhooks",
onClick: () => setActiveTab("webhooks"),
isEnabled: true,
},
{
name: "Settings",
isActive: activeTab === "settings",
@@ -69,6 +76,7 @@ export function PayUI(props: {
{/* TODO: split this into sub-pages */}
{activeTab === "analytics" && <PayAnalytics apiKey={selectedKey} />}
{activeTab === "settings" && <PayConfig apiKey={selectedKey} />}
{activeTab === "webhooks" && <WebhooksPage apiKey={selectedKey} />}
</>
);
}
@@ -0,0 +1,339 @@
import { CopyTextButton } from "@/components/ui/CopyTextButton";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Form,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
RequiredFormLabel,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import type { ApiKey } from "@3rdweb-sdk/react/hooks/useApi";
import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { formatDistanceToNow } from "date-fns";
import { PlusIcon, TrashIcon } from "lucide-react";
import { type PropsWithChildren, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { shortenString } from "utils/usedapp-external";
import { z } from "zod";
type Webhook = {
url: string;
label: string;
active: boolean;
createdAt: string;
id: string;
secret: string;
};
export type WebhooksPageProps = {
apiKey: ApiKey;
};
export function WebhooksPage(props: WebhooksPageProps) {
const webhooksQuery = useQuery({
queryKey: ["webhooks", props.apiKey.key],
queryFn: async () => {
const res = await fetch(
`/api/server-proxy/pay/webhooks/get-all?clientId=${props.apiKey.key}`,
{
headers: {
"Content-Type": "application/json",
},
},
);
const json = await res.json();
return json.result as Array<Webhook>;
},
});
if (webhooksQuery.isLoading) {
return <Spinner className="size-8 mx-auto" />;
}
if (!webhooksQuery.data?.length) {
return (
<div className="border border-border rounded-lg p-8 text-center flex flex-col items-center gap-8">
<h2 className="text-xl font-semibold">No webhooks configured yet.</h2>
<CreateWebhookButton apiKey={props.apiKey}>
<Button variant="primary" className="gap-1">
<PlusIcon className="size-4" />
<span>Create Webhook</span>
</Button>
</CreateWebhookButton>
</div>
);
}
return (
<div className="flex flex-col gap-4">
<Table>
<TableHeader>
<TableRow>
<TableHead>Label</TableHead>
<TableHead>Url</TableHead>
<TableHead>Secret</TableHead>
<TableHead>Created</TableHead>
<TableHead className="text-right">
<CreateWebhookButton apiKey={props.apiKey}>
<Button size="sm" variant="primary" className="gap-1">
<PlusIcon className="size-4" />
<span>Create New Webhook</span>
</Button>
</CreateWebhookButton>
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{webhooksQuery.data.map((webhook) => (
<TableRow key={webhook.id}>
<TableCell className="font-medium">{webhook.label}</TableCell>
<TableCell>{webhook.url}</TableCell>
<TableCell>
<CopyTextButton
textToShow={shortenString(webhook.secret)}
textToCopy={webhook.secret}
tooltip={
"Use this secret to validate the authenticity of incoming webhook requests."
}
copyIconPosition={"right"}
/>
</TableCell>
<TableCell>
{formatDistanceToNow(webhook.createdAt, { addSuffix: true })}
</TableCell>
<TableCell className="text-right">
<DeleteWebhookButton
apiKey={props.apiKey}
webhookId={webhook.id}
>
<Button variant="ghost" size="icon">
<TrashIcon className="size-5" strokeWidth={1} />
</Button>
</DeleteWebhookButton>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
const formSchema = z.object({
url: z.string().url("Please enter a valid URL."),
label: z.string().min(1, "Please enter a label."),
});
function CreateWebhookButton(props: PropsWithChildren<WebhooksPageProps>) {
const [open, setOpen] = useState(false);
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
url: "",
label: "",
},
});
const queryClient = useQueryClient();
const createMutation = useMutation({
mutationFn: async (values: z.infer<typeof formSchema>) => {
const res = await fetch("/api/server-proxy/pay/webhooks/create", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ ...values, clientId: props.apiKey.key }),
});
const json = await res.json();
return json.result as string;
},
onSuccess: () => {
return queryClient.invalidateQueries(["webhooks", props.apiKey.key]);
},
});
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>{props.children}</DialogTrigger>
<DialogContent>
<Form {...form}>
<form
onSubmit={form.handleSubmit((values) =>
toast.promise(
createMutation.mutateAsync(values, {
onError: (err) =>
toast.error("Failed to create webhook", {
description: (err as Error).message,
}),
onSuccess: () => {
setOpen(false);
form.reset();
form.clearErrors();
form.setValue("url", "");
form.setValue("label", "");
},
}),
{
loading: "Creating webhook...",
success: "Webhook created",
error: "Failed to create webhook",
},
),
)}
className="flex flex-col gap-4"
>
<DialogHeader>
<DialogTitle>Create Webhook</DialogTitle>
<DialogDescription>
Receive a webhook notification when a pay event occurs.
</DialogDescription>
</DialogHeader>
<FormField
name="url"
render={({ field }) => (
<FormItem>
<RequiredFormLabel>URL</RequiredFormLabel>
<Input {...field} placeholder="https://" />
<FormDescription>
This is the URL that will receive the webhook.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
name="label"
render={({ field }) => (
<FormItem>
<RequiredFormLabel>Label</RequiredFormLabel>
<Input {...field} placeholder="My Webhook" />
<FormDescription>
A label to help you identify this webhook.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
{/* Note: this is a "fake" form field since there is nothing to select yet */}
<FormItem>
<FormLabel>
Event Type <Badge variant="outline">Coming Soon</Badge>
</FormLabel>
<Select disabled defaultValue="purchase_complete">
<SelectTrigger className="w-full">
<SelectValue placeholder="Purchase Complete" />
</SelectTrigger>
<SelectContent>
<SelectItem value="purchase_complete">
Purchase Complete
</SelectItem>
</SelectContent>
</Select>
<FormDescription>
Which event should trigger this webhook?
</FormDescription>
<FormMessage />
</FormItem>
<DialogFooter>
<Button type="submit" disabled={createMutation.isLoading}>
Create
</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
</Dialog>
);
}
function DeleteWebhookButton(
props: PropsWithChildren<WebhooksPageProps & { webhookId: string }>,
) {
const [open, setOpen] = useState(false);
const queryClient = useQueryClient();
const deleteMutation = useMutation({
mutationFn: async (id: string) => {
const res = await fetch("/api/server-proxy/pay/webhooks/revoke", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ id, clientId: props.apiKey.key }),
});
const json = await res.json();
return json.result as string;
},
onSuccess: () => {
return queryClient.invalidateQueries(["webhooks", props.apiKey.key]);
},
});
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>{props.children}</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete the
webhook.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button
variant="destructive"
onClick={() => {
toast.promise(
deleteMutation.mutateAsync(props.webhookId, {
onSuccess: () => {
setOpen(false);
},
}),
{
loading: "Deleting webhook...",
success: "Webhook deleted",
error: "Failed to delete webhook",
},
);
}}
disabled={deleteMutation.isLoading}
>
Yes, Delete Webhook
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
@@ -1,4 +1,4 @@
import { DashboardFooter } from "../components/DashboardFooter";
import { AppFooter } from "@/components/blocks/app-footer";
import { DashboardHeader } from "../components/Header/DashboardHeader";
export default function DashboardLayout(props: { children: React.ReactNode }) {
@@ -7,7 +7,7 @@ export default function DashboardLayout(props: { children: React.ReactNode }) {
<div className="flex flex-col h-full">
<DashboardHeader />
<main className="grow">{props.children}</main>
<DashboardFooter />
<AppFooter />
</div>
</>
);
@@ -21,37 +21,39 @@ function Colors() {
return (
<div>
<h2 className="text-2xl mb-5 font-semibold tracking-tight">
Background Colors
Neutral background Colors
</h2>
<div className="flex-col md:flex-row flex gap-4 flex-wrap">
<BgColorPreview className="bg-background" />
<BgColorPreview className="bg-secondary" />
<BgColorPreview className="bg-muted" />
<BgColorPreview className="bg-accent" />
<BgColorPreview className="bg-primary" />
<BgColorPreview className="bg-destructive" />
<BgColorPreview className="bg-card" />
<BgColorPreview className="bg-popover" />
<BgColorPreview className="bg-inverted" />
</div>
<Separator className="my-10" />
<h2 className="text-2xl mb-5 font-semibold tracking-tight">
Foreground Colors
Foreground Colors with Background
</h2>
<div className="flex flex-col gap-5">
<div className="flex flex-col gap-2">
<TextColorPreview className="text-foreground" />
<TextColorPreview className="text-secondary-foreground" />
<TextColorPreview className="text-muted-foreground" />
<TextColorPreview className="text-accent-foreground" />
<TextColorPreview className="text-primary-foreground" />
<TextColorPreview className="text-success-foreground" />
<TextColorPreview className="text-destructive-foreground" />
<TextColorPreview className="text-card-foreground" />
<TextColorPreview className="text-popover-foreground" />
<TextColorPreview className="text-popover-foreground bg-popover" />
<TextColorPreview className="text-card-foreground bg-card" />
<TextColorPreview className="text-secondary-foreground bg-secondary" />
<TextColorPreview className="text-muted-foreground bg-muted" />
<TextColorPreview className="text-accent-foreground bg-accent" />
<TextColorPreview className="text-primary-foreground bg-primary" />
<TextColorPreview className="text-success-foreground bg-success" />
<TextColorPreview className="text-destructive-foreground bg-destructive" />
<TextColorPreview className="text-warning-foreground bg-warning" />
<TextColorPreview className="text-inverted-foreground bg-inverted" />
<TextColorPreview className="text-destructive-text" />
<TextColorPreview className="text-success-text" />
</div>
</div>
);
@@ -75,7 +77,7 @@ function TextColorPreview(props: { className: string }) {
return (
<div className="grid grid-cols-2">
<p>{props.className}</p>
<p className={cn("text-base", props.className)}>
<p className={cn("text-base p-2 rounded-lg", props.className)}>
The quick brown fox jumps over the lazy dog
</p>
</div>
@@ -115,7 +115,8 @@ export function CreateTicket() {
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
{/* Check this */}
<DialogContent>
<form ref={formRef} action={formAction}>
<DialogHeader>
<DialogTitle>Get in touch</DialogTitle>
@@ -128,7 +129,7 @@ export function CreateTicket() {
{/* render the form */}
{user?.jwt ? (
<>
<div className="py-4 flex flex-col gap-4">
<div className="py-4 flex flex-col gap-4 mt-3">
<SupportForm_SelectInput
formLabel="What do you need help with?"
name="product"
Binary file not shown.

After

Width:  |  Height:  |  Size: 849 KiB

@@ -7,6 +7,7 @@ import {
CardTitle,
} from "@/components/ui/card";
import { BookOpenIcon, ChevronRightIcon } from "lucide-react";
import type { Metadata } from "next";
import Image from "next/image";
import Link from "next/link";
import { SiDiscord } from "react-icons/si";
@@ -18,6 +19,12 @@ import miscIcon from "../../../../public/assets/support/misc.svg";
import connectIcon from "../../../../public/assets/support/wallets.png";
import { CreateTicket } from "./components/create-ticket.client";
export const metadata: Metadata = {
title: "thirdweb Support",
openGraph: {
title: "thirdweb Support",
},
};
const HELP_PRODUCTS = [
{
title: "Connect",
@@ -1,12 +1,12 @@
"use client";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationNext,
PaginationPrevious,
} from "../../../@/components/ui/pagination";
} from "@/components/ui/pagination";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import React from "react";
@@ -1,7 +1,7 @@
"use client";
import { Button } from "@/components/ui/button";
import { ChevronDown } from "lucide-react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { Button } from "../../../@/components/ui/button";
export type SortingHeaderProps = {
sortBy: string;
@@ -1,10 +1,7 @@
"use client";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import {
ToggleGroup,
ToggleGroupItem,
} from "../../../@/components/ui/toggle-group";
import type { TimeRange } from "../../../lib/search";
import type { TimeRange } from "../../../../lib/search";
export function TimeRangeSwitcher() {
const router = useRouter();
@@ -1,6 +1,3 @@
import type { ChainMetadata } from "thirdweb/chains";
import { shortenAddress } from "thirdweb/utils";
import { ChainIcon } from "../../(dashboard)/(chain)/components/server/chain-icon";
import {
Table,
TableBody,
@@ -9,11 +6,17 @@ import {
TableHead,
TableHeader,
TableRow,
} from "../../../@/components/ui/table";
import type { SortBy, TimeRange, TrendingContract } from "../../../lib/search";
} from "@/components/ui/table";
import type { ChainMetadata } from "thirdweb/chains";
import { shortenAddress } from "thirdweb/utils";
import { ChainIcon } from "../../(chain)/components/server/chain-icon";
import type {
SortBy,
TimeRange,
TrendingContract,
} from "../../../../lib/search";
import { TablePagination } from "./pagination.client";
import { SortingHeader } from "./sorting-header.client";
import { TimeRangeSwitcher } from "./time-range-switcher.client";
export async function TrendingContractSection(props: {
topContracts: TrendingContract[];
@@ -28,9 +31,6 @@ export async function TrendingContractSection(props: {
return (
props.topContracts.length > 0 && (
<div className="flex flex-col gap-4 w-full">
<div className="w-full flex flex-row gap-4 justify-center md:justify-end py-4">
<TimeRangeSwitcher />
</div>
<Table
className={`border-white ${isLandingPage && "border-b-[1px] font-mono text-xs md:text-sm mb-4"}`}
>
@@ -146,7 +146,7 @@ function ChangeCell(props: { displayCount: string; change: number }) {
if (!props.displayCount) {
return null;
}
const color = props.change > 0 ? "text-success-foreground" : "text-red-400";
const color = props.change > 0 ? "text-success-text" : "text-red-400";
const badge = (
<span className={`${color}`}>
{props.change > 0 ? "▲" : "▼"}{" "}
@@ -1,4 +1,4 @@
import { Spinner } from "../../@/components/ui/Spinner/Spinner";
import { Spinner } from "@/components/ui/Spinner/Spinner";
export default function Loading() {
return (

Before

Width:  |  Height:  |  Size: 729 KiB

After

Width:  |  Height:  |  Size: 729 KiB

@@ -3,7 +3,7 @@ import {
type SortBy,
type TimeRange,
fetchTopContracts,
} from "../../lib/search";
} from "../../../lib/search";
import { TrendingContractSection } from "./components/trending-table";
export const metadata: Metadata = {
@@ -20,6 +20,7 @@ export default async function DashboardContractTrendingPage(props: {
}) {
const topContracts = await fetchTopContracts({
...props.searchParams,
timeRange: "month",
});
return (
<div>
@@ -1,49 +0,0 @@
import Link from "next/link";
export function DashboardFooter() {
return (
<footer className="flex flex-col items-center justify-center gap-4 p-4 border-t md:flex-row bg-card">
<a
target="_blank"
href="https://feedback.thirdweb.com"
rel="noreferrer"
className="text-sm text-muted-foreground hover:underline"
>
Feedback
</a>
<Link
href="/privacy"
target="_blank"
rel="noreferrer"
className="text-sm text-muted-foreground hover:underline"
>
Privacy Policy
</Link>
<Link
href="/tos"
target="_blank"
rel="noreferrer"
className="text-sm text-muted-foreground hover:underline"
>
Terms of Service
</Link>
<Link
href="/gas"
target="_blank"
rel="noreferrer"
className="text-sm text-muted-foreground hover:underline"
>
Gas Estimator
</Link>
<Link
href="/chainlist"
target="_blank"
rel="noreferrer"
className="text-sm text-muted-foreground hover:underline"
>
Chain List
</Link>
<p className="text-sm text-muted-foreground">Copyright © 2024 thirdweb</p>
</footer>
);
}
@@ -11,59 +11,58 @@ import { headerLinks } from "./headerLinks";
export function DashboardHeader() {
return (
// the "h-24" avoids layout shift when connecting wallet (connected wallet button is taller than disconnected...)
<header className="flex items-center flex-shrink-0 h-20 border-b bg-card md:h-24">
<div className="container flex flex-row items-center justify-between gap-5 py-4">
{/* Left */}
<div className="flex items-center gap-5">
<div className="flex items-center gap-2">
<MobileBurgerMenu />
<Link href="/dashboard">
<ThirdwebMiniLogo className="size-10" />
</Link>
</div>
<div className="items-center hidden gap-5 md:flex">
{headerLinks.left.map((link) => (
<NavLink
key={link.href}
href={link.href}
target={link.href.startsWith("https") ? "_blank" : undefined}
className="text-secondary-foreground hover:text-foreground"
activeClassName="text-foreground font-semibold"
>
{link.name}
</NavLink>
))}
</div>
<header className="flex flex-row items-center justify-between flex-shrink-0 h-20 border-b border-border bg-background md:h-24 py-4 px-4 md:px-6">
{/* Left */}
<div className="flex items-center gap-6">
<div className="flex items-center gap-2">
<MobileBurgerMenu />
<Link href="/dashboard">
<ThirdwebMiniLogo className="h-7" />
</Link>
</div>
{/* Right */}
<div className="flex items-center gap-5">
<div className="items-center hidden gap-5 lg:flex">
<div className="items-center hidden gap-2 md:flex">
{headerLinks.left.map((link) => (
<NavLink
key={link.href}
href={link.href}
target={link.href.startsWith("https") ? "_blank" : undefined}
className="text-foreground font-medium py-2 px-[10px] hover:underline"
activeClassName="font-semibold"
>
{link.name}
</NavLink>
))}
</div>
</div>
{/* Right */}
<div className="flex items-center gap-4">
<div className="items-center gap-2 lg:flex">
<div className="items-center hidden gap-2 lg:flex">
{headerLinks.right.map((link) => (
<Link
key={link.href}
href={link.href}
target={link.href.startsWith("https") ? "_blank" : undefined}
className="text-secondary-foreground hover:text-foreground"
className="text-foreground font-medium py-2 px-[10px] hover:underline"
>
{link.name}
</Link>
))}
</div>
<ColorModeToggle />
<ClientOnly
ssr={
<div className="w-[144px] h-[48px] bg-muted border rounded-lg flex items-center justify-center">
<Spinner className="size-4" />
</div>
}
>
<CustomConnectWallet />
</ClientOnly>
</div>
<ClientOnly
ssr={
<div className="w-[144px] h-[48px] bg-muted border rounded-lg flex items-center justify-center">
<Spinner className="size-4" />
</div>
}
>
<CustomConnectWallet />
</ClientOnly>
</div>
</header>
);
@@ -26,7 +26,7 @@ export function MobileBurgerMenu() {
return (
<>
<Button
variant="ghost"
variant="outline"
size="icon"
className="md:hidden"
onClick={() => setShowBurgerMenu(!showBurgerMenu)}
@@ -19,13 +19,7 @@ export const ClientOnly: ComponentWithChildren<ClientOnlyProps> = ({
ssr,
style,
}) => {
const [hasMounted, setHasMounted] = useState(false);
// FIXME: legitimate usecase - however ideally we wouldn't need this entire file
// eslint-disable-next-line no-restricted-syntax
useEffect(() => {
setHasMounted(true);
}, []);
const hasMounted = useIsClientMounted();
if (!hasMounted) {
return <> {ssr} </>;
@@ -44,3 +38,14 @@ export const ClientOnly: ComponentWithChildren<ClientOnlyProps> = ({
</div>
);
};
export function useIsClientMounted() {
const [hasMounted, setHasMounted] = useState(false);
// eslint-disable-next-line no-restricted-syntax
useEffect(() => {
setHasMounted(true);
}, []);
return hasMounted;
}
@@ -6,7 +6,6 @@ import {
useEVMContractInfo,
} from "@3rdweb-sdk/react/hooks/useActiveChainId";
import { useQueryClient } from "@tanstack/react-query";
import type { Chain } from "@thirdweb-dev/chains";
import { ThirdwebSDKProvider } from "@thirdweb-dev/react";
import {
DASHBOARD_THIRDWEB_CLIENT_ID,
@@ -19,6 +18,7 @@ import { getDashboardChainRpc } from "lib/rpc";
import { StorageSingleton } from "lib/sdk";
import { useEffect, useMemo, useState } from "react";
import { ethers5Adapter } from "thirdweb/adapters/ethers5";
import { type ChainMetadata, ethereum } from "thirdweb/chains";
import {
useActiveAccount,
useActiveWallet,
@@ -26,6 +26,22 @@ import {
} from "thirdweb/react";
import { setThirdwebDomains } from "thirdweb/utils";
import type { ComponentWithChildren } from "types/component-with-children";
import type { StoredChain } from "../../contexts/configured-chains";
const PLACEHOLDER_CHAIN: StoredChain = {
chainId: 1,
chain: "ETH",
name: "Ethereum",
rpc: [ethereum.rpc],
nativeCurrency: {
decimals: 18,
name: "Ether",
symbol: "ETH",
},
shortName: "eth",
slug: "ethereum",
testnet: false,
};
const THIRDWEB_API_HOST = new URL(
process.env.NEXT_PUBLIC_THIRDWEB_API_HOST || "https://api.thirdweb.com",
@@ -44,7 +60,7 @@ setThirdwebDomains({
export interface DashboardThirdwebProviderProps {
contractInfo?: EVMContractInfo;
activeChain?: Chain;
activeChain?: ChainMetadata;
}
export const DashboardThirdwebProviderSetup: ComponentWithChildren<
@@ -59,7 +75,7 @@ export const DashboardThirdwebProviderSetup: ComponentWithChildren<
if (!chain) {
return undefined;
}
const rpcUrl = getDashboardChainRpc(chain);
const rpcUrl = getDashboardChainRpc(chain.chainId);
if (!rpcUrl) {
return undefined;
}
@@ -76,7 +92,9 @@ export const DashboardThirdwebProviderSetup: ComponentWithChildren<
queryClient={queryClient}
signer={ethersSigner}
activeChain={activeChain}
supportedChains={supportedChains}
supportedChains={
supportedChains.length ? supportedChains : [PLACEHOLDER_CHAIN]
}
sdkOptions={{
gasSettings: { maxPriceInGwei: 650 },
readonlySettings,
@@ -13,12 +13,12 @@ import {
useDisclosure,
} from "@chakra-ui/react";
import { AiOutlineWarning } from "@react-icons/all-files/ai/AiOutlineWarning";
import { ChainId, useSDK, useSDKChainId } from "@thirdweb-dev/react";
import { BigNumber } from "ethers";
import { useSDK, useSDKChainId } from "@thirdweb-dev/react";
import { useTrack } from "hooks/analytics/useTrack";
import { useSupportedChain } from "hooks/chains/configureChains";
import { forwardRef, useCallback, useMemo, useRef } from "react";
import { VscDebugDisconnect } from "react-icons/vsc";
import { localhost } from "thirdweb/chains";
import {
useActiveAccount,
useActiveWallet,
@@ -69,9 +69,7 @@ export const MismatchButton = forwardRef<HTMLButtonElement, ButtonProps>(
/>
);
}
const shouldShowEVMFaucet = BigNumber.from(evmBalance.data?.value || 0).eq(
0,
);
const shouldShowEVMFaucet = (evmBalance.data?.value || 0n) === 0n;
return (
<Popover
initialFocusRef={initialFocusRef}
@@ -244,7 +242,7 @@ const NoFundsNotice: React.FC<NoFundsNoticeProps> = ({ symbol }) => {
const hasFaucet =
chainInfo &&
(chainInfo.chainId === ChainId.Localhost ||
(chainInfo.chainId === localhost.id ||
(chainInfo.faucets && chainInfo.faucets.length > 0));
const requestFunds = async () => {
@@ -254,7 +252,7 @@ const NoFundsNotice: React.FC<NoFundsNoticeProps> = ({ symbol }) => {
action: "click",
label: "request-funds",
});
if (chainInfo.chainId === ChainId.Localhost) {
if (chainInfo.chainId === localhost.id) {
await sdk.wallet.requestFunds(10);
} else if (chainInfo?.faucets && chainInfo.faucets.length > 0) {
const faucet = chainInfo.faucets[0];
@@ -9,9 +9,9 @@ import {
PopoverContent,
PopoverTrigger,
Tooltip,
useColorMode,
} from "@chakra-ui/react";
import { CHAIN_ID_TO_GNOSIS } from "constants/mappings";
import { useTheme } from "next-themes";
import { Fragment, useEffect, useMemo, useRef, useState } from "react";
import { BiTransferAlt } from "react-icons/bi";
import { FiInfo } from "react-icons/fi";
@@ -60,7 +60,7 @@ export const TransactionButton: React.FC<TransactionButtonProps> = ({
onChainSelect,
...restButtonProps
}) => {
const colorMode = useColorMode();
const { theme } = useTheme();
const activeWallet = useActiveWallet();
const walletRequiresExternalConfirmation =
useWalletRequiresExternalConfirmation();
@@ -72,7 +72,7 @@ export const TransactionButton: React.FC<TransactionButtonProps> = ({
[chain],
);
const ColorModeComp = colorMode.colorMode === "dark" ? DarkMode : Fragment;
const ColorModeComp = theme === "dark" ? DarkMode : Fragment;
const numberWidth = useMemo(() => {
// for each digit of transaction count add 8.3px

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