diff --git a/apps/playground-web/src/components/ui/TokenSelector.tsx b/apps/playground-web/src/components/ui/TokenSelector.tsx
index 2462f0a4c11..8d9266c4826 100644
--- a/apps/playground-web/src/components/ui/TokenSelector.tsx
+++ b/apps/playground-web/src/components/ui/TokenSelector.tsx
@@ -10,13 +10,7 @@ import {
import { shortenAddress } from "thirdweb/utils";
import { Badge } from "@/components/ui/badge";
import { Img } from "@/components/ui/Img";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
+import { SelectWithSearch } from "@/components/ui/select-with-search";
import { useAllChainsData } from "@/hooks/chains";
import { useTokensData } from "@/hooks/useTokensData";
import type { TokenMetadata } from "@/lib/types";
@@ -85,12 +79,41 @@ export function TokenSelector(props: {
return value;
}, [tokens]);
+ const options = useMemo(() => {
+ return tokens.map((token) => ({
+ label: token.symbol,
+ value: `${token.chainId}:${token.address}`,
+ }));
+ }, [tokens]);
+
const selectedValue = props.selectedToken
? `${props.selectedToken.chainId}:${props.selectedToken.address}`
: undefined;
+ const searchFn = useCallback(
+ (option: { label: string; value: string }, searchValue: string) => {
+ const token = addressChainToToken.get(option.value);
+ if (!token) {
+ return false;
+ }
+
+ const searchLower = searchValue.toLowerCase();
+ return (
+ token.symbol.toLowerCase().includes(searchLower) ||
+ token.name.toLowerCase().includes(searchLower) ||
+ token.address.toLowerCase().includes(searchLower)
+ );
+ },
+ [addressChainToToken],
+ );
+
const renderTokenOption = useCallback(
- (token: TokenMetadata) => {
+ (option: { label: string; value: string }) => {
+ const token = addressChainToToken.get(option.value);
+ if (!token) {
+ return option.label;
+ }
+
const resolvedSrc = token.iconUri
? replaceIpfsUrl(token.iconUri, props.client)
: fallbackChainIcon;
@@ -121,11 +144,13 @@ export function TokenSelector(props: {
);
},
- [props.disableAddress, props.client],
+ [props.disableAddress, props.client, addressChainToToken],
);
return (
-
+ />
);
}
diff --git a/packages/thirdweb/src/react/core/hooks/usePaymentMethods.ts b/packages/thirdweb/src/react/core/hooks/usePaymentMethods.ts
index d633d0ab336..897f0ff9ad2 100644
--- a/packages/thirdweb/src/react/core/hooks/usePaymentMethods.ts
+++ b/packages/thirdweb/src/react/core/hooks/usePaymentMethods.ts
@@ -8,6 +8,7 @@ import { getClientFetch } from "../../../utils/fetch.js";
import { toTokens, toUnits } from "../../../utils/units.js";
import type { Wallet } from "../../../wallets/interfaces/wallet.js";
import type { PaymentMethod } from "../machines/paymentMachine.js";
+import type { SupportedTokens } from "../utils/defaultTokens.js";
import { useActiveWallet } from "./wallets/useActiveWallet.js";
/**
@@ -33,6 +34,7 @@ export function usePaymentMethods(options: {
client: ThirdwebClient;
payerWallet?: Wallet;
includeDestinationToken?: boolean;
+ supportedTokens?: SupportedTokens;
}) {
const {
destinationToken,
@@ -40,6 +42,7 @@ export function usePaymentMethods(options: {
client,
payerWallet,
includeDestinationToken,
+ supportedTokens,
} = options;
const localWallet = useActiveWallet(); // TODO (bridge): get all connected wallets
const wallet = payerWallet || localWallet;
@@ -118,8 +121,28 @@ export function usePaymentMethods(options: {
(a.originToken.prices.USD || 1)
);
});
- // Move all sufficient balance quotes to the top
- return [...sufficientBalanceQuotes, ...insufficientBalanceQuotes];
+
+ // Filter out quotes that are not included in the supportedTokens (if provided)
+ const tokensToInclude = supportedTokens
+ ? Object.keys(supportedTokens).flatMap(
+ (c: string) =>
+ supportedTokens[Number(c)]?.map((t) => ({
+ chainId: Number(c),
+ address: t.address,
+ })) ?? [],
+ )
+ : [];
+ const finalQuotes = supportedTokens
+ ? [...sufficientBalanceQuotes, ...insufficientBalanceQuotes].filter(
+ (q) =>
+ tokensToInclude.find(
+ (t) =>
+ t.chainId === q.originToken.chainId &&
+ t.address === q.originToken.address,
+ ),
+ )
+ : [...sufficientBalanceQuotes, ...insufficientBalanceQuotes];
+ return finalQuotes;
},
queryKey: [
"payment-methods",
@@ -128,6 +151,7 @@ export function usePaymentMethods(options: {
destinationAmount,
payerWallet?.getAccount()?.address,
includeDestinationToken,
+ supportedTokens,
], // 5 minutes
refetchOnWindowFocus: false,
staleTime: 5 * 60 * 1000,
diff --git a/packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx b/packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx
index a01fe1d589e..bc1540d9b88 100644
--- a/packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx
+++ b/packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx
@@ -17,6 +17,7 @@ import {
type PaymentMethod,
usePaymentMachine,
} from "../../../core/machines/paymentMachine.js";
+import type { SupportedTokens } from "../../../core/utils/defaultTokens.js";
import { webWindowAdapter } from "../../adapters/WindowAdapter.js";
import en from "../ConnectWallet/locale/en.js";
import type { ConnectLocale } from "../ConnectWallet/locale/types.js";
@@ -128,6 +129,7 @@ export interface BridgeOrchestratorProps {
* @default true
*/
showThirdwebBranding?: boolean;
+ supportedTokens?: SupportedTokens;
}
export function BridgeOrchestrator({
@@ -144,6 +146,7 @@ export function BridgeOrchestrator({
presetOptions,
paymentMethods = ["crypto", "card"],
showThirdwebBranding = true,
+ supportedTokens,
}: BridgeOrchestratorProps) {
// Initialize adapters
const adapters = useMemo(
@@ -313,6 +316,7 @@ export function BridgeOrchestrator({
paymentMethods={paymentMethods}
receiverAddress={state.context.receiverAddress}
currency={uiOptions.currency}
+ supportedTokens={supportedTokens}
/>
)}
diff --git a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx
index 5a3c052cf57..c4048a7cac7 100644
--- a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx
+++ b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx
@@ -398,6 +398,7 @@ export function BuyWidget(props: BuyWidgetProps) {
// Show normal bridge orchestrator
content = (
);
}
diff --git a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx
index 830ab55a969..2b70601b4a9 100644
--- a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx
+++ b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx
@@ -409,6 +409,7 @@ export function TransactionWidget(props: TransactionWidgetProps) {
// Show normal bridge orchestrator
content = (