Skip to content

Commit 802d3bf

Browse files
fix: sanitize block explorer URLs (#5237)
1 parent 09b1912 commit 802d3bf

File tree

8 files changed

+52
-11
lines changed

8 files changed

+52
-11
lines changed

.changeset/angry-mayflies-push.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+
Sanitize block explorer URLs

packages/thirdweb/src/react/web/ui/ConnectWallet/TransactionsScreen.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { ExternalLinkIcon } from "@radix-ui/react-icons";
44
import { useState } from "react";
55
import type { ThirdwebClient } from "../../../../client/client.js";
6+
import { formatExplorerAddressUrl } from "../../../../utils/url.js";
67
import { iconSize } from "../../../core/design-system/index.js";
78
import { useChainExplorers } from "../../../core/hooks/others/useChainQuery.js";
89
import { useActiveAccount } from "../../../core/hooks/wallets/useActiveAccount.js";
@@ -125,7 +126,10 @@ export function TransactionsScreen(props: {
125126
<ButtonLink
126127
fullWidth
127128
variant="outline"
128-
href={`${chainExplorers.explorers[0]?.url}/address/${activeAccount?.address}`}
129+
href={formatExplorerAddressUrl(
130+
chainExplorers.explorers[0]?.url ?? "",
131+
activeAccount?.address ?? "",
132+
)}
129133
target="_blank"
130134
as="a"
131135
gap="xs"

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatSteps.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { NATIVE_TOKEN_ADDRESS } from "../../../../../../../constants/addresses.j
1010
import type { BuyWithFiatQuote } from "../../../../../../../pay/buyWithFiat/getQuote.js";
1111
import type { BuyWithFiatStatus } from "../../../../../../../pay/buyWithFiat/getStatus.js";
1212
import { formatNumber } from "../../../../../../../utils/formatNumber.js";
13+
import { formatExplorerTxUrl } from "../../../../../../../utils/url.js";
1314
import {
1415
type Theme,
1516
fontSize,
@@ -345,7 +346,10 @@ export function FiatSteps(props: {
345346
onRampExplorers.explorers[0]?.url && onRampTxHash
346347
? {
347348
label: "View on Explorer",
348-
url: `${onRampExplorers.explorers[0]?.url}/tx/${onRampTxHash}`,
349+
url: formatExplorerTxUrl(
350+
onRampExplorers.explorers[0]?.url,
351+
onRampTxHash,
352+
),
349353
}
350354
: undefined
351355
}
@@ -382,7 +386,10 @@ export function FiatSteps(props: {
382386
toChainExplorers.explorers[0]?.url && toTokenTxHash
383387
? {
384388
label: "View on Explorer",
385-
url: `${toChainExplorers.explorers[0].url}/tx/${toTokenTxHash}`,
389+
url: formatExplorerTxUrl(
390+
toChainExplorers.explorers[0]?.url,
391+
toTokenTxHash,
392+
),
386393
}
387394
: undefined
388395
}

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatTxDetailsTable.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ExternalLinkIcon } from "@radix-ui/react-icons";
22
import { getCachedChain } from "../../../../../../../chains/utils.js";
33
import type { ThirdwebClient } from "../../../../../../../client/client.js";
44
import { formatNumber } from "../../../../../../../utils/formatNumber.js";
5+
import { formatExplorerTxUrl } from "../../../../../../../utils/url.js";
56
import {
67
fontSize,
78
iconSize,
@@ -121,9 +122,10 @@ export function OnRampTxDetailsTable(props: {
121122
<ButtonLink
122123
fullWidth
123124
variant="outline"
124-
href={`${
125-
onRampExplorers.explorers[0].url || ""
126-
}/tx/${onrampTxHash}`}
125+
href={formatExplorerTxUrl(
126+
onRampExplorers.explorers[0]?.url,
127+
onrampTxHash,
128+
)}
127129
target="_blank"
128130
gap="xs"
129131
style={{

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/pay-transactions/SwapDetailsScreen.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { ThirdwebClient } from "../../../../../../../client/client.js";
44
import type { BuyWithCryptoQuote } from "../../../../../../../pay/buyWithCrypto/getQuote.js";
55
import type { ValidBuyWithCryptoStatus } from "../../../../../../../pay/buyWithCrypto/getStatus.js";
66
import { shortenAddress } from "../../../../../../../utils/address.js";
7+
import { formatExplorerTxUrl } from "../../../../../../../utils/url.js";
78
import {
89
fontSize,
910
iconSize,
@@ -199,7 +200,10 @@ export function SwapTxDetailsTable(
199200
<ButtonLink
200201
fullWidth
201202
variant="outline"
202-
href={`${fromChainExplorers.explorers[0].url}/tx/${sourceTxHash}`}
203+
href={formatExplorerTxUrl(
204+
fromChainExplorers.explorers[0]?.url,
205+
sourceTxHash,
206+
)}
203207
target="_blank"
204208
gap="xs"
205209
style={{
@@ -330,7 +334,10 @@ export function SwapTxDetailsTable(
330334
<ButtonLink
331335
fullWidth
332336
variant="outline"
333-
href={`${fromChainExplorers.explorers[0].url}/tx/${sourceTxHash}`}
337+
href={formatExplorerTxUrl(
338+
fromChainExplorers.explorers[0]?.url,
339+
sourceTxHash,
340+
)}
334341
target="_blank"
335342
gap="xs"
336343
style={{
@@ -352,7 +359,10 @@ export function SwapTxDetailsTable(
352359
<ButtonLink
353360
fullWidth
354361
variant="outline"
355-
href={`${toChainExplorers.explorers[0].url}/tx/${destinationTxHash}`}
362+
href={formatExplorerTxUrl(
363+
toChainExplorers.explorers[0]?.url,
364+
destinationTxHash,
365+
)}
356366
target="_blank"
357367
gap="xs"
358368
style={{

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/WalletTransactionHistory.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { ThirdwebClient } from "../../../../../client/client.js";
77
import { getTransactionStore } from "../../../../../transaction/transaction-store.js";
88
import { shortenHex } from "../../../../../utils/address.js";
99
import type { Hex } from "../../../../../utils/encoding/hex.js";
10+
import { formatExplorerTxUrl } from "../../../../../utils/url.js";
1011
import { useCustomTheme } from "../../../../core/design-system/CustomThemeProvider.js";
1112
import { iconSize, spacing } from "../../../../core/design-system/index.js";
1213
import { useWaitForReceipt } from "../../../../core/hooks/contract/useWaitForReceipt.js";
@@ -192,7 +193,7 @@ function TransactionButton(props: {
192193
if (props.explorerUrl) {
193194
return (
194195
<a
195-
href={`${props.explorerUrl}/tx/${props.hash}`}
196+
href={formatExplorerTxUrl(props.explorerUrl, props.hash)}
196197
target="_blank"
197198
rel="noreferrer"
198199
>

packages/thirdweb/src/react/web/ui/TransactionButton/ExecutingScreen.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
33
import type { Hex } from "viem";
44
import type { WaitForReceiptOptions } from "../../../../transaction/actions/wait-for-tx-receipt.js";
55
import type { PreparedTransaction } from "../../../../transaction/prepare-transaction.js";
6+
import { formatExplorerTxUrl } from "../../../../utils/url.js";
67
import { iconSize } from "../../../core/design-system/index.js";
78
import { useChainExplorers } from "../../../core/hooks/others/useChainQuery.js";
89
import { useSendTransaction } from "../../hooks/transaction/useSendTransaction.js";
@@ -106,7 +107,10 @@ export function ExecutingTxScreen(props: {
106107
<ButtonLink
107108
fullWidth
108109
variant="outline"
109-
href={`${chainExplorers.explorers[0]?.url}/tx/${txHash}`}
110+
href={formatExplorerTxUrl(
111+
chainExplorers.explorers[0]?.url ?? "",
112+
txHash,
113+
)}
110114
target="_blank"
111115
as="a"
112116
gap="xs"

packages/thirdweb/src/utils/url.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,11 @@ export function formatWalletConnectUrl(
6363
? formatUniversalUrl(appUrl, wcUri)
6464
: formatNativeUrl(appUrl, wcUri);
6565
}
66+
67+
export function formatExplorerTxUrl(explorerUrl: string, txHash: string) {
68+
return `${explorerUrl.endsWith("/") ? explorerUrl : `${explorerUrl}/`}tx/${txHash}`;
69+
}
70+
71+
export function formatExplorerAddressUrl(explorerUrl: string, address: string) {
72+
return `${explorerUrl.endsWith("/") ? explorerUrl : `${explorerUrl}/`}address/${address}`;
73+
}

0 commit comments

Comments
 (0)