Skip to content

Commit 62cfbb7

Browse files
committed
SDK: Show error in BuyWidget and SwapWidget UI if fetching token details fails (#8215)
<!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR introduces error handling in the `BuyWidget` and `SwapWidget` UIs, displaying appropriate error messages when fetching token details fails. ### Detailed summary - Added `isError` state to handle errors in token fetching. - Updated `SelectedTokenButton` to check for errors before rendering. - Enhanced `SwapUI` to show error messages based on different query states. - Implemented error display in `FundWallet` for unsupported tokens. - Modified balance display logic to accommodate new error handling. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Inline error banners in Buy and Swap widgets when token details fail to load. - Clear, specific messages for quote, buy-token, and sell-token fetch failures. - Improvements - Selected token UI now falls back gracefully on errors instead of showing partial data. - Balance display uses richer token info (value, decimals, symbol, name) for accuracy. - More consistent handling of unsupported tokens across the flow. - Bug Fixes - Prevents stale token icons/details from appearing during error states. - Disables auto-retry on token price fetches to reduce UI flicker. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent d7104f6 commit 62cfbb7

File tree

4 files changed

+55
-11
lines changed

4 files changed

+55
-11
lines changed

.changeset/rare-buckets-fly.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Show error in BuyWidget and SwapWidget UI if fetching token details fails

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

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,14 @@ export function FundWallet(props: FundWalletProps) {
251251
? tokenQuery.data.token
252252
: undefined,
253253
isFetching: tokenQuery.isFetching,
254+
isError:
255+
tokenQuery.isError ||
256+
tokenQuery.data?.type === "unsupported_token",
254257
}
255258
: undefined
256259
}
257260
balance={{
258-
data: tokenBalanceQuery.data?.value,
261+
data: tokenBalanceQuery.data,
259262
isFetching: tokenBalanceQuery.isFetching,
260263
}}
261264
client={props.client}
@@ -279,6 +282,22 @@ export function FundWallet(props: FundWalletProps) {
279282

280283
<Spacer y="md" />
281284

285+
{(tokenQuery.isError ||
286+
tokenQuery.data?.type === "unsupported_token") && (
287+
<div
288+
style={{
289+
border: `1px solid ${theme.colors.borderColor}`,
290+
borderRadius: radius.full,
291+
padding: spacing.xs,
292+
marginBottom: spacing.md,
293+
}}
294+
>
295+
<Text size="sm" color="danger" center>
296+
Failed to fetch token details
297+
</Text>
298+
</div>
299+
)}
300+
282301
{/* Continue Button */}
283302
{activeWalletInfo ? (
284303
<Button
@@ -373,6 +392,7 @@ function TokenSection(props: {
373392
| {
374393
data: TokenWithPrices | undefined;
375394
isFetching: boolean;
395+
isError: boolean;
376396
}
377397
| undefined;
378398
currency: SupportedFiatCurrency;
@@ -381,7 +401,14 @@ function TokenSection(props: {
381401
title: string;
382402
isConnected: boolean;
383403
balance: {
384-
data: bigint | undefined;
404+
data:
405+
| {
406+
value: bigint;
407+
decimals: number;
408+
symbol: string;
409+
name: string;
410+
}
411+
| undefined;
385412
isFetching: boolean;
386413
};
387414
onWalletClick: () => void;
@@ -565,17 +592,16 @@ function TokenSection(props: {
565592
<Text size="xs" color="secondaryText">
566593
Current Balance
567594
</Text>
568-
{props.balance.data === undefined ||
569-
props.selectedToken.data === undefined ? (
595+
{props.balance.data === undefined ? (
570596
<Skeleton height={fontSize.xs} width="100px" />
571597
) : (
572598
<Text size="xs" color="primaryText">
573599
{formatTokenAmount(
574-
props.balance.data,
575-
props.selectedToken.data.decimals,
600+
props.balance.data.value,
601+
props.balance.data.decimals,
576602
5,
577603
)}{" "}
578-
{props.selectedToken.data.symbol}
604+
{props.balance.data.symbol}
579605
</Text>
580606
)}
581607
</div>

packages/thirdweb/src/react/web/ui/Bridge/common/selected-token-button.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export function SelectedTokenButton(props: {
2121
| {
2222
data: TokenWithPrices | undefined;
2323
isFetching: boolean;
24+
isError: boolean;
2425
}
2526
| undefined;
2627
client: ThirdwebClient;
@@ -47,7 +48,7 @@ export function SelectedTokenButton(props: {
4748
{/* icons */}
4849
<Container relative color="secondaryText">
4950
{/* token icon */}
50-
{props.selectedToken ? (
51+
{props.selectedToken && !props.selectedToken.isError ? (
5152
<Img
5253
key={props.selectedToken?.data?.iconUri}
5354
src={
@@ -112,7 +113,7 @@ export function SelectedTokenButton(props: {
112113
</Container>
113114

114115
{/* token symbol and chain name */}
115-
{props.selectedToken ? (
116+
{props.selectedToken && !props.selectedToken.isError ? (
116117
<Container flex="column" style={{ gap: "3px" }}>
117118
{props.selectedToken?.isFetching ? (
118119
<Skeleton width="60px" height={fontSize.md} />

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ function useTokenPrice(options: {
9696
);
9797
},
9898
refetchOnMount: false,
99+
retry: false,
99100
refetchOnWindowFocus: false,
100101
});
101102
}
@@ -320,6 +321,7 @@ export function SwapUI(props: SwapUIProps) {
320321
? {
321322
data: sellTokenQuery.data,
322323
isFetching: sellTokenQuery.isFetching,
324+
isError: sellTokenQuery.isError,
323325
}
324326
: undefined
325327
}
@@ -372,6 +374,7 @@ export function SwapUI(props: SwapUIProps) {
372374
? {
373375
data: buyTokenQuery.data,
374376
isFetching: buyTokenQuery.isFetching,
377+
isError: buyTokenQuery.isError,
375378
}
376379
: undefined
377380
}
@@ -389,7 +392,9 @@ export function SwapUI(props: SwapUIProps) {
389392
/>
390393

391394
{/* error message */}
392-
{preparedResultQuery.error ? (
395+
{preparedResultQuery.error ||
396+
buyTokenQuery.isError ||
397+
sellTokenQuery.isError ? (
393398
<Text
394399
size="sm"
395400
color="danger"
@@ -398,7 +403,13 @@ export function SwapUI(props: SwapUIProps) {
398403
paddingBlock: spacing.md,
399404
}}
400405
>
401-
Failed to get a quote
406+
{preparedResultQuery.error
407+
? "Failed to get a quote"
408+
: buyTokenQuery.isError
409+
? "Failed to fetch buy token details"
410+
: sellTokenQuery.isError
411+
? "Failed to fetch sell token details"
412+
: "Failed to get a quote"}
402413
</Text>
403414
) : (
404415
<Spacer y="md" />
@@ -626,6 +637,7 @@ function TokenSection(props: {
626637
| {
627638
data: TokenWithPrices | undefined;
628639
isFetching: boolean;
640+
isError: boolean;
629641
}
630642
| undefined;
631643
currency: SupportedFiatCurrency;

0 commit comments

Comments
 (0)