Skip to content

Commit 2d5b05e

Browse files
committed
[MNY-338] Add filters when fetching chains in chain selection ui
1 parent 7ebc32a commit 2d5b05e

File tree

9 files changed

+221
-37
lines changed

9 files changed

+221
-37
lines changed

packages/thirdweb/src/bridge/Chains.ts

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,30 @@ import { ApiError } from "./types/Errors.js";
5454
*/
5555
export async function chains(options: chains.Options): Promise<chains.Result> {
5656
const { client } = options;
57-
5857
return withCache(
5958
async () => {
6059
const clientFetch = getClientFetch(client);
6160
const url = new URL(`${getThirdwebBaseUrl("bridge")}/v1/chains`);
6261

62+
if (options.testnet) {
63+
url.searchParams.set("testnet", options.testnet.toString());
64+
}
65+
66+
// set type or originChainId or destinationChainId
67+
if ("type" in options && options.type) {
68+
url.searchParams.set("type", options.type);
69+
} else if ("originChainId" in options && options.originChainId) {
70+
url.searchParams.set("originChainId", options.originChainId.toString());
71+
} else if (
72+
"destinationChainId" in options &&
73+
options.destinationChainId
74+
) {
75+
url.searchParams.set(
76+
"destinationChainId",
77+
options.destinationChainId.toString(),
78+
);
79+
}
80+
6381
const response = await clientFetch(url.toString());
6482
if (!response.ok) {
6583
const errorJson = await response.json();
@@ -75,7 +93,7 @@ export async function chains(options: chains.Options): Promise<chains.Result> {
7593
return data;
7694
},
7795
{
78-
cacheKey: "bridge-chains",
96+
cacheKey: `bridge-chains-${JSON.stringify(options)}`,
7997
cacheTime: 1000 * 60 * 60 * 1, // 1 hours
8098
},
8199
);
@@ -95,7 +113,32 @@ export declare namespace chains {
95113
type Options = {
96114
/** Your thirdweb client */
97115
client: ThirdwebClient;
98-
};
116+
117+
/**
118+
* If true, returns only testnet chains. Defaults to false.
119+
*/
120+
testnet?: boolean;
121+
} & (
122+
| {
123+
/**
124+
* setting type=origin: Returns all chains that can be used as origin,
125+
* setting type=destination: Returns all chains that can be used as destination
126+
*/
127+
type?: "origin" | "destination";
128+
}
129+
| {
130+
/**
131+
* setting originChainId=X: Returns destination chains reachable from chain X
132+
*/
133+
originChainId?: number;
134+
}
135+
| {
136+
/**
137+
* setting destinationChainId=X: Returns origin chains reachable from chain X
138+
*/
139+
destinationChainId?: number;
140+
}
141+
);
99142

100143
/**
101144
* Result returned from fetching supported bridge chains.

packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import { WithHeader } from "./common/WithHeader.js";
4949
import { useActiveWalletInfo } from "./swap-widget/hooks.js";
5050
import { SelectToken } from "./swap-widget/select-token-ui.js";
5151
import type { ActiveWalletInfo } from "./swap-widget/types.js";
52-
import { useBridgeChains } from "./swap-widget/use-bridge-chains.js";
52+
import { useBridgeChain } from "./swap-widget/use-bridge-chains.js";
5353

5454
type FundWalletProps = {
5555
/**
@@ -211,6 +211,11 @@ export function FundWallet(props: FundWalletProps) {
211211
autoFocusCrossIcon={false}
212212
>
213213
<SelectToken
214+
type="buy"
215+
selections={{
216+
buyChainId: props.selectedToken?.chainId,
217+
sellChainId: undefined,
218+
}}
214219
activeWalletInfo={activeWalletInfo}
215220
onClose={() => setIsTokenSelectionOpen(false)}
216221
client={props.client}
@@ -403,11 +408,11 @@ function TokenSection(props: {
403408
presetOptions: [number, number, number];
404409
}) {
405410
const theme = useCustomTheme();
406-
const chainQuery = useBridgeChains(props.client);
407-
const chain = chainQuery.data?.find(
408-
(chain) => chain.chainId === props.selectedToken?.data?.chainId,
409-
);
410-
411+
const chainQuery = useBridgeChain({
412+
chainId: props.selectedToken?.data?.chainId,
413+
client: props.client,
414+
});
415+
const chain = chainQuery.data;
411416
const fiatPricePerToken = props.selectedToken?.data?.prices[props.currency];
412417

413418
const { fiatValue, tokenValue } = getAmounts(

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ function SwapWidgetContent(
366366
}, [buyToken, sellToken, isPersistEnabled]);
367367

368368
// preload requests
369-
useBridgeChains(props.client);
369+
useBridgeChains({ client: props.client });
370370

371371
// if wallet suddenly disconnects, show screen 1
372372
if (screen.id === "1:swap-ui" || !activeWalletInfo) {

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-chain.tsx

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { Skeleton } from "../../components/Skeleton.js";
1515
import { Spacer } from "../../components/Spacer.js";
1616
import { Text } from "../../components/text.js";
1717
import { SearchInput } from "./SearchInput.js";
18-
import { useBridgeChains } from "./use-bridge-chains.js";
18+
import { useBridgeChainsWithFilters } from "./use-bridge-chains.js";
1919
import { cleanedChainName } from "./utils.js";
2020

2121
type SelectBuyTokenProps = {
@@ -24,13 +24,23 @@ type SelectBuyTokenProps = {
2424
onSelectChain: (chain: BridgeChain) => void;
2525
selectedChain: BridgeChain | undefined;
2626
isMobile: boolean;
27+
type: "buy" | "sell";
28+
selections: {
29+
buyChainId: number | undefined;
30+
sellChainId: number | undefined;
31+
};
2732
};
2833

2934
/**
3035
* @internal
3136
*/
3237
export function SelectBridgeChain(props: SelectBuyTokenProps) {
33-
const chainQuery = useBridgeChains(props.client);
38+
const chainQuery = useBridgeChainsWithFilters({
39+
client: props.client,
40+
type: props.type,
41+
buyChainId: props.selections.buyChainId,
42+
sellChainId: props.selections.sellChainId,
43+
});
3444

3545
return (
3646
<SelectBridgeChainUI
@@ -126,7 +136,7 @@ export function SelectBridgeChainUI(
126136
{props.isPending &&
127137
new Array(20).fill(0).map(() => (
128138
// biome-ignore lint/correctness/useJsxKeyInIterable: ok
129-
<ChainButtonSkeleton />
139+
<ChainButtonSkeleton isMobile={props.isMobile} />
130140
))}
131141

132142
{filteredChains.length === 0 && !props.isPending && (
@@ -148,18 +158,24 @@ export function SelectBridgeChainUI(
148158
);
149159
}
150160

151-
function ChainButtonSkeleton() {
161+
function ChainButtonSkeleton(props: { isMobile: boolean }) {
162+
const iconSizeValue = props.isMobile ? iconSize.lg : iconSize.md;
152163
return (
153164
<div
154165
style={{
155166
display: "flex",
156167
alignItems: "center",
157168
gap: spacing.sm,
158-
padding: `${spacing.sm} ${spacing.sm}`,
169+
padding: props.isMobile
170+
? `${spacing.sm} ${spacing.sm}`
171+
: `${spacing.xs} ${spacing.xs}`,
159172
}}
160173
>
161-
<Skeleton height={`${iconSize.lg}px`} width={`${iconSize.lg}px`} />
162-
<Skeleton height={fontSize.md} width="160px" />
174+
<Skeleton height={`${iconSizeValue}px`} width={`${iconSizeValue}px`} />
175+
<Skeleton
176+
height={props.isMobile ? fontSize.md : fontSize.sm}
177+
width="160px"
178+
/>
163179
</div>
164180
);
165181
}

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { SearchInput } from "./SearchInput.js";
2626
import { SelectChainButton } from "./SelectChainButton.js";
2727
import { SelectBridgeChain } from "./select-chain.js";
2828
import type { ActiveWalletInfo, TokenSelection } from "./types.js";
29-
import { useBridgeChains } from "./use-bridge-chains.js";
29+
import { useBridgeChainsWithFilters } from "./use-bridge-chains.js";
3030
import {
3131
type TokenBalance,
3232
useTokenBalances,
@@ -43,6 +43,11 @@ type SelectTokenUIProps = {
4343
selectedToken: TokenSelection | undefined;
4444
setSelectedToken: (token: TokenSelection) => void;
4545
activeWalletInfo: ActiveWalletInfo | undefined;
46+
type: "buy" | "sell";
47+
selections: {
48+
buyChainId: number | undefined;
49+
sellChainId: number | undefined;
50+
};
4651
};
4752

4853
function findChain(chains: BridgeChain[], activeChainId: number | undefined) {
@@ -58,7 +63,13 @@ const INITIAL_LIMIT = 100;
5863
* @internal
5964
*/
6065
export function SelectToken(props: SelectTokenUIProps) {
61-
const chainQuery = useBridgeChains(props.client);
66+
const chainQuery = useBridgeChainsWithFilters({
67+
client: props.client,
68+
type: props.type,
69+
buyChainId: props.selections.buyChainId,
70+
sellChainId: props.selections.sellChainId,
71+
});
72+
6273
const [search, _setSearch] = useState("");
6374
const debouncedSearch = useDebouncedValue(search, 500);
6475
const [limit, setLimit] = useState(INITIAL_LIMIT);
@@ -146,6 +157,11 @@ function SelectTokenUI(
146157
selectedToken: TokenSelection | undefined;
147158
setSelectedToken: (token: TokenSelection) => void;
148159
showMore: (() => void) | undefined;
160+
type: "buy" | "sell";
161+
selections: {
162+
buyChainId: number | undefined;
163+
sellChainId: number | undefined;
164+
};
149165
},
150166
) {
151167
const isMobile = useIsMobile();
@@ -203,6 +219,8 @@ function SelectTokenUI(
203219
>
204220
<LeftContainer>
205221
<SelectBridgeChain
222+
type={props.type}
223+
selections={props.selections}
206224
onBack={() => setScreen("select-token")}
207225
client={props.client}
208226
isMobile={false}
@@ -269,6 +287,8 @@ function SelectTokenUI(
269287
setScreen("select-token");
270288
}}
271289
selectedChain={props.selectedChain}
290+
type={props.type}
291+
selections={props.selections}
272292
/>
273293
);
274294
}
@@ -467,16 +487,16 @@ function TokenSelectionScreen(props: {
467487
</Container>
468488

469489
{!props.selectedChain && (
470-
<div
490+
<Container
491+
flex="column"
492+
center="both"
493+
expand
471494
style={{
472-
display: "flex",
473-
alignItems: "center",
474-
justifyContent: "center",
475495
minHeight: "300px",
476496
}}
477497
>
478498
<Spinner color="secondaryText" size="xl" />
479-
</div>
499+
</Container>
480500
)}
481501

482502
{props.selectedChain && (

0 commit comments

Comments
 (0)