diff --git a/.changeset/blue-comics-doubt.md b/.changeset/blue-comics-doubt.md new file mode 100644 index 00000000000..d99be9ea08b --- /dev/null +++ b/.changeset/blue-comics-doubt.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +Better error messages in PayEmbed diff --git a/packages/thirdweb/src/bridge/Buy.ts b/packages/thirdweb/src/bridge/Buy.ts index b4e2ffbc5f7..99fe7880067 100644 --- a/packages/thirdweb/src/bridge/Buy.ts +++ b/packages/thirdweb/src/bridge/Buy.ts @@ -4,6 +4,7 @@ import type { ThirdwebClient } from "../client/client.js"; import { getThirdwebBaseUrl } from "../utils/domains.js"; import { getClientFetch } from "../utils/fetch.js"; import { stringify } from "../utils/json.js"; +import { ApiError } from "./types/Errors.js"; import type { PreparedQuote, Quote } from "./types/Quote.js"; /** @@ -127,9 +128,12 @@ export async function quote(options: quote.Options): Promise { const response = await clientFetch(url.toString()); if (!response.ok) { const errorJson = await response.json(); - throw new Error( - `${errorJson.code} | ${errorJson.message} - ${errorJson.correlationId}`, - ); + throw new ApiError({ + code: errorJson.code || "UNKNOWN_ERROR", + message: errorJson.message || response.statusText, + correlationId: errorJson.correlationId || undefined, + statusCode: response.status, + }); } const { data }: { data: Quote } = await response.json(); @@ -357,9 +361,12 @@ export async function prepare( }); if (!response.ok) { const errorJson = await response.json(); - throw new Error( - `${errorJson.code} | ${errorJson.message} - ${errorJson.correlationId}`, - ); + throw new ApiError({ + code: errorJson.code || "UNKNOWN_ERROR", + message: errorJson.message || response.statusText, + correlationId: errorJson.correlationId || undefined, + statusCode: response.status, + }); } const { data }: { data: PreparedQuote } = await response.json(); diff --git a/packages/thirdweb/src/bridge/Chains.ts b/packages/thirdweb/src/bridge/Chains.ts index a68a06c4b2a..9e9a1dea1ff 100644 --- a/packages/thirdweb/src/bridge/Chains.ts +++ b/packages/thirdweb/src/bridge/Chains.ts @@ -2,6 +2,7 @@ import type { ThirdwebClient } from "../client/client.js"; import { getThirdwebBaseUrl } from "../utils/domains.js"; import { getClientFetch } from "../utils/fetch.js"; import type { Chain } from "./types/Chain.js"; +import { ApiError } from "./types/Errors.js"; /** * Retrieves supported Universal Bridge chains. @@ -59,7 +60,12 @@ export async function chains(options: chains.Options): Promise { const response = await clientFetch(url.toString()); if (!response.ok) { const errorJson = await response.json(); - throw new Error(`${errorJson.code} | ${errorJson.message}`); + throw new ApiError({ + code: errorJson.code || "UNKNOWN_ERROR", + message: errorJson.message || response.statusText, + correlationId: errorJson.correlationId || undefined, + statusCode: response.status, + }); } const { data }: { data: Chain[] } = await response.json(); diff --git a/packages/thirdweb/src/bridge/Onramp.ts b/packages/thirdweb/src/bridge/Onramp.ts index 8add6929c72..bacd1236315 100644 --- a/packages/thirdweb/src/bridge/Onramp.ts +++ b/packages/thirdweb/src/bridge/Onramp.ts @@ -3,6 +3,7 @@ import type { ThirdwebClient } from "../client/client.js"; import { getThirdwebBaseUrl } from "../utils/domains.js"; import { getClientFetch } from "../utils/fetch.js"; import { stringify } from "../utils/json.js"; +import { ApiError } from "./types/Errors.js"; import type { RouteStep } from "./types/Route.js"; import type { Token } from "./types/Token.js"; @@ -191,9 +192,12 @@ export async function prepare( if (!response.ok) { const errorJson = await response.json(); - throw new Error( - `${errorJson.code || response.status} | ${errorJson.message || response.statusText} - ${errorJson.correlationId || "N/A"}`, - ); + throw new ApiError({ + code: errorJson.code || "UNKNOWN_ERROR", + message: errorJson.message || response.statusText, + correlationId: errorJson.correlationId || undefined, + statusCode: response.status, + }); } const { data }: { data: OnrampPrepareQuoteResponseData } = diff --git a/packages/thirdweb/src/bridge/OnrampStatus.ts b/packages/thirdweb/src/bridge/OnrampStatus.ts index 33a3d08c5c6..b576fde40fd 100644 --- a/packages/thirdweb/src/bridge/OnrampStatus.ts +++ b/packages/thirdweb/src/bridge/OnrampStatus.ts @@ -2,6 +2,7 @@ import type { Hex as ox__Hex } from "ox"; import type { ThirdwebClient } from "../client/client.js"; import { getThirdwebBaseUrl } from "../utils/domains.js"; import { getClientFetch } from "../utils/fetch.js"; +import { ApiError } from "./types/Errors.js"; /** * Retrieves the status of an Onramp session created via {@link Bridge.Onramp.prepare}. The @@ -72,9 +73,12 @@ export async function status(options: status.Options): Promise { const response = await clientFetch(url.toString()); if (!response.ok) { const errorJson = await response.json(); - throw new Error( - `${errorJson.code || response.status} | ${errorJson.message || response.statusText} - ${errorJson.correlationId || "N/A"}`, - ); + throw new ApiError({ + code: errorJson.code || "UNKNOWN_ERROR", + message: errorJson.message || response.statusText, + correlationId: errorJson.correlationId || undefined, + statusCode: response.status, + }); } const { data }: { data: status.Result } = await response.json(); diff --git a/packages/thirdweb/src/bridge/Routes.test.ts b/packages/thirdweb/src/bridge/Routes.test.ts index af31d4745f6..9917707710f 100644 --- a/packages/thirdweb/src/bridge/Routes.test.ts +++ b/packages/thirdweb/src/bridge/Routes.test.ts @@ -155,7 +155,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("Bridge.routes", () => { offset: 1000, }), ).rejects.toThrowErrorMatchingInlineSnapshot( - `[Error: InvalidRoutesRequest | The provided request is invalid.]`, + "[Error: The provided request is invalid.]", ); }); }); diff --git a/packages/thirdweb/src/bridge/Routes.ts b/packages/thirdweb/src/bridge/Routes.ts index 2db75647493..d023c7d7e95 100644 --- a/packages/thirdweb/src/bridge/Routes.ts +++ b/packages/thirdweb/src/bridge/Routes.ts @@ -2,6 +2,7 @@ import type { Address as ox__Address, Hex as ox__Hex } from "ox"; import type { ThirdwebClient } from "../client/client.js"; import { getThirdwebBaseUrl } from "../utils/domains.js"; import { getClientFetch } from "../utils/fetch.js"; +import { ApiError } from "./types/Errors.js"; import type { Route } from "./types/Route.js"; /** @@ -162,7 +163,12 @@ export async function routes(options: routes.Options): Promise { const response = await clientFetch(url.toString()); if (!response.ok) { const errorJson = await response.json(); - throw new Error(`${errorJson.code} | ${errorJson.message}`); + throw new ApiError({ + code: errorJson.code || "UNKNOWN_ERROR", + message: errorJson.message || response.statusText, + correlationId: errorJson.correlationId || undefined, + statusCode: response.status, + }); } const { data }: { data: Route[] } = await response.json(); diff --git a/packages/thirdweb/src/bridge/Sell.ts b/packages/thirdweb/src/bridge/Sell.ts index 4ab038f0379..9bf0c1187bd 100644 --- a/packages/thirdweb/src/bridge/Sell.ts +++ b/packages/thirdweb/src/bridge/Sell.ts @@ -4,6 +4,7 @@ import type { ThirdwebClient } from "../client/client.js"; import { getThirdwebBaseUrl } from "../utils/domains.js"; import { getClientFetch } from "../utils/fetch.js"; import { stringify } from "../utils/json.js"; +import { ApiError } from "./types/Errors.js"; import type { PreparedQuote, Quote } from "./types/Quote.js"; /** @@ -126,9 +127,12 @@ export async function quote(options: quote.Options): Promise { const response = await clientFetch(url.toString()); if (!response.ok) { const errorJson = await response.json(); - throw new Error( - `${errorJson.code} | ${errorJson.message} - ${errorJson.correlationId}`, - ); + throw new ApiError({ + code: errorJson.code || "UNKNOWN_ERROR", + message: errorJson.message || response.statusText, + correlationId: errorJson.correlationId || undefined, + statusCode: response.status, + }); } const { data }: { data: Quote } = await response.json(); @@ -348,9 +352,12 @@ export async function prepare( }); if (!response.ok) { const errorJson = await response.json(); - throw new Error( - `${errorJson.code} | ${errorJson.message} - ${errorJson.correlationId}`, - ); + throw new ApiError({ + code: errorJson.code || "UNKNOWN_ERROR", + message: errorJson.message || response.statusText, + correlationId: errorJson.correlationId || undefined, + statusCode: response.status, + }); } const { data }: { data: PreparedQuote } = await response.json(); diff --git a/packages/thirdweb/src/bridge/Status.ts b/packages/thirdweb/src/bridge/Status.ts index 1e5cddba369..47027f6baf0 100644 --- a/packages/thirdweb/src/bridge/Status.ts +++ b/packages/thirdweb/src/bridge/Status.ts @@ -3,6 +3,7 @@ import type { Chain } from "../chains/types.js"; import type { ThirdwebClient } from "../client/client.js"; import { getThirdwebBaseUrl } from "../utils/domains.js"; import { getClientFetch } from "../utils/fetch.js"; +import { ApiError } from "./types/Errors.js"; import type { Status } from "./types/Status.js"; /** @@ -115,9 +116,12 @@ export async function status(options: status.Options): Promise { const response = await clientFetch(url.toString()); if (!response.ok) { const errorJson = await response.json(); - throw new Error( - `${errorJson.code} | ${errorJson.message} - ${errorJson.correlationId}`, - ); + throw new ApiError({ + code: errorJson.code || "UNKNOWN_ERROR", + message: errorJson.message || response.statusText, + correlationId: errorJson.correlationId || undefined, + statusCode: response.status, + }); } const { data }: { data: Status } = await response.json(); diff --git a/packages/thirdweb/src/bridge/Transfer.ts b/packages/thirdweb/src/bridge/Transfer.ts index 6ffb4fbe14c..f72263540a3 100644 --- a/packages/thirdweb/src/bridge/Transfer.ts +++ b/packages/thirdweb/src/bridge/Transfer.ts @@ -4,6 +4,7 @@ import type { ThirdwebClient } from "../client/client.js"; import { getThirdwebBaseUrl } from "../utils/domains.js"; import { getClientFetch } from "../utils/fetch.js"; import { stringify } from "../utils/json.js"; +import { ApiError } from "./types/Errors.js"; import type { PreparedQuote } from "./types/Quote.js"; /** @@ -212,9 +213,12 @@ export async function prepare( }); if (!response.ok) { const errorJson = await response.json(); - throw new Error( - `${errorJson.code} | ${errorJson.message} - ${errorJson.correlationId}`, - ); + throw new ApiError({ + code: errorJson.code || "UNKNOWN_ERROR", + message: errorJson.message || response.statusText, + correlationId: errorJson.correlationId || undefined, + statusCode: response.status, + }); } const { data }: { data: PreparedQuote } = await response.json(); diff --git a/packages/thirdweb/src/bridge/index.ts b/packages/thirdweb/src/bridge/index.ts index 4626b6e5078..52efb55cc0a 100644 --- a/packages/thirdweb/src/bridge/index.ts +++ b/packages/thirdweb/src/bridge/index.ts @@ -16,4 +16,5 @@ export type { } from "./types/Route.js"; export type { Status } from "./types/Status.js"; export type { Token } from "./types/Token.js"; -export type { BridgeAction } from "./types/BridgeAction.js"; +export type { Action } from "./types/BridgeAction.js"; +export type { ApiError } from "./types/Errors.js"; diff --git a/packages/thirdweb/src/bridge/types/BridgeAction.ts b/packages/thirdweb/src/bridge/types/BridgeAction.ts index 4c743d4d1b5..7a83d5c9d3a 100644 --- a/packages/thirdweb/src/bridge/types/BridgeAction.ts +++ b/packages/thirdweb/src/bridge/types/BridgeAction.ts @@ -1 +1 @@ -export type BridgeAction = "approval" | "transfer" | "buy" | "sell"; +export type Action = "approval" | "transfer" | "buy" | "sell"; diff --git a/packages/thirdweb/src/bridge/types/Errors.ts b/packages/thirdweb/src/bridge/types/Errors.ts new file mode 100644 index 00000000000..842c3915869 --- /dev/null +++ b/packages/thirdweb/src/bridge/types/Errors.ts @@ -0,0 +1,24 @@ +type ErrorCode = + | "INVALID_INPUT" + | "ROUTE_NOT_FOUND" + | "AMOUNT_TOO_LOW" + | "AMOUNT_TOO_HIGH" + | "UNKNOWN_ERROR"; + +export class ApiError extends Error { + code: ErrorCode; + correlationId?: string; + statusCode: number; + + constructor(args: { + code: ErrorCode; + message: string; + statusCode: number; + correlationId?: string; + }) { + super(args.message); + this.code = args.code; + this.correlationId = args.correlationId; + this.statusCode = args.statusCode; + } +} diff --git a/packages/thirdweb/src/bridge/types/Route.ts b/packages/thirdweb/src/bridge/types/Route.ts index ac23656fbde..2c4c1a204f8 100644 --- a/packages/thirdweb/src/bridge/types/Route.ts +++ b/packages/thirdweb/src/bridge/types/Route.ts @@ -1,7 +1,7 @@ import type { Hex as ox__Hex } from "ox"; import type { Chain } from "../../chains/types.js"; import type { ThirdwebClient } from "../../client/client.js"; -import type { BridgeAction } from "./BridgeAction.js"; +import type { Action } from "./BridgeAction.js"; import type { Token } from "./Token.js"; export type Route = { @@ -35,7 +35,7 @@ export type RouteTransaction = { /** * The action this transaction performs. This can be "approval", "transfer", "buy", or "sell". */ - action: BridgeAction; + action: Action; /** * The transaction ID, used for tracking purposes. */ diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/PayWIthCreditCard.tsx b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/PayWIthCreditCard.tsx index 415d1dfcd94..31d103dd8c2 100644 --- a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/PayWIthCreditCard.tsx +++ b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/PayWIthCreditCard.tsx @@ -85,7 +85,7 @@ export function PayWithCreditCard(props: { {props.value ? `${props.currency.symbol}${formatNumber( Number(props.value), - 6, + 2, )}` : "--"} diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.tsx b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.tsx index 5dc2c4804f9..3cb2379045b 100644 --- a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.tsx +++ b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.tsx @@ -5,7 +5,6 @@ import type { Chain } from "../../../../../../../chains/types.js"; import type { ThirdwebClient } from "../../../../../../../client/client.js"; import { NATIVE_TOKEN_ADDRESS } from "../../../../../../../constants/addresses.js"; import type { FiatProvider } from "../../../../../../../pay/utils/commonTypes.js"; -import { formatNumber } from "../../../../../../../utils/formatNumber.js"; import { type Theme, iconSize, @@ -25,7 +24,6 @@ import { Spinner } from "../../../../components/Spinner.js"; import { Container } from "../../../../components/basic.js"; import { Button } from "../../../../components/buttons.js"; import { Text } from "../../../../components/text.js"; -import { TokenSymbol } from "../../../../components/token/TokenSymbol.js"; import { type ERC20OrNativeToken, isNativeToken } from "../../nativeToken.js"; import { EstimatedTimeAndFees } from "../EstimatedTimeAndFees.js"; import { PayWithCreditCard } from "../PayWIthCreditCard.js"; @@ -227,77 +225,43 @@ export function FiatScreenContent(props: { {/* Error message */} {errorMsg && (
- {errorMsg.data?.minimumAmountEth ? ( - - Minimum amount is{" "} - {formatNumber(Number(errorMsg.data.minimumAmountEth), 6)}{" "} - - - ) : ( -
- - {errorMsg.title} - - - {errorMsg.message} - -
- )} + + {errorMsg.title} + + + {errorMsg.message} +
)} - {errorMsg?.data?.minimumAmountEth ? ( - - ) : ( - - )} + ); } diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.tsx b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.tsx index f9ac5e1df2b..f27b41b5215 100644 --- a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.tsx +++ b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.tsx @@ -8,7 +8,6 @@ import { NATIVE_TOKEN_ADDRESS } from "../../../../../../../constants/addresses.j import { getContract } from "../../../../../../../contract/contract.js"; import { allowance } from "../../../../../../../extensions/erc20/__generated__/IERC20/read/allowance.js"; import type { GetBuyWithCryptoQuoteParams } from "../../../../../../../pay/buyWithCrypto/getQuote.js"; -import { formatNumber } from "../../../../../../../utils/formatNumber.js"; import type { Account } from "../../../../../../../wallets/interfaces/wallet.js"; import type { PayUIOptions } from "../../../../../../core/hooks/connection/ConnectButtonProps.js"; import { useWalletBalance } from "../../../../../../core/hooks/others/useWalletBalance.js"; @@ -286,28 +285,14 @@ export function SwapScreenContent(props: { {/* Error message */} {errorMsg && (
- {errorMsg.data?.minimumAmountEth ? ( +
- Minimum amount is{" "} - {formatNumber(Number(errorMsg.data.minimumAmountEth), 6)}{" "} - + {errorMsg.title} - ) : ( -
- - {errorMsg.title} - - - {errorMsg.message} - -
- )} + + {errorMsg.message} + +
)} @@ -324,23 +309,7 @@ export function SwapScreenContent(props: { {/* Button */} - {errorMsg?.data?.minimumAmountEth ? ( - - ) : isNotEnoughBalance || errorMsg ? ( + {isNotEnoughBalance || errorMsg ? (